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
@@ -4,11 +4,10 @@ module CanvasSync
4
4
  # Syncs Admins using the Canvas API
5
5
  #
6
6
  #
7
- # @param job_chain [Hash]
8
7
  # @param options [Hash]
9
- def perform(job_chain, _options)
8
+ def perform(options)
10
9
  updated_admin_ids = []
11
- api_client = CanvasSync.get_canvas_sync_client(job_chain[:global_options])
10
+ api_client = CanvasSync.get_canvas_sync_client(batch_context)
12
11
  CanvasSync.sync_scope(Account).find_each do |acc|
13
12
  api_client.account_admins(acc.canvas_id).all_pages_each do |admin_params|
14
13
  admin_params[:account_id] = acc.canvas_id
@@ -17,7 +16,6 @@ module CanvasSync
17
16
  end
18
17
  end
19
18
  Admin.where.not(id: updated_admin_ids).update_all(workflow_state: 'inactive')
20
- CanvasSync.invoke_next(job_chain)
21
19
  end
22
20
  end
23
21
  end
@@ -6,13 +6,11 @@ module CanvasSync
6
6
  # Starts a report processor for the assignment_groups report
7
7
  # (the proserv_assignment_group_export_csv report must be enabled)
8
8
  #
9
- # @param job_chain [Hash]
10
9
  # @param options [Hash]
11
- def perform(job_chain, options)
10
+ def perform(options)
12
11
  super(
13
- job_chain,
14
12
  "proserv_assignment_group_export_csv",
15
- merge_report_params(job_chain, options),
13
+ merge_report_params(options),
16
14
  CanvasSync::Processors::AssignmentGroupsProcessor.to_s,
17
15
  {},
18
16
  )
@@ -6,13 +6,11 @@ module CanvasSync
6
6
  # Starts a report processor for the assignment report
7
7
  # (the proserv_assignment_export_csv report must be enabled)
8
8
  #
9
- # @param job_chain [Hash]
10
9
  # @param options [Hash]
11
- def perform(job_chain, options)
10
+ def perform(options)
12
11
  super(
13
- job_chain,
14
12
  "proserv_assignment_export_csv",
15
- merge_report_params(job_chain, options),
13
+ merge_report_params(options),
16
14
  CanvasSync::Processors::AssignmentsProcessor.to_s,
17
15
  {},
18
16
  )
@@ -6,13 +6,11 @@ module CanvasSync
6
6
  # Starts a report processor for the context modules report
7
7
  # (the proserv_context_module_items_csv report must be enabled)
8
8
  #
9
- # @param job_chain [Hash]
10
9
  # @param options [Hash]
11
- def perform(job_chain, options)
10
+ def perform(options)
12
11
  super(
13
- job_chain,
14
12
  "proserv_context_module_items_csv",
15
- merge_report_params(job_chain, options),
13
+ merge_report_params(options),
16
14
  CanvasSync::Processors::ContextModuleItemsProcessor.to_s,
17
15
  {},
18
16
  )
@@ -6,13 +6,11 @@ module CanvasSync
6
6
  # Starts a report processor for the context modules report
7
7
  # (the proserv_context_modules_csv report must be enabled)
8
8
  #
9
- # @param job_chain [Hash]
10
9
  # @param options [Hash]
11
- def perform(job_chain, options)
10
+ def perform(options)
12
11
  super(
13
- job_chain,
14
12
  "proserv_context_modules_csv",
15
- merge_report_params(job_chain, options),
13
+ merge_report_params(options),
16
14
  CanvasSync::Processors::ContextModulesProcessor.to_s,
17
15
  {},
18
16
  )
@@ -2,40 +2,14 @@ module CanvasSync
2
2
  module Jobs
3
3
  # ActiveJob class that starts a Canvas provisioning report
4
4
  class SyncProvisioningReportJob < CanvasSync::Job
