elastomer-client 3.2.3 → 6.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer/devcontainer.json +46 -0
  3. data/.devcontainer/postCreateCommand.sh +4 -0
  4. data/.github/dependabot.yaml +11 -0
  5. data/.github/workflows/main.yml +45 -0
  6. data/.github/workflows/rubocop.yml +15 -0
  7. data/.gitignore +1 -1
  8. data/.rubocop.yml +13 -65
  9. data/.ruby-version +1 -0
  10. data/CHANGELOG.md +73 -0
  11. data/Gemfile +18 -1
  12. data/README.md +110 -51
  13. data/Rakefile +3 -1
  14. data/docker/compose.yaml +71 -0
  15. data/docker/elasticsearch8plus.yml +13 -0
  16. data/docs/README.md +4 -5
  17. data/docs/bulk_indexing.md +1 -1
  18. data/docs/client.md +20 -33
  19. data/docs/cluster.md +8 -8
  20. data/docs/docs.md +5 -5
  21. data/docs/index.md +4 -4
  22. data/docs/multi_search.md +1 -1
  23. data/docs/notifications.md +3 -3
  24. data/docs/scan_scroll.md +1 -1
  25. data/docs/snapshots.md +1 -1
  26. data/docs/templates.md +1 -1
  27. data/elastomer-client.gemspec +7 -16
  28. data/lib/{elastomer → elastomer_client}/client/bulk.rb +70 -47
  29. data/lib/{elastomer → elastomer_client}/client/cluster.rb +18 -16
  30. data/lib/{elastomer → elastomer_client}/client/delete_by_query.rb +6 -4
  31. data/lib/{elastomer → elastomer_client}/client/docs.rb +82 -72
  32. data/lib/{elastomer → elastomer_client}/client/errors.rb +7 -17
  33. data/lib/{elastomer → elastomer_client}/client/index.rb +55 -79
  34. data/lib/{elastomer → elastomer_client}/client/multi_percolate.rb +7 -5
  35. data/lib/{elastomer → elastomer_client}/client/multi_search.rb +5 -3
  36. data/lib/{elastomer → elastomer_client}/client/native_delete_by_query.rb +6 -6
  37. data/lib/{elastomer → elastomer_client}/client/nodes.rb +11 -10
  38. data/lib/{elastomer → elastomer_client}/client/percolator.rb +9 -10
  39. data/lib/elastomer_client/client/reindex.rb +29 -0
  40. data/lib/{elastomer → elastomer_client}/client/repository.rb +7 -5
  41. data/lib/{elastomer → elastomer_client}/client/rest_api_spec/api_spec.rb +7 -6
  42. data/lib/{elastomer → elastomer_client}/client/rest_api_spec/api_spec_v5_6.rb +1 -1
  43. data/lib/elastomer_client/client/rest_api_spec/api_spec_v8_13.rb +7567 -0
  44. data/lib/elastomer_client/client/rest_api_spec/api_spec_v8_7.rb +6553 -0
  45. data/lib/{elastomer → elastomer_client}/client/rest_api_spec/rest_api.rb +5 -3
  46. data/lib/{elastomer → elastomer_client}/client/rest_api_spec.rb +3 -2
  47. data/lib/{elastomer → elastomer_client}/client/scroller.rb +17 -16
  48. data/lib/{elastomer → elastomer_client}/client/snapshot.rb +10 -8
  49. data/lib/{elastomer → elastomer_client}/client/tasks.rb +9 -13
  50. data/lib/{elastomer → elastomer_client}/client/template.rb +10 -9
  51. data/lib/elastomer_client/client/update_by_query.rb +50 -0
  52. data/lib/{elastomer → elastomer_client}/client.rb +51 -62
  53. data/lib/{elastomer → elastomer_client}/core_ext/time.rb +2 -0
  54. data/lib/{elastomer → elastomer_client}/middleware/compress.rb +2 -2
  55. data/lib/{elastomer → elastomer_client}/middleware/encode_json.rb +4 -2
  56. data/lib/{elastomer → elastomer_client}/middleware/limit_size.rb +5 -3
  57. data/lib/{elastomer → elastomer_client}/middleware/opaque_id.rb +10 -7
  58. data/lib/{elastomer → elastomer_client}/middleware/parse_json.rb +5 -3
  59. data/lib/{elastomer → elastomer_client}/notifications.rb +17 -15
  60. data/lib/elastomer_client/version.rb +9 -0
  61. data/lib/elastomer_client/version_support.rb +24 -0
  62. data/script/bootstrap +4 -2
  63. data/script/console +3 -1
  64. data/script/generate-rest-api-spec +77 -22
  65. data/test/assertions.rb +32 -39
  66. data/test/client/bulk_test.rb +166 -141
  67. data/test/client/cluster_test.rb +35 -13
  68. data/test/client/docs_test.rb +387 -274
  69. data/test/client/errors_test.rb +38 -40
  70. data/test/client/index_test.rb +243 -202
  71. data/test/client/multi_percolate_test.rb +46 -41
  72. data/test/client/multi_search_test.rb +122 -67
  73. data/test/client/native_delete_by_query_test.rb +96 -88
  74. data/test/client/nodes_test.rb +21 -10
  75. data/test/client/percolator_test.rb +19 -14
  76. data/test/client/reindex_test.rb +76 -0
  77. data/test/client/repository_test.rb +31 -19
  78. data/test/client/rest_api_spec/api_spec_test.rb +13 -11
  79. data/test/client/rest_api_spec/rest_api_test.rb +9 -7
  80. data/test/client/scroller_test.rb +44 -70
  81. data/test/client/snapshot_test.rb +38 -21
  82. data/test/client/stubbed_client_test.rb +7 -4
  83. data/test/client/tasks_test.rb +12 -17
  84. data/test/client/template_test.rb +34 -13
  85. data/test/client/update_by_query_test.rb +137 -0
  86. data/test/client_test.rb +158 -92
  87. data/test/core_ext/time_test.rb +14 -12
  88. data/test/middleware/encode_json_test.rb +18 -7
  89. data/test/middleware/opaque_id_test.rb +18 -14
  90. data/test/middleware/parse_json_test.rb +17 -9
  91. data/test/mock_response.rb +30 -0
  92. data/test/notifications_test.rb +15 -8
  93. data/test/test_helper.rb +40 -97
  94. data/test/version_support_test.rb +13 -78
  95. metadata +60 -208
  96. data/.overcommit.yml +0 -5
  97. data/.travis.yml +0 -34
  98. data/docker/docker-compose.cibuild.yml +0 -8
  99. data/docker/docker-compose.es24.yml +0 -34
  100. data/docker/docker-compose.es56.yml +0 -37
  101. data/docs/warmers.md +0 -3
  102. data/lib/elastomer/client/app_delete_by_query.rb +0 -144
  103. data/lib/elastomer/client/rest_api_spec/api_spec_v2_3.rb +0 -2232
  104. data/lib/elastomer/client/rest_api_spec/api_spec_v2_4.rb +0 -2250
  105. data/lib/elastomer/client/warmer.rb +0 -98
  106. data/lib/elastomer/version.rb +0 -7
  107. data/lib/elastomer/version_support.rb +0 -182
  108. data/script/cibuild +0 -103
  109. data/script/cibuild-elastomer-client +0 -1
  110. data/script/cibuild-elastomer-client-es24 +0 -8
  111. data/script/cibuild-elastomer-client-es56 +0 -8
  112. data/test/client/app_delete_by_query_test.rb +0 -192
  113. data/test/client/es_5_x_warmer_test.rb +0 -13
  114. data/test/client/warmer_test.rb +0 -60
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "../test_helper"
2
4
 
