canvas_sync 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|