query_test.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. package elasticsearch
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "reflect"
  6. "strconv"
  7. "strings"
  8. "testing"
  9. "github.com/grafana/grafana/pkg/components/simplejson"
  10. "github.com/grafana/grafana/pkg/models"
  11. "github.com/grafana/grafana/pkg/tsdb"
  12. . "github.com/smartystreets/goconvey/convey"
  13. )
  14. func testElasticSearchResponse(query Query, expectedElasticSearchRequestJSON string) {
  15. var queryExpectedJSONInterface, queryJSONInterface interface{}
  16. jsonDate, _ := simplejson.NewJson([]byte(`{"esVersion":2}`))
  17. dsInfo := &models.DataSource{
  18. Database: "grafana-test",
  19. JsonData: jsonDate,
  20. }
  21. testTimeRange := tsdb.NewTimeRange("5m", "now")
  22. s, err := query.Build(&tsdb.TsdbQuery{TimeRange: testTimeRange}, dsInfo)
  23. So(err, ShouldBeNil)
  24. queryJSON := strings.Split(s, "\n")[1]
  25. err = json.Unmarshal([]byte(queryJSON), &queryJSONInterface)
  26. So(err, ShouldBeNil)
  27. expectedElasticSearchRequestJSON = strings.Replace(
  28. expectedElasticSearchRequestJSON,
  29. "<FROM_TIMESTAMP>",
  30. strconv.FormatInt(testTimeRange.GetFromAsMsEpoch(), 10),
  31. -1,
  32. )
  33. expectedElasticSearchRequestJSON = strings.Replace(
  34. expectedElasticSearchRequestJSON,
  35. "<TO_TIMESTAMP>",
  36. strconv.FormatInt(testTimeRange.GetToAsMsEpoch(), 10),
  37. -1,
  38. )
  39. err = json.Unmarshal([]byte(expectedElasticSearchRequestJSON), &queryExpectedJSONInterface)
  40. So(err, ShouldBeNil)
  41. result := reflect.DeepEqual(queryExpectedJSONInterface, queryJSONInterface)
  42. if !result {
  43. fmt.Printf("ERROR: %s \n != \n %s", expectedElasticSearchRequestJSON, queryJSON)
  44. }
  45. So(result, ShouldBeTrue)
  46. }
  47. func TestElasticSearchQueryBuilder(t *testing.T) {
  48. Convey("Elasticsearch QueryBuilder query testing", t, func() {
  49. Convey("Build test average metric with moving average", func() {
  50. var expectedElasticsearchQueryJSON = `
  51. {
  52. "size": 0,
  53. "query": {
  54. "bool": {
  55. "filter": [
  56. {
  57. "range": {
  58. "timestamp": {
  59. "gte": "<FROM_TIMESTAMP>",
  60. "lte": "<TO_TIMESTAMP>",
  61. "format": "epoch_millis"
  62. }
  63. }
  64. },
  65. {
  66. "query_string": {
  67. "analyze_wildcard": true,
  68. "query": "(test:query) AND (name:sample)"
  69. }
  70. }
  71. ]
  72. }
  73. },
  74. "aggs": {
  75. "2": {
  76. "date_histogram": {
  77. "interval": "200ms",
  78. "field": "timestamp",
  79. "min_doc_count": 0,
  80. "extended_bounds": {
  81. "min": "<FROM_TIMESTAMP>",
  82. "max": "<TO_TIMESTAMP>"
  83. },
  84. "format": "epoch_millis"
  85. },
  86. "aggs": {
  87. "1": {
  88. "avg": {
  89. "field": "value",
  90. "script": {
  91. "inline": "_value * 2"
  92. }
  93. }
  94. },
  95. "3": {
  96. "moving_avg": {
  97. "buckets_path": "1",
  98. "window": 5,
  99. "model": "simple",
  100. "minimize": false
  101. }
  102. }
  103. }
  104. }
  105. }
  106. }`
  107. testElasticSearchResponse(avgWithMovingAvg, expectedElasticsearchQueryJSON)
  108. })
  109. Convey("Test Wildcards and Quotes", func() {
  110. expectedElasticsearchQueryJSON := `
  111. {
  112. "size": 0,
  113. "query": {
  114. "bool": {
  115. "filter": [
  116. {
  117. "range": {
  118. "timestamp": {
  119. "gte": "<FROM_TIMESTAMP>",
  120. "lte": "<TO_TIMESTAMP>",
  121. "format": "epoch_millis"
  122. }
  123. }
  124. },
  125. {
  126. "query_string": {
  127. "analyze_wildcard": true,
  128. "query": "scope:$location.leagueconnect.api AND name:*CreateRegistration AND name:\"*.201-responses.rate\""
  129. }
  130. }
  131. ]
  132. }
  133. },
  134. "aggs": {
  135. "2": {
  136. "aggs": {
  137. "1": {
  138. "sum": {
  139. "field": "value"
  140. }
  141. }
  142. },
  143. "date_histogram": {
  144. "extended_bounds": {
  145. "max": "<TO_TIMESTAMP>",
  146. "min": "<FROM_TIMESTAMP>"
  147. },
  148. "field": "timestamp",
  149. "format": "epoch_millis",
  150. "min_doc_count": 0
  151. }
  152. }
  153. }
  154. }`
  155. testElasticSearchResponse(wildcardsAndQuotes, expectedElasticsearchQueryJSON)
  156. })
  157. Convey("Test Term Aggregates", func() {
  158. expectedElasticsearchQueryJSON := `
  159. {
  160. "size": 0,
  161. "query": {
  162. "bool": {
  163. "filter": [
  164. {
  165. "range": {
  166. "timestamp": {
  167. "gte": "<FROM_TIMESTAMP>",
  168. "lte": "<TO_TIMESTAMP>",
  169. "format": "epoch_millis"
  170. }
  171. }
  172. },
  173. {
  174. "query_string": {
  175. "analyze_wildcard": true,
  176. "query": "(scope:*.hmp.metricsd) AND (name_raw:builtin.general.*_instance_count)"
  177. }
  178. }
  179. ]
  180. }
  181. },
  182. "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":"200ms","min_doc_count":0}}},"terms":{"field":"name_raw","order":{"_term":"desc"},"size":10}}}
  183. }`
  184. testElasticSearchResponse(termAggs, expectedElasticsearchQueryJSON)
  185. })
  186. Convey("Test Filters Aggregates", func() {
  187. expectedElasticsearchQueryJSON := `{
  188. "size": 0,
  189. "query": {
  190. "bool": {
  191. "filter": [
  192. {
  193. "range": {
  194. "time": {
  195. "gte": "<FROM_TIMESTAMP>",
  196. "lte": "<TO_TIMESTAMP>",
  197. "format": "epoch_millis"
  198. }
  199. }
  200. },
  201. {
  202. "query_string": {
  203. "analyze_wildcard": true,
  204. "query": "*"
  205. }
  206. }
  207. ]
  208. }
  209. },
  210. "aggs": {
  211. "3": {
  212. "filters": {
  213. "filters": {
  214. "hello": {
  215. "query_string": {
  216. "query": "host:\"67.65.185.232\"",
  217. "analyze_wildcard": true
  218. }
  219. }
  220. }
  221. },
  222. "aggs": {
  223. "2": {
  224. "date_histogram": {
  225. "interval": "200ms",
  226. "field": "time",
  227. "min_doc_count": 0,
  228. "extended_bounds": {
  229. "min": "<FROM_TIMESTAMP>",
  230. "max": "<TO_TIMESTAMP>"
  231. },
  232. "format": "epoch_millis"
  233. },
  234. "aggs": {}
  235. }
  236. }
  237. }
  238. }
  239. }
  240. `
  241. testElasticSearchResponse(filtersAggs, expectedElasticsearchQueryJSON)
  242. })
  243. })
  244. }
  245. func makeTime(hour int) string {
  246. //unixtime 1500000000 == 2017-07-14T02:40:00+00:00
  247. return strconv.Itoa((1500000000 + hour*60*60) * 1000)
  248. }
  249. func getIndexListByTime(pattern string, interval string, hour int) string {
  250. timeRange := &tsdb.TimeRange{
  251. From: makeTime(0),
  252. To: makeTime(hour),
  253. }
  254. return getIndexList(pattern, interval, timeRange)
  255. }
  256. func TestElasticsearchGetIndexList(t *testing.T) {
  257. Convey("Test Elasticsearch getIndex ", t, func() {
  258. Convey("Parse Interval Formats", func() {
  259. So(getIndexListByTime("[logstash-]YYYY.MM.DD", "Daily", 48),
  260. ShouldEqual, "logstash-2017.07.14,logstash-2017.07.15,logstash-2017.07.16")
  261. So(len(strings.Split(getIndexListByTime("[logstash-]YYYY.MM.DD.HH", "Hourly", 3), ",")),
  262. ShouldEqual, 4)
  263. So(getIndexListByTime("[logstash-]YYYY.W", "Weekly", 100),
  264. ShouldEqual, "logstash-2017.28,logstash-2017.29")
  265. So(getIndexListByTime("[logstash-]YYYY.MM", "Monthly", 700),
  266. ShouldEqual, "logstash-2017.07,logstash-2017.08")
  267. So(getIndexListByTime("[logstash-]YYYY", "Yearly", 10000),
  268. ShouldEqual, "logstash-2017,logstash-2018,logstash-2019")
  269. })
  270. Convey("No Interval", func() {
  271. index := getIndexListByTime("logstash-test", "", 1)
  272. So(index, ShouldEqual, "logstash-test")
  273. })
  274. })
  275. }