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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e95ac1a81ec266133aa196823f9c4af450b6ff0c628b2ca9dccbb0fcd3b32863
4
- data.tar.gz: d4ac1d46eadaa7f1067d07b4811e00803308f8d1c91cf9165f6e17534a280449
3
+ metadata.gz: 3449c737f53b2443bc81890e9788ff4aad6837c70865512e58b5a5d3809ad96e
4
+ data.tar.gz: 4b2775168992e4887e5e330178138bd918a225bf9d57f2b7425a021acc7ee7c1
5
5
  SHA512:
6
- metadata.gz: 22b65864b0795e2355b17d19b78d262524b29a9c0b1352603cd226a8d5c135a5bb0566c6c8449ce4ea0516ebedbee1e7a94965d7448e98a927b07716bd65c049
7
- data.tar.gz: 0daaae716b201d20f99c768e5a7bc9d6ae997f953ab2d238862298ab00a39d82746b5e1a71537f13eeb09ea260c097955a22487405128aa5cbe9339cc1860fce
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, type: 'radio', title: 'SMART App Launch',
15
- description: 'How will the DTR SMART App launch?',
16
- options: { list_options: [{ label: 'Launch from Inferno', value: 'inferno' },
17
- { label: 'Launch from EHR', value: 'ehr' }] }
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, optional: true, description: 'Required if "Launch from Inferno" is selected'
20
- input :smart_patient_id, optional: true, title: 'SMART App Launch Patient ID (Dinner Static)',
21
- type: 'text',
22
- description: %(
23
- Patient instance id to be provided by Inferno as the `patient` as a part of the SMART app
24
- launch.
25
- )
26
- input :smart_fhir_context, optional: true, title: 'SMART App Launch fhirContext (Dinner Static)',
27
- type: 'textarea',
28
- description: %(
29
- References to be provided by Inferno as the `fhirContext` as a part of the SMART app
30
- launch. These references help determine the behavior of the app. Referenced instances
31
- may be providedin the "EHR-available resources" input.
32
- )
33
- input :ehr_bundle, optional: true, title: 'EHR-available resources (Dinner Static)', type: 'textarea',
34
- description: %(
35
- Resources available from the EHR needed to drive the dinner static workflow.
36
- Formatted as a FHIR bundle that contains resources, each with an `id` property populated. Each
37
- instance present will be available for retrieval from Inferno at the endpoint
38
- `[fhir-base]/[resource type]/[instance id].`
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
- launch_prompt = if smart_app_launch == 'inferno'
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 == 'inferno'}
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, type: 'radio', title: 'SMART App Launch',
14
- description: 'How will the DTR SMART App launch?',
15
- options: { list_options: [{ label: 'Launch from Inferno', value: 'inferno' },
16
- { label: 'Launch from EHR', value: 'ehr' }] }
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, optional: true, description: 'Required if "Launch from Inferno" is selected'
19
- input :smart_patient_id, optional: true, title: 'SMART App Launch Patient ID (Respiratory Assist Device)',
20
- type: 'text',
21
- description: %(
22
- Patient instance id to be provided by Inferno as the `patient` as a part of the SMART app
23
- launch.
24
- )
25
- input :smart_fhir_context, optional: true, title: 'SMART App Launch fhirContext (Respiratory Assist Device)',
26
- type: 'textarea',
27
- description: %(
28
- References to be provided by Inferno as the `fhirContext` as a part of the SMART app
29
- launch. These references help determine the behavior of the app. Referenced instances
30
- may be providedin the "EHR-available resources" input.
31
- )
32
- input :ehr_bundle, optional: true, title: 'EHR-available resources (Respiratory Assist Device)', type: 'textarea',
33
- description: %(
34
- Resources available from the EHR needed to drive the respiratory assist device
35
- workflow. Formatted as a FHIR bundle that contains resources, each with an `id`
36
- property populated. Each instance present will be available for retrieval from
37
- Inferno at the endpoint `[fhir-base]/[resource type]/[instance id].`
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
- launch_prompt = if smart_app_launch == 'inferno'
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 == 'inferno'}
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
@@ -21,6 +21,7 @@ module DaVinciDTRTestKit
21
21
  )
22
22
 
23
23
  run do
24
+ assert_valid_json(request.request_body)
24
25
  questionnaire_response = FHIR.from_contents(request.request_body)
25
26
  skip_if !questionnaire_response.present?, 'QuestionnaireResponse not received'
26
27
 
@@ -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 2.1.1 *Static Questionnaire Workflow* from the menu on the left.
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 "access_token" input, put `cnVuIHRvZ2V0aGVy`.
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, 'dtr_smart_app_authorize', method(:ehr_authorize),
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
@@ -153,7 +153,7 @@
153
153
  },
154
154
  {
155
155
  "valueCoding": {
156
- "code": "Pickels"
156
+ "code": "Pickles"
157
157
  }
158
158
  },
159
159
  {
@@ -156,7 +156,7 @@
156
156
  },
157
157
  {
158
158
  "valueCoding": {
159
- "code": "Pickels"
159
+ "code": "Pickles"
160
160
  }
161
161
  },
162
162
  {
@@ -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
- if smart_app_launch_input.present? && smart_app_launch_input['value'] == 'inferno'
66
- fhir_context_input = test_input.find { |input| input['name'] == 'smart_fhir_context' }
67
- fhir_context_input_value = fhir_context_input['value'] if fhir_context_input.present?
68
- fhir_context = fhir_context_input_value || [
69
- { reference: 'Coverage/cov015' },
70
- { reference: 'DeviceRequest/devreqe0470' }
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
- 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
- smart_patient = smart_patient_input_value || 'pat015'
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 = JWT.decode(encoded_jwt, nil, false)&.first # skip signature verification
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
- JWT.decode(token, nil, false)&.first&.dig('inferno_client_id')
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
- ehr_bundle_input = JSON.parse(test_result.input_json).find { |input| input['name'] == 'ehr_bundle' }
53
- ehr_bundle_input_value = ehr_bundle_input_value = ehr_bundle_input['value'] if ehr_bundle_input.present?
54
- ehr_bundle = FHIR.from_contents(ehr_bundle_input_value) if ehr_bundle_input_value.present?
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)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DaVinciDTRTestKit
4
- VERSION = '0.11.0'
4
+ VERSION = '0.11.1'
5
5
  end
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.0
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-15 00:00:00.000000000 Z
13
+ date: 2024-07-16 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: inferno_core