quiz_api_client 4.2.0 → 4.4.0
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 +4 -4
- data/README.md +1 -1
- data/lib/quiz_api_client/services/courses_service.rb +26 -0
- data/lib/quiz_api_client/services/items_service.rb +11 -0
- data/lib/quiz_api_client/services/quiz_clone_jobs_service.rb +11 -0
- data/lib/quiz_api_client/services/quiz_sync_job_service.rb +17 -0
- data/lib/quiz_api_client/services/quiz_sync_jobs_service.rb +16 -0
- data/lib/quiz_api_client/version.rb +1 -1
- data/lib/quiz_api_client.rb +15 -0
- data/spec/config_spec.rb +66 -0
- data/spec/contracts/interaction_types_service_spec.rb +22 -0
- data/spec/contracts/item_analyses_service_spec.rb +59 -0
- data/spec/contracts/items_service_spec.rb +59 -0
- data/spec/contracts/qti_imports_service_spec.rb +34 -0
- data/spec/contracts/quiz_clone_job_service_spec.rb +20 -0
- data/spec/contracts/quiz_clone_jobs_service_spec.rb +21 -0
- data/spec/contracts/quiz_entries_service_spec.rb +125 -0
- data/spec/contracts/quiz_service_spec.rb +68 -0
- data/spec/contracts/quiz_session_events_service_spec.rb +30 -0
- data/spec/contracts/quiz_session_result_service_spec.rb +42 -0
- data/spec/contracts/quiz_session_service_spec.rb +56 -0
- data/spec/contracts/quiz_sessions_service_spec.rb +28 -0
- data/spec/contracts/quiz_sync_job_service_spec.rb +21 -0
- data/spec/contracts/quiz_sync_jobs_service_spec.rb +21 -0
- data/spec/contracts/quizzes_service_spec.rb +80 -0
- data/spec/contracts/session_item_results_service_spec.rb +60 -0
- data/spec/contracts/session_items_service_spec.rb +21 -0
- data/spec/contracts/shared_banks_spec.rb +366 -0
- data/spec/contracts/shared_examples/http_delete_example.rb +56 -0
- data/spec/contracts/shared_examples/http_get_example.rb +139 -0
- data/spec/contracts/shared_examples/http_patch_example.rb +60 -0
- data/spec/contracts/shared_examples/http_post_example.rb +68 -0
- data/spec/contracts/shared_examples/http_put_example.rb +60 -0
- data/spec/http_client_spec.rb +347 -0
- data/spec/json_formatter_spec.rb +32 -0
- data/spec/quiz_api_client/http_request/failure_spec.rb +100 -0
- data/spec/quiz_api_client/http_request/metrics_spec.rb +75 -0
- data/spec/quiz_api_client_spec.rb +124 -0
- data/spec/services/base_api_service_spec.rb +50 -0
- data/spec/services/courses_service_spec.rb +59 -0
- data/spec/services/interaction_types_service_spec.rb +25 -0
- data/spec/services/item_analyses_service_spec.rb +76 -0
- data/spec/services/items_service_spec.rb +56 -0
- data/spec/services/jwt_service_spec.rb +66 -0
- data/spec/services/qti_imports_service_spec.rb +114 -0
- data/spec/services/quiz_analyses_service_spec.rb +44 -0
- data/spec/services/quiz_clone_job_service_spec.rb +41 -0
- data/spec/services/quiz_clone_jobs_service_spec.rb +77 -0
- data/spec/services/quiz_entries_service_spec.rb +71 -0
- data/spec/services/quiz_service_spec.rb +49 -0
- data/spec/services/quiz_session_events_service_spec.rb +42 -0
- data/spec/services/quiz_session_result_service_spec.rb +26 -0
- data/spec/services/quiz_session_service_spec.rb +49 -0
- data/spec/services/quiz_sessions_service_spec.rb +42 -0
- data/spec/services/quiz_sync_job_service_spec.rb +41 -0
- data/spec/services/quiz_sync_jobs_service_spec.rb +77 -0
- data/spec/services/quizzes_service_spec.rb +71 -0
- data/spec/services/session_item_results_service_spec.rb +33 -0
- data/spec/services/session_items_service_spec.rb +26 -0
- data/spec/spec_helper.rb +42 -0
- data/spec/support/pact_config.rb +64 -0
- data/spec/support/pact_helper.rb +19 -0
- metadata +121 -39
- data/.dockerignore +0 -7
- data/.editorconfig +0 -16
- data/.gitignore +0 -13
- data/.rspec +0 -3
- data/.rubocop.yml +0 -72
- data/CHANGELOG.md +0 -35
- data/Dockerfile +0 -12
- data/Gemfile +0 -5
- data/Jenkinsfile +0 -86
- data/bin/console +0 -7
- data/bin/contracts-generate +0 -26
- data/bin/setup +0 -65
- data/docker-compose.dev.override.yml +0 -11
- data/docker-compose.yml +0 -10
- data/quiz_api_client.gemspec +0 -60
@@ -0,0 +1,124 @@
|
|
1
|
+
describe QuizApiClient do
|
2
|
+
it 'has a version number' do
|
3
|
+
expect(QuizApiClient::VERSION).not_to be nil
|
4
|
+
end
|
5
|
+
|
6
|
+
context 'service helper methods' do
|
7
|
+
let(:host) { 'api.host' }
|
8
|
+
let(:shared_secret) { 'secret' }
|
9
|
+
let(:protocol) { 'http' }
|
10
|
+
let(:consumer_key) { 'some consumer_key' }
|
11
|
+
let(:consumer_request_id) { 'guid_value' }
|
12
|
+
let(:subject) do
|
13
|
+
QuizApiClient::Client.new(
|
14
|
+
consumer_key: consumer_key,
|
15
|
+
consumer_request_id: consumer_request_id,
|
16
|
+
host: host,
|
17
|
+
shared_secret: shared_secret,
|
18
|
+
protocol: protocol
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#config' do
|
23
|
+
it 'should populate the values' do
|
24
|
+
config = subject.config
|
25
|
+
expect(config.consumer_key).to eq consumer_key
|
26
|
+
expect(config.consumer_request_id).to eq consumer_request_id
|
27
|
+
expect(config.host).to eq host
|
28
|
+
expect(config.shared_secret).to eq shared_secret
|
29
|
+
expect(config.protocol).to eq protocol
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should yield the config on instantiation' do
|
33
|
+
client = QuizApiClient::Client.new(
|
34
|
+
consumer_key: consumer_key,
|
35
|
+
consumer_request_id: consumer_request_id,
|
36
|
+
host: host,
|
37
|
+
shared_secret: shared_secret,
|
38
|
+
protocol: protocol
|
39
|
+
) do |config|
|
40
|
+
config.host = 'my.hosting'
|
41
|
+
end
|
42
|
+
|
43
|
+
expect(client.config.host).to eq 'my.hosting'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#jwt_service' do
|
48
|
+
it 'should create the service' do
|
49
|
+
expect(QuizApiClient::Services::JwtService).to receive(:new).with(subject.config)
|
50
|
+
subject.jwt_service
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#courses_service' do
|
55
|
+
it 'creates the service' do
|
56
|
+
expect(QuizApiClient::Services::CoursesService).to receive(:new).with(subject.config)
|
57
|
+
subject.courses_service
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#quizzes_service' do
|
62
|
+
it 'should create the service' do
|
63
|
+
expect(QuizApiClient::Services::QuizzesService).to receive(:new).with(subject.config)
|
64
|
+
subject.quizzes_service
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe '#quiz_session_service' do
|
69
|
+
it 'should create the service' do
|
70
|
+
expect(QuizApiClient::Services::QuizSessionService).to receive(:new).with(subject.config)
|
71
|
+
subject.quiz_session_service
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#quiz_sessions_service' do
|
76
|
+
it 'should create the service' do
|
77
|
+
expect(QuizApiClient::Services::QuizSessionsService).to receive(:new).with(subject.config)
|
78
|
+
subject.quiz_sessions_service
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe '#qti_imports_service' do
|
83
|
+
it 'should create the service' do
|
84
|
+
expect(QuizApiClient::Services::QtiImportsService).to receive(:new).with(subject.config)
|
85
|
+
subject.qti_imports_service
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe '#item_analyses_service' do
|
90
|
+
it 'should create the service' do
|
91
|
+
expect(QuizApiClient::Services::ItemAnalysesService).to receive(:new).with(subject.config)
|
92
|
+
subject.item_analyses_service
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe '#quiz_analyses_service' do
|
97
|
+
it 'should create the service' do
|
98
|
+
expect(QuizApiClient::Services::QuizAnalysesService).to receive(:new).with(subject.config)
|
99
|
+
subject.quiz_analyses_service
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe '#quiz_session_events_service' do
|
104
|
+
it 'should create the service' do
|
105
|
+
expect(QuizApiClient::Services::QuizSessionEventsService).to receive(:new).with(subject.config)
|
106
|
+
subject.quiz_session_events_service
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe '#items_service' do
|
111
|
+
it 'should create the service' do
|
112
|
+
expect(QuizApiClient::Services::ItemsService).to receive(:new).with(subject.config)
|
113
|
+
subject.items_service
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe '#interaction_types_service' do
|
118
|
+
it 'should create the service' do
|
119
|
+
expect(QuizApiClient::Services::InteractionTypesService).to receive(:new).with(subject.config)
|
120
|
+
subject.interaction_types_service
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
describe QuizApiClient::Services::BaseApiService do
|
2
|
+
let(:consumer_key) { 'consumer key' }
|
3
|
+
let(:host) { 'api.host' }
|
4
|
+
let(:shared_secret) { 'secret' }
|
5
|
+
let(:protocol) { 'http' }
|
6
|
+
let(:service_class) do
|
7
|
+
Class.new(QuizApiClient::Services::BaseApiService) do
|
8
|
+
def test_uri
|
9
|
+
uri
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
let(:service) do
|
14
|
+
service_class.new(QuizApiClient::Config.new do |c|
|
15
|
+
c.consumer_key = consumer_key
|
16
|
+
c.host = host
|
17
|
+
c.shared_secret = shared_secret
|
18
|
+
c.protocol = protocol
|
19
|
+
end)
|
20
|
+
end
|
21
|
+
|
22
|
+
def decode_token(token, secret)
|
23
|
+
JWT.decode(
|
24
|
+
token, secret, true,
|
25
|
+
algorithm: QuizApiClient::Services::JwtService::HASHING_ALGORITHM
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#uri' do
|
30
|
+
it 'returns full URI' do
|
31
|
+
expect(service.test_uri).to eq 'http://api.host'
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'with https protocol' do
|
35
|
+
let(:protocol) { 'https' }
|
36
|
+
|
37
|
+
it 'uses specified protocol' do
|
38
|
+
expect(service.test_uri).to eq 'https://api.host'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'with port specified in host' do
|
43
|
+
let(:host) { 'api.host:8443' }
|
44
|
+
|
45
|
+
it 'includes port in URI' do
|
46
|
+
expect(service.test_uri).to eq 'http://api.host:8443'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
describe QuizApiClient::Services::CoursesService do
|
2
|
+
let(:host) { 'api.host' }
|
3
|
+
let(:config) { QuizApiClient::Config.new { |c| c.host = host } }
|
4
|
+
let(:subject) { described_class.new(config) }
|
5
|
+
|
6
|
+
describe '#create' do
|
7
|
+
let(:params) do
|
8
|
+
{
|
9
|
+
title: 'foo',
|
10
|
+
canvas_id: 2,
|
11
|
+
is_blueprint: true
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:response) do
|
16
|
+
{
|
17
|
+
'id' => '4',
|
18
|
+
'title' => 'foo',
|
19
|
+
'canvas_id' => '2',
|
20
|
+
'is_blueprint' => true,
|
21
|
+
'created_at' => '2022-06-22T18:59:27.577Z',
|
22
|
+
'updated_at' => '2022-06-22T18:59:27.577Z'
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:expected_url) { "https://#{host}/api/courses" }
|
27
|
+
|
28
|
+
before do
|
29
|
+
stub_request(:post, expected_url)
|
30
|
+
.with(body: { course: params }.to_json)
|
31
|
+
.to_return(
|
32
|
+
status: 201,
|
33
|
+
body: response.to_json,
|
34
|
+
headers: { 'Content-Type' => 'application/json' }
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'posts to the correct endpoint and returns the response' do
|
39
|
+
expect(
|
40
|
+
subject.create(params: params, token: 'token').parsed_response
|
41
|
+
).to eq(response)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#destroy' do
|
46
|
+
let(:params) { { canvas_id: 1 } }
|
47
|
+
let(:expected_url) { "https://#{host}/api/courses/1" }
|
48
|
+
|
49
|
+
before do
|
50
|
+
stub_request(:delete, expected_url).to_return(status: 204)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'deletes to the correct endpoint and returns the response' do
|
54
|
+
response = subject.destroy(params: params, token: 'token')
|
55
|
+
expect(response.code).to eq 204
|
56
|
+
expect(response.body).to be_nil
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
describe QuizApiClient::Services::InteractionTypesService do
|
2
|
+
let(:host) { 'api.host' }
|
3
|
+
let(:config) { QuizApiClient::Config.new { |c| c.host = host } }
|
4
|
+
let(:subject) { described_class.new(config) }
|
5
|
+
|
6
|
+
describe '#list' do
|
7
|
+
let(:status_code) { 200 }
|
8
|
+
let(:expected_url) { "https://#{host}/api/interaction_types" }
|
9
|
+
let(:stubbed_response) { [{ 'name' => 'Type One', 'id' => 1 }] }
|
10
|
+
|
11
|
+
before do
|
12
|
+
stub_request(:get, expected_url)
|
13
|
+
.to_return(
|
14
|
+
status: status_code,
|
15
|
+
body: stubbed_response.to_json,
|
16
|
+
headers: { 'Content-Type' => 'application/json' }
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'gets from quiz_api/api/interaction_types and returns the response' do
|
21
|
+
result = subject.list(token: 'token')
|
22
|
+
expect(result.parsed_response).to eql(stubbed_response)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
describe QuizApiClient::Services::ItemAnalysesService do
|
2
|
+
let(:host) { 'api.host' }
|
3
|
+
let(:config) { QuizApiClient::Config.new { |c| c.host = host } }
|
4
|
+
let(:subject) { described_class.new(config) }
|
5
|
+
|
6
|
+
describe '#list' do
|
7
|
+
let(:params) { { quiz_id: 1, id: 7 } }
|
8
|
+
let(:stubbed_response) { { 'id' => '1' } }
|
9
|
+
let(:expected_url) do
|
10
|
+
"https://#{host}/api/quizzes/#{params[:quiz_id]}/stats/item_analyses"
|
11
|
+
end
|
12
|
+
let(:expected_body) { '' }
|
13
|
+
let(:status_code) { 200 }
|
14
|
+
|
15
|
+
before do
|
16
|
+
stub_request(:get, expected_url)
|
17
|
+
.with(body: expected_body)
|
18
|
+
.to_return(
|
19
|
+
status: status_code,
|
20
|
+
body: stubbed_response.to_json,
|
21
|
+
headers: { 'Content-Type' => 'application/json' }
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'posts to /api/quizzes/1/stats/item_analyses and returns the response' do
|
26
|
+
result = subject.list(params: params, token: 'token')
|
27
|
+
expect(result.parsed_response).to eql(stubbed_response)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'raises an error when no quiz_id is specified' do
|
31
|
+
params = {}
|
32
|
+
expect do
|
33
|
+
subject.list(params: params, token: 'token')
|
34
|
+
end.to raise_error 'Quiz Id Required'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '#get' do
|
39
|
+
let(:params) { { quiz_id: 1, id: 7 } }
|
40
|
+
let(:stubbed_response) { { 'id' => '1' } }
|
41
|
+
let(:expected_url) do
|
42
|
+
"https://#{host}/api/quizzes/#{params[:quiz_id]}/stats/item_analyses/#{params[:id]}"
|
43
|
+
end
|
44
|
+
let(:expected_body) { '' }
|
45
|
+
let(:status_code) { 200 }
|
46
|
+
|
47
|
+
before do
|
48
|
+
stub_request(:get, expected_url)
|
49
|
+
.with(body: expected_body)
|
50
|
+
.to_return(
|
51
|
+
status: status_code,
|
52
|
+
body: stubbed_response.to_json,
|
53
|
+
headers: { 'Content-Type' => 'application/json' }
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'posts to /api/quizzes/1/stats/item_analyses/7 and returns the response' do
|
58
|
+
result = subject.get(params: params, token: 'token')
|
59
|
+
expect(result.parsed_response).to eql(stubbed_response)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'raises an error when no quiz_id is specified' do
|
63
|
+
params = {}
|
64
|
+
expect do
|
65
|
+
subject.list(params: params, token: 'token')
|
66
|
+
end.to raise_error 'Quiz Id Required'
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'response' do
|
70
|
+
it 'returns the response with the correct status code' do
|
71
|
+
response = subject.get(params: params, token: 'token')
|
72
|
+
expect(response.code).to eq(status_code)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
describe QuizApiClient::Services::ItemsService do
|
2
|
+
let(:host) { 'api.host' }
|
3
|
+
let(:config) { QuizApiClient::Config.new { |c| c.host = host } }
|
4
|
+
let(:subject) { described_class.new(config) }
|
5
|
+
|
6
|
+
describe '#list' do
|
7
|
+
let(:params) { { quiz_id: 1 } }
|
8
|
+
let(:stubbed_response) { { 'id' => 1, 'item' => { 'id' => 1 } } }
|
9
|
+
let(:expected_url) { "https://#{host}/api/quizzes/#{params[:quiz_id]}/items" }
|
10
|
+
let(:status_code) { 200 }
|
11
|
+
|
12
|
+
before do
|
13
|
+
stub_request(:get, expected_url)
|
14
|
+
.to_return(
|
15
|
+
status: status_code,
|
16
|
+
body: stubbed_response.to_json,
|
17
|
+
headers: { 'Content-Type' => 'application/json' }
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'list from quiz_api/api/quizzes/{id}/items and returns the response' do
|
22
|
+
result = subject.list(params: params, token: 'token')
|
23
|
+
expect(result.parsed_response).to eql(stubbed_response)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#create' do
|
28
|
+
let(:params) do
|
29
|
+
{
|
30
|
+
quiz_id: 1,
|
31
|
+
item_body: 'item body',
|
32
|
+
scoring_data: { value: 'value' },
|
33
|
+
scoring_algorithm: 'Equivalence',
|
34
|
+
interaction_type_id: 'choice',
|
35
|
+
user_response_type: 'response type'
|
36
|
+
}
|
37
|
+
end
|
38
|
+
let(:stubbed_response) { { 'id' => 1, 'item' => { 'id' => 1 } } }
|
39
|
+
let(:expected_url) { "https://#{host}/api/quizzes/#{params[:quiz_id]}/items" }
|
40
|
+
let(:status_code) { 201 }
|
41
|
+
|
42
|
+
before do
|
43
|
+
stub_request(:post, expected_url)
|
44
|
+
.to_return(
|
45
|
+
status: status_code,
|
46
|
+
body: stubbed_response.to_json,
|
47
|
+
headers: { 'Content-Type' => 'application/json' }
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'posts to quiz_api/api/quizzes/{id}/items and returns the response' do
|
52
|
+
result = subject.create(params: params, token: 'token')
|
53
|
+
expect(result.parsed_response).to eql(stubbed_response)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
describe QuizApiClient::Services::JwtService do
|
2
|
+
let(:host) { 'test.host' }
|
3
|
+
let(:shared_secret) { 'secret' }
|
4
|
+
let(:consumer_key) { 'some consumer_key' }
|
5
|
+
|
6
|
+
let(:config) do
|
7
|
+
QuizApiClient::Config.new do |c|
|
8
|
+
c.shared_secret = shared_secret
|
9
|
+
c.host = host
|
10
|
+
c.consumer_key = consumer_key
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
subject do
|
15
|
+
QuizApiClient::Services::JwtService.new(config)
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'grant_permission' do
|
19
|
+
it 'generates a JWT using the shared_secret' do
|
20
|
+
jwt = subject.grant_permission(scope: 'quiz.create')
|
21
|
+
|
22
|
+
payload, header = JWT.decode(jwt, shared_secret, true, algorithm: 'HS512')
|
23
|
+
|
24
|
+
expect(payload['host']).to eq(host)
|
25
|
+
expect(payload['scope']).to eq('quiz.create')
|
26
|
+
expect(payload['consumer_key']).to eq(consumer_key)
|
27
|
+
expect(payload).not_to have_key('resource_id')
|
28
|
+
expect(payload).not_to have_key('user')
|
29
|
+
expect(payload).to have_key('exp')
|
30
|
+
expect(header['alg']).to eq('HS512')
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'includes user uuid in payload when provided' do
|
34
|
+
jwt = subject.grant_permission(scope: 'quiz.create', uuid: '123')
|
35
|
+
|
36
|
+
payload = JWT.decode(jwt, shared_secret, true, algorithm: 'HS512').first
|
37
|
+
|
38
|
+
expect(payload['user']).to eq('uuid' => '123')
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'merges in other provided user context' do
|
42
|
+
jwt = subject.grant_permission(scope: 'quiz.create', uuid: '123', user: { email: 'test@example.com' })
|
43
|
+
|
44
|
+
payload = JWT.decode(jwt, shared_secret, true, algorithm: 'HS512').first
|
45
|
+
|
46
|
+
expect(payload['user']).to eq('uuid' => '123', 'email' => 'test@example.com')
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'allows arbitrary additional params' do
|
50
|
+
jwt = subject.grant_permission(scope: 'quiz.create', foo: 'bar', monkey: 'do')
|
51
|
+
payload = JWT.decode(jwt, shared_secret, true, algorithm: 'HS512').first
|
52
|
+
expect(payload['foo']).to eq 'bar'
|
53
|
+
expect(payload['monkey']).to eq 'do'
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'with port in host' do
|
57
|
+
let(:host) { 'test.host:8443' }
|
58
|
+
|
59
|
+
it 'leaves port out of payload host' do
|
60
|
+
jwt = subject.grant_permission scope: 'quiz.build'
|
61
|
+
payload, _header = JWT.decode(jwt, shared_secret, true, algorithm: 'HS512')
|
62
|
+
expect(payload['host']).to eq 'test.host'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
describe QuizApiClient::Services::QtiImportsService do
|
2
|
+
let(:host) { 'api.host' }
|
3
|
+
let(:config) { QuizApiClient::Config.new { |c| c.host = host } }
|
4
|
+
let(:subject) { described_class.new(config) }
|
5
|
+
|
6
|
+
describe '#create' do
|
7
|
+
let(:params) { { url: 'https://fake-s3-url.com', quiz_id: 1 } }
|
8
|
+
let(:stubbed_response) { { 'id' => '1', 'status' => 'created' } }
|
9
|
+
let(:expected_url) { "https://#{host}/api/quizzes/1/qti_imports" }
|
10
|
+
let(:expected_body) { {} }
|
11
|
+
let(:status_code) { 200 }
|
12
|
+
|
13
|
+
before do
|
14
|
+
stub_request(:post, expected_url)
|
15
|
+
.with(body: expected_body)
|
16
|
+
.to_return(
|
17
|
+
status: 200,
|
18
|
+
body: stubbed_response.to_json,
|
19
|
+
headers: { 'Content-Type' => 'application/json' }
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'posts to quiz_api/api/qti_imports and returns the response' do
|
24
|
+
result = subject.create(params: params, token: 'token')
|
25
|
+
expect(result.parsed_response).to eql(stubbed_response)
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'response' do
|
29
|
+
it 'returns the response with the correct code' do
|
30
|
+
response = subject.create(params: params, token: 'token')
|
31
|
+
expect(response.code).to eq(status_code)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'no quiz id provided' do
|
36
|
+
let(:params) {}
|
37
|
+
it 'raises Quiz Id Required' do
|
38
|
+
expect do
|
39
|
+
subject.create(params: params, token: 'token')
|
40
|
+
end.to raise_error('Quiz Id Required')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#banks' do
|
46
|
+
let(:params) { { everything: false, overwrite: false, assessment_question_banks: ['abc123'] } }
|
47
|
+
let(:stubbed_response) { { 'id' => '1', 'status' => 'created' } }
|
48
|
+
let(:expected_url) { "https://#{host}/api/qti_imports/banks" }
|
49
|
+
let(:expected_body) { {} }
|
50
|
+
let(:status_code) { 200 }
|
51
|
+
|
52
|
+
before do
|
53
|
+
stub_request(:post, expected_url)
|
54
|
+
.with(body: expected_body)
|
55
|
+
.to_return(
|
56
|
+
status: 200,
|
57
|
+
body: stubbed_response.to_json,
|
58
|
+
headers: { 'Content-Type' => 'application/json' }
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'posts to quiz_api/api/qti_imports and returns the response' do
|
63
|
+
result = subject.banks(params: params, token: 'token')
|
64
|
+
expect(result.parsed_response).to eql(stubbed_response)
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'response' do
|
68
|
+
it 'returns the response with the correct code' do
|
69
|
+
response = subject.banks(params: params, token: 'token')
|
70
|
+
expect(response.code).to eq(status_code)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#get_imported_consumer_settings' do
|
76
|
+
let(:params) { { quiz_id: 1 } }
|
77
|
+
let(:stubbed_response) { { 'score_to_keep' => 'highest', 'max_attempts' => '10' } }
|
78
|
+
let(:expected_url) { "https://#{host}/api/quizzes/1/qti_imports/imported_consumer_settings" }
|
79
|
+
|
80
|
+
let(:expected_body) { {} }
|
81
|
+
let(:status_code) { 200 }
|
82
|
+
|
83
|
+
before do
|
84
|
+
stub_request(:get, expected_url)
|
85
|
+
.with(body: expected_body)
|
86
|
+
.to_return(
|
87
|
+
status: 200,
|
88
|
+
body: stubbed_response.to_json,
|
89
|
+
headers: { 'Content-Type' => 'application/json' }
|
90
|
+
)
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'posts to quiz_api/api/qti_imports and returns the response' do
|
94
|
+
result = subject.get_imported_consumer_settings(params: params, token: 'token')
|
95
|
+
expect(result.parsed_response).to eql(stubbed_response)
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'response' do
|
99
|
+
it 'returns the response with the correct code' do
|
100
|
+
response = subject.get_imported_consumer_settings(params: params, token: 'token')
|
101
|
+
expect(response.code).to eq(status_code)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'no quiz id provided' do
|
106
|
+
let(:params) {}
|
107
|
+
it 'raises Quiz Id Required' do
|
108
|
+
expect do
|
109
|
+
subject.create(params: params, token: 'token')
|
110
|
+
end.to raise_error('Quiz Id Required')
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
describe QuizApiClient::Services::QuizAnalysesService do
|
2
|
+
let(:host) { 'api.host' }
|
3
|
+
let(:config) { QuizApiClient::Config.new { |c| c.host = host } }
|
4
|
+
let(:subject) { described_class.new(config) }
|
5
|
+
|
6
|
+
describe '#list' do
|
7
|
+
let(:params) { { quiz_id: 1 } }
|
8
|
+
let(:stubbed_response) { { 'id' => '1' } }
|
9
|
+
let(:expected_url) do
|
10
|
+
"https://#{host}/api/quizzes/#{params[:quiz_id]}/stats/quiz_analysis"
|
11
|
+
end
|
12
|
+
let(:expected_body) { '' }
|
13
|
+
let(:status_code) { 200 }
|
14
|
+
|
15
|
+
before do
|
16
|
+
stub_request(:get, expected_url)
|
17
|
+
.with(body: expected_body)
|
18
|
+
.to_return(
|
19
|
+
status: status_code,
|
20
|
+
body: stubbed_response.to_json,
|
21
|
+
headers: { 'Content-Type' => 'application/json' }
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'posts to quiz_api/api/quizzes and returns the response' do
|
26
|
+
result = subject.get(params: params, token: 'token')
|
27
|
+
expect(result.parsed_response).to eql(stubbed_response)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'raises an error when no quiz_id is specified' do
|
31
|
+
params = {}
|
32
|
+
expect do
|
33
|
+
subject.get(params: params, token: 'token')
|
34
|
+
end.to raise_error 'Quiz Id Required'
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'response' do
|
38
|
+
it 'returns the response with the correct status code' do
|
39
|
+
response = subject.get(params: params, token: 'token')
|
40
|
+
expect(response.code).to eq(status_code)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
describe QuizApiClient::Services::QuizCloneJobService do
|
2
|
+
let(:host) { 'api.host' }
|
3
|
+
let(:config) { QuizApiClient::Config.new { |c| c.host = host } }
|
4
|
+
let(:subject) { described_class.new(config) }
|
5
|
+
|
6
|
+
describe '#show' do
|
7
|
+
let(:expected_url) { "https://#{host}/api/quiz_clone_jobs/#{params[:id]}" }
|
8
|
+
let(:params) { { id: 1 } }
|
9
|
+
let(:stubbed_response) { { 'id' => 1, 'original_quiz_id' => 666, 'status' => 'completed' } }
|
10
|
+
|
11
|
+
context 'on success' do
|
12
|
+
before do
|
13
|
+
stub_request(:get, expected_url)
|
14
|
+
.to_return(
|
15
|
+
status: 200,
|
16
|
+
body: stubbed_response.to_json,
|
17
|
+
headers: { 'Content-Type' => 'application/json' }
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'gets from /api/quiz_clone_jobs/:id' do
|
22
|
+
result = subject.show(params: params, token: 'token')
|
23
|
+
expect(result.parsed_response).to eql(stubbed_response)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'on failure' do
|
28
|
+
let(:status_code) { 401 }
|
29
|
+
|
30
|
+
before do
|
31
|
+
stub_request(:get, expected_url)
|
32
|
+
.to_return(status: status_code)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'returns a response with the correct code' do
|
36
|
+
response = subject.show(params: params, token: 'token')
|
37
|
+
expect(response.code).to eq(status_code)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|