3
- describe Elastomer::Client::Snapshot do
5
+ describe ElastomerClient::Client::Snapshot do
4
6
  before do
5
7
  @index = nil
6
8
  @restored_index = nil
@@ -12,6 +14,9 @@ describe Elastomer::Client::Snapshot do
12
14
  @index_name = "elastomer-snapshot-test-index"
13
15
  @index = $client.index(@index_name)
14
16
  @name = "elastomer-test"
17
+ if $client.version_support.es_version_8_plus?
18
+ $client.cluster.update_settings persistent: { "ingest.geoip.downloader.enabled" => "false" }
19
+ end
15
20
  end
16
21
 
17
22
  after do
@@ -21,24 +26,28 @@ describe Elastomer::Client::Snapshot do
21
26
  it "determines if a snapshot exists" do
22
27
  with_tmp_repo do |repo|
23
28
  snapshot = repo.snapshot(@name)
24
- assert_equal false, snapshot.exists?
25
- assert_equal false, snapshot.exist?
26
- snapshot.create({}, :wait_for_completion => true)
27
- assert_equal true, snapshot.exist?
29
+
30
+ refute_predicate snapshot, :exists?
31
+ refute_predicate snapshot, :exist?
32
+ snapshot.create({}, wait_for_completion: true)
33
+
34
+ assert_predicate snapshot, :exist?
28
35
  end
