canvas_sync 0.16.2 → 0.17.0.beta3

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 (77) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +49 -137
  3. data/app/models/canvas_sync/sync_batch.rb +5 -0
  4. data/db/migrate/20170915210836_create_canvas_sync_job_log.rb +12 -31
  5. data/db/migrate/20180725155729_add_job_id_to_canvas_sync_job_logs.rb +4 -13
  6. data/db/migrate/20190916154829_add_fork_count_to_canvas_sync_job_logs.rb +3 -11
  7. data/db/migrate/20201018210836_create_canvas_sync_sync_batches.rb +11 -0
  8. data/lib/canvas_sync.rb +36 -118
  9. data/lib/canvas_sync/concerns/api_syncable.rb +27 -0
  10. data/lib/canvas_sync/job.rb +5 -5
  11. data/lib/canvas_sync/job_batches/batch.rb +399 -0
  12. data/lib/canvas_sync/job_batches/batch_aware_job.rb +62 -0
  13. data/lib/canvas_sync/job_batches/callback.rb +153 -0
  14. data/lib/canvas_sync/job_batches/chain_builder.rb +210 -0
  15. data/lib/canvas_sync/job_batches/context_hash.rb +147 -0
  16. data/lib/canvas_sync/job_batches/jobs/base_job.rb +7 -0
  17. data/lib/canvas_sync/job_batches/jobs/concurrent_batch_job.rb +18 -0
  18. data/lib/canvas_sync/job_batches/jobs/serial_batch_job.rb +73 -0
  19. data/lib/canvas_sync/job_batches/sidekiq.rb +93 -0
  20. data/lib/canvas_sync/job_batches/status.rb +63 -0
  21. data/lib/canvas_sync/jobs/begin_sync_chain_job.rb +34 -0
  22. data/lib/canvas_sync/jobs/report_checker.rb +3 -6
  23. data/lib/canvas_sync/jobs/report_processor_job.rb +2 -5
  24. data/lib/canvas_sync/jobs/report_starter.rb +27 -19
  25. data/lib/canvas_sync/jobs/sync_accounts_job.rb +3 -5
  26. data/lib/canvas_sync/jobs/sync_admins_job.rb +2 -4
  27. data/lib/canvas_sync/jobs/sync_assignment_groups_job.rb +2 -4
  28. data/lib/canvas_sync/jobs/sync_assignments_job.rb +2 -4
  29. data/lib/canvas_sync/jobs/sync_context_module_items_job.rb +2 -4
  30. data/lib/canvas_sync/jobs/sync_context_modules_job.rb +2 -4
  31. data/lib/canvas_sync/jobs/sync_provisioning_report_job.rb +5 -35
  32. data/lib/canvas_sync/jobs/sync_roles_job.rb +2 -5
  33. data/lib/canvas_sync/jobs/sync_simple_table_job.rb +11 -32
  34. data/lib/canvas_sync/jobs/sync_submissions_job.rb +2 -4
  35. data/lib/canvas_sync/jobs/sync_terms_job.rb +25 -8
  36. data/lib/canvas_sync/misc_helper.rb +15 -0
  37. data/lib/canvas_sync/version.rb +1 -1
  38. data/spec/canvas_sync/canvas_sync_spec.rb +136 -153
  39. data/spec/canvas_sync/jobs/job_spec.rb +9 -17
  40. data/spec/canvas_sync/jobs/report_checker_spec.rb +1 -3
  41. data/spec/canvas_sync/jobs/report_processor_job_spec.rb +0 -3
  42. data/spec/canvas_sync/jobs/report_starter_spec.rb +19 -28
  43. data/spec/canvas_sync/jobs/sync_admins_job_spec.rb +1 -4
  44. data/spec/canvas_sync/jobs/sync_assignment_groups_job_spec.rb +2 -1
  45. data/spec/canvas_sync/jobs/sync_assignments_job_spec.rb +3 -2
  46. data/spec/canvas_sync/jobs/sync_context_module_items_job_spec.rb +3 -2
  47. data/spec/canvas_sync/jobs/sync_context_modules_job_spec.rb +3 -2
  48. data/spec/canvas_sync/jobs/sync_provisioning_report_job_spec.rb +3 -35
  49. data/spec/canvas_sync/jobs/sync_roles_job_spec.rb +1 -4
  50. data/spec/canvas_sync/jobs/sync_simple_table_job_spec.rb +5 -12
  51. data/spec/canvas_sync/jobs/sync_submissions_job_spec.rb +2 -1
  52. data/spec/canvas_sync/jobs/sync_terms_job_spec.rb +1 -4
  53. data/spec/dummy/app/models/account.rb +3 -0
  54. data/spec/dummy/app/models/pseudonym.rb +14 -0
  55. data/spec/dummy/app/models/submission.rb +1 -0
  56. data/spec/dummy/app/models/user.rb +1 -0
  57. data/spec/dummy/config/environments/test.rb +2 -0
  58. data/spec/dummy/db/migrate/20201016181346_create_pseudonyms.rb +24 -0
  59. data/spec/dummy/db/schema.rb +24 -4
  60. data/spec/job_batching/batch_aware_job_spec.rb +100 -0
  61. data/spec/job_batching/batch_spec.rb +363 -0
  62. data/spec/job_batching/callback_spec.rb +38 -0
  63. data/spec/job_batching/flow_spec.rb +91 -0
  64. data/spec/job_batching/integration/integration.rb +57 -0
  65. data/spec/job_batching/integration/nested.rb +88 -0
  66. data/spec/job_batching/integration/simple.rb +47 -0
  67. data/spec/job_batching/integration/workflow.rb +134 -0
  68. data/spec/job_batching/integration_helper.rb +48 -0
  69. data/spec/job_batching/sidekiq_spec.rb +124 -0
  70. data/spec/job_batching/status_spec.rb +92 -0
  71. data/spec/job_batching/support/base_job.rb +14 -0
  72. data/spec/job_batching/support/sample_callback.rb +2 -0
  73. data/spec/spec_helper.rb +17 -0
  74. metadata +90 -8
  75. data/lib/canvas_sync/job_chain.rb +0 -57
  76. data/lib/canvas_sync/jobs/fork_gather.rb +0 -59
  77. data/spec/canvas_sync/jobs/fork_gather_spec.rb +0 -73
