query_test.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. package elasticsearch
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "github.com/grafana/grafana/pkg/components/simplejson"
  6. "github.com/grafana/grafana/pkg/models"
  7. "github.com/grafana/grafana/pkg/tsdb"
  8. . "github.com/smartystreets/goconvey/convey"
  9. "reflect"
  10. "strconv"
  11. "strings"
  12. "testing"
  13. )
  14. func testElasticSearchResponse(requestJSON string, expectedElasticSearchRequestJSON string) {
  15. var queryExpectedJSONInterface, queryJSONInterface interface{}
  16. parser := ElasticSearchQueryParser{}
  17. model := &Query{}
  18. err := json.Unmarshal([]byte(requestJSON), model)
  19. So(err, ShouldBeNil)
  20. jsonDate, _ := simplejson.NewJson([]byte(`{"esVersion":2}`))
  21. dsInfo := &models.DataSource{
  22. Database: "grafana-test",
  23. JsonData: jsonDate,
  24. }
  25. testTimeRange := tsdb.NewTimeRange("5m", "now")
  26. req, _ := simplejson.NewJson([]byte(requestJSON))
  27. query, err := parser.Parse(req, dsInfo)
  28. s, err := query.Build(&tsdb.TsdbQuery{TimeRange: testTimeRange}, dsInfo)
  29. queryJSON := strings.Split(s, "\n")[1]
  30. err = json.Unmarshal([]byte(queryJSON), &queryJSONInterface)
  31. So(err, ShouldBeNil)
  32. expectedElasticSearchRequestJSON = strings.Replace(
  33. expectedElasticSearchRequestJSON,
  34. "<FROM_TIMESTAMP>",
  35. strconv.FormatInt(testTimeRange.GetFromAsMsEpoch(), 10),
  36. -1,
  37. )
  38. expectedElasticSearchRequestJSON = strings.Replace(
  39. expectedElasticSearchRequestJSON,
  40. "<TO_TIMESTAMP>",
  41. strconv.FormatInt(testTimeRange.GetToAsMsEpoch(), 10),
  42. -1,
  43. )
  44. err = json.Unmarshal([]byte(expectedElasticSearchRequestJSON), &queryExpectedJSONInterface)
  45. So(err, ShouldBeNil)
  46. result := reflect.DeepEqual(queryExpectedJSONInterface, queryJSONInterface)
  47. if !result {
  48. fmt.Printf("ERROR: %s \n != \n %s", expectedElasticSearchRequestJSON, queryJSON)
  49. }
  50. So(result, ShouldBeTrue)
  51. }
  52. func TestElasticSearchQueryBuilder(t *testing.T) {
  53. Convey("Elasticsearch QueryBuilder query testing", t, func() {
  54. Convey("Build test average metric with moving average", func() {
  55. var testElasticsearchModelRequestJSON = `
  56. {
  57. "bucketAggs": [
  58. {
  59. "field": "timestamp",
  60. "id": "2",
  61. "settings": {
  62. "interval": "auto",
  63. "min_doc_count": 0,
  64. "trimEdges": 0
  65. },
  66. "type": "date_histogram"
  67. }
  68. ],
  69. "dsType": "elasticsearch",
  70. "metrics": [
  71. {
  72. "field": "value",
  73. "id": "1",
  74. "inlineScript": "_value * 2",
  75. "meta": {},
  76. "settings": {
  77. "script": {
  78. "inline": "_value * 2"
  79. }
  80. },
  81. "type": "avg"
  82. },
  83. {
  84. "field": "1",
  85. "id": "3",
  86. "meta": {},
  87. "pipelineAgg": "1",
  88. "settings": {
  89. "minimize": false,
  90. "model": "simple",
  91. "window": 5
  92. },
  93. "type": "moving_avg"
  94. }
  95. ],
  96. "query": "(test:query) AND (name:sample)",
  97. "refId": "A",
  98. "timeField": "timestamp"
  99. }
  100. `
  101. var expectedElasticsearchQueryJSON = `
  102. {
  103. "size": 0,
  104. "query": {
  105. "bool": {
  106. "filter": [
  107. {
  108. "range": {
  109. "timestamp": {
  110. "gte": "<FROM_TIMESTAMP>",
  111. "lte": "<TO_TIMESTAMP>",
  112. "format": "epoch_millis"
  113. }
  114. }
  115. },
  116. {
  117. "query_string": {
  118. "analyze_wildcard": true,
  119. "query": "(test:query) AND (name:sample)"
  120. }
  121. }
  122. ]
  123. }
  124. },
  125. "aggs": {
  126. "2": {
  127. "date_histogram": {
  128. "interval": "200ms",
  129. "field": "timestamp",
  130. "min_doc_count": 0,
  131. "extended_bounds": {
  132. "min": "<FROM_TIMESTAMP>",
  133. "max": "<TO_TIMESTAMP>"
  134. },
  135. "format": "epoch_millis"
  136. },
  137. "aggs": {
  138. "1": {
  139. "avg": {
  140. "field": "value",
  141. "script": {
  142. "inline": "_value * 2"
  143. }
  144. }
  145. },
  146. "3": {
  147. "moving_avg": {
  148. "buckets_path": "1",
  149. "window": 5,
  150. "model": "simple",
  151. "minimize": false
  152. }
  153. }
  154. }
  155. }
  156. }
  157. }`
  158. testElasticSearchResponse(testElasticsearchModelRequestJSON, expectedElasticsearchQueryJSON)
  159. })
  160. Convey("Test Wildcards and Quotes", func() {
  161. testElasticsearchModelRequestJSON := `
  162. {
  163. "alias": "New",
  164. "bucketAggs": [
  165. {
  166. "field": "timestamp",
  167. "id": "2",
  168. "type": "date_histogram"
  169. }
  170. ],
  171. "dsType": "elasticsearch",
  172. "metrics": [
  173. {
  174. "type": "sum",
  175. "field": "value",
  176. "id": "1"
  177. }
  178. ],
  179. "query": "scope:$location.leagueconnect.api AND name:*CreateRegistration AND name:\"*.201-responses.rate\"",
  180. "refId": "A",
  181. "timeField": "timestamp"
  182. }`
  183. expectedElasticsearchQueryJSON := `
  184. {
  185. "size": 0,
  186. "query": {
  187. "bool": {
  188. "filter": [
  189. {
  190. "range": {
  191. "timestamp": {
  192. "gte": "<FROM_TIMESTAMP>",
  193. "lte": "<TO_TIMESTAMP>",
  194. "format": "epoch_millis"
  195. }
  196. }
  197. },
  198. {
  199. "query_string": {
  200. "analyze_wildcard": true,
  201. "query": "scope:$location.leagueconnect.api AND name:*CreateRegistration AND name:\"*.201-responses.rate\""
  202. }
  203. }
  204. ]
  205. }
  206. },
  207. "aggs": {
  208. "2": {
  209. "aggs": {
  210. "1": {
  211. "sum": {
  212. "field": "value"
  213. }
  214. }
  215. },
  216. "date_histogram": {
  217. "extended_bounds": {
  218. "max": "<TO_TIMESTAMP>",
  219. "min": "<FROM_TIMESTAMP>"
  220. },
  221. "field": "timestamp",
  222. "format": "epoch_millis",
  223. "min_doc_count": 0
  224. }
  225. }
  226. }
  227. }`
  228. testElasticSearchResponse(testElasticsearchModelRequestJSON, expectedElasticsearchQueryJSON)
  229. })
  230. Convey("Test Term Aggregates", func() {
  231. testElasticsearchModelRequestJSON := `
  232. {
  233. "bucketAggs": [{
  234. "field": "name_raw",
  235. "id": "4",
  236. "settings": {
  237. "order": "desc",
  238. "orderBy": "_term",
  239. "size": "10"
  240. },
  241. "type": "terms"
  242. }, {
  243. "field": "timestamp",
  244. "id": "2",
  245. "settings": {
  246. "interval": "1m",
  247. "min_doc_count": 0,
  248. "trimEdges": 0
  249. },
  250. "type": "date_histogram"
  251. }],
  252. "dsType": "elasticsearch",
  253. "filters": [{
  254. "boolOp": "AND",
  255. "not": false,
  256. "type": "rfc190Scope",
  257. "value": "*.hmp.metricsd"
  258. }, {
  259. "boolOp": "AND",
  260. "not": false,
  261. "type": "name_raw",
  262. "value": "builtin.general.*_instance_count"
  263. }],
  264. "metricObject": {},
  265. "metrics": [{
  266. "field": "value",
  267. "id": "1",
  268. "meta": {},
  269. "options": {},
  270. "settings": {},
  271. "type": "sum"
  272. }],
  273. "mode": 0,
  274. "numToGraph": 10,
  275. "prependHostName": false,
  276. "query": "(scope:*.hmp.metricsd) AND (name_raw:builtin.general.*_instance_count)",
  277. "refId": "A",
  278. "regexAlias": false,
  279. "selectedApplication": "",
  280. "selectedHost": "",
  281. "selectedLocation": "",
  282. "timeField": "timestamp",
  283. "useFullHostName": "",
  284. "useQuery": false
  285. }`
  286. expectedElasticsearchQueryJSON := `
  287. {
  288. "size": 0,
  289. "query": {
  290. "bool": {
  291. "filter": [
  292. {
  293. "range": {
  294. "timestamp": {
  295. "gte": "<FROM_TIMESTAMP>",
  296. "lte": "<TO_TIMESTAMP>",
  297. "format": "epoch_millis"
  298. }
  299. }
  300. },
  301. {
  302. "query_string": {
  303. "analyze_wildcard": true,
  304. "query": "(scope:*.hmp.metricsd) AND (name_raw:builtin.general.*_instance_count)"
  305. }
  306. }
  307. ]
  308. }
  309. },
  310. "aggs": {"4":{"aggs":{"2":{"aggs":{"1":{"sum":{"field":"value"}}},"date_histogram":{"extended_bounds":{"max":"<TO_TIMESTAMP>","min":"<FROM_TIMESTAMP>"},"field":"timestamp","format":"epoch_millis","interval":"1m","min_doc_count":0}}},"terms":{"field":"name_raw","order":{"_term":"desc"},"size":10}}}
  311. }`
  312. testElasticSearchResponse(testElasticsearchModelRequestJSON, expectedElasticsearchQueryJSON)
  313. })
  314. })
  315. }