elastic_adapter 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +41 -0
  7. data/Rakefile +24 -0
  8. data/elastic_adapter.gemspec +30 -0
  9. data/example.env +4 -0
  10. data/lib/elastic_adapter/decoration/count_response.rb +18 -0
  11. data/lib/elastic_adapter/decoration/decorator.rb +39 -0
  12. data/lib/elastic_adapter/decoration/hit_decorator.rb +25 -0
  13. data/lib/elastic_adapter/decoration/response_decorator_factory.rb +51 -0
  14. data/lib/elastic_adapter/decoration/search_response.rb +29 -0
  15. data/lib/elastic_adapter/decoration/suggestion_response.rb +25 -0
  16. data/lib/elastic_adapter/decoration/validation_response.rb +16 -0
  17. data/lib/elastic_adapter/document_type.rb +21 -0
  18. data/lib/elastic_adapter/index.rb +108 -0
  19. data/lib/elastic_adapter/response.rb +57 -0
  20. data/lib/elastic_adapter/version.rb +3 -0
  21. data/lib/elastic_adapter.rb +21 -0
  22. data/spec/cassettes/ElasticAdapter_Index/_count/empty_index/is_a_response.yml +30 -0
  23. data/spec/cassettes/ElasticAdapter_Index/_count/empty_index/returs_the_amount_of_all_documents.yml +30 -0
  24. data/spec/cassettes/ElasticAdapter_Index/_count/not_empty_index/is_a_response.yml +30 -0
  25. data/spec/cassettes/ElasticAdapter_Index/_count/not_empty_index/returns_1.yml +30 -0
  26. data/spec/cassettes/ElasticAdapter_Index/_create_index/index_is_present/response/has_an_exception.yml +30 -0
  27. data/spec/cassettes/ElasticAdapter_Index/_create_index/index_is_present/response/is_a_Response.yml +30 -0
  28. data/spec/cassettes/ElasticAdapter_Index/_create_index/index_not_present/response/has_no_exception.yml +57 -0
  29. data/spec/cassettes/ElasticAdapter_Index/_create_index/index_not_present/response/is_a_Response.yml +57 -0
  30. data/spec/cassettes/ElasticAdapter_Index/_delete_index/index_not_present/repsonse/has_an_exception.yml +30 -0
  31. data/spec/cassettes/ElasticAdapter_Index/_delete_index/index_not_present/repsonse/is_a_Response.yml +30 -0
  32. data/spec/cassettes/ElasticAdapter_Index/_delete_index/index_present/repsonse/has_no_exception.yml +57 -0
  33. data/spec/cassettes/ElasticAdapter_Index/_delete_index/index_present/repsonse/is_a_Response.yml +57 -0
  34. data/spec/cassettes/ElasticAdapter_Index/_get/document_exists/response/contains_the_document.yml +30 -0
  35. data/spec/cassettes/ElasticAdapter_Index/_index/existing_document/doesn_t_change_the_document_count.yml +84 -0
  36. data/spec/cassettes/ElasticAdapter_Index/_index/existing_document/invokes_to_hash_on_the_document.yml +30 -0
  37. data/spec/cassettes/ElasticAdapter_Index/_index/existing_document/updates_the_document.yml +30 -0
  38. data/spec/cassettes/ElasticAdapter_Index/_index/new_document/indexes_a_document.yml +57 -0
  39. data/spec/cassettes/ElasticAdapter_Index/_index/new_document/invokes_to_hash_on_the_document.yml +30 -0
  40. data/spec/cassettes/ElasticAdapter_Index/_search/match_all/returns_all_documents.yml +30 -0
  41. data/spec/cassettes/ElasticAdapter_Index/_search/zoo/returns_one_document.yml +30 -0
  42. data/spec/cassettes/ElasticAdapter_Index/_search/zoo/returns_the_wanted_document.yml +30 -0
  43. data/spec/cassettes/ElasticAdapter_Index/_suggest/query_ba_/returns_bar.yml +30 -0
  44. data/spec/cassettes/ElasticAdapter_Index/_suggest/query_ba_/returns_one_result.yml +30 -0
  45. data/spec/cassettes/ElasticAdapter_Index/_validate/invalid_query/is_a_response.yml +30 -0
  46. data/spec/cassettes/ElasticAdapter_Index/_validate/invalid_query/is_false.yml +31 -0
  47. data/spec/cassettes/ElasticAdapter_Index/_validate/valid_query/is_a_response.yml +30 -0
  48. data/spec/cassettes/ElasticAdapter_Index/_validate/valid_query/is_true.yml +30 -0
  49. data/spec/decoration/response_decorator_factory_spec.rb +75 -0
  50. data/spec/document_type_spec.rb +42 -0
  51. data/spec/elastic_adapter_spec.rb +4 -0
  52. data/spec/index_spec.rb +458 -0
  53. data/spec/response_spec.rb +80 -0
  54. data/spec/spec_helper.rb +102 -0
  55. metadata +243 -0
