canvas_sync 0.16.4 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (260) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +235 -151
  3. data/app/controllers/{api → canvas_sync/api}/v1/health_check_controller.rb +1 -1
  4. data/app/controllers/canvas_sync/api/v1/live_events_controller.rb +122 -0
  5. data/app/models/canvas_sync/sync_batch.rb +5 -0
  6. data/config/initializers/apartment.rb +10 -1
  7. data/config/routes.rb +7 -0
  8. data/db/migrate/20170915210836_create_canvas_sync_job_log.rb +12 -31
  9. data/db/migrate/20180725155729_add_job_id_to_canvas_sync_job_logs.rb +4 -13
  10. data/db/migrate/20190916154829_add_fork_count_to_canvas_sync_job_logs.rb +3 -11
  11. data/db/migrate/20201018210836_create_canvas_sync_sync_batches.rb +11 -0
  12. data/db/migrate/20201030210836_add_full_sync_to_canvas_sync_sync_batch.rb +7 -0
  13. data/lib/canvas_sync/batch_processor.rb +41 -0
  14. data/lib/canvas_sync/concerns/ability_helper.rb +72 -0
  15. data/lib/canvas_sync/concerns/account/ancestry.rb +2 -0
  16. data/lib/canvas_sync/concerns/account/base.rb +15 -0
  17. data/lib/canvas_sync/concerns/api_syncable.rb +17 -10
  18. data/lib/canvas_sync/concerns/live_event_sync.rb +46 -0
  19. data/lib/canvas_sync/concerns/role/base.rb +57 -0
  20. data/lib/canvas_sync/concerns/sync_mapping.rb +120 -0
  21. data/lib/canvas_sync/engine.rb +80 -0
  22. data/lib/canvas_sync/generators/install_generator.rb +1 -0
  23. data/lib/canvas_sync/generators/install_live_events_generator.rb +0 -1
  24. data/lib/canvas_sync/generators/templates/migrations/create_content_migrations.rb +24 -0
  25. data/lib/canvas_sync/generators/templates/migrations/create_course_nicknames.rb +17 -0
  26. data/lib/canvas_sync/generators/templates/migrations/create_grading_period_groups.rb +18 -0
  27. data/lib/canvas_sync/generators/templates/migrations/create_grading_periods.rb +22 -0
  28. data/lib/canvas_sync/generators/templates/migrations/create_learning_outcome_results.rb +46 -0
  29. data/lib/canvas_sync/generators/templates/migrations/create_learning_outcomes.rb +30 -0
  30. data/lib/canvas_sync/generators/templates/migrations/create_rubric_assessments.rb +31 -0
  31. data/lib/canvas_sync/generators/templates/migrations/create_rubric_associations.rb +36 -0
  32. data/lib/canvas_sync/generators/templates/migrations/create_rubrics.rb +38 -0
  33. data/lib/canvas_sync/generators/templates/migrations/create_user_observers.rb +17 -0
  34. data/lib/canvas_sync/generators/templates/migrations/create_users.rb +0 -1
  35. data/lib/canvas_sync/generators/templates/models/account.rb +3 -0
  36. data/lib/canvas_sync/generators/templates/models/admin.rb +2 -0
  37. data/lib/canvas_sync/generators/templates/models/assignment.rb +3 -0
  38. data/lib/canvas_sync/generators/templates/models/assignment_group.rb +3 -0
  39. data/lib/canvas_sync/generators/templates/models/content_migration.rb +12 -0
  40. data/lib/canvas_sync/generators/templates/models/context_module.rb +3 -0
  41. data/lib/canvas_sync/generators/templates/models/context_module_item.rb +3 -0
  42. data/lib/canvas_sync/generators/templates/models/course.rb +11 -0
  43. data/lib/canvas_sync/generators/templates/models/course_nickname.rb +13 -0
  44. data/lib/canvas_sync/generators/templates/models/enrollment.rb +14 -0
  45. data/lib/canvas_sync/generators/templates/models/grading_period.rb +10 -0
  46. data/lib/canvas_sync/generators/templates/models/grading_period_group.rb +9 -0
  47. data/lib/canvas_sync/generators/templates/models/group.rb +2 -0
  48. data/lib/canvas_sync/generators/templates/models/group_membership.rb +2 -0
  49. data/lib/canvas_sync/generators/templates/models/learning_outcome.rb +24 -0
  50. data/lib/canvas_sync/generators/templates/models/learning_outcome_result.rb +48 -0
  51. data/lib/canvas_sync/generators/templates/models/pseudonym.rb +2 -0
  52. data/lib/canvas_sync/generators/templates/models/role.rb +2 -0
  53. data/lib/canvas_sync/generators/templates/models/rubric.rb +29 -0
  54. data/lib/canvas_sync/generators/templates/models/rubric_assessment.rb +17 -0
  55. data/lib/canvas_sync/generators/templates/models/rubric_association.rb +14 -0
  56. data/lib/canvas_sync/generators/templates/models/section.rb +9 -0
  57. data/lib/canvas_sync/generators/templates/models/submission.rb +3 -0
  58. data/lib/canvas_sync/generators/templates/models/term.rb +3 -0
  59. data/lib/canvas_sync/generators/templates/models/user.rb +11 -0
  60. data/lib/canvas_sync/generators/templates/models/user_observer.rb +13 -0
  61. data/lib/canvas_sync/generators/templates/services/live_events/assignment_event.rb +1 -1
  62. data/lib/canvas_sync/generators/templates/services/live_events/assignment_group_event.rb +1 -1
  63. data/lib/canvas_sync/generators/templates/services/live_events/course_event.rb +1 -3
  64. data/lib/canvas_sync/generators/templates/services/live_events/course_section_event.rb +1 -1
  65. data/lib/canvas_sync/generators/templates/services/live_events/enrollment_event.rb +1 -1
  66. data/lib/canvas_sync/generators/templates/services/live_events/grade_event.rb +1 -1
  67. data/lib/canvas_sync/generators/templates/services/live_events/module_event.rb +1 -1
  68. data/lib/canvas_sync/generators/templates/services/live_events/module_item_event.rb +1 -1
  69. data/lib/canvas_sync/generators/templates/services/live_events/submission_event.rb +1 -1
  70. data/lib/canvas_sync/generators/templates/services/live_events/syllabus_event.rb +1 -1
  71. data/lib/canvas_sync/generators/templates/services/live_events/user_event.rb +1 -3
  72. data/lib/canvas_sync/importers/bulk_importer.rb +138 -31
  73. data/lib/canvas_sync/job.rb +7 -5
  74. data/lib/canvas_sync/job_batches/active_job.rb +108 -0
  75. data/lib/canvas_sync/job_batches/batch.rb +543 -0
  76. data/lib/canvas_sync/job_batches/callback.rb +149 -0
  77. data/lib/canvas_sync/job_batches/chain_builder.rb +249 -0
  78. data/lib/canvas_sync/job_batches/context_hash.rb +159 -0
  79. data/lib/canvas_sync/job_batches/hier_batch_ids.lua +25 -0
  80. data/lib/canvas_sync/job_batches/jobs/base_job.rb +7 -0
  81. data/lib/canvas_sync/job_batches/jobs/concurrent_batch_job.rb +22 -0
  82. data/lib/canvas_sync/job_batches/jobs/managed_batch_job.rb +170 -0
  83. data/lib/canvas_sync/job_batches/jobs/serial_batch_job.rb +22 -0
  84. data/lib/canvas_sync/job_batches/pool.rb +245 -0
  85. data/lib/canvas_sync/job_batches/pool_refill.lua +47 -0
  86. data/lib/canvas_sync/job_batches/redis_model.rb +69 -0
  87. data/lib/canvas_sync/job_batches/redis_script.rb +163 -0
  88. data/lib/canvas_sync/job_batches/schedule_callback.lua +14 -0
  89. data/lib/canvas_sync/job_batches/sidekiq/web/batches_assets/css/styles.less +182 -0
  90. data/lib/canvas_sync/job_batches/sidekiq/web/batches_assets/js/batch_tree.js +108 -0
  91. data/lib/canvas_sync/job_batches/sidekiq/web/batches_assets/js/util.js +2 -0
  92. data/lib/canvas_sync/job_batches/sidekiq/web/helpers.rb +41 -0
  93. data/lib/canvas_sync/job_batches/sidekiq/web/views/_batch_tree.erb +6 -0
  94. data/lib/canvas_sync/job_batches/sidekiq/web/views/_batches_table.erb +44 -0
  95. data/lib/canvas_sync/job_batches/sidekiq/web/views/_common.erb +13 -0
  96. data/lib/canvas_sync/job_batches/sidekiq/web/views/_jobs_table.erb +21 -0
  97. data/lib/canvas_sync/job_batches/sidekiq/web/views/_pagination.erb +26 -0
  98. data/lib/canvas_sync/job_batches/sidekiq/web/views/batch.erb +81 -0
  99. data/lib/canvas_sync/job_batches/sidekiq/web/views/batches.erb +23 -0
  100. data/lib/canvas_sync/job_batches/sidekiq/web/views/pool.erb +137 -0
  101. data/lib/canvas_sync/job_batches/sidekiq/web/views/pools.erb +47 -0
  102. data/lib/canvas_sync/job_batches/sidekiq/web.rb +218 -0
  103. data/lib/canvas_sync/job_batches/sidekiq.rb +136 -0
  104. data/lib/canvas_sync/job_batches/status.rb +91 -0
  105. data/lib/canvas_sync/jobs/begin_sync_chain_job.rb +99 -0
  106. data/lib/canvas_sync/jobs/canvas_process_waiter.rb +41 -0
  107. data/lib/canvas_sync/jobs/report_checker.rb +70 -8
  108. data/lib/canvas_sync/jobs/report_processor_job.rb +4 -7
  109. data/lib/canvas_sync/jobs/report_starter.rb +34 -20
  110. data/lib/canvas_sync/jobs/sync_accounts_job.rb +3 -5
  111. data/lib/canvas_sync/jobs/sync_admins_job.rb +2 -4
  112. data/lib/canvas_sync/jobs/sync_assignment_groups_job.rb +2 -4
  113. data/lib/canvas_sync/jobs/sync_assignments_job.rb +2 -4
  114. data/lib/canvas_sync/jobs/sync_content_migrations_job.rb +20 -0
  115. data/lib/canvas_sync/jobs/sync_context_module_items_job.rb +2 -4
  116. data/lib/canvas_sync/jobs/sync_context_modules_job.rb +2 -4
  117. data/lib/canvas_sync/jobs/sync_provisioning_report_job.rb +16 -50
  118. data/lib/canvas_sync/jobs/sync_roles_job.rb +2 -5
  119. data/lib/canvas_sync/jobs/sync_rubric_assessments_job.rb +15 -0
  120. data/lib/canvas_sync/jobs/sync_rubric_associations_job.rb +15 -0
  121. data/lib/canvas_sync/jobs/sync_rubrics_job.rb +15 -0
  122. data/lib/canvas_sync/jobs/sync_simple_table_job.rb +11 -32
  123. data/lib/canvas_sync/jobs/sync_submissions_job.rb +6 -4
  124. data/lib/canvas_sync/jobs/sync_terms_job.rb +9 -8
  125. data/lib/canvas_sync/jobs/term_batches_job.rb +50 -0
  126. data/lib/canvas_sync/{generators/templates/services/live_events/base_event.rb → live_events/base_handler.rb} +6 -10
  127. data/lib/canvas_sync/live_events/process_event_job.rb +26 -0
  128. data/lib/canvas_sync/live_events.rb +38 -0
  129. data/lib/canvas_sync/misc_helper.rb +63 -0
  130. data/lib/canvas_sync/processors/assignment_groups_processor.rb +3 -8
  131. data/lib/canvas_sync/processors/assignments_processor.rb +3 -8
  132. data/lib/canvas_sync/processors/content_migrations_processor.rb +19 -0
  133. data/lib/canvas_sync/processors/context_module_items_processor.rb +3 -8
  134. data/lib/canvas_sync/processors/context_modules_processor.rb +3 -8
  135. data/lib/canvas_sync/processors/model_mappings.yml +420 -0
  136. data/lib/canvas_sync/processors/normal_processor.rb +3 -3
  137. data/lib/canvas_sync/processors/provisioning_report_processor.rb +42 -55
  138. data/lib/canvas_sync/processors/report_processor.rb +15 -9
  139. data/lib/canvas_sync/processors/rubric_assessments_processor.rb +19 -0
  140. data/lib/canvas_sync/processors/rubric_associations_processor.rb +19 -0
  141. data/lib/canvas_sync/processors/rubrics_processor.rb +19 -0
  142. data/lib/canvas_sync/processors/submissions_processor.rb +3 -8
  143. data/lib/canvas_sync/record.rb +103 -0
  144. data/lib/canvas_sync/version.rb +1 -1
  145. data/lib/canvas_sync.rb +124 -125
  146. data/spec/canvas_sync/canvas_sync_spec.rb +224 -155
  147. data/spec/canvas_sync/jobs/canvas_process_waiter_spec.rb +34 -0
  148. data/spec/canvas_sync/jobs/job_spec.rb +9 -17
  149. data/spec/canvas_sync/jobs/report_checker_spec.rb +1 -3
  150. data/spec/canvas_sync/jobs/report_processor_job_spec.rb +0 -3
  151. data/spec/canvas_sync/jobs/report_starter_spec.rb +19 -28
  152. data/spec/canvas_sync/jobs/sync_admins_job_spec.rb +1 -4
  153. data/spec/canvas_sync/jobs/sync_assignment_groups_job_spec.rb +2 -1
  154. data/spec/canvas_sync/jobs/sync_assignments_job_spec.rb +3 -2
  155. data/spec/canvas_sync/jobs/sync_content_migrations_job_spec.rb +30 -0
  156. data/spec/canvas_sync/jobs/sync_context_module_items_job_spec.rb +3 -2
  157. data/spec/canvas_sync/jobs/sync_context_modules_job_spec.rb +3 -2
  158. data/spec/canvas_sync/jobs/sync_provisioning_report_job_spec.rb +7 -41
  159. data/spec/canvas_sync/jobs/sync_roles_job_spec.rb +1 -4
  160. data/spec/canvas_sync/jobs/sync_simple_table_job_spec.rb +5 -12
  161. data/spec/canvas_sync/jobs/sync_submissions_job_spec.rb +8 -2
  162. data/spec/canvas_sync/jobs/sync_terms_job_spec.rb +1 -4
  163. data/spec/canvas_sync/live_events/live_event_sync_spec.rb +27 -0
  164. data/spec/canvas_sync/live_events/live_events_controller_spec.rb +54 -0
  165. data/spec/canvas_sync/live_events/process_event_job_spec.rb +38 -0
  166. data/spec/canvas_sync/misc_helper_spec.rb +58 -0
  167. data/spec/canvas_sync/models/assignment_spec.rb +1 -1
  168. data/spec/canvas_sync/processors/content_migrations_processor_spec.rb +13 -0
  169. data/spec/canvas_sync/processors/provisioning_report_processor_spec.rb +101 -1
  170. data/spec/canvas_sync/processors/rubric_assessments_spec.rb +16 -0
  171. data/spec/canvas_sync/processors/rubric_associations_spec.rb +16 -0
  172. data/spec/canvas_sync/processors/rubrics_processor_spec.rb +17 -0
  173. data/spec/dummy/app/models/account.rb +6 -0
  174. data/spec/dummy/app/models/admin.rb +2 -0
  175. data/spec/dummy/app/models/assignment.rb +3 -0
  176. data/spec/dummy/app/models/assignment_group.rb +3 -0
  177. data/spec/dummy/app/models/content_migration.rb +18 -0
  178. data/spec/dummy/app/models/context_module.rb +3 -0
  179. data/spec/dummy/app/models/context_module_item.rb +3 -0
  180. data/spec/dummy/app/models/course.rb +11 -0
  181. data/spec/dummy/app/models/course_nickname.rb +19 -0
  182. data/spec/dummy/app/models/enrollment.rb +14 -0
  183. data/spec/dummy/app/models/grading_period.rb +16 -0
  184. data/spec/dummy/app/models/grading_period_group.rb +15 -0
  185. data/spec/dummy/app/models/group.rb +2 -0
  186. data/spec/dummy/app/models/group_membership.rb +2 -0
  187. data/spec/dummy/app/models/learning_outcome.rb +30 -0
  188. data/spec/dummy/app/models/learning_outcome_result.rb +54 -0
  189. data/spec/dummy/app/models/pseudonym.rb +16 -0
  190. data/spec/dummy/app/models/role.rb +2 -0
  191. data/spec/dummy/app/models/rubric.rb +35 -0
  192. data/spec/dummy/app/models/rubric_assessment.rb +22 -0
  193. data/spec/dummy/app/models/rubric_association.rb +20 -0
  194. data/spec/dummy/app/models/section.rb +9 -0
  195. data/spec/dummy/app/models/submission.rb +4 -0
  196. data/spec/dummy/app/models/term.rb +3 -0
  197. data/spec/dummy/app/models/user.rb +11 -0
  198. data/spec/dummy/app/models/user_observer.rb +19 -0
  199. data/spec/dummy/app/services/live_events/assignment_event.rb +1 -1
  200. data/spec/dummy/app/services/live_events/course_event.rb +1 -3
  201. data/spec/dummy/app/services/live_events/course_section_event.rb +1 -1
  202. data/spec/dummy/app/services/live_events/enrollment_event.rb +1 -1
  203. data/spec/dummy/app/services/live_events/grade_event.rb +1 -1
  204. data/spec/dummy/app/services/live_events/module_event.rb +1 -1
  205. data/spec/dummy/app/services/live_events/module_item_event.rb +1 -1
  206. data/spec/dummy/app/services/live_events/submission_event.rb +1 -1
  207. data/spec/dummy/app/services/live_events/syllabus_event.rb +1 -1
  208. data/spec/dummy/app/services/live_events/user_event.rb +1 -3
  209. data/spec/dummy/config/environments/test.rb +2 -0
  210. data/spec/dummy/config/routes.rb +1 -0
  211. data/spec/dummy/db/migrate/20201016181346_create_pseudonyms.rb +24 -0
  212. data/spec/dummy/db/migrate/20210907233329_create_user_observers.rb +23 -0
  213. data/spec/dummy/db/migrate/20210907233330_create_grading_periods.rb +28 -0
  214. data/spec/dummy/db/migrate/20211001184920_create_grading_period_groups.rb +24 -0
  215. data/spec/dummy/db/migrate/20220308072643_create_content_migrations.rb +30 -0
  216. data/spec/dummy/db/migrate/20220712210559_create_learning_outcomes.rb +36 -0
  217. data/spec/dummy/db/migrate/{20190702203620_create_users.rb → 20220926221926_create_users.rb} +0 -1
  218. data/spec/dummy/db/migrate/20240408223326_create_course_nicknames.rb +23 -0
  219. data/spec/dummy/db/migrate/20240509105100_create_rubrics.rb +44 -0
  220. data/spec/dummy/db/migrate/20240510094100_create_rubric_associations.rb +42 -0
  221. data/spec/dummy/db/migrate/20240510101100_create_rubric_assessments.rb +37 -0
  222. data/spec/dummy/db/migrate/20240523101010_create_learning_outcome_results.rb +52 -0
  223. data/spec/dummy/db/schema.rb +244 -5
  224. data/spec/factories/user_factory.rb +0 -1
  225. data/spec/job_batching/active_job_spec.rb +107 -0
  226. data/spec/job_batching/batch_spec.rb +489 -0
  227. data/spec/job_batching/callback_spec.rb +38 -0
  228. data/spec/job_batching/context_hash_spec.rb +54 -0
  229. data/spec/job_batching/flow_spec.rb +82 -0
  230. data/spec/job_batching/integration/fail_then_succeed.rb +42 -0
  231. data/spec/job_batching/integration/integration.rb +57 -0
  232. data/spec/job_batching/integration/nested.rb +88 -0
  233. data/spec/job_batching/integration/simple.rb +47 -0
  234. data/spec/job_batching/integration/workflow.rb +134 -0
  235. data/spec/job_batching/integration_helper.rb +50 -0
  236. data/spec/job_batching/pool_spec.rb +161 -0
  237. data/spec/job_batching/sidekiq_spec.rb +125 -0
  238. data/spec/job_batching/status_spec.rb +76 -0
  239. data/spec/job_batching/support/base_job.rb +14 -0
  240. data/spec/job_batching/support/sample_callback.rb +2 -0
  241. data/spec/spec_helper.rb +17 -0
  242. data/spec/support/fixtures/reports/content_migrations.csv +3 -0
  243. data/spec/support/fixtures/reports/course_nicknames.csv +3 -0
  244. data/spec/support/fixtures/reports/grading_period_groups.csv +2 -0
  245. data/spec/support/fixtures/reports/grading_periods.csv +3 -0
  246. data/spec/support/fixtures/reports/learning_outcome_results.csv +3 -0
  247. data/spec/support/fixtures/reports/learning_outcomes.csv +3 -0
  248. data/spec/support/fixtures/reports/provisioning_csv_unzipped/courses.csv +3 -0
  249. data/spec/support/fixtures/reports/provisioning_csv_unzipped/users.csv +4 -0
  250. data/spec/support/fixtures/reports/rubric_assessments.csv +3 -0
  251. data/spec/support/fixtures/reports/rubric_associations.csv +3 -0
  252. data/spec/support/fixtures/reports/rubrics.csv +3 -0
  253. data/spec/support/fixtures/reports/user_observers.csv +3 -0
  254. data/spec/support/fixtures/reports/users.csv +3 -2
  255. data/spec/support/fixtures/reports/xlist.csv +1 -1
  256. metadata +329 -27
  257. data/app/controllers/api/v1/live_events_controller.rb +0 -18
  258. data/lib/canvas_sync/job_chain.rb +0 -57
  259. data/lib/canvas_sync/jobs/fork_gather.rb +0 -59
  260. data/spec/canvas_sync/jobs/fork_gather_spec.rb +0 -73
