chewy 0.8.3 → 0.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +43 -11
  3. data/Appraisals +39 -12
  4. data/CHANGELOG.md +42 -0
  5. data/Gemfile +1 -1
  6. data/README.md +60 -7
  7. data/chewy.gemspec +12 -5
  8. data/gemfiles/{rails.4.0.mongoid.gemfile → rails.4.0.mongoid.4.0.0.gemfile} +1 -1
  9. data/gemfiles/{rails.4.0.mongoid.kaminari.gemfile → rails.4.0.mongoid.4.0.0.kaminari.gemfile} +1 -1
  10. data/gemfiles/{rails.4.0.mongoid.will_paginate.gemfile → rails.4.0.mongoid.4.0.0.will_paginate.gemfile} +1 -1
  11. data/gemfiles/rails.4.0.mongoid.5.1.0.gemfile +15 -0
  12. data/gemfiles/rails.4.0.mongoid.5.1.0.kaminari.gemfile +14 -0
  13. data/gemfiles/rails.4.0.mongoid.5.1.0.will_paginate.gemfile +14 -0
  14. data/gemfiles/{rails.4.1.mongoid.gemfile → rails.4.1.mongoid.4.0.0.gemfile} +1 -1
  15. data/gemfiles/{rails.4.1.mongoid.kaminari.gemfile → rails.4.1.mongoid.4.0.0.kaminari.gemfile} +1 -1
  16. data/gemfiles/{rails.4.1.mongoid.will_paginate.gemfile → rails.4.1.mongoid.4.0.0.will_paginate.gemfile} +1 -1
  17. data/gemfiles/rails.4.1.mongoid.5.1.0.gemfile +15 -0
  18. data/gemfiles/rails.4.1.mongoid.5.1.0.kaminari.gemfile +14 -0
  19. data/gemfiles/rails.4.1.mongoid.5.1.0.will_paginate.gemfile +14 -0
  20. data/gemfiles/{rails.4.2.mongoid.gemfile → rails.4.2.mongoid.4.0.0.gemfile} +1 -1
  21. data/gemfiles/{rails.4.2.mongoid.kaminari.gemfile → rails.4.2.mongoid.4.0.0.kaminari.gemfile} +1 -1
  22. data/gemfiles/{rails.4.2.mongoid.will_paginate.gemfile → rails.4.2.mongoid.4.0.0.will_paginate.gemfile} +1 -1
  23. data/gemfiles/rails.4.2.mongoid.5.1.0.gemfile +15 -0
  24. data/gemfiles/rails.4.2.mongoid.5.1.0.kaminari.gemfile +14 -0
  25. data/gemfiles/rails.4.2.mongoid.5.1.0.will_paginate.gemfile +14 -0
  26. data/gemfiles/rails.5.0.0.beta3.activerecord.gemfile +16 -0
  27. data/gemfiles/rails.5.0.0.beta3.activerecord.kaminari.gemfile +16 -0
  28. data/gemfiles/rails.5.0.0.beta3.activerecord.will_paginate.gemfile +15 -0
  29. data/gemfiles/{sequel.4.28.gemfile → sequel.4.31.gemfile} +1 -1
  30. data/lib/chewy.rb +7 -1
  31. data/lib/chewy/errors.rb +6 -0
  32. data/lib/chewy/fields/base.rb +12 -8
  33. data/lib/chewy/fields/root.rb +1 -1
  34. data/lib/chewy/index.rb +17 -8
  35. data/lib/chewy/index/actions.rb +4 -4
  36. data/lib/chewy/query.rb +8 -13
  37. data/lib/chewy/query/compose.rb +2 -2
  38. data/lib/chewy/query/criteria.rb +2 -2
  39. data/lib/chewy/query/loading.rb +1 -1
  40. data/lib/chewy/query/nodes/bool.rb +1 -1
  41. data/lib/chewy/query/nodes/regexp.rb +2 -2
  42. data/lib/chewy/railtie.rb +15 -3
  43. data/lib/chewy/rake_helper.rb +5 -2
  44. data/lib/chewy/rspec/update_index.rb +17 -6
  45. data/lib/chewy/strategy.rb +7 -3
  46. data/lib/chewy/strategy/active_job.rb +2 -2
  47. data/lib/chewy/strategy/resque.rb +2 -2
  48. data/lib/chewy/strategy/sidekiq.rb +2 -2
  49. data/lib/chewy/type.rb +14 -0
  50. data/lib/chewy/type/adapter/active_record.rb +11 -1
  51. data/lib/chewy/type/adapter/orm.rb +13 -11
  52. data/lib/chewy/type/adapter/sequel.rb +10 -12
  53. data/lib/chewy/type/import.rb +53 -22
  54. data/lib/chewy/type/witchcraft.rb +208 -0
  55. data/lib/chewy/type/wrapper.rb +25 -7
  56. data/lib/chewy/version.rb +1 -1
  57. data/lib/tasks/chewy.rake +22 -14
  58. data/spec/chewy/fields/base_spec.rb +6 -2
  59. data/spec/chewy/fields/time_fields_spec.rb +4 -4
  60. data/spec/chewy/index/actions_spec.rb +32 -18
  61. data/spec/chewy/index_spec.rb +19 -0
  62. data/spec/chewy/query/pagination_spec.rb +1 -1
  63. data/spec/chewy/query_spec.rb +77 -21
  64. data/spec/chewy/rspec/update_index_spec.rb +75 -62
  65. data/spec/chewy/runtime_spec.rb +1 -1
  66. data/spec/chewy/strategy/active_job_spec.rb +6 -1
  67. data/spec/chewy/strategy/atomic_spec.rb +5 -5
  68. data/spec/chewy/strategy/resque_spec.rb +7 -2
  69. data/spec/chewy/strategy/sidekiq_spec.rb +6 -1
  70. data/spec/chewy/strategy_spec.rb +13 -1
  71. data/spec/chewy/type/actions_spec.rb +4 -1
  72. data/spec/chewy/type/import_spec.rb +71 -2
  73. data/spec/chewy/type/observe_spec.rb +9 -9
  74. data/spec/chewy/type/witchcraft_spec.rb +154 -0
  75. data/spec/chewy/type/wrapper_spec.rb +30 -5
  76. data/spec/chewy/type_spec.rb +10 -0
  77. data/spec/chewy_spec.rb +29 -5
  78. data/spec/spec_helper.rb +2 -0
  79. data/spec/support/class_helpers.rb +15 -0
  80. data/spec/support/mongoid.rb +5 -0
  81. metadata +64 -21
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  if defined?(::Resque)
4
4
  require 'resque_spec'
