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.
 
 
 

554 lines
12 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.Error(), Equals, "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) TestFetchStats(c *C) {
  233. conn := NewConnection(ES_HOST, ES_PORT)
  234. indexName := "testfetchstats"
  235. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  236. c.Assert(err, IsNil)
  237. // we must wait for a bit otherwise ES crashes
  238. time.Sleep(1 * time.Second)
  239. response, err := conn.FetchStats()
  240. c.Assert(err, IsNil)
  241. c.Assert(response.All.Indices[indexName].Primaries["docs"].Count, Equals, 0)
  242. _, err = conn.DeleteIndex(indexName)
  243. c.Assert(err, IsNil)
  244. }
  245. func (s *GoesTestSuite) TestIndexIdDefined(c *C) {
  246. indexName := "testindexiddefined"
  247. docType := "tweet"
  248. docId := "1234"
  249. conn := NewConnection(ES_HOST, ES_PORT)
  250. // just in case
  251. conn.DeleteIndex(indexName)
  252. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  253. c.Assert(err, IsNil)
  254. defer conn.DeleteIndex(indexName)
  255. d := Document{
  256. Index: indexName,
  257. Type: docType,
  258. Id: docId,
  259. Fields: map[string]interface{}{
  260. "user": "foo",
  261. "message": "bar",
  262. },
  263. }
  264. extraArgs := make(url.Values, 1)
  265. extraArgs.Set("ttl", "86400000")
  266. response, err := conn.Index(d, extraArgs)
  267. c.Assert(err, IsNil)
  268. expectedResponse := Response{
  269. Ok: true,
  270. Index: indexName,
  271. Id: docId,
  272. Type: docType,
  273. Version: 1,
  274. }
  275. c.Assert(response, DeepEquals, expectedResponse)
  276. }
  277. func (s *GoesTestSuite) TestIndexIdNotDefined(c *C) {
  278. indexName := "testindexidnotdefined"
  279. docType := "tweet"
  280. conn := NewConnection(ES_HOST, ES_PORT)
  281. // just in case
  282. conn.DeleteIndex(indexName)
  283. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  284. c.Assert(err, IsNil)
  285. defer conn.DeleteIndex(indexName)
  286. d := Document{
  287. Index: indexName,
  288. Type: docType,
  289. Fields: map[string]interface{}{
  290. "user": "foo",
  291. "message": "bar",
  292. },
  293. }
  294. response, err := conn.Index(d, url.Values{})
  295. c.Assert(err, IsNil)
  296. c.Assert(response.Ok, Equals, true)
  297. c.Assert(response.Index, Equals, indexName)
  298. c.Assert(response.Type, Equals, docType)
  299. c.Assert(response.Version, Equals, 1)
  300. c.Assert(response.Id != "", Equals, true)
  301. }
  302. func (s *GoesTestSuite) TestDelete(c *C) {
  303. indexName := "testdelete"
  304. docType := "tweet"
  305. docId := "1234"
  306. conn := NewConnection(ES_HOST, ES_PORT)
  307. // just in case
  308. conn.DeleteIndex(indexName)
  309. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  310. c.Assert(err, IsNil)
  311. defer conn.DeleteIndex(indexName)
  312. d := Document{
  313. Index: indexName,
  314. Type: docType,
  315. Id: docId,
  316. Fields: map[string]interface{}{
  317. "user": "foo",
  318. },
  319. }
  320. _, err = conn.Index(d, url.Values{})
  321. c.Assert(err, IsNil)
  322. response, err := conn.Delete(d, url.Values{})
  323. c.Assert(err, IsNil)
  324. expectedResponse := Response{
  325. Ok: true,
  326. Found: true,
  327. Index: indexName,
  328. Type: docType,
  329. Id: docId,
  330. // XXX : even after a DELETE the version number seems to be incremented
  331. Version: 2,
  332. }
  333. c.Assert(response, DeepEquals, expectedResponse)
  334. response, err = conn.Delete(d, url.Values{})
  335. c.Assert(err, IsNil)
  336. expectedResponse = Response{
  337. Ok: true,
  338. Found: false,
  339. Index: indexName,
  340. Type: docType,
  341. Id: docId,
  342. // XXX : even after a DELETE the version number seems to be incremented
  343. Version: 3,
  344. }
  345. c.Assert(response, DeepEquals, expectedResponse)
  346. }
  347. func (s *GoesTestSuite) TestGet(c *C) {
  348. indexName := "testget"
  349. docType := "tweet"
  350. docId := "111"
  351. source := map[string]interface{}{
  352. "f1": "foo",
  353. "f2": "foo",
  354. }
  355. conn := NewConnection(ES_HOST, ES_PORT)
  356. conn.DeleteIndex(indexName)
  357. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  358. c.Assert(err, IsNil)
  359. defer conn.DeleteIndex(indexName)
  360. d := Document{
  361. Index: indexName,
  362. Type: docType,
  363. Id: docId,
  364. Fields: source,
  365. }
  366. _, err = conn.Index(d, url.Values{})
  367. c.Assert(err, IsNil)
  368. response, err := conn.Get(indexName, docType, docId, url.Values{})
  369. c.Assert(err, IsNil)
  370. expectedResponse := Response{
  371. Index: indexName,
  372. Type: docType,
  373. Id: docId,
  374. Version: 1,
  375. Exists: true,
  376. Source: source,
  377. }
  378. c.Assert(response, DeepEquals, expectedResponse)
  379. fields := make(url.Values, 1)
  380. fields.Set("fields", "f1")
  381. response, err = conn.Get(indexName, docType, docId, fields)
  382. c.Assert(err, IsNil)
  383. expectedResponse = Response{
  384. Index: indexName,
  385. Type: docType,
  386. Id: docId,
  387. Version: 1,
  388. Exists: true,
  389. Fields: map[string]interface{}{
  390. "f1": "foo",
  391. },
  392. }
  393. c.Assert(response, DeepEquals, expectedResponse)
  394. }
  395. func (s *GoesTestSuite) TestSearch(c *C) {
  396. indexName := "testsearch"
  397. docType := "tweet"
  398. docId := "1234"
  399. source := map[string]interface{}{
  400. "user": "foo",
  401. "message": "bar",
  402. }
  403. conn := NewConnection(ES_HOST, ES_PORT)
  404. conn.DeleteIndex(indexName)
  405. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  406. c.Assert(err, IsNil)
  407. //defer conn.DeleteIndex(indexName)
  408. d := Document{
  409. Index: indexName,
  410. Type: docType,
  411. Id: docId,
  412. Fields: source,
  413. }
  414. _, err = conn.Index(d, url.Values{})
  415. c.Assert(err, IsNil)
  416. _, err = conn.RefreshIndex(indexName)
  417. c.Assert(err, IsNil)
  418. // I can feel my eyes bleeding
  419. query := map[string]interface{}{
  420. "query": map[string]interface{}{
  421. "bool": map[string]interface{}{
  422. "must": []map[string]interface{}{
  423. map[string]interface{}{
  424. "match_all": map[string]interface{}{},
  425. },
  426. },
  427. },
  428. },
  429. }
  430. response, err := conn.Search(query, []string{indexName}, []string{docType})
  431. expectedHits := Hits{
  432. Total: 1,
  433. MaxScore: 1.0,
  434. Hits: []Hit{
  435. Hit{
  436. Index: indexName,
  437. Type: docType,
  438. Id: docId,
  439. Score: 1.0,
  440. Source: source,
  441. },
  442. },
  443. }
  444. c.Assert(response.Hits, DeepEquals, expectedHits)
  445. }