chewy 6.0.0 → 7.5.1

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 (188) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +1 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +39 -0
  4. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  5. data/.github/PULL_REQUEST_TEMPLATE.md +16 -0
  6. data/.github/dependabot.yml +42 -0
  7. data/.github/workflows/ruby.yml +48 -0
  8. data/.rubocop.yml +16 -8
  9. data/.rubocop_todo.yml +110 -22
  10. data/CHANGELOG.md +385 -105
  11. data/CODE_OF_CONDUCT.md +14 -0
  12. data/CONTRIBUTING.md +63 -0
  13. data/Gemfile +4 -10
  14. data/Guardfile +3 -1
  15. data/README.md +494 -275
  16. data/chewy.gemspec +5 -20
  17. data/gemfiles/base.gemfile +12 -0
  18. data/gemfiles/rails.6.1.activerecord.gemfile +10 -15
  19. data/gemfiles/rails.7.0.activerecord.gemfile +14 -0
  20. data/gemfiles/rails.7.1.activerecord.gemfile +14 -0
  21. data/lib/chewy/config.rb +58 -50
  22. data/lib/chewy/elastic_client.rb +31 -0
  23. data/lib/chewy/errors.rb +7 -10
  24. data/lib/chewy/fields/base.rb +79 -13
  25. data/lib/chewy/fields/root.rb +4 -14
  26. data/lib/chewy/index/actions.rb +54 -37
  27. data/lib/chewy/{type → index}/adapter/active_record.rb +30 -6
  28. data/lib/chewy/{type → index}/adapter/base.rb +2 -3
  29. data/lib/chewy/{type → index}/adapter/object.rb +27 -31
  30. data/lib/chewy/{type → index}/adapter/orm.rb +17 -18
  31. data/lib/chewy/index/aliases.rb +14 -5
  32. data/lib/chewy/index/crutch.rb +40 -0
  33. data/lib/chewy/index/import/bulk_builder.rb +311 -0
  34. data/lib/chewy/{type → index}/import/bulk_request.rb +6 -7
  35. data/lib/chewy/{type → index}/import/journal_builder.rb +11 -12
  36. data/lib/chewy/{type → index}/import/routine.rb +18 -17
  37. data/lib/chewy/{type → index}/import.rb +76 -32
  38. data/lib/chewy/{type → index}/mapping.rb +29 -34
  39. data/lib/chewy/index/observe/active_record_methods.rb +87 -0
  40. data/lib/chewy/index/observe/callback.rb +34 -0
  41. data/lib/chewy/index/observe.rb +17 -0
  42. data/lib/chewy/index/specification.rb +1 -0
  43. data/lib/chewy/{type → index}/syncer.rb +59 -59
  44. data/lib/chewy/{type → index}/witchcraft.rb +11 -7
  45. data/lib/chewy/{type → index}/wrapper.rb +2 -2
  46. data/lib/chewy/index.rb +67 -94
  47. data/lib/chewy/journal.rb +25 -14
  48. data/lib/chewy/log_subscriber.rb +5 -1
  49. data/lib/chewy/minitest/helpers.rb +86 -13
  50. data/lib/chewy/minitest/search_index_receiver.rb +24 -26
  51. data/lib/chewy/railtie.rb +6 -20
  52. data/lib/chewy/rake_helper.rb +169 -113
  53. data/lib/chewy/rspec/build_query.rb +12 -0
  54. data/lib/chewy/rspec/helpers.rb +55 -0
  55. data/lib/chewy/rspec/update_index.rb +55 -44
  56. data/lib/chewy/rspec.rb +2 -0
  57. data/lib/chewy/runtime/version.rb +1 -1
  58. data/lib/chewy/runtime.rb +1 -1
  59. data/lib/chewy/search/loader.rb +19 -41
  60. data/lib/chewy/search/parameters/collapse.rb +16 -0
  61. data/lib/chewy/search/parameters/concerns/query_storage.rb +2 -2
  62. data/lib/chewy/search/parameters/ignore_unavailable.rb +27 -0
  63. data/lib/chewy/search/parameters/indices.rb +13 -58
  64. data/lib/chewy/search/parameters/knn.rb +16 -0
  65. data/lib/chewy/search/parameters/order.rb +6 -19
  66. data/lib/chewy/search/parameters/source.rb +5 -1
  67. data/lib/chewy/search/parameters/storage.rb +1 -1
  68. data/lib/chewy/search/parameters/track_total_hits.rb +16 -0
  69. data/lib/chewy/search/parameters.rb +6 -4
  70. data/lib/chewy/search/query_proxy.rb +9 -2
  71. data/lib/chewy/search/request.rb +169 -134
  72. data/lib/chewy/search/response.rb +5 -5
  73. data/lib/chewy/search/scoping.rb +7 -8
  74. data/lib/chewy/search/scrolling.rb +13 -13
  75. data/lib/chewy/search.rb +9 -19
  76. data/lib/chewy/stash.rb +19 -30
  77. data/lib/chewy/strategy/active_job.rb +1 -1
  78. data/lib/chewy/strategy/atomic_no_refresh.rb +18 -0
  79. data/lib/chewy/strategy/base.rb +10 -0
  80. data/lib/chewy/strategy/delayed_sidekiq/scheduler.rb +151 -0
  81. data/lib/chewy/strategy/delayed_sidekiq/worker.rb +52 -0
  82. data/lib/chewy/strategy/delayed_sidekiq.rb +30 -0
  83. data/lib/chewy/strategy/lazy_sidekiq.rb +64 -0
  84. data/lib/chewy/strategy/sidekiq.rb +2 -1
  85. data/lib/chewy/strategy.rb +6 -19
  86. data/lib/chewy/version.rb +1 -1
  87. data/lib/chewy.rb +39 -86
  88. data/lib/generators/chewy/install_generator.rb +1 -1
  89. data/lib/tasks/chewy.rake +36 -32
  90. data/migration_guide.md +46 -8
  91. data/spec/chewy/config_spec.rb +14 -39
  92. data/spec/chewy/elastic_client_spec.rb +26 -0
  93. data/spec/chewy/fields/base_spec.rb +432 -147
  94. data/spec/chewy/fields/root_spec.rb +20 -28
  95. data/spec/chewy/fields/time_fields_spec.rb +5 -5
  96. data/spec/chewy/index/actions_spec.rb +368 -59
  97. data/spec/chewy/{type → index}/adapter/active_record_spec.rb +156 -40
  98. data/spec/chewy/{type → index}/adapter/object_spec.rb +21 -6
  99. data/spec/chewy/index/aliases_spec.rb +3 -3
  100. data/spec/chewy/index/import/bulk_builder_spec.rb +494 -0
  101. data/spec/chewy/{type → index}/import/bulk_request_spec.rb +5 -12
  102. data/spec/chewy/{type → index}/import/journal_builder_spec.rb +9 -19
  103. data/spec/chewy/{type → index}/import/routine_spec.rb +19 -19
  104. data/spec/chewy/{type → index}/import_spec.rb +164 -98
  105. data/spec/chewy/index/mapping_spec.rb +135 -0
  106. data/spec/chewy/index/observe/active_record_methods_spec.rb +68 -0
  107. data/spec/chewy/index/observe/callback_spec.rb +139 -0
  108. data/spec/chewy/index/observe_spec.rb +143 -0
  109. data/spec/chewy/index/settings_spec.rb +3 -1
  110. data/spec/chewy/index/specification_spec.rb +20 -30
  111. data/spec/chewy/{type → index}/syncer_spec.rb +14 -19
  112. data/spec/chewy/{type → index}/witchcraft_spec.rb +20 -22
  113. data/spec/chewy/index/wrapper_spec.rb +100 -0
  114. data/spec/chewy/index_spec.rb +60 -105
  115. data/spec/chewy/journal_spec.rb +25 -74
  116. data/spec/chewy/minitest/helpers_spec.rb +123 -15
  117. data/spec/chewy/minitest/search_index_receiver_spec.rb +28 -30
  118. data/spec/chewy/multi_search_spec.rb +4 -5
  119. data/spec/chewy/rake_helper_spec.rb +315 -55
  120. data/spec/chewy/rspec/build_query_spec.rb +34 -0
  121. data/spec/chewy/rspec/helpers_spec.rb +61 -0
  122. data/spec/chewy/rspec/update_index_spec.rb +74 -71
  123. data/spec/chewy/runtime_spec.rb +2 -2
  124. data/spec/chewy/search/loader_spec.rb +19 -53
  125. data/spec/chewy/search/pagination/kaminari_examples.rb +4 -6
  126. data/spec/chewy/search/pagination/kaminari_spec.rb +2 -2
  127. data/spec/chewy/search/parameters/collapse_spec.rb +5 -0
  128. data/spec/chewy/search/parameters/ignore_unavailable_spec.rb +67 -0
  129. data/spec/chewy/search/parameters/indices_spec.rb +26 -117
  130. data/spec/chewy/search/parameters/knn_spec.rb +5 -0
  131. data/spec/chewy/search/parameters/order_spec.rb +18 -11
  132. data/spec/chewy/search/parameters/query_storage_examples.rb +67 -21
  133. data/spec/chewy/search/parameters/search_after_spec.rb +4 -1
  134. data/spec/chewy/search/parameters/source_spec.rb +8 -2
  135. data/spec/chewy/search/parameters/track_total_hits_spec.rb +5 -0
  136. data/spec/chewy/search/parameters_spec.rb +18 -4
  137. data/spec/chewy/search/query_proxy_spec.rb +68 -17
  138. data/spec/chewy/search/request_spec.rb +292 -110
  139. data/spec/chewy/search/response_spec.rb +12 -12
  140. data/spec/chewy/search/scrolling_spec.rb +10 -17
  141. data/spec/chewy/search_spec.rb +40 -34
  142. data/spec/chewy/stash_spec.rb +9 -21
  143. data/spec/chewy/strategy/active_job_spec.rb +16 -16
  144. data/spec/chewy/strategy/atomic_no_refresh_spec.rb +60 -0
  145. data/spec/chewy/strategy/atomic_spec.rb +9 -10
  146. data/spec/chewy/strategy/delayed_sidekiq_spec.rb +202 -0
  147. data/spec/chewy/strategy/lazy_sidekiq_spec.rb +214 -0
  148. data/spec/chewy/strategy/sidekiq_spec.rb +12 -12
  149. data/spec/chewy/strategy_spec.rb +19 -15
  150. data/spec/chewy_spec.rb +24 -107
  151. data/spec/spec_helper.rb +3 -22
  152. data/spec/support/active_record.rb +25 -7
  153. metadata +78 -339
  154. data/.circleci/config.yml +0 -240
  155. data/Appraisals +0 -81
  156. data/gemfiles/rails.5.2.activerecord.gemfile +0 -17
  157. data/gemfiles/rails.5.2.mongoid.6.4.gemfile +0 -17
  158. data/gemfiles/rails.6.0.activerecord.gemfile +0 -17
  159. data/gemfiles/sequel.4.45.gemfile +0 -11
  160. data/lib/chewy/backports/deep_dup.rb +0 -46
  161. data/lib/chewy/backports/duplicable.rb +0 -91
  162. data/lib/chewy/search/pagination/will_paginate.rb +0 -43
  163. data/lib/chewy/search/parameters/types.rb +0 -20
  164. data/lib/chewy/strategy/resque.rb +0 -27
  165. data/lib/chewy/strategy/shoryuken.rb +0 -40
  166. data/lib/chewy/type/actions.rb +0 -43
  167. data/lib/chewy/type/adapter/mongoid.rb +0 -67
  168. data/lib/chewy/type/adapter/sequel.rb +0 -93
  169. data/lib/chewy/type/crutch.rb +0 -32
  170. data/lib/chewy/type/import/bulk_builder.rb +0 -122
  171. data/lib/chewy/type/observe.rb +0 -82
  172. data/lib/chewy/type.rb +0 -120
  173. data/lib/sequel/plugins/chewy_observe.rb +0 -63
  174. data/spec/chewy/search/pagination/will_paginate_examples.rb +0 -63
  175. data/spec/chewy/search/pagination/will_paginate_spec.rb +0 -23
  176. data/spec/chewy/search/parameters/types_spec.rb +0 -5
  177. data/spec/chewy/strategy/resque_spec.rb +0 -46
  178. data/spec/chewy/strategy/shoryuken_spec.rb +0 -70
  179. data/spec/chewy/type/actions_spec.rb +0 -50
  180. data/spec/chewy/type/adapter/mongoid_spec.rb +0 -372
  181. data/spec/chewy/type/adapter/sequel_spec.rb +0 -472
  182. data/spec/chewy/type/import/bulk_builder_spec.rb +0 -194
  183. data/spec/chewy/type/mapping_spec.rb +0 -175
  184. data/spec/chewy/type/observe_spec.rb +0 -137
  185. data/spec/chewy/type/wrapper_spec.rb +0 -100
  186. data/spec/chewy/type_spec.rb +0 -55
  187. data/spec/support/mongoid.rb +0 -93
  188. data/spec/support/sequel.rb +0 -80