29
36
  end
30
37
 
31
38
  it "creates snapshots" do
32
39
  with_tmp_repo do |repo|
33
- response = repo.snapshot(@name).create({}, :wait_for_completion => true)
40
+ response = repo.snapshot(@name).create({}, wait_for_completion: true)
41
+
34
42
  assert_equal @name, response["snapshot"]["snapshot"]
35
43
  end
36
44
  end
37
45
 
38
46
  it "creates snapshots with options" do
39
- @index.create(:number_of_shards => 1, :number_of_replicas => 0)
47
+ @index.create(settings: { number_of_shards: 1, number_of_replicas: 0 })
40
48
  with_tmp_repo do |repo|
41
- response = repo.snapshot(@name).create({:indices => [@index_name]}, :wait_for_completion => true)
49
+ response = repo.snapshot(@name).create({ indices: [@index_name] }, wait_for_completion: true)
50
+
42
51
  assert_equal [@index_name], response["snapshot"]["indices"]
43
52
  assert_equal 1, response["snapshot"]["shards"]["total"]
44
53
  end
@@ -47,17 +56,20 @@ describe Elastomer::Client::Snapshot do
47
56
  it "gets snapshot info for one and all" do
48
57
  with_tmp_snapshot do |snapshot, repo|
49
58
  response = snapshot.get
59
+
50
60
  assert_equal snapshot.name, response["snapshots"][0]["snapshot"]
51
61
  response = repo.snapshots.get
62
+
52
63
  assert_equal snapshot.name, response["snapshots"][0]["snapshot"]
53
64
  end
54
65
  end
55
66
 
56
67
  it "gets snapshot status for one and all" do
57
- @index.create(:number_of_shards => 1, :number_of_replicas => 0)
68
+ @index.create(settings: { number_of_shards: 1, number_of_replicas: 0 })
58
69
  with_tmp_repo do |repo|
59
- repo.snapshot(@name).create({:indices => [@index_name]}, :wait_for_completion => true)
70
+ repo.snapshot(@name).create({indices: [@index_name]}, wait_for_completion: true)
60
71
  response = repo.snapshot(@name).status
72
+
61
73
  assert_equal 1, response["snapshots"][0]["shards_stats"]["total"]
62
74
  end
63
75
  end
@@ -67,9 +79,11 @@ describe Elastomer::Client::Snapshot do
67
79
  # check for an empty result instead
68
80
  with_tmp_repo do |repo|
69
81
  response = repo.snapshots.status
70
- assert_equal [], response["snapshots"]
82
+
83
+ assert_empty response["snapshots"]
71
84
  response = $client.snapshot.status
72
- assert_equal [], response["snapshots"]
85
+
86
+ assert_empty response["snapshots"]
73
87
  end
74
88
  end
75
89
 
@@ -81,18 +95,20 @@ describe Elastomer::Client::Snapshot do
81
95
  it "deletes snapshots" do
82
96
  with_tmp_snapshot do |snapshot|
83
97
  response = snapshot.delete
84
- assert_equal true, response["acknowledged"]
98
+
99
+ assert response["acknowledged"]
85
100
  end
86
101
  end
87
102
 
88
103
  it "restores snapshots" do
89
- @index.create(:number_of_shards => 1, :number_of_replicas => 0)
104
+ @index.create(settings: { number_of_shards: 1, number_of_replicas: 0 })
90
105
  wait_for_index(@index_name)
91
106
  with_tmp_repo do |repo|
92
107
  snapshot = repo.snapshot(@name)
93
- snapshot.create({:indices => [@index_name]}, :wait_for_completion => true)
108
+ snapshot.create({ indices: [@index_name] }, wait_for_completion: true)
94
109
  @index.delete
95
- response = snapshot.restore({}, :wait_for_completion => true)
110
+ response = snapshot.restore({}, wait_for_completion: true)
111
+
96
112
  assert_equal 1, response["snapshot"]["shards"]["total"]
