canvas_sync 0.16.4 → 0.17.0.beta1

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 (76) 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 +35 -118
  9. data/lib/canvas_sync/job.rb +5 -5
  10. data/lib/canvas_sync/job_batches/batch.rb +399 -0
  11. data/lib/canvas_sync/job_batches/batch_aware_job.rb +62 -0
  12. data/lib/canvas_sync/job_batches/callback.rb +153 -0
  13. data/lib/canvas_sync/job_batches/chain_builder.rb +203 -0
  14. data/lib/canvas_sync/job_batches/context_hash.rb +147 -0
  15. data/lib/canvas_sync/job_batches/jobs/base_job.rb +7 -0
  16. data/lib/canvas_sync/job_batches/jobs/concurrent_batch_job.rb +18 -0
  17. data/lib/canvas_sync/job_batches/jobs/serial_batch_job.rb +73 -0
  18. data/lib/canvas_sync/job_batches/sidekiq.rb +91 -0
  19. data/lib/canvas_sync/job_batches/status.rb +63 -0
  20. data/lib/canvas_sync/jobs/begin_sync_chain_job.rb +34 -0
  21. data/lib/canvas_sync/jobs/report_checker.rb +3 -6
  22. data/lib/canvas_sync/jobs/report_processor_job.rb +2 -5
  23. data/lib/canvas_sync/jobs/report_starter.rb +27 -19
  24. data/lib/canvas_sync/jobs/sync_accounts_job.rb +3 -5
  25. data/lib/canvas_sync/jobs/sync_admins_job.rb +2 -4
  26. data/lib/canvas_sync/jobs/sync_assignment_groups_job.rb +2 -4
  27. data/lib/canvas_sync/jobs/sync_assignments_job.rb +2 -4
  28. data/lib/canvas_sync/jobs/sync_context_module_items_job.rb +2 -4
  29. data/lib/canvas_sync/jobs/sync_context_modules_job.rb +2 -4
  30. data/lib/canvas_sync/jobs/sync_provisioning_report_job.rb +4 -31
  31. data/lib/canvas_sync/jobs/sync_roles_job.rb +2 -5
  32. data/lib/canvas_sync/jobs/sync_simple_table_job.rb +11 -32
  33. data/lib/canvas_sync/jobs/sync_submissions_job.rb +2 -4
  34. data/lib/canvas_sync/jobs/sync_terms_job.rb +22 -7
  35. data/lib/canvas_sync/misc_helper.rb +15 -0
  36. data/lib/canvas_sync/version.rb +1 -1
  37. data/spec/canvas_sync/canvas_sync_spec.rb +126 -153
  38. data/spec/canvas_sync/jobs/job_spec.rb +9 -17
  39. data/spec/canvas_sync/jobs/report_checker_spec.rb +1 -3
  40. data/spec/canvas_sync/jobs/report_processor_job_spec.rb +0 -3
  41. data/spec/canvas_sync/jobs/report_starter_spec.rb +19 -28
  42. data/spec/canvas_sync/jobs/sync_admins_job_spec.rb +1 -4
  43. data/spec/canvas_sync/jobs/sync_assignment_groups_job_spec.rb +2 -1
  44. data/spec/canvas_sync/jobs/sync_assignments_job_spec.rb +3 -2
  45. data/spec/canvas_sync/jobs/sync_context_module_items_job_spec.rb +3 -2
  46. data/spec/canvas_sync/jobs/sync_context_modules_job_spec.rb +3 -2
  47. data/spec/canvas_sync/jobs/sync_provisioning_report_job_spec.rb +3 -35
  48. data/spec/canvas_sync/jobs/sync_roles_job_spec.rb +1 -4
  49. data/spec/canvas_sync/jobs/sync_simple_table_job_spec.rb +5 -12
  50. data/spec/canvas_sync/jobs/sync_submissions_job_spec.rb +2 -1
  51. data/spec/canvas_sync/jobs/sync_terms_job_spec.rb +1 -4
  52. data/spec/dummy/app/models/account.rb +3 -0
  53. data/spec/dummy/app/models/pseudonym.rb +14 -0
  54. data/spec/dummy/app/models/submission.rb +1 -0
  55. data/spec/dummy/app/models/user.rb +1 -0
  56. data/spec/dummy/config/environments/test.rb +2 -0
  57. data/spec/dummy/db/migrate/20201016181346_create_pseudonyms.rb +24 -0
  58. data/spec/dummy/db/schema.rb +24 -4
  59. data/spec/job_batching/batch_aware_job_spec.rb +100 -0
  60. data/spec/job_batching/batch_spec.rb +363 -0
  61. data/spec/job_batching/callback_spec.rb +38 -0
  62. data/spec/job_batching/flow_spec.rb +91 -0
  63. data/spec/job_batching/integration/integration.rb +57 -0
  64. data/spec/job_batching/integration/nested.rb +88 -0
  65. data/spec/job_batching/integration/simple.rb +47 -0
  66. data/spec/job_batching/integration/workflow.rb +134 -0
  67. data/spec/job_batching/integration_helper.rb +48 -0
  68. data/spec/job_batching/sidekiq_spec.rb +124 -0
  69. data/spec/job_batching/status_spec.rb +92 -0
  70. data/spec/job_batching/support/base_job.rb +14 -0
  71. data/spec/job_batching/support/sample_callback.rb +2 -0
  72. data/spec/spec_helper.rb +10 -0
  73. metadata +90 -8
  74. data/lib/canvas_sync/job_chain.rb +0 -57
  75. data/lib/canvas_sync/jobs/fork_gather.rb +0 -59
  76. 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,17 @@ 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