5
5
 
6
- describe Chewy::Strategy::Resque do
6
+ describe Chewy::Strategy::Resque, :orm do
7
7
  around { |example| Chewy.strategy(:bypass) { example.run } }
8
8
  before { ResqueSpec.reset! }
9
9
  before do
@@ -28,8 +28,13 @@ if defined?(::Resque)
28
28
  with_resque do
29
29
  expect { [city, other_city].map(&:save!) }
30
30
  .to update_index(CitiesIndex::City, strategy: :resque)
31
- .and_reindex(city, other_city)
31
+ .and_reindex(city, other_city).only
32
32
  end
33
33
  end
34
+
35
+ specify do
36
+ expect(CitiesIndex::City).to receive(:import!).with([city.id, other_city.id], {suffix: '201601'})
37
+ Chewy::Strategy::Resque::Worker.perform("CitiesIndex::City", [city.id, other_city.id], suffix: '201601')
38
+ end
34
39
  end
35
40
  end
@@ -28,8 +28,13 @@ if defined?(::Sidekiq)
28
28
  ::Sidekiq::Testing.inline! do
29
29
  expect { [city, other_city].map(&:save!) }
30
30
  .to update_index(CitiesIndex::City, strategy: :sidekiq)
31
- .and_reindex(city, other_city)
31
+ .and_reindex(city, other_city).only
32
32
  end