97
113
  end
98
114
  end
@@ -108,15 +124,16 @@ describe Elastomer::Client::Snapshot do
108
124
  end
109
125
 
110
126
  it "restores snapshots with options" do
111
- @index.create(:number_of_shards => 1, :number_of_replicas => 0)
127
+ @index.create(settings: { number_of_shards: 1, number_of_replicas: 0 })
112
128
  wait_for_index(@index_name)
113
129
  with_tmp_repo do |repo|
114
130
  snapshot = repo.snapshot(@name)
115
- snapshot.create({:indices => [@index_name]}, :wait_for_completion => true)
131
+ snapshot.create({indices: [@index_name]}, wait_for_completion: true)
116
132
  response = snapshot.restore({
117
- :rename_pattern => @index_name,
118
- :rename_replacement => @restored_index_name
119
- }, :wait_for_completion => true)
133
+ rename_pattern: @index_name,
134
+ rename_replacement: @restored_index_name
135
+ }, wait_for_completion: true)
136
+
120
137
  assert_equal [@restored_index_name], response["snapshot"]["indices"]
121
138
  assert_equal 1, response["snapshot"]["shards"]["total"]
122
139
  end
@@ -1,21 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "../test_helper"
2
4
 
3
5
  describe "stubbed client tests" do
4
6
  before do
5
7
  @stubs = Faraday::Adapter.lookup_middleware(:test)::Stubs.new
6
- @client = Elastomer::Client.new :adapter => [:test, @stubs]
8
+ @client = ElastomerClient::Client.new adapter: [:test, @stubs]
7
9
  @client.instance_variable_set(:@version, "5.6.4")
8
10
  end
9
11
 
10
- describe Elastomer::Client::Cluster do
12
+ describe ElastomerClient::Client::Cluster do
11
13
  it "reroutes shards" do
12
14
  @stubs.post "/_cluster/reroute?dry_run=true" do |env|
13
15
  assert_match %r/^\{"commands":\[\{"move":\{[^\{\}]+\}\}\]\}$/, env[:body]
14
16
  [200, {"Content-Type" => "application/json"}, '{"acknowledged" : true}']
15
17
  end
16
18
 
17
- commands = { :move => { :index => "test", :shard => 0, :from_node => "node1", :to_node => "node2" }}
18
- h = @client.cluster.reroute commands, :dry_run => true
19
+ commands = { move: { index: "test", shard: 0, from_node: "node1", to_node: "node2" }}
20
+ h = @client.cluster.reroute commands, dry_run: true
21
+
19
22
  assert_acknowledged h
20
23
  end
21
24
  end
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "../test_helper"
2
4
 
3
- describe Elastomer::Client::Tasks do
5
+ describe ElastomerClient::Client::Tasks do
4
6
  before do
5
7
  @tasks = $client.tasks
6
8
 
@@ -15,20 +17,19 @@ describe Elastomer::Client::Tasks do
15
17
 
16
18
  it "list all in-flight tasks" do
17
19
  h = @tasks.get
18
- assert h["nodes"].keys.size > 0
20
+
21
+ assert_operator h["nodes"].keys.size, :>, 0
19
22
 
20
23
  total_tasks = h["nodes"].map { |k, v| v["tasks"].keys.count }.sum
21
- assert total_tasks > 0
24
+
25
+ assert_operator total_tasks, :>, 0
22
26
  end
23
27
 
24
28
  it "groups by parent->child relationships when get-all tasks API is grouped by 'parents'" do
25
- unless $client.version_support.es_version_5_x?
26
- skip "Tasks API is not supported in ES version #{$client.version}"
27
- end
28
-
29
- h = @tasks.get :group_by => "parents"
29
+ h = @tasks.get group_by: "parents"
30
30
  parent_id = h["tasks"].select { |k, v| v.key?("children") }.keys.first
31
31
  childs_parent_ref = h.dig("tasks", parent_id, "children").first["parent_task_id"]
32
+
32
33
  assert_equal parent_id, childs_parent_ref
33
34
  end
34
35
 
@@ -47,7 +48,7 @@ describe Elastomer::Client::Tasks do
47
48
 
48
49
  it "raises exception when get_by_id is called w/invalid node ID is supplied" do
