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.
- checksums.yaml +4 -4
- data/README.md +49 -137
- data/app/models/canvas_sync/sync_batch.rb +5 -0
- data/db/migrate/20170915210836_create_canvas_sync_job_log.rb +12 -31
- data/db/migrate/20180725155729_add_job_id_to_canvas_sync_job_logs.rb +4 -13
- data/db/migrate/20190916154829_add_fork_count_to_canvas_sync_job_logs.rb +3 -11
- data/db/migrate/20201018210836_create_canvas_sync_sync_batches.rb +11 -0
- data/lib/canvas_sync.rb +36 -118
- data/lib/canvas_sync/concerns/api_syncable.rb +27 -0
- data/lib/canvas_sync/job.rb +5 -5
- data/lib/canvas_sync/job_batches/batch.rb +399 -0
- data/lib/canvas_sync/job_batches/batch_aware_job.rb +62 -0
- data/lib/canvas_sync/job_batches/callback.rb +153 -0
- data/lib/canvas_sync/job_batches/chain_builder.rb +210 -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 +18 -0
- data/lib/canvas_sync/job_batches/jobs/serial_batch_job.rb +73 -0
- data/lib/canvas_sync/job_batches/sidekiq.rb +93 -0
- data/lib/canvas_sync/job_batches/status.rb +63 -0
- data/lib/canvas_sync/jobs/begin_sync_chain_job.rb +34 -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 +27 -19
- 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 +5 -35
- 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/misc_helper.rb +15 -0
- 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/app/models/account.rb +3 -0
- data/spec/dummy/app/models/pseudonym.rb +14 -0
- data/spec/dummy/app/models/submission.rb +1 -0
- data/spec/dummy/app/models/user.rb +1 -0
- data/spec/dummy/config/environments/test.rb +2 -0
- data/spec/dummy/db/migrate/20201016181346_create_pseudonyms.rb +24 -0
- data/spec/dummy/db/schema.rb +24 -4
- data/spec/job_batching/batch_aware_job_spec.rb +100 -0
- data/spec/job_batching/batch_spec.rb +363 -0
- data/spec/job_batching/callback_spec.rb +38 -0
- data/spec/job_batching/flow_spec.rb +91 -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 +90 -8
- data/lib/canvas_sync/job_chain.rb +0 -57
- data/lib/canvas_sync/jobs/fork_gather.rb +0 -59
- 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
|
@@ -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
|
data/spec/dummy/db/schema.rb
CHANGED
@@ -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:
|
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"
|
96
|
-
t.datetime "updated_at"
|
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
|