5
  # @param options [Hash] If options contains a :term_scope a seperate provisioning report
7
6
  # will be started for each term in that scope. :models should be an array of
8
7
  # 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
8
+ def perform(options)
9
+ start_report(report_params(options), options)
32
10
  end
33
11
 
34
12
  protected
35
13
 
36
- def start_report(report_params, job_chain, options)
14
+ def start_report(report_params, options)
37
15
  CanvasSync::Jobs::ReportStarter.perform_later(
38
- job_chain,
39
16
  "proservices_provisioning_csv",
40
17
  report_params,
41
18
  CanvasSync::Processors::ProvisioningReportProcessor.to_s,
@@ -43,7 +20,7 @@ module CanvasSync
43
20
  )
44
21
  end
45
22
 
46
- def report_params(options, canvas_term_id=nil)
23
+ def report_params(options, canvas_term_id = options[:canvas_term_id] || batch_context[:canvas_term_id])
47
24
  params = {
48
25
  include_deleted: true,
49
26
  }
@@ -60,10 +37,6 @@ module CanvasSync
60
37
 
61
38
  { parameters: params }
62
39
  end
63
-
64
- def get_term_id(term)
65
- term.try(:canvas_id) || term.canvas_term_id
66
- end
67
40
  end
68
41
  end
69
42
  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,15 @@ 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
8
  # @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]
9
+ def perform(options)
10
+ CanvasSync.get_canvas_sync_client(batch_context).terms("self").all_pages!.each do |term_params|
11
+ if account_id = batch_context[:account_id]
13
12
  # These branches are primarily to support Legacy apps
14
13
  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])
14
+ Term.create_or_update(term_params, account_id)
16
15
  else
17
- term_params[:account_id] |= job_chain[:global_options][:account_id]
16
+ term_params[:account_id] |= account_id
18
17
  update_or_create_model(Term, term_params)
19
18
  end
20
19
  else
@@ -22,7 +21,23 @@ module CanvasSync
22
21
  end
23
22
  end
24
23
 
25
- CanvasSync.invoke_next(job_chain)
24
+ if (jobs = options[:sub_jobs]).present?
25
+ context = options[:context] || {}
26
+ if options[:term_scope]
27
+ Term.send(options[:term_scope]).find_each.map do |term|
28
+ local_context = context.merge(canvas_term_id: get_term_id(term))
29
+ JobBatches::ConcurrentBatchJob.perform_now(jobs, context: local_context)
30
+ end
31
+ else
32
+ JobBatches::ConcurrentBatchJob.perform_now(jobs, context: context)
33
+ end
34
+ end
35
+ end
36
+
37
+ protected
38
+
39
+ def get_term_id(term)
40
+ term.try(:canvas_id) || term.canvas_term_id
26
41
  end
27
42
  end
28
43
  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.4".freeze
2
+ VERSION = "0.17.0.beta1".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,42 @@ 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
+ :sub_jobs=>[
40
+ {:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["courses"], :term_scope=>"active", :c=>3}}
41
+ ]
42
+ }]}
43
+ ]]}
44
+ ], {:legacy_support=>false, :updated_after=>nil, :d=>4}],
41
45
  })
42
46
  end
43
47
 
44
48
  context 'we are syncing users with a term scope' do