49
50
  assert_raises(ArgumentError) do
50
- @tasks.get_by_id nil, 42
51
+ @tasks.get_by_id nil, 42
51
52
  end
52
53
  end
53
54
 
@@ -64,7 +65,7 @@ describe Elastomer::Client::Tasks do
64
65
  begin
65
66
  resp = @tasks.wait_by_id t["node"], t["id"], "3s"
66
67
  success = !resp.key?("node_failures")
67
- rescue Elastomer::Client::ServerError => e
68
+ rescue ElastomerClient::Client::ServerError => e
68
69
  # this means the timeout expired before the task finished, but it's a good thing!
69
70
  success = /Timed out waiting for completion/ =~ e.message
70
71
  end
@@ -90,13 +91,7 @@ describe Elastomer::Client::Tasks do
90
91
  t = ts.values.first
91
92
  resp = @tasks.get_by_id t["node"], t["id"]
92
93
 
93
- # ES 5.x and 2.x responses are structured differently
94
- if $client.version_support.tasks_new_response_format?
95
- found_by_id = resp["task"]["node"] == t["node"] && resp["task"]["id"] == t["id"]
96
- else
97
- nid, tid = resp["nodes"][t["node"]]["tasks"].keys.first.split(":")
98
- found_by_id = nid == t["node"] && tid.to_i == t["id"]
99
- end
94
+ found_by_id = resp["task"]["node"] == t["node"] && resp["task"]["id"] == t["id"]
100
95
 
101
96
  break if found_by_id
102
97
  end
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "../test_helper"
2
4
 
3
- describe Elastomer::Client::Cluster do
5
+ describe ElastomerClient::Client::Cluster do
4
6
 
5
7
  before do
6
8
  @name = "elastomer-template-test"
@@ -12,27 +14,46 @@ describe Elastomer::Client::Cluster do
12
14
  end
13
15
 
14
16
  it "lists templates in the cluster" do
15
- @template.create({:template => "test-elastomer*"})
17
+ if $client.version_support.es_version_8_plus?
18
+ @template.create({index_patterns: ["test-elastomer*"]})
19
+ else
20
+ @template.create({template: "test-elastomer*"})
21
+ end
16
22
  templates = $client.cluster.templates
17
- assert !templates.empty?, "expected to see a template"
23
+
24
+ refute_empty templates, "expected to see a template"
18
25
  end
19
26
 
20
27
  it "creates a template" do
