canvas_sync 0.1.1

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 (85) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +178 -0
  3. data/Rakefile +23 -0
  4. data/lib/canvas_sync.rb +96 -0
  5. data/lib/canvas_sync/generators/install_generator.rb +54 -0
  6. data/lib/canvas_sync/generators/templates/course.rb +8 -0
  7. data/lib/canvas_sync/generators/templates/create_courses.rb +21 -0
  8. data/lib/canvas_sync/generators/templates/create_enrollments.rb +26 -0
  9. data/lib/canvas_sync/generators/templates/create_sections.rb +20 -0
  10. data/lib/canvas_sync/generators/templates/create_terms.rb +18 -0
  11. data/lib/canvas_sync/generators/templates/create_users.rb +18 -0
  12. data/lib/canvas_sync/generators/templates/enrollment.rb +8 -0
  13. data/lib/canvas_sync/generators/templates/section.rb +7 -0
  14. data/lib/canvas_sync/generators/templates/term.rb +28 -0
  15. data/lib/canvas_sync/generators/templates/user.rb +6 -0
  16. data/lib/canvas_sync/importers/bulk_importer.rb +54 -0
  17. data/lib/canvas_sync/jobs/application_job.rb +25 -0
  18. data/lib/canvas_sync/jobs/report_checker.rb +48 -0
  19. data/lib/canvas_sync/jobs/report_processor_job.rb +36 -0
  20. data/lib/canvas_sync/jobs/report_starter.rb +29 -0
  21. data/lib/canvas_sync/jobs/sync_provisioning_report_job.rb +58 -0
  22. data/lib/canvas_sync/jobs/sync_terms_job.rb +23 -0
  23. data/lib/canvas_sync/jobs/sync_users_job.rb +32 -0
  24. data/lib/canvas_sync/processors/provisioning_report_processor.rb +118 -0
  25. data/lib/canvas_sync/version.rb +3 -0
  26. data/spec/canvas_sync/canvas_sync_spec.rb +60 -0
  27. data/spec/canvas_sync/jobs/report_checker_spec.rb +62 -0
  28. data/spec/canvas_sync/jobs/report_processor_job_spec.rb +30 -0
  29. data/spec/canvas_sync/jobs/report_starter_spec.rb +27 -0
  30. data/spec/canvas_sync/jobs/sync_provisioning_report_job_spec.rb +81 -0
  31. data/spec/canvas_sync/jobs/sync_terms_job_spec.rb +18 -0
  32. data/spec/canvas_sync/jobs/sync_users_job_spec.rb +18 -0
  33. data/spec/canvas_sync/models/course_spec.rb +30 -0
  34. data/spec/canvas_sync/models/enrollment_spec.rb +30 -0
  35. data/spec/canvas_sync/models/section_spec.rb +24 -0
  36. data/spec/canvas_sync/models/term_spec.rb +71 -0
  37. data/spec/canvas_sync/models/user_spec.rb +18 -0
  38. data/spec/canvas_sync/processors/provisioning_report_processor_spec.rb +41 -0
  39. data/spec/dummy/README.rdoc +1 -0
  40. data/spec/dummy/Rakefile +6 -0
  41. data/spec/dummy/app/models/application_record.rb +3 -0
  42. data/spec/dummy/app/models/course.rb +14 -0
  43. data/spec/dummy/app/models/enrollment.rb +14 -0
  44. data/spec/dummy/app/models/section.rb +13 -0
  45. data/spec/dummy/app/models/term.rb +34 -0
  46. data/spec/dummy/app/models/user.rb +12 -0
  47. data/spec/dummy/bin/rails +4 -0
  48. data/spec/dummy/config.ru +4 -0
  49. data/spec/dummy/config/application.rb +26 -0
  50. data/spec/dummy/config/boot.rb +5 -0
  51. data/spec/dummy/config/database.yml +25 -0
  52. data/spec/dummy/config/environment.rb +5 -0
  53. data/spec/dummy/config/environments/development.rb +41 -0
  54. data/spec/dummy/config/environments/test.rb +42 -0
  55. data/spec/dummy/config/initializers/assets.rb +11 -0
  56. data/spec/dummy/config/initializers/session_store.rb +3 -0
  57. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  58. data/spec/dummy/config/routes.rb +2 -0
  59. data/spec/dummy/config/secrets.yml +22 -0
  60. data/spec/dummy/db/development.sqlite3 +0 -0
  61. data/spec/dummy/db/migrate/20170831220702_create_courses.rb +27 -0
  62. data/spec/dummy/db/migrate/20170831221129_create_users.rb +24 -0
  63. data/spec/dummy/db/migrate/20170905192509_create_enrollments.rb +32 -0
  64. data/spec/dummy/db/migrate/20170906193506_create_terms.rb +24 -0
  65. data/spec/dummy/db/migrate/20170906203438_create_sections.rb +26 -0
  66. data/spec/dummy/db/schema.rb +88 -0
  67. data/spec/dummy/db/test.sqlite3 +0 -0
  68. data/spec/dummy/log/development.log +828 -0
  69. data/spec/dummy/log/test.log +14582 -0
  70. data/spec/factories/course_factory.rb +10 -0
  71. data/spec/factories/enrollment_factory.rb +5 -0
  72. data/spec/factories/section_factory.rb +5 -0
  73. data/spec/factories/term_factory.rb +10 -0
  74. data/spec/factories/user_factory.rb +9 -0
  75. data/spec/spec_helper.rb +46 -0
  76. data/spec/support/fake_canvas.rb +22 -0
  77. data/spec/support/fixtures/canvas_responses/terms.json +64 -0
  78. data/spec/support/fixtures/reports/courses.csv +3 -0
  79. data/spec/support/fixtures/reports/enrollments.csv +3 -0
  80. data/spec/support/fixtures/reports/provisioning_csv +0 -0
  81. data/spec/support/fixtures/reports/provisioning_csv_unzipped/courses.csv +3 -0
  82. data/spec/support/fixtures/reports/provisioning_csv_unzipped/users.csv +4 -0
  83. data/spec/support/fixtures/reports/sections.csv +3 -0
  84. data/spec/support/fixtures/reports/users.csv +4 -0
  85. metadata +423 -0