@@ -1,26 +1,29 @@
1
1
  require 'spec_helper'
2
+ require 'rake'
2
3
 
3
4
  describe Chewy::RakeHelper, :orm do
4
5
  before { Chewy.massacre }
5
6
 
6
7
  before do
8
+ described_class.instance_variable_set(:@journal_exists, journal_exists)
9
+
7
10
  stub_model(:city)
8
11
  stub_model(:country)
9
12
 
10
13
  stub_index(:cities) do
11
- define_type City do
12
- field :name
13
- field :updated_at, type: 'date'
14
- end
14
+ index_scope City
15
+ field :name
16
+ field :updated_at, type: 'date'
15
17
  end
16
18
  stub_index(:countries) do
17
- define_type Country
19
+ index_scope Country
18
20
  end
19
21
  stub_index(:users)
20
22
 
21
23
  allow(described_class).to receive(:all_indexes) { [CitiesIndex, CountriesIndex, UsersIndex] }
22
24
  end
23
25
 
26
+ let(:journal_exists) { true }
24
27
  let!(:cities) { Array.new(3) { |i| City.create!(name: "Name#{i + 1}") } }
25
28
  let!(:countries) { Array.new(2) { |i| Country.create!(name: "Name#{i + 1}") } }
26
29
  let(:journal) do
