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.
 
 
 

726 lines
16 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.Ok, Equals, true)
  105. c.Assert(resp.Acknowledged, Equals, true)
  106. }
  107. func (s *GoesTestSuite) TestDeleteIndexInexistantIndex(c *C) {
  108. conn := NewConnection(ES_HOST, ES_PORT)
  109. resp, err := conn.DeleteIndex("foobar")
  110. c.Assert(err.Error(), Equals, "[404] IndexMissingException[[foobar] missing]")
  111. c.Assert(resp, DeepEquals, Response{})
  112. }
  113. func (s *GoesTestSuite) TestDeleteIndexExistingIndex(c *C) {
  114. conn := NewConnection(ES_HOST, ES_PORT)
  115. indexName := "testdeleteindexexistingindex"
  116. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  117. c.Assert(err, IsNil)
  118. resp, err := conn.DeleteIndex(indexName)
  119. c.Assert(err, IsNil)
  120. expectedResponse := Response{}
  121. expectedResponse.Ok = true
  122. expectedResponse.Acknowledged = true
  123. c.Assert(resp, DeepEquals, expectedResponse)
  124. }
  125. func (s *GoesTestSuite) TestRefreshIndex(c *C) {
  126. conn := NewConnection(ES_HOST, ES_PORT)
  127. indexName := "testrefreshindex"
  128. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  129. c.Assert(err, IsNil)
  130. resp, err := conn.RefreshIndex(indexName)
  131. c.Assert(err, IsNil)
  132. c.Assert(resp.Ok, Equals, true)
  133. _, err = conn.DeleteIndex(indexName)
  134. c.Assert(err, IsNil)
  135. }
  136. func (s *GoesTestSuite) TestBulkSend(c *C) {
  137. indexName := "testbulkadd"
  138. docType := "tweet"
  139. tweets := []Document{
  140. Document{
  141. Id: "123",
  142. Index: nil,
  143. Type: docType,
  144. BulkCommand: BULK_COMMAND_INDEX,
  145. Fields: map[string]interface{}{
  146. "user": "foo",
  147. "message": "some foo message",
  148. },
  149. },
  150. Document{
  151. Id: nil,
  152. Index: indexName,
  153. Type: docType,
  154. BulkCommand: BULK_COMMAND_INDEX,
  155. Fields: map[string]interface{}{
  156. "user": "bar",
  157. "message": "some bar message",
  158. },
  159. },
  160. }
  161. conn := NewConnection(ES_HOST, ES_PORT)
  162. _, err := conn.CreateIndex(indexName, nil)
  163. c.Assert(err, IsNil)
  164. response, err := conn.BulkSend(indexName, tweets)
  165. i := Item{
  166. Ok: true,
  167. Id: "123",
  168. Type: docType,
  169. Version: 1,
  170. Index: indexName,
  171. }
  172. c.Assert(response.Items[0][BULK_COMMAND_INDEX], Equals, i)
  173. c.Assert(err, IsNil)
  174. _, err = conn.RefreshIndex(indexName)
  175. c.Assert(err, IsNil)
  176. var query = map[string]interface{}{
  177. "query": map[string]interface{}{
  178. "match_all": map[string]interface{}{},
  179. },
  180. }
  181. searchResults, err := conn.Search(query, []string{indexName}, []string{})
  182. c.Assert(err, IsNil)
  183. var expectedTotal uint64 = 2
  184. c.Assert(searchResults.Hits.Total, Equals, expectedTotal)
  185. extraDocId := ""
  186. checked := 0
  187. for _, hit := range searchResults.Hits.Hits {
  188. if hit.Source["user"] == "foo" {
  189. c.Assert(hit.Id, Equals, "123")
  190. checked++
  191. }
  192. if hit.Source["user"] == "bar" {
  193. c.Assert(len(hit.Id) > 0, Equals, true)
  194. extraDocId = hit.Id
  195. checked++
  196. }
  197. }
  198. c.Assert(checked, Equals, 2)
  199. docToDelete := []Document{
  200. Document{
  201. Id: "123",
  202. Index: indexName,
  203. Type: docType,
  204. BulkCommand: BULK_COMMAND_DELETE,
  205. },
  206. Document{
  207. Id: extraDocId,
  208. Index: indexName,
  209. Type: docType,
  210. BulkCommand: BULK_COMMAND_DELETE,
  211. },
  212. }
  213. response, err = conn.BulkSend(indexName, docToDelete)
  214. i = Item{
  215. Ok: true,
  216. Id: "123",
  217. Type: docType,
  218. Version: 2,
  219. Index: indexName,
  220. }
  221. c.Assert(response.Items[0][BULK_COMMAND_DELETE], Equals, i)
  222. c.Assert(err, IsNil)
  223. _, err = conn.RefreshIndex(indexName)
  224. c.Assert(err, IsNil)
  225. searchResults, err = conn.Search(query, []string{indexName}, []string{})
  226. c.Assert(err, IsNil)
  227. expectedTotal = 0
  228. c.Assert(searchResults.Hits.Total, Equals, expectedTotal)
  229. _, err = conn.DeleteIndex(indexName)
  230. c.Assert(err, IsNil)
  231. }
  232. func (s *GoesTestSuite) TestStats(c *C) {
  233. conn := NewConnection(ES_HOST, ES_PORT)
  234. indexName := "teststats"
  235. conn.DeleteIndex(indexName)
  236. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  237. c.Assert(err, IsNil)
  238. // we must wait for a bit otherwise ES crashes
  239. time.Sleep(1 * time.Second)
  240. response, err := conn.Stats([]string{indexName}, url.Values{})
  241. c.Assert(err, IsNil)
  242. c.Assert(response.All.Indices[indexName].Primaries["docs"].Count, Equals, 0)
  243. _, err = conn.DeleteIndex(indexName)
  244. c.Assert(err, IsNil)
  245. }
  246. func (s *GoesTestSuite) TestIndexIdDefined(c *C) {
  247. indexName := "testindexiddefined"
  248. docType := "tweet"
  249. docId := "1234"
  250. conn := NewConnection(ES_HOST, ES_PORT)
  251. // just in case
  252. conn.DeleteIndex(indexName)
  253. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  254. c.Assert(err, IsNil)
  255. defer conn.DeleteIndex(indexName)
  256. d := Document{
  257. Index: indexName,
  258. Type: docType,
  259. Id: docId,
  260. Fields: map[string]interface{}{
  261. "user": "foo",
  262. "message": "bar",
  263. },
  264. }
  265. extraArgs := make(url.Values, 1)
  266. extraArgs.Set("ttl", "86400000")
  267. response, err := conn.Index(d, extraArgs)
  268. c.Assert(err, IsNil)
  269. expectedResponse := Response{
  270. Ok: true,
  271. Index: indexName,
  272. Id: docId,
  273. Type: docType,
  274. Version: 1,
  275. }
  276. c.Assert(response, DeepEquals, expectedResponse)
  277. }
  278. func (s *GoesTestSuite) TestIndexIdNotDefined(c *C) {
  279. indexName := "testindexidnotdefined"
  280. docType := "tweet"
  281. conn := NewConnection(ES_HOST, ES_PORT)
  282. // just in case
  283. conn.DeleteIndex(indexName)
  284. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  285. c.Assert(err, IsNil)
  286. defer conn.DeleteIndex(indexName)
  287. d := Document{
  288. Index: indexName,
  289. Type: docType,
  290. Fields: map[string]interface{}{
  291. "user": "foo",
  292. "message": "bar",
  293. },
  294. }
  295. response, err := conn.Index(d, url.Values{})
  296. c.Assert(err, IsNil)
  297. c.Assert(response.Ok, Equals, true)
  298. c.Assert(response.Index, Equals, indexName)
  299. c.Assert(response.Type, Equals, docType)
  300. c.Assert(response.Version, Equals, 1)
  301. c.Assert(response.Id != "", Equals, true)
  302. }
  303. func (s *GoesTestSuite) TestDelete(c *C) {
  304. indexName := "testdelete"
  305. docType := "tweet"
  306. docId := "1234"
  307. conn := NewConnection(ES_HOST, ES_PORT)
  308. // just in case
  309. conn.DeleteIndex(indexName)
  310. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  311. c.Assert(err, IsNil)
  312. defer conn.DeleteIndex(indexName)
  313. d := Document{
  314. Index: indexName,
  315. Type: docType,
  316. Id: docId,
  317. Fields: map[string]interface{}{
  318. "user": "foo",
  319. },
  320. }
  321. _, err = conn.Index(d, url.Values{})
  322. c.Assert(err, IsNil)
  323. response, err := conn.Delete(d, url.Values{})
  324. c.Assert(err, IsNil)
  325. expectedResponse := Response{
  326. Ok: true,
  327. Found: true,
  328. Index: indexName,
  329. Type: docType,
  330. Id: docId,
  331. // XXX : even after a DELETE the version number seems to be incremented
  332. Version: 2,
  333. }
  334. c.Assert(response, DeepEquals, expectedResponse)
  335. response, err = conn.Delete(d, url.Values{})
  336. c.Assert(err, IsNil)
  337. expectedResponse = Response{
  338. Ok: true,
  339. Found: false,
  340. Index: indexName,
  341. Type: docType,
  342. Id: docId,
  343. // XXX : even after a DELETE the version number seems to be incremented
  344. Version: 3,
  345. }
  346. c.Assert(response, DeepEquals, expectedResponse)
  347. }
  348. func (s *GoesTestSuite) TestGet(c *C) {
  349. indexName := "testget"
  350. docType := "tweet"
  351. docId := "111"
  352. source := map[string]interface{}{
  353. "f1": "foo",
  354. "f2": "foo",
  355. }
  356. conn := NewConnection(ES_HOST, ES_PORT)
  357. conn.DeleteIndex(indexName)
  358. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  359. c.Assert(err, IsNil)
  360. defer conn.DeleteIndex(indexName)
  361. d := Document{
  362. Index: indexName,
  363. Type: docType,
  364. Id: docId,
  365. Fields: source,
  366. }
  367. _, err = conn.Index(d, url.Values{})
  368. c.Assert(err, IsNil)
  369. response, err := conn.Get(indexName, docType, docId, url.Values{})
  370. c.Assert(err, IsNil)
  371. expectedResponse := Response{
  372. Index: indexName,
  373. Type: docType,
  374. Id: docId,
  375. Version: 1,
  376. Exists: true,
  377. Source: source,
  378. }
  379. c.Assert(response, DeepEquals, expectedResponse)
  380. fields := make(url.Values, 1)
  381. fields.Set("fields", "f1")
  382. response, err = conn.Get(indexName, docType, docId, fields)
  383. c.Assert(err, IsNil)
  384. expectedResponse = Response{
  385. Index: indexName,
  386. Type: docType,
  387. Id: docId,
  388. Version: 1,
  389. Exists: true,
  390. Fields: map[string]interface{}{
  391. "f1": "foo",
  392. },
  393. }
  394. c.Assert(response, DeepEquals, expectedResponse)
  395. }
  396. func (s *GoesTestSuite) TestSearch(c *C) {
  397. indexName := "testsearch"
  398. docType := "tweet"
  399. docId := "1234"
  400. source := map[string]interface{}{
  401. "user": "foo",
  402. "message": "bar",
  403. }
  404. conn := NewConnection(ES_HOST, ES_PORT)
  405. conn.DeleteIndex(indexName)
  406. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  407. c.Assert(err, IsNil)
  408. defer conn.DeleteIndex(indexName)
  409. d := Document{
  410. Index: indexName,
  411. Type: docType,
  412. Id: docId,
  413. Fields: source,
  414. }
  415. _, err = conn.Index(d, url.Values{})
  416. c.Assert(err, IsNil)
  417. _, err = conn.RefreshIndex(indexName)
  418. c.Assert(err, IsNil)
  419. // I can feel my eyes bleeding
  420. query := map[string]interface{}{
  421. "query": map[string]interface{}{
  422. "bool": map[string]interface{}{
  423. "must": []map[string]interface{}{
  424. map[string]interface{}{
  425. "match_all": map[string]interface{}{},
  426. },
  427. },
  428. },
  429. },
  430. }
  431. response, err := conn.Search(query, []string{indexName}, []string{docType})
  432. expectedHits := Hits{
  433. Total: 1,
  434. MaxScore: 1.0,
  435. Hits: []Hit{
  436. Hit{
  437. Index: indexName,
  438. Type: docType,
  439. Id: docId,
  440. Score: 1.0,
  441. Source: source,
  442. },
  443. },
  444. }
  445. c.Assert(response.Hits, DeepEquals, expectedHits)
  446. }
  447. func (s *GoesTestSuite) TestIndexStatus(c *C) {
  448. indexName := "testindexstatus"
  449. conn := NewConnection(ES_HOST, ES_PORT)
  450. conn.DeleteIndex(indexName)
  451. mapping := map[string]interface{}{
  452. "settings": map[string]interface{}{
  453. "index.number_of_shards": 1,
  454. "index.number_of_replicas": 1,
  455. },
  456. }
  457. _, err := conn.CreateIndex(indexName, mapping)
  458. c.Assert(err, IsNil)
  459. defer conn.DeleteIndex(indexName)
  460. // gives ES some time to do its job
  461. time.Sleep(1 * time.Second)
  462. response, err := conn.IndexStatus([]string{"_all"})
  463. c.Assert(err, IsNil)
  464. c.Assert(response.Ok, Equals, true)
  465. expectedShards := Shard{Total: 2, Successful: 1, Failed: 0}
  466. c.Assert(response.Shards, Equals, expectedShards)
  467. expectedIndices := map[string]IndexStatus{
  468. indexName: IndexStatus{
  469. Index: map[string]interface{}{
  470. "primary_size": "99b",
  471. "primary_size_in_bytes": float64(99),
  472. "size": "99b",
  473. "size_in_bytes": float64(99),
  474. },
  475. Translog: map[string]uint64{
  476. "operations": 0,
  477. },
  478. Docs: map[string]uint64{
  479. "num_docs": 0,
  480. "max_doc": 0,
  481. "deleted_docs": 0,
  482. },
  483. Merges: map[string]interface{}{
  484. "current": float64(0),
  485. "current_docs": float64(0),
  486. "current_size": "0b",
  487. "current_size_in_bytes": float64(0),
  488. "total": float64(0),
  489. "total_time": "0s",
  490. "total_time_in_millis": float64(0),
  491. "total_docs": float64(0),
  492. "total_size": "0b",
  493. "total_size_in_bytes": float64(0),
  494. },
  495. Refresh: map[string]interface{}{
  496. "total": float64(1),
  497. "total_time": "0s",
  498. "total_time_in_millis": float64(0),
  499. },
  500. Flush: map[string]interface{}{
  501. "total": float64(0),
  502. "total_time": "0s",
  503. "total_time_in_millis": float64(0),
  504. },
  505. },
  506. }
  507. c.Assert(response.Indices, DeepEquals, expectedIndices)
  508. }
  509. func (s *GoesTestSuite) TestScroll(c *C) {
  510. indexName := "testscroll"
  511. docType := "tweet"
  512. tweets := []Document{
  513. Document{
  514. Id: nil,
  515. Index: indexName,
  516. Type: docType,
  517. BulkCommand: BULK_COMMAND_INDEX,
  518. Fields: map[string]interface{}{
  519. "user": "foo",
  520. "message": "some foo message",
  521. },
  522. },
  523. Document{
  524. Id: nil,
  525. Index: indexName,
  526. Type: docType,
  527. BulkCommand: BULK_COMMAND_INDEX,
  528. Fields: map[string]interface{}{
  529. "user": "bar",
  530. "message": "some bar message",
  531. },
  532. },
  533. Document{
  534. Id: nil,
  535. Index: indexName,
  536. Type: docType,
  537. BulkCommand: BULK_COMMAND_INDEX,
  538. Fields: map[string]interface{}{
  539. "user": "foo",
  540. "message": "another foo message",
  541. },
  542. },
  543. }
  544. conn := NewConnection(ES_HOST, ES_PORT)
  545. mapping := map[string]interface{}{
  546. "settings": map[string]interface{}{
  547. "index.number_of_shards": 1,
  548. "index.number_of_replicas": 0,
  549. },
  550. }
  551. defer conn.DeleteIndex(indexName)
  552. _, err := conn.CreateIndex(indexName, mapping)
  553. c.Assert(err, IsNil)
  554. _, err = conn.BulkSend(indexName, tweets)
  555. c.Assert(err, IsNil)
  556. _, err = conn.RefreshIndex(indexName)
  557. c.Assert(err, IsNil)
  558. query := map[string]interface{}{
  559. "query": map[string]interface{}{
  560. "filtered": map[string]interface{}{
  561. "filter": map[string]interface{}{
  562. "term": map[string]interface{}{
  563. "user": "foo",
  564. },
  565. },
  566. },
  567. },
  568. }
  569. scan, err := conn.Scan(query, []string{indexName}, []string{docType}, "1m", 1)
  570. c.Assert(err, IsNil)
  571. c.Assert(len(scan.ScrollId) > 0, Equals, true)
  572. searchResults, err := conn.Scroll(scan.ScrollId, "1m")
  573. c.Assert(err, IsNil)
  574. // some data in first chunk
  575. c.Assert(searchResults.Hits.Total, Equals, uint64(2))
  576. c.Assert(len(searchResults.ScrollId) > 0, Equals, true)
  577. c.Assert(len(searchResults.Hits.Hits), Equals, 1)
  578. searchResults, err = conn.Scroll(searchResults.ScrollId, "1m")
  579. c.Assert(err, IsNil)
  580. // more data in second chunk
  581. c.Assert(searchResults.Hits.Total, Equals, uint64(2))
  582. c.Assert(len(searchResults.ScrollId) > 0, Equals, true)
  583. c.Assert(len(searchResults.Hits.Hits), Equals, 1)
  584. searchResults, err = conn.Scroll(searchResults.ScrollId, "1m")
  585. c.Assert(err, IsNil)
  586. // nothing in third chunk
  587. c.Assert(searchResults.Hits.Total, Equals, uint64(2))
  588. c.Assert(len(searchResults.ScrollId) > 0, Equals, true)
  589. c.Assert(len(searchResults.Hits.Hits), Equals, 0)
  590. }