davinci_dtr_test_kit 0.12.0 → 0.13.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.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_full_ehr_dinner_static_questionnaire_response_conformance_test.rb +15 -0
  3. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_full_ehr_dinner_static_questionnaire_response_correctness_test.rb +30 -0
  4. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_full_ehr_questionnaire_workflow_group.rb +15 -5
  5. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_smart_app_dinner_questionnaire_package_request_test.rb +1 -1
  6. data/lib/davinci_dtr_test_kit/client_groups/shared/dtr_questionnaire_response_basic_conformance_test.rb +3 -7
  7. data/lib/davinci_dtr_test_kit/client_groups/shared/dtr_questionnaire_response_pre_population_test.rb +9 -5
  8. data/lib/davinci_dtr_test_kit/cql_test.rb +182 -137
  9. data/lib/davinci_dtr_test_kit/docs/dtr_light_ehr_suite_description_v201.md +29 -0
  10. data/lib/davinci_dtr_test_kit/dtr_light_ehr_suite.rb +38 -25
  11. data/lib/davinci_dtr_test_kit/dtr_options.rb +7 -0
  12. data/lib/davinci_dtr_test_kit/dtr_questionnaire_response_validation.rb +118 -75
  13. data/lib/davinci_dtr_test_kit/dtr_smart_app_suite.rb +6 -3
  14. data/lib/davinci_dtr_test_kit/fixture_loader.rb +6 -84
  15. data/lib/davinci_dtr_test_kit/fixtures.rb +43 -48
  16. data/lib/davinci_dtr_test_kit/mock_auth_server.rb +101 -18
  17. data/lib/davinci_dtr_test_kit/mock_ehr.rb +32 -24
  18. data/lib/davinci_dtr_test_kit/mock_payer.rb +41 -64
  19. data/lib/davinci_dtr_test_kit/payer_server_groups/adaptive_next_questionnaire_expressions_test.rb +2 -2
  20. data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_adaptive_request_validation_test.rb +2 -1
  21. data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_adaptive_response_validation_test.rb +6 -5
  22. data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_next_request_validation_test.rb +1 -1
  23. data/lib/davinci_dtr_test_kit/payer_server_groups/static_form_request_validation_test.rb +2 -1
  24. data/lib/davinci_dtr_test_kit/payer_server_groups/static_form_response_validation_test.rb +6 -4
  25. data/lib/davinci_dtr_test_kit/tags.rb +1 -0
  26. data/lib/davinci_dtr_test_kit/urls.rb +13 -10
  27. data/lib/davinci_dtr_test_kit/validation_test.rb +2 -1
  28. data/lib/davinci_dtr_test_kit/version.rb +1 -1
  29. data/lib/davinci_dtr_test_kit.rb +1 -1
  30. metadata +24 -8
  31. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_full_ehr_prepopulation_representation_attestation_test.rb +0 -33
  32. data/lib/davinci_dtr_test_kit/client_groups/resp_assist_device/dtr_full_ehr_questionnaire_workflow_group.rb +0 -19
  33. /data/lib/davinci_dtr_test_kit/fixtures/{pre_populated_questionnaire_response.json → respiratory_assist_device/pre_populated_questionnaire_response.json} +0 -0
  34. /data/lib/davinci_dtr_test_kit/fixtures/{questionnaire_package.json → respiratory_assist_device/questionnaire_package.json} +0 -0
@@ -1,16 +1,37 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'urls'
2
- require_relative 'fixtures'
3
4
 
4
5
  module DaVinciDTRTestKit
5
6
  module MockAuthServer