@@ -52,17 +55,18 @@ describe Chewy::RakeHelper, :orm do
52
55
  .to update_index(CitiesIndex)
53
56
  expect(output.string).to match(Regexp.new(<<-OUTPUT, Regexp::MULTILINE))
54
57
  \\AResetting CitiesIndex
55
- Imported CitiesIndex::City in \\d+s, stats: index 3
56
- Applying journal to \\[CitiesIndex::City\\], 2 entries, stage 1
57
- Imported CitiesIndex::City in \\d+s, stats: index 2
58
- Imported Chewy::Stash::Specification::Specification in \\d+s, stats: index 1
58
+ Imported CitiesIndex in \\d+s, stats: index 3
59
+ Applying journal to \\[CitiesIndex\\], 2 entries, stage 1
60
+ Imported CitiesIndex in \\d+s, stats: index 2
61
+ Imported Chewy::Stash::Specification in \\d+s, stats: index 1
59
62
  Resetting CountriesIndex
60
- Imported CountriesIndex::Country in \\d+s, stats: index 2
61
- Applying journal to \\[CountriesIndex::Country\\], 1 entries, stage 1
62
- Imported CountriesIndex::Country in \\d+s, stats: index 1
63
- Imported Chewy::Stash::Specification::Specification in \\d+s, stats: index 1
63
+ Imported CountriesIndex in \\d+s, stats: index 2
64
+ Applying journal to \\[CountriesIndex\\], 1 entries, stage 1
65
+ Imported CountriesIndex in \\d+s, stats: index 1
66
+ Imported Chewy::Stash::Specification in \\d+s, stats: index 1
64
67
  Resetting UsersIndex
