canvas_sync 0.16.5 → 0.17.0.beta5
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/README.md +49 -137
- data/app/models/canvas_sync/sync_batch.rb +5 -0
- data/db/migrate/20201018210836_create_canvas_sync_sync_batches.rb +11 -0
- data/lib/canvas_sync.rb +35 -97
- data/lib/canvas_sync/importers/bulk_importer.rb +4 -7
- data/lib/canvas_sync/job.rb +4 -10
- data/lib/canvas_sync/job_batches/batch.rb +403 -0
- data/lib/canvas_sync/job_batches/batch_aware_job.rb +62 -0
- data/lib/canvas_sync/job_batches/callback.rb +152 -0
- data/lib/canvas_sync/job_batches/chain_builder.rb +220 -0
- data/lib/canvas_sync/job_batches/context_hash.rb +147 -0
- data/lib/canvas_sync/job_batches/jobs/base_job.rb +7 -0
- data/lib/canvas_sync/job_batches/jobs/concurrent_batch_job.rb +19 -0
- data/lib/canvas_sync/job_batches/jobs/serial_batch_job.rb +75 -0
- data/lib/canvas_sync/job_batches/sidekiq.rb +93 -0
- data/lib/canvas_sync/job_batches/status.rb +83 -0
- data/lib/canvas_sync/jobs/begin_sync_chain_job.rb +35 -0
- data/lib/canvas_sync/jobs/report_checker.rb +3 -6
- data/lib/canvas_sync/jobs/report_processor_job.rb +2 -5
- data/lib/canvas_sync/jobs/report_starter.rb +28 -20
- data/lib/canvas_sync/jobs/sync_accounts_job.rb +3 -5
- data/lib/canvas_sync/jobs/sync_admins_job.rb +2 -4
- data/lib/canvas_sync/jobs/sync_assignment_groups_job.rb +2 -4
- data/lib/canvas_sync/jobs/sync_assignments_job.rb +2 -4
- data/lib/canvas_sync/jobs/sync_context_module_items_job.rb +2 -4
- data/lib/canvas_sync/jobs/sync_context_modules_job.rb +2 -4
- data/lib/canvas_sync/jobs/sync_provisioning_report_job.rb +4 -34
- data/lib/canvas_sync/jobs/sync_roles_job.rb +2 -5
- data/lib/canvas_sync/jobs/sync_simple_table_job.rb +11 -32
- data/lib/canvas_sync/jobs/sync_submissions_job.rb +2 -4
- data/lib/canvas_sync/jobs/sync_terms_job.rb +25 -8
- data/lib/canvas_sync/processors/assignment_groups_processor.rb +2 -3
- data/lib/canvas_sync/processors/assignments_processor.rb +2 -3
- data/lib/canvas_sync/processors/context_module_items_processor.rb +2 -3
- data/lib/canvas_sync/processors/context_modules_processor.rb +2 -3
- data/lib/canvas_sync/processors/normal_processor.rb +1 -2
- data/lib/canvas_sync/processors/provisioning_report_processor.rb +2 -10
- data/lib/canvas_sync/processors/submissions_processor.rb +2 -3
- data/lib/canvas_sync/version.rb +1 -1
- data/spec/canvas_sync/canvas_sync_spec.rb +136 -153
- data/spec/canvas_sync/jobs/job_spec.rb +9 -17
- data/spec/canvas_sync/jobs/report_checker_spec.rb +1 -3
- data/spec/canvas_sync/jobs/report_processor_job_spec.rb +0 -3
- data/spec/canvas_sync/jobs/report_starter_spec.rb +19 -28
- data/spec/canvas_sync/jobs/sync_admins_job_spec.rb +1 -4
- data/spec/canvas_sync/jobs/sync_assignment_groups_job_spec.rb +2 -1
- data/spec/canvas_sync/jobs/sync_assignments_job_spec.rb +3 -2
- data/spec/canvas_sync/jobs/sync_context_module_items_job_spec.rb +3 -2
- data/spec/canvas_sync/jobs/sync_context_modules_job_spec.rb +3 -2
- data/spec/canvas_sync/jobs/sync_provisioning_report_job_spec.rb +3 -35
- data/spec/canvas_sync/jobs/sync_roles_job_spec.rb +1 -4
- data/spec/canvas_sync/jobs/sync_simple_table_job_spec.rb +5 -12
- data/spec/canvas_sync/jobs/sync_submissions_job_spec.rb +2 -1
- data/spec/canvas_sync/jobs/sync_terms_job_spec.rb +1 -4
- data/spec/dummy/config/environments/test.rb +2 -0
- data/spec/dummy/db/schema.rb +9 -1
- data/spec/job_batching/batch_aware_job_spec.rb +100 -0
- data/spec/job_batching/batch_spec.rb +372 -0
- data/spec/job_batching/callback_spec.rb +38 -0
- data/spec/job_batching/flow_spec.rb +88 -0
- data/spec/job_batching/integration/integration.rb +57 -0
- data/spec/job_batching/integration/nested.rb +88 -0
- data/spec/job_batching/integration/simple.rb +47 -0
- data/spec/job_batching/integration/workflow.rb +134 -0
- data/spec/job_batching/integration_helper.rb +48 -0
- data/spec/job_batching/sidekiq_spec.rb +124 -0
- data/spec/job_batching/status_spec.rb +92 -0
- data/spec/job_batching/support/base_job.rb +14 -0
- data/spec/job_batching/support/sample_callback.rb +2 -0
- data/spec/spec_helper.rb +17 -0
- metadata +85 -8
- data/lib/canvas_sync/job_chain.rb +0 -102
- data/lib/canvas_sync/jobs/fork_gather.rb +0 -74
- data/spec/canvas_sync/jobs/fork_gather_spec.rb +0 -73
@@ -0,0 +1,372 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class TestWorker < BatchTestJobBase
|
4
|
+
def perform
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
RSpec.describe CanvasSync::JobBatches::Batch do
|
9
|
+
describe '#initialize' do
|
10
|
+
subject { described_class }
|
11
|
+
|
12
|
+
it 'creates bid when called without it' do
|
13
|
+
expect(subject.new.bid).not_to be_nil
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'reuses bid when called with it' do
|
17
|
+
batch = subject.new('dayPO5KxuRXXxw')
|
18
|
+
expect(batch.bid).to eq('dayPO5KxuRXXxw')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#description' do
|
23
|
+
let(:description) { 'custom description' }
|
24
|
+
before do
|
25
|
+
subject.description = description
|
26
|
+
subject.jobs { }
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'sets descriptions' do
|
30
|
+
expect(subject.description).to eq(description)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'persists description' do
|
34
|
+
expect(CanvasSync::JobBatches::Batch.redis { |r| r.hget("BID-#{subject.bid}", 'description') })
|
35
|
+
.to eq(description)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#callback_queue' do
|
40
|
+
let(:callback_queue) { 'custom_queue' }
|
41
|
+
before do
|
42
|
+
subject.callback_queue = callback_queue
|
43
|
+
subject.jobs { }
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'sets callback_queue' do
|
47
|
+
expect(subject.callback_queue).to eq(callback_queue)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'persists callback_queue' do
|
51
|
+
expect(CanvasSync::JobBatches::Batch.redis { |r| r.hget("BID-#{subject.bid}", 'callback_queue') })
|
52
|
+
.to eq(callback_queue)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#jobs' do
|
57
|
+
it 'throws error if no block given' do
|
58
|
+
expect { subject.jobs }.to raise_error CanvasSync::JobBatches::Batch::NoBlockGivenError
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'increments to_process (when started)'
|
62
|
+
|
63
|
+
it 'decrements to_process (when finished)'
|
64
|
+
# it 'calls process_successful_job to wait for block to finish' do
|
65
|
+
# batch = CanvasSync::JobBatches::Batch.new
|
66
|
+
# expect(CanvasSync::JobBatches::Batch).to receive(:process_successful_job).with(batch.bid)
|
67
|
+
# batch.jobs {}
|
68
|
+
# end
|
69
|
+
|
70
|
+
it 'sets Thread.current bid' do
|
71
|
+
batch = CanvasSync::JobBatches::Batch.new
|
72
|
+
batch.jobs do
|
73
|
+
expect(Thread.current[:batch]).to eq(batch)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe '#invalidate_all' do
|
79
|
+
class InvalidatableJob < BatchTestJobBase
|
80
|
+
def perform
|
81
|
+
return unless valid_within_batch?
|
82
|
+
was_performed
|
83
|
+
end
|
84
|
+
|
85
|
+
def was_performed; end
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'marks batch in redis as invalidated' do
|
89
|
+
batch = CanvasSync::JobBatches::Batch.new
|
90
|
+
job = InvalidatableJob.new
|
91
|
+
allow(job).to receive(:was_performed)
|
92
|
+
|
93
|
+
batch.invalidate_all
|
94
|
+
batch.jobs { job.perform }
|
95
|
+
|
96
|
+
expect(job).not_to have_received(:was_performed)
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'nested batches' do
|
100
|
+
let(:batch_parent) { CanvasSync::JobBatches::Batch.new }
|
101
|
+
let(:batch_child_1) { CanvasSync::JobBatches::Batch.new }
|
102
|
+
let(:batch_child_2) { CanvasSync::JobBatches::Batch.new }
|
103
|
+
let(:job_of_parent) { InvalidatableJob.new }
|
104
|
+
let(:job_of_child_1) { InvalidatableJob.new }
|
105
|
+
let(:job_of_child_2) { InvalidatableJob.new }
|
106
|
+
|
107
|
+
before do
|
108
|
+
allow(job_of_parent).to receive(:was_performed)
|
109
|
+
allow(job_of_child_1).to receive(:was_performed)
|
110
|
+
allow(job_of_child_2).to receive(:was_performed)
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'invalidates all job if parent batch is marked as invalidated' do
|
114
|
+
batch_parent.invalidate_all
|
115
|
+
batch_parent.jobs do
|
116
|
+
[
|
117
|
+
job_of_parent.perform,
|
118
|
+
batch_child_1.jobs do
|
119
|
+
[
|
120
|
+
job_of_child_1.perform,
|
121
|
+
batch_child_2.jobs { job_of_child_2.perform }
|
122
|
+
]
|
123
|
+
end
|
124
|
+
]
|
125
|
+
end
|
126
|
+
|
127
|
+
expect(job_of_parent).not_to have_received(:was_performed)
|
128
|
+
expect(job_of_child_1).not_to have_received(:was_performed)
|
129
|
+
expect(job_of_child_2).not_to have_received(:was_performed)
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'invalidates only requested batch' do
|
133
|
+
batch_child_2.invalidate_all
|
134
|
+
batch_parent.jobs do
|
135
|
+
[
|
136
|
+
job_of_parent.perform,
|
137
|
+
batch_child_1.jobs do
|
138
|
+
[
|
139
|
+
job_of_child_1.perform,
|
140
|
+
batch_child_2.jobs { job_of_child_2.perform }
|
141
|
+
]
|
142
|
+
end
|
143
|
+
]
|
144
|
+
end
|
145
|
+
|
146
|
+
expect(job_of_parent).to have_received(:was_performed)
|
147
|
+
expect(job_of_child_1).to have_received(:was_performed)
|
148
|
+
expect(job_of_child_2).not_to have_received(:was_performed)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
describe '#process_failed_job' do
|
154
|
+
let(:batch) { CanvasSync::JobBatches::Batch.new }
|
155
|
+
let(:bid) { batch.bid }
|
156
|
+
let(:jid) { 'ABCD' }
|
157
|
+
before { CanvasSync::JobBatches::Batch.redis { |r| r.hset("BID-#{bid}", 'pending', 1) } }
|
158
|
+
|
159
|
+
context 'complete' do
|
160
|
+
let(:failed_jid) { 'xxx' }
|
161
|
+
|
162
|
+
it 'tries to call complete callback' do
|
163
|
+
expect(CanvasSync::JobBatches::Batch).to receive(:enqueue_callbacks).with(:complete, bid)
|
164
|
+
CanvasSync::JobBatches::Batch.process_failed_job(bid, failed_jid)
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'add job to failed list' do
|
168
|
+
CanvasSync::JobBatches::Batch.process_failed_job(bid, 'failed-job-id')
|
169
|
+
CanvasSync::JobBatches::Batch.process_failed_job(bid, failed_jid)
|
170
|
+
failed = CanvasSync::JobBatches::Batch.redis { |r| r.smembers("BID-#{bid}-failed") }
|
171
|
+
expect(failed).to eq(['xxx', 'failed-job-id'])
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
describe '#process_successful_job' do
|
177
|
+
let(:batch) { CanvasSync::JobBatches::Batch.new }
|
178
|
+
let(:bid) { batch.bid }
|
179
|
+
let(:jid) { 'ABCD' }
|
180
|
+
before { CanvasSync::JobBatches::Batch.redis { |r| r.hset("BID-#{bid}", 'pending', 1) } }
|
181
|
+
|
182
|
+
context 'complete' do
|
183
|
+
before { batch.on(:complete, Object) }
|
184
|
+
# before { batch.increment_job_queue(bid) }
|
185
|
+
# before { batch.jobs do TestWorker.perform_async end }
|
186
|
+
# before { CanvasSync::JobBatches::Batch.process_failed_job(bid, 'failed-job-id') }
|
187
|
+
|
188
|
+
it 'tries to call complete callback' do
|
189
|
+
expect(CanvasSync::JobBatches::Batch).to receive(:enqueue_callbacks).with(:complete, bid)
|
190
|
+
CanvasSync::JobBatches::Batch.process_failed_job(bid, 'failed-job-id')
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
context 'success' do
|
195
|
+
before { batch.on(:complete, Object) }
|
196
|
+
it 'tries to call complete callback' do
|
197
|
+
expect(CanvasSync::JobBatches::Batch).to receive(:enqueue_callbacks).with(:complete, bid).ordered
|
198
|
+
expect(CanvasSync::JobBatches::Batch).to receive(:enqueue_callbacks).with(:success, bid).ordered
|
199
|
+
CanvasSync::JobBatches::Batch.process_successful_job(bid, jid)
|
200
|
+
end
|
201
|
+
|
202
|
+
it 'tries to call success callback after a previous failure' do
|
203
|
+
expect(CanvasSync::JobBatches::Batch).to receive(:enqueue_callbacks).with(:complete, bid).ordered
|
204
|
+
CanvasSync::JobBatches::Batch.process_failed_job(bid, jid)
|
205
|
+
|
206
|
+
expect(CanvasSync::JobBatches::Batch).to receive(:enqueue_callbacks).with(:complete, bid).ordered
|
207
|
+
expect(CanvasSync::JobBatches::Batch).to receive(:enqueue_callbacks).with(:success, bid).ordered
|
208
|
+
CanvasSync::JobBatches::Batch.process_successful_job(bid, jid)
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'cleanups redis key' do
|
212
|
+
CanvasSync::JobBatches::Batch.process_successful_job(bid, jid)
|
213
|
+
expect(CanvasSync::JobBatches::Batch.redis { |r| r.get("BID-#{bid}-pending") }.to_i).to eq(0)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
describe '#increment_job_queue' do
|
219
|
+
let(:bid) { 'BID' }
|
220
|
+
let(:batch) { CanvasSync::JobBatches::Batch.new }
|
221
|
+
|
222
|
+
it 'increments pending' do
|
223
|
+
batch.jobs do TestWorker.perform_async end
|
224
|
+
pending = CanvasSync::JobBatches::Batch.redis { |r| r.hget("BID-#{batch.bid}", 'pending') }
|
225
|
+
expect(pending).to eq('1')
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'increments total' do
|
229
|
+
batch.jobs do TestWorker.perform_async end
|
230
|
+
total = CanvasSync::JobBatches::Batch.redis { |r| r.hget("BID-#{batch.bid}", 'total') }
|
231
|
+
expect(total).to eq('1')
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
describe '#enqueue_callbacks' do
|
236
|
+
let(:callback) { double('callback') }
|
237
|
+
let(:event) { :complete }
|
238
|
+
|
239
|
+
context 'on :success' do
|
240
|
+
let(:event) { :success }
|
241
|
+
context 'when no callbacks are defined' do
|
242
|
+
it 'clears redis keys' do
|
243
|
+
batch = CanvasSync::JobBatches::Batch.new
|
244
|
+
expect(CanvasSync::JobBatches::Batch).to receive(:cleanup_redis).with(batch.bid)
|
245
|
+
CanvasSync::JobBatches::Batch.enqueue_callbacks(event, batch.bid)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
context 'when already called' do
|
251
|
+
it 'returns and does not enqueue callbacks' do
|
252
|
+
batch = CanvasSync::JobBatches::Batch.new
|
253
|
+
batch.on(event, SampleCallback)
|
254
|
+
CanvasSync::JobBatches::Batch.redis { |r| r.hset("BID-#{batch.bid}", event, true) }
|
255
|
+
|
256
|
+
expect(batch).not_to receive(:push_callbacks)
|
257
|
+
CanvasSync::JobBatches::Batch.enqueue_callbacks(event, batch.bid)
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
context 'With ActiveJob Adapter' do
|
262
|
+
around(:all) do |block|
|
263
|
+
CanvasSync::JobBatches::Batch::Callback.send(:remove_const, :Worker)
|
264
|
+
CanvasSync::JobBatches::Batch::Callback.const_set(:Worker, CanvasSync::JobBatches::Batch::Callback::ActiveJobCallbackWorker)
|
265
|
+
block.run
|
266
|
+
end
|
267
|
+
|
268
|
+
context 'when not yet called' do
|
269
|
+
context 'when there is no callback' do
|
270
|
+
it 'it returns' do
|
271
|
+
batch = CanvasSync::JobBatches::Batch.new
|
272
|
+
|
273
|
+
expect(batch).not_to receive(:push_callbacks)
|
274
|
+
CanvasSync::JobBatches::Batch.enqueue_callbacks(event, batch.bid)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
context 'when callback defined' do
|
279
|
+
let(:opts) { { 'a' => 'b' } }
|
280
|
+
|
281
|
+
it 'calls it passing options' do
|
282
|
+
batch = CanvasSync::JobBatches::Batch.new
|
283
|
+
batch.on(event, SampleCallback, opts)
|
284
|
+
|
285
|
+
CanvasSync::JobBatches::Batch.enqueue_callbacks(event, batch.bid)
|
286
|
+
|
287
|
+
expect(CanvasSync::JobBatches::Batch::Callback::Worker).to have_been_enqueued.with(
|
288
|
+
'SampleCallback', event.to_s, opts, batch.bid, nil
|
289
|
+
)
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
context 'when multiple callbacks are defined' do
|
294
|
+
let(:opts) { { 'a' => 'b' } }
|
295
|
+
let(:opts2) { { 'b' => 'a' } }
|
296
|
+
|
297
|
+
it 'enqueues each callback passing their options' do
|
298
|
+
batch = CanvasSync::JobBatches::Batch.new
|
299
|
+
batch.on(event, SampleCallback, opts)
|
300
|
+
batch.on(event, SampleCallback2, opts2)
|
301
|
+
|
302
|
+
CanvasSync::JobBatches::Batch.enqueue_callbacks(event, batch.bid)
|
303
|
+
expect(CanvasSync::JobBatches::Batch::Callback::Worker).to have_been_enqueued.with(
|
304
|
+
'SampleCallback2', event.to_s, opts2, batch.bid, nil
|
305
|
+
)
|
306
|
+
expect(CanvasSync::JobBatches::Batch::Callback::Worker).to have_been_enqueued.with(
|
307
|
+
'SampleCallback', event.to_s, opts, batch.bid, nil
|
308
|
+
)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
context 'With Sidekiq Adapter' do
|
315
|
+
around(:all) do |block|
|
316
|
+
CanvasSync::JobBatches::Batch::Callback.send(:remove_const, :Worker)
|
317
|
+
CanvasSync::JobBatches::Batch::Callback.const_set(:Worker, CanvasSync::JobBatches::Batch::Callback::SidekiqCallbackWorker)
|
318
|
+
block.run
|
319
|
+
end
|
320
|
+
|
321
|
+
context 'when not yet called' do
|
322
|
+
context 'when there is no callback' do
|
323
|
+
it 'it returns' do
|
324
|
+
batch = CanvasSync::JobBatches::Batch.new
|
325
|
+
|
326
|
+
expect(batch).not_to receive(:push_callbacks)
|
327
|
+
CanvasSync::JobBatches::Batch.enqueue_callbacks(event, batch.bid)
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
context 'when callback defined' do
|
332
|
+
let(:opts) { { 'a' => 'b' } }
|
333
|
+
|
334
|
+
it 'calls it passing options' do
|
335
|
+
batch = CanvasSync::JobBatches::Batch.new
|
336
|
+
batch.on(event, SampleCallback, opts)
|
337
|
+
|
338
|
+
expect(Sidekiq::Client).to receive(:push_bulk).with(
|
339
|
+
'class' => Sidekiq::Batch::Callback::Worker,
|
340
|
+
'args' => [['SampleCallback', event.to_s, opts, batch.bid, nil]],
|
341
|
+
'queue' => 'default'
|
342
|
+
)
|
343
|
+
|
344
|
+
CanvasSync::JobBatches::Batch.enqueue_callbacks(event, batch.bid)
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
context 'when multiple callbacks are defined' do
|
349
|
+
let(:opts) { { 'a' => 'b' } }
|
350
|
+
let(:opts2) { { 'b' => 'a' } }
|
351
|
+
|
352
|
+
it 'enqueues each callback passing their options' do
|
353
|
+
batch = CanvasSync::JobBatches::Batch.new
|
354
|
+
batch.on(event, SampleCallback, opts)
|
355
|
+
batch.on(event, SampleCallback2, opts2)
|
356
|
+
|
357
|
+
expect(Sidekiq::Client).to receive(:push_bulk).with(
|
358
|
+
'class' => Sidekiq::Batch::Callback::Worker,
|
359
|
+
'args' => [
|
360
|
+
['SampleCallback2', event.to_s, opts2, batch.bid, nil],
|
361
|
+
['SampleCallback', event.to_s, opts, batch.bid, nil]
|
362
|
+
],
|
363
|
+
'queue' => 'default'
|
364
|
+
)
|
365
|
+
|
366
|
+
CanvasSync::JobBatches::Batch.enqueue_callbacks(event, batch.bid)
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe CanvasSync::JobBatches::Batch::Callback::Worker do
|
4
|
+
describe '#perform' do
|
5
|
+
it 'does not do anything if it cannot find the callback class' do
|
6
|
+
subject.perform('SampleCallback', 'complete', {}, 'ABCD', 'EFGH')
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'does not do anything if event is different from complete or success' do
|
10
|
+
expect(SampleCallback).not_to receive(:new)
|
11
|
+
subject.perform('SampleCallback', 'ups', {}, 'ABCD', 'EFGH')
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'calls on_success if defined' do
|
15
|
+
callback_instance = double('SampleCallback', on_success: true)
|
16
|
+
expect(SampleCallback).to receive(:new).and_return(callback_instance)
|
17
|
+
expect(callback_instance).to receive(:on_success)
|
18
|
+
.with(instance_of(CanvasSync::JobBatches::Batch::Status), {})
|
19
|
+
subject.perform('SampleCallback', 'success', {}, 'ABCD', 'EFGH')
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'calls on_complete if defined' do
|
23
|
+
callback_instance = double('SampleCallback')
|
24
|
+
expect(SampleCallback).to receive(:new).and_return(callback_instance)
|
25
|
+
expect(callback_instance).to receive(:on_complete)
|
26
|
+
.with(instance_of(CanvasSync::JobBatches::Batch::Status), {})
|
27
|
+
subject.perform('SampleCallback', 'complete', {}, 'ABCD', 'EFGH')
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'calls specific callback if defined' do
|
31
|
+
callback_instance = double('SampleCallback')
|
32
|
+
expect(SampleCallback).to receive(:new).and_return(callback_instance)
|
33
|
+
expect(callback_instance).to receive(:sample_method)
|
34
|
+
.with(instance_of(CanvasSync::JobBatches::Batch::Status), {})
|
35
|
+
subject.perform('SampleCallback#sample_method', 'complete', {}, 'ABCD', 'EFGH')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class WorkerA < BatchTestJobBase
|
4
|
+
def perform
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
class WorkerB < BatchTestJobBase
|
9
|
+
def perform
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class WorkerC < BatchTestJobBase
|
14
|
+
def perform
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
RSpec.describe 'Batch flow' do
|
19
|
+
context 'when handling a batch' do
|
20
|
+
let(:batch) { CanvasSync::JobBatches::Batch.new }
|
21
|
+
before { batch.on(:complete, SampleCallback, :id => 42) }
|
22
|
+
before { batch.description = 'describing the batch' }
|
23
|
+
let(:status) { CanvasSync::JobBatches::Batch::Status.new(batch.bid) }
|
24
|
+
let(:jids) { batch.jobs do 3.times do TestWorker.perform_async end end }
|
25
|
+
let(:queue) { Sidekiq::Queue.new }
|
26
|
+
|
27
|
+
it 'correctly initializes' do
|
28
|
+
expect(jids.size).to eq(3)
|
29
|
+
|
30
|
+
expect(batch.bid).not_to be_nil
|
31
|
+
expect(batch.description).to eq('describing the batch')
|
32
|
+
|
33
|
+
batch.jobs {}
|
34
|
+
|
35
|
+
expect(status.total).to eq(3)
|
36
|
+
expect(status.pending).to eq(3)
|
37
|
+
expect(status.failures).to eq(0)
|
38
|
+
expect(status.complete?).to be false
|
39
|
+
expect(status.created_at).not_to be_nil
|
40
|
+
expect(status.bid).to eq(batch.bid)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'handles an empty batch' do
|
44
|
+
batch = CanvasSync::JobBatches::Batch.new
|
45
|
+
jids = batch.jobs do nil end
|
46
|
+
expect(jids.size).to eq(0)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'when handling a nested batch' do
|
51
|
+
let(:batchA) { CanvasSync::JobBatches::Batch.new }
|
52
|
+
let(:batchB) { CanvasSync::JobBatches::Batch.new }
|
53
|
+
let(:batchC) { CanvasSync::JobBatches::Batch.new(batchA.bid) }
|
54
|
+
let(:batchD) { CanvasSync::JobBatches::Batch.new }
|
55
|
+
let(:jids) { [] }
|
56
|
+
let(:parent) { batchA.bid }
|
57
|
+
let(:children) { [] }
|
58
|
+
|
59
|
+
it 'handles a basic nested batch' do
|
60
|
+
batchA.jobs do
|
61
|
+
jids << WorkerA.perform_async
|
62
|
+
batchB.jobs do
|
63
|
+
jids << WorkerB.perform_async
|
64
|
+
end
|
65
|
+
jids << WorkerA.perform_async
|
66
|
+
children << batchB.bid
|
67
|
+
end
|
68
|
+
|
69
|
+
batchC.jobs do
|
70
|
+
batchD.jobs do
|
71
|
+
jids << WorkerC.perform_async
|
72
|
+
end
|
73
|
+
children << batchD.bid
|
74
|
+
end
|
75
|
+
|
76
|
+
expect(jids.size).to eq(4)
|
77
|
+
expect(CanvasSync::JobBatches::Batch::Status.new(parent).child_count).to eq(2)
|
78
|
+
children.each do |kid|
|
79
|
+
status = CanvasSync::JobBatches::Batch::Status.new(kid)
|
80
|
+
expect(status.child_count).to eq(0)
|
81
|
+
expect(status.pending).to eq(1)
|
82
|
+
expect(status.parent_bid).to eq(parent)
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|