onc_certification_g10_test_kit 2.3.0 → 3.0.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/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
|