@@ -0,0 +1,14 @@
1
+ # #
2
+ # AUTO GENERATED MODEL
3
+ # This model was auto generated by the CanvasSync Gem.
4
+ # You can customize it as needed, but make sure you test
5
+ # any changes you make to the auto generated methods.
6
+ #
7
+
8
+
9
+ class Pseudonym < ApplicationRecord
10
+ include CanvasSync::Record
11
+
12
+ validates :canvas_id, uniqueness: true, presence: true
13
+ belongs_to :user, primary_key: :canvas_id, foreign_key: :canvas_user_id
14
+ end
@@ -20,6 +20,7 @@ class Submission < ApplicationRecord
20
20
  canvas_user_id: :user_id,
21
21
  submitted_at: :submitted_at,
22
22
  graded_at: :graded_at,
23
+ cached_due_date: :due_at,
23
24
  score: :score,
24
25
  excused: :excused,
25
26
  workflow_state: :workflow_state,
@@ -11,6 +11,7 @@ class User < ApplicationRecord
11
11
  include CanvasSync::Concerns::ApiSyncable
12
12
 
13
13
  validates :canvas_id, uniqueness: true, presence: true
14
+ has_many :pseudonyms, primary_key: :canvas_id, foreign_key: :canvas_user_id
14
15
  has_many :enrollments, primary_key: :canvas_id, foreign_key: :canvas_user_id
15
16
  has_many :admins, primary_key: :canvas_id, foreign_key: :canvas_user_id
16
17
  has_many :admin_roles, through: :admins, source: :role
@@ -37,6 +37,8 @@ Rails.application.configure do
37
37
  # Print deprecation notices to the stderr.
38
38
  config.active_support.deprecation = :stderr
39
39
 
40
+ config.active_job.queue_adapter = :test
41
+
40
42
  # Raises error for missing translations
41
43
  # config.action_view.raise_on_missing_translations = true
42
44
  end
@@ -0,0 +1,24 @@
1
+ # #
2
+ # AUTO GENERATED MIGRATION
3
+ # This migration was auto generated by the CanvasSync Gem.
4
+ # You can add new columns to this table, but removing or
5
+ # re-naming ones created here may break Canvas Syncing.
6
+ #
7
+
8
+
9
+ class CreatePseudonyms < ActiveRecord::Migration[5.1]
10
+ def change
11
+ create_table :pseudonyms do |t|
12
+ t.bigint :canvas_id, null: false
13
+ t.bigint :canvas_user_id
14
+ t.string :sis_id
15
+ t.string :unique_id
16
+ t.string :workflow_state
17
+
18
+ t.timestamps
19
+ end
20
+
21
+ add_index :pseudonyms, :canvas_id, unique: true
22
+ add_index :pseudonyms, :canvas_user_id
23
+ end
24
+ end
@@ -10,7 +10,7 @@
10
10
  #
