davinci_dtr_test_kit 0.9.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 +7 -0
- data/LICENSE +201 -0
- data/lib/davinci_dtr_test_kit/auth_groups/oauth2_authentication_group.rb +51 -0
- data/lib/davinci_dtr_test_kit/auth_groups/token_request_test.rb +25 -0
- data/lib/davinci_dtr_test_kit/auth_groups/token_validation_test.rb +13 -0
- data/lib/davinci_dtr_test_kit/client_groups/dinner_adaptive/dtr_smart_app_questionnaire_workflow_group.rb +20 -0
- data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_questionnaire_response_save_test.rb +31 -0
- data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_smart_app_questionnaire_workflow_group.rb +89 -0
- data/lib/davinci_dtr_test_kit/client_groups/dinner_static/prepopulation_attestation_test.rb +29 -0
- data/lib/davinci_dtr_test_kit/client_groups/dinner_static/prepopulation_override_attestation_test.rb +30 -0
- data/lib/davinci_dtr_test_kit/client_groups/dinner_static/rendering_enabled_questions_attestation_test.rb +30 -0
- data/lib/davinci_dtr_test_kit/client_groups/resp_assist_device/dtr_full_ehr_questionnaire_workflow_group.rb +19 -0
- data/lib/davinci_dtr_test_kit/client_groups/resp_assist_device/dtr_questionnaire_package_group.rb +16 -0
- data/lib/davinci_dtr_test_kit/client_groups/resp_assist_device/dtr_questionnaire_rendering_attestation_test.rb +32 -0
- data/lib/davinci_dtr_test_kit/client_groups/resp_assist_device/dtr_questionnaire_rendering_group.rb +14 -0
- data/lib/davinci_dtr_test_kit/client_groups/resp_assist_device/dtr_questionnaire_response_group.rb +23 -0
- data/lib/davinci_dtr_test_kit/client_groups/resp_assist_device/dtr_questionnaire_response_save_test.rb +31 -0
- data/lib/davinci_dtr_test_kit/client_groups/resp_assist_device/dtr_smart_app_questionnaire_workflow_group.rb +22 -0
- data/lib/davinci_dtr_test_kit/client_groups/shared/dtr_questionnaire_package_request_test.rb +36 -0
- data/lib/davinci_dtr_test_kit/client_groups/shared/dtr_questionnaire_package_request_validation_test.rb +35 -0
- data/lib/davinci_dtr_test_kit/client_groups/shared/dtr_questionnaire_response_basic_conformance_test.rb +28 -0
- data/lib/davinci_dtr_test_kit/client_groups/shared/dtr_questionnaire_response_pre_population_test.rb +30 -0
- data/lib/davinci_dtr_test_kit/cql_test.rb +387 -0
- data/lib/davinci_dtr_test_kit/docs/dtr_payer_server_suite_description_v201.md +127 -0
- data/lib/davinci_dtr_test_kit/docs/dtr_smart_app_suite_description_v201.md +118 -0
- data/lib/davinci_dtr_test_kit/dtr_full_ehr_suite.rb +55 -0
- data/lib/davinci_dtr_test_kit/dtr_light_ehr_suite.rb +39 -0
- data/lib/davinci_dtr_test_kit/dtr_payer_server_suite.rb +104 -0
- data/lib/davinci_dtr_test_kit/dtr_questionnaire_response_validation.rb +180 -0
- data/lib/davinci_dtr_test_kit/dtr_smart_app_suite.rb +85 -0
- data/lib/davinci_dtr_test_kit/ext/inferno_core/record_response_route.rb +98 -0
- data/lib/davinci_dtr_test_kit/ext/inferno_core/request.rb +19 -0
- data/lib/davinci_dtr_test_kit/ext/inferno_core/runnable.rb +35 -0
- data/lib/davinci_dtr_test_kit/fixture_loader.rb +99 -0
- data/lib/davinci_dtr_test_kit/fixtures/dinner_adaptive/dinner_order_adaptive_next_question_burrito.json +170 -0
- data/lib/davinci_dtr_test_kit/fixtures/dinner_adaptive/dinner_order_adaptive_next_question_hamburger.json +175 -0
- data/lib/davinci_dtr_test_kit/fixtures/dinner_adaptive/dinner_order_adaptive_next_question_initial.json +140 -0
- data/lib/davinci_dtr_test_kit/fixtures/dinner_adaptive/questionnaire_dinner_order_adaptive.json +95 -0
- data/lib/davinci_dtr_test_kit/fixtures/dinner_static/questionnaire_dinner_order_static.json +283 -0
- data/lib/davinci_dtr_test_kit/fixtures/dinner_static/questionnaire_response_dinner_order_static.json +170 -0
- data/lib/davinci_dtr_test_kit/fixtures/pre_populated_questionnaire_response.json +581 -0
- data/lib/davinci_dtr_test_kit/fixtures/questionnaire_package.json +2121 -0
- data/lib/davinci_dtr_test_kit/fixtures.rb +65 -0
- data/lib/davinci_dtr_test_kit/mock_ehr.rb +72 -0
- data/lib/davinci_dtr_test_kit/mock_payer.rb +142 -0
- data/lib/davinci_dtr_test_kit/payer_server_groups/adaptive_form_libraries_test.rb +19 -0
- data/lib/davinci_dtr_test_kit/payer_server_groups/adaptive_form_questionnaire_expressions_test.rb +20 -0
- data/lib/davinci_dtr_test_kit/payer_server_groups/adaptive_form_questionnaire_extensions_test.rb +19 -0
- data/lib/davinci_dtr_test_kit/payer_server_groups/adaptive_next_questionnaire_expressions_test.rb +20 -0
- data/lib/davinci_dtr_test_kit/payer_server_groups/adaptive_next_questionnaire_extensions_test.rb +19 -0
- data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_adaptive_group.rb +88 -0
- data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_adaptive_request_test.rb +41 -0
- data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_adaptive_request_validation_test.rb +44 -0
- data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_adaptive_response_bundles_validation_test.rb +40 -0
- data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_adaptive_response_search_validation_test.rb +42 -0
- data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_adaptive_response_validation_test.rb +49 -0
- data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_next_request_validation_test.rb +61 -0
- data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_next_response_complete_test.rb +17 -0
- data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_next_response_validation_test.rb +43 -0
- data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_static_group.rb +51 -0
- data/lib/davinci_dtr_test_kit/payer_server_groups/static_form_libraries_test.rb +19 -0
- data/lib/davinci_dtr_test_kit/payer_server_groups/static_form_questionnaire_expressions_test.rb +20 -0
- data/lib/davinci_dtr_test_kit/payer_server_groups/static_form_questionnaire_extensions_test.rb +19 -0
- data/lib/davinci_dtr_test_kit/payer_server_groups/static_form_request_test.rb +33 -0
- data/lib/davinci_dtr_test_kit/payer_server_groups/static_form_request_validation_test.rb +46 -0
- data/lib/davinci_dtr_test_kit/payer_server_groups/static_form_response_validation_test.rb +50 -0
- data/lib/davinci_dtr_test_kit/tags.rb +8 -0
- data/lib/davinci_dtr_test_kit/urls.rb +50 -0
- data/lib/davinci_dtr_test_kit/validation_test.rb +72 -0
- data/lib/davinci_dtr_test_kit/version.rb +5 -0
- data/lib/davinci_dtr_test_kit.rb +4 -0
- metadata +132 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
require_relative 'fixture_loader'
|
|
2
|
+
|
|
3
|
+
module DaVinciDTRTestKit
|
|
4
|
+
module Fixtures
|
|
5
|
+
DATA_REQUIREMENT_ANSWERS = { 'RAD Prepopulation' => '3.1' }.freeze
|
|
6
|
+
|
|
7
|
+
def get_questionnaire_package_for_group_id(group_id)
|
|
8
|
+
FixtureLoader.instance.questionnaire_package_for_group_id(group_id)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def find_questionnaire_instance_for_test_id(test_id)
|
|
12
|
+
canonical_url = find_questionnaire_canonical_for_test_id(test_id)
|
|
13
|
+
return unless canonical_url.present?
|
|
14
|
+
|
|
15
|
+
package = get_questionnaire_packcage_for_canonical(canonical_url)
|
|
16
|
+
return unless package.present?
|
|
17
|
+
|
|
18
|
+
questionnaire = nil
|
|
19
|
+
package.entry.find do |entry|
|
|
20
|
+
questionnaire = entry.resource if entry.resource.is_a?(FHIR::Questionnaire)
|
|
21
|
+
end
|
|
22
|
+
questionnaire
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def find_questionnaire_canonical_for_test_id(test_id)
|
|
26
|
+
canonical_url = nil
|
|
27
|
+
|
|
28
|
+
# test_id is of the form [suite id]-[group id 1]-...-[group id n]-[test id]
|
|
29
|
+
groups = test_id.split('-')[1..-2] # first is suite, last is test, we want groups
|
|
30
|
+
groups.each do |one_group_id|
|
|
31
|
+
next if canonical_url.present?
|
|
32
|
+
|
|
33
|
+
canonical_url = get_questionnaire_canonical_for_group_id(one_group_id)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
canonical_url
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def get_questionnaire_canonical_for_group_id(group_id)
|
|
40
|
+
FixtureLoader.instance.questionnaire_canonical_for_group_id(group_id)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def get_questionnaire_packcage_for_canonical(url)
|
|
44
|
+
FixtureLoader.instance.questionnaire_package_for_canonical(url)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def find_questionnaire_response_for_test_id(test_id)
|
|
48
|
+
questionnaire_response = nil
|
|
49
|
+
|
|
50
|
+
# test_id is of the form [suite id]-[group id 1]-...-[group id n]-[test id]
|
|
51
|
+
groups = test_id.split('-')[1..-2] # first is suite, last is test, we want groups
|
|
52
|
+
groups.each do |one_group_id|
|
|
53
|
+
next if questionnaire_response.present?
|
|
54
|
+
|
|
55
|
+
questionnaire_response = get_questionnaire_response_for_group_id(one_group_id)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
questionnaire_response
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def get_questionnaire_response_for_group_id(group_id)
|
|
62
|
+
FixtureLoader.instance.questionnaire_response_for_group_id(group_id)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DaVinciDTRTestKit
|
|
4
|
+
module MockEHR
|
|
5
|
+
RESOURCE_SERVER_BASE = ENV.fetch('FHIR_REFERENCE_SERVER')
|
|
6
|
+
RESOURCE_SERVER_BEARER_TOKEN = 'SAMPLE_TOKEN'
|
|
7
|
+
|
|
8
|
+
RESPONSE_HEADERS = { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }.freeze
|
|
9
|
+
|
|
10
|
+
def resource_server_client
|
|
11
|
+
return @resource_server_client if @resource_server_client
|
|
12
|
+
|
|
13
|
+
client = FHIR::Client.new(RESOURCE_SERVER_BASE)
|
|
14
|
+
client.set_bearer_token(RESOURCE_SERVER_BEARER_TOKEN)
|
|
15
|
+
@resource_server_client = client
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def metadata_handler(_env)
|
|
19
|
+
cs = resource_server_client.capability_statement
|
|
20
|
+
if cs.present?
|
|
21
|
+
[200, { 'Content-Type' => 'application/json', 'Access-Control-Allow-Origin' => '*' }, [cs.to_json]]
|
|
22
|
+
else
|
|
23
|
+
[500, {}, ['Unexpected error occurred while fetching metadata']]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def get_fhir_resource(request, _test = nil, _test_result = nil)
|
|
28
|
+
resource_type, id = resource_type_and_id_from_url(request.url)
|
|
29
|
+
request.response_headers = RESPONSE_HEADERS
|
|
30
|
+
|
|
31
|
+
begin
|
|
32
|
+
fhir_class = FHIR.const_get(resource_type)
|
|
33
|
+
rescue NameError
|
|
34
|
+
resource_type = nil
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
if resource_type.present?
|
|
38
|
+
response = if id.present?
|
|
39
|
+
resource_server_client.read(fhir_class, id)
|
|
40
|
+
else
|
|
41
|
+
resource_server_client.search(fhir_class, search: { parameters: request.query_parameters })
|
|
42
|
+
end
|
|
43
|
+
request.status = response.code
|
|
44
|
+
request.response_body = response.body
|
|
45
|
+
else
|
|
46
|
+
request.status = 400
|
|
47
|
+
request.response_headers = { 'Content-Type': 'application/json' }
|
|
48
|
+
request.response_body = FHIR::OperationOutcome.new(
|
|
49
|
+
issue: FHIR::OperationOutcome::Issue.new(severity: 'warning', code: 'not-supported',
|
|
50
|
+
details: FHIR::CodeableConcept.new(
|
|
51
|
+
text: 'No recognized resource type in URL'
|
|
52
|
+
))
|
|
53
|
+
).to_json
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def questionnaire_response_response(request, _test = nil, _test_result = nil)
|
|
58
|
+
request.status = 201
|
|
59
|
+
request.response_headers = RESPONSE_HEADERS
|
|
60
|
+
request.response_body = request.request_body
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Pull resource type and ID from url
|
|
64
|
+
# e.g. http://example.org/fhir/Patient/123 -> ['Patient', '123']
|
|
65
|
+
# @private
|
|
66
|
+
def resource_type_and_id_from_url(url)
|
|
67
|
+
path = url.split('?').first.split('/fhir/').second
|
|
68
|
+
path.sub!(%r{/$}, '')
|
|
69
|
+
path.split('/')
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'fixtures'
|
|
4
|
+
|
|
5
|
+
module DaVinciDTRTestKit
|
|
6
|
+
module MockPayer
|
|
7
|
+
include Fixtures
|
|
8
|
+
|
|
9
|
+
RESPONSE_HEADERS = { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }.freeze
|
|
10
|
+
|
|
11
|
+
def token_response(request, _test = nil, _test_result = nil)
|
|
12
|
+
# Placeholder for a more complete mock token endpoint
|
|
13
|
+
request.response_body = { access_token: SecureRandom.hex, token_type: 'bearer', expires_in: 300 }.to_json
|
|
14
|
+
request.status = 200
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def questionnaire_package_response(request, _test = nil, test_result = nil)
|
|
18
|
+
request.status = 200
|
|
19
|
+
request.response_headers = RESPONSE_HEADERS
|
|
20
|
+
request.response_body = build_package_questionnaire_response(request, test_result.test_id).to_json
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def payer_questionnaire_response(request, _test = nil, test_result = nil)
|
|
24
|
+
endpoint_input = JSON.parse(test_result.input_json).find { |input| input['name'] == 'custom_endpoint' }
|
|
25
|
+
url_input = JSON.parse(test_result.input_json).find { |input| input['name'] == 'url' }
|
|
26
|
+
client = FHIR::Client.new(url_input['value'])
|
|
27
|
+
client.default_json
|
|
28
|
+
endpoint = endpoint_input['value'].nil? ? '/Questionnaire/$questionnaire-package' : endpoint_input['value']
|
|
29
|
+
payer_response = client.send(:post, endpoint, JSON.parse(request.request_body),
|
|
30
|
+
{ 'Content-Type' => 'application/json' })
|
|
31
|
+
|
|
32
|
+
request.status = 200
|
|
33
|
+
request.response_headers = RESPONSE_HEADERS
|
|
34
|
+
request.response_body = payer_response.response[:body].to_s
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def questionnaire_next_response(request, _test = nil, test_result = nil)
|
|
38
|
+
url_endpoint = JSON.parse(test_result.input_json).find { |input| input['name'] == 'url' }
|
|
39
|
+
client = FHIR::Client.new(url_endpoint['value'])
|
|
40
|
+
client.default_json
|
|
41
|
+
payer_response = client.send(:post, '/Questionnaire/$next-question', JSON.parse(request.request_body),
|
|
42
|
+
{ 'Content-Type' => 'application/json' })
|
|
43
|
+
|
|
44
|
+
request.status = 200
|
|
45
|
+
request.response_headers = RESPONSE_HEADERS
|
|
46
|
+
|
|
47
|
+
request.response_body = payer_response.response[:body]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def extract_client_id(request)
|
|
51
|
+
URI.decode_www_form(request.request_body).to_h['client_id']
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Header expected to be a bearer token of the form "Bearer: <token>"
|
|
55
|
+
def extract_bearer_token(request)
|
|
56
|
+
request.request_header('Authorization')&.value&.split&.last
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def extract_token_from_query_params(request)
|
|
60
|
+
request.query_parameters['token']
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def test_resumes?(test)
|
|
64
|
+
!test.config.options[:accepts_multiple_requests]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def build_package_questionnaire_response(request, test_id)
|
|
68
|
+
test_questionnaire_canonical = find_questionnaire_canonical_for_test_id(test_id)
|
|
69
|
+
test_questionnaire_loaded = false
|
|
70
|
+
|
|
71
|
+
bundles = []
|
|
72
|
+
issues = []
|
|
73
|
+
|
|
74
|
+
# first try the parameters - load the questionnaire specified by the questionnaire parameter
|
|
75
|
+
input_parameters = FHIR.from_contents(request.request_body)
|
|
76
|
+
input_parameters.parameter.each do |one_parameter|
|
|
77
|
+
next unless one_parameter.name == 'questionnaire'
|
|
78
|
+
next unless one_parameter.valueCanonical
|
|
79
|
+
|
|
80
|
+
# don't load test questionnaire if it is also specified explicitly
|
|
81
|
+
test_questionnaire_loaded = true if one_parameter.valueCanonical == test_questionnaire_canonical
|
|
82
|
+
|
|
83
|
+
add_questionnaire_canonical_to_response(one_parameter.valueCanonical, bundles, issues)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
unless test_questionnaire_loaded
|
|
87
|
+
if test_questionnaire_canonical
|
|
88
|
+
add_questionnaire_canonical_to_response(test_questionnaire_canonical, bundles, issues)
|
|
89
|
+
|
|
90
|
+
elsif bundles.empty?
|
|
91
|
+
# no questionnaire for this test ...
|
|
92
|
+
operation_outcome_issue = FHIR::OperationOutcome::Issue.new
|
|
93
|
+
operation_outcome_issue.severity = 'error'
|
|
94
|
+
operation_outcome_issue.code = 'business-rule'
|
|
95
|
+
details = FHIR::CodeableConcept.new
|
|
96
|
+
details.text = "no questionnaire found for test #{test_id}"
|
|
97
|
+
operation_outcome_issue.details = details
|
|
98
|
+
issues << operation_outcome_issue
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
build_package_questionnaire_response_from_lists(bundles, issues)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def add_questionnaire_canonical_to_response(questionnaire_canonical, bundles, issues)
|
|
106
|
+
questionnaire_bundle = get_questionnaire_packcage_for_canonical(questionnaire_canonical)
|
|
107
|
+
|
|
108
|
+
if questionnaire_bundle
|
|
109
|
+
bundles << questionnaire_bundle
|
|
110
|
+
else
|
|
111
|
+
operation_outcome_issue = FHIR::OperationOutcome::Issue.new
|
|
112
|
+
operation_outcome_issue.severity = 'warning'
|
|
113
|
+
operation_outcome_issue.code = 'value'
|
|
114
|
+
details = FHIR::CodeableConcept.new
|
|
115
|
+
details.text = "Questionnaire Canonical #{questionnaire_canonical} does not exist"
|
|
116
|
+
operation_outcome_issue.details = details
|
|
117
|
+
issues << operation_outcome_issue
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def build_package_questionnaire_response_from_lists(bundles, issues)
|
|
122
|
+
response = FHIR::Parameters.new
|
|
123
|
+
bundles.each do |one_bundle|
|
|
124
|
+
return_param = FHIR::Parameters::Parameter.new
|
|
125
|
+
return_param.name = 'return'
|
|
126
|
+
return_param.resource = one_bundle
|
|
127
|
+
response.parameter << return_param
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
unless issues.empty?
|
|
131
|
+
outcome = FHIR::OperationOutcome.new
|
|
132
|
+
outcome.issue = issues
|
|
133
|
+
outcome_param = FHIR::Parameters::Parameter.new
|
|
134
|
+
outcome_param.name = 'outcome'
|
|
135
|
+
outcome_param.resource = outcome
|
|
136
|
+
response.parameter << outcome_param
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
response
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require_relative '../cql_test'
|
|
2
|
+
module DaVinciDTRTestKit
|
|
3
|
+
class PayerAdaptiveFormLibrariesTest < Inferno::Test
|
|
4
|
+
include DaVinciDTRTestKit::CQLTest
|
|
5
|
+
|
|
6
|
+
id :dtr_v201_payer_adaptive_form_libraries_test
|
|
7
|
+
title 'Parameters contain libraries necessary for pre-population'
|
|
8
|
+
description %(
|
|
9
|
+
Inferno check that the payer response contains no duplicate library names
|
|
10
|
+
and that libraries contain cql and elm data.
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
run do
|
|
14
|
+
skip_if retrieval_method == 'Static', 'Performing only static flow tests - only one flow is required.'
|
|
15
|
+
skip_if scratch[:adaptive_responses].nil?, 'No questionnaire bundle returned.'
|
|
16
|
+
check_libraries(scratch[:adaptive_responses])
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
data/lib/davinci_dtr_test_kit/payer_server_groups/adaptive_form_questionnaire_expressions_test.rb
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require_relative '../cql_test'
|
|
2
|
+
module DaVinciDTRTestKit
|
|
3
|
+
class PayerAdaptiveFormExpressionsTest < Inferno::Test
|
|
4
|
+
include DaVinciDTRTestKit::CQLTest
|
|
5
|
+
|
|
6
|
+
id :dtr_v201_payer_adaptive_form_expressions_test
|
|
7
|
+
title 'Questionnaire(s) contains items with expressions necessary for pre-population'
|
|
8
|
+
description %(
|
|
9
|
+
Inferno checks that the payer server response has appropriate expressions and that expressions are
|
|
10
|
+
written in cql.
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
run do
|
|
14
|
+
skip_if retrieval_method == 'Static', 'Performing only static flow tests - only one flow is required.'
|
|
15
|
+
skip_if scratch[:adaptive_responses].nil?, 'No questionnaire bundle returned.'
|
|
16
|
+
questionnaire_items_test(scratch[:adaptive_responses], final_cql_test: false)
|
|
17
|
+
scratch[:adaptive_responses] = nil
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
data/lib/davinci_dtr_test_kit/payer_server_groups/adaptive_form_questionnaire_extensions_test.rb
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require_relative '../cql_test'
|
|
2
|
+
module DaVinciDTRTestKit
|
|
3
|
+
class PayerAdaptiveFormExtensionsTest < Inferno::Test
|
|
4
|
+
include DaVinciDTRTestKit::CQLTest
|
|
5
|
+
|
|
6
|
+
id :dtr_v201_payer_adaptive_form_extensions_test
|
|
7
|
+
title 'Questionnaire(s) contains extensions necessary for pre-population'
|
|
8
|
+
description %(
|
|
9
|
+
Inferno checks that the payer server response has appropriate extensions and references to libraries within
|
|
10
|
+
those extensions.
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
run do
|
|
14
|
+
skip_if retrieval_method == 'Static', 'Performing only static flow tests - only one flow is required.'
|
|
15
|
+
skip_if scratch[:adaptive_responses].nil?, 'No questionnaire bundle returned.'
|
|
16
|
+
questionnaire_extensions_test(scratch[:adaptive_responses])
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
data/lib/davinci_dtr_test_kit/payer_server_groups/adaptive_next_questionnaire_expressions_test.rb
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require_relative '../cql_test'
|
|
2
|
+
module DaVinciDTRTestKit
|
|
3
|
+
class PayerStaticFormExpressionsTest < Inferno::Test
|
|
4
|
+
include DaVinciDTRTestKit::CQLTest
|
|
5
|
+
|
|
6
|
+
id :dtr_v201_payer_adaptive_next_form_expressions_test
|
|
7
|
+
title 'Questionnaire(s) contains items with expressions necessary for pre-population'
|
|
8
|
+
description %(
|
|
9
|
+
Inferno checks that the payer server response has appropriate expressions and that expressions are
|
|
10
|
+
written in cql.
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
run do
|
|
14
|
+
skip_if retrieval_method == 'Static', 'Performing only static flow tests - only one flow is required.'
|
|
15
|
+
skip_if scratch[:next_responses].nil?, 'No questionnaires returned.'
|
|
16
|
+
questionnaire_items_test(scratch[:next_responses], final_cql_test: true)
|
|
17
|
+
scratch[:next_responses] = nil
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
data/lib/davinci_dtr_test_kit/payer_server_groups/adaptive_next_questionnaire_extensions_test.rb
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require_relative '../cql_test'
|
|
2
|
+
module DaVinciDTRTestKit
|
|
3
|
+
class PayerStaticFormExtensionsTest < Inferno::Test
|
|
4
|
+
include DaVinciDTRTestKit::CQLTest
|
|
5
|
+
|
|
6
|
+
id :dtr_v201_payer_adaptive_next_form_extensions_test
|
|
7
|
+
title 'Questionnaire(s) contains extensions necessary for pre-population'
|
|
8
|
+
description %(
|
|
9
|
+
Inferno checks that the payer server response has appropriate extensions and references to libraries within
|
|
10
|
+
those extensions.
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
run do
|
|
14
|
+
skip_if retrieval_method == 'Static', 'Performing only static flow tests - only one flow is required.'
|
|
15
|
+
skip_if scratch[:next_responses].nil?, 'No questionnaires returned.'
|
|
16
|
+
questionnaire_extensions_test(scratch[:next_responses])
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
require_relative 'payer_server_adaptive_request_test'
|
|
2
|
+
require_relative 'payer_server_adaptive_request_validation_test'
|
|
3
|
+
require_relative 'payer_server_adaptive_response_bundles_validation_test'
|
|
4
|
+
require_relative 'payer_server_adaptive_response_search_validation_test'
|
|
5
|
+
require_relative 'payer_server_adaptive_response_validation_test'
|
|
6
|
+
require_relative 'payer_server_next_request_validation_test'
|
|
7
|
+
require_relative 'payer_server_next_response_validation_test'
|
|
8
|
+
require_relative 'payer_server_next_response_complete_test'
|
|
9
|
+
require_relative 'adaptive_form_libraries_test'
|
|
10
|
+
require_relative 'adaptive_form_questionnaire_extensions_test'
|
|
11
|
+
require_relative 'adaptive_form_questionnaire_expressions_test'
|
|
12
|
+
require_relative 'adaptive_next_questionnaire_extensions_test'
|
|
13
|
+
require_relative 'adaptive_next_questionnaire_expressions_test'
|
|
14
|
+
|
|
15
|
+
module DaVinciDTRTestKit
|
|
16
|
+
class DTRPayerServerAdaptiveQuestionnairePackageGroup < Inferno::TestGroup
|
|
17
|
+
title 'Adaptive Questionnaire Retrieval'
|
|
18
|
+
description %(
|
|
19
|
+
|
|
20
|
+
## Background
|
|
21
|
+
|
|
22
|
+
These tests validate the ability of the Payer Server to provide an adaptive questionnaire
|
|
23
|
+
following requests from the DTR Client. Resources are validated as specified
|
|
24
|
+
in the DTR v2.0.1 Implementation Guide.
|
|
25
|
+
|
|
26
|
+
There are several input options, which correspond to different workflows. No inputs are explicitly required,
|
|
27
|
+
but all inputs for at least one work flow must be provided to complete testing (see below).
|
|
28
|
+
|
|
29
|
+
## Testing Work Flow Options
|
|
30
|
+
|
|
31
|
+
- Enter the `FHIR Server Base Url` and `Access Token` if you are connecting a client that will provide
|
|
32
|
+
inferno with requests to be tested and sent to the server under test. These inputs must align with
|
|
33
|
+
the configuration of the DTR client being used to provide requests. Optionally,
|
|
34
|
+
an `Endpoint for a Particular Adaptive Resource` can also be provided, which should include the ID
|
|
35
|
+
of the resource of interest (e.g., `/Questionnaire/HomeOxygenTherapyAdditional/$questionnaire-package`).
|
|
36
|
+
|
|
37
|
+
- Enter the `Initial Adaptive Questionnaire Request` and a set of `Next Question Requests`, in addition to the
|
|
38
|
+
`FHIR Server Base Url` pointing to the payer server,
|
|
39
|
+
to provide the json requests manually, rather than relying on a DTR client.
|
|
40
|
+
)
|
|
41
|
+
id :payer_server_adaptive_questionnaire
|
|
42
|
+
run_as_group
|
|
43
|
+
|
|
44
|
+
input :initial_adaptive_questionnaire_request,
|
|
45
|
+
optional: true,
|
|
46
|
+
title: 'Initial Adaptive Questionnaire Request',
|
|
47
|
+
description: 'Manual Flow',
|
|
48
|
+
type: 'textarea'
|
|
49
|
+
|
|
50
|
+
input :next_question_requests,
|
|
51
|
+
optional: true,
|
|
52
|
+
title: 'Next Question Requests',
|
|
53
|
+
description: 'Manual Flow',
|
|
54
|
+
type: 'textarea'
|
|
55
|
+
|
|
56
|
+
input_order :retrieval_method,
|
|
57
|
+
:url,
|
|
58
|
+
:custom_endpoint,
|
|
59
|
+
:access_token,
|
|
60
|
+
:initial_adaptive_questionnaire_request,
|
|
61
|
+
:next_question_requests,
|
|
62
|
+
:credentials
|
|
63
|
+
|
|
64
|
+
# receive client request
|
|
65
|
+
test from: :payer_server_questionnaire_request,
|
|
66
|
+
receives_request: :client_questionnaire_package
|
|
67
|
+
|
|
68
|
+
# optionally validate client request
|
|
69
|
+
test from: :payer_server_adaptive_questionnaire_request_validation
|
|
70
|
+
|
|
71
|
+
# pass request to payer server, validate questionnaire response
|
|
72
|
+
test from: :payer_server_adaptive_response_validation_test
|
|
73
|
+
test from: :dtr_v201_payer_adaptive_form_libraries_test
|
|
74
|
+
test from: :dtr_v201_payer_adaptive_form_extensions_test
|
|
75
|
+
test from: :dtr_v201_payer_adaptive_form_expressions_test
|
|
76
|
+
test from: :payer_server_adaptive_response_bundles_validation_test
|
|
77
|
+
test from: :payer_server_adaptive_response_search_validation_test
|
|
78
|
+
|
|
79
|
+
# optionally validate the client request
|
|
80
|
+
test from: :payer_server_next_request_validation
|
|
81
|
+
|
|
82
|
+
# pass request to payer server, validate adaptive questionnaire response
|
|
83
|
+
test from: :payer_server_next_response_validation_test
|
|
84
|
+
test from: :dtr_v201_payer_adaptive_next_form_extensions_test
|
|
85
|
+
test from: :dtr_v201_payer_adaptive_next_form_expressions_test
|
|
86
|
+
test from: :payer_server_adaptive_completion_test
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require_relative '../urls'
|
|
2
|
+
|
|
3
|
+
module DaVinciDTRTestKit
|
|
4
|
+
class AdaptiveFormTest < Inferno::Test
|
|
5
|
+
include URLs
|
|
6
|
+
title 'Confirm the client completes the DTR Adaptive Questionnaire work flow'
|
|
7
|
+
description %(
|
|
8
|
+
Inferno will wait for a DTR questionnaire package request from the client. Upon receipt, Inferno will generate and
|
|
9
|
+
send a response.
|
|
10
|
+
)
|
|
11
|
+
id :payer_server_questionnaire_request
|
|
12
|
+
config options: { accepts_multiple_requests: true }
|
|
13
|
+
|
|
14
|
+
run do
|
|
15
|
+
skip_if retrieval_method == 'Static', 'Performing only static flow tests - only one flow is required.'
|
|
16
|
+
pass_if !(initial_adaptive_questionnaire_request.nil? || next_question_requests.nil?),
|
|
17
|
+
'Proceeding with manually provided resources.'
|
|
18
|
+
skip_if access_token.nil?, 'Please provide an access token or all request resources as inputs.'
|
|
19
|
+
wait(
|
|
20
|
+
identifier: access_token,
|
|
21
|
+
message: %(
|
|
22
|
+
**Adaptive Form Testing**
|
|
23
|
+
|
|
24
|
+
Invoke the DTR Questionnaire Package operation by sending a POST request to
|
|
25
|
+
|
|
26
|
+
`#{questionnaire_package_url}`
|
|
27
|
+
|
|
28
|
+
and Next Question operations by sending POST requests to
|
|
29
|
+
|
|
30
|
+
`#{next_url}`
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
A set of questionnaire packages generated by Inferno will be returned. Each of the following tests
|
|
34
|
+
will validate all resources, marking messages in the order they are received.
|
|
35
|
+
|
|
36
|
+
**[click here](#{resume_pass_url}?token=#{access_token})** when the adaptive forms have been completed.
|
|
37
|
+
)
|
|
38
|
+
)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_adaptive_request_validation_test.rb
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require_relative '../validation_test'
|
|
2
|
+
module DaVinciDTRTestKit
|
|
3
|
+
class PayerAdaptiveFormRequestTest < Inferno::Test
|
|
4
|
+
include URLs
|
|
5
|
+
include DaVinciDTRTestKit::ValidationTest
|
|
6
|
+
title '[USER INPUT VALIDATION] Questionnaire Package request is valid'
|
|
7
|
+
description %(
|
|
8
|
+
This test validates the conformance of the client's request to the
|
|
9
|
+
[DTR Questionnaire Package Input Parameters](http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-qpackage-input-parameters)
|
|
10
|
+
structure.
|
|
11
|
+
|
|
12
|
+
It verifies the presence of mandatory elements and that elements with required bindings contain appropriate
|
|
13
|
+
values. CodeableConcept element bindings will fail if none of their codings have a code/system belonging
|
|
14
|
+
to the bound ValueSet. Quantity, Coding, and code element bindings will fail if their code/system are not found in
|
|
15
|
+
the valueset.
|
|
16
|
+
|
|
17
|
+
This test may process multiple resources, labeling messages with the corresponding tested resources
|
|
18
|
+
in the order that they were received.
|
|
19
|
+
)
|
|
20
|
+
id :payer_server_adaptive_questionnaire_request_validation
|
|
21
|
+
|
|
22
|
+
run do
|
|
23
|
+
skip_if retrieval_method == 'Static', 'Performing only static flow tests - only one flow is required.'
|
|
24
|
+
if initial_adaptive_questionnaire_request.nil?
|
|
25
|
+
resources = load_tagged_requests(QUESTIONNAIRE_TAG)
|
|
26
|
+
using_manual_entry = false
|
|
27
|
+
else
|
|
28
|
+
resources = initial_adaptive_questionnaire_request
|
|
29
|
+
using_manual_entry = true
|
|
30
|
+
end
|
|
31
|
+
skip_if resources.nil?, 'No request resources to validate.'
|
|
32
|
+
perform_request_validation_test(
|
|
33
|
+
resources,
|
|
34
|
+
:parameters,
|
|
35
|
+
'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-qpackage-input-parameters',
|
|
36
|
+
questionnaire_package_url,
|
|
37
|
+
using_manual_entry
|
|
38
|
+
)
|
|
39
|
+
rescue Inferno::Exceptions::AssertionException => e
|
|
40
|
+
msg = e.message.to_s.strip
|
|
41
|
+
skip msg
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require_relative '../validation_test'
|
|
2
|
+
module DaVinciDTRTestKit
|
|
3
|
+
class PayerAdaptiveFormResponseBundlesTest < Inferno::Test
|
|
4
|
+
include DaVinciDTRTestKit::ValidationTest
|
|
5
|
+
id :payer_server_adaptive_response_bundles_validation_test
|
|
6
|
+
title 'Validate that the adaptive response contains valid Questionnaire Bundle resources'
|
|
7
|
+
description %(
|
|
8
|
+
This test ensures that the payer's response includes a resource that conforms to the the
|
|
9
|
+
[DTR Quesitonnaire Bundle](http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/DTR-QPackageBundle)
|
|
10
|
+
structure.
|
|
11
|
+
|
|
12
|
+
It verifies the presence of mandatory elements and that elements with required bindings contain appropriate
|
|
13
|
+
values. CodeableConcept element bindings will fail if none of their codings have a code/system belonging
|
|
14
|
+
to the bound ValueSet. Quantity, Coding, and code element bindings will fail if their code/system are not found in
|
|
15
|
+
the valueset.
|
|
16
|
+
|
|
17
|
+
This test may process multiple resources, labeling messages with the corresponding tested resources
|
|
18
|
+
in the order that they were received.
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
run do
|
|
22
|
+
skip_if retrieval_method == 'Static', 'Performing only static flow tests - only one flow is required.'
|
|
23
|
+
test_passed = false
|
|
24
|
+
profile_url = 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/DTR-QPackageBundle'
|
|
25
|
+
assert !scratch[:adaptive_responses].nil?, 'No resources to validate.'
|
|
26
|
+
scratch[:adaptive_responses].each_with_index do |resource, index|
|
|
27
|
+
fhir_resource = FHIR.from_contents(resource.response[:body])
|
|
28
|
+
fhir_resource.parameter.each do |param|
|
|
29
|
+
resource_is_valid = validate_resource(param.resource, :bundle, profile_url, index)
|
|
30
|
+
test_passed = true if resource_is_valid
|
|
31
|
+
rescue StandardError
|
|
32
|
+
next
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
raise tests_failed[profile_url][0] if !test_passed && !tests_failed[profile_url].blank?
|
|
36
|
+
|
|
37
|
+
messages.clear if test_passed
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
require_relative '../validation_test'
|
|
2
|
+
module DaVinciDTRTestKit
|
|
3
|
+
class PayerAdaptiveFormResponseSearchTest < Inferno::Test
|
|
4
|
+
include DaVinciDTRTestKit::ValidationTest
|
|
5
|
+
id :payer_server_adaptive_response_search_validation_test
|
|
6
|
+
title 'Validate that the adaptive response contains valid a Adaptive Form Search resource'
|
|
7
|
+
description %(
|
|
8
|
+
This test validates the conformance of the payer's response to the
|
|
9
|
+
[DTR Questionnaire for Adaptive Form Search](http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-questionnaire-adapt-search)
|
|
10
|
+
structure.
|
|
11
|
+
|
|
12
|
+
It verifies the presence of mandatory elements and that elements with required bindings contain appropriate
|
|
13
|
+
values. CodeableConcept element bindings will fail if none of their codings have a code/system belonging
|
|
14
|
+
to the bound ValueSet. Quantity, Coding, and code element bindings will fail if their code/system are not found in
|
|
15
|
+
the valueset.
|
|
16
|
+
|
|
17
|
+
This test may process multiple resources, labeling messages with the corresponding tested resources
|
|
18
|
+
in the order that they were received.
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
run do
|
|
22
|
+
skip_if retrieval_method == 'Static', 'Performing only static flow tests - only one flow is required.'
|
|
23
|
+
test_passed = false
|
|
24
|
+
profile_url = 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-questionnaire-adapt-search'
|
|
25
|
+
assert !scratch[:adaptive_responses].nil?, 'No resources to validate.'
|
|
26
|
+
scratch[:adaptive_responses].each_with_index do |resource, index|
|
|
27
|
+
fhir_resource = FHIR.from_contents(resource.response[:body])
|
|
28
|
+
fhir_resource.parameter.each do |param|
|
|
29
|
+
param.resource.entry.each do |entry|
|
|
30
|
+
resource_is_valid = validate_resource(entry.resource, :questionnaire, profile_url, index)
|
|
31
|
+
test_passed = true if resource_is_valid
|
|
32
|
+
end
|
|
33
|
+
rescue StandardError
|
|
34
|
+
next
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
raise tests_failed[profile_url][0] if !test_passed && !tests_failed[profile_url].blank?
|
|
38
|
+
|
|
39
|
+
messages.clear if test_passed
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|