chewy 0.8.3 → 0.8.4

Sign up to get free protection for your applications and to get access to all the features.
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