6
- include Fixtures
7
+ AUTHORIZED_PRACTITIONER_ID = 'pra1234' # Must exist on the FHIR_REFERENCE_SERVER (env var)
8
+
9
+ RSA_PRIVATE_KEY = OpenSSL::PKey::RSA.generate(2048)
10
+ RSA_PUBLIC_KEY = RSA_PRIVATE_KEY.public_key
11
+ SUPPORTED_SCOPES = ['launch', 'patient/*.rs', 'user/*.rs', 'offline_access', 'openid', 'fhirUser'].freeze
12
+
13
+ def requests_repo
14
+ @requests_repo ||= Inferno::Repositories::Requests.new
15
+ end
16
+
17
+ def auth_server_jwks(_env)
18
+ response_body = {
19
+ keys: [
20
+ {
21
+ kty: 'RSA',
22
+ alg: 'RS256',
23
+ n: Base64.urlsafe_encode64(RSA_PUBLIC_KEY.n.to_s(2), padding: false),
24
+ e: Base64.urlsafe_encode64(RSA_PUBLIC_KEY.e.to_s(2), padding: false),
25
+ use: 'sig'
26
+ }
27
+ ]
28
+ }.to_json
29
+
30
+ [200, { 'Content-Type' => 'application/json', 'Access-Control-Allow-Origin' => '*' }, [response_body]]
31
+ end
7
32
 
8
33
  def ehr_smart_config(env)
