elasticsearch-model 5.1.0 → 6.1.0
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.
- checksums.yaml +4 -4
- data/Gemfile +5 -0
- data/README.md +18 -11
- data/Rakefile +27 -36
- data/elasticsearch-model.gemspec +5 -5
- data/examples/activerecord_custom_analyzer.rb +135 -0
- data/examples/activerecord_mapping_completion.rb +3 -18
- data/examples/datamapper_article.rb +11 -1
- data/gemfiles/3.0.gemfile +6 -1
- data/gemfiles/4.0.gemfile +7 -1
- data/gemfiles/5.0.gemfile +7 -1
- data/lib/elasticsearch/model/adapters/active_record.rb +7 -23
- data/lib/elasticsearch/model/adapters/mongoid.rb +10 -3
- data/lib/elasticsearch/model/importing.rb +1 -1
- data/lib/elasticsearch/model/indexing.rb +6 -4
- data/lib/elasticsearch/model/naming.rb +9 -2
- data/lib/elasticsearch/model/response/aggregations.rb +1 -1
- data/lib/elasticsearch/model/response/base.rb +3 -2
- data/lib/elasticsearch/model/response/pagination/kaminari.rb +109 -0
- data/lib/elasticsearch/model/response/pagination/will_paginate.rb +95 -0
- data/lib/elasticsearch/model/response/pagination.rb +2 -192
- data/lib/elasticsearch/model/response/result.rb +1 -1
- data/lib/elasticsearch/model/response/suggestions.rb +1 -1
- data/lib/elasticsearch/model/response.rb +11 -10
- data/lib/elasticsearch/model/version.rb +1 -1
- data/lib/elasticsearch/model.rb +15 -8
- data/spec/elasticsearch/model/adapter_spec.rb +119 -0
- data/spec/elasticsearch/model/adapters/active_record/associations_spec.rb +334 -0
- data/spec/elasticsearch/model/adapters/active_record/basic_spec.rb +340 -0
- data/spec/elasticsearch/model/adapters/active_record/dynamic_index_name_spec.rb +18 -0
- data/spec/elasticsearch/model/adapters/active_record/import_spec.rb +187 -0
- data/spec/elasticsearch/model/adapters/active_record/multi_model_spec.rb +110 -0
- data/spec/elasticsearch/model/adapters/active_record/namespaced_model_spec.rb +38 -0
- data/spec/elasticsearch/model/adapters/active_record/pagination_spec.rb +315 -0
- data/spec/elasticsearch/model/adapters/active_record/parent_child_spec.rb +75 -0
- data/spec/elasticsearch/model/adapters/active_record/serialization_spec.rb +61 -0
- data/spec/elasticsearch/model/adapters/active_record_spec.rb +207 -0
- data/spec/elasticsearch/model/adapters/default_spec.rb +41 -0
- data/spec/elasticsearch/model/adapters/mongoid/basic_spec.rb +267 -0
- data/spec/elasticsearch/model/adapters/mongoid/multi_model_spec.rb +66 -0
- data/spec/elasticsearch/model/adapters/mongoid_spec.rb +235 -0
- data/spec/elasticsearch/model/adapters/multiple_spec.rb +125 -0
- data/spec/elasticsearch/model/callbacks_spec.rb +33 -0
- data/spec/elasticsearch/model/client_spec.rb +66 -0
- data/spec/elasticsearch/model/hash_wrapper_spec.rb +12 -0
- data/spec/elasticsearch/model/importing_spec.rb +214 -0
- data/spec/elasticsearch/model/indexing_spec.rb +918 -0
- data/spec/elasticsearch/model/module_spec.rb +101 -0
- data/spec/elasticsearch/model/multimodel_spec.rb +55 -0
- data/spec/elasticsearch/model/naming_inheritance_spec.rb +184 -0
- data/spec/elasticsearch/model/naming_spec.rb +186 -0
- data/spec/elasticsearch/model/proxy_spec.rb +107 -0
- data/spec/elasticsearch/model/response/aggregations_spec.rb +66 -0
- data/spec/elasticsearch/model/response/base_spec.rb +90 -0
- data/spec/elasticsearch/model/response/pagination/kaminari_spec.rb +410 -0
- data/spec/elasticsearch/model/response/pagination/will_paginate_spec.rb +262 -0
- data/spec/elasticsearch/model/response/records_spec.rb +118 -0
- data/spec/elasticsearch/model/response/response_spec.rb +131 -0
- data/spec/elasticsearch/model/response/result_spec.rb +122 -0
- data/spec/elasticsearch/model/response/results_spec.rb +56 -0
- data/spec/elasticsearch/model/searching_search_request_spec.rb +112 -0
- data/spec/elasticsearch/model/searching_spec.rb +49 -0
- data/spec/elasticsearch/model/serializing_spec.rb +22 -0
- data/spec/spec_helper.rb +161 -0
- data/spec/support/app/answer.rb +33 -0
- data/spec/support/app/article.rb +22 -0
- data/spec/support/app/article_for_pagination.rb +12 -0
- data/spec/support/app/article_with_custom_serialization.rb +13 -0
- data/spec/support/app/article_with_dynamic_index_name.rb +15 -0
- data/spec/support/app/author.rb +9 -0
- data/spec/support/app/authorship.rb +4 -0
- data/spec/support/app/category.rb +3 -0
- data/spec/support/app/comment.rb +3 -0
- data/spec/support/app/episode.rb +11 -0
- data/spec/support/app/image.rb +19 -0
- data/spec/support/app/import_article.rb +12 -0
- data/spec/support/app/mongoid_article.rb +21 -0
- data/spec/support/app/namespaced_book.rb +10 -0
- data/spec/support/app/parent_and_child_searchable.rb +24 -0
- data/spec/support/app/post.rb +14 -0
- data/spec/support/app/question.rb +27 -0
- data/spec/support/app/searchable.rb +48 -0
- data/spec/support/app/series.rb +11 -0
- data/spec/support/app.rb +21 -0
- data/spec/support/model.json +1 -0
- metadata +134 -90
- data/test/integration/active_record_associations_parent_child_test.rb +0 -147
- data/test/integration/active_record_associations_test.rb +0 -339
- data/test/integration/active_record_basic_test.rb +0 -251
- data/test/integration/active_record_custom_serialization_test.rb +0 -67
- data/test/integration/active_record_import_test.rb +0 -115
- data/test/integration/active_record_namespaced_model_test.rb +0 -54
- data/test/integration/active_record_pagination_test.rb +0 -149
- data/test/integration/dynamic_index_name_test.rb +0 -52
- data/test/integration/mongoid_basic_test.rb +0 -176
- data/test/integration/multiple_models_test.rb +0 -176
- data/test/support/model.json +0 -1
- data/test/test_helper.rb +0 -92
- data/test/unit/adapter_active_record_test.rb +0 -157
- data/test/unit/adapter_default_test.rb +0 -41
- data/test/unit/adapter_mongoid_test.rb +0 -104
- data/test/unit/adapter_multiple_test.rb +0 -106
- data/test/unit/adapter_test.rb +0 -69
- data/test/unit/callbacks_test.rb +0 -31
- data/test/unit/client_test.rb +0 -27
- data/test/unit/hash_wrapper_test.rb +0 -13
- data/test/unit/importing_test.rb +0 -203
- data/test/unit/indexing_test.rb +0 -687
- data/test/unit/module_test.rb +0 -68
- data/test/unit/multimodel_test.rb +0 -38
- data/test/unit/naming_inheritance_test.rb +0 -94
- data/test/unit/naming_test.rb +0 -103
- data/test/unit/proxy_test.rb +0 -98
- data/test/unit/response_aggregations_test.rb +0 -46
- data/test/unit/response_base_test.rb +0 -40
- data/test/unit/response_pagination_kaminari_test.rb +0 -433
- data/test/unit/response_pagination_will_paginate_test.rb +0 -398
- data/test/unit/response_records_test.rb +0 -91
- data/test/unit/response_result_test.rb +0 -90
- data/test/unit/response_results_test.rb +0 -31
- data/test/unit/response_test.rb +0 -104
- data/test/unit/searching_search_request_test.rb +0 -78
- data/test/unit/searching_test.rb +0 -41
- data/test/unit/serializing_test.rb +0 -17
- /data/{test → spec}/support/model.yml +0 -0
|
@@ -0,0 +1,918 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Elasticsearch::Model::Indexing do
|
|
4
|
+
|
|
5
|
+
before(:all) do
|
|
6
|
+
class ::DummyIndexingModel
|
|
7
|
+
extend ActiveModel::Naming
|
|
8
|
+
extend Elasticsearch::Model::Naming::ClassMethods
|
|
9
|
+
extend Elasticsearch::Model::Indexing::ClassMethods
|
|
10
|
+
|
|
11
|
+
def self.foo
|
|
12
|
+
'bar'
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class NotFound < Exception; end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
after(:all) do
|
|
20
|
+
remove_classes(DummyIndexingModel, NotFound)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe 'the Settings class' do
|
|
24
|
+
|
|
25
|
+
it 'should be convertible to a hash' do
|
|
26
|
+
expect(Elasticsearch::Model::Indexing::Settings.new(foo: 'bar').to_hash).to eq(foo: 'bar')
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'should be convertible to json' do
|
|
30
|
+
expect(Elasticsearch::Model::Indexing::Settings.new(foo: 'bar').as_json).to eq(foo: 'bar')
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe '#settings' do
|
|
35
|
+
|
|
36
|
+
it 'returns an instance of the Settings class' do
|
|
37
|
+
expect(DummyIndexingModel.settings).to be_a(Elasticsearch::Model::Indexing::Settings)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
context 'when the settings are updated' do
|
|
41
|
+
|
|
42
|
+
before do
|
|
43
|
+
DummyIndexingModel.settings(foo: 'boo')
|
|
44
|
+
DummyIndexingModel.settings(bar: 'bam')
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it 'updates the settings on the class' do
|
|
48
|
+
expect(DummyIndexingModel.settings.to_hash).to eq(foo: 'boo', bar: 'bam')
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
context 'when the settings are updated with a yml file' do
|
|
53
|
+
|
|
54
|
+
before do
|
|
55
|
+
DummyIndexingModel.settings File.open('spec/support/model.yml')
|
|
56
|
+
DummyIndexingModel.settings bar: 'bam'
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'updates the settings on the class' do
|
|
60
|
+
expect(DummyIndexingModel.settings.to_hash).to eq(foo: 'boo', bar: 'bam', 'baz' => 'qux')
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
context 'when the settings are updated with a json file' do
|
|
65
|
+
|
|
66
|
+
before do
|
|
67
|
+
DummyIndexingModel.settings File.open('spec/support/model.json')
|
|
68
|
+
DummyIndexingModel.settings bar: 'bam'
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it 'updates the settings on the class' do
|
|
72
|
+
expect(DummyIndexingModel.settings.to_hash).to eq(foo: 'boo', bar: 'bam', 'baz' => 'qux', 'laz' => 'qux')
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
describe '#mappings' do
|
|
78
|
+
|
|
79
|
+
let(:expected_mapping_hash) do
|
|
80
|
+
{ :mytype => { foo: 'bar', :properties => {} } }
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it 'returns an instance of the Mappings class' do
|
|
84
|
+
expect(DummyIndexingModel.mappings).to be_a(Elasticsearch::Model::Indexing::Mappings)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it 'raises an exception when there is no type passed to the #initialize method' do
|
|
88
|
+
expect {
|
|
89
|
+
Elasticsearch::Model::Indexing::Mappings.new
|
|
90
|
+
}.to raise_exception(ArgumentError)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it 'should be convertible to a hash' do
|
|
94
|
+
expect(Elasticsearch::Model::Indexing::Mappings.new(:mytype, { foo: 'bar' }).to_hash).to eq(expected_mapping_hash)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it 'should be convertible to json' do
|
|
98
|
+
expect(Elasticsearch::Model::Indexing::Mappings.new(:mytype, { foo: 'bar' }).as_json).to eq(expected_mapping_hash)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
context 'when specific mappings are defined' do
|
|
102
|
+
|
|
103
|
+
let(:mappings) do
|
|
104
|
+
Elasticsearch::Model::Indexing::Mappings.new(:mytype)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
before do
|
|
108
|
+
mappings.indexes :foo, { type: 'boolean', include_in_all: false }
|
|
109
|
+
mappings.indexes :bar
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it 'creates the correct mapping definition' do
|
|
113
|
+
expect(mappings.to_hash[:mytype][:properties][:foo][:type]).to eq('boolean')
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
it 'uses text as the default type' do
|
|
117
|
+
expect(mappings.to_hash[:mytype][:properties][:bar][:type]).to eq('text')
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
context 'when mappings are defined for multiple fields' do
|
|
121
|
+
|
|
122
|
+
before do
|
|
123
|
+
mappings.indexes :my_field, type: 'text' do
|
|
124
|
+
indexes :raw, type: 'keyword'
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it 'defines the mapping for all the fields' do
|
|
129
|
+
expect(mappings.to_hash[:mytype][:properties][:my_field][:type]).to eq('text')
|
|
130
|
+
expect(mappings.to_hash[:mytype][:properties][:my_field][:fields][:raw][:type]).to eq('keyword')
|
|
131
|
+
expect(mappings.to_hash[:mytype][:properties][:my_field][:fields][:raw][:properties]).to be_nil
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
context 'when embedded properties are defined' do
|
|
136
|
+
|
|
137
|
+
before do
|
|
138
|
+
mappings.indexes :foo do
|
|
139
|
+
indexes :bar
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
mappings.indexes :foo_object, type: 'object' do
|
|
143
|
+
indexes :bar
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
mappings.indexes :foo_nested, type: 'nested' do
|
|
147
|
+
indexes :bar
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
mappings.indexes :foo_nested_as_symbol, type: :nested do
|
|
151
|
+
indexes :bar
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
it 'defines mappings for the embedded properties' do
|
|
156
|
+
expect(mappings.to_hash[:mytype][:properties][:foo][:type]).to eq('object')
|
|
157
|
+
expect(mappings.to_hash[:mytype][:properties][:foo][:properties][:bar][:type]).to eq('text')
|
|
158
|
+
expect(mappings.to_hash[:mytype][:properties][:foo][:fields]).to be_nil
|
|
159
|
+
|
|
160
|
+
expect(mappings.to_hash[:mytype][:properties][:foo_object][:type]).to eq('object')
|
|
161
|
+
expect(mappings.to_hash[:mytype][:properties][:foo_object][:properties][:bar][:type]).to eq('text')
|
|
162
|
+
expect(mappings.to_hash[:mytype][:properties][:foo_object][:fields]).to be_nil
|
|
163
|
+
|
|
164
|
+
expect(mappings.to_hash[:mytype][:properties][:foo_nested][:type]).to eq('nested')
|
|
165
|
+
expect(mappings.to_hash[:mytype][:properties][:foo_nested][:properties][:bar][:type]).to eq('text')
|
|
166
|
+
expect(mappings.to_hash[:mytype][:properties][:foo_nested][:fields]).to be_nil
|
|
167
|
+
|
|
168
|
+
expect(mappings.to_hash[:mytype][:properties][:foo_nested_as_symbol][:type]).to eq(:nested)
|
|
169
|
+
expect(mappings.to_hash[:mytype][:properties][:foo_nested_as_symbol][:properties]).not_to be_nil
|
|
170
|
+
expect(mappings.to_hash[:mytype][:properties][:foo_nested_as_symbol][:fields]).to be_nil
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
context 'when the method is called on a class' do
|
|
176
|
+
|
|
177
|
+
before do
|
|
178
|
+
DummyIndexingModel.mappings(foo: 'boo')
|
|
179
|
+
DummyIndexingModel.mappings(bar: 'bam')
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
let(:expected_mappings_hash) do
|
|
183
|
+
{ _doc: { foo: "boo", bar: "bam", properties: {} } }
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
it 'sets the mappings' do
|
|
187
|
+
expect(DummyIndexingModel.mappings.to_hash).to eq(expected_mappings_hash)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
context 'when the method is called with a block' do
|
|
191
|
+
|
|
192
|
+
before do
|
|
193
|
+
DummyIndexingModel.mapping do
|
|
194
|
+
indexes :foo, type: 'boolean'
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
it 'sets the mappings' do
|
|
199
|
+
expect(DummyIndexingModel.mapping.to_hash[:_doc][:properties][:foo][:type]).to eq('boolean')
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
describe 'instance methods' do
|
|
206
|
+
|
|
207
|
+
before(:all) do
|
|
208
|
+
class ::DummyIndexingModelWithCallbacks
|
|
209
|
+
extend Elasticsearch::Model::Indexing::ClassMethods
|
|
210
|
+
include Elasticsearch::Model::Indexing::InstanceMethods
|
|
211
|
+
|
|
212
|
+
def self.before_save(&block)
|
|
213
|
+
(@callbacks ||= {})[block.hash] = block
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def changes_to_save
|
|
217
|
+
{:foo => ['One', 'Two']}
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
class ::DummyIndexingModelWithNoChanges
|
|
222
|
+
extend Elasticsearch::Model::Indexing::ClassMethods
|
|
223
|
+
include Elasticsearch::Model::Indexing::InstanceMethods
|
|
224
|
+
|
|
225
|
+
def self.before_save(&block)
|
|
226
|
+
(@callbacks ||= {})[block.hash] = block
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def changes_to_save
|
|
230
|
+
{}
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
class ::DummyIndexingModelWithCallbacksAndCustomAsIndexedJson
|
|
235
|
+
extend Elasticsearch::Model::Indexing::ClassMethods
|
|
236
|
+
include Elasticsearch::Model::Indexing::InstanceMethods
|
|
237
|
+
|
|
238
|
+
def self.before_save(&block)
|
|
239
|
+
(@callbacks ||= {})[block.hash] = block
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def changes_to_save
|
|
243
|
+
{:foo => ['A', 'B'], :bar => ['C', 'D']}
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def as_indexed_json(options={})
|
|
247
|
+
{ :foo => 'B' }
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
class ::DummyIndexingModelWithOldDirty
|
|
252
|
+
extend Elasticsearch::Model::Indexing::ClassMethods
|
|
253
|
+
include Elasticsearch::Model::Indexing::InstanceMethods
|
|
254
|
+
|
|
255
|
+
def self.before_save(&block)
|
|
256
|
+
(@callbacks ||= {})[block.hash] = block
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def changes
|
|
260
|
+
{:foo => ['One', 'Two']}
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
after(:all) do
|
|
266
|
+
Object.send(:remove_const, :DummyIndexingModelWithCallbacks) if defined?(DummyIndexingModelWithCallbacks)
|
|
267
|
+
Object.send(:remove_const, :DummyIndexingModelWithNoChanges) if defined?(DummyIndexingModelWithNoChanges)
|
|
268
|
+
Object.send(:remove_const, :DummyIndexingModelWithCallbacksAndCustomAsIndexedJson) if defined?(DummyIndexingModelWithCallbacksAndCustomAsIndexedJson)
|
|
269
|
+
Object.send(:remove_const, :DummyIndexingModelWithOldDirty) if defined?(DummyIndexingModelWithOldDirty)
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
context 'when the module is included' do
|
|
273
|
+
|
|
274
|
+
context 'when the model uses the old ActiveModel::Dirty' do
|
|
275
|
+
|
|
276
|
+
before do
|
|
277
|
+
DummyIndexingModelWithOldDirty.__send__ :include, Elasticsearch::Model::Indexing::InstanceMethods
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
it 'registers callbacks' do
|
|
281
|
+
expect(DummyIndexingModelWithOldDirty.instance_variable_get(:@callbacks)).not_to be_empty
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
let(:instance) do
|
|
285
|
+
DummyIndexingModelWithOldDirty.new
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
it 'sets the @__changed_model_attributes variable before the callback' do
|
|
289
|
+
DummyIndexingModelWithOldDirty.instance_variable_get(:@callbacks).each do |n, callback|
|
|
290
|
+
instance.instance_eval(&callback)
|
|
291
|
+
expect(instance.instance_variable_get(:@__changed_model_attributes)).to eq(foo: 'Two')
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
context 'when the model users the current ActiveModel::Dirty' do
|
|
297
|
+
|
|
298
|
+
before do
|
|
299
|
+
DummyIndexingModelWithCallbacks.__send__ :include, Elasticsearch::Model::Indexing::InstanceMethods
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
it 'registers callbacks' do
|
|
303
|
+
expect(DummyIndexingModelWithCallbacks.instance_variable_get(:@callbacks)).not_to be_empty
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
let(:instance) do
|
|
307
|
+
DummyIndexingModelWithCallbacks.new
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
it 'sets the @__changed_model_attributes variable before the callback' do
|
|
311
|
+
DummyIndexingModelWithCallbacks.instance_variable_get(:@callbacks).each do |n, callback|
|
|
312
|
+
instance.instance_eval(&callback)
|
|
313
|
+
expect(instance.instance_variable_get(:@__changed_model_attributes)).to eq(foo: 'Two')
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
describe '#index_document' do
|
|
320
|
+
|
|
321
|
+
before do
|
|
322
|
+
expect(instance).to receive(:client).and_return(client)
|
|
323
|
+
expect(instance).to receive(:as_indexed_json).and_return('JSON')
|
|
324
|
+
expect(instance).to receive(:index_name).and_return('foo')
|
|
325
|
+
expect(instance).to receive(:document_type).and_return('bar')
|
|
326
|
+
expect(instance).to receive(:id).and_return('1')
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
let(:client) do
|
|
330
|
+
double('client')
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
let(:instance) do
|
|
334
|
+
DummyIndexingModelWithCallbacks.new
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
context 'when no options are passed to the method' do
|
|
338
|
+
|
|
339
|
+
before do
|
|
340
|
+
expect(client).to receive(:index).with(index: 'foo', type: 'bar', id: '1', body: 'JSON').and_return(true)
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
it 'provides the method on an instance' do
|
|
344
|
+
expect(instance.index_document).to be(true)
|
|
345
|
+
end
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
context 'when extra options are passed to the method' do
|
|
349
|
+
|
|
350
|
+
before do
|
|
351
|
+
expect(client).to receive(:index).with(index: 'foo', type: 'bar', id: '1', body: 'JSON', parent: 'A').and_return(true)
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
it 'passes the extra options to the method call on the client' do
|
|
355
|
+
expect(instance.index_document(parent: 'A')).to be(true)
|
|
356
|
+
end
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
describe '#delete_document' do
|
|
361
|
+
|
|
362
|
+
before do
|
|
363
|
+
expect(instance).to receive(:client).and_return(client)
|
|
364
|
+
expect(instance).to receive(:index_name).and_return('foo')
|
|
365
|
+
expect(instance).to receive(:document_type).and_return('bar')
|
|
366
|
+
expect(instance).to receive(:id).and_return('1')
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
let(:client) do
|
|
370
|
+
double('client')
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
let(:instance) do
|
|
374
|
+
DummyIndexingModelWithCallbacks.new
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
context 'when no options are passed to the method' do
|
|
378
|
+
|
|
379
|
+
before do
|
|
380
|
+
expect(client).to receive(:delete).with(index: 'foo', type: 'bar', id: '1').and_return(true)
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
it 'provides the method on an instance' do
|
|
384
|
+
expect(instance.delete_document).to be(true)
|
|
385
|
+
end
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
context 'when extra options are passed to the method' do
|
|
389
|
+
|
|
390
|
+
before do
|
|
391
|
+
expect(client).to receive(:delete).with(index: 'foo', type: 'bar', id: '1', parent: 'A').and_return(true)
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
it 'passes the extra options to the method call on the client' do
|
|
395
|
+
expect(instance.delete_document(parent: 'A')).to be(true)
|
|
396
|
+
end
|
|
397
|
+
end
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
describe '#update_document' do
|
|
401
|
+
|
|
402
|
+
let(:client) do
|
|
403
|
+
double('client')
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
let(:instance) do
|
|
407
|
+
DummyIndexingModelWithCallbacks.new
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
context 'when no changes are present' do
|
|
411
|
+
|
|
412
|
+
before do
|
|
413
|
+
expect(instance).to receive(:index_document).and_return(true)
|
|
414
|
+
expect(client).to receive(:update).never
|
|
415
|
+
instance.instance_variable_set(:@__changed_model_attributes, nil)
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
it 'updates the document' do
|
|
419
|
+
expect(instance.update_document).to be(true)
|
|
420
|
+
end
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
context 'when changes are present' do
|
|
424
|
+
|
|
425
|
+
before do
|
|
426
|
+
allow(instance).to receive(:client).and_return(client)
|
|
427
|
+
allow(instance).to receive(:index_name).and_return('foo')
|
|
428
|
+
allow(instance).to receive(:document_type).and_return('bar')
|
|
429
|
+
allow(instance).to receive(:id).and_return('1')
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
context 'when the changes are included in the as_indexed_json representation' do
|
|
433
|
+
|
|
434
|
+
before do
|
|
435
|
+
instance.instance_variable_set(:@__changed_model_attributes, { foo: 'bar' })
|
|
436
|
+
expect(client).to receive(:update).with(index: 'foo', type: 'bar', id: '1', body: { doc: { foo: 'bar' } }).and_return(true)
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
it 'updates the document' do
|
|
440
|
+
expect(instance.update_document).to be(true)
|
|
441
|
+
end
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
context 'when the changes are not all included in the as_indexed_json representation' do
|
|
445
|
+
|
|
446
|
+
let(:instance) do
|
|
447
|
+
DummyIndexingModelWithCallbacksAndCustomAsIndexedJson.new
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
before do
|
|
451
|
+
instance.instance_variable_set(:@__changed_model_attributes, {'foo' => 'B', 'bar' => 'D' })
|
|
452
|
+
expect(client).to receive(:update).with(index: 'foo', type: 'bar', id: '1', body: { doc: { foo: 'B' } }).and_return(true)
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
it 'updates the document' do
|
|
456
|
+
expect(instance.update_document).to be(true)
|
|
457
|
+
end
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
context 'when none of the changes are included in the as_indexed_json representation' do
|
|
461
|
+
|
|
462
|
+
let(:instance) do
|
|
463
|
+
DummyIndexingModelWithCallbacksAndCustomAsIndexedJson.new
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
before do
|
|
467
|
+
instance.instance_variable_set(:@__changed_model_attributes, {'bar' => 'D' })
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
it 'does not update the document' do
|
|
471
|
+
expect(instance.update_document).to_not be(true)
|
|
472
|
+
end
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
context 'when there are partial updates' do
|
|
476
|
+
|
|
477
|
+
let(:instance) do
|
|
478
|
+
DummyIndexingModelWithCallbacksAndCustomAsIndexedJson.new
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
before do
|
|
482
|
+
instance.instance_variable_set(:@__changed_model_attributes, { 'foo' => { 'bar' => 'BAR'} })
|
|
483
|
+
expect(instance).to receive(:as_indexed_json).and_return('foo' => 'BAR')
|
|
484
|
+
expect(client).to receive(:update).with(index: 'foo', type: 'bar', id: '1', body: { doc: { 'foo' => 'BAR' } }).and_return(true)
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
it 'updates the document' do
|
|
488
|
+
expect(instance.update_document).to be(true)
|
|
489
|
+
end
|
|
490
|
+
end
|
|
491
|
+
end
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
describe '#update_document_attributes' do
|
|
495
|
+
|
|
496
|
+
let(:client) do
|
|
497
|
+
double('client')
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
let(:instance) do
|
|
501
|
+
DummyIndexingModelWithCallbacks.new
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
context 'when changes are present' do
|
|
505
|
+
|
|
506
|
+
before do
|
|
507
|
+
expect(instance).to receive(:client).and_return(client)
|
|
508
|
+
expect(instance).to receive(:index_name).and_return('foo')
|
|
509
|
+
expect(instance).to receive(:document_type).and_return('bar')
|
|
510
|
+
expect(instance).to receive(:id).and_return('1')
|
|
511
|
+
instance.instance_variable_set(:@__changed_model_attributes, { author: 'john' })
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
context 'when no options are specified' do
|
|
515
|
+
|
|
516
|
+
before do
|
|
517
|
+
expect(client).to receive(:update).with(index: 'foo', type: 'bar', id: '1', body: { doc: { title: 'green' } }).and_return(true)
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
it 'updates the document' do
|
|
521
|
+
expect(instance.update_document_attributes(title: 'green')).to be(true)
|
|
522
|
+
end
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
context 'when extra options are provided' do
|
|
526
|
+
|
|
527
|
+
before do
|
|
528
|
+
expect(client).to receive(:update).with(index: 'foo', type: 'bar', id: '1', body: { doc: { title: 'green' } }, refresh: true).and_return(true)
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
it 'updates the document' do
|
|
532
|
+
expect(instance.update_document_attributes({ title: 'green' }, refresh: true)).to be(true)
|
|
533
|
+
end
|
|
534
|
+
end
|
|
535
|
+
end
|
|
536
|
+
end
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
describe '#index_exists?' do
|
|
540
|
+
|
|
541
|
+
before do
|
|
542
|
+
expect(DummyIndexingModel).to receive(:client).and_return(client)
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
context 'when the index exists' do
|
|
546
|
+
|
|
547
|
+
let(:client) do
|
|
548
|
+
double('client', indices: double('indices', exists: true))
|
|
549
|
+
end
|
|
550
|
+
|
|
551
|
+
it 'returns true' do
|
|
552
|
+
expect(DummyIndexingModel.index_exists?).to be(true)
|
|
553
|
+
end
|
|
554
|
+
end
|
|
555
|
+
|
|
556
|
+
context 'when the index does not exists' do
|
|
557
|
+
|
|
558
|
+
let(:client) do
|
|
559
|
+
double('client', indices: double('indices', exists: false))
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
it 'returns false' do
|
|
563
|
+
expect(DummyIndexingModel.index_exists?).to be(false)
|
|
564
|
+
end
|
|
565
|
+
end
|
|
566
|
+
|
|
567
|
+
context 'when the index API raises an error' do
|
|
568
|
+
|
|
569
|
+
let(:client) do
|
|
570
|
+
double('client').tap do |cl|
|
|
571
|
+
expect(cl).to receive(:indices).and_raise(StandardError)
|
|
572
|
+
end
|
|
573
|
+
end
|
|
574
|
+
|
|
575
|
+
it 'returns false' do
|
|
576
|
+
expect(DummyIndexingModel.index_exists?).to be(false)
|
|
577
|
+
end
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
context 'when the indices.exists API raises an error' do
|
|
581
|
+
|
|
582
|
+
let(:client) do
|
|
583
|
+
double('client', indices: indices)
|
|
584
|
+
end
|
|
585
|
+
|
|
586
|
+
let(:indices) do
|
|
587
|
+
double('indices').tap do |ind|
|
|
588
|
+
expect(ind).to receive(:exists).and_raise(StandardError)
|
|
589
|
+
end
|
|
590
|
+
end
|
|
591
|
+
|
|
592
|
+
it 'returns false' do
|
|
593
|
+
expect(DummyIndexingModel.index_exists?).to be(false)
|
|
594
|
+
end
|
|
595
|
+
end
|
|
596
|
+
end
|
|
597
|
+
|
|
598
|
+
describe '#delete_index!' do
|
|
599
|
+
|
|
600
|
+
before(:all) do
|
|
601
|
+
class ::DummyIndexingModelForRecreate
|
|
602
|
+
extend ActiveModel::Naming
|
|
603
|
+
extend Elasticsearch::Model::Naming::ClassMethods
|
|
604
|
+
extend Elasticsearch::Model::Indexing::ClassMethods
|
|
605
|
+
end
|
|
606
|
+
end
|
|
607
|
+
|
|
608
|
+
after(:all) do
|
|
609
|
+
Object.send(:remove_const, :DummyIndexingModelForRecreate) if defined?(DummyIndexingModelForRecreate)
|
|
610
|
+
end
|
|
611
|
+
|
|
612
|
+
context 'when the index is not found' do
|
|
613
|
+
|
|
614
|
+
let(:client) do
|
|
615
|
+
double('client', indices: indices, transport: double('transport', { logger: nil }))
|
|
616
|
+
end
|
|
617
|
+
|
|
618
|
+
let(:indices) do
|
|
619
|
+
double('indices').tap do |ind|
|
|
620
|
+
expect(ind).to receive(:delete).and_raise(NotFound)
|
|
621
|
+
end
|
|
622
|
+
end
|
|
623
|
+
|
|
624
|
+
before do
|
|
625
|
+
expect(DummyIndexingModelForRecreate).to receive(:client).at_most(3).times.and_return(client)
|
|
626
|
+
end
|
|
627
|
+
|
|
628
|
+
context 'when the force option is true' do
|
|
629
|
+
|
|
630
|
+
it 'deletes the index without raising an exception' do
|
|
631
|
+
expect(DummyIndexingModelForRecreate.delete_index!(force: true)).to be_nil
|
|
632
|
+
end
|
|
633
|
+
|
|
634
|
+
context 'when the client has a logger' do
|
|
635
|
+
|
|
636
|
+
let(:logger) do
|
|
637
|
+
Logger.new(STDOUT).tap { |l| l.level = Logger::DEBUG }
|
|
638
|
+
end
|
|
639
|
+
|
|
640
|
+
let(:client) do
|
|
641
|
+
double('client', indices: indices, transport: double('transport', { logger: logger }))
|
|
642
|
+
end
|
|
643
|
+
|
|
644
|
+
it 'deletes the index without raising an exception' do
|
|
645
|
+
expect(DummyIndexingModelForRecreate.delete_index!(force: true)).to be_nil
|
|
646
|
+
end
|
|
647
|
+
|
|
648
|
+
it 'logs the message that the index is not found' do
|
|
649
|
+
expect(logger).to receive(:debug)
|
|
650
|
+
expect(DummyIndexingModelForRecreate.delete_index!(force: true)).to be_nil
|
|
651
|
+
end
|
|
652
|
+
end
|
|
653
|
+
end
|
|
654
|
+
|
|
655
|
+
context 'when the force option is not provided' do
|
|
656
|
+
|
|
657
|
+
it 'raises an exception' do
|
|
658
|
+
expect {
|
|
659
|
+
DummyIndexingModelForRecreate.delete_index!
|
|
660
|
+
}.to raise_exception(NotFound)
|
|
661
|
+
end
|
|
662
|
+
end
|
|
663
|
+
|
|
664
|
+
context 'when the exception is not NotFound' do
|
|
665
|
+
|
|
666
|
+
let(:indices) do
|
|
667
|
+
double('indices').tap do |ind|
|
|
668
|
+
expect(ind).to receive(:delete).and_raise(Exception)
|
|
669
|
+
end
|
|
670
|
+
end
|
|
671
|
+
|
|
672
|
+
it 'raises an exception' do
|
|
673
|
+
expect {
|
|
674
|
+
DummyIndexingModelForRecreate.delete_index!
|
|
675
|
+
}.to raise_exception(Exception)
|
|
676
|
+
end
|
|
677
|
+
end
|
|
678
|
+
end
|
|
679
|
+
|
|
680
|
+
context 'when an index name is provided in the options' do
|
|
681
|
+
|
|
682
|
+
before do
|
|
683
|
+
expect(DummyIndexingModelForRecreate).to receive(:client).and_return(client)
|
|
684
|
+
expect(indices).to receive(:delete).with(index: 'custom-foo')
|
|
685
|
+
end
|
|
686
|
+
|
|
687
|
+
let(:client) do
|
|
688
|
+
double('client', indices: indices)
|
|
689
|
+
end
|
|
690
|
+
|
|
691
|
+
let(:indices) do
|
|
692
|
+
double('indices', delete: true)
|
|
693
|
+
end
|
|
694
|
+
|
|
695
|
+
it 'uses the index name' do
|
|
696
|
+
expect(DummyIndexingModelForRecreate.delete_index!(index: 'custom-foo'))
|
|
697
|
+
end
|
|
698
|
+
end
|
|
699
|
+
end
|
|
700
|
+
|
|
701
|
+
describe '#create_index' do
|
|
702
|
+
|
|
703
|
+
before(:all) do
|
|
704
|
+
class ::DummyIndexingModelForCreate
|
|
705
|
+
extend ActiveModel::Naming
|
|
706
|
+
extend Elasticsearch::Model::Naming::ClassMethods
|
|
707
|
+
extend Elasticsearch::Model::Indexing::ClassMethods
|
|
708
|
+
|
|
709
|
+
index_name 'foo'
|
|
710
|
+
|
|
711
|
+
settings index: { number_of_shards: 1 } do
|
|
712
|
+
mappings do
|
|
713
|
+
indexes :foo, analyzer: 'keyword'
|
|
714
|
+
end
|
|
715
|
+
end
|
|
716
|
+
end
|
|
717
|
+
end
|
|
718
|
+
|
|
719
|
+
after(:all) do
|
|
720
|
+
Object.send(:remove_const, :DummyIndexingModelForCreate) if defined?(DummyIndexingModelForCreate)
|
|
721
|
+
end
|
|
722
|
+
|
|
723
|
+
let(:client) do
|
|
724
|
+
double('client', indices: indices)
|
|
725
|
+
end
|
|
726
|
+
|
|
727
|
+
let(:indices) do
|
|
728
|
+
double('indices')
|
|
729
|
+
end
|
|
730
|
+
|
|
731
|
+
context 'when the index does not exist' do
|
|
732
|
+
|
|
733
|
+
before do
|
|
734
|
+
expect(DummyIndexingModelForCreate).to receive(:client).and_return(client)
|
|
735
|
+
expect(DummyIndexingModelForCreate).to receive(:index_exists?).and_return(false)
|
|
736
|
+
end
|
|
737
|
+
|
|
738
|
+
context 'when options are not provided' do
|
|
739
|
+
|
|
740
|
+
let(:expected_body) do
|
|
741
|
+
{ mappings: { _doc: { properties: { foo: { analyzer: 'keyword',
|
|
742
|
+
type: 'text' } } } },
|
|
743
|
+
settings: { index: { number_of_shards: 1 } } }
|
|
744
|
+
end
|
|
745
|
+
|
|
746
|
+
before do
|
|
747
|
+
expect(indices).to receive(:create).with(index: 'foo', body: expected_body).and_return(true)
|
|
748
|
+
end
|
|
749
|
+
|
|
750
|
+
it 'creates the index' do
|
|
751
|
+
expect(DummyIndexingModelForCreate.create_index!).to be(true)
|
|
752
|
+
end
|
|
753
|
+
end
|
|
754
|
+
|
|
755
|
+
context 'when options are provided' do
|
|
756
|
+
|
|
757
|
+
let(:expected_body) do
|
|
758
|
+
{ mappings: { foobar: { properties: { foo: { analyzer: 'bar' } } } },
|
|
759
|
+
settings: { index: { number_of_shards: 3 } } }
|
|
760
|
+
end
|
|
761
|
+
|
|
762
|
+
before do
|
|
763
|
+
expect(indices).to receive(:create).with(index: 'foobar', body: expected_body).and_return(true)
|
|
764
|
+
end
|
|
765
|
+
|
|
766
|
+
it 'creates the index' do
|
|
767
|
+
expect(DummyIndexingModelForCreate.create_index! \
|
|
768
|
+
index: 'foobar',
|
|
769
|
+
settings: { index: { number_of_shards: 3 } },
|
|
770
|
+
mappings: { foobar: { properties: { foo: { analyzer: 'bar' } } } }
|
|
771
|
+
).to be(true)
|
|
772
|
+
end
|
|
773
|
+
end
|
|
774
|
+
end
|
|
775
|
+
|
|
776
|
+
context 'when the index exists' do
|
|
777
|
+
|
|
778
|
+
before do
|
|
779
|
+
expect(DummyIndexingModelForCreate).to receive(:index_exists?).and_return(true)
|
|
780
|
+
expect(indices).to receive(:create).never
|
|
781
|
+
end
|
|
782
|
+
|
|
783
|
+
it 'does not create the index' do
|
|
784
|
+
expect(DummyIndexingModelForCreate.create_index!).to be_nil
|
|
785
|
+
end
|
|
786
|
+
end
|
|
787
|
+
|
|
788
|
+
context 'when creating the index raises an exception' do
|
|
789
|
+
|
|
790
|
+
before do
|
|
791
|
+
expect(DummyIndexingModelForCreate).to receive(:client).and_return(client)
|
|
792
|
+
expect(DummyIndexingModelForCreate).to receive(:index_exists?).and_return(false)
|
|
793
|
+
expect(DummyIndexingModelForCreate).to receive(:delete_index!).and_return(true)
|
|
794
|
+
expect(indices).to receive(:create).and_raise(Exception)
|
|
795
|
+
end
|
|
796
|
+
|
|
797
|
+
it 'raises the exception' do
|
|
798
|
+
expect {
|
|
799
|
+
DummyIndexingModelForCreate.create_index!(force: true)
|
|
800
|
+
}.to raise_exception(Exception)
|
|
801
|
+
end
|
|
802
|
+
end
|
|
803
|
+
|
|
804
|
+
context 'when an index name is provided in the options' do
|
|
805
|
+
|
|
806
|
+
before do
|
|
807
|
+
expect(DummyIndexingModelForCreate).to receive(:client).and_return(client).twice
|
|
808
|
+
expect(indices).to receive(:exists).and_return(false)
|
|
809
|
+
expect(indices).to receive(:create).with(index: 'custom-foo', body: expected_body)
|
|
810
|
+
end
|
|
811
|
+
|
|
812
|
+
let(:expected_body) do
|
|
813
|
+
{ mappings: { _doc: { properties: { foo: { analyzer: 'keyword',
|
|
814
|
+
type: 'text' } } } },
|
|
815
|
+
settings: { index: { number_of_shards: 1 } } }
|
|
816
|
+
end
|
|
817
|
+
|
|
818
|
+
it 'uses the index name' do
|
|
819
|
+
expect(DummyIndexingModelForCreate.create_index!(index: 'custom-foo'))
|
|
820
|
+
end
|
|
821
|
+
end
|
|
822
|
+
|
|
823
|
+
context 'when the logging level is debug'
|
|
824
|
+
end
|
|
825
|
+
|
|
826
|
+
describe '#refresh_index!' do
|
|
827
|
+
|
|
828
|
+
before(:all) do
|
|
829
|
+
class ::DummyIndexingModelForRefresh
|
|
830
|
+
extend ActiveModel::Naming
|
|
831
|
+
extend Elasticsearch::Model::Naming::ClassMethods
|
|
832
|
+
extend Elasticsearch::Model::Indexing::ClassMethods
|
|
833
|
+
|
|
834
|
+
index_name 'foo'
|
|
835
|
+
|
|
836
|
+
settings index: { number_of_shards: 1 } do
|
|
837
|
+
mappings do
|
|
838
|
+
indexes :foo, analyzer: 'keyword'
|
|
839
|
+
end
|
|
840
|
+
end
|
|
841
|
+
end
|
|
842
|
+
end
|
|
843
|
+
|
|
844
|
+
after(:all) do
|
|
845
|
+
Object.send(:remove_const, :DummyIndexingModelForRefresh) if defined?(DummyIndexingModelForRefresh)
|
|
846
|
+
end
|
|
847
|
+
|
|
848
|
+
let(:client) do
|
|
849
|
+
double('client', indices: indices, transport: double('transport', { logger: nil }))
|
|
850
|
+
end
|
|
851
|
+
|
|
852
|
+
let(:indices) do
|
|
853
|
+
double('indices')
|
|
854
|
+
end
|
|
855
|
+
|
|
856
|
+
before do
|
|
857
|
+
expect(DummyIndexingModelForRefresh).to receive(:client).at_most(3).times.and_return(client)
|
|
858
|
+
end
|
|
859
|
+
|
|
860
|
+
context 'when the force option is true' do
|
|
861
|
+
|
|
862
|
+
context 'when the operation raises a NotFound exception' do
|
|
863
|
+
|
|
864
|
+
before do
|
|
865
|
+
expect(indices).to receive(:refresh).and_raise(NotFound)
|
|
866
|
+
end
|
|
867
|
+
|
|
868
|
+
it 'does not raise an exception' do
|
|
869
|
+
expect(DummyIndexingModelForRefresh.refresh_index!(force: true)).to be_nil
|
|
870
|
+
end
|
|
871
|
+
|
|
872
|
+
context 'when the client has a logger' do
|
|
873
|
+
|
|
874
|
+
let(:logger) do
|
|
875
|
+
Logger.new(STDOUT).tap { |l| l.level = Logger::DEBUG }
|
|
876
|
+
end
|
|
877
|
+
|
|
878
|
+
let(:client) do
|
|
879
|
+
double('client', indices: indices, transport: double('transport', { logger: logger }))
|
|
880
|
+
end
|
|
881
|
+
|
|
882
|
+
it 'does not raise an exception' do
|
|
883
|
+
expect(DummyIndexingModelForRefresh.refresh_index!(force: true)).to be_nil
|
|
884
|
+
end
|
|
885
|
+
|
|
886
|
+
it 'logs the message that the index is not found' do
|
|
887
|
+
expect(logger).to receive(:debug)
|
|
888
|
+
expect(DummyIndexingModelForRefresh.refresh_index!(force: true)).to be_nil
|
|
889
|
+
end
|
|
890
|
+
end
|
|
891
|
+
end
|
|
892
|
+
|
|
893
|
+
context 'when the operation raises another type of exception' do
|
|
894
|
+
|
|
895
|
+
before do
|
|
896
|
+
expect(indices).to receive(:refresh).and_raise(Exception)
|
|
897
|
+
end
|
|
898
|
+
|
|
899
|
+
it 'does not raise an exception' do
|
|
900
|
+
expect {
|
|
901
|
+
DummyIndexingModelForRefresh.refresh_index!(force: true)
|
|
902
|
+
}.to raise_exception(Exception)
|
|
903
|
+
end
|
|
904
|
+
end
|
|
905
|
+
end
|
|
906
|
+
|
|
907
|
+
context 'when an index name is provided in the options' do
|
|
908
|
+
|
|
909
|
+
before do
|
|
910
|
+
expect(indices).to receive(:refresh).with(index: 'custom-foo')
|
|
911
|
+
end
|
|
912
|
+
|
|
913
|
+
it 'uses the index name' do
|
|
914
|
+
expect(DummyIndexingModelForRefresh.refresh_index!(index: 'custom-foo'))
|
|
915
|
+
end
|
|
916
|
+
end
|
|
917
|
+
end
|
|
918
|
+
end
|