@@ -16,7 +16,6 @@ RSpec.describe CanvasSync::Jobs::ReportStarter do
16
16
  expect(CanvasSync::Jobs::ReportChecker).to receive(:set).and_call_original
17
17
 
18
18
  CanvasSync::Jobs::ReportStarter.perform_now(
19
- { jobs: [], global_options: {} },
20
19
  report_name,
21
20
  report_params,
22
21
  processor,
@@ -24,30 +23,27 @@ RSpec.describe CanvasSync::Jobs::ReportStarter do
24
23
  end
25
24
 
26
25
  context 'allow_redownloads is true' do
27
- context 'the report has already been cached' do
28
- it 'runs the report checker for the already started report' do
29
- expect_any_instance_of(Bearcat::Client).to_not receive(:start_report)
30
- job_chain = { jobs: [], global_options: { report_name => 1 } }
26
+ # context 'the report has already been cached' do
27
+ # it 'runs the report checker for the already started report' do
28
+ # expect_any_instance_of(Bearcat::Client).to_not receive(:start_report)
31
29
 
32
- expect(CanvasSync::Jobs::ReportChecker).to receive(:set).and_return(report_checker_double)
33
- expect(report_checker_double).to receive(:perform_later).with(
34
- job_chain,
35
- report_name,
36
- 1,
37
- processor,
38
- options
39
- )
30
+ # expect(CanvasSync::Jobs::ReportChecker).to receive(:set).and_return(report_checker_double)
31
+ # expect(report_checker_double).to receive(:perform_later).with(
32
+ # report_name,
33
+ # 1,
34
+ # processor,
35
+ # options
36
+ # )
40
37
 
41
- CanvasSync::Jobs::ReportStarter.perform_now(
42
- job_chain,
43
- report_name,
44
- report_params,
45
- processor,
46
- options,
47
- allow_redownloads: true
48
- )
49
- end
50
- end
38
+ # CanvasSync::Jobs::ReportStarter.perform_now(
39
+ # report_name,
40
+ # report_params,
41
+ # processor,
42
+ # options,
43
+ # allow_redownloads: true
44
+ # )
45
+ # end
46
+ # end
51
47
 
52
48
  context 'the report has not been started before' do
53
49
  it 'starts a new report and caches the report id' do
@@ -55,12 +51,8 @@ RSpec.describe CanvasSync::Jobs::ReportStarter do
55
51
  .with('self', report_name, report_params)
56
52
  .and_return({ 'id' => 1 })
57
53
 
58
- orig_job_chain = { jobs: [], global_options: {} }
59
- new_job_chain = { jobs: [], global_options: { report_name => 1 } }
60
-
61
54
  expect(CanvasSync::Jobs::ReportChecker).to receive(:set).and_return(report_checker_double)
62
55
  expect(report_checker_double).to receive(:perform_later).with(
63
- new_job_chain,
64
56
  report_name,
65
57
  1,
66
58
  processor,
@@ -68,7 +60,6 @@ RSpec.describe CanvasSync::Jobs::ReportStarter do
68
60
  )
69
61
 
70
62
  CanvasSync::Jobs::ReportStarter.perform_now(
71
- orig_job_chain,
72
63
  report_name,
73
64
  report_params,
74
65
  processor,
@@ -4,13 +4,10 @@ RSpec.describe CanvasSync::Jobs::SyncAdminsJob do
4
4
  describe '#perform' do
5
5
  let!(:account) { FactoryGirl.create(:account, canvas_id: 1) }
6
6
  let(:admin_params) { open_canvas_fixture('admins') }
7
- let(:job_chain) { { jobs: [], global_options: {}} }
8
7
 
9
8
  it 'retrieves all admins from the Canvas API and then invokes the next job' do
10
- expect(CanvasSync).to receive(:invoke_next).with(job_chain)
11
-
12
9
  expect {
13
- CanvasSync::Jobs::SyncAdminsJob.perform_now(job_chain, {})
10
+ CanvasSync::Jobs::SyncAdminsJob.perform_now({})
14
11
  }.to change { Admin.count }.by(admin_params.length)
15
12
  end
16
13
  end
@@ -10,7 +10,8 @@ RSpec.describe CanvasSync::Jobs::SyncAssignmentGroupsJob do
10
10
 
11
11
  expect(CanvasSync::Jobs::ReportChecker).to receive(:set).and_call_original
12
12
 
13
- CanvasSync::Jobs::SyncAssignmentGroupsJob.perform_now({ jobs: [], global_options: { canvas_term_id: 1 } }, {})
13
+ set_batch_context(canvas_term_id: 1)
14
+ CanvasSync::Jobs::SyncAssignmentGroupsJob.perform_now({})
14
15
  end
15
16
  end
16
17
  end
@@ -10,7 +10,8 @@ RSpec.describe CanvasSync::Jobs::SyncAssignmentsJob do
10
10
 
11
11
  expect(CanvasSync::Jobs::ReportChecker).to receive(:set).and_call_original
12
12
 
13
- CanvasSync::Jobs::SyncAssignmentsJob.perform_now({ jobs: [], global_options: { canvas_term_id: 1 } }, {})
13
+ set_batch_context(canvas_term_id: 1)
14
+ CanvasSync::Jobs::SyncAssignmentsJob.perform_now({})
14
15
  end
15
16
  end
16
17
 
@@ -22,7 +23,7 @@ RSpec.describe CanvasSync::Jobs::SyncAssignmentsJob do
22
23
 
23
24
  expect(CanvasSync::Jobs::ReportChecker).to receive(:set).and_call_original
24
25
 
25
- CanvasSync::Jobs::SyncAssignmentsJob.perform_now({ jobs: [], global_options: {} }, {})
26
+ CanvasSync::Jobs::SyncAssignmentsJob.perform_now({})
26
27
  end
27
28
  end
28
29
  end
@@ -0,0 +1,30 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe CanvasSync::Jobs::SyncContentMigrationsJob do
4
+ describe "#perform" do
5
+ context "no parameters is specified" do
6
+ it "enqueues a ReportStarter for the proserv_content_migrations_csv" do
7
+ expect_any_instance_of(Bearcat::Client).to receive(:start_report)
8
+ .with("self", "proserv_content_migrations_csv", { parameters: { } })
9
+ .and_return("id" => 1)
10
+
11
+ expect(CanvasSync::Jobs::ReportChecker).to receive(:set).and_call_original
12
+
13
+ CanvasSync::Jobs::SyncContentMigrationsJob.perform_now({})
14
+ end
15
+ end
16
+
17
+ context "updated_after parameters is specified" do
18
+ it "enqueues a ReportStarter for the proserv_content_migrations_csv and get data from given date" do
19
+ expect_any_instance_of(Bearcat::Client).to receive(:start_report)
20
+ .with("self", "proserv_content_migrations_csv", { parameters: { updated_after: 6.hours.ago.to_s } })
21
+ .and_return("id" => 1)
22
+
23
+ expect(CanvasSync::Jobs::ReportChecker).to receive(:set).and_call_original
24
+
25
+ set_batch_context(updated_after: 6.hours.ago.to_s)
26
+ CanvasSync::Jobs::SyncContentMigrationsJob.perform_now({})
27
+ end
28
+ end
29
+ end
30
+ end
@@ -10,7 +10,8 @@ RSpec.describe CanvasSync::Jobs::SyncContextModuleItemsJob do
10
10
 
11
11
  expect(CanvasSync::Jobs::ReportChecker).to receive(:set).and_call_original
12
12
 
13
- CanvasSync::Jobs::SyncContextModuleItemsJob.perform_now({ jobs: [], global_options: { canvas_term_id: 1 } }, {})
13
+ set_batch_context(canvas_term_id: 1)
14
+ CanvasSync::Jobs::SyncContextModuleItemsJob.perform_now({})
14
15
  end
15
16
  end
16
17
 
@@ -22,7 +23,7 @@ RSpec.describe CanvasSync::Jobs::SyncContextModuleItemsJob do
22
23
 
23
24
  expect(CanvasSync::Jobs::ReportChecker).to receive(:set).and_call_original
24
25
 
25
- CanvasSync::Jobs::SyncContextModuleItemsJob.perform_now({ jobs: [], global_options: {} }, {})
26
+ CanvasSync::Jobs::SyncContextModuleItemsJob.perform_now({})
26
27
  end
27
28
  end
28
29
  end
@@ -10,7 +10,8 @@ RSpec.describe CanvasSync::Jobs::SyncContextModulesJob do
10
10
 
11
11
  expect(CanvasSync::Jobs::ReportChecker).to receive(:set).and_call_original
12
12
 
13
- CanvasSync::Jobs::SyncContextModulesJob.perform_now({ jobs: [], global_options: { canvas_term_id: 1 } }, {})
13
+ set_batch_context(canvas_term_id: 1)
14
+ CanvasSync::Jobs::SyncContextModulesJob.perform_now({})
14
15
  end
15
16
  end
16
17
 
@@ -22,7 +23,7 @@ RSpec.describe CanvasSync::Jobs::SyncContextModulesJob do
22
23
 
23
24
  expect(CanvasSync::Jobs::ReportChecker).to receive(:set).and_call_original
24
25
 
25
- CanvasSync::Jobs::SyncContextModulesJob.perform_now({ jobs: [], global_options: {} }, {})
26
+ CanvasSync::Jobs::SyncContextModulesJob.perform_now({})
26
27
  end
27
28
  end
28
29
  end
@@ -2,67 +2,36 @@ require 'spec_helper'
2
2
 
3
3
  RSpec.describe CanvasSync::Jobs::SyncProvisioningReportJob do
4
4
  describe '#perform' do
5
- let(:job_chain) { {jobs: [], global_options: {}} }
6
-
7
5
  context 'a term scope is specified' do
8
- let!(:active_term_1) { FactoryGirl.create(:term) }
9
- let!(:active_term_2) { FactoryGirl.create(:term) }
10
- let!(:inactive_term_1) { FactoryGirl.create(:term, workflow_state: 'inactive') }
6
+ let!(:term) { FactoryGirl.create(:term) }
11
7
 
12
8
  it 'enqueues a ReportStarter for a provisioning report for the specified models for each term' do
13
- expected_job_chain = Marshal.load(Marshal.dump(job_chain))
14
- expected_job_chain[:global_options][:canvas_term_id] = active_term_1.canvas_id
15
- expected_job_chain[:global_options] = hash_including(expected_job_chain[:global_options])
16
-
17
- expect(CanvasSync::Jobs::ReportStarter).to receive(:perform_later)
18
- .with(
19
- expected_job_chain,
20
- 'proservices_provisioning_csv',
21
- {
22
- parameters: {
23
- include_deleted: true,
24
- 'users' => true,
25
- 'courses' => true,
26
- enrollment_term_id: active_term_1.canvas_id
27
- }
28
- },
29
- CanvasSync::Processors::ProvisioningReportProcessor.to_s,
30
- { models: ['users', 'courses'], term_scope: 'active' }
31
- )
32
-
33
- expected_job_chain_2 = Marshal.load(Marshal.dump(job_chain))
34
- expected_job_chain_2[:global_options][:canvas_term_id] = active_term_2.canvas_id
35
- expected_job_chain_2[:global_options] = hash_including(expected_job_chain_2[:global_options])
36
-
37
- expect(CanvasSync::Jobs::ReportStarter).to receive(:perform_later)
9
+ expect_any_instance_of(CanvasSync::Jobs::ReportStarter).to receive(:start_report)
38
10
  .with(
39
- expected_job_chain_2,
11
+ 'self',
40
12
  'proservices_provisioning_csv',
41
13
  {
42
14
  parameters: {
43
15
  include_deleted: true,
44
16
  'users' => true,
45
17
  'courses' => true,
46
- enrollment_term_id: active_term_2.canvas_id
18
+ enrollment_term_id: term.canvas_id,
47
19
  }
48
20
  },
49
- CanvasSync::Processors::ProvisioningReportProcessor.to_s,
50
- { models: ['users', 'courses'], term_scope: 'active' }
51
21
  )
52
22
 
23
+ set_batch_context(canvas_term_id: term.canvas_id)
53
24
  CanvasSync::Jobs::SyncProvisioningReportJob.perform_now(
54
- job_chain,
55
25
  { models: ['users', 'courses'], term_scope: 'active' }
56
26
  )
57
- expect(CanvasSync::JobLog.last.fork_count).to eq 2
58
27
  end
59
28
  end
60
29
 
61
30
  context 'a term scope is not specified' do
62
31
  it 'enqueues a single ReportStarter for a provisioning report across all terms for the specified models' do
63
- expect(CanvasSync::Jobs::ReportStarter).to receive(:perform_later)
32
+ expect_any_instance_of(CanvasSync::Jobs::ReportStarter).to receive(:start_report)
64
33
  .with(
65
- job_chain,
34
+ 'self',
66
35
  'proservices_provisioning_csv',
67
36
  {
68
37
  parameters: {
@@ -71,12 +40,9 @@ RSpec.describe CanvasSync::Jobs::SyncProvisioningReportJob do
71
40
  'courses' => true,
72
41
  }
73
42
  },
74
- CanvasSync::Processors::ProvisioningReportProcessor.to_s,
75
- { models: ['users', 'courses'] }
76
43
  )
77
44
 
78
45
  CanvasSync::Jobs::SyncProvisioningReportJob.perform_now(
79
- job_chain,
80
46
  { models: ['users', 'courses'] }
81
47
  )
82
48
  end
@@ -4,13 +4,10 @@ RSpec.describe CanvasSync::Jobs::SyncRolesJob do
4
4
  describe '#perform' do
5
5
  let!(:account) { FactoryGirl.create(:account, canvas_id: 1) }
6
6
  let(:role_params) { open_canvas_fixture('roles') }
7
- let(:job_chain) { { jobs: [], global_options: {}} }
8
7
 
9
8
  it 'retrieves all roles from the Canvas API and then invokes the next job' do
10
- expect(CanvasSync).to receive(:invoke_next).with(job_chain)
11
-
12
9
  expect {
13
- CanvasSync::Jobs::SyncRolesJob.perform_now(job_chain, {})
10
+ CanvasSync::Jobs::SyncRolesJob.perform_now({})
14
11
  }.to change { Role.count }.by(role_params.length)
15
12
  end
16
13
  end
@@ -2,25 +2,17 @@ require 'spec_helper'
2
2
 
3
3
  RSpec.describe CanvasSync::Jobs::SyncSimpleTableJob do
4
4
  describe '#perform' do
5
- let(:job_chain) { {jobs: [], global_options: {}} }
6
-
7
5
  context 'Simple report' do
8
- let!(:active_term_1) { FactoryGirl.create(:term) }
9
- let!(:inactive_term_1) { FactoryGirl.create(:term, workflow_state: 'inactive') }
6
+ let!(:term) { FactoryGirl.create(:term) }
10
7
 
11
8
  it 'enqueues a ReportStarter for a provisioning report for the specified model for a term' do
12
- expected_job_chain = Marshal.load(Marshal.dump(job_chain))
13
- expected_job_chain[:global_options][:canvas_term_id] = active_term_1.canvas_id
14
- expected_job_chain[:global_options] = hash_including(expected_job_chain[:global_options])
15
-
16
9
  expect(CanvasSync::Jobs::ReportStarter).to receive(:perform_later)
17
10
  .with(
18
- expected_job_chain,
19
11
  'proservices_provisioning_csv',
20
12
  {
21
13
  "parameters[include_deleted]" => true,
22
14
  "parameters[courses]" => true,
23
- "parameters[enrollment_term_id]" => active_term_1.canvas_id
15
+ "parameters[enrollment_term_id]" => term.canvas_id
24
16
  },
25
17
  CanvasSync::Processors::NormalProcessor.to_s,
26
18
  {
@@ -32,13 +24,14 @@ RSpec.describe CanvasSync::Jobs::SyncSimpleTableJob do
32
24
  params: {
33
25
  "parameters[include_deleted]" => true,
34
26
  "parameters[courses]" => true,
35
- "parameters[enrollment_term_id]" => active_term_1.canvas_id
27
+ "parameters[enrollment_term_id]" => term.canvas_id
36
28
  }
37
29
  }
38
30
  )
39
31
 
32
+ set_batch_context(canvas_term_id: term.canvas_id)
33
+
40
34
  CanvasSync::Jobs::SyncSimpleTableJob.perform_now(
41
- job_chain,
42
35
  {
43
36
  report_name: 'proservices_provisioning_csv',
44
37
  model: 'courses',
@@ -5,12 +5,18 @@ RSpec.describe CanvasSync::Jobs::SyncSubmissionsJob do
5
5
  context "a term id is in the global_options" do
6
6
  it "enqueues a ReportStarter for the proserv_student_submissions_csv for the given term" do
7
7
  expect_any_instance_of(Bearcat::Client).to receive(:start_report)
8
- .with("self", "proserv_student_submissions_csv", { parameters: { enrollment_term_id: 1, include_all: nil } })
8
+ .with("self", "proserv_student_submissions_csv", { parameters: {
9
+ enrollment_term_id: 1,
10
+ include_all: nil,
11
+ enrollment_batch_size: nil,
12
+ include_all_except: nil
13
+ } })
9
14
  .and_return("id" => 1)
10
15
 
11
16
  expect(CanvasSync::Jobs::ReportChecker).to receive(:set).and_call_original
12
17
 
13
- CanvasSync::Jobs::SyncSubmissionsJob.perform_now({ jobs: [], global_options: { canvas_term_id: 1 } }, {})
18
+ set_batch_context(canvas_term_id: 1)
19
+ CanvasSync::Jobs::SyncSubmissionsJob.perform_now({})
14
20
  end
15
21
  end
16
22
  end
@@ -3,13 +3,10 @@ require 'spec_helper'
3
3
  RSpec.describe CanvasSync::Jobs::SyncTermsJob do
4
4
  describe '#perform' do
5
5
  let(:term_params) { open_canvas_fixture('terms')['enrollment_terms'] }
6
- let(:job_chain) { { jobs: [], global_options: {}} }
7
6
 
8
7
  it 'retrieves all terms from the Canvas API and then invokes the next job' do
9
- expect(CanvasSync).to receive(:invoke_next).with(job_chain)
10
-
11
8
  expect {
12
- CanvasSync::Jobs::SyncTermsJob.perform_now(job_chain, {})
9
+ CanvasSync::Jobs::SyncTermsJob.perform_now({})
13
10
  }.to change { Term.count }.by(term_params.length)
14
11
  end
15
12
  end
@@ -0,0 +1,27 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe CanvasSync::Concerns::LiveEventSync do
4
+ before(:all) do
5
+ User.include(CanvasSync::Concerns::LiveEventSync)
6
+ end
7
+
8
+ let(:event) {
9
+ {
10
+ "metadata" => {
11
+ event_name: "user_created",
12
+ },
13
+ "payload" => {
14
+ user_id: 124,
15
+ },
16
+ }
17
+ }
18
+
19
+ describe "#perform" do
20
+ it "determines ID from payload" do
21
+ expect_any_instance_of(User).to receive(:process_live_event).with(:created, event["payload"], event["metadata"]) do |user, *args|
22
+ expect(user.canvas_id).to eql 124
23
+ end
24
+ User.cs_internal_process_live_event(event.with_indifferent_access)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,54 @@
1
+ require "spec_helper"
2
+ require "json/jwt"
3
+
4
+ RSpec.describe CanvasSync::Api::V1::LiveEventsController, type: :controller do
5
+ routes { CanvasSync::Engine.routes }
6
+
7
+ let(:event) {
8
+ {
9
+ "metadata" => {
10
+ event_name: "user_created",
11
+ },
12
+ "payload" => {
13
+ user_id: 42660000000000001,
14
+ },
15
+ }.with_indifferent_access
16
+ }
17
+
18
+ describe "#transform_ids!" do
19
+ it "transforms sharded IDs to local IDs" do
20
+ controller.send(:transform_ids!, event)
21
+ expect(event[:payload][:user_id]).to eql 1
22
+ expect(event[:payload][:sharded_user_id]).to eql 42660000000000001
23
+ end
24
+
25
+ xit "it does not transform cross-shard IDs" do
26
+ # TODO
27
+ end
28
+ end
29
+
30
+ describe "#process_dataservices_event" do
31
+ let(:private_key) { OpenSSL::PKey::RSA.new(2048) }
32
+ let(:jwk) { JSON::JWK.new(private_key) }
33
+ let(:jwks) { JSON::JWK::Set.new([jwk]) }
34
+
35
+ before :each do
36
+ allow(controller).to receive(:dataservices_jwks).and_return(jwks)
37
+ end
38
+
39
+ let(:event_data) { event.to_json }
40
+
41
+ it "triggers a background job" do
42
+ expect(controller).to receive(:dispatch_event)
43
+ expect(controller).to receive(:validate_tenant!)
44
+ post :process_event, params: { "_json" => JSON::JWT.new(event).sign(jwk).to_s }
45
+ expect(response).to be_successful
46
+ end
47
+
48
+ it "does not allow unsigned events" do
49
+ expect(controller).to_not receive(:validate_tenant!)
50
+ post :process_event, params: { "_json" => event.to_json }
51
+ expect(response).to_not be_successful
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,38 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe CanvasSync::LiveEvents::ProcessEventJob do
4
+ before(:all) do
5
+ User.include(CanvasSync::Concerns::LiveEventSync)
6
+ end
7
+
8
+ let(:event) {
9
+ {
10
+ "metadata" => {
11
+ event_name: "user_created",
12
+ },
13
+ "payload" => {
14
+ user_id: 1,
15
+ },
16
+ }
17
+ }
18
+
19
+ describe "#perform" do
20
+ it "invokes a legacy handler if present" do
21
+ expect(LiveEvents::UserCreatedEvent).to receive(:perform_later)
22
+ described_class.perform_now(event)
23
+ end
24
+
25
+ it "does not invoke new handlers if legacy is present" do
26
+ expect(CanvasSync::LiveEvents).to_not receive(:registered_handlers)
27
+ described_class.perform_now(event)
28
+ end
29
+
30
+ it "invokes new handlers" do
31
+ hide_const("LiveEvents::UserCreatedEvent")
32
+ expect(CanvasSync::LiveEvents).to receive(:registered_handlers).and_call_original
33
+ expect(User).to receive(:cs_internal_process_live_event).and_call_original
34
+ expect_any_instance_of(User).to receive(:process_live_event).with(:created, event["payload"], event["metadata"])
35
+ described_class.perform_now(event)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe CanvasSync::MiscHelper do
4
+ describe ".invoke_task" do
5
+ with_model :Model do
6
+ table
7
+ model do
8
+ def wait_callback(*args); end
9
+
10
+ def self.wait_callback(*args); end
11
+ end
12
+ end
13
+
14
+ class CPW_TestWorker
15
+ extend Sidekiq::Worker
16
+ end
17
+
18
+ it 'schedules a given job' do
19
+ expect(CPW_TestWorker).to receive(:perform_async)
20
+ described_class.invoke_task(
21
+ job: 'CPW_TestWorker',
22
+ args: [1, 2],
23
+ )
24
+ end
25
+
26
+ it 'accepts a method string' do
27
+ expect(Model).to receive(:wait_callback).with(1, 2, a: 3, b: 4)
28
+ described_class.invoke_task(
29
+ method: "#{Model.to_s}.wait_callback",
30
+ args: [1, 2],
31
+ kwargs: { a: 3, b: 4 },
32
+ )
33
+ end
34
+
35
+ it 'invokes a model method' do
36
+ model = Model.create!
37
+ expect(Model).to receive(:find_by).with(id: model.id).and_return(model)
38
+ expect(model).to receive(:wait_callback).with(1, 2, a: 3, b: 4)
39
+ described_class.invoke_task(
40
+ model: Model.to_s,
41
+ find_by: { id: model.id },
42
+ method: :wait_callback,
43
+ args: [1, 2],
44
+ kwargs: { a: 3, b: 4 },
45
+ )
46
+ end
47
+
48
+ it 'invokes a class method' do
49
+ expect(Model).to receive(:wait_callback).with(1, 2, a: 3, b: 4)
50
+ described_class.invoke_task(
51
+ class: Model.to_s,
52
+ method: :wait_callback,
53
+ args: [1, 2],
54
+ kwargs: { a: 3, b: 4 },
55
+ )
56
+ end
57
+ end
58
+ end
@@ -35,7 +35,7 @@ RSpec.describe Assignment, type: :model do
35
35
  let!(:matching_course) { FactoryGirl.create(:course) }
36
36
 
37
37
  before do
38
- subject.update_attributes(canvas_context_type: "Course", canvas_context_id: matching_course.canvas_id)
38
+ subject.update(canvas_context_type: "Course", canvas_context_id: matching_course.canvas_id)
39
39
  end
40
40
 
41
41
  it "should belong to courses where the canvas_context_type is Course and canvas_context_id is the canvas_course_id" do
@@ -0,0 +1,13 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe CanvasSync::Processors::ContentMigrationsProcessor do
4
+ let(:subject) { CanvasSync::Processors::ContentMigrationsProcessor }
5
+
6
+ describe "#process" do
7
+ it "inserts content migrations" do
8
+ expect {
9
+ subject.process("spec/support/fixtures/reports/content_migrations.csv", {}, 1)
10
+ }.to change { ContentMigration.count }.by(2)
11
+ end
12
+ end
13
+ end