21
- assert !@template.exists?, "the template should not exist"
22
-
23
- @template.create({
24
- :template => "test-elastomer*",
25
- :settings => { :number_of_shards => 3 },
26
- :mappings => {
27
- :doco => { :_source => { :enabled => false }}
28
- }
28
+ refute_predicate @template, :exists?, "the template should not exist"
29
+
30
+ if $client.version_support.es_version_8_plus?
31
+ template_config = {index_patterns: ["test-elastomer*"]}
32
+ else
33
+ template_config = {template: "test-elastomer*"}
34
+ end
35
+
36
+ template_config.merge!({
37
+ settings: { number_of_shards: 3 },
38
+ mappings: mappings_wrapper("book", {
39
+ _source: { enabled: false }
40
+ })
29
41
  })
30
42
 
31
- assert @template.exists?, " we now have a cluster-test template"
43
+ @template.create(template_config)
44
+
45
+ assert_predicate @template, :exists?, " we now have a cluster-test template"
32
46
 
33
47
  template = @template.get
48
+
34
49
  assert_equal [@name], template.keys
35
- assert_equal "test-elastomer*", template[@name]["template"]
50
+
51
+ if $client.version_support.es_version_8_plus?
52
+ assert_equal "test-elastomer*", template[@name]["index_patterns"][0]
53
+ else
54
+ assert_equal "test-elastomer*", template[@name]["template"]
55
+ end
56
+
36
57
  assert_equal "3", template[@name]["settings"]["index"]["number_of_shards"]
37
58
  end
38
59
  end
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../test_helper"
4
+
5
+ describe ElastomerClient::Client::UpdateByQuery do
6
+ before do
7
+ @index = $client.index "elastomer-update-by-query-test"
8
+ @index.delete if @index.exists?
9
+ @docs = @index.docs("docs")
10
+ end
11
+
12
+ after do
13
+ @index.delete if @index.exists?
14
+ end
15
+
16
+ describe "when an index with documents exists" do
17
+ before do
18
+ @index.create(nil)
19
+ wait_for_index(@index.name)
20
+ end
21
+
22
+ it "updates by query" do
23
+ @docs.index({ _id: 0, name: "mittens" })
24
+ @docs.index({ _id: 1, name: "luna" })
25
+
26
+ @index.refresh
27
+
28
+ query = {
29
+ query: {
30
+ match: {
31
+ name: "mittens"
32
+ }
33
+ },
34
+ script: {
35
+ source: "ctx._source.name = 'mittens updated'"
36
+ }
37
+ }
38
+
39
+ response = @index.update_by_query(query)
40
+
41
+ refute_nil response["took"]
42
+ refute(response["timed_out"])
43
+ assert_equal(1, response["batches"])
44
+ assert_equal(1, response["total"])
45
+ assert_equal(1, response["updated"])
46
+ assert_empty(response["failures"])
47
+
48
+ @index.refresh
49
+ response = @docs.multi_get(ids: [0, 1])
50
+
51
+ assert_equal "mittens updated", response.fetch("docs")[0]["_source"]["name"]
52
+ assert_equal "luna", response.fetch("docs")[1]["_source"]["name"]
53
+ end
54
+
55
+ it "fails when internal version is 0" do
56
+ if $client.version_support.es_version_8_plus?
57
+ skip "Concurrency control with internal version is not supported in ES #{$client.version}"
58
+ end
59
+ @docs.index({_id: 0, name: "mittens"})
60
+ # Creating a document with external version 0 also sets the internal version to 0
61
+ # Otherwise you can't index a document with version 0.
62
+ @docs.index({_id: 1, _version: 0, _version_type: "external", name: "mittens"})
63
+ @index.refresh
64
+
65
+ query = {
66
+ query: {
67
+ match: {
68
+ name: "mittens"
69
+ }
70
+ }
71
+ }
72
+
73
+ assert_raises(ElastomerClient::Client::RequestError) do
74
+ @index.update_by_query(query)
75
+ end
76
+ end
77
+
78
+ it "fails when an unknown parameter is provided" do
79
+ assert_raises(ElastomerClient::Client::IllegalArgument) do
80
+ @index.update_by_query({}, foo: "bar")
81
+ end
82
+ end
83
+
84
+ it "updates by query when routing is specified" do
85
+ index = $client.index "elastomer-update-by-query-routing-test"
86
+ index.delete if index.exists?
87
+ type = "docs"
88
+ # default number of shards in ES8 is 1, so set it to 2 shards so routing to different shards can be tested
89
+ settings = $client.version_support.es_version_8_plus? ? { number_of_shards: 2 } : {}
90
+ index.create({
91
+ settings:,
92
+ mappings: mappings_wrapper(type, {
93
+ properties: {
94
+ name: { type: "text", analyzer: "standard" },
95
+ },
96
+ _routing: { required: true }
97
+ })
98
+ })
99
+ wait_for_index(@index.name)
100
+ docs = index.docs(type)
101
+
102
+ docs.index({ _id: 0, _routing: "cat", name: "mittens" })
103
+ docs.index({ _id: 1, _routing: "cat", name: "luna" })
104
+ docs.index({ _id: 2, _routing: "dog", name: "mittens" })
105
+
106
+ query = {
107
+ query: {
108
+ match: {
109
+ name: "mittens"
110
+ }
111
+ },
112
+ script: {
113
+ source: "ctx._source.name = 'mittens updated'"
114
+ }
115
+ }
116
+
117
+ index.refresh
118
+ response = index.update_by_query(query, routing: "cat")
119
+
120
+ assert_equal(1, response["updated"])
121
+
122
+ response = docs.multi_get({
123
+ docs: [
124
+ { _id: 0, routing: "cat" },
125
+ { _id: 1, routing: "cat" },
126
+ { _id: 2, routing: "dog" },
127
+ ]
128
+ })
129
+
130
+ assert_equal "mittens updated", response.fetch("docs")[0]["_source"]["name"]
131
+ assert_equal "luna", response.fetch("docs")[1]["_source"]["name"]
132
+ assert_equal "mittens", response.fetch("docs")[2]["_source"]["name"]
133
+
134
+ index.delete if index.exists?
135
+ end
136
+ end
137
+ end