elastomer-client 2.3.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.travis.yml +0 -4
  4. data/CHANGELOG.md +8 -0
  5. data/docker/docker-compose.cibuild.yml +8 -0
  6. data/docker/docker-compose.es24.yml +34 -0
  7. data/docker/docker-compose.es56.yml +37 -0
  8. data/docker/elasticsearch.yml +15 -0
  9. data/docs/index.md +2 -2
  10. data/docs/notifications.md +1 -1
  11. data/elastomer-client.gemspec +2 -0
  12. data/lib/elastomer/client.rb +86 -33
  13. data/lib/elastomer/client/app_delete_by_query.rb +158 -0
  14. data/lib/elastomer/client/delete_by_query.rb +8 -115
  15. data/lib/elastomer/client/docs.rb +63 -13
  16. data/lib/elastomer/client/errors.rb +10 -2
  17. data/lib/elastomer/client/index.rb +40 -12
  18. data/lib/elastomer/client/multi_percolate.rb +2 -2
  19. data/lib/elastomer/client/native_delete_by_query.rb +60 -0
  20. data/lib/elastomer/client/percolator.rb +6 -3
  21. data/lib/elastomer/client/scroller.rb +22 -7
  22. data/lib/elastomer/client/tasks.rb +188 -0
  23. data/lib/elastomer/client/warmer.rb +6 -0
  24. data/lib/elastomer/notifications.rb +1 -0
  25. data/lib/elastomer/version.rb +1 -1
  26. data/lib/elastomer/version_support.rb +177 -0
  27. data/script/cibuild +77 -6
  28. data/script/cibuild-elastomer-client +1 -0
  29. data/script/cibuild-elastomer-client-es24 +8 -0
  30. data/script/cibuild-elastomer-client-es56 +8 -0
  31. data/script/poll-for-es +20 -0
  32. data/test/client/{delete_by_query_test.rb → app_delete_by_query_test.rb} +7 -7
  33. data/test/client/bulk_test.rb +9 -13
  34. data/test/client/cluster_test.rb +2 -2
  35. data/test/client/docs_test.rb +133 -49
  36. data/test/client/errors_test.rb +21 -1
  37. data/test/client/es_5_x_warmer_test.rb +13 -0
  38. data/test/client/index_test.rb +104 -39
  39. data/test/client/multi_percolate_test.rb +13 -6
  40. data/test/client/multi_search_test.rb +5 -5
  41. data/test/client/native_delete_by_query_test.rb +123 -0
  42. data/test/client/nodes_test.rb +1 -1
  43. data/test/client/percolator_test.rb +10 -2
  44. data/test/client/repository_test.rb +1 -1
  45. data/test/client/scroller_test.rb +16 -6
  46. data/test/client/snapshot_test.rb +1 -1
  47. data/test/client/stubbed_client_test.rb +1 -1
  48. data/test/client/tasks_test.rb +139 -0
  49. data/test/client/template_test.rb +1 -1
  50. data/test/client/warmer_test.rb +8 -4
  51. data/test/client_test.rb +99 -0
  52. data/test/core_ext/time_test.rb +1 -1
  53. data/test/notifications_test.rb +4 -0
  54. data/test/test_helper.rb +129 -21
  55. data/test/version_support_test.rb +119 -0
  56. metadata +59 -5
@@ -1,4 +1,4 @@
1
- require File.expand_path("../../test_helper", __FILE__)
1
+ require_relative "../test_helper"
2
2
 
3
3
  describe Elastomer::Client::Error do
4
4
 
@@ -72,4 +72,24 @@ describe Elastomer::Client::Error do
72
72
  assert !Elastomer::Client::ConnectionFailed.fatal, "Connection failures are not fatal"
73
73
  assert !Elastomer::Client::ServerError.fatal, "Server errors are not fatal"
74
74
  end
75
+
76
+ if parameter_validation?
77
+ it "wraps illegal argument exceptions" do
78
+ begin
79
+ $client.get("/_cluster/health?consistency=all")
80
+ assert false, "IllegalArgument exception was not raised"
81
+ rescue Elastomer::Client::IllegalArgument => err
82
+ assert_match(/request \[\/_cluster\/health\] contains unrecognized parameter: \[consistency\]/, err.message)
83
+ end
84
+ end
85
+ else
86
+ it "does not raise illegal argument exceptions" do
87
+ begin
88
+ $client.get("/_cluster/health?consistency=all")
89
+ assert true, "Exception was not raised"
90
+ rescue Elastomer::Client::Error => err
91
+ assert false, "Exception #{err} was raised"
92
+ end
93
+ end
94
+ end
75
95
  end