5
- # @param job_chain [Hash]
6
- # @param options [Hash] If options contains a :term_scope a seperate provisioning report
7
- # will be started for each term in that scope. :models should be an array of
8
- # models to sync.
9
- def perform(job_chain, options)
10
- if options[:term_scope]
11
- sub_reports = CanvasSync.fork(@job_log, job_chain, keys: [:canvas_term_id]) do |job_chain|
12
- Term.send(options[:term_scope]).find_each.map do |term|
13
- # Deep copy the job_chain so each report gets the correct term id passed into
14
- # its options with no side effects
15
- term_id = get_term_id(term)
16
- duped_job_chain = Marshal.load(Marshal.dump(job_chain))
17
- duped_job_chain[:global_options][:canvas_term_id] = term_id
18
- {
19
- job_chain: duped_job_chain,
20
- params: report_params(options, term_id),
21
- options: options,
22
- }
23
- end
24
- end
25
-
26
- sub_reports.each do |r|
27
- start_report(r[:params], r[:job_chain], r[:options])
28
- end
29
- else
30
- start_report(report_params(options), job_chain, options)
31
- end
5
+ def perform(options)
6
+ start_report(report_params(options), options)
32
7
  end
33
8
 
34
- private
9
+ protected
35
10
 
36
- def start_report(report_params, job_chain, options)
11
+ def start_report(report_params, options)
37
12
  CanvasSync::Jobs::ReportStarter.perform_later(
38
- job_chain,
39
13
  "proservices_provisioning_csv",
40
14
  report_params,
41
15
  CanvasSync::Processors::ProvisioningReportProcessor.to_s,
@@ -43,7 +17,7 @@ module CanvasSync
43
17
  )
44
18
  end
45
19
 
46
- def report_params(options, canvas_term_id=nil)
20
+ def report_params(options, canvas_term_id = options[:canvas_term_id] || batch_context[:canvas_term_id])
47
21
  params = {
48
22
  include_deleted: true,
49
23
  }
@@ -60,10 +34,6 @@ module CanvasSync
60
34
 
61
35
  { parameters: params }
62
36
  end
63
-
64
- def get_term_id(term)
65
- term.try(:canvas_id) || term.canvas_term_id
66
- end
67
37
  end
68
38
  end
69
39
  end
@@ -3,12 +3,10 @@ module CanvasSync
3
3
  class SyncRolesJob < CanvasSync::Job
4
4
  # Syncs Roles using the Canvas API
5
5
  #
6
- #
7
- # @param job_chain [Hash]
8
6
  # @param options [Hash]
9
- def perform(job_chain, _options)
7
+ def perform(options)
10
8
  updated_role_ids = []
11
- api_client = CanvasSync.get_canvas_sync_client(job_chain[:global_options])
9
+ api_client = CanvasSync.get_canvas_sync_client(batch_context)
12
10
  CanvasSync.sync_scope(Account).find_each do |acc|
13
11
  api_client.list_roles(acc.canvas_id, state: %w[active inactive]).all_pages_each do |role_params|
14
12
  role = update_or_create_model(Role, role_params)
@@ -16,7 +14,6 @@ module CanvasSync
16
14
  end
17
15
  end
18
16
  Role.where.not(id: updated_role_ids).update_all(workflow_state: 'inactive')
19
- CanvasSync.invoke_next(job_chain)
20
17
  end
21
18
  end
22
19
  end
@@ -5,36 +5,19 @@ module CanvasSync
5
5
  # Starts a report processor for the specified report
6
6
  # (the specified report must be enabled)
7
7
  #
