canvas_sync 0.26.1 → 0.27.1.beta2
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 +117 -20
- data/app/controllers/canvas_sync/api/v1/live_events_controller.rb +1 -0
- data/lib/canvas_sync/config.rb +1 -1
- data/lib/canvas_sync/importers/bulk_importer.rb +2 -0
- data/lib/canvas_sync/jobs/begin_sync_chain_job.rb +1 -1
- data/lib/canvas_sync/jobs/beta_cleanup/create_temp_tables_job.rb +30 -0
- data/lib/canvas_sync/jobs/beta_cleanup/delete_related_records_job.rb +125 -0
- data/lib/canvas_sync/jobs/beta_cleanup/delete_temp_tables_job.rb +16 -0
- data/lib/canvas_sync/jobs/report_starter.rb +33 -46
- data/lib/canvas_sync/jobs/report_sync_task.rb +273 -0
- data/lib/canvas_sync/jobs/sync_accounts_job.rb +10 -7
- data/lib/canvas_sync/jobs/sync_assignment_groups_job.rb +2 -15
- data/lib/canvas_sync/jobs/sync_assignment_overrides_job.rb +26 -14
- data/lib/canvas_sync/jobs/sync_assignments_job.rb +2 -15
- data/lib/canvas_sync/jobs/sync_content_migrations_job.rb +2 -15
- data/lib/canvas_sync/jobs/sync_context_module_items_job.rb +2 -15
- data/lib/canvas_sync/jobs/sync_context_modules_job.rb +2 -15
- data/lib/canvas_sync/jobs/sync_course_progresses_job.rb +2 -16
- data/lib/canvas_sync/jobs/sync_provisioning_report_job.rb +135 -14
- data/lib/canvas_sync/jobs/sync_rubric_assessments_job.rb +2 -10
- data/lib/canvas_sync/jobs/sync_rubric_associations_job.rb +2 -10
- data/lib/canvas_sync/jobs/sync_rubrics_job.rb +2 -10
- data/lib/canvas_sync/jobs/sync_scores_job.rb +2 -13
- data/lib/canvas_sync/jobs/sync_submissions_job.rb +9 -18
- data/lib/canvas_sync/jobs/term_batches_job.rb +4 -2
- data/lib/canvas_sync/version.rb +1 -1
- data/lib/canvas_sync.rb +31 -4
- data/spec/canvas_sync/canvas_sync_spec.rb +62 -22
- data/spec/canvas_sync/jobs/report_starter_spec.rb +102 -55
- data/spec/canvas_sync/jobs/report_sync_task_spec.rb +367 -0
- data/spec/canvas_sync/jobs/sync_provisioning_report_job_spec.rb +24 -35
- data/spec/canvas_sync/processors/assignment_groups_processor_spec.rb +3 -4
- data/spec/canvas_sync/processors/assignment_overrides_processor_spec.rb +7 -4
- data/spec/canvas_sync/processors/assignments_processor_spec.rb +3 -4
- data/spec/canvas_sync/processors/content_migrations_processor_spec.rb +3 -4
- data/spec/canvas_sync/processors/context_module_items_processor_spec.rb +4 -5
- data/spec/canvas_sync/processors/context_modules_processor_spec.rb +3 -4
- data/spec/canvas_sync/processors/course_completion_report_processor_spec.rb +7 -4
- data/spec/canvas_sync/processors/provisioning_report_processor_spec.rb +46 -24
- data/spec/canvas_sync/processors/rubric_assessments_spec.rb +3 -4
- data/spec/canvas_sync/processors/rubric_associations_spec.rb +3 -4
- data/spec/canvas_sync/processors/rubrics_processor_spec.rb +3 -4
- data/spec/canvas_sync/processors/submissions_processor_spec.rb +3 -4
- data/spec/factories/account_factory.rb +1 -1
- metadata +7 -33
- data/lib/canvas_sync/jobs/report_checker.rb +0 -108
- data/lib/canvas_sync/jobs/report_processor_job.rb +0 -35
- data/lib/canvas_sync/processors/assignment_groups_processor.rb +0 -19
- data/lib/canvas_sync/processors/assignment_overrides_processor.rb +0 -41
- data/lib/canvas_sync/processors/assignments_processor.rb +0 -19
- data/lib/canvas_sync/processors/content_migrations_processor.rb +0 -19
- data/lib/canvas_sync/processors/context_module_items_processor.rb +0 -19
- data/lib/canvas_sync/processors/context_modules_processor.rb +0 -19
- data/lib/canvas_sync/processors/course_completion_report_processor.rb +0 -20
- data/lib/canvas_sync/processors/provisioning_report_processor.rb +0 -149
- data/lib/canvas_sync/processors/rubric_assessments_processor.rb +0 -19
- data/lib/canvas_sync/processors/rubric_associations_processor.rb +0 -19
- data/lib/canvas_sync/processors/rubrics_processor.rb +0 -19
- data/lib/canvas_sync/processors/submissions_processor.rb +0 -19
- data/spec/canvas_sync/jobs/report_checker_spec.rb +0 -57
- data/spec/canvas_sync/jobs/report_processor_job_spec.rb +0 -25
- data/spec/canvas_sync/jobs/sync_assignment_groups_job_spec.rb +0 -18
- data/spec/canvas_sync/jobs/sync_assignments_job_spec.rb +0 -30
- data/spec/canvas_sync/jobs/sync_content_migrations_job_spec.rb +0 -30
- data/spec/canvas_sync/jobs/sync_context_module_items_job_spec.rb +0 -30
- data/spec/canvas_sync/jobs/sync_context_modules_job_spec.rb +0 -30
- data/spec/canvas_sync/jobs/sync_scores_job_spec.rb +0 -15
- data/spec/canvas_sync/jobs/sync_submissions_job_spec.rb +0 -23
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe CanvasSync::Jobs::ReportSyncTask do
|
|
4
|
+
class SyncSpecsTask < CanvasSync::Jobs::ReportSyncTask
|
|
5
|
+
report_name 'sync_specs_csv'
|
|
6
|
+
|
|
7
|
+
def report_parameters
|
|
8
|
+
merge_report_params(options, { include_all: options[:include_all] })
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
let(:batch_context) { { canvas_term_id: 1 }.with_indifferent_access }
|
|
13
|
+
|
|
14
|
+
def stub_batch_context(context = batch_context)
|
|
15
|
+
report_batch = instance_double(CanvasSync::JobBatches::Batch,
|
|
16
|
+
context: { report_class: 'SyncSpecsTask', report_options: {} })
|
|
17
|
+
parent_batch = instance_double(CanvasSync::JobBatches::Batch, context: context)
|
|
18
|
+
|
|
19
|
+
allow(CanvasSync::JobBatches::Batch).to receive(:current).and_return(report_batch)
|
|
20
|
+
allow(CanvasSync::JobBatches::Batch).to receive(:current_context).and_return(context)
|
|
21
|
+
allow(report_batch).to receive(:parent).and_return(parent_batch)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def create_job(job_class, context = batch_context)
|
|
25
|
+
job_class.new.tap { |job| allow(job).to receive(:batch_context).and_return(context) }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe "#report_parameters" do
|
|
29
|
+
before { allow(CanvasSync::JobBatches::Batch).to receive(:current_context).and_return(batch_context) }
|
|
30
|
+
|
|
31
|
+
it "merges batch context parameters" do
|
|
32
|
+
task = SyncSpecsTask.new({}, { canvas_term_id: 123, updated_after: '2024-01-01' }, {})
|
|
33
|
+
allow(CanvasSync::JobBatches::Batch).to receive(:current_context)
|
|
34
|
+
.and_return({ canvas_term_id: 123, updated_after: '2024-01-01' })
|
|
35
|
+
|
|
36
|
+
expect(task.report_parameters).to eq({
|
|
37
|
+
parameters: { enrollment_term_id: 123, updated_after: '2024-01-01', include_all: nil }
|
|
38
|
+
})
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "merges options parameters" do
|
|
42
|
+
task = SyncSpecsTask.new({ canvas_term_id: 456, include_all: true }, {}, {})
|
|
43
|
+
allow(CanvasSync::JobBatches::Batch).to receive(:current_context).and_return({})
|
|
44
|
+
|
|
45
|
+
expect(task.report_parameters).to eq({
|
|
46
|
+
parameters: { enrollment_term_id: 456, include_all: true }
|
|
47
|
+
})
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "prioritizes options over batch context" do
|
|
51
|
+
task = SyncSpecsTask.new({ canvas_term_id: 789 }, {}, {})
|
|
52
|
+
allow(CanvasSync::JobBatches::Batch).to receive(:current_context)
|
|
53
|
+
.and_return({ canvas_term_id: 123 })
|
|
54
|
+
|
|
55
|
+
expect(task.report_parameters[:parameters][:enrollment_term_id]).to eq(789)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "merges report_params and report_parameters from options" do
|
|
59
|
+
task = SyncSpecsTask.new({
|
|
60
|
+
report_params: { custom: 'value' },
|
|
61
|
+
report_parameters: { another: 'value' }
|
|
62
|
+
}, {}, {})
|
|
63
|
+
allow(CanvasSync::JobBatches::Batch).to receive(:current_context).and_return({})
|
|
64
|
+
|
|
65
|
+
params = task.report_parameters[:parameters]
|
|
66
|
+
expect(params[:custom]).to eq('value')
|
|
67
|
+
expect(params[:another]).to eq('value')
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
describe ".perform_later" do
|
|
72
|
+
it "creates a batch and enqueues StarterJob" do
|
|
73
|
+
batch = instance_double(CanvasSync::JobBatches::Batch)
|
|
74
|
+
allow(CanvasSync::JobBatches::Batch).to receive(:new).and_return(batch)
|
|
75
|
+
allow(batch).to receive(:description=)
|
|
76
|
+
allow(batch).to receive(:allow_context_changes=)
|
|
77
|
+
allow(batch).to receive(:context).and_return({})
|
|
78
|
+
|
|
79
|
+
expect(batch).to receive(:jobs) do |&block|
|
|
80
|
+
expect(SyncSpecsTask::StarterJob).to receive(:perform_later)
|
|
81
|
+
block.call
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
SyncSpecsTask.perform_later({ include_all: true })
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
describe ".from_context" do
|
|
89
|
+
it "reconstructs task from batch context" do
|
|
90
|
+
stub_batch_context({ canvas_term_id: 1 })
|
|
91
|
+
allow(CanvasSync::JobBatches::Batch.current).to receive(:context)
|
|
92
|
+
.and_return({ report_class: 'SyncSpecsTask', report_options: { include_all: true } })
|
|
93
|
+
|
|
94
|
+
task = CanvasSync::Jobs::ReportSyncTask.from_context
|
|
95
|
+
|
|
96
|
+
expect(task).to be_a(SyncSpecsTask)
|
|
97
|
+
expect(task.options).to eq({ include_all: true })
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
describe described_class::StarterJob do
|
|
102
|
+
let(:client) { instance_double(Bearcat::Client) }
|
|
103
|
+
|
|
104
|
+
before do
|
|
105
|
+
stub_batch_context
|
|
106
|
+
allow_any_instance_of(Bearcat::Client).to receive(:start_report)
|
|
107
|
+
.and_return("id" => 123)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "starts the report and enqueues checker" do
|
|
111
|
+
expect_any_instance_of(Bearcat::Client).to receive(:start_report)
|
|
112
|
+
.with("self", "sync_specs_csv", { parameters: { enrollment_term_id: 1, include_all: nil } })
|
|
113
|
+
expect(SyncSpecsTask::CheckerJob).to receive(:set).with(wait: anything)
|
|
114
|
+
.and_return(double(perform_later: nil))
|
|
115
|
+
|
|
116
|
+
job = create_job(SyncSpecsTask::StarterJob)
|
|
117
|
+
job.perform
|
|
118
|
+
|
|
119
|
+
expect(batch_context[:report_attempt]).to eq(1)
|
|
120
|
+
expect(batch_context[:report_id]).to eq("sync_specs_csv/123")
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it "enqueues CheckerJob with wait time" do
|
|
124
|
+
checker_double = double
|
|
125
|
+
expect(SyncSpecsTask::CheckerJob).to receive(:set).with(wait: anything)
|
|
126
|
+
.and_return(checker_double)
|
|
127
|
+
expect(checker_double).to receive(:perform_later)
|
|
128
|
+
|
|
129
|
+
job = create_job(SyncSpecsTask::StarterJob)
|
|
130
|
+
job.perform
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
it "sets sync_start_time in batch context" do
|
|
134
|
+
allow(SyncSpecsTask::CheckerJob).to receive(:set)
|
|
135
|
+
.and_return(double(perform_later: nil))
|
|
136
|
+
|
|
137
|
+
job = create_job(SyncSpecsTask::StarterJob)
|
|
138
|
+
job.perform
|
|
139
|
+
|
|
140
|
+
expect(batch_context[:sync_start_time]).to be_present
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
context "with caching enabled" do
|
|
144
|
+
let(:redis_double) { double('Redis') }
|
|
145
|
+
let(:cache_key) { "SyncBatch[batch-123]:abc123def" }
|
|
146
|
+
|
|
147
|
+
before do
|
|
148
|
+
# CanvasSync.redis can be called with or without a block
|
|
149
|
+
allow(CanvasSync).to receive(:redis) do |&block|
|
|
150
|
+
if block
|
|
151
|
+
block.call(redis_double)
|
|
152
|
+
else
|
|
153
|
+
redis_double
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
batch_context[:sync_batch_id] = 'batch-123'
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it "uses cached report when available and fresh" do
|
|
160
|
+
batch_context[:report_caching] = { scope: :sync_batch, max_age: 23.hours }
|
|
161
|
+
cached_data = {
|
|
162
|
+
"report_id" => "sync_specs_csv/999",
|
|
163
|
+
"started_at" => 1.hour.ago.iso8601
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
expect(redis_double).to receive(:hgetall).with(anything).and_return(cached_data)
|
|
167
|
+
expect_any_instance_of(Bearcat::Client).to_not receive(:start_report)
|
|
168
|
+
allow(SyncSpecsTask::CheckerJob).to receive(:set).and_return(double(perform_later: nil))
|
|
169
|
+
|
|
170
|
+
job = create_job(SyncSpecsTask::StarterJob)
|
|
171
|
+
job.perform
|
|
172
|
+
|
|
173
|
+
expect(batch_context[:report_id]).to eq("sync_specs_csv/999")
|
|
174
|
+
expect(batch_context[:sync_start_time]).to eq(cached_data["started_at"])
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
it "ignores stale cached report and starts new one" do
|
|
178
|
+
batch_context[:report_caching] = { scope: :sync_batch, max_age: 23.hours }
|
|
179
|
+
stale_cached_data = {
|
|
180
|
+
"report_id" => "sync_specs_csv/999",
|
|
181
|
+
"started_at" => 25.hours.ago.iso8601
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
expect(redis_double).to receive(:hgetall).with(anything).and_return(stale_cached_data)
|
|
185
|
+
expect_any_instance_of(Bearcat::Client).to receive(:start_report).and_return("id" => 123)
|
|
186
|
+
expect(redis_double).to receive(:hset).with(anything, hash_including(:report_id, :started_at))
|
|
187
|
+
expect(redis_double).to receive(:expire)
|
|
188
|
+
allow(SyncSpecsTask::CheckerJob).to receive(:set).and_return(double(perform_later: nil))
|
|
189
|
+
|
|
190
|
+
job = create_job(SyncSpecsTask::StarterJob)
|
|
191
|
+
job.perform
|
|
192
|
+
|
|
193
|
+
expect(batch_context[:report_id]).to eq("sync_specs_csv/123")
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
it "stores new report in cache" do
|
|
197
|
+
batch_context[:report_caching] = { scope: :sync_batch, max_age: 23.hours }
|
|
198
|
+
|
|
199
|
+
expect(redis_double).to receive(:hgetall).with(anything).and_return({})
|
|
200
|
+
expect_any_instance_of(Bearcat::Client).to receive(:start_report).and_return("id" => 123)
|
|
201
|
+
expect(redis_double).to receive(:hset).with(anything, hash_including(:report_id, :started_at))
|
|
202
|
+
expect(redis_double).to receive(:expire).with(anything, 23.hours.to_i)
|
|
203
|
+
allow(SyncSpecsTask::CheckerJob).to receive(:set).and_return(double(perform_later: nil))
|
|
204
|
+
|
|
205
|
+
job = create_job(SyncSpecsTask::StarterJob)
|
|
206
|
+
job.perform
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
it "uses custom max_age when specified" do
|
|
210
|
+
batch_context[:report_caching] = { scope: :sync_batch, max_age: 12.hours }
|
|
211
|
+
|
|
212
|
+
expect(redis_double).to receive(:hgetall).with(anything).and_return({})
|
|
213
|
+
expect_any_instance_of(Bearcat::Client).to receive(:start_report).and_return("id" => 123)
|
|
214
|
+
expect(redis_double).to receive(:hset)
|
|
215
|
+
expect(redis_double).to receive(:expire).with(anything, 12.hours.to_i)
|
|
216
|
+
allow(SyncSpecsTask::CheckerJob).to receive(:set).and_return(double(perform_later: nil))
|
|
217
|
+
|
|
218
|
+
job = create_job(SyncSpecsTask::StarterJob)
|
|
219
|
+
job.perform
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
it "supports task-level caching options" do
|
|
223
|
+
task_options = { caching: { scope: :sync_batch, max_age: 6.hours } }
|
|
224
|
+
allow(SyncSpecsTask).to receive(:new).and_return(
|
|
225
|
+
SyncSpecsTask.new(task_options, batch_context, batch_context)
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
expect(redis_double).to receive(:hgetall).with(anything).and_return({})
|
|
229
|
+
expect_any_instance_of(Bearcat::Client).to receive(:start_report).and_return("id" => 123)
|
|
230
|
+
expect(redis_double).to receive(:hset)
|
|
231
|
+
expect(redis_double).to receive(:expire).with(anything, 6.hours.to_i)
|
|
232
|
+
allow(SyncSpecsTask::CheckerJob).to receive(:set).and_return(double(perform_later: nil))
|
|
233
|
+
|
|
234
|
+
job = create_job(SyncSpecsTask::StarterJob)
|
|
235
|
+
allow(job).to receive(:report_task).and_return(
|
|
236
|
+
SyncSpecsTask.new(task_options, batch_context, batch_context)
|
|
237
|
+
)
|
|
238
|
+
job.perform
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
describe described_class::CheckerJob do
|
|
244
|
+
let(:batch_context) {
|
|
245
|
+
{ canvas_term_id: 1, report_id: 'sync_specs_csv/123', report_attempt: 1 }.with_indifferent_access
|
|
246
|
+
}
|
|
247
|
+
let(:client) { instance_double(Bearcat::Client) }
|
|
248
|
+
|
|
249
|
+
before do
|
|
250
|
+
stub_batch_context(batch_context)
|
|
251
|
+
allow(CanvasSync).to receive(:get_canvas_sync_client).and_return(client)
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
context "when complete" do
|
|
255
|
+
it "enqueues ProcessJob" do
|
|
256
|
+
allow(client).to receive(:report_status)
|
|
257
|
+
.and_return("status" => "complete", "attachment" => { "url" => "http://example.com/report.csv" })
|
|
258
|
+
|
|
259
|
+
expect(SyncSpecsTask::ProcessJob).to receive(:perform_later).with("http://example.com/report.csv")
|
|
260
|
+
|
|
261
|
+
create_job(SyncSpecsTask::CheckerJob, batch_context).perform
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
context "when error or deleted" do
|
|
266
|
+
it "retries if under max_tries" do
|
|
267
|
+
allow(client).to receive(:report_status).and_return("status" => "error")
|
|
268
|
+
expect(client).to receive(:start_report).and_return("id" => 456)
|
|
269
|
+
expect(SyncSpecsTask::CheckerJob).to receive(:set).and_return(double(perform_later: nil))
|
|
270
|
+
|
|
271
|
+
create_job(SyncSpecsTask::CheckerJob, batch_context).perform
|
|
272
|
+
|
|
273
|
+
expect(batch_context[:report_attempt]).to eq(2)
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
it "handles deleted status the same as error" do
|
|
277
|
+
allow(client).to receive(:report_status).and_return("status" => "deleted")
|
|
278
|
+
expect(client).to receive(:start_report).and_return("id" => 456)
|
|
279
|
+
expect(SyncSpecsTask::CheckerJob).to receive(:set).and_return(double(perform_later: nil))
|
|
280
|
+
|
|
281
|
+
create_job(SyncSpecsTask::CheckerJob, batch_context).perform
|
|
282
|
+
|
|
283
|
+
expect(batch_context[:report_attempt]).to eq(2)
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
it "raises FatalReportError after max_tries" do
|
|
287
|
+
batch_context[:report_attempt] = 3
|
|
288
|
+
allow(client).to receive(:report_status).and_return("status" => "error")
|
|
289
|
+
|
|
290
|
+
expect {
|
|
291
|
+
create_job(SyncSpecsTask::CheckerJob, batch_context).perform
|
|
292
|
+
}.to raise_error(CanvasSync::Jobs::ReportSyncTask::FatalReportError)
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
it "does not re-enqueue or process when errored after max_tries" do
|
|
296
|
+
batch_context[:report_attempt] = 3
|
|
297
|
+
allow(client).to receive(:report_status).and_return("status" => "error")
|
|
298
|
+
|
|
299
|
+
expect(SyncSpecsTask::CheckerJob).to_not receive(:set)
|
|
300
|
+
expect(SyncSpecsTask::ProcessJob).to_not receive(:perform_later)
|
|
301
|
+
|
|
302
|
+
expect {
|
|
303
|
+
create_job(SyncSpecsTask::CheckerJob, batch_context).perform
|
|
304
|
+
}.to raise_error(CanvasSync::Jobs::ReportSyncTask::FatalReportError)
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
context "when still processing" do
|
|
309
|
+
it "re-enqueues itself" do
|
|
310
|
+
allow(client).to receive(:report_status).and_return("status" => "running")
|
|
311
|
+
expect(SyncSpecsTask::CheckerJob).to receive(:set).and_return(double(perform_later: nil))
|
|
312
|
+
|
|
313
|
+
create_job(SyncSpecsTask::CheckerJob, batch_context).perform
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
it "raises FatalReportError on timeout" do
|
|
317
|
+
batch_context[:sync_start_time] = (DateTime.now - 25.hours).iso8601
|
|
318
|
+
allow(client).to receive(:report_status).and_return("status" => "running")
|
|
319
|
+
|
|
320
|
+
expect {
|
|
321
|
+
create_job(SyncSpecsTask::CheckerJob, batch_context).perform
|
|
322
|
+
}.to raise_error(CanvasSync::Jobs::ReportSyncTask::FatalReportError, /stuck/)
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
context "when compiling" do
|
|
327
|
+
it "tracks compilation start time" do
|
|
328
|
+
allow(client).to receive(:report_status).and_return("status" => "compiling")
|
|
329
|
+
expect(SyncSpecsTask::CheckerJob).to receive(:set).and_return(double(perform_later: nil))
|
|
330
|
+
|
|
331
|
+
create_job(SyncSpecsTask::CheckerJob, batch_context).perform
|
|
332
|
+
|
|
333
|
+
expect(batch_context[:compiling_since]).to be_present
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
it "raises FatalReportError on compilation timeout" do
|
|
337
|
+
batch_context[:compiling_since] = (DateTime.now - 4.hours).iso8601
|
|
338
|
+
allow(client).to receive(:report_status).and_return("status" => "compiling")
|
|
339
|
+
|
|
340
|
+
expect {
|
|
341
|
+
create_job(SyncSpecsTask::CheckerJob, batch_context).perform
|
|
342
|
+
}.to raise_error(CanvasSync::Jobs::ReportSyncTask::FatalReportError, /stuck/)
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
describe described_class::ProcessJob do
|
|
348
|
+
let(:batch_context) { { report_id: 'sync_specs_csv/123' }.with_indifferent_access }
|
|
349
|
+
let(:client) { instance_double(Bearcat::Client) }
|
|
350
|
+
|
|
351
|
+
before do
|
|
352
|
+
stub_batch_context(batch_context)
|
|
353
|
+
allow(CanvasSync).to receive(:get_canvas_sync_client).and_return(client)
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
it "downloads and processes the report" do
|
|
357
|
+
allow(client).to receive(:download_report)
|
|
358
|
+
task = instance_double(SyncSpecsTask)
|
|
359
|
+
allow(SyncSpecsTask).to receive(:new).and_return(task)
|
|
360
|
+
expect(task).to receive(:process)
|
|
361
|
+
|
|
362
|
+
job = create_job(SyncSpecsTask::ProcessJob, batch_context)
|
|
363
|
+
allow(job).to receive(:canvas_sync_client).and_return(client)
|
|
364
|
+
job.perform("http://example.com/report.csv")
|
|
365
|
+
end
|
|
366
|
+
end
|
|
367
|
+
end
|
|
@@ -1,50 +1,39 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
3
|
RSpec.describe CanvasSync::Jobs::SyncProvisioningReportJob do
|
|
4
|
-
describe '#
|
|
4
|
+
describe '#report_parameters' do
|
|
5
5
|
context 'a term scope is specified' do
|
|
6
6
|
let!(:term) { FactoryBot.create(:term) }
|
|
7
7
|
|
|
8
|
-
it '
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
'self',
|
|
12
|
-
'proservices_provisioning_csv',
|
|
13
|
-
{
|
|
14
|
-
parameters: {
|
|
15
|
-
include_deleted: true,
|
|
16
|
-
'users' => true,
|
|
17
|
-
'courses' => true,
|
|
18
|
-
enrollment_term_id: term.canvas_id,
|
|
19
|
-
}
|
|
20
|
-
},
|
|
21
|
-
)
|
|
8
|
+
it 'includes term_id and model parameters' do
|
|
9
|
+
task = described_class.new({ models: ['users', 'courses'], term_scope: 'active' }, {}, {})
|
|
10
|
+
allow(CanvasSync::JobBatches::Batch).to receive(:current_context).and_return({ canvas_term_id: term.canvas_id })
|
|
22
11
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
12
|
+
params = task.report_parameters
|
|
13
|
+
expect(params).to eq({
|
|
14
|
+
parameters: {
|
|
15
|
+
include_deleted: true,
|
|
16
|
+
'users' => true,
|
|
17
|
+
'courses' => true,
|
|
18
|
+
enrollment_term_id: term.canvas_id,
|
|
19
|
+
}
|
|
20
|
+
})
|
|
27
21
|
end
|
|
28
22
|
end
|
|
29
23
|
|
|
30
24
|
context 'a term scope is not specified' do
|
|
31
|
-
it '
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
'self',
|
|
35
|
-
'proservices_provisioning_csv',
|
|
36
|
-
{
|
|
37
|
-
parameters: {
|
|
38
|
-
include_deleted: true,
|
|
39
|
-
'users' => true,
|
|
40
|
-
'courses' => true,
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
)
|
|
25
|
+
it 'includes model parameters without term_id' do
|
|
26
|
+
task = described_class.new({ models: ['users', 'courses'] }, {}, {})
|
|
27
|
+
allow(CanvasSync::JobBatches::Batch).to receive(:current_context).and_return({})
|
|
44
28
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
29
|
+
params = task.report_parameters
|
|
30
|
+
expect(params).to eq({
|
|
31
|
+
parameters: {
|
|
32
|
+
include_deleted: true,
|
|
33
|
+
'users' => true,
|
|
34
|
+
'courses' => true,
|
|
35
|
+
}
|
|
36
|
+
})
|
|
48
37
|
end
|
|
49
38
|
end
|
|
50
39
|
end
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
2
|
|
|
3
|
-
RSpec.describe CanvasSync::
|
|
4
|
-
let(:subject) { CanvasSync::Processors::AssignmentGroupsProcessor }
|
|
5
|
-
|
|
3
|
+
RSpec.describe CanvasSync::Jobs::SyncAssignmentGroupsJob do
|
|
6
4
|
describe "#process" do
|
|
7
5
|
it "inserts assignment_groups" do
|
|
6
|
+
task = described_class.new({}, {}, {})
|
|
8
7
|
expect {
|
|
9
|
-
|
|
8
|
+
task.process("spec/support/fixtures/reports/assignment_groups.csv")
|
|
10
9
|
}.to change { AssignmentGroup.count }.by(2)
|
|
11
10
|
end
|
|
12
11
|
end
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
2
|
|
|
3
|
-
RSpec.describe CanvasSync::
|
|
3
|
+
RSpec.describe CanvasSync::Jobs::SyncAssignmentOverridesJob do
|
|
4
4
|
describe '#process' do
|
|
5
5
|
it 'inserts assignment overrides' do
|
|
6
|
+
task = described_class.new({}, {}, {})
|
|
6
7
|
expect {
|
|
7
|
-
|
|
8
|
+
task.process('spec/support/fixtures/reports/assignment_overrides.csv')
|
|
8
9
|
}.to change { AssignmentOverride.count }.by(2)
|
|
9
10
|
|
|
10
11
|
override = AssignmentOverride.first
|
|
@@ -23,12 +24,14 @@ RSpec.describe CanvasSync::Processors::AssignmentOverridesProcessor do
|
|
|
23
24
|
|
|
24
25
|
context 'record already present in the database' do
|
|
25
26
|
before do
|
|
26
|
-
described_class.
|
|
27
|
+
task = described_class.new({}, {}, {})
|
|
28
|
+
task.process('spec/support/fixtures/reports/assignment_overrides.csv')
|
|
27
29
|
end
|
|
28
30
|
|
|
29
31
|
it 'updates the override' do
|
|
32
|
+
task = described_class.new({}, {}, {})
|
|
30
33
|
expect {
|
|
31
|
-
|
|
34
|
+
task.process('spec/support/fixtures/reports/assignment_overrides_conflict.csv')
|
|
32
35
|
}.to change { AssignmentOverride.count }.by(0)
|
|
33
36
|
|
|
34
37
|
override = AssignmentOverride.first
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
2
|
|
|
3
|
-
RSpec.describe CanvasSync::
|
|
4
|
-
let(:subject) { CanvasSync::Processors::AssignmentsProcessor }
|
|
5
|
-
|
|
3
|
+
RSpec.describe CanvasSync::Jobs::SyncAssignmentsJob do
|
|
6
4
|
describe "#process" do
|
|
7
5
|
it "inserts assignments" do
|
|
6
|
+
task = described_class.new({}, {}, {})
|
|
8
7
|
expect {
|
|
9
|
-
|
|
8
|
+
task.process("spec/support/fixtures/reports/assignments.csv")
|
|
10
9
|
}.to change { Assignment.count }.by(2)
|
|
11
10
|
end
|
|
12
11
|
end
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
2
|
|
|
3
|
-
RSpec.describe CanvasSync::
|
|
4
|
-
let(:subject) { CanvasSync::Processors::ContentMigrationsProcessor }
|
|
5
|
-
|
|
3
|
+
RSpec.describe CanvasSync::Jobs::SyncContentMigrationsJob do
|
|
6
4
|
describe "#process" do
|
|
7
5
|
it "inserts content migrations" do
|
|
6
|
+
task = described_class.new({}, {}, {})
|
|
8
7
|
expect {
|
|
9
|
-
|
|
8
|
+
task.process("spec/support/fixtures/reports/content_migrations.csv")
|
|
10
9
|
}.to change { ContentMigration.count }.by(2)
|
|
11
10
|
end
|
|
12
11
|
end
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
2
|
|
|
3
|
-
RSpec.describe CanvasSync::
|
|
4
|
-
let(:subject) { CanvasSync::Processors::ContextModuleItemsProcessor }
|
|
5
|
-
|
|
3
|
+
RSpec.describe CanvasSync::Jobs::SyncContextModuleItemsJob do
|
|
6
4
|
describe "#process" do
|
|
7
|
-
it "inserts context
|
|
5
|
+
it "inserts context module items" do
|
|
6
|
+
task = described_class.new({}, {}, {})
|
|
8
7
|
expect {
|
|
9
|
-
|
|
8
|
+
task.process("spec/support/fixtures/reports/context_module_items.csv")
|
|
10
9
|
}.to change { ContextModuleItem.count }.by(2)
|
|
11
10
|
end
|
|
12
11
|
end
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
2
|
|
|
3
|
-
RSpec.describe CanvasSync::
|
|
4
|
-
let(:subject) { CanvasSync::Processors::ContextModulesProcessor }
|
|
5
|
-
|
|
3
|
+
RSpec.describe CanvasSync::Jobs::SyncContextModulesJob do
|
|
6
4
|
describe "#process" do
|
|
7
5
|
it "inserts context modules" do
|
|
6
|
+
task = described_class.new({}, {}, {})
|
|
8
7
|
expect {
|
|
9
|
-
|
|
8
|
+
task.process("spec/support/fixtures/reports/context_modules.csv")
|
|
10
9
|
}.to change { ContextModule.count }.by(2)
|
|
11
10
|
expect(ContextModule.last).to have_attributes(
|
|
12
11
|
canvas_id: 23,
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
2
|
|
|
3
|
-
RSpec.describe CanvasSync::
|
|
3
|
+
RSpec.describe CanvasSync::Jobs::SyncCourseProgressesJob do
|
|
4
4
|
|
|
5
5
|
describe '#process' do
|
|
6
6
|
it 'inserts course progresses' do
|
|
7
|
+
task = described_class.new({}, {}, {})
|
|
7
8
|
expect {
|
|
8
|
-
|
|
9
|
+
task.process('spec/support/fixtures/reports/course_progresses.csv')
|
|
9
10
|
}.to change { CourseProgress.count }.by(2)
|
|
10
11
|
cp = CourseProgress.first
|
|
11
12
|
expect(cp).to have_attributes(
|
|
@@ -26,12 +27,14 @@ RSpec.describe CanvasSync::Processors::CourseCompletionReportProcessor do
|
|
|
26
27
|
|
|
27
28
|
context 'record already present in the database' do
|
|
28
29
|
before do
|
|
29
|
-
described_class.
|
|
30
|
+
task = described_class.new({}, {}, {})
|
|
31
|
+
task.process('spec/support/fixtures/reports/course_progresses.csv')
|
|
30
32
|
end
|
|
31
33
|
|
|
32
34
|
it 'updates the course progress' do
|
|
35
|
+
task = described_class.new({}, {}, {})
|
|
33
36
|
expect {
|
|
34
|
-
|
|
37
|
+
task.process('spec/support/fixtures/reports/course_progresses_conflict.csv')
|
|
35
38
|
}.to change { CourseProgress.count }.by(0)
|
|
36
39
|
cp = CourseProgress.first
|
|
37
40
|
expect(cp).to have_attributes(
|