@@ -0,0 +1,13 @@
1
+ require_relative "../test_helper"
2
+
3
+ describe "Elastomer::Client::Warmer under ES 5.x" do
4
+ it "cannot be instantiated" do
5
+ if $client.version_support.supports_warmers?
6
+ skip "warmers are still supported in ES #{$client.version}."
7
+ end
8
+
9
+ assert_raises(Elastomer::Client::IncompatibleVersionException) do
10
+ Elastomer::Client::Warmer.new($client, "index", "warmer")
11
+ end
12
+ end
13
+ end
@@ -1,4 +1,4 @@
1
- require File.expand_path("../../test_helper", __FILE__)
1
+ require_relative "../test_helper"
2
2
 
3
3
  describe Elastomer::Client::Index do
4
4
 
@@ -55,8 +55,8 @@ describe Elastomer::Client::Index do
55
55
  :_source => { :enabled => false },
56
56
  :_all => { :enabled => false },
57
57
  :properties => {
58
- :title => { :type => "string", :analyzer => "standard" },
59
- :author => { :type => "string", :index => "not_analyzed" }
58
+ :title => $client.version_support.text(analyzer: "standard"),
59
+ :author => $client.version_support.keyword
60
60
  }
61
61
  }
62
62
  }
@@ -74,8 +74,8 @@ describe Elastomer::Client::Index do
74
74
  :_source => { :enabled => false },
75
75
  :_all => { :enabled => false },
76
76
  :properties => {
77
- :title => { :type => "string", :analyzer => "standard" },
78
- :author => { :type => "string", :index => "not_analyzed" }
77
+ :title => $client.version_support.text(analyzer: "standard"),
78
+ :author => $client.version_support.keyword
79
79
  }
80
80
  }
81
81
  }
@@ -110,7 +110,7 @@ describe Elastomer::Client::Index do
110
110
  :doco => {
111
111
  :_source => { :enabled => false },
112
112
  :_all => { :enabled => false },
113
- :properties => {:title => { :type => "string", :analyzer => "standard" }}
113
+ :properties => {:title => $client.version_support.text(analyzer: "standard")}
114
114
  }
115
115
  }
116
116
  )
@@ -118,14 +118,14 @@ describe Elastomer::Client::Index do
118
118
  assert_property_exists @index.mapping[@name], "doco", "title"
119
119
 
120
120
  @index.update_mapping "doco", { :doco => { :properties => {
121
- :author => { :type => "string", :index => "not_analyzed" }
121
+ :author => $client.version_support.keyword
122
122
  }}}
123
123
 
124
124
  assert_property_exists @index.mapping[@name], "doco", "author"
125
125
  assert_property_exists @index.mapping[@name], "doco", "title"
126
126
 
127
127
  @index.update_mapping "mux_mool", { :mux_mool => { :properties => {
128
- :song => { :type => "string", :index => "not_analyzed" }
128
+ :song => $client.version_support.keyword
129
129
  }}}
130
130
 
131
131
  assert_property_exists @index.mapping[@name], "mux_mool", "song"
@@ -137,7 +137,7 @@ describe Elastomer::Client::Index do
137
137
  :doco => {
138
138
  :_source => { :enabled => false },
139
139
  :_all => { :enabled => false },
140
- :properties => {:title => { :type => "string", :analyzer => "standard" }}
140
+ :properties => {:title => $client.version_support.text(analyzer: "standard")}
141
141
  }
142
142
  }
143
143
  )
@@ -145,14 +145,14 @@ describe Elastomer::Client::Index do
145
145
  assert_property_exists @index.mapping[@name], "doco", "title"
146
146
 
147
147
  @index.put_mapping "doco", { :doco => { :properties => {
148
- :author => { :type => "string", :index => "not_analyzed" }
148
+ :author => $client.version_support.keyword
149
149
  }}}