8
- # @param job_chain [Hash]
9
- # @param options [Hash]
10
- def perform(job_chain, options)
11
- if options[:term_scope]
12
- sub_reports = CanvasSync.fork(@job_log, job_chain, keys: [:canvas_term_id]) do |job_chain|
13
- Term.send(options[:term_scope]).find_each.map do |term|
14
- # Deep copy the job_chain so each report gets the correct term id passed into
15
- # its options with no side effects
16
- term_id = get_term_id(term)
17
- duped_job_chain = Marshal.load(Marshal.dump(job_chain))
18
- duped_job_chain[:global_options][:canvas_term_id] = term_id
19
- {
20
- job_chain: duped_job_chain,
21
- params: report_params(options, term_id),
22
- options: options,
23
- }
24
- end
25
- end
26
-
27
- sub_reports.each do |r|
28
- start_report(r[:params], r[:job_chain], r[:options])
29
- end
30
- else
31
- start_report(report_params(options), job_chain, options)
32
- end
8
+ # @param options [Hash] {
9
+ # report_name: "", # Name of the report in the Canvas API
10
+ # model: , # Model to map the report results as
11
+ # mapping: {} # Mapping to describe how to convert the report to the Model,
12
+ # klass: ,
13
+ # params: {}, # List of params to pass to the report
14
+ # }
15
+ def perform(options)
16
+ start_report(report_params(options), options)
33
17
  end
34
18
 
35
- def start_report(params, job_chain, options)
19
+ def start_report(params, options)
36
20
  CanvasSync::Jobs::ReportStarter.perform_later(
37
- job_chain,
38
21
  options[:report_name],
39
22
  params,
40
23
  CanvasSync::Processors::NormalProcessor.to_s,
@@ -42,15 +25,11 @@ module CanvasSync
42
25
  )
43
26
  end
44
27
 
45
- def report_params(options, canvas_term_id=nil)
28
+ def report_params(options, canvas_term_id = options[:canvas_term_id] || batch_context[:canvas_term_id])
46
29
  params = options[:params] || {}
47
30
  params["parameters[enrollment_term_id]"] = canvas_term_id if canvas_term_id
48
31
  params
49
32
  end
50
-
51
- def get_term_id(term)
52
- term.try(:canvas_id) || term.canvas_term_id
53
- end
54
33
  end
55
34
  end
56
35
  end
@@ -6,13 +6,11 @@ module CanvasSync
6
6
  # Starts a report processor for the submission report
7
7
  # (the proserv_student_submissions_csv report must be enabled)
8
8
  #
9
- # @param job_chain [Hash]
10
9
  # @param options [Hash]
11
- def perform(job_chain, options)
10
+ def perform(options)
12
11
  super(
13
- job_chain,
14
12
  "proserv_student_submissions_csv",
15
- merge_report_params(job_chain, options, { include_all: options[:include_all] }, {}),
13
+ merge_report_params(options, { include_all: options[:include_all] }, {}),
16
14
  CanvasSync::Processors::SubmissionsProcessor.to_s,
17
15
  {},
18
16
  )
@@ -5,16 +5,17 @@ module CanvasSync
5
5
  #
6
6
  # Terms are pre-synced so that provisioning reports can be scoped to term.
7
7
  #
8
- # @param job_chain [Hash]
9
- # @param options [Hash]
10
- def perform(job_chain, _options)
11
- CanvasSync.get_canvas_sync_client(job_chain[:global_options]).terms("self").all_pages!.each do |term_params|
12
- if job_chain[:global_options][:account_id]
8
+ # @param options [Hash] If options contains a :term_scope a seperate provisioning report
9
+ # will be started for each term in that scope. :models should be an array of
10
+ # models to sync.
11
+ def perform(options)
12
+ CanvasSync.get_canvas_sync_client(batch_context).terms("self").all_pages!.each do |term_params|
13
+ if account_id = batch_context[:account_id]
13
14
  # These branches are primarily to support Legacy apps
14
15
  if Term.respond_to?(:create_or_update) && Term.method(:create_or_update).arity.abs == 2
15
- Term.create_or_update(term_params, job_chain[:global_options][:account_id])
16
+ Term.create_or_update(term_params, account_id)
16
17
  else
17
- term_params[:account_id] |= job_chain[:global_options][:account_id]
18
+ term_params[:account_id] |= account_id
18
19
  update_or_create_model(Term, term_params)