@@ -0,0 +1,458 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.shared_examples "response without exception" do
4
+ it "is a Response" do
5
+ expect(response).to be_a ElasticAdapter::Response
6
+ end
7
+
8
+ it "has no exception" do
9
+ expect(response).not_to have_key :exception
10
+ end
11
+ end
12
+
13
+ RSpec.shared_examples "response with exception" do
14
+ it "is a Response" do
15
+ expect(response).to be_a ElasticAdapter::Response
16
+ end
17
+
18
+ it "has an exception" do
19
+ expect(response).to have_key :exception
20
+ end
21
+ end
22
+
23
+ module ElasticAdapter
24
+ describe Index, :vcr do
25
+ def test_index(name = "test_index", options = {})
26
+ params = {
27
+ name: name,
28
+ url: "http://localhost:9200",
29
+ log: true,
30
+ settings: {},
31
+ document_type: OpenStruct.new(
32
+ name: "test_doc",
33
+ mappings: {
34
+ test_doc: {
35
+ properties: {
36
+ foo: { type: "string" }
37
+ }
38
+ }
39
+ }
40
+ )
41
+ }.merge(options)
42
+
43
+ Index.new(params)
44
+ end
45
+
46
+ def create_test_index(name = "test_index", options = {})
47
+ test_index(name, options).create_index
48
+ end
49
+
50
+ def delete_test_index(name = "test_index", options = {})
51
+ test_index(name, options).delete_index
52
+ end
53
+
54
+ def index_document(document, name = "test_index", options = {})
55
+ test_index(name, options).index(document)
56
+ end
57
+
58
+ def wait_for_elasticsearch
59
+ if ENV["RECORDING"]
60
+ sleep 1
61
+ end
62
+ end
63
+
64
+ let(:name) { "test_index" }
65
+ let(:mappings) do
66
+ {
67
+ test_index: {
68
+ properties: {
69
+ foo: {
70
+ type: "string"
71
+ }
72
+ }
73
+ }
74
+ }
75
+ end
76
+ let(:document_type) do
77
+ OpenStruct.new(name: "test_doc", mappings: mappings)
78
+ end
79
+ let(:settings) { { number_of_shards: 1 } }
80
+ let(:log) { true }
81
+ let(:url) { "http://localhost:9200"}
82
+
83
+ let(:subject) do
84
+ Index.new(
85
+ name: name,
86
+ settings: settings,
87
+ document_type: document_type,
88
+ url: url,
89
+ log: log
90
+ )
91
+ end
92
+
93
+ describe "#initialize" do
94
+ it "assigns the name" do
95
+ expect(subject.instance_variable_get('@name')).to be name
96
+ end
97
+
98
+ it "assigns the settings" do
99
+ expect(subject.instance_variable_get('@settings')).to be settings
100
+ end
101
+
102
+ it "assigns the document_type" do
103
+ expect(subject.instance_variable_get('@document_type')).to be document_type
104
+ end
105
+
106
+ it "assigns the url" do
107
+ expect(subject.instance_variable_get('@url')).to be url
108
+ end
109
+
110
+ it "assigns the log" do
111
+ expect(subject.instance_variable_get('@log')).to be log
112
+ end
113
+ end
114
+
115
+ describe "getter" do
116
+ describe "name" do
117
+ it "returns the name" do
118
+ expect(subject.name).to eq name
119
+ end
120
+ end
121
+
122
+ describe "settings" do
123
+ it "returns the settings" do
124
+ expect(subject.settings).to eq settings
125
+ end
126
+ end
127
+
128
+ describe "document_type" do
129
+ it "returns the document_type" do
130
+ expect(subject.document_type).to eq document_type
131
+ end
132
+ end
133
+
134
+ describe "url" do
135
+ it "returns the url" do
136
+ expect(subject.url).to eq url
137
+ end
138
+ end
139
+
140
+ describe "log" do
141
+ it "returns the log" do
142
+ expect(subject.log).to eq log
143
+ end
144
+ end
145
+
146
+ describe "client" do
147
+ it "returns the client" do
148
+ expect(subject.client).to be_a ::Elasticsearch::Transport::Client
149
+ end
150
+ end
151
+ end
152
+
153
+ describe "#validate" do
154
+ before :all do
155
+ create_test_index
156
+ wait_for_elasticsearch
157
+ end
158
+
159
+ after :all do
160
+ delete_test_index
161
+ end
162
+
163
+ context "invalid query" do
164
+ let(:query) do
165
+ {
166
+ asd: "[[[ BOOM! ]]]"
167
+ }
168
+ end
169
+
170
+ let(:response) { subject.validate(query) }
171
+
172
+ it "is false" do
173
+ expect(response).to eq false
174
+ end
175
+
176
+ it "is a response" do
177
+ expect(response).to be_a Decoration::ValidationResponse
178
+ end
179
+ end
180
+
181
+ context "valid query" do
182
+ let(:query) do
183
+ {
184
+ query: {
185
+ match_all: {}
186
+ }
187
+ }
188
+ end
189
+
190
+ let(:response) { subject.validate(query) }
191
+
192
+ it "is true" do
193
+ expect(response).to eq true
194
+ end
195
+
196
+ it "is a response" do
197
+ expect(response).to be_a Decoration::ValidationResponse
198
+ end
199
+ end
200
+ end
201
+
202
+ describe "#suggest" do
203
+ before :all do
204
+ create_test_index "test_index", document_type: OpenStruct.new(
205
+ name: "test_doc",
206
+ mappings: {
207
+ test_doc: {
208
+ properties: {
209
+ foo: { type: "completion" }
210
+ }
211
+ }
212
+ }
213
+ )
214
+
215
+ index_document(foo: {input: "bar"})
216
+ index_document(foo: {input: "zoo"})
217
+ sleep 1
218
+ end
219
+
220
+ after :all do
221
+ delete_test_index
222
+ end
223
+
224
+ context "query 'ba'" do
225
+ let(:query) do
226
+ {
227
+ foo_suggest: {
228
+ text: "ba",
229
+ completion: {
230
+ field: "foo"
231
+ }
232
+ }
233
+ }
234
+ end
235
+
236
+ let(:response) { subject.suggest(query)}
237
+
238
+ it "returns one result" do
239
+ expect(response.count).to eq 1
240
+ end
241
+
242
+ it "returns bar" do
243
+ expect(response[:options].first).to include text: "bar"
244
+ end
245
+
246
+ end
247
+ end
248
+
249
+ describe "#search" do
250
+ before :all do
251
+ create_test_index
252
+ index_document(foo: "bar", id: 1)
253
+ index_document(foo: "zoo", id: 2)
254
+ sleep 1
255
+ end
256
+
257
+ after :all do
258
+ delete_test_index
259
+ end
260
+
261
+ context "match_all" do
262
+ it "returns all documents" do
263
+ expect(subject.search({query: {match_all: {}}}).count).to eq 2
264
+ end
265
+ end
266
+
267
+ context "zoo" do
268
+ let(:response) { subject.search(query: {match: {foo: "zoo"}})}
269
+ it "returns one document" do
270
+ expect(response.count).to eq 1
271
+ end
272
+
273
+ it "returns the wanted document" do
274
+ expect(response[:hits].first[:id]).to eq "2"
275
+ expect(response[:hits].first[:foo]).to eq "zoo"
276
+ end
277
+ end
278
+ end
279
+
280
+ describe "#get" do
281
+ context "document exists" do
282
+ let(:document) { {id: "1", foo: "bar"} }
283
+ before :all do
284
+ create_test_index
285
+ index_document(foo: "bar", id: 1)
286
+ end
287
+
288
+ after :all do
289
+ delete_test_index
290
+ end
291
+
292
+ let(:response) { subject.get(1) }
293
+
294
+ describe "response" do
295
+ it "contains the document" do
296
+ expect(response).to eq document
297
+ end
298
+ end
299
+ end
300
+ end
301
+
302
+ describe "#index" do
303
+ context "new document" do
304
+ let(:document) { { foo: "bar" } }
305
+
306
+ before :all do
307
+ create_test_index
308
+ end
309
+
310
+ after :all do
311
+ delete_test_index
312
+ end
313
+
314
+ it "indexes a document" do
315
+ subject.index(document)
316
+ # wait_for_elasticsearch
317
+ sleep 1
318
+ expect(subject.count).to eq 1
319
+ end
320
+
321
+ it "invokes to_hash on the document" do
322
+ expect(document).to receive(:to_hash).and_return(document.to_hash)
323
+ subject.index(document)
324
+ end
325
+ end
326
+
327
+ context "existing document" do
328
+ let(:document) { {foo: "baz", id: 1} }
329
+
330
+ before :all do
331
+ create_test_index
332
+ # wait_for_elasticsearch
333
+ sleep 1
334
+ index_document foo: "bar", id: 1
335
+ # wait_for_elasticsearch
336
+ sleep 1
337
+ end
338
+
339
+ after :all do
340
+ delete_test_index
341
+ end
342
+
343
+ it "doesn't change the document count" do
344
+ expect(subject.count).to eq 1
345
+ subject.index(document)
346
+ sleep 1
347
+ # wait_for_elasticsearch
348
+ expect(subject.count).to eq 1
349
+ end
350
+
351
+ it "invokes to_hash on the document" do
352
+ expect(document).to receive(:to_hash).and_return(document.to_hash)
353
+ subject.index(document)
354
+ end
355
+
356
+ it "updates the document" do
357
+ expect(subject.get(1)[:foo]).to eq "baz"
358
+ end
359
+ end
360
+ end
361
+
362
+ describe "#count" do
363
+ context "empty index" do
364
+ before :all do
365
+ create_test_index
366
+ wait_for_elasticsearch
367
+ end
368
+
369
+ after :all do
370
+ delete_test_index
371
+ end
372
+
373
+ it "returs the amount of all documents" do
374
+ expect(subject.count).to eq 0
375
+ end
376
+
377
+ it "is a response" do
378
+ expect(subject.count).to be_a Decoration::CountResponse
379
+ end
380
+ end
381
+
382
+ context "not empty index" do
383
+ before :all do
384
+ create_test_index
385
+ index_document foo: "bar"
386
+ sleep 1
387
+ # wait_for_elasticsearch
388
+ end
389
+
390
+ after :all do
391
+ delete_test_index
392
+ end
393
+
394
+ it "returns 1" do
395
+ expect(subject.count).to eq 1
396
+ end
397
+
398
+ it "is a response" do
399
+ expect(subject.count).to be_a Decoration::CountResponse
400
+ end
401
+ end
402
+ end
403
+
404
+ describe "#delete_index" do
405
+ context "index present" do
406
+ before :each do
407
+ create_test_index
408
+ end
409
+
410
+ let(:response) { subject.delete_index }
411
+
412
+ describe "repsonse" do
413
+ include_examples "response without exception"
414
+ end
415
+ end
416
+
417
+ context "index not present" do
418
+ let(:response) { subject.delete_index }
419
+
420
+ describe "repsonse" do
421
+ include_examples "response with exception"
422
+ end
423
+ end
424
+ end
425
+
426
+ describe "#create_index" do
427
+ context "index is present" do
428
+ before :all do
429
+ create_test_index
430
+ end
431
+
432
+ after :all do
433
+ delete_test_index
434
+ end
435
+
436
+ let(:response) { subject.create_index }
437
+
438
+ describe "response" do
439
+ # TODO fix this
440
+ # Somehow VCR doesn't record the requests for the current context
441
+ include_examples "response with exception"
442
+ end
443
+ end
444
+
445
+ context "index not present" do
446
+ after :each do
447
+ delete_test_index
448
+ end
449
+
450
+ let(:response) { subject.create_index }
451
+
452
+ describe "response" do
453
+ include_examples "response without exception"
454
+ end
455
+ end
456
+ end
457
+ end
458
+ end
@@ -0,0 +1,80 @@
1
+ require "spec_helper"
2
+
3
+ module ElasticAdapter
4
+ describe Response do
5
+ describe "delegation" do
6
+ let(:hash) { { foo: "bar" } }
7
+ let(:response) { Response.new(hash) }
8
+
9
+ describe "#original_object" do
10
+ it "returns the original hash" do
11
+ expect(response.original_object).to be hash
12
+ end
13
+ end
14
+
15
+ describe "object" do
16
+ it "returns the sanitized hash" do
17
+ expect(response.object).to eq({ foo: "bar" })
18
+ end
19
+ end
20
+ end
21
+
22
+ describe "sanitization" do
23
+ it "turns all strings in Hash keys to symbols" do
24
+ hash = {"foo" => "bar"}
25
+ response = Response.new(hash)
26
+ expect(response.keys.first).to be_a Symbol
27
+ end
28
+
29
+ it "removes all leading underscores from keys" do
30
+ hash = {"_foo" => {"_bar" => "baz" }}
31
+ expected = {foo: {bar: "baz" }}
32
+ response = Response.new(hash)
33
+ expect(response.object).to eq expected
34
+ end
35
+ end
36
+
37
+ describe "#failure?" do
38
+ context "no exception" do
39
+ let(:hash) { { foo: "bar" } }
40
+ let(:response) { Response.new(hash) }
41
+
42
+ it "returns false" do
43
+ expect(response.failure?).to be false
44
+ end
45
+ end
46
+
47
+ context "with exception" do
48
+ let(:hash) { { foo: "bar", exception: ArgumentError.new("foo") } }
49
+ let(:response) { Response.new(hash) }
50
+
51
+ it "returns true" do
52
+ expect(response.failure?).to be true
53
+ end
54
+ end
55
+ end
56
+
57
+ describe "#decorate" do
58
+ context "find request" do
59
+ let(:document) { {foo: "bar", id: 1} }
60
+ let(:response_hash) do
61
+ {
62
+ "found" => true,
63
+ "_id" => 1,
64
+ "_source" => {
65
+ "foo" => "bar"
66
+ }
67
+ }
68
+ end
69
+
70
+ let(:response) do
71
+ response = Response.new(response_hash)
72
+ end
73
+
74
+ it "is the document" do
75
+ expect(response.decorate.to_hash).to eq document
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,102 @@
1
+ require "elastic_adapter"
2
+ require "rake"
3
+ require "webmock/rspec"
4
+ require "vcr"
5
+
6
+ VCR.configure do |config|
7
+ config.cassette_library_dir = 'spec/cassettes'
8
+ config.hook_into :webmock
9
+ config.default_cassette_options = { record: :new_episodes }
10
+ config.configure_rspec_metadata!
11
+ config.allow_http_connections_when_no_cassette = true
12
+ end
13
+
14
+ # This file was generated by the `rspec --init` command. Conventionally, all
15
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
16
+ # The generated `.rspec` file contains `--require spec_helper` which will cause this
17
+ # file to always be loaded, without a need to explicitly require it in any files.
18
+ #
19
+ # Given that it is always loaded, you are encouraged to keep this file as
20
+ # light-weight as possible. Requiring heavyweight dependencies from this file
21
+ # will add to the boot time of your test suite on EVERY test run, even for an
22
+ # individual file that may not need all of that loaded. Instead, consider making
23
+ # a separate helper file that requires the additional dependencies and performs
24
+ # the additional setup, and require it from the spec files that actually need it.
25
+ #
26
+ # The `.rspec` file also contains a few flags that are not defaults but that
27
+ # users commonly want.
28
+ #
29
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
30
+ RSpec.configure do |config|
31
+ # rspec-expectations config goes here. You can use an alternate
32
+ # assertion/expectation library such as wrong or the stdlib/minitest
33
+ # assertions if you prefer.
34
+ config.expect_with :rspec do |expectations|
35
+ # This option will default to `true` in RSpec 4. It makes the `description`
36
+ # and `failure_message` of custom matchers include text for helper methods
37
+ # defined using `chain`, e.g.:
38
+ # be_bigger_than(2).and_smaller_than(4).description
39
+ # # => "be bigger than 2 and smaller than 4"
40
+ # ...rather than:
41
+ # # => "be bigger than 2"
42
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
43
+ end
44
+
45
+ # rspec-mocks config goes here. You can use an alternate test double
46
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
47
+ config.mock_with :rspec do |mocks|
48
+ # Prevents you from mocking or stubbing a method that does not exist on
49
+ # a real object. This is generally recommended, and will default to
50
+ # `true` in RSpec 4.
51
+ mocks.verify_partial_doubles = true
52
+ end
53
+
54
+ # The settings below are suggested to provide a good initial experience
55
+ # with RSpec, but feel free to customize to your heart's content.
56
+ =begin
57
+ # These two settings work together to allow you to limit a spec run
58
+ # to individual examples or groups you care about by tagging them with
59
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
60
+ # get run.
61
+ config.filter_run :focus
62
+ config.run_all_when_everything_filtered = true
63
+
64
+ # Limits the available syntax to the non-monkey patched syntax that is recommended.
65
+ # For more details, see:
66
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
67
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
68
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
69
+ config.disable_monkey_patching!
70
+
71
+ # This setting enables warnings. It's recommended, but in some cases may
72
+ # be too noisy due to issues in dependencies.
73
+ config.warnings = true
74
+
75
+ # Many RSpec users commonly either run the entire suite or an individual
76
+ # file, and it's useful to allow more verbose output when running an
77
+ # individual spec file.
78
+ if config.files_to_run.one?
79
+ # Use the documentation formatter for detailed output,
80
+ # unless a formatter has already been configured
81
+ # (e.g. via a command-line flag).
82
+ config.default_formatter = 'doc'
83
+ end
84
+
85
+ # Print the 10 slowest examples and example groups at the
86
+ # end of the spec run, to help surface which specs are running
87
+ # particularly slow.
88
+ config.profile_examples = 10
89
+
90
+ # Run specs in random order to surface order dependencies. If you find an
91
+ # order dependency and want to debug it, you can fix the order by providing
92
+ # the seed, which is printed after each run.
93
+ # --seed 1234
94
+ config.order = :random
95
+
96
+ # Seed global randomization in this process using the `--seed` CLI option.
97
+ # Setting this allows you to use `--seed` to deterministically reproduce
98
+ # test failures related to randomization by passing the same `--seed` value
99
+ # as the one that triggered the failure.
100
+ Kernel.srand config.seed
101
+ =end
102
+ end