11
11
  # It's strongly recommended that you check this file into your version control system.
12
12
 
13
- ActiveRecord::Schema.define(version: 2020_04_16_214248) do
13
+ ActiveRecord::Schema.define(version: 2020_10_18_210836) do
14
14
 
15
15
  # These are extensions that must be enabled in order to support this database
16
16
  enable_extension "plpgsql"
@@ -83,7 +83,7 @@ ActiveRecord::Schema.define(version: 2020_04_16_214248) do
83
83
  t.index ["canvas_id"], name: "index_assignments_on_canvas_id", unique: true
84
84
  end
85
85
 
86
- create_table "canvas_sync_job_logs", force: :cascade do |t|
86
+ create_table "canvas_sync_job_logs", id: :serial, force: :cascade do |t|
87
87
  t.datetime "started_at"
88
88
  t.datetime "completed_at"
89
89
  t.string "exception"
@@ -92,13 +92,21 @@ ActiveRecord::Schema.define(version: 2020_04_16_214248) do
92
92
  t.string "status"
93
93
  t.text "metadata"
94
94
  t.text "job_arguments"
95
- t.datetime "created_at", null: false
96
- t.datetime "updated_at", null: false
95
+ t.datetime "created_at"
96
+ t.datetime "updated_at"
97
97
  t.string "job_id"
98
98
  t.integer "fork_count"
99
99
  t.index ["job_id"], name: "index_canvas_sync_job_logs_on_job_id"
100
100
  end
101
101
 
102
+ create_table "canvas_sync_sync_batches", id: :serial, force: :cascade do |t|
103
+ t.datetime "started_at"
104
+ t.datetime "completed_at"
105
+ t.string "status"
106
+ t.datetime "created_at"
107
+ t.datetime "updated_at"
108
+ end
109
+
102
110
  create_table "context_module_items", force: :cascade do |t|
103
111
  t.bigint "canvas_id"
104
112
  t.bigint "canvas_context_module_id"
@@ -191,6 +199,18 @@ ActiveRecord::Schema.define(version: 2020_04_16_214248) do
191
199
  t.index ["canvas_id"], name: "index_groups_on_canvas_id", unique: true
192
200
  end
193
201
 
202
+ create_table "pseudonyms", force: :cascade do |t|
203
+ t.bigint "canvas_id", null: false
204
+ t.bigint "canvas_user_id"
205
+ t.string "sis_id"
206
+ t.string "unique_id"
207
+ t.string "workflow_state"
208
+ t.datetime "created_at", null: false
209
+ t.datetime "updated_at", null: false
210
+ t.index ["canvas_id"], name: "index_pseudonyms_on_canvas_id", unique: true
211
+ t.index ["canvas_user_id"], name: "index_pseudonyms_on_canvas_user_id"
212
+ end
213
+
194
214
  create_table "roles", force: :cascade do |t|
195
215
  t.integer "canvas_id", null: false
196
216
  t.string "label"