45
49
  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 }
50
+ chain = CanvasSync.default_provisioning_report_chain(['users', 'courses'], term_scope: :active)
51
+ expect(chain.normalize!).to eq({
52
+ :job => "CanvasSync::Jobs::BeginSyncChainJob",
53
+ :parameters => [[
54
+ {:job=>"CanvasSync::JobBatches::ConcurrentBatchJob", :parameters=>[[
55
+ {:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["users"]}},
56
+ {:job=>"CanvasSync::Jobs::SyncTermsJob", :parameters=>[{
57
+ :sub_jobs=>[
58
+ {:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["courses"], :term_scope=>"active"}}
59
+ ]
60
+ }]}
61
+ ]]}
62
+ ], {:legacy_support=>false, :updated_after=>nil}]
54
63
  })
55
64
  end
56
65
  end
@@ -58,26 +67,36 @@ RSpec.describe CanvasSync do
58
67
  context 'we are syncing users without a term scope' do
59
68
  it 'syncs users along with the rest of the provisioning report' do
60
69
  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 }
70
+ expect(chain.normalize!).to eq({
71
+ :job => "CanvasSync::Jobs::BeginSyncChainJob",
72
+ :parameters => [[
73
+ {:job=>"CanvasSync::JobBatches::ConcurrentBatchJob", :parameters=>[[
74
+ {:job=>"CanvasSync::Jobs::SyncTermsJob", :parameters=>[{
75
+ :sub_jobs=>[
76
+ {:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["users", "courses"], :term_scope=>nil}}
77
+ ]
78
+ }]}
79
+ ]]}
80
+ ], {:legacy_support=>false, :updated_after=>nil}],
67
81
  })
68
82
  end
69
83
  end
70
84
 
71
85
  context 'we are syncing roles with a term scope' do
72
86
  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 }
87
+ chain = CanvasSync.default_provisioning_report_chain(['roles', 'courses'], term_scope: :active)
88
+ expect(chain.normalize!).to eq({
89
+ :job => "CanvasSync::Jobs::BeginSyncChainJob",
90
+ :parameters => [[
91
+ {:job=>"CanvasSync::JobBatches::ConcurrentBatchJob", :parameters=>[[
92
+ {:job=>"CanvasSync::Jobs::SyncRolesJob", :options=>{}},
93
+ {:job=>"CanvasSync::Jobs::SyncTermsJob", :parameters=>[{
94
+ :sub_jobs=>[
95
+ {:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["courses"], :term_scope=>"active"}}
96
+ ]
97
+ }]}
98
+ ]]}
99
+ ], {:legacy_support=>false, :updated_after=>nil}],
81
100
  })
82
101
  end
83
102
  end
@@ -85,27 +104,37 @@ RSpec.describe CanvasSync do
85
104
  context 'we are syncing roles without a term scope' do
86
105
  it 'syncs roles separately even with no term scope' do
87
106
  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 }
107
+ expect(chain.normalize!).to eq({
108
+ :job => "CanvasSync::Jobs::BeginSyncChainJob",
109
+ :parameters => [[
110
+ {:job=>"CanvasSync::JobBatches::ConcurrentBatchJob", :parameters=>[[
111
+ {:job=>"CanvasSync::Jobs::SyncRolesJob", :options=>{}},
112
+ {:job=>"CanvasSync::Jobs::SyncTermsJob", :parameters=>[{
113
+ :sub_jobs=>[
114
+ {:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["courses"], :term_scope=>nil}}
115
+ ]
116
+ }]}
117
+ ]]}
118
+ ], {:legacy_support=>false, :updated_after=>nil}],
95
119
  })
96
120
  end
97
121
  end
98
122
 
99
123
  context 'we are syncing admins with a term scope' do
100
124
  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 }
125
+ chain = CanvasSync.default_provisioning_report_chain(['admins', 'courses'], term_scope: :active)
126
+ expect(chain.normalize!).to eq({
127
+ :job => "CanvasSync::Jobs::BeginSyncChainJob",
128
+ :parameters => [[
129
+ {:job=>"CanvasSync::JobBatches::ConcurrentBatchJob", :parameters=>[[
130
+ {:job=>"CanvasSync::Jobs::SyncAdminsJob", :options=>{}},
131
+ {:job=>"CanvasSync::Jobs::SyncTermsJob", :parameters=>[{
132
+ :sub_jobs=>[
133
+ {:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["courses"], :term_scope=>"active"}}
134
+ ]
135
+ }]}
136
+ ]]}
137
+ ], {:legacy_support=>false, :updated_after=>nil}],
109
138
  })
