davinci_dtr_test_kit 0.11.0 → 0.11.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_dinner_questionnaire_package_request_test.rb +64 -27
- data/lib/davinci_dtr_test_kit/client_groups/resp_assist_device/dtr_resp_questionnaire_package_request_test.rb +64 -27
- data/lib/davinci_dtr_test_kit/client_groups/shared/dtr_questionnaire_response_pre_population_test.rb +1 -0
- data/lib/davinci_dtr_test_kit/docs/dtr_payer_server_suite_description_v201.md +2 -2
- data/lib/davinci_dtr_test_kit/dtr_smart_app_suite.rb +1 -1
- data/lib/davinci_dtr_test_kit/fixtures/dinner_adaptive/dinner_order_adaptive_next_question_hamburger.json +1 -1
- data/lib/davinci_dtr_test_kit/fixtures/dinner_static/questionnaire_dinner_order_static.json +1 -1
- data/lib/davinci_dtr_test_kit/mock_auth_server.rb +25 -15
- data/lib/davinci_dtr_test_kit/mock_ehr.rb +8 -3
- data/lib/davinci_dtr_test_kit/payer_server_groups/static_form_request_validation_test.rb +1 -0
- data/lib/davinci_dtr_test_kit/payer_server_groups/static_form_response_validation_test.rb +1 -0
- data/lib/davinci_dtr_test_kit/validation_test.rb +1 -0
- data/lib/davinci_dtr_test_kit/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3449c737f53b2443bc81890e9788ff4aad6837c70865512e58b5a5d3809ad96e
|
4
|
+
data.tar.gz: 4b2775168992e4887e5e330178138bd918a225bf9d57f2b7425a021acc7ee7c1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e6107a0cf03478d3bdc9c9b155af0664b8d39b9a3819e563c3dcf45bc69b34d80a83b0be270022be6d75aeb95a6b2b9b85d486c00693a9ad3e4f0605e2d504ee
|
7
|
+
data.tar.gz: 69701c0a2b4a2a69ae16d5e8dd1b79fd9d27fddf0230d02dc6793be32752d965f01688d3661df72cfdddc9a208b252fda1303f516b5aa6458d33631383fc17f2
|
@@ -11,39 +11,76 @@ module DaVinciDTRTestKit
|
|
11
11
|
Inferno will wait for a DTR questionnaire package request from the client. Upon receipt, Inferno will generate and
|
12
12
|
send a response.
|
13
13
|
)
|
14
|
-
input :smart_app_launch,
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
input :smart_app_launch,
|
15
|
+
type: 'radio',
|
16
|
+
title: 'SMART App Launch',
|
17
|
+
description: 'How will the DTR SMART App launch?',
|
18
|
+
options: { list_options: [{ label: 'EHR Launch from Inferno', value: 'ehr' },
|
19
|
+
{ label: 'Standalone Launch', value: 'standalone' }] }
|
18
20
|
input :client_id
|
19
|
-
input :launch_uri,
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
21
|
+
input :launch_uri,
|
22
|
+
optional: true,
|
23
|
+
description: 'Required if "Launch from Inferno" is selected'
|
24
|
+
input :smart_patient_id,
|
25
|
+
optional: true,
|
26
|
+
title: 'SMART App Launch Patient ID (Dinner Static)',
|
27
|
+
type: 'text',
|
28
|
+
description: %(
|
29
|
+
Patient instance `id` to be provided by Inferno as the `patient` as a part of the SMART App
|
30
|
+
Launch.
|
31
|
+
),
|
32
|
+
default: 'pat015'
|
33
|
+
input :smart_fhir_context,
|
34
|
+
optional: true,
|
35
|
+
title: 'SMART App Launch fhirContext (Dinner Static)',
|
36
|
+
type: 'textarea',
|
37
|
+
description: %(
|
38
|
+
References to be provided by Inferno as the `fhirContext` as a part of the SMART App
|
39
|
+
Launch. These references help determine the behavior of the app. Referenced instances
|
40
|
+
may be provided in the "EHR-available resources" input.
|
41
|
+
),
|
42
|
+
default: JSON.pretty_generate([{ reference: 'Coverage/cov015' },
|
43
|
+
{ reference: 'DeviceRequest/devreqe0470' }])
|
44
|
+
input :ehr_bundle,
|
45
|
+
optional: true,
|
46
|
+
title: 'EHR-available resources (Dinner Static)',
|
47
|
+
type: 'textarea',
|
48
|
+
description: %(
|
49
|
+
Resources available from the EHR needed to drive the dinner static workflow.
|
50
|
+
Formatted as a FHIR bundle that contains resources, each with an `id` property populated. Each
|
51
|
+
instance present will be available for retrieval from Inferno at the endpoint:
|
52
|
+
|
53
|
+
```
|
54
|
+
[fhir-base]/[resource type]/[instance id]
|
55
|
+
```
|
56
|
+
)
|
40
57
|
|
41
58
|
def example_client_jwt_payload_part
|
42
59
|
Base64.strict_encode64({ inferno_client_id: client_id }.to_json).delete('=')
|
43
60
|
end
|
44
61
|
|
45
62
|
run do
|
46
|
-
|
63
|
+
# validate relevant inputs and provide warnings if they are bad
|
64
|
+
warning do
|
65
|
+
if smart_fhir_context
|
66
|
+
assert_valid_json(smart_fhir_context,
|
67
|
+
'The **SMART App Launch fhirContext** input is not valid JSON, so it will not be included in
|
68
|
+
the access token response.')
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
warning do
|
73
|
+
if ehr_bundle
|
74
|
+
assert_valid_json(ehr_bundle,
|
75
|
+
'The **EHR-available resources** input is not valid JSON, so no tester-specified instances
|
76
|
+
will be available to access from Inferno.')
|
77
|
+
assert(FHIR.from_contents(ehr_bundle).is_a?(FHIR::Bundle),
|
78
|
+
'The **EHR-available resources** input does not contain a FHIR Bundle, so no tester-specified instances
|
79
|
+
will be available to access from Inferno.')
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
launch_prompt = if smart_app_launch == 'ehr'
|
47
84
|
%(Launch the DTR SMART App from Inferno by right clicking
|
48
85
|
[this link](#{launch_uri}?iss=#{fhir_base_url}&launch=#{launch_uri})
|
49
86
|
and selecting or "Open in new window" or "Open in new tab".)
|
@@ -60,7 +97,7 @@ module DaVinciDTRTestKit
|
|
60
97
|
|
61
98
|
#{launch_prompt}
|
62
99
|
|
63
|
-
#{inferno_prompt_cont if smart_app_launch == '
|
100
|
+
#{inferno_prompt_cont if smart_app_launch == 'ehr'}
|
64
101
|
|
65
102
|
Then, Inferno will expect the SMART App to invoke the DTR Questionnaire Package operation by sending a POST
|
66
103
|
request to
|
@@ -10,39 +10,76 @@ module DaVinciDTRTestKit
|
|
10
10
|
Inferno will wait for a DTR questionnaire package request from the client. Upon receipt, Inferno will generate and
|
11
11
|
send a response.
|
12
12
|
)
|
13
|
-
input :smart_app_launch,
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
input :smart_app_launch,
|
14
|
+
type: 'radio',
|
15
|
+
title: 'SMART App Launch',
|
16
|
+
description: 'How will the DTR SMART App launch?',
|
17
|
+
options: { list_options: [{ label: 'EHR Launch from Inferno', value: 'ehr' },
|
18
|
+
{ label: 'Standalone Launch', value: 'standalone' }] }
|
17
19
|
input :client_id
|
18
|
-
input :launch_uri,
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
20
|
+
input :launch_uri,
|
21
|
+
optional: true,
|
22
|
+
description: 'Required if "Launch from Inferno" is selected'
|
23
|
+
input :smart_patient_id,
|
24
|
+
optional: true,
|
25
|
+
title: 'SMART App Launch Patient ID (Respiratory Assist Device)',
|
26
|
+
type: 'text',
|
27
|
+
description: %(
|
28
|
+
Patient instance `id` to be provided by Inferno as the `patient` as a part of the SMART App
|
29
|
+
Launch.
|
30
|
+
),
|
31
|
+
default: 'pat015'
|
32
|
+
input :smart_fhir_context,
|
33
|
+
optional: true,
|
34
|
+
title: 'SMART App Launch fhirContext (Respiratory Assist Device)',
|
35
|
+
type: 'textarea',
|
36
|
+
description: %(
|
37
|
+
References to be provided by Inferno as the `fhirContext` as a part of the SMART App
|
38
|
+
Launch. These references help determine the behavior of the app. Referenced instances
|
39
|
+
may be provided in the "EHR-available resources" input.
|
40
|
+
),
|
41
|
+
default: JSON.pretty_generate([{ reference: 'Coverage/cov015' },
|
42
|
+
{ reference: 'DeviceRequest/devreqe0470' }])
|
43
|
+
input :ehr_bundle,
|
44
|
+
optional: true,
|
45
|
+
title: 'EHR-available resources (Respiratory Assist Device)',
|
46
|
+
type: 'textarea',
|
47
|
+
description: %(
|
48
|
+
Resources available from the EHR needed to drive the respiratory assist device workflow.
|
49
|
+
Formatted as a FHIR bundle that contains resources, each with an `id` property populated. Each
|
50
|
+
instance present will be available for retrieval from Inferno at the endpoint
|
51
|
+
|
52
|
+
```
|
53
|
+
[fhir-base]/[resource type]/[instance id]
|
54
|
+
```
|
55
|
+
)
|
39
56
|
|
40
57
|
def example_client_jwt_payload_part
|
41
58
|
Base64.strict_encode64({ inferno_client_id: client_id }.to_json).delete('=')
|
42
59
|
end
|
43
60
|
|
44
61
|
run do
|
45
|
-
|
62
|
+
# validate relevant inputs and provide warnings if they are bad
|
63
|
+
warning do
|
64
|
+
if smart_fhir_context
|
65
|
+
assert_valid_json(smart_fhir_context,
|
66
|
+
'The **SMART App Launch fhirContext** input is not valid JSON, so it will not be included in
|
67
|
+
the access token response.')
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
warning do
|
72
|
+
if ehr_bundle
|
73
|
+
assert_valid_json(ehr_bundle,
|
74
|
+
'The **EHR-available resources** input is not valid JSON, so no tester-specified instances
|
75
|
+
will be available to access from Inferno.')
|
76
|
+
assert(FHIR.from_contents(ehr_bundle).is_a?(FHIR::Bundle),
|
77
|
+
'The **EHR-available resources** input does not contain a FHIR Bundle, so no tester-specified instances
|
78
|
+
will be available to access from Inferno.')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
launch_prompt = if smart_app_launch == 'ehr'
|
46
83
|
%(Launch the DTR SMART App from Inferno by right clicking
|
47
84
|
[this link](#{launch_uri}?iss=#{fhir_base_url}&launch=#{launch_uri})
|
48
85
|
and selecting or "Open in new window" or "Open in new tab".)
|
@@ -58,7 +95,7 @@ module DaVinciDTRTestKit
|
|
58
95
|
|
59
96
|
#{launch_prompt}
|
60
97
|
|
61
|
-
#{inferno_prompt_cont if smart_app_launch == '
|
98
|
+
#{inferno_prompt_cont if smart_app_launch == 'ehr'}
|
62
99
|
|
63
100
|
Then, Inferno will expect the SMART App to invoke the DTR Questionnaire Package operation by sending a POST
|
64
101
|
request to
|
@@ -81,9 +81,9 @@ If you would like to try out the tests but don't have a DTR payer server impleme
|
|
81
81
|
you can run these tests against the DTR SMART Client test suite included in this test kit
|
82
82
|
using the following steps:
|
83
83
|
1. Start an Inferno session of the Da Vinci DTR SMART App Test Suite.
|
84
|
-
1. Select test
|
84
|
+
1. Select test 1.1.1 *Retrieving the Static Questionnaire* from the menu on the left.
|
85
85
|
1. Click the "Run All Tests" button in the upper right.
|
86
|
-
1. In the "
|
86
|
+
1. In the "SMART App Launch" select `Standalone Launch` and in the "client_id" input, put `sample`.
|
87
87
|
1. Click the "submit" button in the dialog that appears. The client tests will now be waiting for requests.
|
88
88
|
1. Start an Inferno session of the DTR Payer Server test suite.
|
89
89
|
1. Select test 1 *Static Questionnaire Package Retrieval* from the menu on the left.
|
@@ -61,7 +61,7 @@ module DaVinciDTRTestKit
|
|
61
61
|
DTRSmartAppSuite.extract_client_id_from_query_params(request)
|
62
62
|
end
|
63
63
|
|
64
|
-
record_response_route :post, EHR_AUTHORIZE_PATH, '
|
64
|
+
record_response_route :post, EHR_AUTHORIZE_PATH, 'dtr_smart_app_ehr_authorize', method(:ehr_authorize),
|
65
65
|
resumes: ->(_) { false } do |request|
|
66
66
|
DTRSmartAppSuite.extract_client_id_from_form_params(request)
|
67
67
|
end
|
@@ -60,22 +60,20 @@ module DaVinciDTRTestKit
|
|
60
60
|
token = JWT.encode({ inferno_client_id: client_id }, nil, 'none')
|
61
61
|
response = { access_token: token, token_type: 'bearer', expires_in: 3600 }
|
62
62
|
test_input = JSON.parse(test_result.input_json)
|
63
|
-
smart_app_launch_input = test_input.find { |input| input['name'] == 'smart_app_launch' }
|
64
63
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
fhir_context = fhir_context_input_value
|
69
|
-
|
70
|
-
|
71
|
-
|
64
|
+
fhir_context_input = test_input.find { |input| input['name'] == 'smart_fhir_context' }
|
65
|
+
fhir_context_input_value = fhir_context_input['value'] if fhir_context_input.present?
|
66
|
+
begin
|
67
|
+
fhir_context = JSON.parse(fhir_context_input_value)
|
68
|
+
rescue StandardError
|
69
|
+
fhir_context = nil
|
70
|
+
end
|
71
|
+
response.merge!({ fhirContext: fhir_context }) if fhir_context
|
72
72
|
|
73
|
-
|
74
|
-
|
75
|
-
|
73
|
+
smart_patient_input = test_input.find { |input| input['name'] == 'smart_patient_id' }
|
74
|
+
smart_patient_input_value = smart_patient_input['value'] if smart_patient_input.present?
|
75
|
+
response.merge!({ patient: smart_patient_input_value }) if smart_patient_input_value
|
76
76
|
|
77
|
-
response.merge!({ patient: smart_patient, fhirContext: fhir_context })
|
78
|
-
end
|
79
77
|
request.response_body = response.to_json
|
80
78
|
request.response_headers = { 'Access-Control-Allow-Origin' => '*' }
|
81
79
|
request.status = 200
|
@@ -102,7 +100,13 @@ module DaVinciDTRTestKit
|
|
102
100
|
encoded_jwt = URI.decode_www_form(request.request_body).to_h['client_assertion']
|
103
101
|
return unless encoded_jwt.present?
|
104
102
|
|
105
|
-
jwt_payload =
|
103
|
+
jwt_payload =
|
104
|
+
begin
|
105
|
+
JWT.decode(encoded_jwt, nil, false)&.first # skip signature verification
|
106
|
+
rescue StandardError
|
107
|
+
nil
|
108
|
+
end
|
109
|
+
|
106
110
|
jwt_payload['iss'] || jwt_payload['sub'] if jwt_payload.present?
|
107
111
|
end
|
108
112
|
|
@@ -120,7 +124,13 @@ module DaVinciDTRTestKit
|
|
120
124
|
|
121
125
|
def extract_client_id_from_bearer_token(request)
|
122
126
|
token = extract_bearer_token(request)
|
123
|
-
|
127
|
+
jwt =
|
128
|
+
begin
|
129
|
+
JWT.decode(token, nil, false)
|
130
|
+
rescue StandardError
|
131
|
+
nil
|
132
|
+
end
|
133
|
+
jwt&.first&.dig('inferno_client_id')
|
124
134
|
end
|
125
135
|
|
126
136
|
# Header expected to be a bearer token of the form "Bearer: <token>"
|
@@ -49,9 +49,14 @@ module DaVinciDTRTestKit
|
|
49
49
|
end
|
50
50
|
|
51
51
|
# Respond with user-inputted resource if there is one that matches the request
|
52
|
-
|
53
|
-
|
54
|
-
|
52
|
+
begin
|
53
|
+
ehr_bundle_input = JSON.parse(test_result.input_json).find { |input| input['name'] == 'ehr_bundle' }
|
54
|
+
ehr_bundle_input_value = ehr_bundle_input_value = ehr_bundle_input['value'] if ehr_bundle_input.present?
|
55
|
+
ehr_bundle = FHIR.from_contents(ehr_bundle_input_value) if ehr_bundle_input_value.present?
|
56
|
+
rescue StandardError
|
57
|
+
ehr_bundle = nil
|
58
|
+
end
|
59
|
+
|
55
60
|
if id.present? && ehr_bundle.present? && ehr_bundle.is_a?(FHIR::Bundle)
|
56
61
|
matching_resource = ehr_bundle.entry&.find do |entry|
|
57
62
|
entry.resource.is_a?(fhir_class) && entry.resource&.id == id
|
@@ -37,6 +37,7 @@ module DaVinciDTRTestKit
|
|
37
37
|
else
|
38
38
|
# TODO: fix redundant logic here
|
39
39
|
skip_if initial_static_questionnaire_request.nil?, 'No request resource was provided - required for manual flow'
|
40
|
+
assert_valid_json(initial_static_questionnaire_request)
|
40
41
|
request = FHIR.from_contents(initial_static_questionnaire_request)
|
41
42
|
assert assert_valid_resource(resource: request, profile_url: 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-qpackage-input-parameters')
|
42
43
|
end
|
@@ -36,6 +36,7 @@ module DaVinciDTRTestKit
|
|
36
36
|
request = fhir_operation("#{url}/Questionnaire/$questionnaire-package",
|
37
37
|
body: JSON.parse(initial_static_questionnaire_request),
|
38
38
|
headers: { 'Content-Type': 'application/json' })
|
39
|
+
assert_valid_json(request.response[:body])
|
39
40
|
resource = FHIR.from_contents(request.response[:body])
|
40
41
|
scratch[:output_parameters] = resource
|
41
42
|
assert_response_status([200, 201], response: request.response)
|
@@ -60,6 +60,7 @@ module DaVinciDTRTestKit
|
|
60
60
|
omit_if resources.blank?,
|
61
61
|
"No #{resource_type} resources provided so the #{profile_url} profile does not apply"
|
62
62
|
resources.each_with_index do |resource, index|
|
63
|
+
assert_valid_json(resource.response[:body])
|
63
64
|
fhir_resource = FHIR.from_contents(resource.response[:body])
|
64
65
|
assert_response_status([200, 202], request: resource, response: resource.response)
|
65
66
|
validate_resource(fhir_resource, resource_type, profile_url, index)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: davinci_dtr_test_kit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.11.
|
4
|
+
version: 0.11.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Karl Naden
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2024-07-
|
13
|
+
date: 2024-07-16 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: inferno_core
|