quiz_api_client 4.1.0 → 4.3.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 +4 -0
- data/lib/quiz_api_client/config.rb +29 -8
- data/lib/quiz_api_client/http_client.rb +11 -40
- data/lib/quiz_api_client/http_request/failure.rb +65 -0
- data/lib/quiz_api_client/http_request/metrics.rb +67 -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 +12 -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 +117 -0
- data/spec/services/base_api_service_spec.rb +50 -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 +130 -35
- 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 -28
- 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 -59
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 11e55f74ad6fd90e5f09e214394d3d44103e7027d83ce03299f5670cbc79111d
|
4
|
+
data.tar.gz: 836308804ec45f08806c57bf63c6d7b9167e03eee52d955e7bca38b310f75305
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9ed1d073d41458ff170b5767eec5d37e560af8211f6fa5da0906d7d644411a9a4e589c7d644b807300dd76400374e0e9bcd58d4595bd2e4004d65d228e4afb9f
|
7
|
+
data.tar.gz: 26d1ce56705ad6a1ba18c93175ae572e4ab54e95438513095c663c6a3d6efda3a57cce29ff432ac6885b5bf139305f954bab53890360b89945fdc0c48878b123
|
data/README.md
CHANGED
@@ -41,6 +41,10 @@ client = QuizApiClient::Client.new(
|
|
41
41
|
|
42
42
|
In order to set addition error information in your error handling system, you can set the `error_hander` property of the config. The list of valid values can be found in the `QuizApiClient::Config::ERROR_HANDLERS` constant.
|
43
43
|
|
44
|
+
### Metrics
|
45
|
+
|
46
|
+
HTTP Request metrics will now be provided if the `setup_metrics` method is called. The list of valid values can be found in the `QuizApiClient::Config::METRICS_HANDLERS` constant. The count and duration metrics will be provided under the namespace provided.
|
47
|
+
|
44
48
|
### Creation of Tokens
|
45
49
|
|
46
50
|
JWTs are created without hitting quiz_api and and they are validated on quiz_api. Tokens are created for a given scope, expiration, and an optional resource_id.
|
@@ -3,10 +3,13 @@ module QuizApiClient
|
|
3
3
|
DEFAULT_ALLOWABLE_RESPONSE_CODES = [401, 422].freeze
|
4
4
|
DEFAULT_PROTOCOL = 'https'.freeze
|
5
5
|
ERROR_HANDLERS = %i[sentry_raven].freeze
|
6
|
+
METRICS_HANDLERS = %i[inststatsd].freeze
|
6
7
|
|
7
8
|
class InvalidErrorHandler < StandardError; end
|
9
|
+
class InvalidMetricsHandler < StandardError; end
|
10
|
+
class InvalidMetricsNamespace < StandardError; end
|
8
11
|
|
9
|
-
attr_reader :error_handler
|
12
|
+
attr_reader :error_handler, :metrics_handler, :metrics_namespace
|
10
13
|
attr_writer :protocol, :allowable_response_codes
|
11
14
|
attr_accessor :consumer_key, :consumer_request_id, :host, :shared_secret
|
12
15
|
|
@@ -19,9 +22,17 @@ module QuizApiClient
|
|
19
22
|
end
|
20
23
|
|
21
24
|
def error_handler=(handler)
|
22
|
-
|
25
|
+
validate_error_handler!(handler)
|
23
26
|
|
24
|
-
@error_handler = handler
|
27
|
+
@error_handler = handler.to_sym
|
28
|
+
end
|
29
|
+
|
30
|
+
def setup_metrics(handler, namespace)
|
31
|
+
validate_metrics_handler!(handler)
|
32
|
+
validate_metrics_namespace!(namespace)
|
33
|
+
|
34
|
+
@metrics_handler = handler.to_sym
|
35
|
+
@metrics_namespace = namespace.to_s.strip
|
25
36
|
end
|
26
37
|
|
27
38
|
def allowable_response_codes
|
@@ -30,14 +41,24 @@ module QuizApiClient
|
|
30
41
|
|
31
42
|
private
|
32
43
|
|
33
|
-
def
|
44
|
+
def validate_error_handler!(handler)
|
34
45
|
return unless handler
|
46
|
+
return if ERROR_HANDLERS.include?(handler)
|
35
47
|
|
36
|
-
|
37
|
-
|
38
|
-
end
|
48
|
+
raise InvalidErrorHandler, "It must be one of the following: #{ERROR_HANDLERS.inspect}"
|
49
|
+
end
|
39
50
|
|
40
|
-
|
51
|
+
def validate_metrics_handler!(handler)
|
52
|
+
return unless handler
|
53
|
+
return if METRICS_HANDLERS.include?(handler)
|
54
|
+
|
55
|
+
raise InvalidMetricsHandler, "It must be one of the following: #{METRICS_HANDLERS.inspect}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def validate_metrics_namespace!(namespace)
|
59
|
+
return unless namespace.nil? || namespace.to_s.strip == ''
|
60
|
+
|
61
|
+
raise InvalidMetricsNamespace, 'It must be present'
|
41
62
|
end
|
42
63
|
end
|
43
64
|
end
|
@@ -82,6 +82,7 @@ module QuizApiClient
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def make_request(method, url, request_options = {})
|
85
|
+
start_time = Time.now
|
85
86
|
resp = self.class.send(
|
86
87
|
method,
|
87
88
|
url,
|
@@ -91,6 +92,8 @@ module QuizApiClient
|
|
91
92
|
resp
|
92
93
|
rescue HTTParty::Error, Errno::ECONNREFUSED, Net::ReadTimeout => e
|
93
94
|
raise_error(method, url, current_error: e)
|
95
|
+
ensure
|
96
|
+
record_metrics(method, url, resp, start_time, Time.now)
|
94
97
|
end
|
95
98
|
|
96
99
|
def make_paginated_request(method, url, options)
|
@@ -146,50 +149,18 @@ module QuizApiClient
|
|
146
149
|
[url, options.merge(query: query)]
|
147
150
|
end
|
148
151
|
|
149
|
-
def
|
150
|
-
|
151
|
-
quiz_api_client: {
|
152
|
-
request: {
|
153
|
-
method: method,
|
154
|
-
url: url
|
155
|
-
}
|
156
|
-
}
|
157
|
-
}
|
158
|
-
|
159
|
-
if response
|
160
|
-
context[:quiz_api_client][:response] = {
|
161
|
-
body: response.body,
|
162
|
-
code: response.code
|
163
|
-
}
|
164
|
-
end
|
165
|
-
|
166
|
-
context
|
167
|
-
end
|
168
|
-
|
169
|
-
def record_error_context(context)
|
170
|
-
case config.error_handler
|
171
|
-
when :sentry_raven
|
172
|
-
require 'sentry-raven'
|
173
|
-
Raven.extra_context(context)
|
174
|
-
end
|
175
|
-
end
|
152
|
+
def raise_error(method, url, response: nil, current_error: nil)
|
153
|
+
failure = QuizApiClient::HttpRequest::Failure.new(config)
|
176
154
|
|
177
|
-
|
178
|
-
if current_error && response
|
179
|
-
"#{current_error.message}: #{url} responded #{response.body} (#{response.code})"
|
180
|
-
elsif current_error
|
181
|
-
current_error.message
|
182
|
-
elsif response
|
183
|
-
"#{url} responded #{response.body} (#{response.code})"
|
184
|
-
end
|
155
|
+
failure.raise_error(method, url, response: response, current_error: current_error)
|
185
156
|
end
|
186
157
|
|
187
|
-
def
|
188
|
-
|
189
|
-
|
190
|
-
record_error_context(context)
|
158
|
+
def record_metrics(method, url, resp, start_time, end_time)
|
159
|
+
code = resp&.code || 0
|
160
|
+
metrics = QuizApiClient::HttpRequest::Metrics.new(config, method, url, code)
|
191
161
|
|
192
|
-
|
162
|
+
metrics.increment
|
163
|
+
metrics.duration(start_time, end_time)
|
193
164
|
end
|
194
165
|
|
195
166
|
def successful_response?(resp)
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module QuizApiClient
|
2
|
+
module HttpRequest
|
3
|
+
class Failure
|
4
|
+
attr_reader :config
|
5
|
+
|
6
|
+
def initialize(config)
|
7
|
+
@config = config
|
8
|
+
end
|
9
|
+
|
10
|
+
def raise_error(
|
11
|
+
method,
|
12
|
+
url,
|
13
|
+
response: nil,
|
14
|
+
current_error: nil,
|
15
|
+
error_class: QuizApiClient::HttpClient::RequestFailed
|
16
|
+
)
|
17
|
+
context = generate_error_context(method, url, response)
|
18
|
+
|
19
|
+
record_error_context(context)
|
20
|
+
|
21
|
+
raise error_class.new(context), error_message(current_error, url, response)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def generate_error_context(method, url, response = nil)
|
27
|
+
context = {
|
28
|
+
quiz_api_client: {
|
29
|
+
request: {
|
30
|
+
method: method,
|
31
|
+
url: url
|
32
|
+
}
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
if response
|
37
|
+
context[:quiz_api_client][:response] = {
|
38
|
+
body: response.body,
|
39
|
+
code: response.code
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
context
|
44
|
+
end
|
45
|
+
|
46
|
+
def record_error_context(context)
|
47
|
+
case config.error_handler
|
48
|
+
when :sentry_raven
|
49
|
+
require 'sentry-raven'
|
50
|
+
Raven.extra_context(context)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def error_message(current_error, url, response)
|
55
|
+
if current_error && response
|
56
|
+
"#{current_error.message}: #{url} responded #{response.body} (#{response.code})"
|
57
|
+
elsif current_error
|
58
|
+
current_error.message
|
59
|
+
elsif response
|
60
|
+
"#{url} responded #{response.body} (#{response.code})"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module QuizApiClient
|
2
|
+
module HttpRequest
|
3
|
+
class Metrics
|
4
|
+
extend Forwardable
|
5
|
+
|
6
|
+
attr_reader :config, :method, :url, :code
|
7
|
+
def_delegators :config, :metrics_handler, :metrics_namespace
|
8
|
+
|
9
|
+
def initialize(config, method, url, code)
|
10
|
+
@config = config
|
11
|
+
@method = method
|
12
|
+
@url = url
|
13
|
+
@code = code
|
14
|
+
end
|
15
|
+
|
16
|
+
def increment
|
17
|
+
return unless configured?
|
18
|
+
|
19
|
+
case metrics_handler
|
20
|
+
when :inststatsd
|
21
|
+
InstStatsd::Statsd.increment count_metric_name, tags: tags
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def duration(start_time, end_time)
|
26
|
+
return unless configured?
|
27
|
+
|
28
|
+
duration_ms = ((end_time - start_time) * 1_000).round
|
29
|
+
|
30
|
+
case metrics_handler
|
31
|
+
when :inststatsd
|
32
|
+
InstStatsd::Statsd.timing duration_metric_name, duration_ms, tags: tags
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def configured?
|
39
|
+
metrics_handler_present? && metrics_namespace_present?
|
40
|
+
end
|
41
|
+
|
42
|
+
def count_metric_name
|
43
|
+
"#{metrics_namespace}.quiz_api_client.request.count"
|
44
|
+
end
|
45
|
+
|
46
|
+
def duration_metric_name
|
47
|
+
"#{metrics_namespace}.quiz_api_client.request.duration_ms"
|
48
|
+
end
|
49
|
+
|
50
|
+
def metrics_handler_present?
|
51
|
+
!metrics_handler.nil?
|
52
|
+
end
|
53
|
+
|
54
|
+
def metrics_namespace_present?
|
55
|
+
!metrics_namespace.nil?
|
56
|
+
end
|
57
|
+
|
58
|
+
def tags
|
59
|
+
{
|
60
|
+
method: method,
|
61
|
+
status: code,
|
62
|
+
url: url
|
63
|
+
}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -1,5 +1,11 @@
|
|
1
1
|
module QuizApiClient::Services
|
2
2
|
class ItemsService < BaseApiService
|
3
|
+
def list(params:, token: nil)
|
4
|
+
raise 'Quiz Id Required' unless params && params[:quiz_id]
|
5
|
+
|
6
|
+
list_from_quiz_api(params: params, token: token)
|
7
|
+
end
|
8
|
+
|
3
9
|
def create(params:, token: nil)
|
4
10
|
raise 'Quiz Id Required' unless params && params[:quiz_id]
|
5
11
|
|
@@ -8,6 +14,11 @@ module QuizApiClient::Services
|
|
8
14
|
|
9
15
|
private
|
10
16
|
|
17
|
+
def list_from_quiz_api(params:, token:)
|
18
|
+
quiz_id = params.delete(:quiz_id)
|
19
|
+
client(token: token).get("/api/quizzes/#{quiz_id}/items")
|
20
|
+
end
|
21
|
+
|
11
22
|
def post_to_quiz_api(params:, token:)
|
12
23
|
quiz_id = params.delete(:quiz_id)
|
13
24
|
client(token: token).post(
|
@@ -4,6 +4,10 @@ module QuizApiClient::Services
|
|
4
4
|
post_to_quiz_api(params: params, token: token)
|
5
5
|
end
|
6
6
|
|
7
|
+
def create_batch(body:, token: nil)
|
8
|
+
batch_post_to_quiz_api(body: body, token: token)
|
9
|
+
end
|
10
|
+
|
7
11
|
private
|
8
12
|
|
9
13
|
def post_to_quiz_api(params:, token:)
|
@@ -11,5 +15,12 @@ module QuizApiClient::Services
|
|
11
15
|
"/api/quizzes/#{params.fetch(:quiz_id)}/quiz_clone_jobs"
|
12
16
|
)
|
13
17
|
end
|
18
|
+
|
19
|
+
def batch_post_to_quiz_api(body:, token:)
|
20
|
+
client(token: token).post(
|
21
|
+
'/api/quiz_clone_jobs/create_batch',
|
22
|
+
body
|
23
|
+
)
|
24
|
+
end
|
14
25
|
end
|
15
26
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module QuizApiClient::Services
|
2
|
+
class QuizSyncJobService < BaseApiService
|
3
|
+
def show(params:, token: nil)
|
4
|
+
raise 'Quiz Sync Job Id Required' unless params && params[:id]
|
5
|
+
|
6
|
+
get_from_quiz_api(params: params, token: token)
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def get_from_quiz_api(params:, token:)
|
12
|
+
client(token: token).get(
|
13
|
+
"/api/quiz_sync_jobs/#{params.fetch(:id)}"
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module QuizApiClient::Services
|
2
|
+
class QuizSyncJobsService < BaseApiService
|
3
|
+
def create_batch(body:, token: nil)
|
4
|
+
batch_post_to_quiz_api(body: body, token: token)
|
5
|
+
end
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
def batch_post_to_quiz_api(body:, token:)
|
10
|
+
client(token: token).post(
|
11
|
+
'/api/quiz_sync_jobs/create_batch',
|
12
|
+
body
|
13
|
+
)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/quiz_api_client.rb
CHANGED
@@ -50,6 +50,14 @@ module QuizApiClient
|
|
50
50
|
@_quiz_clone_jobs_service ||= Services::QuizCloneJobsService.new(config)
|
51
51
|
end
|
52
52
|
|
53
|
+
def quiz_sync_job_service
|
54
|
+
@_quiz_sync_job_service ||= Services::QuizSyncJobService.new(config)
|
55
|
+
end
|
56
|
+
|
57
|
+
def quiz_sync_jobs_service
|
58
|
+
@_quiz_sync_jobs_service ||= Services::QuizSyncJobsService.new(config)
|
59
|
+
end
|
60
|
+
|
53
61
|
def qti_imports_service
|
54
62
|
@_qti_imports_service ||= Services::QtiImportsService.new(config)
|
55
63
|
end
|
@@ -101,6 +109,8 @@ require 'quiz_api_client/version'
|
|
101
109
|
require 'quiz_api_client/config'
|
102
110
|
require 'quiz_api_client/http_client'
|
103
111
|
require 'quiz_api_client/json_formatter'
|
112
|
+
require 'quiz_api_client/http_request/failure'
|
113
|
+
require 'quiz_api_client/http_request/metrics'
|
104
114
|
require 'quiz_api_client/services/jwt_service'
|
105
115
|
require 'quiz_api_client/services/base_api_service'
|
106
116
|
|
@@ -118,6 +128,8 @@ require 'quiz_api_client/services/quizzes_service'
|
|
118
128
|
require 'quiz_api_client/services/quiz_session_result_service'
|
119
129
|
require 'quiz_api_client/services/quiz_clone_job_service'
|
120
130
|
require 'quiz_api_client/services/quiz_clone_jobs_service'
|
131
|
+
require 'quiz_api_client/services/quiz_sync_job_service'
|
132
|
+
require 'quiz_api_client/services/quiz_sync_jobs_service'
|
121
133
|
require 'quiz_api_client/services/session_items_service'
|
122
134
|
require 'quiz_api_client/services/session_item_results_service'
|
123
135
|
require 'quiz_api_client/services/shared_banks'
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
describe QuizApiClient::Config do
|
2
|
+
describe 'initialize with block' do
|
3
|
+
it 'sets the config value' do
|
4
|
+
config = described_class.new do |c|
|
5
|
+
c.host = 'a host'
|
6
|
+
end
|
7
|
+
expect(config.host).to eq 'a host'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#protocol' do
|
12
|
+
it 'returns the default when nil' do
|
13
|
+
config = described_class.new
|
14
|
+
expect(config.protocol).to eq QuizApiClient::Config::DEFAULT_PROTOCOL
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#error_handler=' do
|
19
|
+
it 'raises an error with an invalid error handler' do
|
20
|
+
config = described_class.new
|
21
|
+
expect { config.error_handler = :invalid_error_handler }
|
22
|
+
.to raise_error(QuizApiClient::Config::InvalidErrorHandler)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#allowable_response_codes' do
|
27
|
+
it 'returns the default when nil' do
|
28
|
+
config = described_class.new
|
29
|
+
expect(config.allowable_response_codes).to eq QuizApiClient::Config::DEFAULT_ALLOWABLE_RESPONSE_CODES
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#setup_metrics' do
|
34
|
+
let(:valid_handler) { :inststatsd }
|
35
|
+
let(:invalid_handler) { :invalid_handler }
|
36
|
+
|
37
|
+
let(:valid_namespace) { :quiz_lti }
|
38
|
+
let(:invalid_namespace) { ' ' }
|
39
|
+
|
40
|
+
it 'raises an error with an invalid metrics handler' do
|
41
|
+
config = described_class.new
|
42
|
+
expect { config.setup_metrics(invalid_handler, valid_namespace) }
|
43
|
+
.to raise_error(QuizApiClient::Config::InvalidMetricsHandler)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'raises an error with an invalid namespace' do
|
47
|
+
config = described_class.new
|
48
|
+
expect { config.setup_metrics(valid_handler, invalid_namespace) }
|
49
|
+
.to raise_error(QuizApiClient::Config::InvalidMetricsNamespace)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'raises an error with an nil namespace' do
|
53
|
+
config = described_class.new
|
54
|
+
expect { config.setup_metrics(valid_handler, nil) }
|
55
|
+
.to raise_error(QuizApiClient::Config::InvalidMetricsNamespace)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'sets the handler and namespace successfully' do
|
59
|
+
config = described_class.new
|
60
|
+
config.setup_metrics(valid_handler, valid_namespace)
|
61
|
+
|
62
|
+
expect(config.metrics_handler).to eq valid_handler
|
63
|
+
expect(config.metrics_namespace).to eq valid_namespace.to_s
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
describe QuizApiClient::Services::InteractionTypesService, :pact do
|
2
|
+
include PactHelper
|
3
|
+
|
4
|
+
it_behaves_like 'a http get request to quiz_api collection endpoint' do
|
5
|
+
let(:provider_state) { 'a set of interaction types' }
|
6
|
+
let(:request_description) { 'a request to retrieve a list of interaction types' }
|
7
|
+
let(:quizzes_api_path) { '/api/interaction_types' }
|
8
|
+
let(:scope) { 'quiz.build' }
|
9
|
+
let(:params) { nil }
|
10
|
+
let(:response_body) do
|
11
|
+
Pact.each_like(
|
12
|
+
id: '1',
|
13
|
+
slug: 'choice',
|
14
|
+
name: 'Multiple Choice',
|
15
|
+
properties_schema: {},
|
16
|
+
scoring_algorithm_default: 'Equivalence',
|
17
|
+
user_response_type_options: ['Uuid']
|
18
|
+
)
|
19
|
+
end
|
20
|
+
let(:service_name) { :interaction_types_service }
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
describe QuizApiClient::Services::ItemAnalysesService, :pact do
|
2
|
+
include PactHelper
|
3
|
+
|
4
|
+
it_behaves_like 'a http get request to quiz_api collection endpoint', testrail_id: %w[3402546] do
|
5
|
+
let(:request_description) { 'a request to retrieve item analyses all quiz_id items' }
|
6
|
+
let(:quiz_id) { 1 }
|
7
|
+
let(:quizzes_api_path) { "/api/quizzes/#{quiz_id}/stats/item_analyses" }
|
8
|
+
let(:provider_state) { 'quiz with item analysis' }
|
9
|
+
let(:resource_id) { '1' }
|
10
|
+
let(:scope) { 'quiz.analysis' }
|
11
|
+
let(:params) { { quiz_id: '1' } }
|
12
|
+
let(:response_body) do
|
13
|
+
[
|
14
|
+
{
|
15
|
+
item_id: Pact.like('1'),
|
16
|
+
points_possible: Pact.like(1.0),
|
17
|
+
item_body: Pact.like('item body'),
|
18
|
+
interaction_type: 'choice',
|
19
|
+
item_analysis: {},
|
20
|
+
batch_timestamp: Pact.like('2017-06-15T22:14:51.215Z'),
|
21
|
+
outcome_alignment_set_guid: Pact.like('cbedd9b0-d1ab-43a9-a3b2-89c3134a722a')
|
22
|
+
},
|
23
|
+
{
|
24
|
+
item_id: Pact.like('1'),
|
25
|
+
points_possible: Pact.like(1.0),
|
26
|
+
item_body: Pact.like('item body'),
|
27
|
+
interaction_type: 'choice',
|
28
|
+
item_analysis: {},
|
29
|
+
batch_timestamp: Pact.like('2017-06-15T22:14:51.215Z'),
|
30
|
+
outcome_alignment_set_guid: Pact.like('cbedd9b0-d1ab-43a9-a3b2-89c3134a722a')
|
31
|
+
}
|
32
|
+
]
|
33
|
+
end
|
34
|
+
let(:service_name) { :item_analyses_service }
|
35
|
+
end
|
36
|
+
|
37
|
+
it_behaves_like 'a http get only request to quiz_api', testrail_id: %w[3402547] do
|
38
|
+
let(:request_description) { 'a request to retrieve item analyses for a quiz item' }
|
39
|
+
let(:quiz_id) { 1 }
|
40
|
+
let(:id) { 1 }
|
41
|
+
let(:quizzes_api_path) { "/api/quizzes/#{quiz_id}/stats/item_analyses/#{id}" }
|
42
|
+
let(:provider_state) { 'quiz with item analysis' }
|
43
|
+
let(:resource_id) { '1' }
|
44
|
+
let(:scope) { 'quiz.analysis' }
|
45
|
+
let(:params) { { quiz_id: '1', id: '1' } }
|
46
|
+
let(:response_body) do
|
47
|
+
{
|
48
|
+
item_id: Pact.like('1'),
|
49
|
+
points_possible: Pact.like(1.0),
|
50
|
+
item_body: Pact.like('item body'),
|
51
|
+
interaction_type: 'choice',
|
52
|
+
item_analysis: {},
|
53
|
+
batch_timestamp: Pact.like('2017-06-15T22:14:51.215Z'),
|
54
|
+
outcome_alignment_set_guid: Pact.like('cbedd9b0-d1ab-43a9-a3b2-89c3134a722a')
|
55
|
+
}
|
56
|
+
end
|
57
|
+
let(:service_name) { :item_analyses_service }
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
describe QuizApiClient::Services::ItemsService, :pact do
|
2
|
+
include PactHelper
|
3
|
+
|
4
|
+
it_behaves_like 'a http post request to quiz_api' do
|
5
|
+
let(:provider_state) { 'a quiz and a multiple choice interaction type' }
|
6
|
+
let(:request_description) { 'a request to create an item' }
|
7
|
+
let(:quizzes_api_path) { "/api/quizzes/#{quiz_id}/items" }
|
8
|
+
let(:resource_id) { '1' }
|
9
|
+
let(:scope) { 'quiz.build' }
|
10
|
+
let(:quiz_id) { 1 }
|
11
|
+
let(:params) do
|
12
|
+
{
|
13
|
+
quiz_id: quiz_id,
|
14
|
+
interaction_data: {
|
15
|
+
choices: [{
|
16
|
+
id: 'guid',
|
17
|
+
itemBody: '<p>Choice</p>',
|
18
|
+
position: 1
|
19
|
+
}]
|
20
|
+
},
|
21
|
+
interaction_type_id: 1, # we'll seed InteractionType::MultipleChoice
|
22
|
+
item_body: 'Some kind of stem',
|
23
|
+
properties: {},
|
24
|
+
scoring_algorithm: 'Equivalence',
|
25
|
+
scoring_data: {
|
26
|
+
value: 'another guid'
|
27
|
+
},
|
28
|
+
title: 'A perfectly cromulent title',
|
29
|
+
user_response_type: 'Uuid'
|
30
|
+
}
|
31
|
+
end
|
32
|
+
let(:item_params) { params.clone.tap { |p| p.delete(:quiz_id) } }
|
33
|
+
let(:body) { { quiz_id: quiz_id, item: item_params } }
|
34
|
+
let(:response_body) do
|
35
|
+
{
|
36
|
+
id: Pact.like('1'),
|
37
|
+
interaction_data: {
|
38
|
+
choices: Pact.each_like(
|
39
|
+
id: 'a guid',
|
40
|
+
item_body: 'choice description',
|
41
|
+
position: 1
|
42
|
+
)
|
43
|
+
},
|
44
|
+
item_body: Pact.like(''),
|
45
|
+
properties: Pact.like({}),
|
46
|
+
status: Pact.like(''),
|
47
|
+
title: Pact.like(''),
|
48
|
+
user_response_type: Pact.like(''),
|
49
|
+
stimulus_id: Pact.like(''),
|
50
|
+
interaction_type: Pact.like({}),
|
51
|
+
scoring_data: {
|
52
|
+
value: Pact.like('')
|
53
|
+
},
|
54
|
+
scoring_algorithm: Pact.like('')
|
55
|
+
}
|
56
|
+
end
|
57
|
+
let(:service_name) { :items_service }
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
describe QuizApiClient::Services::QtiImportsService, :pact do
|
2
|
+
include PactHelper
|
3
|
+
|
4
|
+
it_behaves_like 'a http post request to quiz_api', testrail_id: %w[3402548] do
|
5
|
+
let(:request_description) { 'a request to import a QTI' }
|
6
|
+
let(:provider_state) { 'a quiz' }
|
7
|
+
let(:quiz_id) { 1 }
|
8
|
+
let(:url) { 'http://fake.url' }
|
9
|
+
let(:quizzes_api_path) { "/api/quizzes/#{quiz_id}/qti_imports" }
|
10
|
+
let(:scope) { 'qti_import.create' }
|
11
|
+
let(:resource_id) { quiz_id }
|
12
|
+
let(:params) do
|
13
|
+
{
|
14
|
+
quiz_id: quiz_id,
|
15
|
+
url: url
|
16
|
+
}
|
17
|
+
end
|
18
|
+
let(:body) { { qti_import: params } }
|
19
|
+
let(:response_body) do
|
20
|
+
{
|
21
|
+
id: Pact.like('1'),
|
22
|
+
parent_id: quiz_id.to_s,
|
23
|
+
parent_type: Pact.like('Quiz'),
|
24
|
+
status: 'scheduled',
|
25
|
+
url: url,
|
26
|
+
message: Pact.like(''),
|
27
|
+
created_at: Pact.like(''),
|
28
|
+
updated_at: Pact.like(''),
|
29
|
+
progress: Pact.like(0.0)
|
30
|
+
}
|
31
|
+
end
|
32
|
+
let(:service_name) { :qti_imports_service }
|
33
|
+
end
|
34
|
+
end
|