19
20
  end
20
21
  else
@@ -22,7 +23,23 @@ module CanvasSync
22
23
  end
23
24
  end
24
25
 
25
- CanvasSync.invoke_next(job_chain)
26
+ if (jobs = options[:sub_jobs]).present?
27
+ context = options[:context] || {}
28
+ if options[:term_scope]
29
+ Term.send(options[:term_scope]).find_each.map do |term|
30
+ local_context = context.merge(canvas_term_id: get_term_id(term))
31
+ JobBatches::ConcurrentBatchJob.perform_now(jobs, context: local_context)
32
+ end
33
+ else
34
+ JobBatches::ConcurrentBatchJob.perform_now(jobs, context: context)
35
+ end
36
+ end
37
+ end
38
+
39
+ protected
40
+
41
+ def get_term_id(term)
42
+ term.try(:canvas_id) || term.canvas_term_id
26
43
  end
27
44
  end
28
45
  end
@@ -0,0 +1,15 @@
1
+ require 'active_record'
2
+
3
+ module CanvasSync
4
+ module MiscHelper
5
+ MigrationClass = Rails.version < '5.0' ? ActiveRecord::Migration : ActiveRecord::Migration[4.2]
6
+
7
+ def self.to_boolean(v)
8
+ if Rails.version < '5.0'
9
+ ActiveRecord::Type::Boolean.new.type_cast_from_user(v)
10
+ else
11
+ ActiveRecord::Type::Boolean.new.deserialize(v)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,3 +1,3 @@
1
1
  module CanvasSync
2
- VERSION = "0.16.2".freeze
2
+ VERSION = "0.17.0.beta3".freeze
3
3
  end
@@ -3,13 +3,12 @@ require 'spec_helper'
3
3
  RSpec.describe CanvasSync do
4
4
  describe '.provisioning_sync' do
5
5
  it 'invokes the first job in the queue and passes on the rest of the job chain' do
6
- expected_job_chain = CanvasSync.default_provisioning_report_chain(['courses'], nil).chain_data
7
- first_job = expected_job_chain[:jobs].shift
6
+ expected_job_chain = CanvasSync.default_provisioning_report_chain(['courses'], term_scope: nil).normalize![:parameters][0]
8
7
 
9
- expect(CanvasSync::Jobs::SyncTermsJob).to receive(:perform_later)
8
+ expect(CanvasSync::Jobs::BeginSyncChainJob).to receive(:perform_later)
10
9
  .with(
11
10
  expected_job_chain,
12
- first_job[:options]
11
+ anything
13
12
  )
14
13
 
15
14
  CanvasSync.provisioning_sync(['courses'])
@@ -25,32 +24,44 @@ RSpec.describe CanvasSync do
25
24
 
26
25
  describe '.default_provisioning_report_chain' do
27
26
  it 'splits an options: Hash into options for separate models' do
