index_test.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. // Copyright 2012-2015 Oliver Eilhard. All rights reserved.
  2. // Use of this source code is governed by a MIT-license.
  3. // See http://olivere.mit-license.org/license.txt for details.
  4. package elastic
  5. import (
  6. "encoding/json"
  7. "fmt"
  8. "os"
  9. "testing"
  10. "time"
  11. )
  12. const (
  13. testIndexName = "elastic-test"
  14. testIndexName2 = "elastic-test2"
  15. testMapping = `
  16. {
  17. "settings":{
  18. "number_of_shards":1,
  19. "number_of_replicas":0
  20. },
  21. "mappings":{
  22. "tweet":{
  23. "properties":{
  24. "tags":{
  25. "type":"string"
  26. },
  27. "location":{
  28. "type":"geo_point"
  29. },
  30. "suggest_field":{
  31. "type":"completion",
  32. "payloads":true
  33. }
  34. }
  35. }
  36. }
  37. }
  38. `
  39. )
  40. type tweet struct {
  41. User string `json:"user"`
  42. Message string `json:"message"`
  43. Retweets int `json:"retweets"`
  44. Image string `json:"image,omitempty"`
  45. Created time.Time `json:"created,omitempty"`
  46. Tags []string `json:"tags,omitempty"`
  47. Location string `json:"location,omitempty"`
  48. Suggest *SuggestField `json:"suggest_field,omitempty"`
  49. }
  50. func (t tweet) String() string {
  51. return fmt.Sprintf("tweet{User:%q,Message:%q,Retweets:%d}", t.User, t.Message, t.Retweets)
  52. }
  53. func isTravis() bool {
  54. return os.Getenv("TRAVIS") != ""
  55. }
  56. func travisGoVersion() string {
  57. return os.Getenv("TRAVIS_GO_VERSION")
  58. }
  59. type logger interface {
  60. Error(args ...interface{})
  61. Errorf(format string, args ...interface{})
  62. Fatal(args ...interface{})
  63. Fatalf(format string, args ...interface{})
  64. Fail()
  65. FailNow()
  66. Log(args ...interface{})
  67. Logf(format string, args ...interface{})
  68. }
  69. func setupTestClient(t logger, options ...ClientOptionFunc) (client *Client) {
  70. var err error
  71. client, err = NewClient(options...)
  72. if err != nil {
  73. t.Fatal(err)
  74. }
  75. client.DeleteIndex(testIndexName).Do()
  76. client.DeleteIndex(testIndexName2).Do()
  77. return client
  78. }
  79. func setupTestClientAndCreateIndex(t logger, options ...ClientOptionFunc) *Client {
  80. client := setupTestClient(t, options...)
  81. // Create index
  82. createIndex, err := client.CreateIndex(testIndexName).Body(testMapping).Do()
  83. if err != nil {
  84. t.Fatal(err)
  85. }
  86. if createIndex == nil {
  87. t.Errorf("expected result to be != nil; got: %v", createIndex)
  88. }
  89. // Create second index
  90. createIndex2, err := client.CreateIndex(testIndexName2).Body(testMapping).Do()
  91. if err != nil {
  92. t.Fatal(err)
  93. }
  94. if createIndex2 == nil {
  95. t.Errorf("expected result to be != nil; got: %v", createIndex2)
  96. }
  97. return client
  98. }
  99. func setupTestClientAndCreateIndexAndAddDocs(t logger, options ...ClientOptionFunc) *Client {
  100. client := setupTestClientAndCreateIndex(t, options...)
  101. tweet1 := tweet{User: "olivere", Message: "Welcome to Golang and Elasticsearch."}
  102. tweet2 := tweet{User: "olivere", Message: "Another unrelated topic."}
  103. tweet3 := tweet{User: "sandrae", Message: "Cycling is fun."}
  104. _, err := client.Index().Index(testIndexName).Type("tweet").Id("1").BodyJson(&tweet1).Do()
  105. if err != nil {
  106. t.Fatal(err)
  107. }
  108. _, err = client.Index().Index(testIndexName).Type("tweet").Id("2").BodyJson(&tweet2).Do()
  109. if err != nil {
  110. t.Fatal(err)
  111. }
  112. _, err = client.Index().Index(testIndexName).Type("tweet").Id("3").BodyJson(&tweet3).Do()
  113. if err != nil {
  114. t.Fatal(err)
  115. }
  116. _, err = client.Flush().Index(testIndexName).Do()
  117. if err != nil {
  118. t.Fatal(err)
  119. }
  120. return client
  121. }
  122. func TestIndexLifecycle(t *testing.T) {
  123. client := setupTestClient(t)
  124. // Create index
  125. createIndex, err := client.CreateIndex(testIndexName).Do()
  126. if err != nil {
  127. t.Fatal(err)
  128. }
  129. if !createIndex.Acknowledged {
  130. t.Errorf("expected CreateIndexResult.Acknowledged %v; got %v", true, createIndex.Acknowledged)
  131. }
  132. // Check if index exists
  133. indexExists, err := client.IndexExists(testIndexName).Do()
  134. if err != nil {
  135. t.Fatal(err)
  136. }
  137. if !indexExists {
  138. t.Fatalf("index %s should exist, but doesn't\n", testIndexName)
  139. }
  140. // Delete index
  141. deleteIndex, err := client.DeleteIndex(testIndexName).Do()
  142. if err != nil {
  143. t.Fatal(err)
  144. }
  145. if !deleteIndex.Acknowledged {
  146. t.Errorf("expected DeleteIndexResult.Acknowledged %v; got %v", true, deleteIndex.Acknowledged)
  147. }
  148. // Check if index exists
  149. indexExists, err = client.IndexExists(testIndexName).Do()
  150. if err != nil {
  151. t.Fatal(err)
  152. }
  153. if indexExists {
  154. t.Fatalf("index %s should not exist, but does\n", testIndexName)
  155. }
  156. }
  157. func TestIndexExistScenarios(t *testing.T) {
  158. client := setupTestClient(t)
  159. // Should return false if index does not exist
  160. indexExists, err := client.IndexExists(testIndexName).Do()
  161. if err != nil {
  162. t.Fatal(err)
  163. }
  164. if indexExists {
  165. t.Fatalf("expected index exists to return %v, got %v", false, indexExists)
  166. }
  167. // Create index
  168. createIndex, err := client.CreateIndex(testIndexName).Do()
  169. if err != nil {
  170. t.Fatal(err)
  171. }
  172. if !createIndex.Acknowledged {
  173. t.Errorf("expected CreateIndexResult.Ack %v; got %v", true, createIndex.Acknowledged)
  174. }
  175. // Should return true if index does not exist
  176. indexExists, err = client.IndexExists(testIndexName).Do()
  177. if err != nil {
  178. t.Fatal(err)
  179. }
  180. if !indexExists {
  181. t.Fatalf("expected index exists to return %v, got %v", true, indexExists)
  182. }
  183. }
  184. // TODO(oe): Find out why this test fails on Travis CI.
  185. /*
  186. func TestIndexOpenAndClose(t *testing.T) {
  187. client := setupTestClient(t)
  188. // Create index
  189. createIndex, err := client.CreateIndex(testIndexName).Do()
  190. if err != nil {
  191. t.Fatal(err)
  192. }
  193. if !createIndex.Acknowledged {
  194. t.Errorf("expected CreateIndexResult.Acknowledged %v; got %v", true, createIndex.Acknowledged)
  195. }
  196. defer func() {
  197. // Delete index
  198. deleteIndex, err := client.DeleteIndex(testIndexName).Do()
  199. if err != nil {
  200. t.Fatal(err)
  201. }
  202. if !deleteIndex.Acknowledged {
  203. t.Errorf("expected DeleteIndexResult.Acknowledged %v; got %v", true, deleteIndex.Acknowledged)
  204. }
  205. }()
  206. waitForYellow := func() {
  207. // Wait for status yellow
  208. res, err := client.ClusterHealth().WaitForStatus("yellow").Timeout("15s").Do()
  209. if err != nil {
  210. t.Fatal(err)
  211. }
  212. if res != nil && res.TimedOut {
  213. t.Fatalf("cluster time out waiting for status %q", "yellow")
  214. }
  215. }
  216. // Wait for cluster
  217. waitForYellow()
  218. // Close index
  219. cresp, err := client.CloseIndex(testIndexName).Do()
  220. if err != nil {
  221. t.Fatal(err)
  222. }
  223. if !cresp.Acknowledged {
  224. t.Fatalf("expected close index of %q to be acknowledged\n", testIndexName)
  225. }
  226. // Wait for cluster
  227. waitForYellow()
  228. // Open index again
  229. oresp, err := client.OpenIndex(testIndexName).Do()
  230. if err != nil {
  231. t.Fatal(err)
  232. }
  233. if !oresp.Acknowledged {
  234. t.Fatalf("expected open index of %q to be acknowledged\n", testIndexName)
  235. }
  236. }
  237. */
  238. func TestDocumentLifecycle(t *testing.T) {
  239. client := setupTestClientAndCreateIndex(t)
  240. tweet1 := tweet{User: "olivere", Message: "Welcome to Golang and Elasticsearch."}
  241. // Add a document
  242. indexResult, err := client.Index().
  243. Index(testIndexName).
  244. Type("tweet").
  245. Id("1").
  246. BodyJson(&tweet1).
  247. Do()
  248. if err != nil {
  249. t.Fatal(err)
  250. }
  251. if indexResult == nil {
  252. t.Errorf("expected result to be != nil; got: %v", indexResult)
  253. }
  254. // Exists
  255. exists, err := client.Exists().Index(testIndexName).Type("tweet").Id("1").Do()
  256. if err != nil {
  257. t.Fatal(err)
  258. }
  259. if !exists {
  260. t.Errorf("expected exists %v; got %v", true, exists)
  261. }
  262. // Get document
  263. getResult, err := client.Get().
  264. Index(testIndexName).
  265. Type("tweet").
  266. Id("1").
  267. Do()
  268. if err != nil {
  269. t.Fatal(err)
  270. }
  271. if getResult.Index != testIndexName {
  272. t.Errorf("expected GetResult.Index %q; got %q", testIndexName, getResult.Index)
  273. }
  274. if getResult.Type != "tweet" {
  275. t.Errorf("expected GetResult.Type %q; got %q", "tweet", getResult.Type)
  276. }
  277. if getResult.Id != "1" {
  278. t.Errorf("expected GetResult.Id %q; got %q", "1", getResult.Id)
  279. }
  280. if getResult.Source == nil {
  281. t.Errorf("expected GetResult.Source to be != nil; got nil")
  282. }
  283. // Decode the Source field
  284. var tweetGot tweet
  285. err = json.Unmarshal(*getResult.Source, &tweetGot)
  286. if err != nil {
  287. t.Fatal(err)
  288. }
  289. if tweetGot.User != tweet1.User {
  290. t.Errorf("expected Tweet.User to be %q; got %q", tweet1.User, tweetGot.User)
  291. }
  292. if tweetGot.Message != tweet1.Message {
  293. t.Errorf("expected Tweet.Message to be %q; got %q", tweet1.Message, tweetGot.Message)
  294. }
  295. // Delete document again
  296. deleteResult, err := client.Delete().Index(testIndexName).Type("tweet").Id("1").Do()
  297. if err != nil {
  298. t.Fatal(err)
  299. }
  300. if deleteResult == nil {
  301. t.Errorf("expected result to be != nil; got: %v", deleteResult)
  302. }
  303. // Exists
  304. exists, err = client.Exists().Index(testIndexName).Type("tweet").Id("1").Do()
  305. if err != nil {
  306. t.Fatal(err)
  307. }
  308. if exists {
  309. t.Errorf("expected exists %v; got %v", false, exists)
  310. }
  311. }
  312. func TestDocumentLifecycleWithAutomaticIDGeneration(t *testing.T) {
  313. client := setupTestClientAndCreateIndex(t)
  314. tweet1 := tweet{User: "olivere", Message: "Welcome to Golang and Elasticsearch."}
  315. // Add a document
  316. indexResult, err := client.Index().
  317. Index(testIndexName).
  318. Type("tweet").
  319. BodyJson(&tweet1).
  320. Do()
  321. if err != nil {
  322. t.Fatal(err)
  323. }
  324. if indexResult == nil {
  325. t.Errorf("expected result to be != nil; got: %v", indexResult)
  326. }
  327. if indexResult.Id == "" {
  328. t.Fatalf("expected Es to generate an automatic ID, got: %v", indexResult.Id)
  329. }
  330. id := indexResult.Id
  331. // Exists
  332. exists, err := client.Exists().Index(testIndexName).Type("tweet").Id(id).Do()
  333. if err != nil {
  334. t.Fatal(err)
  335. }
  336. if !exists {
  337. t.Errorf("expected exists %v; got %v", true, exists)
  338. }
  339. // Get document
  340. getResult, err := client.Get().
  341. Index(testIndexName).
  342. Type("tweet").
  343. Id(id).
  344. Do()
  345. if err != nil {
  346. t.Fatal(err)
  347. }
  348. if getResult.Index != testIndexName {
  349. t.Errorf("expected GetResult.Index %q; got %q", testIndexName, getResult.Index)
  350. }
  351. if getResult.Type != "tweet" {
  352. t.Errorf("expected GetResult.Type %q; got %q", "tweet", getResult.Type)
  353. }
  354. if getResult.Id != id {
  355. t.Errorf("expected GetResult.Id %q; got %q", id, getResult.Id)
  356. }
  357. if getResult.Source == nil {
  358. t.Errorf("expected GetResult.Source to be != nil; got nil")
  359. }
  360. // Decode the Source field
  361. var tweetGot tweet
  362. err = json.Unmarshal(*getResult.Source, &tweetGot)
  363. if err != nil {
  364. t.Fatal(err)
  365. }
  366. if tweetGot.User != tweet1.User {
  367. t.Errorf("expected Tweet.User to be %q; got %q", tweet1.User, tweetGot.User)
  368. }
  369. if tweetGot.Message != tweet1.Message {
  370. t.Errorf("expected Tweet.Message to be %q; got %q", tweet1.Message, tweetGot.Message)
  371. }
  372. // Delete document again
  373. deleteResult, err := client.Delete().Index(testIndexName).Type("tweet").Id(id).Do()
  374. if err != nil {
  375. t.Fatal(err)
  376. }
  377. if deleteResult == nil {
  378. t.Errorf("expected result to be != nil; got: %v", deleteResult)
  379. }
  380. // Exists
  381. exists, err = client.Exists().Index(testIndexName).Type("tweet").Id(id).Do()
  382. if err != nil {
  383. t.Fatal(err)
  384. }
  385. if exists {
  386. t.Errorf("expected exists %v; got %v", false, exists)
  387. }
  388. }
  389. func TestIndexCreateExistsOpenCloseDelete(t *testing.T) {
  390. // TODO: Find out how to make these test robust
  391. t.Skip("test fails regularly with 409 (Conflict): " +
  392. "IndexPrimaryShardNotAllocatedException[[elastic-test] " +
  393. "primary not allocated post api... skipping")
  394. client := setupTestClient(t)
  395. // Create index
  396. createIndex, err := client.CreateIndex(testIndexName).Body(testMapping).Do()
  397. if err != nil {
  398. t.Fatal(err)
  399. }
  400. if createIndex == nil {
  401. t.Fatalf("expected response; got: %v", createIndex)
  402. }
  403. if !createIndex.Acknowledged {
  404. t.Errorf("expected ack for creating index; got: %v", createIndex.Acknowledged)
  405. }
  406. // Exists
  407. indexExists, err := client.IndexExists(testIndexName).Do()
  408. if err != nil {
  409. t.Fatal(err)
  410. }
  411. if !indexExists {
  412. t.Fatalf("expected index exists=%v; got %v", true, indexExists)
  413. }
  414. // Flush
  415. _, err = client.Flush().Index(testIndexName).Do()
  416. if err != nil {
  417. t.Fatal(err)
  418. }
  419. // Close index
  420. closeIndex, err := client.CloseIndex(testIndexName).Do()
  421. if err != nil {
  422. t.Fatal(err)
  423. }
  424. if closeIndex == nil {
  425. t.Fatalf("expected response; got: %v", closeIndex)
  426. }
  427. if !closeIndex.Acknowledged {
  428. t.Errorf("expected ack for closing index; got: %v", closeIndex.Acknowledged)
  429. }
  430. // Open index
  431. openIndex, err := client.OpenIndex(testIndexName).Do()
  432. if err != nil {
  433. t.Fatal(err)
  434. }
  435. if openIndex == nil {
  436. t.Fatalf("expected response; got: %v", openIndex)
  437. }
  438. if !openIndex.Acknowledged {
  439. t.Errorf("expected ack for opening index; got: %v", openIndex.Acknowledged)
  440. }
  441. // Flush
  442. _, err = client.Flush().Index(testIndexName).Do()
  443. if err != nil {
  444. t.Fatal(err)
  445. }
  446. // Delete index
  447. deleteIndex, err := client.DeleteIndex(testIndexName).Do()
  448. if err != nil {
  449. t.Fatal(err)
  450. }
  451. if deleteIndex == nil {
  452. t.Fatalf("expected response; got: %v", deleteIndex)
  453. }
  454. if !deleteIndex.Acknowledged {
  455. t.Errorf("expected ack for deleting index; got %v", deleteIndex.Acknowledged)
  456. }
  457. }