9
- protocol = env['rack.url_scheme']
10
- host = env['HTTP_HOST']
11
- path = env['REQUEST_PATH'] || env['PATH_INFO']
12
- path.gsub!(%r{#{SMART_CONFIG_PATH}(/)?}, '')
13
- base_url = "#{protocol}://#{host + path}"
34
+ base_url = env_base_url(env, SMART_CONFIG_PATH)
14
35
  response_body =
15
36
  {
16
37
  authorization_endpoint: base_url + EHR_AUTHORIZE_PATH,
@@ -18,7 +39,7 @@ module DaVinciDTRTestKit
18
39
  token_endpoint_auth_methods_supported: ['private_key_jwt'],
19
40
  token_endpoint_auth_signing_alg_values_supported: ['RS256'],
20
41
  grant_types_supported: ['authorization_code'],
21
- scopes_supported: ['launch', 'patient/*.rs', 'user/*.rs', 'offline_access'],
42
+ scopes_supported: SUPPORTED_SCOPES,
22
43
  response_types_supported: ['code'],
23
44
  code_challenge_methods_supported: ['S256'],
24
45
  capabilities: [
@@ -34,9 +55,23 @@ module DaVinciDTRTestKit
34
55
  [200, { 'Content-Type' => 'application/json', 'Access-Control-Allow-Origin' => '*' }, [response_body]]
35
56
  end
36
57
 
58
+ def ehr_openid_config(env)
59
+ base_url = env_base_url(env, OPENID_CONFIG_PATH)
60
+ response_body = {
61
+ issuer: base_url + FHIR_BASE_PATH,
62
+ authorization_endpoint: base_url + EHR_AUTHORIZE_PATH,
63
+ token_endpoint: base_url + EHR_TOKEN_PATH,
64
+ jwks_uri: base_url + JKWS_PATH,
65
+ response_types_supported: ['id_token'],
66
+ subject_types_supported: ['public'],
67
+ id_token_signing_alg_values_supported: ['RS256']
68
+ }.to_json
69
+ [200, { 'Content-Type' => 'application/json', 'Access-Control-Allow-Origin' => '*' }, [response_body]]
70
+ end
71
+
37
72
  def ehr_authorize(request, _test = nil, _test_result = nil)
38
73
  # Authorization requests can bet GET or POST
39
- params = request.verb == 'get' ? request.query_parameters : URI.decode_www_form(request.request_body)&.to_h
74
+ params = params_hash(request)
40
75
  if params['redirect_uri'].present?
41
76
  redirect_uri = "#{params['redirect_uri']}?" \
42
77
  "code=#{SecureRandom.hex}&" \
@@ -57,25 +92,34 @@ module DaVinciDTRTestKit
57
92
 
58
93
  def ehr_token_response(request, _test = nil, test_result = nil)
59
94
  client_id = extract_client_id_from_token_request(request)
60
- token = JWT.encode({ inferno_client_id: client_id }, nil, 'none')
61
- response = { access_token: token, token_type: 'bearer', expires_in: 3600 }
62
- test_input = JSON.parse(test_result.input_json)
95
+ access_token = JWT.encode({ inferno_client_id: client_id }, nil, 'none')
96
+ granted_scopes = SUPPORTED_SCOPES & requested_scopes(test_result.test_session_id)
63
97
 
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?
98
+ response = { access_token:, scope: granted_scopes.join(' '), token_type: 'bearer', expires_in: 3600 }
99
+
100
+ if granted_scopes.include?('openid')
101
+ response.merge!(id_token: create_id_token(request, client_id, fhir_user: granted_scopes.include?('fhirUser')))
102
+ end
103
+
104
+ fhir_context_input = find_test_input(test_result, 'smart_fhir_context')
105
+ fhir_context_input_value = fhir_context_input['value'] if fhir_context_input
66
106
  begin
67
107
  fhir_context = JSON.parse(fhir_context_input_value)
68
108
  rescue StandardError
69
109
  fhir_context = nil
70
110
  end
71
- response.merge!({ fhirContext: fhir_context }) if fhir_context
111
+ response.merge!(fhirContext: fhir_context) if fhir_context
72
112
 
73
- smart_patient_input = test_input.find { |input| input['name'] == 'smart_patient_id' }
113
+ smart_patient_input = find_test_input(test_result, 'smart_patient_id')
74
114
  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
115
+ response.merge!(patient: smart_patient_input_value) if smart_patient_input_value
76
116
 
77
117
  request.response_body = response.to_json
78
- request.response_headers = { 'Access-Control-Allow-Origin' => '*' }
118
+ request.response_headers = {
119
+ 'Cache-Control' => 'no-store',
120
+ 'Pragma' => 'no-cache',
121
+ 'Access-Control-Allow-Origin' => '*'
122
+ }
79
123
  request.status = 200
80
124
  end
81
125
 
@@ -141,5 +185,44 @@ module DaVinciDTRTestKit
141
185
  def extract_token_from_query_params(request)
142
186
  request.query_parameters['token']
143
187
  end
188
+
189
+ def create_id_token(request, client_id, fhir_user: false)
190
+ # No point in mocking an identity provider, just always use known Practitioner as the authorized user
191
+ suite_base_url = request.url.split(EHR_TOKEN_PATH).first
192
+ id_token_hash = {
193
+ iss: suite_base_url + FHIR_BASE_PATH,
194
+ sub: AUTHORIZED_PRACTITIONER_ID,
195
+ aud: client_id,
196
+ exp: Time.now.to_i + (24 * 60 * 60), # 24 hrs
197
+ iat: Time.now.to_i
198
+ }
199
+ id_token_hash.merge!(fhirUser: "#{suite_base_url}/fhir/Practitioner/#{AUTHORIZED_PRACTITIONER_ID}") if fhir_user
200
+
201
+ JWT.encode(id_token_hash, RSA_PRIVATE_KEY, 'RS256')
202
+ end
203
+
204
+ def requested_scopes(test_session_id)
205
+ auth_request = requests_repo.tagged_requests(test_session_id, [EHR_AUTHORIZE_TAG]).last
206
+ return [] unless auth_request
207
+
208
+ scope_str = params_hash(auth_request)&.dig('scope')
209
+ scope_str ? URI.decode_www_form_component(scope_str).split : []
210
+ end
211
+
212
+ def find_test_input(test_result, input_name)
213
+ JSON.parse(test_result.input_json)&.find { |input| input['name'] == input_name }
214
+ end
215
+
216
+ def params_hash(request)
217
+ request.verb == 'get' ? request.query_parameters : URI.decode_www_form(request.request_body)&.to_h
218
+ end
219
+
220
+ def env_base_url(env, endpoint_path)
221
+ protocol = env['rack.url_scheme']
222
+ host = env['HTTP_HOST']
223
+ path = env['REQUEST_PATH'] || env['PATH_INFO']
224
+ path.gsub!(%r{#{endpoint_path}(/)?}, '')
225
+ "#{protocol}://#{host + path}"
226
+ end
144
227
  end
145
228
  end
@@ -27,16 +27,10 @@ module DaVinciDTRTestKit
27
27
  end
28
28
 
29
29
  def get_fhir_resource(request, _test = nil, test_result = nil)
30
- resource_type, id = resource_type_and_id_from_url(request.url)
30
+ fhir_class, id = fhir_class_and_id_from_url(request.url)
31
31
  request.response_headers = RESPONSE_HEADERS
32
32
 
33
- begin
34
- fhir_class = FHIR.const_get(resource_type)
35
- rescue NameError
36
- resource_type = nil
37
- end
38
-
39
- if resource_type.blank?
33
+ if fhir_class.nil?
40
34
  request.status = 400
41
35
  request.response_headers = { 'Content-Type': 'application/json' }
42
36
  request.response_body = FHIR::OperationOutcome.new(
@@ -49,18 +43,9 @@ module DaVinciDTRTestKit
49
43
  end
50
44
 
51
45
  # Respond with user-inputted resource if there is one that matches the request
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
-
60
- if id.present? && ehr_bundle.present? && ehr_bundle.is_a?(FHIR::Bundle)
61
- matching_resource = ehr_bundle.entry&.find do |entry|
62
- entry.resource.is_a?(fhir_class) && entry.resource&.id == id
63
- end&.resource
46
+ ehr_bundle = ehr_input_bundle(test_result)
47
+ if id.present? && ehr_bundle.present?
48
+ matching_resource = find_resource_in_bundle(ehr_bundle, fhir_class, id)
64
49
  if matching_resource.present?
65
50
  request.status = 200
66
51
  request.response_headers = { 'Content-Type': 'application/json' }
@@ -85,13 +70,36 @@ module DaVinciDTRTestKit
85
70
  request.response_body = request.request_body
86
71
  end
87
72
 
88
- # Pull resource type and ID from url
89
- # e.g. http://example.org/fhir/Patient/123 -> ['Patient', '123']
73
+ def ehr_input_bundle(test_result)
74
+ ehr_bundle_input = JSON.parse(test_result.input_json).find { |input| input['name'] == 'ehr_bundle' }
75
+ ehr_bundle_input_value = ehr_bundle_input_value = ehr_bundle_input['value'] if ehr_bundle_input.present?
76
+ ehr_bundle = FHIR.from_contents(ehr_bundle_input_value) if ehr_bundle_input_value.present?
77
+ ehr_bundle if ehr_bundle.is_a?(FHIR::Bundle)
78
+ rescue StandardError
79
+ nil
80
+ end
81
+
82
+ def find_resource_in_bundle(bundle, fhir_class, id)
83
+ bundle.entry&.find do |entry|
84
+ entry.resource.is_a?(fhir_class) && entry.resource&.id == id
85
+ end&.resource
86
+ end
87
+
88
+ # Pull resource type class and ID from url
89
+ # e.g. http://example.org/fhir/Patient/123 -> [FHIR::Patient, '123']
90
90
  # @private
91
- def resource_type_and_id_from_url(url)
91
+ def fhir_class_and_id_from_url(url)
92
92
  path = url.split('?').first.split('/fhir/').second
93
93
  path.sub!(%r{/$}, '')
94
- path.split('/')
94
+ resource_type, id = path.split('/')
95
+
96
+ begin
97
+ fhir_class = FHIR.const_get(resource_type)
98
+ rescue NameError
99
+ fhir_class = nil
100
+ end
101
+
102
+ [fhir_class, id]
95
103
  end
96
104
  end
97
105
  end
@@ -4,14 +4,12 @@ require_relative 'fixtures'
4
4
 
5
5
  module DaVinciDTRTestKit
6
6
  module MockPayer
7
- include Fixtures
8
-
9
7
  RESPONSE_HEADERS = { 'Content-Type' => 'application/json', 'Access-Control-Allow-Origin' => '*' }.freeze
10
8
 
11
9
  def questionnaire_package_response(request, _test = nil, test_result = nil)
12
10
  request.status = 200
13
11
  request.response_headers = RESPONSE_HEADERS
14
- request.response_body = build_package_questionnaire_response(request, test_result.test_id).to_json
12
+ request.response_body = build_questionnaire_package_response(request, test_result.test_id).to_json
15
13
  end
16
14
 
17
15
  def payer_questionnaire_response(request, _test = nil, test_result = nil)
@@ -45,79 +43,58 @@ module DaVinciDTRTestKit
45
43
  !test.config.options[:accepts_multiple_requests]
46
44
  end
47
45
 
48
- def build_package_questionnaire_response(request, test_id)
49
- test_questionnaire_canonical = find_questionnaire_canonical_for_test_id(test_id)
50
- test_questionnaire_loaded = false
51
-
52
- bundles = []
53
- issues = []
54
-
55
- # first try the parameters - load the questionnaire specified by the questionnaire parameter
56
- input_parameters = FHIR.from_contents(request.request_body)
57
- input_parameters.parameter.each do |one_parameter|
58
- next unless one_parameter.name == 'questionnaire'
59
- next unless one_parameter.valueCanonical
46
+ private
60
47
 
61
- # don't load test questionnaire if it is also specified explicitly
62
- test_questionnaire_loaded = true if one_parameter.valueCanonical == test_questionnaire_canonical
48
+ def build_questionnaire_package_response(request, test_id)
49
+ begin
50
+ input_parameters = FHIR.from_contents(request.request_body)
51
+ rescue StandardError
52
+ return operation_outcome('error', 'invalid', 'No valid input parameters')
53
+ end
63
54
 
64
- add_questionnaire_canonical_to_response(one_parameter.valueCanonical, bundles, issues)
55
+ questionnaire_package = Fixtures.questionnaire_package_for_test(test_id)
56
+ unless questionnaire_package
57
+ return operation_outcome('error', 'business-rule', "No Questionnaire found for Inferno test #{test_id}")
65
58
  end
66
59
 
67
- unless test_questionnaire_loaded
68
- if test_questionnaire_canonical
69
- add_questionnaire_canonical_to_response(test_questionnaire_canonical, bundles, issues)
70
-
71
- elsif bundles.empty?
72
- # no questionnaire for this test ...
73
- operation_outcome_issue = FHIR::OperationOutcome::Issue.new
74
- operation_outcome_issue.severity = 'error'
75
- operation_outcome_issue.code = 'business-rule'
76
- details = FHIR::CodeableConcept.new
77
- details.text = "no questionnaire found for test #{test_id}"
78
- operation_outcome_issue.details = details
79
- issues << operation_outcome_issue
80
- end
60
+ questionnaire_canonical = find_questionnaire_canonical(questionnaire_package)
61
+
62
+ other_questionnaire_params = input_parameters.parameter.filter do |param|
63
+ param.name == 'questionnaire' && param.valueCanonical != questionnaire_canonical
81
64
  end
82
65
 
83
- build_package_questionnaire_response_from_lists(bundles, issues)
66
+ return questionnaire_package unless other_questionnaire_params.any?
67
+
68
+ FHIR::Parameters.new(
69
+ parameter: [
70
+ FHIR::Parameters::Parameter.new(
71
+ name: 'PackageBundle',
72
+ resource: questionnaire_package
73
+ ),
74
+ FHIR::Parameters::Parameter.new(
75
+ name: 'Outcome',
76
+ resource: FHIR::OperationOutcome.new(
77
+ issue: other_questionnaire_params.map do |param|
78
+ outcome_issue('warning', 'not-found', "Questionnaire #{param.valueCanonical} does not exist")
79
+ end
80
+ )
81
+ )
82
+ ]
83
+ )
84
84
  end
85
85
 
86
- def add_questionnaire_canonical_to_response(questionnaire_canonical, bundles, issues)
87
- questionnaire_bundle = get_questionnaire_packcage_for_canonical(questionnaire_canonical)
88
-
89
- if questionnaire_bundle
90
- bundles << questionnaire_bundle
91
- else
92
- operation_outcome_issue = FHIR::OperationOutcome::Issue.new
93
- operation_outcome_issue.severity = 'warning'
94
- operation_outcome_issue.code = 'value'
95
- details = FHIR::CodeableConcept.new
96
- details.text = "Questionnaire Canonical #{questionnaire_canonical} does not exist"
97
- operation_outcome_issue.details = details
98
- issues << operation_outcome_issue
99
- end
86
+ def find_questionnaire_canonical(questionnaire_package)
87
+ questionnaire_package&.entry&.find { |e| e.resource.is_a?(FHIR::Questionnaire) }&.resource&.url
100
88
  end
101
89
 
102
- def build_package_questionnaire_response_from_lists(bundles, issues)
103
- response = FHIR::Parameters.new
104
- bundles.each do |one_bundle|
105
- return_param = FHIR::Parameters::Parameter.new
106
- return_param.name = 'return'
107
- return_param.resource = one_bundle
108
- response.parameter << return_param
109
- end
90
+ def operation_outcome(severity, code, text = nil)
91
+ FHIR::OperationOutcome.new(issue: outcome_issue(severity, code, text))
92
+ end
110
93
 
111
- unless issues.empty?
112
- outcome = FHIR::OperationOutcome.new
113
- outcome.issue = issues
114
- outcome_param = FHIR::Parameters::Parameter.new
115
- outcome_param.name = 'outcome'
116
- outcome_param.resource = outcome
117
- response.parameter << outcome_param
94
+ def outcome_issue(severity, code, text = nil)
95
+ FHIR::OperationOutcome::Issue.new(severity:, code:).tap do |issue|
96
+ issue.details = FHIR::CodeableConcept.new(text:) if text.present?
118
97
  end
119
-
120
- response
121
98
  end
122
99
  end
123
100
  end
@@ -6,8 +6,8 @@ module DaVinciDTRTestKit
6
6
  id :dtr_v201_payer_adaptive_next_form_expressions_test
7
7
  title 'Questionnaire(s) contains items with expressions necessary for pre-population'
8
8
  description %(
9
- Inferno checks that the payer server response to $next-question operation has appropriate expressions and that expressions are
10
- written in cql.
9
+ Inferno checks that the payer server response to $next-question operation has appropriate expressions and that
10
+ expressions are written in cql.
11
11
  )
12
12
 
13
13
  run do
@@ -22,7 +22,8 @@ module DaVinciDTRTestKit
22
22
  if initial_adaptive_questionnaire_request.nil?
23
23
  requests = load_tagged_requests(QUESTIONNAIRE_TAG)
24
24
  skip_if requests.blank?, 'No request resource received from the client.'
25
- # making the assumption that only one request was made here - if there were multiple, we are only validating the first
25
+ # making the assumption that only one request was made here - if there were multiple, we are only validating the
26
+ # first
26
27
  resource_is_valid?(resource: FHIR.from_contents(requests[0].request[:body]), profile_url: profile_with_version)
27
28
  else
28
29
  request = FHIR.from_contents(initial_adaptive_questionnaire_request)
@@ -24,21 +24,22 @@ module DaVinciDTRTestKit
24
24
  profile_with_version = 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-qpackage-output-parameters|2.0.1'
25
25
  endpoint = custom_endpoint.blank? ? '/Questionnaire/$questionnaire-package' : custom_endpoint
26
26
  if initial_adaptive_questionnaire_request.nil?
27
- # making the assumption that only one response was received - if there were multiple, we are only validating the first
27
+ # making the assumption that only one response was received - if there were multiple, we are only validating the
28
+ # first
28
29
  response = load_tagged_requests(QUESTIONNAIRE_TAG)[0]
29
30
  scratch[:adaptive_responses] = [response]
30
31
  resource = FHIR.from_contents(response.response[:body])
31
32
  else
32
33
  response = fhir_operation("#{url}#{endpoint}", body: JSON.parse(initial_adaptive_questionnaire_request),
33
- headers: { 'Content-Type': 'application/json' })
34
+ headers: { 'Content-Type': 'application/json' })
34
35
  resource = FHIR.from_contents(response.response[:body])
35
36
  scratch[:adaptive_responses] = [response]
36
37
  end
37
-
38
+
38
39
  assert !scratch[:adaptive_responses].nil?, 'No resources to validate.'
39
40
  assert_response_status([200, 201], response: response.response)
40
- assert_resource_type(:parameters, resource: resource)
41
- assert_valid_resource(resource: resource, profile_url: profile_with_version)
41
+ assert_resource_type(:parameters, resource:)
42
+ assert_valid_resource(resource:, profile_url: profile_with_version)
42
43
  questionnaire_bundle = resource.parameter.find { |param| param.resource.resourceType == 'Bundle' }&.resource
43
44
  assert questionnaire_bundle, 'No questionnaire bundle found in the response'
44
45
  assert_valid_resource(resource: questionnaire_bundle, profile_url: 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/DTR-QPackageBundle|2.0.1')
@@ -50,7 +50,7 @@ module DaVinciDTRTestKit
50
50
  )
51
51
  else
52
52
  messages << { type: 'error',
53
- message: format_markdown("No resources were of type 'Parameters' or 'QuestionnaireResponse'") }
53
+ message: format_markdown("No resources were of type 'Parameters' or 'QuestionnaireResponse'") }
54
54
  end
55
55
  errors_found = messages.any? { |message| message[:type] == 'error' }
56
56
  skip_if errors_found, "No resources conform to the profiles http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaireresponse-adapt
@@ -24,7 +24,8 @@ module DaVinciDTRTestKit
24
24
  skip_if access_token.nil?, 'No access token provided - required for client flow.'
25
25
  requests = load_tagged_requests(QUESTIONNAIRE_TAG)
26
26
  skip_if requests.blank?, 'No request resource received from the client.'
27
- # making the assumption that only one request was made here - if there were multiple, we are only validating the first
27
+ # making the assumption that only one request was made here - if there were multiple, we are only validating the
28
+ # first
28
29
  resource_is_valid?(resource: FHIR.from_contents(requests[0].request[:body]), profile_url: profile_with_version)
29
30
  else
30
31
  request = FHIR.from_contents(initial_static_questionnaire_request)
@@ -26,8 +26,10 @@ module DaVinciDTRTestKit
26
26
  resources = load_tagged_requests(QUESTIONNAIRE_TAG)
27
27
  skip_if resources.nil?, 'No request resource received from the client.'
28
28
  scratch[:output_parameters] = resources
29
- # making the assumption that only one response was received- if there were multiple, we are only validating the first
30
- assert_valid_resource(resource: FHIR.from_contents(resources[0].request[:body]), profile_url: profile_with_version)
29
+ # making the assumption that only one response was received- if there were multiple, we are only validating the
30
+ # first
31
+ assert_valid_resource(resource: FHIR.from_contents(resources[0].request[:body]),
32
+ profile_url: profile_with_version)
31
33
  else
32
34
  request = fhir_operation("#{url}/Questionnaire/$questionnaire-package",
33
35
  body: JSON.parse(initial_static_questionnaire_request),
@@ -36,8 +38,8 @@ module DaVinciDTRTestKit
36
38
  resource = FHIR.from_contents(request.response[:body])
37
39
  scratch[:output_parameters] = resource
38
40
  assert_response_status([200, 201], response: request.response)
39
- assert_resource_type(:parameters, resource: resource)
40
- assert_valid_resource(resource: resource, profile_url: profile_with_version)
41
+ assert_resource_type(:parameters, resource:)
42
+ assert_valid_resource(resource:, profile_url: profile_with_version)
41
43
  questionnaire_bundle = resource.parameter.find { |param| param.resource.resourceType == 'Bundle' }&.resource
42
44
  assert questionnaire_bundle, 'No questionnaire bundle found in the response'
43
45
  assert_valid_resource(resource: questionnaire_bundle, profile_url: 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/DTR-QPackageBundle|2.0.1')
@@ -5,4 +5,5 @@ module DaVinciDTRTestKit
5
5
  NEXT_TAG = 'payer_server_adaptive_questionnaire_package'
6
6
  QUESTIONNAIRE_PACKAGE_TAG = 'dtr_questionnaire_package'
7
7
  SMART_APP_EHR_REQUEST_TAG = 'dtr_smart_app_ehr_request'
8
+ EHR_AUTHORIZE_TAG = 'dtr_smart_app_ehr_authorize'
8
9
  end
@@ -1,17 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DaVinciDTRTestKit
4
- SMART_CONFIG_PATH = '/fhir/.well-known/smart-configuration'
5
- EHR_AUTHORIZE_PATH = '/mock_ehr_auth/authorize'
6
- EHR_TOKEN_PATH = '/mock_ehr_auth/token'
7
- PAYER_TOKEN_PATH = '/mock_payer_auth/token'
8
- QUESTIONNAIRE_PACKAGE_PATH = '/fhir/Questionnaire/$questionnaire-package'
9
- NEXT_PATH = '/fhir/Questionnaire/$next-question'
10
- QUESTIONNAIRE_RESPONSE_PATH = '/fhir/QuestionnaireResponse'
4
+ FHIR_BASE_PATH = '/fhir'
5
+ SMART_CONFIG_PATH = "#{FHIR_BASE_PATH}/.well-known/smart-configuration".freeze
6
+ OPENID_CONFIG_PATH = "#{FHIR_BASE_PATH}/.well-known/openid-configuration".freeze
7
+ JKWS_PATH = "#{FHIR_BASE_PATH}/.well-known/jwks.json".freeze
8
+ EHR_AUTHORIZE_PATH = "#{FHIR_BASE_PATH}/mock_ehr_auth/authorize".freeze
9
+ EHR_TOKEN_PATH = "#{FHIR_BASE_PATH}/mock_ehr_auth/token".freeze
10
+ PAYER_TOKEN_PATH = "#{FHIR_BASE_PATH}/mock_payer_auth/token".freeze
11
+ QUESTIONNAIRE_PACKAGE_PATH = "#{FHIR_BASE_PATH}/Questionnaire/$questionnaire-package".freeze
12
+ NEXT_PATH = "#{FHIR_BASE_PATH}/Questionnaire/$next-question".freeze
13
+ QUESTIONNAIRE_RESPONSE_PATH = "#{FHIR_BASE_PATH}/QuestionnaireResponse".freeze
14
+ FHIR_RESOURCE_PATH = "#{FHIR_BASE_PATH}/:resource/:id".freeze
15
+ FHIR_SEARCH_PATH = "#{FHIR_BASE_PATH}/:resource".freeze
11
16
  RESUME_PASS_PATH = '/resume_pass'
12
17
  RESUME_FAIL_PATH = '/resume_fail'
13
- FHIR_RESOURCE_PATH = '/fhir/:resource/:id'
14
- FHIR_SEARCH_PATH = '/fhir/:resource'
15
18
 
16
19
  module URLs
17
20
  def base_url
@@ -43,7 +46,7 @@ module DaVinciDTRTestKit
43
46
  end
44
47
 
45
48
  def fhir_base_url
46
- @fhir_base_url ||= "#{base_url}/fhir"
49
+ @fhir_base_url ||= base_url + FHIR_BASE_PATH
47
50
  end
48
51
 
49
52
  def resume_pass_url
@@ -42,7 +42,8 @@ module DaVinciDTRTestKit
42
42
  else
43
43
  if resource.url != resource_url
44
44
  messages << { type: 'warning',
45
- message: format_markdown("Request made to wrong URL: #{resource.request[:url]}. Should instead be to #{resource_url}") }
45
+ message: format_markdown(%(Request made to wrong URL: #{resource.request[:url]}.
46
+ Should instead be to #{resource_url})) }
46
47
  end
47
48
  fhir_resource = FHIR.from_contents(resource.request[:body])
48
49
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DaVinciDTRTestKit
4
- VERSION = '0.12.0'
4
+ VERSION = '0.13.0'
5
5
  end
@@ -1,4 +1,4 @@
1
1
  require_relative 'davinci_dtr_test_kit/dtr_payer_server_suite'
2
2
  require_relative 'davinci_dtr_test_kit/dtr_smart_app_suite'
3
3
  require_relative 'davinci_dtr_test_kit/dtr_full_ehr_suite'
4
- # require_relative 'davinci_dtr_test_kit/dtr_light_ehr_suite'
4
+ require_relative 'davinci_dtr_test_kit/dtr_light_ehr_suite'