150
150
 
151
151
  assert_property_exists @index.mapping[@name], "doco", "author"
152
152
  assert_property_exists @index.mapping[@name], "doco", "title"
153
153
 
154
154
  @index.put_mapping "mux_mool", { :mux_mool => { :properties => {
155
- :song => { :type => "string", :index => "not_analyzed" }
155
+ :song => $client.version_support.keyword
156
156
  }}}
157
157
 
158
158
  assert_property_exists @index.mapping[@name], "mux_mool", "song"
@@ -163,10 +163,29 @@ describe Elastomer::Client::Index do
163
163
  assert_equal({@name => {"aliases" => {}}}, @index.get_aliases)
164
164
 
165
165
  $client.cluster.update_aliases :add => {:index => @name, :alias => "foofaloo"}
166
- assert_equal({@name => {"aliases" => {"foofaloo" => {}}}}, @index.get_aliases)
166
+ $client.cluster.update_aliases :add => {:index => @name, :alias => "bar"}
167
+
168
+ assert_equal({@name => {"aliases" => {"foofaloo" => {}, "bar" => {}}}}, @index.get_aliases)
167
169
 
168
170
  assert_equal({@name => {"aliases" => {"foofaloo" => {}}}}, @index.get_alias("f*"))
169
- assert_equal({}, @index.get_alias("r*"))
171
+ assert_equal({@name => {"aliases" => {"foofaloo" => {}, "bar" => {}}}}, @index.get_alias("*"))
172
+
173
+ if fetching_non_existent_alias_returns_error?
174
+ exception = assert_raises(Elastomer::Client::RequestError) do
175
+ @index.get_alias("not-there")
176
+ end
177
+ assert_equal("alias [not-there] missing", exception.message)
178
+ assert_equal(404, exception.status)
179
+
180
+ exception = assert_raises(Elastomer::Client::RequestError) do
181
+ @index.get_alias("not*")
182
+ end
183
+ assert_equal("alias [not*] missing", exception.message)
184
+ assert_equal(404, exception.status)
185
+ else
186
+ assert_equal({}, @index.get_alias("not-there"))
187
+ assert_equal({}, @index.get_alias("not*"))
188
+ end
170
189
  end
171
190
 
172
191
  it "adds and deletes aliases to the index" do
@@ -186,7 +205,7 @@ describe Elastomer::Client::Index do
186
205
  end
187
206
 
188
207
  it "analyzes text and returns tokens" do
189
- tokens = @index.analyze "Just a few words to analyze.", :analyzer => "standard", :index => nil
208
+ tokens = @index.analyze({text: "Just a few words to analyze.", analyzer: "standard"}, index: nil)
190
209
  tokens = tokens["tokens"].map { |h| h["token"] }
191
210
  assert_equal %w[just a few words to analyze], tokens
192
211
 
@@ -206,7 +225,7 @@ describe Elastomer::Client::Index do
206
225
  )
207
226
  wait_for_index(@name)
208
227
 
209
- tokens = @index.analyze "Just a few words to analyze.", :analyzer => "english_standard"
228
+ tokens = @index.analyze({text: "Just a few words to analyze.", analyzer: "english_standard"})
210
229
  tokens = tokens["tokens"].map { |h| h["token"] }
211
230
  assert_equal %w[just few words analyze], tokens
212
231
  end
@@ -224,9 +243,12 @@ describe Elastomer::Client::Index do
224
243
  :type => "completion",
225
244
  :analyzer => "simple",
226
245
  :search_analyzer => "simple",
227
- :payloads => false
228
246
  }
229
247
 