33
33
  end
34
+
35
+ specify do
36
+ expect(CitiesIndex::City).to receive(:import!).with([city.id, other_city.id], {suffix: '201601'})
37
+ Chewy::Strategy::Sidekiq::Worker.new.perform("CitiesIndex::City", [city.id, other_city.id], suffix: '201601')
38
+ end
34
39
  end
35
40
  end
@@ -14,7 +14,7 @@ describe Chewy::Strategy do
14
14
  end
15
15
 
16
16
  describe '#push' do
17
- specify { expect { strategy.push(:unexistant) }.to raise_error(NameError).with_message(/uninitialized constant.*Unexistant/) }
17
+ specify { expect { strategy.push(:unexistant) }.to raise_error(RuntimeError).with_message("Can't find update strategy `unexistant`") }
18
18
 
19
19
  specify do
20
20
  expect { strategy.push(:atomic) }
@@ -34,6 +34,18 @@ describe Chewy::Strategy do
34
34
  end
35
35
  end
36
36
 
37
+ describe '#wrap' do
38
+ specify { expect { strategy.wrap(:unexistant) {} }.to raise_error(RuntimeError).with_message("Can't find update strategy `unexistant`") }
39
+
40
+ specify do
41
+ expect do
42
+ strategy.wrap(:urgent) do
43
+ expect(strategy.current).to be_a(Chewy::Strategy::Urgent)
44
+ end
45
+ end.not_to change { strategy.current }
46
+ end
47
+ end
48
+
37
49
  context 'nesting', :orm do
38
50
  before do
39
51
  stub_model(:city) do
@@ -23,6 +23,9 @@ describe Chewy::Type::Actions, :orm do
23
23
  end
24
24
 
25
25
  describe '.reset' do
26
- specify { expect { city.reset }.to update_index(city) }
26
+ specify do
27
+ skip_on_plugin_missing_from_version('delete-by-query', '2.0')
28
+ expect { city.reset }.to update_index(city)
29
+ end
27
30
  end
28
31
  end
@@ -69,6 +69,43 @@ describe Chewy::Type::Import do
69
69
  ])
70
70
  end
71
71
 
72
+ context ':bulk_size' do
73
+ specify do
74
+ dummy_cities.first.destroy
75
+
76
+ imported = []
77
+ allow(CitiesIndex.client).to receive(:bulk) { |params| imported << params[:body]; nil }
78
+
79
+ city.import dummy_cities.map(&:id), bulk_size: 1.2.kilobyte
80
+ expect(imported.flatten).to match_array([
81
+ %Q({"delete":{"_id":1}}),
82
+ %Q({"index":{"_id":2}}\n{"name":"name1"}\n{"index":{"_id":3}}\n{"name":"name2"})
83
+ ])
84
+ end
85
+
86
+ context do
87
+ let!(:dummy_cities) { 3.times.map { |i| City.create(id: i + 1, name: "name#{i}" * 20) } }
88
+
89
+ specify do
90
+ dummy_cities.first.destroy
91
+
92
+ imported = []
93
+ allow(CitiesIndex.client).to receive(:bulk) { |params| imported << params[:body]; nil }
94
+
95
+ city.import dummy_cities.map(&:id), bulk_size: 1.2.kilobyte
96
+ expect(imported.flatten).to match_array([
97
+ %Q({"delete":{"_id":1}}),
98
+ %Q({"index":{"_id":2}}\n{"name":"#{'name1' * 20}"}),
99
+ %Q({"index":{"_id":3}}\n{"name":"#{'name2' * 20}"})
100
+ ])
101
+ end
102
+
103
+ specify do
104
+ expect { city.import dummy_cities.map(&:id), bulk_size: 1.1.kilobyte }.to raise_error ArgumentError
105
+ end
106
+ end
107
+ end
108
+
72
109
  specify do
73
110
  expect(CitiesIndex.client).to receive(:bulk).with(hash_including(refresh: true))