65
- Imported Chewy::Stash::Specification::Specification in \\d+s, stats: index 1
68
+ Imported UsersIndex in 1s, stats:\s
69
+ Imported Chewy::Stash::Specification in \\d+s, stats: index 1
66
70
  Total: \\d+s\\Z
67
71
  OUTPUT
68
72
  end
@@ -73,10 +77,10 @@ Total: \\d+s\\Z
73
77
  .to update_index(CitiesIndex)
74
78
  expect(output.string).to match(Regexp.new(<<-OUTPUT, Regexp::MULTILINE))
75
79
  \\AResetting CitiesIndex
76
- Imported CitiesIndex::City in \\d+s, stats: index 3
77
- Applying journal to \\[CitiesIndex::City\\], 2 entries, stage 1
78
- Imported CitiesIndex::City in \\d+s, stats: index 2
79
- Imported Chewy::Stash::Specification::Specification in \\d+s, stats: index 1
80
+ Imported CitiesIndex in \\d+s, stats: index 3
81
+ Applying journal to \\[CitiesIndex\\], 2 entries, stage 1
82
+ Imported CitiesIndex in \\d+s, stats: index 2
83
+ Imported Chewy::Stash::Specification in \\d+s, stats: index 1
80
84
  Total: \\d+s\\Z
81
85
  OUTPUT
82
86
  end
@@ -87,10 +91,27 @@ Total: \\d+s\\Z
87
91
  .not_to update_index(CitiesIndex)
88
92
  expect(output.string).to match(Regexp.new(<<-OUTPUT, Regexp::MULTILINE))
89
93
  \\AResetting UsersIndex
90
- Imported Chewy::Stash::Specification::Specification in \\d+s, stats: index 1
94
+ Imported UsersIndex in 1s, stats:\s
95
+ Imported Chewy::Stash::Specification in \\d+s, stats: index 1
91
96
  Total: \\d+s\\Z
92
97
  OUTPUT
93
98
  end
99
+
100
+ context 'when journal is missing' do
101
+ let(:journal_exists) { false }
102
+
103
+ specify do
104
+ output = StringIO.new
105
+ expect { described_class.reset(only: [CitiesIndex], output: output) }
106
+ .to update_index(CitiesIndex)
107
+ expect(output.string).to include(
108
+ "############################################################\n" \
109
+ "WARN: You are risking to lose some changes during the reset.\n " \
110
+ "Please consider enabling journaling.\n " \
111
+ 'See https://github.com/toptal/chewy#journaling'
112
+ )
113
+ end
114
+ end
94
115
  end
95
116
 
96
117
  describe '.upgrade' do
@@ -100,13 +121,14 @@ Total: \\d+s\\Z
100
121
  .to update_index(CitiesIndex)
101
122
  expect(output.string).to match(Regexp.new(<<-OUTPUT, Regexp::MULTILINE))
102
123
  \\AResetting CitiesIndex
103
- Imported CitiesIndex::City in \\d+s, stats: index 3
104
- Imported Chewy::Stash::Specification::Specification in \\d+s, stats: index 1
124
+ Imported CitiesIndex in \\d+s, stats: index 3
125
+ Imported Chewy::Stash::Specification in \\d+s, stats: index 1
105
126
  Resetting CountriesIndex
106
- Imported CountriesIndex::Country in \\d+s, stats: index 2
107
- Imported Chewy::Stash::Specification::Specification in \\d+s, stats: index 1
127
+ Imported CountriesIndex in \\d+s, stats: index 2
128
+ Imported Chewy::Stash::Specification in \\d+s, stats: index 1
108
129
  Resetting UsersIndex
109
- Imported Chewy::Stash::Specification::Specification in \\d+s, stats: index 1
130
+ Imported UsersIndex in 1s, stats:\s
131
+ Imported Chewy::Stash::Specification in \\d+s, stats: index 1
110
132
  Total: \\d+s\\Z
111
133
  OUTPUT
112
134
  end
@@ -125,7 +147,8 @@ Total: \\d+s\\Z
125
147
  \\ASkipping CitiesIndex, the specification didn't change
126
148
  Skipping CountriesIndex, the specification didn't change
127
149
  Resetting UsersIndex
128
- Imported Chewy::Stash::Specification::Specification in \\d+s, stats: index 1
150
+ Imported UsersIndex in 1s, stats:\s
151
+ Imported Chewy::Stash::Specification in \\d+s, stats: index 1
129
152
  Total: \\d+s\\Z
130
153
  OUTPUT
131
154
  end
@@ -136,7 +159,8 @@ Total: \\d+s\\Z
136
159
  .not_to update_index(CitiesIndex)
137
160
  expect(output.string).to match(Regexp.new(<<-OUTPUT, Regexp::MULTILINE))
138
161
  \\AResetting UsersIndex
139
- Imported Chewy::Stash::Specification::Specification in \\d+s, stats: index 1
162
+ Imported UsersIndex in 1s, stats:\s
163
+ Imported Chewy::Stash::Specification in \\d+s, stats: index 1
140
164
  Total: \\d+s\\Z
141
165
  OUTPUT
142
166
  end