248
+ # COMPATIBILITY
249
+ # ES 5.x drops support for index-time payloads
250
+ suggest[:payloads] = false if index_time_payloads?
251
+
230
252
  @index.create(
231
253
  :settings => { :number_of_shards => 1, :number_of_replicas => 0 },
232
254
  :mappings => {
@@ -234,8 +256,8 @@ describe Elastomer::Client::Index do
234
256
  :_source => { :enabled => false },
235
257
  :_all => { :enabled => false },
236
258
  :properties => {
237
- :title => { :type => "string", :analyzer => "standard" },
238
- :author => { :type => "string", :index => "not_analyzed" },
259
+ :title => $client.version_support.text(analyzer: "standard"),
260
+ :author => $client.version_support.keyword,
239
261
  :suggest => suggest
240
262
  }
241
263
  }
@@ -270,11 +292,15 @@ describe Elastomer::Client::Index do
270
292
  assert_equal 0, response["_shards"]["failed"]
271
293
  end
272
294
 
273
- it "optimizes" do
274
- response = @index.optimize
295
+ it "force merges" do
296
+ response = @index.forcemerge
275
297
  assert_equal 0, response["_shards"]["failed"]
276
298
  end
277
299
 
300
+ it "optimizes through force merge" do
301
+ assert_equal @index.method(:forcemerge), @index.method(:optimize)
302
+ end
303
+
278
304
  it "recovery" do
279
305
  response = @index.recovery
280
306
  assert_includes response, "elastomer-index-test"
@@ -304,20 +330,25 @@ describe Elastomer::Client::Index do
304
330
  @index.docs("foo").index("foo" => "bar")
305
331
  @index.refresh
306
332
  r = @index.delete_by_query(:q => "*")
307
- assert_equal({
308
- "_all" => {
309
- "found" => 1,
310
- "deleted" => 1,
311
- "missing" => 0,
312
- "failed" => 0,
313
- },
314
- @name => {
315
- "found" => 1,
316
- "deleted" => 1,
317
- "missing" => 0,
318
- "failed" => 0,
319
- }
320
- }, r["_indices"])
333
+
334
+ if supports_native_delete_by_query?
335
+ assert_equal(1, r['deleted'])
336
+ else
337
+ assert_equal({
338
+ "_all" => {
339
+ "found" => 1,
340
+ "deleted" => 1,
341
+ "missing" => 0,
342
+ "failed" => 0,
343
+ },
344
+ @name => {
345
+ "found" => 1,
346
+ "deleted" => 1,
347
+ "missing" => 0,
348
+ "failed" => 0,
349
+ }
350
+ }, r["_indices"])
351
+ end
321
352
  end
322
353
 
323
354
  it "creates a Percolator" do
@@ -327,6 +358,11 @@ describe Elastomer::Client::Index do
327
358
  end
328
359
 
329
360
  it "performs multi percolate queries" do
361
+ # COMPATIBILITY
362
+ if requires_percolator_mapping?
363
+ @index.update_mapping("percolator", { :properties => { :query => { :type => "percolator" } } })
364
+ end
365
+
330
366
  @index.docs.index \
331
367
  :_id => 1,
332
368
  :_type => "doco",
@@ -341,11 +377,12 @@ describe Elastomer::Client::Index do
341
377
 
342
378
  @index.percolator("1").create :query => { :match_all => { } }
343
379
  @index.percolator("2").create :query => { :match => { :author => "pea53" } }
380
+ @index.refresh
344
381
 
345
382
  h = @index.multi_percolate(:type => "doco") do |m|
346
383
  m.percolate :author => "pea53"
347
384
  m.percolate :author => "grantr"
348
- m.count({}, { :author => "grantr" })
385
+ m.count({ :author => "grantr" }, {})
349
386
  end
350
387
 
351
388
  response1, response2, response3 = h["responses"]
@@ -360,14 +397,14 @@ describe Elastomer::Client::Index do
360
397
  :_type => "doco",
361
398
  :title => "the magnificent",
362
399
  :author => "greg",
363
- :suggest => {:input => %w[Greg greg], :output => "Greg", :weight => 2}
400
+ :suggest => {:input => "greg", :weight => 2}
364
401
 
365
402
  @index.docs.index \
366
403
  :_id => 2,
367
404
  :_type => "doco",
368
405
  :title => "the author of rubber-band",
369
406
  :author => "grant",
370
- :suggest => {:input => %w[Grant grant], :output => "Grant", :weight => 1}
407
+ :suggest => {:input => "grant", :weight => 1}
371
408
 
372
409
  @index.refresh
373
410
  response = @index.suggest({:name => {:text => "gr", :completion => {:field => :suggest}}})
@@ -378,8 +415,36 @@ describe Elastomer::Client::Index do
378
415
 
379
416
  options = hash["options"]
380
417
  assert_equal 2, options.length
381
- assert_equal "Greg", options.first["text"]
382
- assert_equal "Grant", options.last["text"]
418
+ assert_equal "greg", options.first["text"]
419
+ assert_equal "grant", options.last["text"]
420
+ end
421
+
422
+ it "handles output parameter of field" do
423
+ document = {
424
+ _id: 1,
425
+ _type: "doco",
426
+ title: "the magnificent",
427
+ author: "greg",
428
+ suggest: {input: %w[Greg greg], output: "Greg", weight: 2}
429
+ }
430
+
431
+ if supports_suggest_output?
432
+ # It is not an error to index `output`...
433
+ @index.docs.index(document)
434
+
435
+ # ...and `output` is used in the search response
436
+ @index.refresh
437
+ response = @index.suggest({:name => {:text => "gr", :completion => {:field => :suggest}}})
438
+ assert_equal "Greg", response.fetch("name").first.fetch("options").first.fetch("text")
439
+ else
440
+ # Indexing the document fails when `output` is provided
441
+ exception = assert_raises(Elastomer::Client::RequestError) do
442
+ @index.docs.index(document)
443
+ end
444
+
445
+ assert_equal(400, exception.status)
446
+ assert_match(/\[output\]/, exception.message)
447
+ end
383
448
  end
384
449
  end
385
450
  end
@@ -1,4 +1,4 @@
1
- require File.expand_path("../../test_helper", __FILE__)
1
+ require_relative "../test_helper"
2
2
 
3
3
  describe Elastomer::Client::MultiPercolate do
4
4
 
@@ -7,25 +7,32 @@ describe Elastomer::Client::MultiPercolate do
7
7
  @index = $client.index(@name)
8
8
 
9
9
  unless @index.exists?
10
- @index.create \
10
+ base_mappings_settings = {
11
11
  :settings => { "index.number_of_shards" => 1, "index.number_of_replicas" => 0 },
12
12
  :mappings => {
13
13
  :doc1 => {
14
14
  :_source => { :enabled => true }, :_all => { :enabled => false },
15
15
  :properties => {
16
- :title => { :type => "string", :analyzer => "standard" },
17
- :author => { :type => "string", :index => "not_analyzed" }
16
+ :title => $client.version_support.text(analyzer: "standard"),
17
+ :author => $client.version_support.keyword
18
18
  }
19
19
  },
20
20
  :doc2 => {
21
21
  :_source => { :enabled => true }, :_all => { :enabled => false },
22
22
  :properties => {
23
- :title => { :type => "string", :analyzer => "standard" },
24
- :author => { :type => "string", :index => "not_analyzed" }
23
+ :title => $client.version_support.text(analyzer: "standard"),
24
+ :author => $client.version_support.keyword
25
25
  }
26
26
  }
27
27
  }
28
+ }
28
29
 
30
+ # COMPATIBILITY
31
+ if requires_percolator_mapping?
32
+ base_mappings_settings[:mappings][:percolator] = { :properties => { :query => { :type => "percolator" } } }
33
+ end
34
+
35
+ @index.create base_mappings_settings
29
36
  wait_for_index(@name)
30
37
  end
31
38
 
@@ -1,4 +1,4 @@
1
- require File.expand_path("../../test_helper", __FILE__)
1
+ require_relative "../test_helper"
2
2
 
3
3
  describe Elastomer::Client::MultiSearch do
4
4
 
@@ -13,15 +13,15 @@ describe Elastomer::Client::MultiSearch do
13
13
  :doc1 => {
14
14
  :_source => { :enabled => true }, :_all => { :enabled => false },
15
15
  :properties => {
16
- :title => { :type => "string", :analyzer => "standard" },
17
- :author => { :type => "string", :index => "not_analyzed" }
16
+ :title => $client.version_support.text(analyzer: "standard"),
17
+ :author => $client.version_support.keyword
18
18
  }
19
19
  },
20
20
  :doc2 => {
21
21
  :_source => { :enabled => true }, :_all => { :enabled => false },
22
22
  :properties => {
23
- :title => { :type => "string", :analyzer => "standard" },
24
- :author => { :type => "string", :index => "not_analyzed" }
23
+ :title => $client.version_support.text(analyzer: "standard"),
24
+ :author => $client.version_support.keyword
25
25
  }
26
26
  }
27
27
  }