@@ -0,0 +1,100 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe CanvasSync::JobBatches::BatchAwareJob do
4
+ include ActiveJob::TestHelper
5
+
6
+ after do
7
+ clear_enqueued_jobs
8
+ clear_performed_jobs
9
+ end
10
+
11
+ context "When Performing" do
12
+ context 'when without batch' do
13
+ it 'just yields' do
14
+ expect(CanvasSync::JobBatches::Batch).not_to receive(:process_successful_job)
15
+ expect(CanvasSync::JobBatches::Batch).not_to receive(:process_failed_job)
16
+ expect_any_instance_of(BatchTestJobBase).to receive(:perform)
17
+
18
+ BatchTestJobBase.perform_now
19
+ end
20
+ end
21
+
22
+ context 'when in batch' do
23
+ let(:bid) { 'SAMPLEBID' }
24
+
25
+ context 'when successful' do
26
+ it 'yields' do
27
+ expect_any_instance_of(BatchTestJobBase).to receive(:perform)
28
+ BatchTestJobBase.perform_now
29
+ end
30
+
31
+ it 'calls process_successful_job' do
32
+ job = BatchTestJobBase.new
33
+ job.instance_variable_set(:@bid, bid)
34
+ expect(CanvasSync::JobBatches::Batch).to receive(:process_successful_job).with(bid, job.job_id)
35
+ job.perform_now
36
+ end
37
+ end
38
+
39
+ context 'when failed' do
40
+ it 'calls process_failed_job and reraises exception' do
41
+ reraised = false
42
+ job = FailingBatchTestJobBase.new
43
+ job.instance_variable_set(:@bid, bid)
44
+ expect(CanvasSync::JobBatches::Batch).to receive(:process_failed_job)
45
+ begin
46
+ job.perform_now
47
+ rescue
48
+ reraised = true
49
+ end
50
+ expect(reraised).to be_truthy
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ context "When Enqueueing" do
57
+ context 'when without batch' do
58
+ it 'just yields' do
59
+ expect(CanvasSync::JobBatches::Batch).not_to receive(:increment_job_queue)
60
+ BatchTestJobBase.perform_later
61
+ expect(BatchTestJobBase).to have_been_enqueued
62
+ end
63
+ end
64
+
65
+ context 'when in batch' do
66
+ let(:bid) { 'SAMPLEBID' }
67
+
68
+ before do
69
+ Thread.current[:batch] = CanvasSync::JobBatches::Batch.new(bid)
70
+ Thread.current[:batch].instance_variable_set(:@open, true)
71
+ end
72
+
73
+ it 'yields' do
74
+ expect {
75
+ BatchTestJobBase.perform_later
76
+ }.to enqueue_job(BatchTestJobBase)
77
+ end
78
+
79
+ it 'assigns bid to job metadata' do
80
+ job = BatchTestJobBase.perform_later
81
+ expect(job.bid).to eq bid
82
+ expect(job.serialize['batch_id']).to eq bid
83
+ end
84
+ end
85
+ end
86
+
87
+ context 'worker' do
88
+ it 'defines method bid' do
89
+ expect(ActiveJob::Base.instance_methods).to include(:bid)
90
+ end
91
+
92
+ it 'defines method batch' do
93
+ expect(ActiveJob::Base.instance_methods).to include(:batch)
94
+ end
95
+
96
+ it 'defines method valid_within_batch?' do
97
+ expect(ActiveJob::Base.instance_methods).to include(:valid_within_batch?)
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,363 @@
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_successful_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 'cleanups redis key' do
203
+ CanvasSync::JobBatches::Batch.process_successful_job(bid, jid)
204
+ expect(CanvasSync::JobBatches::Batch.redis { |r| r.get("BID-#{bid}-pending") }.to_i).to eq(0)
205
+ end
206
+ end
207
+ end
208
+
209
+ describe '#increment_job_queue' do
210
+ let(:bid) { 'BID' }
211
+ let(:batch) { CanvasSync::JobBatches::Batch.new }
212
+
213
+ it 'increments pending' do
214
+ batch.jobs do TestWorker.perform_async end
215
+ pending = CanvasSync::JobBatches::Batch.redis { |r| r.hget("BID-#{batch.bid}", 'pending') }
216
+ expect(pending).to eq('1')
217
+ end
218
+
219
+ it 'increments total' do
220
+ batch.jobs do TestWorker.perform_async end
221
+ total = CanvasSync::JobBatches::Batch.redis { |r| r.hget("BID-#{batch.bid}", 'total') }
222
+ expect(total).to eq('1')
223
+ end
224
+ end
225
+
226
+ describe '#enqueue_callbacks' do
227
+ let(:callback) { double('callback') }
228
+ let(:event) { :complete }
229
+
230
+ context 'on :success' do
231
+ let(:event) { :success }
232
+ context 'when no callbacks are defined' do
233
+ it 'clears redis keys' do
234
+ batch = CanvasSync::JobBatches::Batch.new
235
+ expect(CanvasSync::JobBatches::Batch).to receive(:cleanup_redis).with(batch.bid)
236
+ CanvasSync::JobBatches::Batch.enqueue_callbacks(event, batch.bid)
237
+ end
238
+ end
239
+ end
240
+
241
+ context 'when already called' do
242
+ it 'returns and does not enqueue callbacks' do
243
+ batch = CanvasSync::JobBatches::Batch.new
244
+ batch.on(event, SampleCallback)
245
+ CanvasSync::JobBatches::Batch.redis { |r| r.hset("BID-#{batch.bid}", event, true) }
246
+
247
+ expect(batch).not_to receive(:push_callbacks)
248
+ CanvasSync::JobBatches::Batch.enqueue_callbacks(event, batch.bid)
249
+ end
250
+ end
251
+
252
+ context 'With ActiveJob Adapter' do
253
+ around(:all) do |block|
254
+ CanvasSync::JobBatches::Batch::Callback.send(:remove_const, :Worker)
255
+ CanvasSync::JobBatches::Batch::Callback.const_set(:Worker, CanvasSync::JobBatches::Batch::Callback::ActiveJobCallbackWorker)
256
+ block.run
257
+ end
258
+
259
+ context 'when not yet called' do
260
+ context 'when there is no callback' do
261
+ it 'it returns' do
262
+ batch = CanvasSync::JobBatches::Batch.new
263
+
264
+ expect(batch).not_to receive(:push_callbacks)
265
+ CanvasSync::JobBatches::Batch.enqueue_callbacks(event, batch.bid)
266
+ end
267
+ end
268
+
269
+ context 'when callback defined' do
270
+ let(:opts) { { 'a' => 'b' } }
271
+
272
+ it 'calls it passing options' do
273
+ batch = CanvasSync::JobBatches::Batch.new
274
+ batch.on(event, SampleCallback, opts)
275
+
276
+ CanvasSync::JobBatches::Batch.enqueue_callbacks(event, batch.bid)
277
+
278
+ expect(CanvasSync::JobBatches::Batch::Callback::Worker).to have_been_enqueued.with(
279
+ 'SampleCallback', event.to_s, opts, batch.bid, nil
280
+ )
281
+ end
282
+ end
283
+
284
+ context 'when multiple callbacks are defined' do
285
+ let(:opts) { { 'a' => 'b' } }
286
+ let(:opts2) { { 'b' => 'a' } }
287
+
288
+ it 'enqueues each callback passing their options' do
289
+ batch = CanvasSync::JobBatches::Batch.new
290
+ batch.on(event, SampleCallback, opts)
291
+ batch.on(event, SampleCallback2, opts2)
292
+
293
+ CanvasSync::JobBatches::Batch.enqueue_callbacks(event, batch.bid)
294
+ expect(CanvasSync::JobBatches::Batch::Callback::Worker).to have_been_enqueued.with(
295
+ 'SampleCallback2', event.to_s, opts2, batch.bid, nil
296
+ )
297
+ expect(CanvasSync::JobBatches::Batch::Callback::Worker).to have_been_enqueued.with(
298
+ 'SampleCallback', event.to_s, opts, batch.bid, nil
299
+ )
300
+ end
301
+ end
302
+ end
303
+ end
304
+
305
+ context 'With Sidekiq Adapter' do
306
+ around(:all) do |block|
307
+ CanvasSync::JobBatches::Batch::Callback.send(:remove_const, :Worker)
308
+ CanvasSync::JobBatches::Batch::Callback.const_set(:Worker, CanvasSync::JobBatches::Batch::Callback::SidekiqCallbackWorker)
309
+ block.run
310
+ end
311
+
312
+ context 'when not yet called' do
313
+ context 'when there is no callback' do
314
+ it 'it returns' do
315
+ batch = CanvasSync::JobBatches::Batch.new
316
+
317
+ expect(batch).not_to receive(:push_callbacks)
318
+ CanvasSync::JobBatches::Batch.enqueue_callbacks(event, batch.bid)
319
+ end
320
+ end
321
+
322
+ context 'when callback defined' do
323
+ let(:opts) { { 'a' => 'b' } }
324
+
325
+ it 'calls it passing options' do
326
+ batch = CanvasSync::JobBatches::Batch.new
327
+ batch.on(event, SampleCallback, opts)
328
+
329
+ expect(Sidekiq::Client).to receive(:push_bulk).with(
330
+ 'class' => Sidekiq::Batch::Callback::Worker,
331
+ 'args' => [['SampleCallback', event.to_s, opts, batch.bid, nil]],
332
+ 'queue' => 'default'
333
+ )
334
+
335
+ CanvasSync::JobBatches::Batch.enqueue_callbacks(event, batch.bid)
336
+ end
337
+ end
338
+
339
+ context 'when multiple callbacks are defined' do
340
+ let(:opts) { { 'a' => 'b' } }
341
+ let(:opts2) { { 'b' => 'a' } }
342
+
343
+ it 'enqueues each callback passing their options' do
344
+ batch = CanvasSync::JobBatches::Batch.new
345
+ batch.on(event, SampleCallback, opts)
346
+ batch.on(event, SampleCallback2, opts2)
347
+
348
+ expect(Sidekiq::Client).to receive(:push_bulk).with(
349
+ 'class' => Sidekiq::Batch::Callback::Worker,
350
+ 'args' => [
351
+ ['SampleCallback2', event.to_s, opts2, batch.bid, nil],
352
+ ['SampleCallback', event.to_s, opts, batch.bid, nil]
353
+ ],
354
+ 'queue' => 'default'
355
+ )
356
+
357
+ CanvasSync::JobBatches::Batch.enqueue_callbacks(event, batch.bid)
358
+ end
359
+ end
360
+ end
361
+ end
362
+ end
363
+ end