74
111
  city.import dummy_cities
@@ -83,7 +120,8 @@ describe Chewy::Type::Import do
83
120
  before do
84
121
  names = %w(name0 name1)
85
122
 
86
- criteria = if defined?(::Mongoid)
123
+ criteria = case adapter
124
+ when :mongoid
87
125
  { :name.in => names }
88
126
  else
89
127
  { name: names }
@@ -154,6 +192,7 @@ describe Chewy::Type::Import do
154
192
  end
155
193
 
156
194
  specify do
195
+ skip_on_version_gte('2.0', 'format of exception changed in 2.x')
157
196
  outer_payload = nil
158
197
  ActiveSupport::Notifications.subscribe('import_objects.chewy') do |name, start, finish, id, payload|
159
198
  outer_payload = payload
@@ -171,6 +210,25 @@ describe Chewy::Type::Import do
171
210
  import: {index: 3}
172
211
  })
173
212
  end
213
+
214
+ specify do
215
+ skip_on_version_lt('2.0', 'format of exception was changed')
216
+ outer_payload = nil
217
+ ActiveSupport::Notifications.subscribe('import_objects.chewy') do |name, start, finish, id, payload|
218
+ outer_payload = payload
219
+ end
220
+
221
+ city.import dummy_cities, batch_size: 2
222
+ expect(outer_payload).to eq({
223
+ type: CitiesIndex::City,
224
+ errors: {
225
+ index: {
226
+ {"type"=>"mapper_parsing_exception", "reason"=>"object mapping for [name] tried to parse field [name] as object, but found a concrete value"} => ["1", "2", "3"]
227
+ }
228
+ },
229
+ import: {index: 3}
230
+ })
231
+ end
174
232
  end
175
233
  end
176
234
 
@@ -332,7 +390,18 @@ describe Chewy::Type::Import do
332
390
  country.import canada
333
391
  end
334
392
 
335
- end # END root id
393
+ end
394
+
395
+ context 'default_import_options is set' do
396
+ before do
397
+ CitiesIndex::City.default_import_options(batch_size: 500, bulk_size: 1.megabyte)
398
+ end
399
+
400
+ specify do
401
+ expect(CitiesIndex::City.adapter).to receive(:import).with(batch_size: 500, bulk_size: 1.megabyte)
402
+ CitiesIndex::City.import
403
+ end
404
+ end
336
405
  end
337
406
 
338
407
  describe '.import!', :orm do
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Chewy::Type::Import do
3
+ describe Chewy::Type::Observe do
4
4
  describe '.update_index' do
5
5
  before do
6
6
  stub_index(:dummies) do
@@ -62,14 +62,14 @@ describe Chewy::Type::Import do
62
62
  let!(:country2) { Chewy.strategy(:atomic) { Country.create!(id: 2, update_condition: update_condition) } }
63
63
  let!(:city) { Chewy.strategy(:atomic) { City.create!(id: 1, country: country1) } }
64
64
 
65
- specify { expect { city.save! }.to update_index('cities#city').and_reindex(city) }
66
- specify { expect { city.save! }.to update_index('countries#country').and_reindex(country1) }
65
+ specify { expect { city.save! }.to update_index('cities#city').and_reindex(city).only }
66
+ specify { expect { city.save! }.to update_index('countries#country').and_reindex(country1).only }
67
67
 
68
- specify { expect { city.update_attributes!(country: nil) }.to update_index('cities#city').and_reindex(city) }
69
- specify { expect { city.update_attributes!(country: nil) }.to update_index('countries#country').and_reindex(country1) }
68
+ specify { expect { city.update_attributes!(country: nil) }.to update_index('cities#city').and_reindex(city).only }
69
+ specify { expect { city.update_attributes!(country: nil) }.to update_index('countries#country').and_reindex(country1).only }
70
70
 