@@ -0,0 +1,123 @@
1
+ require_relative "../test_helper"
2
+
3
+ describe Elastomer::Client::NativeDeleteByQuery do
4
+ before do
5
+ @index = $client.index "elastomer-delete-by-query-test"
6
+ @index.delete if @index.exists?
7
+ @docs = @index.docs("docs")
8
+ end
9
+
10
+ after do
11
+ @index.delete if @index.exists?
12
+ end
13
+
14
+ if supports_native_delete_by_query?
15
+ describe "when an index with documents exists" do
16
+ before do
17
+ @index.create(nil)
18
+ wait_for_index(@index.name)
19
+ end
20
+
21
+ it "deletes by query" do
22
+ @docs.index({ :_id => 0, :name => "mittens" })
23
+ @docs.index({ :_id => 1, :name => "luna" })
24
+
25
+ @index.refresh
26
+
27
+ query = {
28
+ query: {
29
+ match: {
30
+ name: "mittens"
31
+ }
32
+ }
33
+ }
34
+
35
+ response = @index.native_delete_by_query(query)
36
+ refute_nil response["took"]
37
+ assert_equal(false, response["timed_out"])
38
+ assert_equal(1, response["batches"])
39
+ assert_equal(1, response["total"])
40
+ assert_equal(1, response["deleted"])
41
+ assert_empty(response["failures"])
42
+
43
+ @index.refresh
44
+ response = @docs.multi_get(:ids => [0, 1])
45
+ refute_found response.fetch("docs")[0]
46
+ assert_found response.fetch("docs")[1]
47
+ end
48
+
49
+ it "fails when internal version is 0" do
50
+ @docs.index({_id: 0, name: "mittens"})
51
+ # Creating a document with external version 0 also sets the internal version to 0
52
+ # Otherwise you can't index a document with version 0.
53
+ @docs.index({_id: 1, _version: 0, _version_type: "external", name: "mittens"})
54
+ @index.refresh
55
+
56
+ query = {
57
+ query: {
58
+ match: {
59
+ name: "mittens"
60
+ }
61
+ }
62
+ }
63
+
64
+ assert_raises(Elastomer::Client::RequestError) do
65
+ @index.native_delete_by_query(query)
66
+ end
67
+ end
68
+
69
+ it "fails when an unknown parameter is provided" do
70
+ assert_raises(Elastomer::Client::IllegalArgument) do
71
+ @index.native_delete_by_query({}, foo: "bar")
72
+ end
73
+ end
74
+
75
+ it "deletes by query when routing is specified" do
76
+ index = $client.index "elastomer-delete-by-query-routing-test"
77
+ index.delete if index.exists?
78
+ type = "docs"
79
+ index.create({mappings: { type => { _routing: { required: true } } } })
80
+ wait_for_index(@index.name)
81
+ docs = index.docs(type)
82
+
83
+ docs.index({ :_id => 0, :_routing => "cat", :name => "mittens" })
84
+ docs.index({ :_id => 1, :_routing => "cat", :name => "luna" })
85
+ docs.index({ :_id => 2, :_routing => "dog", :name => "mittens" })
86
+
87
+ query = {
88
+ query: {
89
+ match: {
90
+ name: "mittens"
91
+ }
92
+ }
93
+ }
94
+
95
+ index.refresh
96
+ response = index.native_delete_by_query(query, routing: "cat")
97
+
98
+ assert_equal(1, response["deleted"])
99
+
100
+ response = docs.multi_get({
101
+ :docs => [
102
+ { :_id => 0, :_routing => "cat" },
103
+ { :_id => 1, :_routing => "cat" },
104
+ { :_id => 2, :_routing => "dog" },
105
+ ]
106
+ })
107
+ refute_found response["docs"][0]
108
+ assert_found response["docs"][1]
109
+ assert_found response["docs"][2]
110
+
111
+ index.delete if index.exists?
112
+ end
113
+ end
114
+ else
115
+ describe "when native _delete_by_query is not supported" do
116
+ it "raises an error" do
117
+ assert_raises(Elastomer::Client::IncompatibleVersionException) do
118
+ @index.native_delete_by_query({query: {match_all: {}}})
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end