bulk_test.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. // Copyright 2012-present 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. "context"
  7. "encoding/json"
  8. "fmt"
  9. "math/rand"
  10. "net/http"
  11. "net/http/httptest"
  12. "testing"
  13. )
  14. func TestBulk(t *testing.T) {
  15. client := setupTestClientAndCreateIndex(t) //, SetTraceLog(log.New(os.Stdout, "", 0)))
  16. tweet1 := tweet{User: "olivere", Message: "Welcome to Golang and Elasticsearch."}
  17. tweet2 := tweet{User: "sandrae", Message: "Dancing all night long. Yeah."}
  18. index1Req := NewBulkIndexRequest().Index(testIndexName).Type("tweet").Id("1").Doc(tweet1)
  19. index2Req := NewBulkIndexRequest().Index(testIndexName).Type("tweet").Id("2").Doc(tweet2)
  20. delete1Req := NewBulkDeleteRequest().Index(testIndexName).Type("tweet").Id("1")
  21. bulkRequest := client.Bulk()
  22. bulkRequest = bulkRequest.Add(index1Req)
  23. bulkRequest = bulkRequest.Add(index2Req)
  24. bulkRequest = bulkRequest.Add(delete1Req)
  25. if bulkRequest.NumberOfActions() != 3 {
  26. t.Errorf("expected bulkRequest.NumberOfActions %d; got %d", 3, bulkRequest.NumberOfActions())
  27. }
  28. bulkResponse, err := bulkRequest.Do(context.TODO())
  29. if err != nil {
  30. t.Fatal(err)
  31. }
  32. if bulkResponse == nil {
  33. t.Errorf("expected bulkResponse to be != nil; got nil")
  34. }
  35. if bulkRequest.NumberOfActions() != 0 {
  36. t.Errorf("expected bulkRequest.NumberOfActions %d; got %d", 0, bulkRequest.NumberOfActions())
  37. }
  38. // Document with Id="1" should not exist
  39. exists, err := client.Exists().Index(testIndexName).Type("tweet").Id("1").Do(context.TODO())
  40. if err != nil {
  41. t.Fatal(err)
  42. }
  43. if exists {
  44. t.Errorf("expected exists %v; got %v", false, exists)
  45. }
  46. // Document with Id="2" should exist
  47. exists, err = client.Exists().Index(testIndexName).Type("tweet").Id("2").Do(context.TODO())
  48. if err != nil {
  49. t.Fatal(err)
  50. }
  51. if !exists {
  52. t.Errorf("expected exists %v; got %v", true, exists)
  53. }
  54. // Update
  55. updateDoc := struct {
  56. Retweets int `json:"retweets"`
  57. }{
  58. 42,
  59. }
  60. update1Req := NewBulkUpdateRequest().Index(testIndexName).Type("tweet").Id("2").Doc(&updateDoc)
  61. bulkRequest = client.Bulk()
  62. bulkRequest = bulkRequest.Add(update1Req)
  63. if bulkRequest.NumberOfActions() != 1 {
  64. t.Errorf("expected bulkRequest.NumberOfActions %d; got %d", 1, bulkRequest.NumberOfActions())
  65. }
  66. bulkResponse, err = bulkRequest.Do(context.TODO())
  67. if err != nil {
  68. t.Fatal(err)
  69. }
  70. if bulkResponse == nil {
  71. t.Errorf("expected bulkResponse to be != nil; got nil")
  72. }
  73. if bulkRequest.NumberOfActions() != 0 {
  74. t.Errorf("expected bulkRequest.NumberOfActions %d; got %d", 0, bulkRequest.NumberOfActions())
  75. }
  76. // Document with Id="1" should have a retweets count of 42
  77. doc, err := client.Get().Index(testIndexName).Type("tweet").Id("2").Do(context.TODO())
  78. if err != nil {
  79. t.Fatal(err)
  80. }
  81. if doc == nil {
  82. t.Fatal("expected doc to be != nil; got nil")
  83. }
  84. if !doc.Found {
  85. t.Fatalf("expected doc to be found; got found = %v", doc.Found)
  86. }
  87. if doc.Source == nil {
  88. t.Fatal("expected doc source to be != nil; got nil")
  89. }
  90. var updatedTweet tweet
  91. err = json.Unmarshal(*doc.Source, &updatedTweet)
  92. if err != nil {
  93. t.Fatal(err)
  94. }
  95. if updatedTweet.Retweets != 42 {
  96. t.Errorf("expected updated tweet retweets = %v; got %v", 42, updatedTweet.Retweets)
  97. }
  98. // Update with script
  99. update2Req := NewBulkUpdateRequest().Index(testIndexName).Type("tweet").Id("2").
  100. RetryOnConflict(3).
  101. Script(NewScript("ctx._source.retweets += params.v").Param("v", 1))
  102. bulkRequest = client.Bulk()
  103. bulkRequest = bulkRequest.Add(update2Req)
  104. if bulkRequest.NumberOfActions() != 1 {
  105. t.Errorf("expected bulkRequest.NumberOfActions %d; got %d", 1, bulkRequest.NumberOfActions())
  106. }
  107. bulkResponse, err = bulkRequest.Refresh("wait_for").Do(context.TODO())
  108. if err != nil {
  109. t.Fatal(err)
  110. }
  111. if bulkResponse == nil {
  112. t.Errorf("expected bulkResponse to be != nil; got nil")
  113. }
  114. if bulkRequest.NumberOfActions() != 0 {
  115. t.Errorf("expected bulkRequest.NumberOfActions %d; got %d", 0, bulkRequest.NumberOfActions())
  116. }
  117. // Document with Id="1" should have a retweets count of 43
  118. doc, err = client.Get().Index(testIndexName).Type("tweet").Id("2").Do(context.TODO())
  119. if err != nil {
  120. t.Fatal(err)
  121. }
  122. if doc == nil {
  123. t.Fatal("expected doc to be != nil; got nil")
  124. }
  125. if !doc.Found {
  126. t.Fatalf("expected doc to be found; got found = %v", doc.Found)
  127. }
  128. if doc.Source == nil {
  129. t.Fatal("expected doc source to be != nil; got nil")
  130. }
  131. err = json.Unmarshal(*doc.Source, &updatedTweet)
  132. if err != nil {
  133. t.Fatal(err)
  134. }
  135. if updatedTweet.Retweets != 43 {
  136. t.Errorf("expected updated tweet retweets = %v; got %v", 43, updatedTweet.Retweets)
  137. }
  138. }
  139. func TestBulkWithIndexSetOnClient(t *testing.T) {
  140. client := setupTestClientAndCreateIndex(t)
  141. tweet1 := tweet{User: "olivere", Message: "Welcome to Golang and Elasticsearch."}
  142. tweet2 := tweet{User: "sandrae", Message: "Dancing all night long. Yeah."}
  143. index1Req := NewBulkIndexRequest().Index(testIndexName).Type("tweet").Id("1").Doc(tweet1)
  144. index2Req := NewBulkIndexRequest().Index(testIndexName).Type("tweet").Id("2").Doc(tweet2)
  145. delete1Req := NewBulkDeleteRequest().Index(testIndexName).Type("tweet").Id("1")
  146. bulkRequest := client.Bulk().Index(testIndexName).Type("tweet")
  147. bulkRequest = bulkRequest.Add(index1Req)
  148. bulkRequest = bulkRequest.Add(index2Req)
  149. bulkRequest = bulkRequest.Add(delete1Req)
  150. if bulkRequest.NumberOfActions() != 3 {
  151. t.Errorf("expected bulkRequest.NumberOfActions %d; got %d", 3, bulkRequest.NumberOfActions())
  152. }
  153. bulkResponse, err := bulkRequest.Do(context.TODO())
  154. if err != nil {
  155. t.Fatal(err)
  156. }
  157. if bulkResponse == nil {
  158. t.Errorf("expected bulkResponse to be != nil; got nil")
  159. }
  160. // Document with Id="1" should not exist
  161. exists, err := client.Exists().Index(testIndexName).Type("tweet").Id("1").Do(context.TODO())
  162. if err != nil {
  163. t.Fatal(err)
  164. }
  165. if exists {
  166. t.Errorf("expected exists %v; got %v", false, exists)
  167. }
  168. // Document with Id="2" should exist
  169. exists, err = client.Exists().Index(testIndexName).Type("tweet").Id("2").Do(context.TODO())
  170. if err != nil {
  171. t.Fatal(err)
  172. }
  173. if !exists {
  174. t.Errorf("expected exists %v; got %v", true, exists)
  175. }
  176. }
  177. func TestBulkIndexDeleteUpdate(t *testing.T) {
  178. client := setupTestClientAndCreateIndex(t)
  179. //client := setupTestClientAndCreateIndexAndLog(t)
  180. tweet1 := tweet{User: "olivere", Message: "Welcome to Golang and Elasticsearch."}
  181. tweet2 := tweet{User: "sandrae", Message: "Dancing all night long. Yeah."}
  182. index1Req := NewBulkIndexRequest().Index(testIndexName).Type("tweet").Id("1").Doc(tweet1)
  183. index2Req := NewBulkIndexRequest().OpType("create").Index(testIndexName).Type("tweet").Id("2").Doc(tweet2)
  184. delete1Req := NewBulkDeleteRequest().Index(testIndexName).Type("tweet").Id("1")
  185. update2Req := NewBulkUpdateRequest().Index(testIndexName).Type("tweet").Id("2").
  186. ReturnSource(true).
  187. Doc(struct {
  188. Retweets int `json:"retweets"`
  189. }{
  190. Retweets: 42,
  191. })
  192. bulkRequest := client.Bulk()
  193. bulkRequest = bulkRequest.Add(index1Req)
  194. bulkRequest = bulkRequest.Add(index2Req)
  195. bulkRequest = bulkRequest.Add(delete1Req)
  196. bulkRequest = bulkRequest.Add(update2Req)
  197. if bulkRequest.NumberOfActions() != 4 {
  198. t.Errorf("expected bulkRequest.NumberOfActions %d; got %d", 4, bulkRequest.NumberOfActions())
  199. }
  200. expected := `{"index":{"_id":"1","_index":"` + testIndexName + `","_type":"tweet"}}
  201. {"user":"olivere","message":"Welcome to Golang and Elasticsearch.","retweets":0,"created":"0001-01-01T00:00:00Z"}
  202. {"create":{"_id":"2","_index":"` + testIndexName + `","_type":"tweet"}}
  203. {"user":"sandrae","message":"Dancing all night long. Yeah.","retweets":0,"created":"0001-01-01T00:00:00Z"}
  204. {"delete":{"_id":"1","_index":"` + testIndexName + `","_type":"tweet"}}
  205. {"update":{"_id":"2","_index":"` + testIndexName + `","_type":"tweet"}}
  206. {"doc":{"retweets":42},"_source":true}
  207. `
  208. got, err := bulkRequest.bodyAsString()
  209. if err != nil {
  210. t.Fatalf("expected no error, got: %v", err)
  211. }
  212. if got != expected {
  213. t.Errorf("expected\n%s\ngot:\n%s", expected, got)
  214. }
  215. // Run the bulk request
  216. bulkResponse, err := bulkRequest.Pretty(true).Do(context.TODO())
  217. if err != nil {
  218. t.Fatal(err)
  219. }
  220. if bulkResponse == nil {
  221. t.Errorf("expected bulkResponse to be != nil; got nil")
  222. }
  223. if bulkResponse.Took == 0 {
  224. t.Errorf("expected took to be > 0; got %d", bulkResponse.Took)
  225. }
  226. if bulkResponse.Errors {
  227. t.Errorf("expected errors to be %v; got %v", false, bulkResponse.Errors)
  228. }
  229. if len(bulkResponse.Items) != 4 {
  230. t.Fatalf("expected 4 result items; got %d", len(bulkResponse.Items))
  231. }
  232. // Indexed actions
  233. indexed := bulkResponse.Indexed()
  234. if indexed == nil {
  235. t.Fatal("expected indexed to be != nil; got nil")
  236. }
  237. if len(indexed) != 1 {
  238. t.Fatalf("expected len(indexed) == %d; got %d", 1, len(indexed))
  239. }
  240. if indexed[0].Id != "1" {
  241. t.Errorf("expected indexed[0].Id == %s; got %s", "1", indexed[0].Id)
  242. }
  243. if indexed[0].Status != 201 {
  244. t.Errorf("expected indexed[0].Status == %d; got %d", 201, indexed[0].Status)
  245. }
  246. // Created actions
  247. created := bulkResponse.Created()
  248. if created == nil {
  249. t.Fatal("expected created to be != nil; got nil")
  250. }
  251. if len(created) != 1 {
  252. t.Fatalf("expected len(created) == %d; got %d", 1, len(created))
  253. }
  254. if created[0].Id != "2" {
  255. t.Errorf("expected created[0].Id == %s; got %s", "2", created[0].Id)
  256. }
  257. if created[0].Status != 201 {
  258. t.Errorf("expected created[0].Status == %d; got %d", 201, created[0].Status)
  259. }
  260. if want, have := "created", created[0].Result; want != have {
  261. t.Errorf("expected created[0].Result == %q; got %q", want, have)
  262. }
  263. // Deleted actions
  264. deleted := bulkResponse.Deleted()
  265. if deleted == nil {
  266. t.Fatal("expected deleted to be != nil; got nil")
  267. }
  268. if len(deleted) != 1 {
  269. t.Fatalf("expected len(deleted) == %d; got %d", 1, len(deleted))
  270. }
  271. if deleted[0].Id != "1" {
  272. t.Errorf("expected deleted[0].Id == %s; got %s", "1", deleted[0].Id)
  273. }
  274. if deleted[0].Status != 200 {
  275. t.Errorf("expected deleted[0].Status == %d; got %d", 200, deleted[0].Status)
  276. }
  277. if !deleted[0].Found {
  278. t.Errorf("expected deleted[0].Found == %v; got %v", true, deleted[0].Found)
  279. }
  280. if want, have := "deleted", deleted[0].Result; want != have {
  281. t.Errorf("expected deleted[0].Result == %q; got %q", want, have)
  282. }
  283. // Updated actions
  284. updated := bulkResponse.Updated()
  285. if updated == nil {
  286. t.Fatal("expected updated to be != nil; got nil")
  287. }
  288. if len(updated) != 1 {
  289. t.Fatalf("expected len(updated) == %d; got %d", 1, len(updated))
  290. }
  291. if updated[0].Id != "2" {
  292. t.Errorf("expected updated[0].Id == %s; got %s", "2", updated[0].Id)
  293. }
  294. if updated[0].Status != 200 {
  295. t.Errorf("expected updated[0].Status == %d; got %d", 200, updated[0].Status)
  296. }
  297. if updated[0].Version != 2 {
  298. t.Errorf("expected updated[0].Version == %d; got %d", 2, updated[0].Version)
  299. }
  300. if want, have := "updated", updated[0].Result; want != have {
  301. t.Errorf("expected updated[0].Result == %q; got %q", want, have)
  302. }
  303. if updated[0].GetResult == nil {
  304. t.Fatalf("expected updated[0].GetResult to be != nil; got nil")
  305. }
  306. if updated[0].GetResult.Source == nil {
  307. t.Fatalf("expected updated[0].GetResult.Source to be != nil; got nil")
  308. }
  309. if want, have := true, updated[0].GetResult.Found; want != have {
  310. t.Fatalf("expected updated[0].GetResult.Found to be != %v; got %v", want, have)
  311. }
  312. var doc tweet
  313. if err := json.Unmarshal(*updated[0].GetResult.Source, &doc); err != nil {
  314. t.Fatalf("expected to unmarshal updated[0].GetResult.Source; got %v", err)
  315. }
  316. if want, have := 42, doc.Retweets; want != have {
  317. t.Fatalf("expected updated tweet to have Retweets = %v; got %v", want, have)
  318. }
  319. // Succeeded actions
  320. succeeded := bulkResponse.Succeeded()
  321. if succeeded == nil {
  322. t.Fatal("expected succeeded to be != nil; got nil")
  323. }
  324. if len(succeeded) != 4 {
  325. t.Fatalf("expected len(succeeded) == %d; got %d", 4, len(succeeded))
  326. }
  327. // ById
  328. id1Results := bulkResponse.ById("1")
  329. if id1Results == nil {
  330. t.Fatal("expected id1Results to be != nil; got nil")
  331. }
  332. if len(id1Results) != 2 {
  333. t.Fatalf("expected len(id1Results) == %d; got %d", 2, len(id1Results))
  334. }
  335. if id1Results[0].Id != "1" {
  336. t.Errorf("expected id1Results[0].Id == %s; got %s", "1", id1Results[0].Id)
  337. }
  338. if id1Results[0].Status != 201 {
  339. t.Errorf("expected id1Results[0].Status == %d; got %d", 201, id1Results[0].Status)
  340. }
  341. if id1Results[0].Version != 1 {
  342. t.Errorf("expected id1Results[0].Version == %d; got %d", 1, id1Results[0].Version)
  343. }
  344. if id1Results[1].Id != "1" {
  345. t.Errorf("expected id1Results[1].Id == %s; got %s", "1", id1Results[1].Id)
  346. }
  347. if id1Results[1].Status != 200 {
  348. t.Errorf("expected id1Results[1].Status == %d; got %d", 200, id1Results[1].Status)
  349. }
  350. if id1Results[1].Version != 2 {
  351. t.Errorf("expected id1Results[1].Version == %d; got %d", 2, id1Results[1].Version)
  352. }
  353. }
  354. func TestFailedBulkRequests(t *testing.T) {
  355. js := `{
  356. "took" : 2,
  357. "errors" : true,
  358. "items" : [ {
  359. "index" : {
  360. "_index" : "elastic-test",
  361. "_type" : "tweet",
  362. "_id" : "1",
  363. "_version" : 1,
  364. "status" : 201
  365. }
  366. }, {
  367. "create" : {
  368. "_index" : "elastic-test",
  369. "_type" : "tweet",
  370. "_id" : "2",
  371. "_version" : 1,
  372. "status" : 423,
  373. "error" : {
  374. "type":"routing_missing_exception",
  375. "reason":"routing is required for [elastic-test2]/[comment]/[1]"
  376. }
  377. }
  378. }, {
  379. "delete" : {
  380. "_index" : "elastic-test",
  381. "_type" : "tweet",
  382. "_id" : "1",
  383. "_version" : 2,
  384. "status" : 404,
  385. "found" : false
  386. }
  387. }, {
  388. "update" : {
  389. "_index" : "elastic-test",
  390. "_type" : "tweet",
  391. "_id" : "2",
  392. "_version" : 2,
  393. "status" : 200
  394. }
  395. } ]
  396. }`
  397. var resp BulkResponse
  398. err := json.Unmarshal([]byte(js), &resp)
  399. if err != nil {
  400. t.Fatal(err)
  401. }
  402. failed := resp.Failed()
  403. if len(failed) != 2 {
  404. t.Errorf("expected %d failed items; got: %d", 2, len(failed))
  405. }
  406. }
  407. func TestBulkEstimatedSizeInBytes(t *testing.T) {
  408. client := setupTestClientAndCreateIndex(t)
  409. tweet1 := tweet{User: "olivere", Message: "Welcome to Golang and Elasticsearch."}
  410. tweet2 := tweet{User: "sandrae", Message: "Dancing all night long. Yeah."}
  411. index1Req := NewBulkIndexRequest().Index(testIndexName).Type("tweet").Id("1").Doc(tweet1)
  412. index2Req := NewBulkIndexRequest().OpType("create").Index(testIndexName).Type("tweet").Id("2").Doc(tweet2)
  413. delete1Req := NewBulkDeleteRequest().Index(testIndexName).Type("tweet").Id("1")
  414. update2Req := NewBulkUpdateRequest().Index(testIndexName).Type("tweet").Id("2").
  415. Doc(struct {
  416. Retweets int `json:"retweets"`
  417. }{
  418. Retweets: 42,
  419. })
  420. bulkRequest := client.Bulk()
  421. bulkRequest = bulkRequest.Add(index1Req)
  422. bulkRequest = bulkRequest.Add(index2Req)
  423. bulkRequest = bulkRequest.Add(delete1Req)
  424. bulkRequest = bulkRequest.Add(update2Req)
  425. if bulkRequest.NumberOfActions() != 4 {
  426. t.Errorf("expected bulkRequest.NumberOfActions %d; got %d", 4, bulkRequest.NumberOfActions())
  427. }
  428. // The estimated size of the bulk request in bytes must be at least
  429. // the length of the body request.
  430. raw, err := bulkRequest.bodyAsString()
  431. if err != nil {
  432. t.Fatal(err)
  433. }
  434. rawlen := int64(len([]byte(raw)))
  435. if got, want := bulkRequest.EstimatedSizeInBytes(), rawlen; got < want {
  436. t.Errorf("expected an EstimatedSizeInBytes = %d; got: %v", want, got)
  437. }
  438. // Reset should also reset the calculated estimated byte size
  439. bulkRequest.Reset()
  440. if got, want := bulkRequest.EstimatedSizeInBytes(), int64(0); got != want {
  441. t.Errorf("expected an EstimatedSizeInBytes = %d; got: %v", want, got)
  442. }
  443. }
  444. func TestBulkEstimateSizeInBytesLength(t *testing.T) {
  445. client := setupTestClientAndCreateIndex(t)
  446. s := client.Bulk()
  447. r := NewBulkDeleteRequest().Index(testIndexName).Type("tweet").Id("1")
  448. s = s.Add(r)
  449. if got, want := s.estimateSizeInBytes(r), int64(1+len(r.String())); got != want {
  450. t.Fatalf("expected %d; got: %d", want, got)
  451. }
  452. }
  453. var benchmarkBulkEstimatedSizeInBytes int64
  454. func BenchmarkBulkEstimatedSizeInBytesWith1Request(b *testing.B) {
  455. client := setupTestClientAndCreateIndex(b)
  456. s := client.Bulk()
  457. var result int64
  458. for n := 0; n < b.N; n++ {
  459. s = s.Add(NewBulkIndexRequest().Index(testIndexName).Type("tweet").Id("1").Doc(struct{ A string }{"1"}))
  460. s = s.Add(NewBulkUpdateRequest().Index(testIndexName).Type("tweet").Id("1").Doc(struct{ A string }{"2"}))
  461. s = s.Add(NewBulkDeleteRequest().Index(testIndexName).Type("tweet").Id("1"))
  462. result = s.EstimatedSizeInBytes()
  463. s.Reset()
  464. }
  465. b.ReportAllocs()
  466. benchmarkBulkEstimatedSizeInBytes = result // ensure the compiler doesn't optimize
  467. }
  468. func BenchmarkBulkEstimatedSizeInBytesWith100Requests(b *testing.B) {
  469. client := setupTestClientAndCreateIndex(b)
  470. s := client.Bulk()
  471. var result int64
  472. for n := 0; n < b.N; n++ {
  473. for i := 0; i < 100; i++ {
  474. s = s.Add(NewBulkIndexRequest().Index(testIndexName).Type("tweet").Id("1").Doc(struct{ A string }{"1"}))
  475. s = s.Add(NewBulkUpdateRequest().Index(testIndexName).Type("tweet").Id("1").Doc(struct{ A string }{"2"}))
  476. s = s.Add(NewBulkDeleteRequest().Index(testIndexName).Type("tweet").Id("1"))
  477. }
  478. result = s.EstimatedSizeInBytes()
  479. s.Reset()
  480. }
  481. b.ReportAllocs()
  482. benchmarkBulkEstimatedSizeInBytes = result // ensure the compiler doesn't optimize
  483. }
  484. func TestBulkContentType(t *testing.T) {
  485. var header http.Header
  486. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  487. header = r.Header
  488. fmt.Fprintln(w, `{}`)
  489. }))
  490. defer ts.Close()
  491. client, err := NewSimpleClient(SetURL(ts.URL))
  492. if err != nil {
  493. t.Fatal(err)
  494. }
  495. indexReq := NewBulkIndexRequest().Index(testIndexName).Type("tweet").Id("1").Doc(tweet{User: "olivere", Message: "Welcome to Golang and Elasticsearch."})
  496. if _, err := client.Bulk().Add(indexReq).Do(context.Background()); err != nil {
  497. t.Fatal(err)
  498. }
  499. if header == nil {
  500. t.Fatalf("expected header, got %v", header)
  501. }
  502. if want, have := "application/x-ndjson", header.Get("Content-Type"); want != have {
  503. t.Fatalf("Content-Type: want %q, have %q", want, have)
  504. }
  505. }
  506. // -- Benchmarks --
  507. func BenchmarkBulkAllocs(b *testing.B) {
  508. b.Run("1000 docs with 64 byte", func(b *testing.B) { benchmarkBulkAllocs(b, 64, 1000) })
  509. b.Run("1000 docs with 1 KiB", func(b *testing.B) { benchmarkBulkAllocs(b, 1024, 1000) })
  510. b.Run("1000 docs with 4 KiB", func(b *testing.B) { benchmarkBulkAllocs(b, 4096, 1000) })
  511. b.Run("1000 docs with 16 KiB", func(b *testing.B) { benchmarkBulkAllocs(b, 16*1024, 1000) })
  512. b.Run("1000 docs with 64 KiB", func(b *testing.B) { benchmarkBulkAllocs(b, 64*1024, 1000) })
  513. b.Run("1000 docs with 256 KiB", func(b *testing.B) { benchmarkBulkAllocs(b, 256*1024, 1000) })
  514. b.Run("1000 docs with 1 MiB", func(b *testing.B) { benchmarkBulkAllocs(b, 1024*1024, 1000) })
  515. }
  516. const (
  517. charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-"
  518. )
  519. func benchmarkBulkAllocs(b *testing.B, size, num int) {
  520. buf := make([]byte, size)
  521. for i := range buf {
  522. buf[i] = charset[rand.Intn(len(charset))]
  523. }
  524. s := &BulkService{}
  525. n := 0
  526. for {
  527. n++
  528. s = s.Add(NewBulkIndexRequest().Index("test").Type("doc").Id("1").Doc(struct {
  529. S string `json:"s"`
  530. }{
  531. S: string(buf),
  532. }))
  533. if n >= num {
  534. break
  535. }
  536. }
  537. for i := 0; i < b.N; i++ {
  538. s.bodyAsString()
  539. }
  540. b.ReportAllocs()
  541. }