onc_certification_g10_test_kit 2.3.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/inferno/terminology/expected_manifest.yml +242 -29
- data/lib/inferno/terminology/fhir_package_manager.rb +27 -0
- data/lib/inferno/terminology/loader.rb +22 -1
- data/lib/inferno/terminology/tasks/create_value_set_validators.rb +1 -1
- data/lib/inferno/terminology/tasks/download_fhir_terminology.rb +5 -0
- data/lib/inferno/terminology/value_set.rb +51 -5
- data/lib/onc_certification_g10_test_kit/base_token_refresh_group.rb +5 -4
- data/lib/onc_certification_g10_test_kit/bulk_data_group_export_stu1.rb +5 -0
- data/lib/onc_certification_g10_test_kit/bulk_data_group_export_stu2.rb +2 -0
- data/lib/onc_certification_g10_test_kit/bulk_data_group_export_validation.rb +206 -28
- data/lib/onc_certification_g10_test_kit/bulk_export_validation_tester.rb +25 -40
- data/lib/onc_certification_g10_test_kit/encounter_context_test.rb +30 -0
- data/lib/onc_certification_g10_test_kit/feature.rb +5 -8
- data/lib/onc_certification_g10_test_kit/limited_scope_grant_test.rb +18 -5
- data/lib/onc_certification_g10_test_kit/profile_selector.rb +175 -0
- data/lib/onc_certification_g10_test_kit/restricted_resource_type_access_group.rb +54 -4
- data/lib/onc_certification_g10_test_kit/single_patient_us_core_5_api_group.rb +93 -0
- data/lib/onc_certification_g10_test_kit/smart_app_launch_invalid_aud_group.rb +50 -5
- data/lib/onc_certification_g10_test_kit/smart_ehr_patient_launch_group.rb +94 -0
- data/lib/onc_certification_g10_test_kit/smart_ehr_patient_launch_group_stu2.rb +94 -0
- data/lib/onc_certification_g10_test_kit/smart_ehr_practitioner_app_group.rb +197 -13
- data/lib/onc_certification_g10_test_kit/smart_invalid_pkce_group.rb +310 -0
- data/lib/onc_certification_g10_test_kit/smart_invalid_token_group_stu2.rb +211 -0
- data/lib/onc_certification_g10_test_kit/smart_limited_app_group.rb +135 -9
- data/lib/onc_certification_g10_test_kit/smart_public_standalone_launch_group.rb +16 -4
- data/lib/onc_certification_g10_test_kit/smart_public_standalone_launch_group_stu2.rb +130 -0
- data/lib/onc_certification_g10_test_kit/smart_scopes_test.rb +134 -67
- data/lib/onc_certification_g10_test_kit/smart_standalone_patient_app_group.rb +166 -11
- data/lib/onc_certification_g10_test_kit/unrestricted_resource_type_access_group.rb +119 -135
- data/lib/onc_certification_g10_test_kit/version.rb +1 -1
- data/lib/onc_certification_g10_test_kit/visual_inspection_and_attestations_group.rb +19 -0
- data/lib/onc_certification_g10_test_kit/well_known_capabilities_test.rb +7 -1
- data/lib/onc_certification_g10_test_kit.rb +115 -74
- metadata +19 -11
- data/lib/onc_certification_g10_test_kit/profile_guesser.rb +0 -72
@@ -0,0 +1,175 @@
|
|
1
|
+
module ONCCertificationG10TestKit
|
2
|
+
module ProfileSelector
|
3
|
+
def extract_profile(profile)
|
4
|
+
case profile
|
5
|
+
when 'Medication'
|
6
|
+
return versioned_us_core_module.const_get('USCoreTestSuite').metadata.find do |meta|
|
7
|
+
meta.resource == profile
|
8
|
+
end.profile_url
|
9
|
+
when 'Location'
|
10
|
+
return 'http://hl7.org/fhir/StructureDefinition/Location'
|
11
|
+
end
|
12
|
+
versioned_us_core_module.const_get("#{profile}Group").metadata.profile_url
|
13
|
+
end
|
14
|
+
|
15
|
+
def observation_contains_code(observation_resource, code)
|
16
|
+
observation_resource&.code&.coding&.any? { |coding| coding&.code == code }
|
17
|
+
end
|
18
|
+
|
19
|
+
def resource_contains_category(resource, category_code, category_system = nil) # rubocop:disable Metrics/CyclomaticComplexity
|
20
|
+
resource&.category&.any? do |category|
|
21
|
+
category.coding&.any? do |coding|
|
22
|
+
coding.code == category_code &&
|
23
|
+
(category_system.blank? || coding.system.blank? || category_system == coding.system)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def select_profile(resource) # rubocop:disable Metrics/CyclomaticComplexity
|
29
|
+
case resource.resourceType
|
30
|
+
when 'Condition'
|
31
|
+
case suite_options[:us_core_version]
|
32
|
+
when 'us_core_5'
|
33
|
+
if resource_contains_category(resource, 'encounter-diagnosis', 'http://terminology.hl7.org/CodeSystem/condition-category')
|
34
|
+
extract_profile('ConditionEncounterDiagnosis')
|
35
|
+
elsif resource_contains_category(resource, 'problem-list-item',
|
36
|
+
'http://terminology.hl7.org/CodeSystem/condition-category') ||
|
37
|
+
resource_contains_category(resource, 'health-concern', 'http://terminology.hl7.org/CodeSystem/condition-category')
|
38
|
+
extract_profile('ConditionProblemsHealthConcerns')
|
39
|
+
end
|
40
|
+
else
|
41
|
+
extract_profile(resource.resourceType)
|
42
|
+
end
|
43
|
+
when 'DiagnosticReport'
|
44
|
+
return extract_profile('DiagnosticReportLab') if resource_contains_category(resource, 'LAB', 'http://terminology.hl7.org/CodeSystem/v2-0074')
|
45
|
+
|
46
|
+
extract_profile('DiagnosticReportNote')
|
47
|
+
when 'Observation'
|
48
|
+
return extract_profile('Smokingstatus') if observation_contains_code(resource, '72166-2')
|
49
|
+
|
50
|
+
return extract_profile('ObservationLab') if resource_contains_category(resource, 'laboratory', 'http://terminology.hl7.org/CodeSystem/observation-category')
|
51
|
+
|
52
|
+
return extract_profile('PediatricBmiForAge') if observation_contains_code(resource, '59576-9')
|
53
|
+
|
54
|
+
return extract_profile('PediatricWeightForHeight') if observation_contains_code(resource, '77606-2')
|
55
|
+
|
56
|
+
return extract_profile('PulseOximetry') if observation_contains_code(resource, '59408-5')
|
57
|
+
|
58
|
+
if observation_contains_code(resource, '8289-1')
|
59
|
+
case suite_options[:us_core_version]
|
60
|
+
when 'us_core_3'
|
61
|
+
return extract_profile('HeadCircumference')
|
62
|
+
else
|
63
|
+
return extract_profile('HeadCircumferencePercentile')
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
return extract_profile('HeadCircumference') if observation_contains_code(resource, '9843-4')
|
68
|
+
|
69
|
+
# FHIR Vital Signs profiles: https://www.hl7.org/fhir/observation-vitalsigns.html
|
70
|
+
# Vital Signs Panel, Oxygen Saturation are not required by USCDI
|
71
|
+
# Body Mass Index is replaced by :pediatric_bmi_age Profile
|
72
|
+
# Systolic Blood Pressure, Diastolic Blood Pressure are covered by :blood_pressure Profile
|
73
|
+
# Head Circumference is replaced by US Core Head Occipital-frontal Circumference Percentile Profile
|
74
|
+
if observation_contains_code(resource, '39156-5') && suite_options[:us_core_version] != 'us_core_3'
|
75
|
+
return extract_profile('Bmi')
|
76
|
+
end
|
77
|
+
|
78
|
+
if observation_contains_code(resource, '85354-9')
|
79
|
+
case suite_options[:us_core_version]
|
80
|
+
when 'us_core_3'
|
81
|
+
return extract_profile('Bp')
|
82
|
+
else
|
83
|
+
return extract_profile('BloodPressure')
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
if observation_contains_code(resource, '8302-2')
|
88
|
+
case suite_options[:us_core_version]
|
89
|
+
when 'us_core_3'
|
90
|
+
return extract_profile('Bodyheight')
|
91
|
+
else
|
92
|
+
return extract_profile('BodyHeight')
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
if observation_contains_code(resource, '8310-5')
|
97
|
+
case suite_options[:us_core_version]
|
98
|
+
when 'us_core_3'
|
99
|
+
return extract_profile('Bodytemp')
|
100
|
+
else
|
101
|
+
return extract_profile('BodyTemperature')
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
if observation_contains_code(resource, '29463-7')
|
106
|
+
case suite_options[:us_core_version]
|
107
|
+
when 'us_core_3'
|
108
|
+
return extract_profile('Bodyweight')
|
109
|
+
else
|
110
|
+
return extract_profile('BodyWeight')
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
if observation_contains_code(resource, '8867-4')
|
115
|
+
case suite_options[:us_core_version]
|
116
|
+
when 'us_core_3'
|
117
|
+
return extract_profile('Heartrate')
|
118
|
+
else
|
119
|
+
return extract_profile('HeartRate')
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
if observation_contains_code(resource, '9279-1')
|
124
|
+
case suite_options[:us_core_version]
|
125
|
+
when 'us_core_3'
|
126
|
+
return extract_profile('Resprate')
|
127
|
+
else
|
128
|
+
return extract_profile('RespiratoryRate')
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
if suite_options[:us_core_version] == 'us_core_5' &&
|
133
|
+
resource_contains_category(
|
134
|
+
resource, 'clinical-test', 'http://terminology.hl7.org/CodeSystem/observation-category'
|
135
|
+
)
|
136
|
+
return extract_profile('ObservationClinicalTest')
|
137
|
+
end
|
138
|
+
|
139
|
+
if suite_options[:us_core_version] == 'us_core_5' && observation_contains_code(resource, '76690-7')
|
140
|
+
return extract_profile('ObservationSexualOrientation')
|
141
|
+
end
|
142
|
+
|
143
|
+
if suite_options[:us_core_version] == 'us_core_5' &&
|
144
|
+
resource_contains_category(resource, 'social-history',
|
145
|
+
'http://terminology.hl7.org/CodeSystem/observation-category')
|
146
|
+
return extract_profile('ObservationSocialHistory')
|
147
|
+
end
|
148
|
+
|
149
|
+
# We will simply match all Observations of category "survey" to SDOH,
|
150
|
+
# and do not look at the category "sdoh". US Core spec team says that
|
151
|
+
# support for the "sdoh" category is limited, and the validation rules
|
152
|
+
# allow for very generic surveys to validate against this profile.
|
153
|
+
# And will not validate against the ObservationSurvey profile itself.
|
154
|
+
# This may not be exactly precise but it works out the same
|
155
|
+
|
156
|
+
# if we wanted to be more specific here, we would add:
|
157
|
+
# `resource_contains_category(resource, 'sdoh',
|
158
|
+
# 'http://terminology.hl7.org/CodeSystem/observation-category') &&`
|
159
|
+
# along with a specific extract_profile('ObservationSurvey') to catch non-sdoh.
|
160
|
+
if suite_options[:us_core_version] == 'us_core_5' &&
|
161
|
+
resource_contains_category(resource, 'survey',
|
162
|
+
'http://terminology.hl7.org/CodeSystem/observation-category')
|
163
|
+
|
164
|
+
return extract_profile('ObservationSdohAssessment')
|
165
|
+
end
|
166
|
+
|
167
|
+
nil
|
168
|
+
else
|
169
|
+
extract_profile(resource.resourceType)
|
170
|
+
end
|
171
|
+
rescue StandardError
|
172
|
+
skip "Could not determine profile of \"#{resource.resourceType}\" resource."
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
@@ -27,6 +27,8 @@ module ONCCertificationG10TestKit
|
|
27
27
|
* Observation
|
28
28
|
* Procedure
|
29
29
|
|
30
|
+
If testing against USCDI v2, ServiceRequest is also checked.
|
31
|
+
|
30
32
|
For each of the resources that can be mapped to USCDI data class or
|
31
33
|
elements, this set of tests performs a minimum number of requests to
|
32
34
|
determine if access to the resource type is appropriately allowed or
|
@@ -38,10 +40,18 @@ module ONCCertificationG10TestKit
|
|
38
40
|
required status search parameter.
|
39
41
|
|
40
42
|
This set of tests does not attempt to access resources that do not
|
41
|
-
directly map to USCDI
|
42
|
-
|
43
|
-
|
44
|
-
|
43
|
+
directly map to USCDI. For USCDI v1 this includes:
|
44
|
+
|
45
|
+
* Encounter
|
46
|
+
* Location
|
47
|
+
* Organization
|
48
|
+
* Practitioner
|
49
|
+
|
50
|
+
For USCDI v2 this includes:
|
51
|
+
|
52
|
+
* Location
|
53
|
+
* Organization
|
54
|
+
* Practitioner
|
45
55
|
|
46
56
|
If the tester chooses to not grant access to a resource, the queries
|
47
57
|
associated with that resource must result in either a 401 (Unauthorized)
|
@@ -299,5 +309,45 @@ module ONCCertificationG10TestKit
|
|
299
309
|
USCoreTestKit::USCoreV311::ProcedureGroup
|
300
310
|
end
|
301
311
|
end
|
312
|
+
|
313
|
+
test from: :g10_restricted_access_test do
|
314
|
+
title 'Access to Encounter resources are restricted properly based on patient-selected scope'
|
315
|
+
description %(
|
316
|
+
This test ensures that access to the Encounter is granted or
|
317
|
+
denied based on the selection by the tester prior to the execution of
|
318
|
+
the test. If the tester indicated that access will be granted to this
|
319
|
+
resource, this test verifies that a search by patient in this resource
|
320
|
+
does not result in an access denied result. If the tester indicated that
|
321
|
+
access will be denied for this resource, this verifies that search by
|
322
|
+
patient in the resource results in an access denied result.
|
323
|
+
)
|
324
|
+
id :g10_encounter_restricted_access
|
325
|
+
|
326
|
+
required_suite_options us_core_version: 'us_core_5'
|
327
|
+
|
328
|
+
def resource_group
|
329
|
+
USCoreTestKit::USCoreV501::EncounterGroup
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
test from: :g10_restricted_access_test do
|
334
|
+
title 'Access to ServiceRequest resources are restricted properly based on patient-selected scope'
|
335
|
+
description %(
|
336
|
+
This test ensures that access to the ServiceRequest is granted or
|
337
|
+
denied based on the selection by the tester prior to the execution of
|
338
|
+
the test. If the tester indicated that access will be granted to this
|
339
|
+
resource, this test verifies that a search by patient in this resource
|
340
|
+
does not result in an access denied result. If the tester indicated that
|
341
|
+
access will be denied for this resource, this verifies that search by
|
342
|
+
patient in the resource results in an access denied result.
|
343
|
+
)
|
344
|
+
id :g10_service_request_restricted_access
|
345
|
+
|
346
|
+
required_suite_options us_core_version: 'us_core_5'
|
347
|
+
|
348
|
+
def resource_group
|
349
|
+
USCoreTestKit::USCoreV501::ServiceRequestGroup
|
350
|
+
end
|
351
|
+
end
|
302
352
|
end
|
303
353
|
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module ONCCertificationG10TestKit
|
2
|
+
class SinglePatientUSCore5APIGroup < Inferno::TestGroup
|
3
|
+
id :g10_single_patient_us_core_5_api
|
4
|
+
title 'Single Patient API (US Core 5.0.1)'
|
5
|
+
description %(
|
6
|
+
For each of the relevant USCDI data elements provided in the
|
7
|
+
CapabilityStatement, this test executes the [required supported
|
8
|
+
searches](http://hl7.org/fhir/us/core/STU4/CapabilityStatement-us-core-server.html)
|
9
|
+
as defined by the US Core Implementation Guide v4.0.0.
|
10
|
+
|
11
|
+
The test begins by searching by one or more patients, with the expectation
|
12
|
+
that the Bearer token provided to the test grants access to all USCDI
|
13
|
+
resources. It uses results returned from that query to generate other
|
14
|
+
queries and checks that the results are consistent with the provided
|
15
|
+
search parameters. It then performs a read on each Resource returned and
|
16
|
+
validates the response against the relevant
|
17
|
+
[profile](http://hl7.org/fhir/us/core/STU4/profiles-and-extensions.html)
|
18
|
+
as currently defined in the US Core Implementation Guide.
|
19
|
+
|
20
|
+
All MUST SUPPORT elements must be seen before the test can pass, as well
|
21
|
+
as Data Absent Reason to demonstrate that the server can properly handle
|
22
|
+
missing data. Note that Encounter, Organization and Practitioner resources
|
23
|
+
must be accessible as references in some US Core profiles to satisfy must
|
24
|
+
support requirements, and those references will be validated to their US
|
25
|
+
Core profile. These resources will not be tested for FHIR search support.
|
26
|
+
)
|
27
|
+
run_as_group
|
28
|
+
|
29
|
+
input :url,
|
30
|
+
title: 'FHIR Endpoint',
|
31
|
+
description: 'URL of the FHIR endpoint used by SMART applications'
|
32
|
+
input :patient_id,
|
33
|
+
title: 'Patient ID from SMART App Launch',
|
34
|
+
locked: true
|
35
|
+
input :additional_patient_ids,
|
36
|
+
title: 'Additional Patient IDs',
|
37
|
+
description: <<~DESCRIPTION,
|
38
|
+
Comma separated list of Patient IDs that together with the Patient
|
39
|
+
ID from the SMART App Launch contain all MUST SUPPORT elements.
|
40
|
+
DESCRIPTION
|
41
|
+
optional: true
|
42
|
+
input :smart_credentials,
|
43
|
+
title: 'SMART App Launch Credentials',
|
44
|
+
type: :oauth_credentials,
|
45
|
+
locked: true
|
46
|
+
|
47
|
+
fhir_client do
|
48
|
+
url :url
|
49
|
+
oauth_credentials :smart_credentials
|
50
|
+
end
|
51
|
+
|
52
|
+
input_order :url, :patient_id, :additional_patient_ids, :implantable_device_codes, :smart_credentials
|
53
|
+
|
54
|
+
test do
|
55
|
+
id :g10_patient_id_setup
|
56
|
+
title 'Manage patient id list'
|
57
|
+
|
58
|
+
input :patient_id, :additional_patient_ids
|
59
|
+
output :patient_ids
|
60
|
+
|
61
|
+
run do
|
62
|
+
smart_app_launch_patient_id = patient_id.presence
|
63
|
+
additional_patient_ids_list =
|
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
|
73
|
+
|
74
|
+
all_patient_ids = ([smart_app_launch_patient_id] + additional_patient_ids_list).compact.uniq
|
75
|
+
|
76
|
+
output patient_ids: all_patient_ids.join(',')
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
USCoreTestKit::USCoreV501::USCoreTestSuite.groups.each do |group|
|
81
|
+
test_group = group.ancestors[1]
|
82
|
+
id = test_group.id
|
83
|
+
|
84
|
+
group_config = {}
|
85
|
+
if test_group.respond_to?(:metadata) && test_group.metadata.delayed?
|
86
|
+
test_group.children.reject! { |child| child.include? USCoreTestKit::SearchTest }
|
87
|
+
group_config[:options] = { read_all_resources: true }
|
88
|
+
end
|
89
|
+
|
90
|
+
group(from: id, exclude_optional: true, config: group_config)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -11,11 +11,10 @@ module ONCCertificationG10TestKit
|
|
11
11
|
# Background
|
12
12
|
|
13
13
|
The Invalid AUD Sequence verifies that a SMART Launch Sequence,
|
14
|
-
specifically the
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
a genuine bearer token is not leaked to a counterfit resource server.
|
14
|
+
specifically the Standalone Launch Sequence, does not work in the case
|
15
|
+
where the client sends an invalid FHIR server as the `aud` parameter
|
16
|
+
during launch. This must fail to ensure that a genuine bearer token is not
|
17
|
+
leaked to a counterfit resource server.
|
19
18
|
|
20
19
|
This test is not included as part of a regular SMART Launch Sequence
|
21
20
|
because it requires the browser of the user to be redirected to the
|
@@ -28,6 +27,11 @@ module ONCCertificationG10TestKit
|
|
28
27
|
Note that this test will launch a new browser window. The user is required
|
29
28
|
to 'Attest' in the Inferno user interface after the launch does not
|
30
29
|
succeed, if the server does not return an error code.
|
30
|
+
|
31
|
+
* [Standalone Launch Sequence
|
32
|
+
(STU1)](http://hl7.org/fhir/smart-app-launch/1.0.0/index.html#standalone-launch-sequence)
|
33
|
+
* [Standalone Launch
|
34
|
+
(STU2)](http://hl7.org/fhir/smart-app-launch/STU2/app-launch.html#launch-app-standalone-launch)
|
31
35
|
)
|
32
36
|
id :g10_smart_invalid_aud
|
33
37
|
run_as_group
|
@@ -87,6 +91,47 @@ module ONCCertificationG10TestKit
|
|
87
91
|
:smart_authorization_url
|
88
92
|
|
89
93
|
test from: :smart_app_redirect do
|
94
|
+
required_suite_options smart_app_launch_version: 'smart_app_launch_1'
|
95
|
+
|
96
|
+
input :client_secret,
|
97
|
+
name: :standalone_client_secret,
|
98
|
+
title: 'Standalone Client Secret',
|
99
|
+
description: 'Client Secret provided during registration of Inferno as a standalone application'
|
100
|
+
|
101
|
+
def aud
|
102
|
+
'https://inferno.healthit.gov/invalid_aud'
|
103
|
+
end
|
104
|
+
|
105
|
+
def wait_message(auth_url)
|
106
|
+
%(
|
107
|
+
Inferno will redirect you to an external website for authorization.
|
108
|
+
**It is expected this will fail**. If the server does not return to
|
109
|
+
Inferno automatically, but does provide an error message, you may
|
110
|
+
return to Inferno and confirm that an error was presented in this
|
111
|
+
window.
|
112
|
+
|
113
|
+
* [Perform Invalid Launch](#{auth_url})
|
114
|
+
* [Attest launch
|
115
|
+
failed](#{Inferno::Application['base_url']}/custom/smart/redirect?state=#{state}&confirm_fail=true)
|
116
|
+
)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
test from: :smart_app_redirect_stu2 do
|
121
|
+
required_suite_options smart_app_launch_version: 'smart_app_launch_2'
|
122
|
+
|
123
|
+
config(
|
124
|
+
inputs: {
|
125
|
+
use_pkce: {
|
126
|
+
default: 'true',
|
127
|
+
locked: true
|
128
|
+
},
|
129
|
+
pkce_code_challenge_method: {
|
130
|
+
locked: true
|
131
|
+
}
|
132
|
+
}
|
133
|
+
)
|
134
|
+
|
90
135
|
input :client_secret,
|
91
136
|
name: :standalone_client_secret,
|
92
137
|
title: 'Standalone Client Secret',
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module ONCCertificationG10TestKit
|
2
|
+
class SMARTEHRPatientLaunchGroup < SMARTAppLaunch::EHRLaunchGroup
|
3
|
+
title 'EHR Launch with Patient Scopes'
|
4
|
+
description %(
|
5
|
+
# Background
|
6
|
+
|
7
|
+
If an application launched from an EHR requests and is granted a clinical
|
8
|
+
scope restricted to a single patient, the EHR SHALL establish a patient in
|
9
|
+
context.
|
10
|
+
|
11
|
+
# Test Methodology
|
12
|
+
|
13
|
+
Inferno will attempt an EHR Launch with a clinical scope restricted to a
|
14
|
+
single patient and verify that a patient id is received.
|
15
|
+
|
16
|
+
For more information on the #{title}
|
17
|
+
|
18
|
+
* [Apps that launch from the
|
19
|
+
EHR](http://hl7.org/fhir/smart-app-launch/STU2/scopes-and-launch-context.html#apps-that-launch-from-the-ehr)
|
20
|
+
)
|
21
|
+
id :g10_ehr_patient_launch
|
22
|
+
run_as_group
|
23
|
+
|
24
|
+
config(
|
25
|
+
inputs: {
|
26
|
+
client_id: {
|
27
|
+
name: :ehr_patient_client_id
|
28
|
+
},
|
29
|
+
client_secret: {
|
30
|
+
name: :ehr_patient_client_secret
|
31
|
+
},
|
32
|
+
requested_scopes: {
|
33
|
+
name: :ehr_patient_requested_scopes,
|
34
|
+
default: 'launch openid fhirUser offline_access patient/Patient.read',
|
35
|
+
locked: true
|
36
|
+
},
|
37
|
+
code: {
|
38
|
+
name: :ehr_patient_code
|
39
|
+
},
|
40
|
+
state: {
|
41
|
+
name: :ehr_patient_state
|
42
|
+
},
|
43
|
+
launch: {
|
44
|
+
name: :ehr_patient_launch
|
45
|
+
},
|
46
|
+
smart_credentials: {
|
47
|
+
name: :ehr_patient_smart_credentials
|
48
|
+
},
|
49
|
+
smart_authorization_url: {
|
50
|
+
title: 'OAuth 2.0 Authorize Endpoint',
|
51
|
+
description: 'OAuth 2.0 Authorize Endpoint provided during the EHR launch'
|
52
|
+
},
|
53
|
+
smart_token_url: {
|
54
|
+
title: 'OAuth 2.0 Token Endpoint',
|
55
|
+
description: 'OAuth 2.0 Token Endpoint provided during the EHR launch'
|
56
|
+
}
|
57
|
+
},
|
58
|
+
outputs: {
|
59
|
+
launch: { name: :ehr_patient_launch },
|
60
|
+
code: { name: :ehr_patient_code },
|
61
|
+
token_retrieval_time: { name: :ehr_patient_token_retrieval_time },
|
62
|
+
state: { name: :ehr_patient_state },
|
63
|
+
id_token: { name: :ehr_patient_id_token },
|
64
|
+
refresh_token: { name: :ehr_patient_refresh_token },
|
65
|
+
access_token: { name: :ehr_patient_access_token },
|
66
|
+
expires_in: { name: :ehr_patient_expires_in },
|
67
|
+
patient_id: { name: :ehr_patient_patient_id },
|
68
|
+
encounter_id: { name: :ehr_patient_encounter_id },
|
69
|
+
received_scopes: { name: :ehr_patient_received_scopes },
|
70
|
+
intent: { name: :ehr_patient_intent },
|
71
|
+
smart_credentials: { name: :ehr_patient_smart_credentials }
|
72
|
+
},
|
73
|
+
requests: {
|
74
|
+
redirect: { name: :ehr_patient_redirect },
|
75
|
+
token: { name: :ehr_patient_token }
|
76
|
+
}
|
77
|
+
)
|
78
|
+
|
79
|
+
input_order :url,
|
80
|
+
:ehr_patient_client_id,
|
81
|
+
:ehr_patient_client_secret,
|
82
|
+
:smart_authorization_url,
|
83
|
+
:smart_token_url,
|
84
|
+
:authorization_method
|
85
|
+
|
86
|
+
test from: :g10_patient_context,
|
87
|
+
config: {
|
88
|
+
inputs: {
|
89
|
+
patient_id: { name: :ehr_patient_patient_id },
|
90
|
+
smart_credentials: { name: :ehr_patient_smart_credentials }
|
91
|
+
}
|
92
|
+
}
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module ONCCertificationG10TestKit
|
2
|
+
class SMARTEHRPatientLaunchGroupSTU2 < SMARTAppLaunch::EHRLaunchGroupSTU2
|
3
|
+
title 'EHR Launch with Patient Scopes'
|
4
|
+
description %(
|
5
|
+
# Background
|
6
|
+
|
7
|
+
If an application launched from an EHR requests and is granted a clinical
|
8
|
+
scope restricted to a single patient, the EHR SHALL establish a patient in
|
9
|
+
context.
|
10
|
+
|
11
|
+
# Test Methodology
|
12
|
+
|
13
|
+
Inferno will attempt an EHR Launch with a clinical scope restricted to a
|
14
|
+
single patient and verify that a patient id is received.
|
15
|
+
|
16
|
+
For more information on the #{title}
|
17
|
+
|
18
|
+
* [Apps that launch from the
|
19
|
+
EHR](http://hl7.org/fhir/smart-app-launch/STU2/scopes-and-launch-context.html#apps-that-launch-from-the-ehr)
|
20
|
+
)
|
21
|
+
id :g10_ehr_patient_launch_stu2
|
22
|
+
run_as_group
|
23
|
+
|
24
|
+
config(
|
25
|
+
inputs: {
|
26
|
+
client_id: {
|
27
|
+
name: :ehr_patient_client_id
|
28
|
+
},
|
29
|
+
client_secret: {
|
30
|
+
name: :ehr_patient_client_secret
|
31
|
+
},
|
32
|
+
requested_scopes: {
|
33
|
+
name: :ehr_patient_requested_scopes,
|
34
|
+
default: 'launch openid fhirUser offline_access patient/Patient.rs',
|
35
|
+
locked: true
|
36
|
+
},
|
37
|
+
code: {
|
38
|
+
name: :ehr_patient_code
|
39
|
+
},
|
40
|
+
state: {
|
41
|
+
name: :ehr_patient_state
|
42
|
+
},
|
43
|
+
launch: {
|
44
|
+
name: :ehr_patient_launch
|
45
|
+
},
|
46
|
+
smart_credentials: {
|
47
|
+
name: :ehr_patient_smart_credentials
|
48
|
+
},
|
49
|
+
smart_authorization_url: {
|
50
|
+
title: 'OAuth 2.0 Authorize Endpoint',
|
51
|
+
description: 'OAuth 2.0 Authorize Endpoint provided during the EHR launch'
|
52
|
+
},
|
53
|
+
smart_token_url: {
|
54
|
+
title: 'OAuth 2.0 Token Endpoint',
|
55
|
+
description: 'OAuth 2.0 Token Endpoint provided during the EHR launch'
|
56
|
+
}
|
57
|
+
},
|
58
|
+
outputs: {
|
59
|
+
launch: { name: :ehr_patient_launch },
|
60
|
+
code: { name: :ehr_patient_code },
|
61
|
+
token_retrieval_time: { name: :ehr_patient_token_retrieval_time },
|
62
|
+
state: { name: :ehr_patient_state },
|
63
|
+
id_token: { name: :ehr_patient_id_token },
|
64
|
+
refresh_token: { name: :ehr_patient_refresh_token },
|
65
|
+
access_token: { name: :ehr_patient_access_token },
|
66
|
+
expires_in: { name: :ehr_patient_expires_in },
|
67
|
+
patient_id: { name: :ehr_patient_patient_id },
|
68
|
+
encounter_id: { name: :ehr_patient_encounter_id },
|
69
|
+
received_scopes: { name: :ehr_patient_received_scopes },
|
70
|
+
intent: { name: :ehr_patient_intent },
|
71
|
+
smart_credentials: { name: :ehr_patient_smart_credentials }
|
72
|
+
},
|
73
|
+
requests: {
|
74
|
+
redirect: { name: :ehr_patient_redirect },
|
75
|
+
token: { name: :ehr_patient_token }
|
76
|
+
}
|
77
|
+
)
|
78
|
+
|
79
|
+
input_order :url,
|
80
|
+
:ehr_patient_client_id,
|
81
|
+
:ehr_patient_client_secret,
|
82
|
+
:smart_authorization_url,
|
83
|
+
:smart_token_url,
|
84
|
+
:authorization_method
|
85
|
+
|
86
|
+
test from: :g10_patient_context,
|
87
|
+
config: {
|
88
|
+
inputs: {
|
89
|
+
patient_id: { name: :ehr_patient_patient_id },
|
90
|
+
smart_credentials: { name: :ehr_patient_smart_credentials }
|
91
|
+
}
|
92
|
+
}
|
93
|
+
end
|
94
|
+
end
|