71
- specify { expect { city.update_attributes!(country: country2) }.to update_index('cities#city').and_reindex(city) }
72
- specify { expect { city.update_attributes!(country: country2) }.to update_index('countries#country').and_reindex(country1, country2) }
71
+ specify { expect { city.update_attributes!(country: country2) }.to update_index('cities#city').and_reindex(city).only }
72
+ specify { expect { city.update_attributes!(country: country2) }.to update_index('countries#country').and_reindex(country1, country2).only }
73
73
  end
74
74
 
75
75
  context do
@@ -86,8 +86,8 @@ describe Chewy::Type::Import do
86
86
  end
87
87
  end
88
88
 
89
- specify { expect { country.save! }.to update_index('cities#city').and_reindex(country.cities) }
90
- specify { expect { country.save! }.to update_index('countries#country').and_reindex(country) }
89
+ specify { expect { country.save! }.to update_index('cities#city').and_reindex(country.cities).only }
90
+ specify { expect { country.save! }.to update_index('countries#country').and_reindex(country).only }
91
91
 
92
92
  context 'conditional update' do
93
93
  let(:update_condition) { false }
@@ -0,0 +1,154 @@
1
+ require 'spec_helper'
2
+
3
+ describe Chewy::Type::Witchcraft do
4
+ def self.mapping(&block)
5
+ before do
6
+ stub_index(:products) do
7
+ define_type :product do
8
+ witchcraft!
9
+
10
+ instance_exec(&block)
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ describe '#cauldron' do
17
+ let(:type) { ProductsIndex::Product }
18
+ let(:object) { }
19
+
20
+ context 'empty mapping' do
21
+ mapping {}
22
+ specify { expect(type.cauldron.brew(object)).to eq({}) }
23
+ end
24
+
25
+ context do
26
+ mapping do
27
+ field :name
28
+ field :age
29
+ field :tags
30
+ end
31
+ let(:attributes) { { name: 'Name', age: 13, tags: %w[Ruby RoR] } }
32
+
33
+ context do
34
+ let(:object) { double(attributes) }
35
+ specify { expect(type.cauldron.brew(object)).to eq(attributes.as_json) }
36
+ end
37
+
38
+ context do
39
+ let(:object) { attributes }
40
+ specify { expect(type.cauldron.brew(object)).to eq(attributes.as_json) }
41
+ end
42
+ end
43
+
44
+ context 'simple lambdas' do
45
+ mapping do
46
+ field :name
47
+ field :age, value: -> (obj) {
48
+ obj.age if obj
49
+ }
50
+ field :tags, value: -> { tags.map(&:to_sym) }
51
+ end
52
+ let(:attributes) { { name: 'Name', age: 13, tags: %w[Ruby RoR] } }
53
+
54
+ context do
55
+ let(:object) { double(attributes) }
56
+ specify { expect(type.cauldron.brew(object)).to eq(attributes.merge(tags: [:Ruby, :RoR]).as_json) }
57
+ end
58
+ end
59
+
60
+ context 'crutches' do
61
+ mapping do
62
+ field :name, value: -> (o, c) { c.names[0] }
63
+ end
64
+ let(:attributes) { { name: 'Name' } }
65
+
66
+ context do
67
+ let(:object) { double(attributes) }
68
+ let(:crutches) { double(names: ['Other']) }
69
+ specify { expect(type.cauldron.brew(object, crutches)).to eq({name: 'Other'}.as_json) }
70
+ end
71
+ end
72
+
73
+ context 'nesting' do
74
+ context do
75
+ mapping do
76
+ field :queries do
77
+ field :title
78
+ field :body, value: -> { "This #{self[:body]}" }
79
+ end
80
+ end
81
+
82
+ let(:object) { double(queries: [
83
+ {title: 'Title1', body: 'Body1'},
84
+ {title: 'Title2', body: 'Body2'}
85
+ ]) }
86
+ specify { expect(type.cauldron.brew(object)).to eq({ queries: [
87
+ {title: 'Title1', body: 'This Body1'},
88
+ {title: 'Title2', body: 'This Body2'}
89
+ ] }.as_json) }
90
+ end
91
+
92
+ context do
93
+ mapping do
94
+ field :queries do
95
+ field :title
96
+ field :body, value: -> { "This #{body}" }
97
+ end
98
+ end
99
+
100
+ let(:object) { double(queries: [
101
+ double(title: 'Title1', body: 'Body1'),
102
+ double(title: 'Title2', body: 'Body2')
103
+ ]) }
104
+ specify { expect(type.cauldron.brew(object)).to eq({ queries: [
105
+ {title: 'Title1', body: 'This Body1'},
106
+ {title: 'Title2', body: 'This Body2'}
107
+ ] }.as_json) }
108
+ end
109
+
110
+ context do
111
+ mapping do
112
+ field :queries, value: -> { queries } do
113
+ field :title
114
+ field :body, value: -> { "This #{body}" }
115
+ end
116
+ end
117
+
118
+ let(:object) { double(queries: [
119
+ double(title: 'Title1', body: 'Body1'),
120
+ double(title: 'Title2', body: 'Body2')
121
+ ]) }
122
+ specify { expect(type.cauldron.brew(object)).to eq({ queries: [
123
+ {title: 'Title1', body: 'This Body1'},
124
+ {title: 'Title2', body: 'This Body2'}
125
+ ] }.as_json) }
126
+ end
127
+
128
+ context do
129
+ mapping do
130
+ field :queries do
131
+ field :fields, value: -> (o, q) { q.fields } do
132
+ field :first
133
+ field :second, value: -> (o, q, f, c) {
134
+ q.value + (f.respond_to?(:second) ? f.second : c.second)
135
+ }
136
+ end
137
+ end
138
+ end
139
+
140
+ let(:object) { double(queries: [
141
+ double(value: 'Value1', fields: [double(first: 'First1', second: 'Second1'), {first: 'First2'}]),
142
+ double(value: 'Value2', fields: double(first: 'First3', second: 'Second2', third: 'Third'))
143
+ ]) }
144
+ specify { expect(type.cauldron.brew(object, double(second: 'Crutch'))).to eq({queries: [
145
+ {fields: [
146
+ {first: 'First1', second: 'Value1Second1'},
147
+ {first: 'First2', second: 'Value1Crutch'}
148
+ ]},
149
+ {fields: {first: 'First3', second: 'Value2Second2'}}
150
+ ]}.as_json) }
151
+ end
152
+ end
153
+ end
154
+ end
@@ -10,12 +10,37 @@ describe Chewy::Type::Wrapper do
10
10
 