110
139
  end
111
140
  end
@@ -113,13 +142,18 @@ RSpec.describe CanvasSync do
113
142
  context 'we are syncing admins without a term scope' do
114
143
  it 'syncs admins separately even with no term scope' do
115
144
  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 }
145
+ expect(chain.normalize!).to eq({
146
+ :job => "CanvasSync::Jobs::BeginSyncChainJob",
147
+ :parameters => [[
148
+ {:job=>"CanvasSync::JobBatches::ConcurrentBatchJob", :parameters=>[[
149
+ {:job=>"CanvasSync::Jobs::SyncAdminsJob", :options=>{}},
150
+ {:job=>"CanvasSync::Jobs::SyncTermsJob", :parameters=>[{
151
+ :sub_jobs=>[
152
+ {:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["courses"], :term_scope=>nil}}
153
+ ]
154
+ }]}
155
+ ]]}
156
+ ], {:legacy_support=>false, :updated_after=>nil}],
123
157
  })
124
158
  end
125
159
  end
@@ -128,13 +162,18 @@ RSpec.describe CanvasSync do
128
162
  it "appends the SyncAssignmentsJob" do
129
163
  chain = CanvasSync.default_provisioning_report_chain(%w[users enrollments assignments])
130
164
 
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 },
165
+ expect(chain.normalize!).to eq(
166
+ :job => "CanvasSync::Jobs::BeginSyncChainJob",
167
+ :parameters => [[
168
+ {:job=>"CanvasSync::JobBatches::ConcurrentBatchJob", :parameters=>[[
169
+ {:job=>"CanvasSync::Jobs::SyncTermsJob", :parameters=>[{
170
+ :sub_jobs=>[
171
+ {:job=>"CanvasSync::Jobs::SyncAssignmentsJob", :options=>{}},
172
+ {:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["users", "enrollments"], :term_scope=>nil}}
173
+ ]
174
+ }]}
175
+ ]]}
176
+ ], {:legacy_support=>false, :updated_after=>nil}],
138
177
  )
139
178
  end
140
179
  end
@@ -143,13 +182,18 @@ RSpec.describe CanvasSync do
143
182
  it "appends the SyncSubmissionsJob" do
144
183
  chain = CanvasSync.default_provisioning_report_chain(%w[users enrollments submissions])
145
184
 
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 },
185
+ expect(chain.normalize!).to eq(
186
+ :job => "CanvasSync::Jobs::BeginSyncChainJob",
187
+ :parameters => [[
188
+ {:job=>"CanvasSync::JobBatches::ConcurrentBatchJob", :parameters=>[[
189
+ {:job=>"CanvasSync::Jobs::SyncTermsJob", :parameters=>[{
190
+ :sub_jobs=>[
191
+ {:job=>"CanvasSync::Jobs::SyncSubmissionsJob", :options=>{}},
192
+ {:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["users", "enrollments"], :term_scope=>nil}}
193
+ ]
194
+ }]}
195
+ ]]}
196
+ ], {:legacy_support=>false, :updated_after=>nil}],
153
197
  )
154
198
  end
155
199
  end
@@ -158,95 +202,24 @@ RSpec.describe CanvasSync do
158
202
  it "appends the SyncAssignmentGroupsJob" do
159
203
  chain = CanvasSync.default_provisioning_report_chain(%w[users enrollments assignment_groups])
160
204
 
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 },
205
+ expect(chain.normalize!).to eq(
206
+ :job => "CanvasSync::Jobs::BeginSyncChainJob",
207
+ :parameters => [[
208
+ {:job=>"CanvasSync::JobBatches::ConcurrentBatchJob", :parameters=>[[
209
+ {:job=>"CanvasSync::Jobs::SyncTermsJob", :parameters=>[{
210
+ :sub_jobs=>[
211
+ {:job=>"CanvasSync::Jobs::SyncAssignmentGroupsJob", :options=>{}},
212
+ {:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["users", "enrollments"], :term_scope=>nil}}
213
+ ]
214
+ }]}
215
+ ]]}
216
+ ], {:legacy_support=>false, :updated_after=>nil}],
168
217
  )
169
218
  end
170
219
  end
171
220
  end
172
221
  end
173
222
 
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
223
  describe ".sync_scope" do
251
224
 
252
225
  end