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.
- checksums.yaml +7 -0
- data/README.md +178 -0
- data/Rakefile +23 -0
- data/lib/canvas_sync.rb +96 -0
- data/lib/canvas_sync/generators/install_generator.rb +54 -0
- data/lib/canvas_sync/generators/templates/course.rb +8 -0
- data/lib/canvas_sync/generators/templates/create_courses.rb +21 -0
- data/lib/canvas_sync/generators/templates/create_enrollments.rb +26 -0
- data/lib/canvas_sync/generators/templates/create_sections.rb +20 -0
- data/lib/canvas_sync/generators/templates/create_terms.rb +18 -0
- data/lib/canvas_sync/generators/templates/create_users.rb +18 -0
- data/lib/canvas_sync/generators/templates/enrollment.rb +8 -0
- data/lib/canvas_sync/generators/templates/section.rb +7 -0
- data/lib/canvas_sync/generators/templates/term.rb +28 -0
- data/lib/canvas_sync/generators/templates/user.rb +6 -0
- data/lib/canvas_sync/importers/bulk_importer.rb +54 -0
- data/lib/canvas_sync/jobs/application_job.rb +25 -0
- data/lib/canvas_sync/jobs/report_checker.rb +48 -0
- data/lib/canvas_sync/jobs/report_processor_job.rb +36 -0
- data/lib/canvas_sync/jobs/report_starter.rb +29 -0
- data/lib/canvas_sync/jobs/sync_provisioning_report_job.rb +58 -0
- data/lib/canvas_sync/jobs/sync_terms_job.rb +23 -0
- data/lib/canvas_sync/jobs/sync_users_job.rb +32 -0
- data/lib/canvas_sync/processors/provisioning_report_processor.rb +118 -0
- data/lib/canvas_sync/version.rb +3 -0
- data/spec/canvas_sync/canvas_sync_spec.rb +60 -0
- data/spec/canvas_sync/jobs/report_checker_spec.rb +62 -0
- data/spec/canvas_sync/jobs/report_processor_job_spec.rb +30 -0
- data/spec/canvas_sync/jobs/report_starter_spec.rb +27 -0
- data/spec/canvas_sync/jobs/sync_provisioning_report_job_spec.rb +81 -0
- data/spec/canvas_sync/jobs/sync_terms_job_spec.rb +18 -0
- data/spec/canvas_sync/jobs/sync_users_job_spec.rb +18 -0
- data/spec/canvas_sync/models/course_spec.rb +30 -0
- data/spec/canvas_sync/models/enrollment_spec.rb +30 -0
- data/spec/canvas_sync/models/section_spec.rb +24 -0
- data/spec/canvas_sync/models/term_spec.rb +71 -0
- data/spec/canvas_sync/models/user_spec.rb +18 -0
- data/spec/canvas_sync/processors/provisioning_report_processor_spec.rb +41 -0
- data/spec/dummy/README.rdoc +1 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/models/application_record.rb +3 -0
- data/spec/dummy/app/models/course.rb +14 -0
- data/spec/dummy/app/models/enrollment.rb +14 -0
- data/spec/dummy/app/models/section.rb +13 -0
- data/spec/dummy/app/models/term.rb +34 -0
- data/spec/dummy/app/models/user.rb +12 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +26 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +41 -0
- data/spec/dummy/config/environments/test.rb +42 -0
- data/spec/dummy/config/initializers/assets.rb +11 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/routes.rb +2 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20170831220702_create_courses.rb +27 -0
- data/spec/dummy/db/migrate/20170831221129_create_users.rb +24 -0
- data/spec/dummy/db/migrate/20170905192509_create_enrollments.rb +32 -0
- data/spec/dummy/db/migrate/20170906193506_create_terms.rb +24 -0
- data/spec/dummy/db/migrate/20170906203438_create_sections.rb +26 -0
- data/spec/dummy/db/schema.rb +88 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +828 -0
- data/spec/dummy/log/test.log +14582 -0
- data/spec/factories/course_factory.rb +10 -0
- data/spec/factories/enrollment_factory.rb +5 -0
- data/spec/factories/section_factory.rb +5 -0
- data/spec/factories/term_factory.rb +10 -0
- data/spec/factories/user_factory.rb +9 -0
- data/spec/spec_helper.rb +46 -0
- data/spec/support/fake_canvas.rb +22 -0
- data/spec/support/fixtures/canvas_responses/terms.json +64 -0
- data/spec/support/fixtures/reports/courses.csv +3 -0
- data/spec/support/fixtures/reports/enrollments.csv +3 -0
- data/spec/support/fixtures/reports/provisioning_csv +0 -0
- data/spec/support/fixtures/reports/provisioning_csv_unzipped/courses.csv +3 -0
- data/spec/support/fixtures/reports/provisioning_csv_unzipped/users.csv +4 -0
- data/spec/support/fixtures/reports/sections.csv +3 -0
- data/spec/support/fixtures/reports/users.csv +4 -0
- metadata +423 -0
@@ -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
|