You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

819 lines
18 KiB

  1. // Copyright 2013 Belogik. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package goes
  5. import (
  6. . "launchpad.net/gocheck"
  7. "net/url"
  8. "os"
  9. "testing"
  10. "time"
  11. )
  12. var (
  13. ES_HOST = "localhost"
  14. ES_PORT = "9200"
  15. )
  16. // Hook up gocheck into the gotest runner.
  17. func Test(t *testing.T) { TestingT(t) }
  18. type GoesTestSuite struct{}
  19. var _ = Suite(&GoesTestSuite{})
  20. func (s *GoesTestSuite) SetUpTest(c *C) {
  21. h := os.Getenv("TEST_ELASTICSEARCH_HOST")
  22. if h != "" {
  23. ES_HOST = h
  24. }
  25. p := os.Getenv("TEST_ELASTICSEARCH_PORT")
  26. if p != "" {
  27. ES_PORT = p
  28. }
  29. }
  30. func (s *GoesTestSuite) TestNewConnection(c *C) {
  31. conn := NewConnection(ES_HOST, ES_PORT)
  32. c.Assert(conn, DeepEquals, &Connection{ES_HOST, ES_PORT})
  33. }
  34. func (s *GoesTestSuite) TestUrl(c *C) {
  35. conn := NewConnection(ES_HOST, ES_PORT)
  36. r := Request{
  37. Conn: conn,
  38. Query: "q",
  39. IndexList: []string{"i"},
  40. TypeList: []string{},
  41. method: "GET",
  42. api: "_search",
  43. }
  44. c.Assert(r.Url(), Equals, "http://"+ES_HOST+":"+ES_PORT+"/i/_search")
  45. r.IndexList = []string{"a", "b"}
  46. c.Assert(r.Url(), Equals, "http://"+ES_HOST+":"+ES_PORT+"/a,b/_search")
  47. r.TypeList = []string{"c", "d"}
  48. c.Assert(r.Url(), Equals, "http://"+ES_HOST+":"+ES_PORT+"/a,b/c,d/_search")
  49. r.ExtraArgs = make(url.Values, 1)
  50. r.ExtraArgs.Set("version", "1")
  51. c.Assert(r.Url(), Equals, "http://"+ES_HOST+":"+ES_PORT+"/a,b/c,d/_search?version=1")
  52. r.id = "1234"
  53. r.api = ""
  54. c.Assert(r.Url(), Equals, "http://"+ES_HOST+":"+ES_PORT+"/a,b/c,d/1234/?version=1")
  55. }
  56. func (s *GoesTestSuite) TestEsDown(c *C) {
  57. conn := NewConnection("a.b.c.d", "1234")
  58. var query = map[string]interface{}{"query": "foo"}
  59. r := Request{
  60. Conn: conn,
  61. Query: query,
  62. IndexList: []string{"i"},
  63. method: "GET",
  64. api: "_search",
  65. }
  66. _, err := r.Run()
  67. c.Assert(err, ErrorMatches, "Get http://a.b.c.d:1234/i/_search:(.*)lookup a.b.c.d: no such host")
  68. }
  69. func (s *GoesTestSuite) TestRunMissingIndex(c *C) {
  70. conn := NewConnection(ES_HOST, ES_PORT)
  71. var query = map[string]interface{}{"query": "foo"}
  72. r := Request{
  73. Conn: conn,
  74. Query: query,
  75. IndexList: []string{"i"},
  76. method: "GET",
  77. api: "_search",
  78. }
  79. _, err := r.Run()
  80. c.Assert(err.Error(), Equals, "[404] IndexMissingException[[i] missing]")
  81. }
  82. func (s *GoesTestSuite) TestCreateIndex(c *C) {
  83. indexName := "testcreateindexgoes"
  84. conn := NewConnection(ES_HOST, ES_PORT)
  85. defer conn.DeleteIndex(indexName)
  86. mapping := map[string]interface{}{
  87. "settings": map[string]interface{}{
  88. "index.number_of_shards": 1,
  89. "index.number_of_replicas": 0,
  90. },
  91. "mappings": map[string]interface{}{
  92. "_default_": map[string]interface{}{
  93. "_source": map[string]interface{}{
  94. "enabled": false,
  95. },
  96. "_all": map[string]interface{}{
  97. "enabled": false,
  98. },
  99. },
  100. },
  101. }
  102. resp, err := conn.CreateIndex(indexName, mapping)
  103. c.Assert(err, IsNil)
  104. c.Assert(resp.Acknowledged, Equals, true)
  105. }
  106. func (s *GoesTestSuite) TestDeleteIndexInexistantIndex(c *C) {
  107. conn := NewConnection(ES_HOST, ES_PORT)
  108. resp, err := conn.DeleteIndex("foobar")
  109. c.Assert(err.Error(), Equals, "[404] IndexMissingException[[foobar] missing]")
  110. c.Assert(resp, DeepEquals, Response{})
  111. }
  112. func (s *GoesTestSuite) TestDeleteIndexExistingIndex(c *C) {
  113. conn := NewConnection(ES_HOST, ES_PORT)
  114. indexName := "testdeleteindexexistingindex"
  115. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  116. c.Assert(err, IsNil)
  117. resp, err := conn.DeleteIndex(indexName)
  118. c.Assert(err, IsNil)
  119. expectedResponse := Response{}
  120. expectedResponse.Acknowledged = true
  121. c.Assert(resp, DeepEquals, expectedResponse)
  122. }
  123. func (s *GoesTestSuite) TestRefreshIndex(c *C) {
  124. conn := NewConnection(ES_HOST, ES_PORT)
  125. indexName := "testrefreshindex"
  126. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  127. c.Assert(err, IsNil)
  128. _, err = conn.RefreshIndex(indexName)
  129. c.Assert(err, IsNil)
  130. _, err = conn.DeleteIndex(indexName)
  131. c.Assert(err, IsNil)
  132. }
  133. func (s *GoesTestSuite) TestBulkSend(c *C) {
  134. indexName := "testbulkadd"
  135. docType := "tweet"
  136. tweets := []Document{
  137. Document{
  138. Id: "123",
  139. Index: nil,
  140. Type: docType,
  141. BulkCommand: BULK_COMMAND_INDEX,
  142. Fields: map[string]interface{}{
  143. "user": "foo",
  144. "message": "some foo message",
  145. },
  146. },
  147. Document{
  148. Id: nil,
  149. Index: indexName,
  150. Type: docType,
  151. BulkCommand: BULK_COMMAND_INDEX,
  152. Fields: map[string]interface{}{
  153. "user": "bar",
  154. "message": "some bar message",
  155. },
  156. },
  157. }
  158. conn := NewConnection(ES_HOST, ES_PORT)
  159. _, err := conn.CreateIndex(indexName, nil)
  160. c.Assert(err, IsNil)
  161. response, err := conn.BulkSend(indexName, tweets)
  162. i := Item{
  163. Id: "123",
  164. Type: docType,
  165. Version: 1,
  166. Index: indexName,
  167. }
  168. c.Assert(response.Items[0][BULK_COMMAND_INDEX], Equals, i)
  169. c.Assert(err, IsNil)
  170. _, err = conn.RefreshIndex(indexName)
  171. c.Assert(err, IsNil)
  172. var query = map[string]interface{}{
  173. "query": map[string]interface{}{
  174. "match_all": map[string]interface{}{},
  175. },
  176. }
  177. searchResults, err := conn.Search(query, []string{indexName}, []string{}, url.Values{})
  178. c.Assert(err, IsNil)
  179. var expectedTotal uint64 = 2
  180. c.Assert(searchResults.Hits.Total, Equals, expectedTotal)
  181. extraDocId := ""
  182. checked := 0
  183. for _, hit := range searchResults.Hits.Hits {
  184. if hit.Source["user"] == "foo" {
  185. c.Assert(hit.Id, Equals, "123")
  186. checked++
  187. }
  188. if hit.Source["user"] == "bar" {
  189. c.Assert(len(hit.Id) > 0, Equals, true)
  190. extraDocId = hit.Id
  191. checked++
  192. }
  193. }
  194. c.Assert(checked, Equals, 2)
  195. docToDelete := []Document{
  196. Document{
  197. Id: "123",
  198. Index: indexName,
  199. Type: docType,
  200. BulkCommand: BULK_COMMAND_DELETE,
  201. },
  202. Document{
  203. Id: extraDocId,
  204. Index: indexName,
  205. Type: docType,
  206. BulkCommand: BULK_COMMAND_DELETE,
  207. },
  208. }
  209. response, err = conn.BulkSend(indexName, docToDelete)
  210. i = Item{
  211. Id: "123",
  212. Type: docType,
  213. Version: 2,
  214. Index: indexName,
  215. }
  216. c.Assert(response.Items[0][BULK_COMMAND_DELETE], Equals, i)
  217. c.Assert(err, IsNil)
  218. _, err = conn.RefreshIndex(indexName)
  219. c.Assert(err, IsNil)
  220. searchResults, err = conn.Search(query, []string{indexName}, []string{}, url.Values{})
  221. c.Assert(err, IsNil)
  222. expectedTotal = 0
  223. c.Assert(searchResults.Hits.Total, Equals, expectedTotal)
  224. _, err = conn.DeleteIndex(indexName)
  225. c.Assert(err, IsNil)
  226. }
  227. func (s *GoesTestSuite) TestStats(c *C) {
  228. conn := NewConnection(ES_HOST, ES_PORT)
  229. indexName := "teststats"
  230. conn.DeleteIndex(indexName)
  231. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  232. c.Assert(err, IsNil)
  233. // we must wait for a bit otherwise ES crashes
  234. time.Sleep(1 * time.Second)
  235. response, err := conn.Stats([]string{indexName}, url.Values{})
  236. c.Assert(err, IsNil)
  237. c.Assert(response.All.Indices[indexName].Primaries["docs"].Count, Equals, 0)
  238. _, err = conn.DeleteIndex(indexName)
  239. c.Assert(err, IsNil)
  240. }
  241. func (s *GoesTestSuite) TestIndexIdDefined(c *C) {
  242. indexName := "testindexiddefined"
  243. docType := "tweet"
  244. docId := "1234"
  245. conn := NewConnection(ES_HOST, ES_PORT)
  246. // just in case
  247. conn.DeleteIndex(indexName)
  248. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  249. c.Assert(err, IsNil)
  250. defer conn.DeleteIndex(indexName)
  251. d := Document{
  252. Index: indexName,
  253. Type: docType,
  254. Id: docId,
  255. Fields: map[string]interface{}{
  256. "user": "foo",
  257. "message": "bar",
  258. },
  259. }
  260. extraArgs := make(url.Values, 1)
  261. extraArgs.Set("ttl", "86400000")
  262. response, err := conn.Index(d, extraArgs)
  263. c.Assert(err, IsNil)
  264. expectedResponse := Response{
  265. Index: indexName,
  266. Id: docId,
  267. Type: docType,
  268. Version: 1,
  269. }
  270. c.Assert(response, DeepEquals, expectedResponse)
  271. }
  272. func (s *GoesTestSuite) TestIndexIdNotDefined(c *C) {
  273. indexName := "testindexidnotdefined"
  274. docType := "tweet"
  275. conn := NewConnection(ES_HOST, ES_PORT)
  276. // just in case
  277. conn.DeleteIndex(indexName)
  278. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  279. c.Assert(err, IsNil)
  280. defer conn.DeleteIndex(indexName)
  281. d := Document{
  282. Index: indexName,
  283. Type: docType,
  284. Fields: map[string]interface{}{
  285. "user": "foo",
  286. "message": "bar",
  287. },
  288. }
  289. response, err := conn.Index(d, url.Values{})
  290. c.Assert(err, IsNil)
  291. c.Assert(response.Index, Equals, indexName)
  292. c.Assert(response.Type, Equals, docType)
  293. c.Assert(response.Version, Equals, 1)
  294. c.Assert(response.Id != "", Equals, true)
  295. }
  296. func (s *GoesTestSuite) TestDelete(c *C) {
  297. indexName := "testdelete"
  298. docType := "tweet"
  299. docId := "1234"
  300. conn := NewConnection(ES_HOST, ES_PORT)
  301. // just in case
  302. conn.DeleteIndex(indexName)
  303. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  304. c.Assert(err, IsNil)
  305. defer conn.DeleteIndex(indexName)
  306. d := Document{
  307. Index: indexName,
  308. Type: docType,
  309. Id: docId,
  310. Fields: map[string]interface{}{
  311. "user": "foo",
  312. },
  313. }
  314. _, err = conn.Index(d, url.Values{})
  315. c.Assert(err, IsNil)
  316. response, err := conn.Delete(d, url.Values{})
  317. c.Assert(err, IsNil)
  318. expectedResponse := Response{
  319. Found: true,
  320. Index: indexName,
  321. Type: docType,
  322. Id: docId,
  323. // XXX : even after a DELETE the version number seems to be incremented
  324. Version: 2,
  325. }
  326. c.Assert(response, DeepEquals, expectedResponse)
  327. response, err = conn.Delete(d, url.Values{})
  328. c.Assert(err, IsNil)
  329. expectedResponse = Response{
  330. Found: false,
  331. Index: indexName,
  332. Type: docType,
  333. Id: docId,
  334. // XXX : even after a DELETE the version number seems to be incremented
  335. Version: 3,
  336. }
  337. c.Assert(response, DeepEquals, expectedResponse)
  338. }
  339. func (s *GoesTestSuite) TestGet(c *C) {
  340. indexName := "testget"
  341. docType := "tweet"
  342. docId := "111"
  343. source := map[string]interface{}{
  344. "f1": "foo",
  345. "f2": "foo",
  346. }
  347. conn := NewConnection(ES_HOST, ES_PORT)
  348. conn.DeleteIndex(indexName)
  349. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  350. c.Assert(err, IsNil)
  351. defer conn.DeleteIndex(indexName)
  352. d := Document{
  353. Index: indexName,
  354. Type: docType,
  355. Id: docId,
  356. Fields: source,
  357. }
  358. _, err = conn.Index(d, url.Values{})
  359. c.Assert(err, IsNil)
  360. response, err := conn.Get(indexName, docType, docId, url.Values{})
  361. c.Assert(err, IsNil)
  362. expectedResponse := Response{
  363. Index: indexName,
  364. Type: docType,
  365. Id: docId,
  366. Version: 1,
  367. Found: true,
  368. Source: source,
  369. }
  370. c.Assert(response, DeepEquals, expectedResponse)
  371. fields := make(url.Values, 1)
  372. fields.Set("fields", "f1")
  373. response, err = conn.Get(indexName, docType, docId, fields)
  374. c.Assert(err, IsNil)
  375. expectedResponse = Response{
  376. Index: indexName,
  377. Type: docType,
  378. Id: docId,
  379. Version: 1,
  380. Found: true,
  381. Fields: map[string]interface{}{
  382. "f1": []interface{}{"foo"},
  383. },
  384. }
  385. c.Assert(response, DeepEquals, expectedResponse)
  386. }
  387. func (s *GoesTestSuite) TestSearch(c *C) {
  388. indexName := "testsearch"
  389. docType := "tweet"
  390. docId := "1234"
  391. source := map[string]interface{}{
  392. "user": "foo",
  393. "message": "bar",
  394. }
  395. conn := NewConnection(ES_HOST, ES_PORT)
  396. conn.DeleteIndex(indexName)
  397. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  398. c.Assert(err, IsNil)
  399. defer conn.DeleteIndex(indexName)
  400. d := Document{
  401. Index: indexName,
  402. Type: docType,
  403. Id: docId,
  404. Fields: source,
  405. }
  406. _, err = conn.Index(d, url.Values{})
  407. c.Assert(err, IsNil)
  408. _, err = conn.RefreshIndex(indexName)
  409. c.Assert(err, IsNil)
  410. // I can feel my eyes bleeding
  411. query := map[string]interface{}{
  412. "query": map[string]interface{}{
  413. "bool": map[string]interface{}{
  414. "must": []map[string]interface{}{
  415. map[string]interface{}{
  416. "match_all": map[string]interface{}{},
  417. },
  418. },
  419. },
  420. },
  421. }
  422. response, err := conn.Search(query, []string{indexName}, []string{docType}, url.Values{})
  423. expectedHits := Hits{
  424. Total: 1,
  425. MaxScore: 1.0,
  426. Hits: []Hit{
  427. Hit{
  428. Index: indexName,
  429. Type: docType,
  430. Id: docId,
  431. Score: 1.0,
  432. Source: source,
  433. },
  434. },
  435. }
  436. c.Assert(response.Hits, DeepEquals, expectedHits)
  437. }
  438. func (s *GoesTestSuite) TestIndexStatus(c *C) {
  439. indexName := "testindexstatus"
  440. conn := NewConnection(ES_HOST, ES_PORT)
  441. conn.DeleteIndex(indexName)
  442. mapping := map[string]interface{}{
  443. "settings": map[string]interface{}{
  444. "index.number_of_shards": 1,
  445. "index.number_of_replicas": 1,
  446. },
  447. }
  448. _, err := conn.CreateIndex(indexName, mapping)
  449. c.Assert(err, IsNil)
  450. defer conn.DeleteIndex(indexName)
  451. // gives ES some time to do its job
  452. time.Sleep(1 * time.Second)
  453. response, err := conn.IndexStatus([]string{"_all"})
  454. c.Assert(err, IsNil)
  455. expectedShards := Shard{Total: 2, Successful: 1, Failed: 0}
  456. c.Assert(response.Shards, Equals, expectedShards)
  457. expectedIndices := map[string]IndexStatus{
  458. indexName: IndexStatus{
  459. Index: map[string]interface{}{
  460. "primary_size_in_bytes": float64(99),
  461. "size_in_bytes": float64(99),
  462. },
  463. Translog: map[string]uint64{
  464. "operations": 0,
  465. },
  466. Docs: map[string]uint64{
  467. "num_docs": 0,
  468. "max_doc": 0,
  469. "deleted_docs": 0,
  470. },
  471. Merges: map[string]interface{}{
  472. "current": float64(0),
  473. "current_docs": float64(0),
  474. "current_size_in_bytes": float64(0),
  475. "total": float64(0),
  476. "total_time_in_millis": float64(0),
  477. "total_docs": float64(0),
  478. "total_size_in_bytes": float64(0),
  479. },
  480. Refresh: map[string]interface{}{
  481. "total": float64(1),
  482. "total_time_in_millis": float64(0),
  483. },
  484. Flush: map[string]interface{}{
  485. "total": float64(0),
  486. "total_time_in_millis": float64(0),
  487. },
  488. },
  489. }
  490. c.Assert(response.Indices, DeepEquals, expectedIndices)
  491. }
  492. func (s *GoesTestSuite) TestScroll(c *C) {
  493. indexName := "testscroll"
  494. docType := "tweet"
  495. tweets := []Document{
  496. Document{
  497. Id: nil,
  498. Index: indexName,
  499. Type: docType,
  500. BulkCommand: BULK_COMMAND_INDEX,
  501. Fields: map[string]interface{}{
  502. "user": "foo",
  503. "message": "some foo message",
  504. },
  505. },
  506. Document{
  507. Id: nil,
  508. Index: indexName,
  509. Type: docType,
  510. BulkCommand: BULK_COMMAND_INDEX,
  511. Fields: map[string]interface{}{
  512. "user": "bar",
  513. "message": "some bar message",
  514. },
  515. },
  516. Document{
  517. Id: nil,
  518. Index: indexName,
  519. Type: docType,
  520. BulkCommand: BULK_COMMAND_INDEX,
  521. Fields: map[string]interface{}{
  522. "user": "foo",
  523. "message": "another foo message",
  524. },
  525. },
  526. }
  527. conn := NewConnection(ES_HOST, ES_PORT)
  528. mapping := map[string]interface{}{
  529. "settings": map[string]interface{}{
  530. "index.number_of_shards": 1,
  531. "index.number_of_replicas": 0,
  532. },
  533. }
  534. defer conn.DeleteIndex(indexName)
  535. _, err := conn.CreateIndex(indexName, mapping)
  536. c.Assert(err, IsNil)
  537. _, err = conn.BulkSend(indexName, tweets)
  538. c.Assert(err, IsNil)
  539. _, err = conn.RefreshIndex(indexName)
  540. c.Assert(err, IsNil)
  541. query := map[string]interface{}{
  542. "query": map[string]interface{}{
  543. "filtered": map[string]interface{}{
  544. "filter": map[string]interface{}{
  545. "term": map[string]interface{}{
  546. "user": "foo",
  547. },
  548. },
  549. },
  550. },
  551. }
  552. scan, err := conn.Scan(query, []string{indexName}, []string{docType}, "1m", 1)
  553. c.Assert(err, IsNil)
  554. c.Assert(len(scan.ScrollId) > 0, Equals, true)
  555. searchResults, err := conn.Scroll(scan.ScrollId, "1m")
  556. c.Assert(err, IsNil)
  557. // some data in first chunk
  558. c.Assert(searchResults.Hits.Total, Equals, uint64(2))
  559. c.Assert(len(searchResults.ScrollId) > 0, Equals, true)
  560. c.Assert(len(searchResults.Hits.Hits), Equals, 1)
  561. searchResults, err = conn.Scroll(searchResults.ScrollId, "1m")
  562. c.Assert(err, IsNil)
  563. // more data in second chunk
  564. c.Assert(searchResults.Hits.Total, Equals, uint64(2))
  565. c.Assert(len(searchResults.ScrollId) > 0, Equals, true)
  566. c.Assert(len(searchResults.Hits.Hits), Equals, 1)
  567. searchResults, err = conn.Scroll(searchResults.ScrollId, "1m")
  568. c.Assert(err, IsNil)
  569. // nothing in third chunk
  570. c.Assert(searchResults.Hits.Total, Equals, uint64(2))
  571. c.Assert(len(searchResults.ScrollId) > 0, Equals, true)
  572. c.Assert(len(searchResults.Hits.Hits), Equals, 0)
  573. }
  574. func (s *GoesTestSuite) TestAggregations(c *C) {
  575. indexName := "testaggs"
  576. docType := "tweet"
  577. tweets := []Document{
  578. Document{
  579. Id: nil,
  580. Index: indexName,
  581. Type: docType,
  582. BulkCommand: BULK_COMMAND_INDEX,
  583. Fields: map[string]interface{}{
  584. "user" : "foo",
  585. "message" : "some foo message",
  586. "age" : 25,
  587. },
  588. },
  589. Document{
  590. Id: nil,
  591. Index: indexName,
  592. Type: docType,
  593. BulkCommand: BULK_COMMAND_INDEX,
  594. Fields: map[string]interface{}{
  595. "user" : "bar",
  596. "message" : "some bar message",
  597. "age" : 30,
  598. },
  599. },
  600. Document{
  601. Id: nil,
  602. Index: indexName,
  603. Type: docType,
  604. BulkCommand: BULK_COMMAND_INDEX,
  605. Fields: map[string]interface{}{
  606. "user" : "foo",
  607. "message" : "another foo message",
  608. },
  609. },
  610. }
  611. conn := NewConnection(ES_HOST, ES_PORT)
  612. mapping := map[string]interface{}{
  613. "settings": map[string]interface{}{
  614. "index.number_of_shards": 1,
  615. "index.number_of_replicas": 0,
  616. },
  617. }
  618. defer conn.DeleteIndex(indexName)
  619. _, err := conn.CreateIndex(indexName, mapping)
  620. c.Assert(err, IsNil)
  621. _, err = conn.BulkSend(indexName, tweets)
  622. c.Assert(err, IsNil)
  623. _, err = conn.RefreshIndex(indexName)
  624. c.Assert(err, IsNil)
  625. query := map[string]interface{}{
  626. "aggs": map[string]interface{}{
  627. "user": map[string]interface{}{
  628. "terms": map[string]interface{}{
  629. "field": "user",
  630. "order": map[string]interface{}{
  631. "_term": "asc",
  632. },
  633. },
  634. "aggs": map[string]interface{}{
  635. "age": map[string]interface{}{
  636. "stats": map[string]interface{}{
  637. "field": "age",
  638. },
  639. },
  640. },
  641. },
  642. "age": map[string]interface{}{
  643. "stats": map[string]interface{}{
  644. "field": "age",
  645. },
  646. },
  647. },
  648. }
  649. resp, err := conn.Search(query, []string{indexName}, []string{docType}, url.Values{})
  650. user, ok := resp.Aggregations["user"]
  651. c.Assert(ok, Equals, true)
  652. c.Assert(len(user.Buckets()), Equals, 2)
  653. c.Assert(user.Buckets()[0].Key(), Equals, "bar")
  654. c.Assert(user.Buckets()[1].Key(), Equals, "foo")
  655. barAge := user.Buckets()[0].Aggregation("age")
  656. c.Assert(barAge["count"], Equals, 1.0)
  657. c.Assert(barAge["sum"], Equals, 30.0)
  658. fooAge := user.Buckets()[1].Aggregation("age")
  659. c.Assert(fooAge["count"], Equals, 1.0)
  660. c.Assert(fooAge["sum"], Equals, 25.0)
  661. age, ok := resp.Aggregations["age"]
  662. c.Assert(ok, Equals, true)
  663. c.Assert(age["count"], Equals, 2.0)
  664. c.Assert(age["sum"], Equals, 25.0 + 30.0)
  665. }