@@ -165,6 +189,7 @@ Total: \\d+s\\Z
165
189
  expect(output.string).to match(Regexp.new(<<-OUTPUT, Regexp::MULTILINE))
166
190
  \\ASkipping CitiesIndex, it does not exists \\(use rake chewy:reset\\[cities\\] to create and update it\\)
167
191
  Skipping CountriesIndex, it does not exists \\(use rake chewy:reset\\[countries\\] to create and update it\\)
192
+ Skipping UsersIndex, it does not exists \\(use rake chewy:reset\\[users\\] to create and update it\\)
168
193
  Total: \\d+s\\Z
169
194
  OUTPUT
170
195
  end
@@ -181,9 +206,10 @@ Total: \\d+s\\Z
181
206
  .to update_index(CitiesIndex)
182
207
  expect(output.string).to match(Regexp.new(<<-OUTPUT, Regexp::MULTILINE))
183
208
  \\AUpdating CitiesIndex
184
- Imported CitiesIndex::City in \\d+s, stats: index 3
209
+ Imported CitiesIndex in \\d+s, stats: index 3
185
210
  Updating CountriesIndex
186
- Imported CountriesIndex::Country in \\d+s, stats: index 2
211
+ Imported CountriesIndex in \\d+s, stats: index 2
212
+ Skipping UsersIndex, it does not exists \\(use rake chewy:reset\\[users\\] to create and update it\\)
187
213
  Total: \\d+s\\Z
188
214
  OUTPUT
189
215
  end
@@ -194,7 +220,7 @@ Total: \\d+s\\Z
194
220
  .not_to update_index(CitiesIndex)
195
221
  expect(output.string).to match(Regexp.new(<<-OUTPUT, Regexp::MULTILINE))
196
222
  \\AUpdating CountriesIndex
197
- Imported CountriesIndex::Country in \\d+s, stats: index 2
223
+ Imported CountriesIndex in \\d+s, stats: index 2
198
224
  Total: \\d+s\\Z
199
225
  OUTPUT
200
226
  end
@@ -205,7 +231,8 @@ Total: \\d+s\\Z
205
231
  .to update_index(CitiesIndex)
206
232
  expect(output.string).to match(Regexp.new(<<-OUTPUT, Regexp::MULTILINE))
207
233
  \\AUpdating CitiesIndex
208
- Imported CitiesIndex::City in \\d+s, stats: index 3
234
+ Imported CitiesIndex in \\d+s, stats: index 3
235
+ Skipping UsersIndex, it does not exists \\(use rake chewy:reset\\[users\\] to create and update it\\)
209
236
  Total: \\d+s\\Z
210
237
  OUTPUT
211
238
  end
@@ -218,15 +245,19 @@ Total: \\d+s\\Z
218
245
  expect { described_class.sync(output: output) }
219
246
  .to update_index(CitiesIndex)
220
247
  expect(output.string).to match(Regexp.new(<<-OUTPUT, Regexp::MULTILINE))
221
- \\ASynchronizing CitiesIndex::City
222
- Imported CitiesIndex::City in \\d+s, stats: index 3
248
+ \\ASynchronizing CitiesIndex
249
+ Imported CitiesIndex in \\d+s, stats: index 3
223
250
  Missing documents: \\[[^\\]]+\\]
224
251
  Took \\d+s
225
- Synchronizing CountriesIndex::Country
226
- CountriesIndex::Country doesn't support outdated synchronization
227
- Imported CountriesIndex::Country in \\d+s, stats: index 2
252
+ Synchronizing CountriesIndex
253
+ CountriesIndex doesn't support outdated synchronization
254
+ Imported CountriesIndex in \\d+s, stats: index 2
228
255
  Missing documents: \\[[^\\]]+\\]
229
256
  Took \\d+s
257
+ Synchronizing UsersIndex
258
+ UsersIndex doesn't support outdated synchronization
259
+ Skipping UsersIndex, up to date
260
+ Took \\d+s
230
261
  Total: \\d+s\\Z
231
262
  OUTPUT
232
263
  end
@@ -236,7 +267,6 @@ Total: \\d+s\\Z
236
267
  CitiesIndex.import(cities.first(2))
237
268
  CountriesIndex.import
238
269
 
239
- sleep(1) if ActiveSupport::VERSION::STRING < '4.1.0'
240
270
  cities.first.update(name: 'Name5')
241
271
  end
242
272
 
@@ -245,14 +275,18 @@ Total: \\d+s\\Z
245
275
  expect { described_class.sync(output: output) }
246
276
  .to update_index(CitiesIndex)
247
277
  expect(output.string).to match(Regexp.new(<<-OUTPUT, Regexp::MULTILINE))
248
- \\ASynchronizing CitiesIndex::City
249
- Imported CitiesIndex::City in \\d+s, stats: index 2
278
+ \\ASynchronizing CitiesIndex
279
+ Imported CitiesIndex in \\d+s, stats: index 2
250
280
  Missing documents: \\["#{cities.last.id}"\\]
251
281
  Outdated documents: \\["#{cities.first.id}"\\]
252
282
  Took \\d+s
253
- Synchronizing CountriesIndex::Country
254
- CountriesIndex::Country doesn't support outdated synchronization
255
- Skipping CountriesIndex::Country, up to date
283
+ Synchronizing CountriesIndex
284
+ CountriesIndex doesn't support outdated synchronization
285
+ Skipping CountriesIndex, up to date
286
+ Took \\d+s
287
+ Synchronizing UsersIndex
288
+ UsersIndex doesn't support outdated synchronization
289
+ Skipping UsersIndex, up to date
256
290
  Took \\d+s
