search_request_test.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. package es
  2. import (
  3. "encoding/json"
  4. "testing"
  5. "time"
  6. "github.com/grafana/grafana/pkg/components/simplejson"
  7. "github.com/grafana/grafana/pkg/tsdb"
  8. . "github.com/smartystreets/goconvey/convey"
  9. )
  10. func TestSearchRequest(t *testing.T) {
  11. Convey("Test elasticsearch search request", t, func() {
  12. timeField := "@timestamp"
  13. Convey("Given new search request builder for es version 5", func() {
  14. b := NewSearchRequestBuilder(5, tsdb.Interval{Value: 15 * time.Second, Text: "15s"})
  15. Convey("When building search request", func() {
  16. sr, err := b.Build()
  17. So(err, ShouldBeNil)
  18. Convey("Should have size of zero", func() {
  19. So(sr.Size, ShouldEqual, 0)
  20. })
  21. Convey("Should have no sorting", func() {
  22. So(sr.Sort, ShouldHaveLength, 0)
  23. })
  24. Convey("When marshal to JSON should generate correct json", func() {
  25. body, err := json.Marshal(sr)
  26. So(err, ShouldBeNil)
  27. json, err := simplejson.NewJson(body)
  28. So(err, ShouldBeNil)
  29. So(json.Get("size").MustInt(500), ShouldEqual, 0)
  30. So(json.Get("sort").Interface(), ShouldBeNil)
  31. So(json.Get("aggs").Interface(), ShouldBeNil)
  32. So(json.Get("query").Interface(), ShouldBeNil)
  33. })
  34. })
  35. Convey("When adding size, sort, filters", func() {
  36. b.Size(200)
  37. b.SortDesc(timeField, "boolean")
  38. filters := b.Query().Bool().Filter()
  39. filters.AddDateRangeFilter(timeField, "$timeTo", "$timeFrom", DateFormatEpochMS)
  40. filters.AddQueryStringFilter("test", true)
  41. Convey("When building search request", func() {
  42. sr, err := b.Build()
  43. So(err, ShouldBeNil)
  44. Convey("Should have correct size", func() {
  45. So(sr.Size, ShouldEqual, 200)
  46. })
  47. Convey("Should have correct sorting", func() {
  48. sort, ok := sr.Sort[timeField].(map[string]string)
  49. So(ok, ShouldBeTrue)
  50. So(sort["order"], ShouldEqual, "desc")
  51. So(sort["unmapped_type"], ShouldEqual, "boolean")
  52. })
  53. Convey("Should have range filter", func() {
  54. f, ok := sr.Query.Bool.Filters[0].(*RangeFilter)
  55. So(ok, ShouldBeTrue)
  56. So(f.Gte, ShouldEqual, "$timeFrom")
  57. So(f.Lte, ShouldEqual, "$timeTo")
  58. So(f.Format, ShouldEqual, "epoch_millis")
  59. })
  60. Convey("Should have query string filter", func() {
  61. f, ok := sr.Query.Bool.Filters[1].(*QueryStringFilter)
  62. So(ok, ShouldBeTrue)
  63. So(f.Query, ShouldEqual, "test")
  64. So(f.AnalyzeWildcard, ShouldBeTrue)
  65. })
  66. Convey("When marshal to JSON should generate correct json", func() {
  67. body, err := json.Marshal(sr)
  68. So(err, ShouldBeNil)
  69. json, err := simplejson.NewJson(body)
  70. So(err, ShouldBeNil)
  71. So(json.Get("size").MustInt(0), ShouldEqual, 200)
  72. sort := json.GetPath("sort", timeField)
  73. So(sort.Get("order").MustString(), ShouldEqual, "desc")
  74. So(sort.Get("unmapped_type").MustString(), ShouldEqual, "boolean")
  75. timeRangeFilter := json.GetPath("query", "bool", "filter").GetIndex(0).Get("range").Get(timeField)
  76. So(timeRangeFilter.Get("gte").MustString(""), ShouldEqual, "$timeFrom")
  77. So(timeRangeFilter.Get("lte").MustString(""), ShouldEqual, "$timeTo")
  78. So(timeRangeFilter.Get("format").MustString(""), ShouldEqual, DateFormatEpochMS)
  79. queryStringFilter := json.GetPath("query", "bool", "filter").GetIndex(1).Get("query_string")
  80. So(queryStringFilter.Get("analyze_wildcard").MustBool(false), ShouldEqual, true)
  81. So(queryStringFilter.Get("query").MustString(""), ShouldEqual, "test")
  82. })
  83. })
  84. })
  85. Convey("When adding doc value field", func() {
  86. b.AddDocValueField(timeField)
  87. Convey("should set correct props", func() {
  88. So(b.customProps["fields"], ShouldBeNil)
  89. scriptFields, ok := b.customProps["script_fields"].(map[string]interface{})
  90. So(ok, ShouldBeTrue)
  91. So(scriptFields, ShouldHaveLength, 0)
  92. docValueFields, ok := b.customProps["docvalue_fields"].([]string)
  93. So(ok, ShouldBeTrue)
  94. So(docValueFields, ShouldHaveLength, 1)
  95. So(docValueFields[0], ShouldEqual, timeField)
  96. })
  97. Convey("When building search request", func() {
  98. sr, err := b.Build()
  99. So(err, ShouldBeNil)
  100. Convey("When marshal to JSON should generate correct json", func() {
  101. body, err := json.Marshal(sr)
  102. So(err, ShouldBeNil)
  103. json, err := simplejson.NewJson(body)
  104. So(err, ShouldBeNil)
  105. scriptFields, err := json.Get("script_fields").Map()
  106. So(err, ShouldBeNil)
  107. So(scriptFields, ShouldHaveLength, 0)
  108. _, err = json.Get("fields").StringArray()
  109. So(err, ShouldNotBeNil)
  110. docValueFields, err := json.Get("docvalue_fields").StringArray()
  111. So(err, ShouldBeNil)
  112. So(docValueFields, ShouldHaveLength, 1)
  113. So(docValueFields[0], ShouldEqual, timeField)
  114. })
  115. })
  116. })
  117. Convey("and adding multiple top level aggs", func() {
  118. aggBuilder := b.Agg()
  119. aggBuilder.Terms("1", "@hostname", nil)
  120. aggBuilder.DateHistogram("2", "@timestamp", nil)
  121. Convey("When building search request", func() {
  122. sr, err := b.Build()
  123. So(err, ShouldBeNil)
  124. Convey("Should have 2 top level aggs", func() {
  125. aggs := sr.Aggs
  126. So(aggs, ShouldHaveLength, 2)
  127. So(aggs[0].Key, ShouldEqual, "1")
  128. So(aggs[0].Aggregation.Type, ShouldEqual, "terms")
  129. So(aggs[1].Key, ShouldEqual, "2")
  130. So(aggs[1].Aggregation.Type, ShouldEqual, "date_histogram")
  131. })
  132. Convey("When marshal to JSON should generate correct json", func() {
  133. body, err := json.Marshal(sr)
  134. So(err, ShouldBeNil)
  135. json, err := simplejson.NewJson(body)
  136. So(err, ShouldBeNil)
  137. So(json.Get("aggs").MustMap(), ShouldHaveLength, 2)
  138. So(json.GetPath("aggs", "1", "terms", "field").MustString(), ShouldEqual, "@hostname")
  139. So(json.GetPath("aggs", "2", "date_histogram", "field").MustString(), ShouldEqual, "@timestamp")
  140. })
  141. })
  142. })
  143. Convey("and adding top level agg with child agg", func() {
  144. aggBuilder := b.Agg()
  145. aggBuilder.Terms("1", "@hostname", func(a *TermsAggregation, ib AggBuilder) {
  146. ib.DateHistogram("2", "@timestamp", nil)
  147. })
  148. Convey("When building search request", func() {
  149. sr, err := b.Build()
  150. So(err, ShouldBeNil)
  151. Convey("Should have 1 top level agg and one child agg", func() {
  152. aggs := sr.Aggs
  153. So(aggs, ShouldHaveLength, 1)
  154. topAgg := aggs[0]
  155. So(topAgg.Key, ShouldEqual, "1")
  156. So(topAgg.Aggregation.Type, ShouldEqual, "terms")
  157. So(topAgg.Aggregation.Aggs, ShouldHaveLength, 1)
  158. childAgg := aggs[0].Aggregation.Aggs[0]
  159. So(childAgg.Key, ShouldEqual, "2")
  160. So(childAgg.Aggregation.Type, ShouldEqual, "date_histogram")
  161. })
  162. Convey("When marshal to JSON should generate correct json", func() {
  163. body, err := json.Marshal(sr)
  164. So(err, ShouldBeNil)
  165. json, err := simplejson.NewJson(body)
  166. So(err, ShouldBeNil)
  167. So(json.Get("aggs").MustMap(), ShouldHaveLength, 1)
  168. firstLevelAgg := json.GetPath("aggs", "1")
  169. secondLevelAgg := firstLevelAgg.GetPath("aggs", "2")
  170. So(firstLevelAgg.GetPath("terms", "field").MustString(), ShouldEqual, "@hostname")
  171. So(secondLevelAgg.GetPath("date_histogram", "field").MustString(), ShouldEqual, "@timestamp")
  172. })
  173. })
  174. })
  175. Convey("and adding two top level aggs with child agg", func() {
  176. aggBuilder := b.Agg()
  177. aggBuilder.Histogram("1", "@hostname", func(a *HistogramAgg, ib AggBuilder) {
  178. ib.DateHistogram("2", "@timestamp", nil)
  179. })
  180. aggBuilder.Filters("3", func(a *FiltersAggregation, ib AggBuilder) {
  181. ib.Terms("4", "@test", nil)
  182. })
  183. Convey("When building search request", func() {
  184. sr, err := b.Build()
  185. So(err, ShouldBeNil)
  186. Convey("Should have 2 top level aggs with one child agg each", func() {
  187. aggs := sr.Aggs
  188. So(aggs, ShouldHaveLength, 2)
  189. topAggOne := aggs[0]
  190. So(topAggOne.Key, ShouldEqual, "1")
  191. So(topAggOne.Aggregation.Type, ShouldEqual, "histogram")
  192. So(topAggOne.Aggregation.Aggs, ShouldHaveLength, 1)
  193. topAggOnechildAgg := topAggOne.Aggregation.Aggs[0]
  194. So(topAggOnechildAgg.Key, ShouldEqual, "2")
  195. So(topAggOnechildAgg.Aggregation.Type, ShouldEqual, "date_histogram")
  196. topAggTwo := aggs[1]
  197. So(topAggTwo.Key, ShouldEqual, "3")
  198. So(topAggTwo.Aggregation.Type, ShouldEqual, "filters")
  199. So(topAggTwo.Aggregation.Aggs, ShouldHaveLength, 1)
  200. topAggTwochildAgg := topAggTwo.Aggregation.Aggs[0]
  201. So(topAggTwochildAgg.Key, ShouldEqual, "4")
  202. So(topAggTwochildAgg.Aggregation.Type, ShouldEqual, "terms")
  203. })
  204. Convey("When marshal to JSON should generate correct json", func() {
  205. body, err := json.Marshal(sr)
  206. So(err, ShouldBeNil)
  207. json, err := simplejson.NewJson(body)
  208. So(err, ShouldBeNil)
  209. topAggOne := json.GetPath("aggs", "1")
  210. So(topAggOne.GetPath("histogram", "field").MustString(), ShouldEqual, "@hostname")
  211. topAggOnechildAgg := topAggOne.GetPath("aggs", "2")
  212. So(topAggOnechildAgg.GetPath("date_histogram", "field").MustString(), ShouldEqual, "@timestamp")
  213. topAggTwo := json.GetPath("aggs", "3")
  214. topAggTwochildAgg := topAggTwo.GetPath("aggs", "4")
  215. So(topAggTwo.GetPath("filters").MustArray(), ShouldHaveLength, 0)
  216. So(topAggTwochildAgg.GetPath("terms", "field").MustString(), ShouldEqual, "@test")
  217. })
  218. })
  219. })
  220. Convey("and adding top level agg with child agg with child agg", func() {
  221. aggBuilder := b.Agg()
  222. aggBuilder.Terms("1", "@hostname", func(a *TermsAggregation, ib AggBuilder) {
  223. ib.Terms("2", "@app", func(a *TermsAggregation, ib AggBuilder) {
  224. ib.DateHistogram("3", "@timestamp", nil)
  225. })
  226. })
  227. Convey("When building search request", func() {
  228. sr, err := b.Build()
  229. So(err, ShouldBeNil)
  230. Convey("Should have 1 top level agg with one child having a child", func() {
  231. aggs := sr.Aggs
  232. So(aggs, ShouldHaveLength, 1)
  233. topAgg := aggs[0]
  234. So(topAgg.Key, ShouldEqual, "1")
  235. So(topAgg.Aggregation.Type, ShouldEqual, "terms")
  236. So(topAgg.Aggregation.Aggs, ShouldHaveLength, 1)
  237. childAgg := topAgg.Aggregation.Aggs[0]
  238. So(childAgg.Key, ShouldEqual, "2")
  239. So(childAgg.Aggregation.Type, ShouldEqual, "terms")
  240. childChildAgg := childAgg.Aggregation.Aggs[0]
  241. So(childChildAgg.Key, ShouldEqual, "3")
  242. So(childChildAgg.Aggregation.Type, ShouldEqual, "date_histogram")
  243. })
  244. Convey("When marshal to JSON should generate correct json", func() {
  245. body, err := json.Marshal(sr)
  246. So(err, ShouldBeNil)
  247. json, err := simplejson.NewJson(body)
  248. So(err, ShouldBeNil)
  249. topAgg := json.GetPath("aggs", "1")
  250. So(topAgg.GetPath("terms", "field").MustString(), ShouldEqual, "@hostname")
  251. childAgg := topAgg.GetPath("aggs", "2")
  252. So(childAgg.GetPath("terms", "field").MustString(), ShouldEqual, "@app")
  253. childChildAgg := childAgg.GetPath("aggs", "3")
  254. So(childChildAgg.GetPath("date_histogram", "field").MustString(), ShouldEqual, "@timestamp")
  255. })
  256. })
  257. })
  258. Convey("and adding bucket and metric aggs", func() {
  259. aggBuilder := b.Agg()
  260. aggBuilder.Terms("1", "@hostname", func(a *TermsAggregation, ib AggBuilder) {
  261. ib.Terms("2", "@app", func(a *TermsAggregation, ib AggBuilder) {
  262. ib.Metric("4", "avg", "@value", nil)
  263. ib.DateHistogram("3", "@timestamp", func(a *DateHistogramAgg, ib AggBuilder) {
  264. ib.Metric("4", "avg", "@value", nil)
  265. ib.Metric("5", "max", "@value", nil)
  266. })
  267. })
  268. })
  269. Convey("When building search request", func() {
  270. sr, err := b.Build()
  271. So(err, ShouldBeNil)
  272. Convey("Should have 1 top level agg with one child having a child", func() {
  273. aggs := sr.Aggs
  274. So(aggs, ShouldHaveLength, 1)
  275. topAgg := aggs[0]
  276. So(topAgg.Key, ShouldEqual, "1")
  277. So(topAgg.Aggregation.Type, ShouldEqual, "terms")
  278. So(topAgg.Aggregation.Aggs, ShouldHaveLength, 1)
  279. childAgg := topAgg.Aggregation.Aggs[0]
  280. So(childAgg.Key, ShouldEqual, "2")
  281. So(childAgg.Aggregation.Type, ShouldEqual, "terms")
  282. childChildOneAgg := childAgg.Aggregation.Aggs[0]
  283. So(childChildOneAgg.Key, ShouldEqual, "4")
  284. So(childChildOneAgg.Aggregation.Type, ShouldEqual, "avg")
  285. childChildTwoAgg := childAgg.Aggregation.Aggs[1]
  286. So(childChildTwoAgg.Key, ShouldEqual, "3")
  287. So(childChildTwoAgg.Aggregation.Type, ShouldEqual, "date_histogram")
  288. childChildTwoChildOneAgg := childChildTwoAgg.Aggregation.Aggs[0]
  289. So(childChildTwoChildOneAgg.Key, ShouldEqual, "4")
  290. So(childChildTwoChildOneAgg.Aggregation.Type, ShouldEqual, "avg")
  291. childChildTwoChildTwoAgg := childChildTwoAgg.Aggregation.Aggs[1]
  292. So(childChildTwoChildTwoAgg.Key, ShouldEqual, "5")
  293. So(childChildTwoChildTwoAgg.Aggregation.Type, ShouldEqual, "max")
  294. })
  295. Convey("When marshal to JSON should generate correct json", func() {
  296. body, err := json.Marshal(sr)
  297. So(err, ShouldBeNil)
  298. json, err := simplejson.NewJson(body)
  299. So(err, ShouldBeNil)
  300. termsAgg := json.GetPath("aggs", "1")
  301. So(termsAgg.GetPath("terms", "field").MustString(), ShouldEqual, "@hostname")
  302. termsAggTwo := termsAgg.GetPath("aggs", "2")
  303. So(termsAggTwo.GetPath("terms", "field").MustString(), ShouldEqual, "@app")
  304. termsAggTwoAvg := termsAggTwo.GetPath("aggs", "4")
  305. So(termsAggTwoAvg.GetPath("avg", "field").MustString(), ShouldEqual, "@value")
  306. dateHistAgg := termsAggTwo.GetPath("aggs", "3")
  307. So(dateHistAgg.GetPath("date_histogram", "field").MustString(), ShouldEqual, "@timestamp")
  308. avgAgg := dateHistAgg.GetPath("aggs", "4")
  309. So(avgAgg.GetPath("avg", "field").MustString(), ShouldEqual, "@value")
  310. maxAgg := dateHistAgg.GetPath("aggs", "5")
  311. So(maxAgg.GetPath("max", "field").MustString(), ShouldEqual, "@value")
  312. })
  313. })
  314. })
  315. })
  316. Convey("Given new search request builder for es version 2", func() {
  317. b := NewSearchRequestBuilder(2, tsdb.Interval{Value: 15 * time.Second, Text: "15s"})
  318. Convey("When adding doc value field", func() {
  319. b.AddDocValueField(timeField)
  320. Convey("should set correct props", func() {
  321. fields, ok := b.customProps["fields"].([]string)
  322. So(ok, ShouldBeTrue)
  323. So(fields, ShouldHaveLength, 2)
  324. So(fields[0], ShouldEqual, "*")
  325. So(fields[1], ShouldEqual, "_source")
  326. scriptFields, ok := b.customProps["script_fields"].(map[string]interface{})
  327. So(ok, ShouldBeTrue)
  328. So(scriptFields, ShouldHaveLength, 0)
  329. fieldDataFields, ok := b.customProps["fielddata_fields"].([]string)
  330. So(ok, ShouldBeTrue)
  331. So(fieldDataFields, ShouldHaveLength, 1)
  332. So(fieldDataFields[0], ShouldEqual, timeField)
  333. })
  334. Convey("When building search request", func() {
  335. sr, err := b.Build()
  336. So(err, ShouldBeNil)
  337. Convey("When marshal to JSON should generate correct json", func() {
  338. body, err := json.Marshal(sr)
  339. So(err, ShouldBeNil)
  340. json, err := simplejson.NewJson(body)
  341. So(err, ShouldBeNil)
  342. scriptFields, err := json.Get("script_fields").Map()
  343. So(err, ShouldBeNil)
  344. So(scriptFields, ShouldHaveLength, 0)
  345. fields, err := json.Get("fields").StringArray()
  346. So(err, ShouldBeNil)
  347. So(fields, ShouldHaveLength, 2)
  348. So(fields[0], ShouldEqual, "*")
  349. So(fields[1], ShouldEqual, "_source")
  350. fieldDataFields, err := json.Get("fielddata_fields").StringArray()
  351. So(err, ShouldBeNil)
  352. So(fieldDataFields, ShouldHaveLength, 1)
  353. So(fieldDataFields[0], ShouldEqual, timeField)
  354. })
  355. })
  356. })
  357. })
  358. })
  359. }
  360. func TestMultiSearchRequest(t *testing.T) {
  361. Convey("Test elasticsearch multi search request", t, func() {
  362. Convey("Given new multi search request builder", func() {
  363. b := NewMultiSearchRequestBuilder(0)
  364. Convey("When adding one search request", func() {
  365. b.Search(tsdb.Interval{Value: 15 * time.Second, Text: "15s"})
  366. Convey("When building search request should contain one search request", func() {
  367. mr, err := b.Build()
  368. So(err, ShouldBeNil)
  369. So(mr.Requests, ShouldHaveLength, 1)
  370. })
  371. })
  372. Convey("When adding two search requests", func() {
  373. b.Search(tsdb.Interval{Value: 15 * time.Second, Text: "15s"})
  374. b.Search(tsdb.Interval{Value: 15 * time.Second, Text: "15s"})
  375. Convey("When building search request should contain two search requests", func() {
  376. mr, err := b.Build()
  377. So(err, ShouldBeNil)
  378. So(mr.Requests, ShouldHaveLength, 2)
  379. })
  380. })
  381. })
  382. })
  383. }