11
11
  let(:city_type) { CitiesIndex::City }
12
12
 
13
- subject { city_type.new(name: 'Martin', age: 42) }
13
+ subject(:city) { city_type.new(name: 'Martin', age: 42) }
14
14
 
15
- it { is_expected.to respond_to :name }
16
- it { is_expected.to respond_to :age }
17
- its(:name) { should == 'Martin' }
18
- its(:age) { should == 42 }
15
+ it do
16
+ is_expected.to respond_to(:name)
17
+ .and respond_to(:age)
18
+ .and have_attributes(
19
+ name: 'Martin',
20
+ age: 42
21
+ )
22
+ end
23
+
24
+ it { expect { city.population }.to raise_error(NoMethodError) }
25
+
26
+ context 'highlight' do
27
+ subject(:city) do
28
+ city_type.new(name: 'Martin', age: 42)
29
+ .tap do |city|
30
+ city._data = {
31
+ 'highlight' => { 'name' => ['<b>Mar</b>tin'] }
32
+ }
33
+ end
34
+ end
35
+
36
+ it do
37
+ is_expected.to respond_to(:name_highlight)
38
+ .and have_attributes(
39
+ name: 'Martin',
40
+ name_highlight: '<b>Mar</b>tin'
41
+ )
42
+ end
43
+ end
19
44
 
20
45
  describe '#==' do
21
46
  specify { expect(city_type.new(id: 42)).to eq(city_type.new(id: 42)) }