257
291
  Total: \\d+s\\Z
258
292
  OUTPUT
@@ -263,8 +297,8 @@ Total: \\d+s\\Z
263
297
  expect { described_class.sync(only: CitiesIndex, output: output) }
264
298
  .to update_index(CitiesIndex)
265
299
  expect(output.string).to match(Regexp.new(<<-OUTPUT, Regexp::MULTILINE))
266
- \\ASynchronizing CitiesIndex::City
267
- Imported CitiesIndex::City in \\d+s, stats: index 2
300
+ \\ASynchronizing CitiesIndex
301
+ Imported CitiesIndex in \\d+s, stats: index 2
268
302
  Missing documents: \\["#{cities.last.id}"\\]
269
303
  Outdated documents: \\["#{cities.first.id}"\\]
270
304
  Took \\d+s
@@ -277,9 +311,13 @@ Total: \\d+s\\Z
277
311
  expect { described_class.sync(except: ['cities'], output: output) }
278
312
  .not_to update_index(CitiesIndex)
279
313
  expect(output.string).to match(Regexp.new(<<-OUTPUT, Regexp::MULTILINE))
280
- \\ASynchronizing CountriesIndex::Country
281
- CountriesIndex::Country doesn't support outdated synchronization
282
- Skipping CountriesIndex::Country, up to date
314
+ \\ASynchronizing CountriesIndex
315
+ CountriesIndex doesn't support outdated synchronization
316
+ Skipping CountriesIndex, up to date
317
+ Took \\d+s
318
+ Synchronizing UsersIndex
319
+ UsersIndex doesn't support outdated synchronization
320
+ Skipping UsersIndex, up to date
283
321
  Took \\d+s
284
322
  Total: \\d+s\\Z
285
323
  OUTPUT
@@ -308,9 +346,9 @@ Total: \\d+s\\Z
308
346
  .to update_index(CitiesIndex)
309
347
  expect(output.string).to match(Regexp.new(<<-OUTPUT, Regexp::MULTILINE))
310
348
  \\AApplying journal entries created after [+-:\\d\\s]+
311
- Applying journal to \\[CitiesIndex::City, CountriesIndex::Country\\], 3 entries, stage 1
312
- Imported CitiesIndex::City in \\d+s, stats: index 2
313
- Imported CountriesIndex::Country in \\d+s, stats: index 1
349
+ Applying journal to \\[CitiesIndex, CountriesIndex\\], 3 entries, stage 1
350
+ Imported CitiesIndex in \\d+s, stats: index 2
351
+ Imported CountriesIndex in \\d+s, stats: index 1
314
352
  Total: \\d+s\\Z
315
353
  OUTPUT
316
354
  end
@@ -321,8 +359,8 @@ Total: \\d+s\\Z
321
359
  .not_to update_index(CitiesIndex)
322
360
  expect(output.string).to match(Regexp.new(<<-OUTPUT, Regexp::MULTILINE))
323
361
  \\AApplying journal entries created after [+-:\\d\\s]+
324
- Applying journal to \\[CountriesIndex::Country\\], 1 entries, stage 1
325
- Imported CountriesIndex::Country in \\d+s, stats: index 1
362
+ Applying journal to \\[CountriesIndex\\], 1 entries, stage 1
363
+ Imported CountriesIndex in \\d+s, stats: index 1
326
364
  Total: \\d+s\\Z
327
365
  OUTPUT
328
366
  end
@@ -333,8 +371,8 @@ Total: \\d+s\\Z
333
371
  .to update_index(CitiesIndex)
334
372
  expect(output.string).to match(Regexp.new(<<-OUTPUT, Regexp::MULTILINE))
335
373
  \\AApplying journal entries created after [+-:\\d\\s]+
336
- Applying journal to \\[CitiesIndex::City\\], 2 entries, stage 1
337
- Imported CitiesIndex::City in \\d+s, stats: index 2
374
+ Applying journal to \\[CitiesIndex\\], 2 entries, stage 1
375
+ Imported CitiesIndex in \\d+s, stats: index 2
338
376
  Total: \\d+s\\Z
339
377
  OUTPUT
340
378
  end
@@ -345,8 +383,8 @@ Total: \\d+s\\Z
345
383
  .not_to update_index(CitiesIndex)
346
384
  expect(output.string).to match(Regexp.new(<<-OUTPUT, Regexp::MULTILINE))
347
385
  \\AApplying journal entries created after [+-:\\d\\s]+
348
- Applying journal to \\[CountriesIndex::Country\\], 1 entries, stage 1
349
- Imported CountriesIndex::Country in \\d+s, stats: index 1
386
+ Applying journal to \\[CountriesIndex\\], 1 entries, stage 1
387
+ Imported CountriesIndex in \\d+s, stats: index 1
350
388
  Total: \\d+s\\Z
351
389
  OUTPUT
352
390
  end
@@ -392,5 +430,227 @@ Total: \\d+s\\Z
392
430
  Total: \\d+s\\Z
393
431
  OUTPUT
394
432
  end