28
- chain = CanvasSync.default_provisioning_report_chain(['users', 'courses'], :active, options: {
27
+ chain = CanvasSync.default_provisioning_report_chain(['users', 'courses'], term_scope: :active, options: {
29
28
  terms: { a: 1 },
30
29
  users: { b: 2 },
31
30
  provisioning: { c: 3 },
32
31
  global: { d: 4 },
33
32
  })
34
- expect(chain.chain_data).to eq({
35
- jobs: [
36
- { job: CanvasSync::Jobs::SyncTermsJob.to_s, options: { a: 1 } },
37
- { job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s, options: { models: ['users'], b: 2 } },
38
- { job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s, options: { term_scope: 'active', models: ['courses'], c: 3 } }
39
- ],
40
- global_options: { legacy_support: false, d: 4 }
33
+ expect(chain.normalize!).to eq({
34
+ :job => "CanvasSync::Jobs::BeginSyncChainJob",
35
+ :parameters => [[
36
+ {:job=>"CanvasSync::JobBatches::ConcurrentBatchJob", :parameters=>[[
37
+ {:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["users"], :b=>2}},
38
+ {:job=>"CanvasSync::Jobs::SyncTermsJob", :parameters=>[{
39
+ :term_scope=>"active",
40
+ :sub_jobs=>[
41
+ {:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["courses"], :c=>3}}
42
+ ]
43
+ }]}
44
+ ]]}
45
+ ], {:legacy_support=>false, :updated_after=>nil, :d=>4}],
41
46
  })
42
47
  end
43
48
 
44
49
  context 'we are syncing users with a term scope' do
45
50
  it 'syncs the users in a separate job that runs first' do
46
- chain = CanvasSync.default_provisioning_report_chain(['users', 'courses'], :active)
47
- expect(chain.chain_data).to eq({
48
- jobs: [
49
- { job: CanvasSync::Jobs::SyncTermsJob.to_s, options: {} },
50
- { job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s, options: { models: ['users'] } },
51
- { job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s, options: { term_scope: 'active', models: ['courses'] } }
52
- ],
53
- global_options: { legacy_support: false }
51
+ chain = CanvasSync.default_provisioning_report_chain(['users', 'courses'], term_scope: :active)
52
+ expect(chain.normalize!).to eq({
53
+ :job => "CanvasSync::Jobs::BeginSyncChainJob",
54
+ :parameters => [[
55
+ {:job=>"CanvasSync::JobBatches::ConcurrentBatchJob", :parameters=>[[
56
+ {:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["users"]}},
57
+ {:job=>"CanvasSync::Jobs::SyncTermsJob", :parameters=>[{
58
+ :term_scope=>"active",
59
+ :sub_jobs=>[
60
+ {:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["courses"]}}
61
+ ]
62
+ }]}
63
+ ]]}
64
+ ], {:legacy_support=>false, :updated_after=>nil}]
54
65
  })
55
66
  end
56
67
  end
@@ -58,26 +69,38 @@ RSpec.describe CanvasSync do
58
69
  context 'we are syncing users without a term scope' do
59
70
  it 'syncs users along with the rest of the provisioning report' do
60
71
  chain = CanvasSync.default_provisioning_report_chain(['users', 'courses'])
61
- expect(chain.chain_data).to eq({
62
- jobs: [
63
- { job: CanvasSync::Jobs::SyncTermsJob.to_s, options: {} },
64
- { job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s, options: { term_scope: nil, models: ['users', 'courses'] } }
65
- ],
66
- global_options: { legacy_support: false }
72
+ expect(chain.normalize!).to eq({
73
+ :job => "CanvasSync::Jobs::BeginSyncChainJob",
74
+ :parameters => [[
75
+ {:job=>"CanvasSync::JobBatches::ConcurrentBatchJob", :parameters=>[[
76
+ {:job=>"CanvasSync::Jobs::SyncTermsJob", :parameters=>[{
77
+ :term_scope=>nil,
78
+ :sub_jobs=>[
79
+ {:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["users", "courses"]}}
80
+ ]
81
+ }]}
82
+ ]]}
83
+ ], {:legacy_support=>false, :updated_after=>nil}],
67
84
  })
68
85
  end
69
86
  end
70
87
 
71
88
  context 'we are syncing roles with a term scope' do
72
89
  it 'syncs the roles in a separate job that runs first' do
73
- chain = CanvasSync.default_provisioning_report_chain(['roles', 'courses'], :active)
74
- expect(chain.chain_data).to eq({
75
- jobs: [
76
- { job: CanvasSync::Jobs::SyncTermsJob.to_s, options: {} },
77
- { job: CanvasSync::Jobs::SyncRolesJob.to_s, options: {} },
78
- { job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s, options: { term_scope: 'active', models: ['courses'] } }
79
- ],
80
- global_options: { legacy_support: false }
90
+ chain = CanvasSync.default_provisioning_report_chain(['roles', 'courses'], term_scope: :active)
91
+ expect(chain.normalize!).to eq({
92
+ :job => "CanvasSync::Jobs::BeginSyncChainJob",
93
+ :parameters => [[
94
+ {:job=>"CanvasSync::JobBatches::ConcurrentBatchJob", :parameters=>[[
95
+ {:job=>"CanvasSync::Jobs::SyncRolesJob", :options=>{}},
96
+ {:job=>"CanvasSync::Jobs::SyncTermsJob", :parameters=>[{
97
+ :term_scope=>"active",
98
+ :sub_jobs=>[
99
+ {:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["courses"]}}
100
+ ]
101
+ }]}
102
+ ]]}
103
+ ], {:legacy_support=>false, :updated_after=>nil}],
81
104
  })
82
105
  end
83
106
  end
@@ -85,27 +108,39 @@ RSpec.describe CanvasSync do
85
108
  context 'we are syncing roles without a term scope' do
86
109
  it 'syncs roles separately even with no term scope' do
87
110
  chain = CanvasSync.default_provisioning_report_chain(['roles', 'courses'])
88
- expect(chain.chain_data).to eq({
89
- jobs: [
90
- { job: CanvasSync::Jobs::SyncTermsJob.to_s, options: {} },
91
- { job: CanvasSync::Jobs::SyncRolesJob.to_s, options: {} },
92
- { job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s, options: { term_scope: nil, models: ['courses'] } }
93
- ],
94
- global_options: { legacy_support: false }
111
+ expect(chain.normalize!).to eq({
112
+ :job => "CanvasSync::Jobs::BeginSyncChainJob",
113
+ :parameters => [[
114
+ {:job=>"CanvasSync::JobBatches::ConcurrentBatchJob", :parameters=>[[
115
+ {:job=>"CanvasSync::Jobs::SyncRolesJob", :options=>{}},
116
+ {:job=>"CanvasSync::Jobs::SyncTermsJob", :parameters=>[{
117
+ :term_scope=>nil,
118
+ :sub_jobs=>[
119
+ {:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["courses"]}}
120
+ ]
121
+ }]}
122
+ ]]}
123
+ ], {:legacy_support=>false, :updated_after=>nil}],
95
124
  })
96
125
  end
97
126
  end
98
127
 
99
128
  context 'we are syncing admins with a term scope' do
100
129
  it 'syncs the admins in a separate job that runs first' do
101
- chain = CanvasSync.default_provisioning_report_chain(['admins', 'courses'], :active)
102
- expect(chain.chain_data).to eq({
103
- jobs: [
104
- { job: CanvasSync::Jobs::SyncTermsJob.to_s, options: {} },
105
- { job: CanvasSync::Jobs::SyncAdminsJob.to_s, options: {} },
106
- { job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s, options: { term_scope: 'active', models: ['courses'] } }
107
- ],
108
- global_options: { legacy_support: false }
130
+ chain = CanvasSync.default_provisioning_report_chain(['admins', 'courses'], term_scope: :active)
131
+ expect(chain.normalize!).to eq({
132
+ :job => "CanvasSync::Jobs::BeginSyncChainJob",
133
+ :parameters => [[
134
+ {:job=>"CanvasSync::JobBatches::ConcurrentBatchJob", :parameters=>[[
135
+ {:job=>"CanvasSync::Jobs::SyncAdminsJob", :options=>{}},
136
+ {:job=>"CanvasSync::Jobs::SyncTermsJob", :parameters=>[{
137
+ :term_scope=>"active",
138
+ :sub_jobs=>[
139
+ {:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["courses"]}}
140
+ ]
141
+ }]}
142
+ ]]}
143
+ ], {:legacy_support=>false, :updated_after=>nil}],
109
144
  })
110
145
  end
111
146
  end
@@ -113,13 +148,19 @@ RSpec.describe CanvasSync do
113
148
  context 'we are syncing admins without a term scope' do
114
149
  it 'syncs admins separately even with no term scope' do
115
150
  chain = CanvasSync.default_provisioning_report_chain(['admins', 'courses'])
116
- expect(chain.chain_data).to eq({
117
- jobs: [
118
- { job: CanvasSync::Jobs::SyncTermsJob.to_s, options: {} },
119
- { job: CanvasSync::Jobs::SyncAdminsJob.to_s, options: {} },
120
- { job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s, options: { term_scope: nil, models: ['courses'] } }
121
- ],
122
- global_options: { legacy_support: false }
151
+ expect(chain.normalize!).to eq({
152
+ :job => "CanvasSync::Jobs::BeginSyncChainJob",
153
+ :parameters => [[
154
+ {:job=>"CanvasSync::JobBatches::ConcurrentBatchJob", :parameters=>[[
155
+ {:job=>"CanvasSync::Jobs::SyncAdminsJob", :options=>{}},
156
+ {:job=>"CanvasSync::Jobs::SyncTermsJob", :parameters=>[{
157
+ :term_scope=>nil,
158
+ :sub_jobs=>[
159
+ {:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["courses"]}}
160
+ ]
161
+ }]}
162
+ ]]}
163
+ ], {:legacy_support=>false, :updated_after=>nil}],
123
164
  })
124
165
  end
125
166
  end
@@ -128,13 +169,19 @@ RSpec.describe CanvasSync do
128
169
  it "appends the SyncAssignmentsJob" do
129
170
  chain = CanvasSync.default_provisioning_report_chain(%w[users enrollments assignments])
130
171
 
131
- expect(chain.chain_data).to eq(
132
- jobs: [
133
- { job: CanvasSync::Jobs::SyncTermsJob.to_s, options: {} },
134
- { job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s, options: { term_scope: nil, models: %w[users enrollments] } },
135
- { job: CanvasSync::Jobs::SyncAssignmentsJob.to_s, options: {} },
136
- ],
137
- global_options: { legacy_support: false },
172
+ expect(chain.normalize!).to eq(
173
+ :job => "CanvasSync::Jobs::BeginSyncChainJob",
174
+ :parameters => [[
175
+ {:job=>"CanvasSync::JobBatches::ConcurrentBatchJob", :parameters=>[[
176
+ {:job=>"CanvasSync::Jobs::SyncTermsJob", :parameters=>[{
177
+ :term_scope=>nil,
178
+ :sub_jobs=>[
179
+ {:job=>"CanvasSync::Jobs::SyncAssignmentsJob", :options=>{}},
180
+ {:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["users", "enrollments"]}}
181
+ ]
182
+ }]}
183
+ ]]}
184
+ ], {:legacy_support=>false, :updated_after=>nil}],
138
185
  )
139
186
  end
140
187
  end
@@ -143,13 +190,19 @@ RSpec.describe CanvasSync do
143
190
  it "appends the SyncSubmissionsJob" do
144
191
  chain = CanvasSync.default_provisioning_report_chain(%w[users enrollments submissions])
145
192
 
146
- expect(chain.chain_data).to eq(
147
- jobs: [
148
- { job: CanvasSync::Jobs::SyncTermsJob.to_s, options: {} },
149
- { job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s, options: { term_scope: nil, models: %w[users enrollments] } },
150
- { job: CanvasSync::Jobs::SyncSubmissionsJob.to_s, options: {} },
151
- ],
152
- global_options: { legacy_support: false },
193
+ expect(chain.normalize!).to eq(
194
+ :job => "CanvasSync::Jobs::BeginSyncChainJob",
195
+ :parameters => [[
196
+ {:job=>"CanvasSync::JobBatches::ConcurrentBatchJob", :parameters=>[[
197
+ {:job=>"CanvasSync::Jobs::SyncTermsJob", :parameters=>[{
198
+ :term_scope=>nil,
199
+ :sub_jobs=>[
200
+ {:job=>"CanvasSync::Jobs::SyncSubmissionsJob", :options=>{}},
201
+ {:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["users", "enrollments"]}}
202
+ ]
203
+ }]}
204
+ ]]}
205
+ ], {:legacy_support=>false, :updated_after=>nil}],
153
206
  )
154
207
  end
155
208
  end
@@ -158,95 +211,25 @@ RSpec.describe CanvasSync do
158
211
  it "appends the SyncAssignmentGroupsJob" do
159
212
  chain = CanvasSync.default_provisioning_report_chain(%w[users enrollments assignment_groups])
160
213
 
161
- expect(chain.chain_data).to eq(
162
- jobs: [
163
- { job: CanvasSync::Jobs::SyncTermsJob.to_s, options: {} },
164
- { job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s, options: { term_scope: nil, models: %w[users enrollments] } },
165
- { job: CanvasSync::Jobs::SyncAssignmentGroupsJob.to_s, options: {} },
166
- ],
167
- global_options: { legacy_support: false },
214
+ expect(chain.normalize!).to eq(
215
+ :job => "CanvasSync::Jobs::BeginSyncChainJob",
216
+ :parameters => [[
217
+ {:job=>"CanvasSync::JobBatches::ConcurrentBatchJob", :parameters=>[[
218
+ {:job=>"CanvasSync::Jobs::SyncTermsJob", :parameters=>[{
219
+ :term_scope=>nil,
220
+ :sub_jobs=>[
221
+ {:job=>"CanvasSync::Jobs::SyncAssignmentGroupsJob", :options=>{}},
222
+ {:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["users", "enrollments"]}}
223
+ ]
224
+ }]}
225
+ ]]}
226
+ ], {:legacy_support=>false, :updated_after=>nil}],
168
227
  )
169
228
  end
170
229
  end
171
230
  end
172
231
  end
173
232
 
174
- describe ".simple_report_sync" do
175
-
176
- it 'invokes the first job in the queue and passes on the rest of the job chain' do
177
- expected_job_chain = CanvasSync.simple_report_chain(
178
- [
179
- {
180
- report_name: 'proservices_provisioning_csv',
181
- model: 'users',
182
- params: {
183
- "parameters[include_deleted]" => true,
184
- "parameters[users]" => true
185
- }
186
- }
187
- ]
188
- ).chain_data
189
- first_job = expected_job_chain[:jobs].shift
190
-
191
- expect(CanvasSync::Jobs::SyncSimpleTableJob).to receive(:perform_later)
192
- .with(
193
- expected_job_chain,
194
- first_job[:options]
195
- )
196
-
197
- CanvasSync.simple_report_sync(
198
- [
199
- {
200
- report_name: 'proservices_provisioning_csv',
201
- model: 'users',
202
- params: {
203
- "parameters[include_deleted]" => true,
204
- "parameters[users]" => true
205
- }
206
- }
207
- ]
208
- )
209
- end
210
-
211
- it 'receives the job chain for the specified table' do
212
- chain = CanvasSync.simple_report_chain(
213
- [
214
- {
215
- report_name: 'proservices_provisioning_csv',
216
- model: 'users',
217
- params: {
218
- "parameters[include_deleted]" => true,
219
- "parameters[users]" => true
220
- }
221
- }
222
- ]
223
- )
224
-
225
- expected_job_chain = {
226
- jobs: [
227
- {
228
- job: CanvasSync::Jobs::SyncSimpleTableJob.to_s,
229
- options: {
230
- report_name: 'proservices_provisioning_csv',
231
- model: 'users',
232
- mapping: 'users',
233
- klass: 'User',
234
- term_scope: nil,
235
- params: {
236
- "parameters[include_deleted]" => true,
237
- "parameters[users]" => true
238
- }
239
- }
240
- }
241
- ],
242
- global_options: {}
243
- }
244
-
245
- expect(chain.chain_data).to eq(expected_job_chain)
246
-
247
- end
248
- end
249
-
250
233
  describe ".sync_scope" do
251
234
 
252
235
  end