@@ -19,5 +19,15 @@ describe Chewy::Type do
19
19
 
20
20
  specify { expect(described_class.scopes).to eq([]) }
21
21
  specify { expect(PlacesIndex::City.scopes).to match_array([:by_rating, :by_name]) }
22
+ specify { expect { PlacesIndex::City.non_existing_method_call }.to raise_error(NoMethodError) }
23
+
24
+ specify { expect(PlacesIndex::City._default_import_options).to eq({}) }
25
+ specify { expect { PlacesIndex::City.default_import_options(invalid_option: "Yeah!") }.to raise_error(ArgumentError) }
26
+
27
+ context 'default_import_options is set' do
28
+ before { PlacesIndex::City.default_import_options(batch_size: 500) }
29
+
30
+ specify { expect(PlacesIndex::City._default_import_options).to eq(batch_size: 500) }
31
+ end
22
32
  end
23
33
  end
@@ -25,11 +25,11 @@ describe Chewy do
25
25
  specify { expect { described_class.derive_type('developers#borogoves') }.to raise_error Chewy::UnderivableType, /DevelopersIndex.*borogoves/ }
26
26
  specify { expect { described_class.derive_type('namespace/autocomplete') }.to raise_error Chewy::UnderivableType, /AutocompleteIndex.*namespace\/autocomplete#type_name/ }
27
27
 
28
- specify { expect(described_class.derive_type(DevelopersIndex.developer)).to eq(DevelopersIndex.developer) }
29
- specify { expect(described_class.derive_type('developers')).to eq(DevelopersIndex.developer) }
30
- specify { expect(described_class.derive_type('developers#developer')).to eq(DevelopersIndex.developer) }
31
- specify { expect(described_class.derive_type('namespace/autocomplete#developer')).to eq(Namespace::AutocompleteIndex.developer) }
32
- specify { expect(described_class.derive_type('namespace/autocomplete#company')).to eq(Namespace::AutocompleteIndex.company) }
28
+ specify { expect(described_class.derive_type(DevelopersIndex::Developer)).to eq(DevelopersIndex::Developer) }
29
+ specify { expect(described_class.derive_type('developers')).to eq(DevelopersIndex::Developer) }
30
+ specify { expect(described_class.derive_type('developers#developer')).to eq(DevelopersIndex::Developer) }
31
+ specify { expect(described_class.derive_type('namespace/autocomplete#developer')).to eq(Namespace::AutocompleteIndex::Developer) }
32
+ specify { expect(described_class.derive_type('namespace/autocomplete#company')).to eq(Namespace::AutocompleteIndex::Company) }
33
33
  end
34
34
 
35
35
  describe '.create_type' do
@@ -110,4 +110,28 @@ describe Chewy do
110
110
  specify { expect(DevelopersIndex.exists?).to eq(false) }
111
111
  specify { expect(CompaniesIndex.exists?).to eq(false) }
112
112
  end
113
+
114
+ describe '.client' do
115
+ let!(:initial_client) { Thread.current[:chewy_client] }
116
+ let(:faraday_block) { proc { } }
117
+ let(:mock_client) { double(:client) }
118
+ let(:expected_client_config) { { transport_options: {} } }
119
+
120
+ before do
121
+ Thread.current[:chewy_client] = nil
122
+ allow(Chewy).to receive_messages(configuration: { transport_options: { proc: faraday_block } })
123
+
124
+ allow(::Elasticsearch::Client).to receive(:new).with(expected_client_config) do |*args, &passed_block|
125
+ # RSpec's `with(…, &block)` was used previously, but doesn't actually do
126
+ # any verification of the passed block (even of its presence).
127
+ expect(passed_block.source_location).to eq(faraday_block.source_location)
128
+
129
+ mock_client
130
+ end
131
+ end
132
+
133
+ its(:client) { is_expected.to eq(mock_client) }
134
+
135
+ after { Thread.current[:chewy_client] = initial_client }
136
+ end
113
137
  end