433
+
434
+ it 'executes asynchronously' do
435
+ output = StringIO.new
436
+ expect(Chewy.client).to receive(:delete_by_query).with(
437
+ {
438
+ body: {query: {match_all: {}}},
439
+ index: ['chewy_journal'],
440
+ refresh: false,
441
+ requests_per_second: 10.0,
442
+ scroll_size: 200,
443
+ wait_for_completion: false
444
+ }
445
+ ).and_call_original
446
+ described_class.journal_clean(
447
+ output: output,
448
+ delete_by_query_options: {
449
+ wait_for_completion: false,
450
+ requests_per_second: 10.0,
451
+ scroll_size: 200
452
+ }
453
+ )
454
+
455
+ expect(output.string).to match(Regexp.new(<<-OUTPUT, Regexp::MULTILINE))
456
+ \\ATask to cleanup the journal has been created, [^\\n]*
457
+ Total: \\d+s\\Z
458
+ OUTPUT
459
+ end
460
+
461
+ context 'execute "chewy:journal:clean" rake task' do
462
+ subject(:task) { Rake.application['chewy:journal:clean'] }
463
+ before do
464
+ Rake::DefaultLoader.new.load('lib/tasks/chewy.rake')
465
+ Rake::Task.define_task(:environment)
466
+ end
467
+ it 'does not raise error' do
468
+ expect { task.invoke }.to_not raise_error
469
+ end
470
+ end
471
+ end
472
+
473
+ describe '.create_missing_indexes!' do
474
+ before do
475
+ [CountriesIndex, Chewy::Stash::Specification].map(&:create!)
476
+
477
+ # To avoid flaky issues when previous specs were run
478
+ expect(Chewy::Index).to receive(:descendants).and_return(
479
+ [
480
+ UsersIndex,
481
+ CountriesIndex,
482
+ CitiesIndex,
483
+ Chewy::Stash::Specification,
484
+ Chewy::Stash::Journal
485
+ ]
486
+ )
487
+ end
488
+
489
+ specify do
490
+ output = StringIO.new
491
+ described_class.create_missing_indexes!(output: output)
492
+ expect(CitiesIndex.exists?).to be_truthy
493
+ expect(UsersIndex.exists?).to be_truthy
494
+ expect(Chewy::Stash::Journal.exists?).to be_falsey
495
+ expect(output.string).to match(Regexp.new(<<-OUTPUT, Regexp::MULTILINE))
496
+ UsersIndex index successfully created
497
+ CitiesIndex index successfully created
498
+ Total: \\d+s\\Z
499
+ OUTPUT
500
+ end
501
+
502
+ context 'when verbose' do
503
+ specify do
504
+ output = StringIO.new
505
+ described_class.create_missing_indexes!(output: output, env: {'VERBOSE' => '1'})
506
+ expect(output.string).to match(Regexp.new(<<-OUTPUT, Regexp::MULTILINE))
507
+ UsersIndex index successfully created
508
+ CountriesIndex already exists, skipping
509
+ CitiesIndex index successfully created
510
+ Chewy::Stash::Specification already exists, skipping
511
+ Total: \\d+s\\Z
512
+ OUTPUT
513
+ end
514
+ end
515
+
516
+ context 'when journaling is enabled' do
517
+ before { Chewy.config.settings[:journal] = true }
518
+ after { Chewy.config.settings.delete(:journal) }
519
+ specify do
520
+ described_class.create_missing_indexes!(output: StringIO.new)
521
+ expect(Chewy::Stash::Journal.exists?).to be_truthy
522
+ end
523
+ end
524
+ end
525
+
526
+ describe '.journal_create' do
527
+ specify do
528
+ output = StringIO.new
529
+ described_class.journal_create(output: output)
530
+ expect(Chewy::Stash::Journal.exists?).to be_truthy
531
+ expect(output.string).to match(Regexp.new(<<-OUTPUT, Regexp::MULTILINE))
532
+ Total: \\d+s\\Z
533
+ OUTPUT
534
+ end
535
+ end
536
+
537
+ describe '.reindex' do
538
+ before do
539
+ journal
540
+ CitiesIndex.create!
541
+ CountriesIndex.create!
542
+ end
543
+
544
+ let(:source_index) { 'cities' }
545
+ let(:dest_index) { 'countries' }
546
+
547
+ context 'with correct arguments' do
548
+ specify do
549
+ output = StringIO.new
550
+ described_class.reindex(source: source_index, dest: dest_index, output: output)
551
+ expect(output.string).to match(Regexp.new(<<-OUTPUT, Regexp::MULTILINE))
552
+ \\Source index is cities
553
+ \\Destination index is countries
554
+ cities index successfully reindexed with countries index data
555
+ Total: \\d+s\\Z
556
+ OUTPUT
557
+ end
558
+ end
559
+
560
+ context 'with missing indexes' do
561
+ context 'without dest index' do
562
+ specify do
563
+ output = StringIO.new
564
+ expect { described_class.reindex(source: source_index, output: output) }
565
+ .to raise_error ArgumentError
566
+ end
567
+ end
568
+
569
+ context 'without source index' do
570
+ specify do
571
+ output = StringIO.new
572
+ expect { described_class.reindex(dest: dest_index, output: output) }
573
+ .to raise_error ArgumentError
574
+ end
575
+ end
576
+ end
577
+ end
578
+
579
+ describe '.update_mapping' do
580
+ before do
581
+ journal
582
+ CitiesIndex.create!
583
+ end
584
+
585
+ let(:index_name) { CitiesIndex.index_name }
586
+ let(:nonexistent_index) { 'wrong_index' }
587
+
588
+ context 'with existing index' do
589
+ specify do
590
+ output = StringIO.new
591
+ described_class.update_mapping(name: index_name, output: output)
592
+ expect(output.string).to match(Regexp.new(<<-OUTPUT, Regexp::MULTILINE))
593
+ \\Index name is cities
594
+ cities index successfully updated
595
+ Total: \\d+s\\Z
596
+ OUTPUT
597
+ end
598
+ end
599
+
600
+ context 'with non-existent index name' do
601
+ specify do
602
+ output = StringIO.new
603
+ expect { described_class.update_mapping(name: nonexistent_index, output: output) }
604
+ .to raise_error NameError
605
+ end
606
+ end
607
+ end
608
+
609
+ describe '.delete_by_query_options_from_env' do
610
+ subject(:options) { described_class.delete_by_query_options_from_env(env) }
611
+ let(:env) do
612
+ {
613
+ 'WAIT_FOR_COMPLETION' => 'false',
614
+ 'REQUESTS_PER_SECOND' => '10',
615
+ 'SCROLL_SIZE' => '5000'
616
+ }
617
+ end
618
+
619
+ it 'parses the options' do
620
+ expect(options).to eq(
621
+ wait_for_completion: false,
622
+ requests_per_second: 10.0,
623
+ scroll_size: 5000
624
+ )
625
+ end
626
+
627
+ context 'with different boolean values' do
628
+ it 'parses the option correctly' do
629
+ %w[1 t true TRUE on ON].each do |v|
630
+ expect(described_class.delete_by_query_options_from_env({'WAIT_FOR_COMPLETION' => v}))
631
+ .to eq(wait_for_completion: true)
632
+ end
633
+
634
+ %w[0 f false FALSE off OFF].each do |v|
635
+ expect(described_class.delete_by_query_options_from_env({'WAIT_FOR_COMPLETION' => v}))
636
+ .to eq(wait_for_completion: false)
637
+ end
638
+ end
639
+ end
640
+
641
+ context 'with other env' do
642
+ let(:env) { {'SOME_ENV' => '123', 'REQUESTS_PER_SECOND' => '15'} }
643
+
644
+ it 'parses only the options' do
645
+ expect(options).to eq(requests_per_second: 15.0)
646
+ end
647
+ end
648
+ end
649
+
650
+ describe '.subscribed_task_stats' do
651
+ specify do
652
+ block_output = described_class.subscribed_task_stats(StringIO.new) { 'expected output' }
653
+ expect(block_output).to eq('expected output')
654
+ end
395
655
  end
