davinci_dtr_test_kit 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|