@@ -0,0 +1,3 @@
1
+ module CanvasSync
2
+ VERSION = "0.1.1"
3
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe CanvasSync do
4
+ describe '.provisioning_sync' do
5
+ let(:canvas_base_url) { 'https://test.instructure.com' }
6
+ let(:canvas_api_token) { 'cool-api-token' }
7
+
8
+ it 'invokes the first job in the queue and passes on the rest of the job chain' do
9
+ expected_job_chain = CanvasSync.default_provisioning_report_chain(['courses'], nil)
10
+ first_job = expected_job_chain[:jobs].shift
11
+
12
+ expect(CanvasSync::Jobs::SyncTermsJob).to receive(:perform_later)
13
+ .with(
14
+ canvas_base_url,
15
+ canvas_api_token,
16
+ expected_job_chain,
17
+ first_job[:options]
18
+ )
19
+
20
+ CanvasSync.provisioning_sync(canvas_base_url, canvas_api_token, ['courses'])
21
+ end
22
+
23
+ context 'an invalid model is passed in' do
24
+ it 'raises a helpful exception' do
25
+ expect {
26
+ CanvasSync.provisioning_sync(canvas_base_url, canvas_api_token, ['courses', 'cheeses'])
27
+ }.to raise_error("Invalid model(s) specified: cheeses. Only #{CanvasSync::SUPPORTED_MODELS.join(', ')} are supported.")
28
+ end
29
+ end
30
+
31
+ describe '.default_provisioning_report_chain' do
32
+ context 'we are syncing users with a term scope' do
33
+ it 'syncs the users in a separate job that runs first' do
34
+ chain = CanvasSync.default_provisioning_report_chain(['users', 'courses'], :active)
35
+ expect(chain).to eq({
36
+ jobs: [
37
+ { job: CanvasSync::Jobs::SyncTermsJob.to_s, options: {} },
38
+ { job: CanvasSync::Jobs::SyncUsersJob.to_s, options: {} },
39
+ { job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s, options: { term_scope: 'active', models: ['courses'] } }
40
+ ],
41
+ options: {}
42
+ })
43
+ end
44
+ end
45
+
46
+ context 'we are syncing users without a term scope' do
47
+ it 'syncs users along with the rest of the provisioning report' do
48
+ chain = CanvasSync.default_provisioning_report_chain(['users', 'courses'])
49
+ expect(chain).to eq({
50
+ jobs: [
51
+ { job: CanvasSync::Jobs::SyncTermsJob.to_s, options: {} },
52
+ { job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s, options: { term_scope: nil, models: ['users', 'courses'] } }
53
+ ],
54
+ options: {}
55
+ })
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe CanvasSync::Jobs::ReportChecker do
4
+ let(:canvas_base_url) { 'https://test.instructure.com' }
5
+ let(:canvas_api_token) { 'cool-api-token' }
6
+ let(:client_double) { double('client') }
7
+ let(:report_id) { 1 }
8
+ let(:report_name) { 'provisioning_csv' }
9
+ let(:processor) { 'FakeProcessor' }
10
+
11
+ describe '#perform' do
12
+ def start_job
13
+ CanvasSync::Jobs::ReportChecker.perform_now(
14
+ canvas_base_url,
15
+ canvas_api_token,
16
+ [],
17
+ 'provisioning_csv',
18
+ report_id,
19
+ processor,
20
+ {}
21
+ )
22
+ end
23
+
24
+ context 'the report has finished' do
25
+ it 'enqueues the report processor job' do
26
+ expect_any_instance_of(Bearcat::Client).to receive(:report_status)
27
+ .with('self', report_name, report_id)
28
+ .and_return({ 'status' => 'complete', 'attachment' => { 'url' => 'blah' } })
29
+
30
+ expect(CanvasSync::Jobs::ReportProcessorJob).to receive(:perform_later)
31
+ .with(canvas_base_url, canvas_api_token, [], report_name, 'blah', processor, {})
32
+
33
+ start_job
34
+ end
35
+ end
36
+
37
+ context 'the report is still running' do
38
+ it 're-enqueues the report checker' do
39
+ expect_any_instance_of(Bearcat::Client).to receive(:report_status)
40
+ .with('self', report_name, report_id)
41
+ .and_return({ 'status' => 'running' })
42
+
43
+ expect(CanvasSync::Jobs::ReportChecker).to receive(:set).and_call_original
44
+
45
+ start_job
46
+ end
47
+ end
48
+
49
+ context 'the report has errored' do
50
+ it 'does not re-enqueue the job or enqueue the processor' do
51
+ expect_any_instance_of(Bearcat::Client).to receive(:report_status)
52
+ .with('self', report_name, report_id)
53
+ .and_return({ 'status' => 'error' })
54
+
55
+ expect(CanvasSync::Jobs::ReportChecker).to_not receive(:set)
56
+ expect(CanvasSync::Jobs::ReportProcessorJob).to_not receive(:perform_later)
57
+
58
+ expect { start_job }.to raise_error
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ class FakeProcessor; end;
4
+
5
+ RSpec.describe CanvasSync::Jobs::ReportProcessorJob do
6
+ let(:canvas_base_url) { 'https://test.instructure.com' }
7
+ let(:canvas_api_token) { 'cool-api-token' }
8
+ let(:report_name) { 'provisioning_csv' }
9
+ let(:report_url) { 'https://test.instructure.com/sample_report_download' }
10
+ let(:processor) { FakeProcessor.to_s }
11
+ let(:job_chain) { ['another-job'] }
12
+
13
+ describe '#perform' do
14
+ it 'downloads the report to a file and then calls the process method on the processor, and then invokes the next job' do
15
+ expect(IO).to receive(:copy_stream)
16
+ expect(FakeProcessor).to receive(:process)
17
+ expect(CanvasSync).to receive(:invoke_next).with(canvas_base_url, canvas_api_token, job_chain)
18
+
19
+ CanvasSync::Jobs::ReportProcessorJob.perform_now(
20
+ canvas_base_url,
21
+ canvas_api_token,
22
+ job_chain,
23
+ report_name,
24
+ report_url,
25
+ processor,
26
+ {}
27
+ )
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe CanvasSync::Jobs::ReportStarter do
4
+ let(:canvas_base_url) { 'https://test.instructure.com' }
5
+ let(:canvas_api_token) { 'cool-api-token' }
6
+ let(:report_params) { { 'parameters[users]' => true } }
7
+ let(:report_name) { 'provisioning_csv' }
8
+ let(:processor) { 'CoolProcessor' }
9
+
10
+ describe '#perform' do
11
+ it 'tells Canvas to start the report and then enqueues a ReportChecker with the report id' do
12
+ expect_any_instance_of(Bearcat::Client).to receive(:start_report)
13
+ .with('self', report_name, report_params)
14
+ .and_return({ 'id' => 1 })
15
+
16
+ expect(CanvasSync::Jobs::ReportChecker).to receive(:set).and_call_original
17
+
18
+ CanvasSync::Jobs::ReportStarter.perform_now(canvas_base_url,
19
+ canvas_api_token,
20
+ [],
21
+ report_name,
22
+ report_params,
23
+ processor,
24
+ { models: ['users'] })
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe CanvasSync::Jobs::SyncProvisioningReportJob do
4
+ let(:canvas_base_url) { 'https://test.instructure.com' }
5
+ let(:canvas_api_token) { 'cool-api-token' }
6
+
7
+ describe '#perform' do
8
+ context 'a term scope is specified' do
9
+ let!(:active_term_1) { FactoryGirl.create(:term) }
10
+ let!(:active_term_2) { FactoryGirl.create(:term) }
11
+ let!(:inactive_term_1) { FactoryGirl.create(:term, workflow_state: 'inactive') }
12
+
13
+ it 'enqueues a ReportStarter for a provisioning report for the specified models for each term' do
14
+ expect(CanvasSync::Jobs::ReportStarter).to receive(:perform_later)
15
+ .with(
16
+ canvas_base_url,
17
+ canvas_api_token,
18
+ [],
19
+ 'proservices_provisioning_csv',
20
+ {
21
+ "parameters[include_deleted]" => true,
22
+ "parameters[users]" => true,
23
+ "parameters[courses]" => true,
24
+ "parameters[enrollment_term_id]" => active_term_1.canvas_term_id
25
+ },
26
+ CanvasSync::Processors::ProvisioningReportProcessor.to_s,
27
+ { models: ['users', 'courses'], term_scope: 'active', canvas_term_id: active_term_1.canvas_term_id }
28
+ )
29
+
30
+ expect(CanvasSync::Jobs::ReportStarter).to receive(:perform_later)
31
+ .with(
32
+ canvas_base_url,
33
+ canvas_api_token,
34
+ [],
35
+ 'proservices_provisioning_csv',
36
+ {
37
+ "parameters[include_deleted]" => true,
38
+ "parameters[users]" => true,
39
+ "parameters[courses]" => true,
40
+ "parameters[enrollment_term_id]" => active_term_2.canvas_term_id
41
+ },
42
+ CanvasSync::Processors::ProvisioningReportProcessor.to_s,
43
+ { models: ['users', 'courses'], term_scope: 'active', canvas_term_id: active_term_2.canvas_term_id }
44
+ )
45
+
46
+ CanvasSync::Jobs::SyncProvisioningReportJob.perform_now(
47
+ canvas_base_url,
48
+ canvas_api_token,
49
+ [],
50
+ { models: ['users', 'courses'], term_scope: 'active' }
51
+ )
52
+ end
53
+ end
54
+
55
+ context 'a term scope is not specified' do
56
+ it 'enqueues a single ReportStarter for a provisioning report across all terms for the specified models' do
57
+ expect(CanvasSync::Jobs::ReportStarter).to receive(:perform_later)
58
+ .with(
59
+ canvas_base_url,
60
+ canvas_api_token,
61
+ [],
62
+ 'proservices_provisioning_csv',
63
+ {
64
+ "parameters[include_deleted]" => true,
65
+ "parameters[users]" => true,
66
+ "parameters[courses]" => true
67
+ },
68
+ CanvasSync::Processors::ProvisioningReportProcessor.to_s,
69
+ { models: ['users', 'courses'] }
70
+ )
71
+
72
+ CanvasSync::Jobs::SyncProvisioningReportJob.perform_now(
73
+ canvas_base_url,
74
+ canvas_api_token,
75
+ [],
76
+ { models: ['users', 'courses'] }
77
+ )
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe CanvasSync::Jobs::SyncTermsJob do
4
+ let(:canvas_base_url) { 'https://test.instructure.com' }
5
+ let(:canvas_api_token) { 'cool-api-token' }
6
+
7
+ describe '#perform' do
8
+ let(:term_params) { open_canvas_fixture('terms')['enrollment_terms'] }
9
+
10
+ it 'retrieves all terms from the Canvas API and then invokes the next job' do
11
+ expect(CanvasSync).to receive(:invoke_next).with(canvas_base_url, canvas_api_token, [])
12
+
13
+ expect {
14
+ CanvasSync::Jobs::SyncTermsJob.perform_now(canvas_base_url, canvas_api_token, [], {})
15
+ }.to change { Term.count }.by(term_params.length)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe CanvasSync::Jobs::SyncUsersJob do
4
+ let(:canvas_base_url) { 'https://test.instructure.com' }
5
+ let(:canvas_api_token) { 'cool-api-token' }
6
+
7
+ describe '#perform' do
8
+ it 'enqueues a ReportStarter for a provisioning report across all terms with just users' do
9
+ expect_any_instance_of(Bearcat::Client).to receive(:start_report)
10
+ .with('self', 'proservices_provisioning_csv', CanvasSync::Jobs::SyncUsersJob::REPORT_PARAMS)
11
+ .and_return({ 'id' => 1 })
12
+
13
+ expect(CanvasSync::Jobs::ReportChecker).to receive(:set).and_call_original
14
+
15
+ CanvasSync::Jobs::SyncUsersJob.perform_now(canvas_base_url, canvas_api_token, [], {})
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Course, type: :model do
4
+ let(:subject) { FactoryGirl.create(:course) }
5
+
6
+ describe 'validations' do
7
+ it { should validate_presence_of(:canvas_course_id) }
8
+ it { should validate_uniqueness_of(:canvas_course_id) }
9
+ end
10
+
11
+ describe 'associations' do
12
+ it do
13
+ should belong_to(:term)
14
+ .with_primary_key(:canvas_term_id)
15
+ .with_foreign_key(:canvas_term_id)
16
+ end
17
+
18
+ it do
19
+ should have_many(:enrollments)
20
+ .with_primary_key(:canvas_course_id)
21
+ .with_foreign_key(:canvas_course_id)
22
+ end
23
+
24
+ it do
25
+ should have_many(:sections)
26
+ .with_primary_key(:canvas_course_id)
27
+ .with_foreign_key(:canvas_course_id)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Enrollment, type: :model do
4
+ let(:subject) { FactoryGirl.create(:enrollment) }
5
+
6
+ describe 'validations' do
7
+ it { should validate_presence_of(:canvas_enrollment_id) }
8
+ it { should validate_uniqueness_of(:canvas_enrollment_id) }
9
+ end
10
+
11
+ describe 'associations' do
12
+ it do
13
+ should belong_to(:user)
14
+ .with_primary_key(:canvas_user_id)
15
+ .with_foreign_key(:canvas_user_id)
16
+ end
17
+
18
+ it do
19
+ should belong_to(:course)
20
+ .with_primary_key(:canvas_course_id)
21
+ .with_foreign_key(:canvas_course_id)
22
+ end
23
+
24
+ it do
25
+ should belong_to(:section)
26
+ .with_primary_key(:canvas_section_id)
27
+ .with_foreign_key(:canvas_section_id)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Section, type: :model do
4
+ let(:subject) { FactoryGirl.create(:section) }
5
+
6
+ describe 'validations' do
7
+ it { should validate_presence_of(:canvas_section_id) }
8
+ it { should validate_uniqueness_of(:canvas_section_id) }
9
+ end
10
+
11
+ describe 'associations' do
12
+ it do
13
+ should belong_to(:course)
14
+ .with_primary_key(:canvas_course_id)
15
+ .with_foreign_key(:canvas_course_id)
16
+ end
17
+
18
+ it do
19
+ should have_many(:enrollments)
20
+ .with_primary_key(:canvas_section_id)
21
+ .with_foreign_key(:canvas_section_id)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Term, type: :model do
4
+ let(:subject) { FactoryGirl.create(:term) }
5
+
6
+ describe 'validations' do
7
+ it { should validate_presence_of(:canvas_term_id) }
8
+ it { should validate_uniqueness_of(:canvas_term_id) }
9
+ end
10
+
11
+ describe 'associations' do
12
+ it do
13
+ should have_many(:courses)
14
+ .with_primary_key(:canvas_term_id)
15
+ .with_foreign_key(:canvas_term_id)
16
+ end
17
+ end
18
+
19
+ describe 'scopes' do
20
+ describe '.active' do
21
+ let!(:active_term) { FactoryGirl.create(:term, workflow_state: 'active', start_at: 2.days.ago, end_at: 3.days.from_now) }
22
+ let!(:inactive_term) { FactoryGirl.create(:term, workflow_state: 'inactive') }
23
+ let!(:completed_term) { FactoryGirl.create(:term, start_at: 2.months.ago, end_at: 1.month.ago) }
24
+ let!(:unstarted_term) { FactoryGirl.create(:term, start_at: 6.months.from_now, end_at: 1.year.from_now) }
25
+
26
+ it 'returns terms with an active workflow_state that have a start_date 15 days in the future or earlier and an end_date 15 days in the past or later' do
27
+ expect(Term.active).to match_array([active_term])
28
+ end
29
+ end
30
+ end
31
+
32
+ describe '.create_or_update' do
33
+ let(:term_params) { open_canvas_fixture('terms')['enrollment_terms'][0] }
34
+
35
+ context 'the term does not already exist' do
36
+ it 'creates it' do
37
+ expect {
38
+ Term.create_or_update(term_params)
39
+ }.to change { Term.count }.by(1)
40
+
41
+ term = Term.last
42
+ expect(term.name).to eq(term_params['name'])
43
+ expect(term.start_at).to eq(term_params['start_at'])
44
+ expect(term.end_at).to eq(term_params['end_at'])
45
+ expect(term.canvas_term_id).to eq(term_params['id'])
46
+ expect(term.grading_period_group_id).to eq(term_params['grading_period_group_id'])
47
+ expect(term.sis_id).to eq(term_params['sis_term_id'])
48
+ expect(term.workflow_state).to eq(term_params['workflow_state'])
49
+ end
50
+ end
51
+
52
+ context 'the term already exists' do
53
+ let!(:existing_term) { FactoryGirl.create(:term, canvas_term_id: term_params['id']) }
54
+
55
+ it 'updates it' do
56
+ expect {
57
+ Term.create_or_update(term_params)
58
+ }.to_not change { Term.count }
59
+
60
+ existing_term.reload
61
+ expect(existing_term.name).to eq(term_params['name'])
62
+ expect(existing_term.start_at).to eq(term_params['start_at'])
63
+ expect(existing_term.end_at).to eq(term_params['end_at'])
64
+ expect(existing_term.canvas_term_id).to eq(term_params['id'])
65
+ expect(existing_term.grading_period_group_id).to eq(term_params['grading_period_group_id'])
66
+ expect(existing_term.sis_id).to eq(term_params['sis_term_id'])
67
+ expect(existing_term.workflow_state).to eq(term_params['workflow_state'])
68
+ end
69
+ end
70
+ end
71
+ end