396
656
  end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ describe :build_query do
4
+ before do
5
+ stub_model(:city)
6
+ stub_index(:cities) { index_scope City }
7
+ CitiesIndex.create
8
+ end
9
+
10
+ let(:expected_query) do
11
+ {
12
+ index: ['cities'],
13
+ body: {
14
+ query: {
15
+ match: {name: 'name'}
16
+ }
17
+ }
18
+ }
19
+ end
20
+ let(:dummy_query) { {match: {name: 'name'}} }
21
+ let(:unexpected_query) { {match: {name: 'name'}} }
22
+
23
+ context 'build expected query' do
24
+ specify do
25
+ expect(CitiesIndex.query(dummy_query)).to build_query(expected_query)
26
+ end
27
+ end
28
+
29
+ context 'not to build unexpected query' do
30
+ specify do
31
+ expect(CitiesIndex.query(dummy_query)).not_to build_query(unexpected_query)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe :rspec_helper do
4
+ include Chewy::Rspec::Helpers
5
+
6
+ before do
7
+ stub_model(:city)
8
+ stub_index(:cities) { index_scope City }
9
+ CitiesIndex.create
10
+ end
11
+
12
+ let(:hits) do
13
+ [
14
+ {
15
+ '_index' => 'cities',
16
+ '_type' => '_doc',
17
+ '_id' => '1',
18
+ '_score' => 3.14,
19
+ '_source' => source
20
+ }
21
+ ]
22
+ end
23
+
24
+ let(:source) { {'name' => 'some_name'} }
25
+ let(:sources) { [source] }
26
+
27
+ context :mock_elasticsearch_response do
28
+ let(:raw_response) do
29
+ {
30
+ 'took' => 4,
31
+ 'timed_out' => false,
32
+ '_shards' => {
33
+ 'total' => 1,
34
+ 'successful' => 1,
35
+ 'skipped' => 0,
36
+ 'failed' => 0
37
+ },
38
+ 'hits' => {
39
+ 'total' => {
40
+ 'value' => 1,
41
+ 'relation' => 'eq'
42
+ },
43
+ 'max_score' => 1.0,
44
+ 'hits' => hits
45
+ }
46
+ }
47
+ end
48
+
49
+ specify do
50
+ mock_elasticsearch_response(CitiesIndex, raw_response)
51
+ expect(CitiesIndex.query({}).hits).to eq(hits)
52
+ end
53
+ end
54
+
55
+ context :mock_elasticsearch_response_sources do
56
+ specify do
57
+ mock_elasticsearch_response_sources(CitiesIndex, sources)
58
+ expect(CitiesIndex.query({}).hits).to eq(hits)
59
+ end
60
+ end
61
+ end