onc_certification_g10_test_kit 2.1.0 → 2.2.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/lib/onc_certification_g10_test_kit/bulk_data_authorization.rb +7 -7
- data/lib/onc_certification_g10_test_kit/bulk_data_group_export.rb +6 -6
- data/lib/onc_certification_g10_test_kit/bulk_data_group_export_validation.rb +2 -2
- data/lib/onc_certification_g10_test_kit/bulk_export_validation_tester.rb +31 -5
- data/lib/onc_certification_g10_test_kit/configuration_checker.rb +16 -1
- data/lib/onc_certification_g10_test_kit/multi_patient_api.rb +2 -2
- data/lib/onc_certification_g10_test_kit/single_patient_api_group.rb +9 -5
- data/lib/onc_certification_g10_test_kit/smart_ehr_practitioner_app_group.rb +15 -1
- data/lib/onc_certification_g10_test_kit/smart_standalone_patient_app_group.rb +14 -1
- data/lib/onc_certification_g10_test_kit/version.rb +1 -1
- data/lib/onc_certification_g10_test_kit/well_known_capabilities_test.rb +1 -11
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b212142dbe987304c75b5323fd3ac1b2323f929a4e01b41f7722bff79db61fee
|
4
|
+
data.tar.gz: 3100cda0404c14b097e68adbdfbbc2e8e77590f53b6912c34c69560410e17a70
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 15417eeffcbbf4ba250c19b810ef4d8a6e5cd7a967e736321c92a5c39a1ba24aff1d9be8d362f41a368cb1d52a25be1bb756db0352c55bf9fff851d1ca688c1c
|
7
|
+
data.tar.gz: 171dcdaaf6bc3be2ec31a1169aaea28d255ae920732042989d48983e9db90aafb8859447fa18526aef86c36d945d29ded1581a2b921283acb7aee95e39f97443
|
@@ -6,8 +6,8 @@ module ONCCertificationG10TestKit
|
|
6
6
|
short_description 'Demonstrate SMART Backend Services Authorization for Bulk Data.'
|
7
7
|
description <<~DESCRIPTION
|
8
8
|
Bulk Data servers are required to authorize clients using the
|
9
|
-
[Backend Service Authorization](http://hl7.org/fhir/uv/bulkdata/STU1/authorization/index.html)
|
10
|
-
specification as defined in the [FHIR Bulk Data Access IG v1.0.
|
9
|
+
[Backend Service Authorization](http://hl7.org/fhir/uv/bulkdata/STU1.0.1/authorization/index.html)
|
10
|
+
specification as defined in the [FHIR Bulk Data Access IG v1.0.1](http://hl7.org/fhir/uv/bulkdata/STU1.0.1/).
|
11
11
|
|
12
12
|
In this set of tests, Inferno serves as a Bulk Data client that requests authorization
|
13
13
|
from the Bulk Data authorization server. It also performs a number of negative tests
|
@@ -89,7 +89,7 @@ module ONCCertificationG10TestKit
|
|
89
89
|
error response as described in [Section 5.2](https://tools.ietf.org/html/rfc6749#section-5.2).
|
90
90
|
```
|
91
91
|
DESCRIPTION
|
92
|
-
# link 'http://hl7.org/fhir/uv/bulkdata/STU1/authorization/index.html#protocol-details'
|
92
|
+
# link 'http://hl7.org/fhir/uv/bulkdata/STU1.0.1/authorization/index.html#protocol-details'
|
93
93
|
|
94
94
|
run do
|
95
95
|
post_request_content = AuthorizationRequestBuilder.build(encryption_method: bulk_encryption_method,
|
@@ -120,7 +120,7 @@ module ONCCertificationG10TestKit
|
|
120
120
|
error response as described in [Section 5.2](https://tools.ietf.org/html/rfc6749#section-5.2).
|
121
121
|
```
|
122
122
|
DESCRIPTION
|
123
|
-
# link 'http://hl7.org/fhir/uv/bulkdata/STU1/authorization/index.html#protocol-details'
|
123
|
+
# link 'http://hl7.org/fhir/uv/bulkdata/STU1.0.1/authorization/index.html#protocol-details'
|
124
124
|
|
125
125
|
run do
|
126
126
|
post_request_content = AuthorizationRequestBuilder.build(encryption_method: bulk_encryption_method,
|
@@ -160,7 +160,7 @@ module ONCCertificationG10TestKit
|
|
160
160
|
error response as described in [Section 5.2](https://tools.ietf.org/html/rfc6749#section-5.2).
|
161
161
|
```
|
162
162
|
DESCRIPTION
|
163
|
-
# link 'http://hl7.org/fhir/uv/bulkdata/STU1/authorization/index.html#protocol-details'
|
163
|
+
# link 'http://hl7.org/fhir/uv/bulkdata/STU1.0.1/authorization/index.html#protocol-details'
|
164
164
|
|
165
165
|
run do
|
166
166
|
post_request_content = AuthorizationRequestBuilder.build(encryption_method: bulk_encryption_method,
|
@@ -180,7 +180,7 @@ module ONCCertificationG10TestKit
|
|
180
180
|
description <<~DESCRIPTION
|
181
181
|
If the access token request is valid and authorized, the authorization server SHALL issue an access token in response.
|
182
182
|
DESCRIPTION
|
183
|
-
# link 'http://hl7.org/fhir/uv/bulkdata/STU1/authorization/index.html#issuing-access-tokens'
|
183
|
+
# link 'http://hl7.org/fhir/uv/bulkdata/STU1.0.1/authorization/index.html#issuing-access-tokens'
|
184
184
|
|
185
185
|
output :authentication_response
|
186
186
|
|
@@ -211,7 +211,7 @@ module ONCCertificationG10TestKit
|
|
211
211
|
| expires_in | required | The lifetime in seconds of the access token. The recommended value is 300, for a five-minute token lifetime. |
|
212
212
|
| scope | required | Scope of access authorized. Note that this can be different from the scopes requested by the app. |
|
213
213
|
DESCRIPTION
|
214
|
-
# link 'http://hl7.org/fhir/uv/bulkdata/STU1/authorization/index.html#issuing-access-tokens'
|
214
|
+
# link 'http://hl7.org/fhir/uv/bulkdata/STU1.0.1/authorization/index.html#issuing-access-tokens'
|
215
215
|
|
216
216
|
input :authentication_response
|
217
217
|
output :bearer_token
|
@@ -130,11 +130,11 @@ module ONCCertificationG10TestKit
|
|
130
130
|
description <<~DESCRIPTION
|
131
131
|
The FHIR server SHALL limit the data returned to only those FHIR resources for which the client is authorized.
|
132
132
|
|
133
|
-
[FHIR R4 Security](
|
133
|
+
[FHIR R4 Security](https://www.hl7.org/fhir/security.html#AccessDenied) and
|
134
134
|
[The OAuth 2.0 Authorization Framework: Bearer Token Usage](https://tools.ietf.org/html/rfc6750#section-3.1)
|
135
135
|
recommend using HTTP status code 401 for invalid token but also allow the actual result be controlled by policy and context.
|
136
136
|
DESCRIPTION
|
137
|
-
# link 'http://hl7.org/fhir/uv/bulkdata/STU1/export/index.html#bulk-data-kick-off-request'
|
137
|
+
# link 'http://hl7.org/fhir/uv/bulkdata/STU1.0.1/export/index.html#bulk-data-kick-off-request'
|
138
138
|
|
139
139
|
include ExportKickOffPerformer
|
140
140
|
|
@@ -154,7 +154,7 @@ module ONCCertificationG10TestKit
|
|
154
154
|
* HTTP Status Code of 202 Accepted
|
155
155
|
* Content-Location header with the absolute URL of an endpoint for subsequent status requests (polling location)
|
156
156
|
DESCRIPTION
|
157
|
-
# link 'http://hl7.org/fhir/uv/bulkdata/STU1/export/index.html#response---success'
|
157
|
+
# link 'http://hl7.org/fhir/uv/bulkdata/STU1.0.1/export/index.html#response---success'
|
158
158
|
|
159
159
|
include ExportKickOffPerformer
|
160
160
|
|
@@ -183,7 +183,7 @@ module ONCCertificationG10TestKit
|
|
183
183
|
|
184
184
|
* transactionTime, request, requiresAccessToken, output, and error
|
185
185
|
DESCRIPTION
|
186
|
-
# link 'http://hl7.org/fhir/uv/bulkdata/STU1/export/index.html#bulk-data-status-request'
|
186
|
+
# link 'http://hl7.org/fhir/uv/bulkdata/STU1.0.1/export/index.html#bulk-data-status-request'
|
187
187
|
|
188
188
|
input :polling_url
|
189
189
|
|
@@ -248,7 +248,7 @@ module ONCCertificationG10TestKit
|
|
248
248
|
|
249
249
|
* url - the path to the file. The format of the file SHOULD reflect that requested in the _outputFormat parameter of the initial kick-off request.
|
250
250
|
DESCRIPTION
|
251
|
-
# link 'http://hl7.org/fhir/uv/bulkdata/STU1/export/index.html#response---complete-status'
|
251
|
+
# link 'http://hl7.org/fhir/uv/bulkdata/STU1.0.1/export/index.html#response---complete-status'
|
252
252
|
|
253
253
|
input :status_response
|
254
254
|
|
@@ -277,7 +277,7 @@ module ONCCertificationG10TestKit
|
|
277
277
|
After a bulk data request has been started, a client MAY send a delete request to the URL provided in the Content-Location header to cancel the request.
|
278
278
|
Bulk Data Server MUST support client's delete request and return HTTP Status Code of "202 Accepted"
|
279
279
|
DESCRIPTION
|
280
|
-
# link 'http://hl7.org/fhir/uv/bulkdata/STU1/export/index.html#bulk-data-delete-request'
|
280
|
+
# link 'http://hl7.org/fhir/uv/bulkdata/STU1.0.1/export/index.html#bulk-data-delete-request'
|
281
281
|
|
282
282
|
include ExportKickOffPerformer
|
283
283
|
|
@@ -54,12 +54,12 @@ module ONCCertificationG10TestKit
|
|
54
54
|
If the requiresAccessToken field in the Complete Status body is set to true, the request SHALL include a valid#{' '}
|
55
55
|
access token.
|
56
56
|
|
57
|
-
[FHIR R4 Security](
|
57
|
+
[FHIR R4 Security](https://www.hl7.org/fhir/security.html#AccessDenied) and
|
58
58
|
[The OAuth 2.0 Authorization Framework: Bearer Token Usage](https://tools.ietf.org/html/rfc6750#section-3.1)
|
59
59
|
recommend using HTTP status code 401 for invalid token but also allow the actual result be controlled by policy#{' '}
|
60
60
|
and context.
|
61
61
|
DESCRIPTION
|
62
|
-
# link 'http://hl7.org/fhir/uv/bulkdata/STU1/export/index.html#file-request'
|
62
|
+
# link 'http://hl7.org/fhir/uv/bulkdata/STU1.0.1/export/index.html#file-request'
|
63
63
|
|
64
64
|
input :bulk_download_url
|
65
65
|
|
@@ -55,6 +55,10 @@ module ONCCertificationG10TestKit
|
|
55
55
|
@resources_from_all_files ||= {}
|
56
56
|
end
|
57
57
|
|
58
|
+
def first_error
|
59
|
+
@first_error ||= {}
|
60
|
+
end
|
61
|
+
|
58
62
|
def patient_ids_seen
|
59
63
|
scratch[:patient_ids_seen] ||= []
|
60
64
|
end
|
@@ -166,7 +170,13 @@ module ONCCertificationG10TestKit
|
|
166
170
|
scratch[:patient_ids_seen] = patient_ids_seen | [resource.id] if resource_type == 'Patient'
|
167
171
|
|
168
172
|
unless resource_is_valid?(resource: resource, profile_url: profile_url)
|
169
|
-
|
173
|
+
if first_error.key?(:line_number)
|
174
|
+
@invalid_resource_count += 1
|
175
|
+
else
|
176
|
+
@invalid_resource_count = 1
|
177
|
+
first_error[:line_number] = line_count
|
178
|
+
first_error[:messages] = messages.dup
|
179
|
+
end
|
170
180
|
end
|
171
181
|
}
|
172
182
|
|
@@ -184,6 +194,19 @@ module ONCCertificationG10TestKit
|
|
184
194
|
line_count
|
185
195
|
end
|
186
196
|
|
197
|
+
def process_validation_errors(resource_count)
|
198
|
+
return if @invalid_resource_count.nil? || @invalid_resource_count.zero?
|
199
|
+
|
200
|
+
first_error_message = "The line number for the first failed resource is #{first_error[:line_number]}."
|
201
|
+
|
202
|
+
messages.clear
|
203
|
+
messages.concat(first_error[:messages])
|
204
|
+
|
205
|
+
assert false,
|
206
|
+
"#{@invalid_resource_count} / #{resource_count} #{resource_type} resources failed profile validation. " \
|
207
|
+
"#{first_error_message}"
|
208
|
+
end
|
209
|
+
|
187
210
|
def perform_bulk_export_validation
|
188
211
|
skip_if status_output.blank?, 'Could not verify this functionality when Bulk Status Output is not provided'
|
189
212
|
skip_if (requires_access_token == 'true' && bearer_token.blank?),
|
@@ -192,19 +215,22 @@ module ONCCertificationG10TestKit
|
|
192
215
|
file_list = JSON.parse(status_output).select { |file| file['type'] == resource_type }
|
193
216
|
if file_list.empty?
|
194
217
|
message = "No #{resource_type} resource file item returned by server."
|
195
|
-
omit_if (OMIT_KLASS.include? resource_type), message
|
218
|
+
omit_if (OMIT_KLASS.include? resource_type), "#{message} #{resource_type} resources are optional."
|
196
219
|
skip message
|
197
220
|
end
|
198
221
|
|
199
222
|
@resources_from_all_files = {}
|
200
|
-
|
223
|
+
resource_count = 0
|
224
|
+
|
201
225
|
file_list.each do |file|
|
202
|
-
|
226
|
+
resource_count += check_file_request(file['url'])
|
203
227
|
end
|
204
228
|
|
229
|
+
process_validation_errors(resource_count)
|
230
|
+
|
205
231
|
validate_conformance(resources_from_all_files)
|
206
232
|
|
207
|
-
pass "Successfully validated #{
|
233
|
+
pass "Successfully validated #{resource_count} #{resource_type} resource(s)."
|
208
234
|
end
|
209
235
|
end
|
210
236
|
end
|
@@ -5,7 +5,7 @@ module ONCCertificationG10TestKit
|
|
5
5
|
EXPECTED_VALIDATOR_VERSION = '2.1.0'.freeze
|
6
6
|
|
7
7
|
def configuration_messages
|
8
|
-
validator_version_message + terminology_messages
|
8
|
+
validator_version_message + terminology_messages + version_message
|
9
9
|
end
|
10
10
|
|
11
11
|
def terminology_checker
|
@@ -101,5 +101,20 @@ module ONCCertificationG10TestKit
|
|
101
101
|
|
102
102
|
messages
|
103
103
|
end
|
104
|
+
|
105
|
+
def version_message
|
106
|
+
return [] if VERSION.match?(/\A\d+\.\d+\.\d+\z/)
|
107
|
+
|
108
|
+
[{
|
109
|
+
type: 'error',
|
110
|
+
message: <<~MESSAGE
|
111
|
+
This is a development version (`#{VERSION}`) of the ONC Certification
|
112
|
+
(g)(10) Standardized API Test Kit and is not suitable for
|
113
|
+
certification. Please [download an official
|
114
|
+
release](https://github.com/onc-healthit/onc-certification-g10-test-kit/releases)
|
115
|
+
if you did not intend to use the development version.
|
116
|
+
MESSAGE
|
117
|
+
}]
|
118
|
+
end
|
104
119
|
end
|
105
120
|
end
|
@@ -21,8 +21,8 @@ module ONCCertificationG10TestKit
|
|
21
21
|
description %(
|
22
22
|
Demonstrate the ability to export clinical data for multiple patients in
|
23
23
|
a group using [FHIR Bulk Data Access
|
24
|
-
IG](http://hl7.org/fhir/uv/bulkdata/STU1/). This test uses [Backend Services
|
25
|
-
Authorization](http://hl7.org/fhir/uv/bulkdata/STU1/authorization/index.html)
|
24
|
+
IG](http://hl7.org/fhir/uv/bulkdata/STU1.0.1/). This test uses [Backend Services
|
25
|
+
Authorization](http://hl7.org/fhir/uv/bulkdata/STU1.0.1/authorization/index.html)
|
26
26
|
to obtain an access token from the server. After authorization, a group
|
27
27
|
level bulk data export request is initialized. Finally, this test reads
|
28
28
|
exported NDJSON files from the server and validates the resources in
|
@@ -61,11 +61,15 @@ module ONCCertificationG10TestKit
|
|
61
61
|
run do
|
62
62
|
smart_app_launch_patient_id = patient_id.presence
|
63
63
|
additional_patient_ids_list =
|
64
|
-
additional_patient_ids
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
64
|
+
if additional_patient_ids.present?
|
65
|
+
additional_patient_ids
|
66
|
+
.split(',')
|
67
|
+
.map(&:strip)
|
68
|
+
.map(&:presence)
|
69
|
+
.compact
|
70
|
+
else
|
71
|
+
[]
|
72
|
+
end
|
69
73
|
|
70
74
|
all_patient_ids = ([smart_app_launch_patient_id] + additional_patient_ids_list).compact.uniq
|
71
75
|
|
@@ -47,7 +47,21 @@ module ONCCertificationG10TestKit
|
|
47
47
|
input_order :url, :ehr_client_id, :ehr_client_secret
|
48
48
|
|
49
49
|
group from: :smart_discovery do
|
50
|
-
test from: 'g10_smart_well_known_capabilities'
|
50
|
+
test from: 'g10_smart_well_known_capabilities',
|
51
|
+
config: {
|
52
|
+
options: {
|
53
|
+
required_capabilities: [
|
54
|
+
'launch-ehr',
|
55
|
+
'client-confidential-symmetric',
|
56
|
+
'sso-openid-connect',
|
57
|
+
'context-banner',
|
58
|
+
'context-style',
|
59
|
+
'context-ehr-patient',
|
60
|
+
'permission-offline',
|
61
|
+
'permission-user'
|
62
|
+
]
|
63
|
+
}
|
64
|
+
}
|
51
65
|
end
|
52
66
|
|
53
67
|
group from: :smart_ehr_launch do
|
@@ -49,7 +49,20 @@ module ONCCertificationG10TestKit
|
|
49
49
|
input_order :url, :standalone_client_id, :standalone_client_secret
|
50
50
|
|
51
51
|
group from: :smart_discovery do
|
52
|
-
test from: 'g10_smart_well_known_capabilities'
|
52
|
+
test from: 'g10_smart_well_known_capabilities',
|
53
|
+
config: {
|
54
|
+
options: {
|
55
|
+
required_capabilities: [
|
56
|
+
'launch-standalone',
|
57
|
+
'client-public',
|
58
|
+
'client-confidential-symmetric',
|
59
|
+
'sso-openid-connect',
|
60
|
+
'context-standalone-patient',
|
61
|
+
'permission-offline',
|
62
|
+
'permission-patient'
|
63
|
+
]
|
64
|
+
}
|
65
|
+
}
|
53
66
|
end
|
54
67
|
|
55
68
|
group from: :smart_standalone_launch do
|
@@ -19,17 +19,7 @@ module ONCCertificationG10TestKit
|
|
19
19
|
assert capabilities.is_a?(Array),
|
20
20
|
"Expected the well-known capabilities to be an Array, but found #{capabilities.class.name}"
|
21
21
|
|
22
|
-
|
23
|
-
'launch-standalone',
|
24
|
-
'client-public',
|
25
|
-
'client-confidential-symmetric',
|
26
|
-
'sso-openid-connect',
|
27
|
-
'context-standalone-patient',
|
28
|
-
'permission-offline',
|
29
|
-
'permission-patient'
|
30
|
-
]
|
31
|
-
|
32
|
-
missing_capabilities = required_smart_capabilities - capabilities
|
22
|
+
missing_capabilities = (config.options[:required_capabilities] || []) - capabilities
|
33
23
|
assert missing_capabilities.empty?,
|
34
24
|
"The following capabilities required for this scenario are missing: #{missing_capabilities.join(', ')}"
|
35
25
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: onc_certification_g10_test_kit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen MacVicar
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-05-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bloomer
|
@@ -114,14 +114,14 @@ dependencies:
|
|
114
114
|
requirements:
|
115
115
|
- - '='
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: 0.1.
|
117
|
+
version: 0.1.3
|
118
118
|
type: :runtime
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - '='
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: 0.1.
|
124
|
+
version: 0.1.3
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: tls_test_kit
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -142,14 +142,14 @@ dependencies:
|
|
142
142
|
requirements:
|
143
143
|
- - '='
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version: 0.2.
|
145
|
+
version: 0.2.2
|
146
146
|
type: :runtime
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
150
|
- - '='
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version: 0.2.
|
152
|
+
version: 0.2.2
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
154
|
name: database_cleaner-sequel
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|