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.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +201 -0
  3. data/lib/davinci_dtr_test_kit/auth_groups/oauth2_authentication_group.rb +51 -0
  4. data/lib/davinci_dtr_test_kit/auth_groups/token_request_test.rb +25 -0
  5. data/lib/davinci_dtr_test_kit/auth_groups/token_validation_test.rb +13 -0
  6. data/lib/davinci_dtr_test_kit/client_groups/dinner_adaptive/dtr_smart_app_questionnaire_workflow_group.rb +20 -0
  7. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_questionnaire_response_save_test.rb +31 -0
  8. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_smart_app_questionnaire_workflow_group.rb +89 -0
  9. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/prepopulation_attestation_test.rb +29 -0
  10. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/prepopulation_override_attestation_test.rb +30 -0
  11. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/rendering_enabled_questions_attestation_test.rb +30 -0
  12. data/lib/davinci_dtr_test_kit/client_groups/resp_assist_device/dtr_full_ehr_questionnaire_workflow_group.rb +19 -0
  13. data/lib/davinci_dtr_test_kit/client_groups/resp_assist_device/dtr_questionnaire_package_group.rb +16 -0
  14. data/lib/davinci_dtr_test_kit/client_groups/resp_assist_device/dtr_questionnaire_rendering_attestation_test.rb +32 -0
  15. data/lib/davinci_dtr_test_kit/client_groups/resp_assist_device/dtr_questionnaire_rendering_group.rb +14 -0
  16. data/lib/davinci_dtr_test_kit/client_groups/resp_assist_device/dtr_questionnaire_response_group.rb +23 -0
  17. data/lib/davinci_dtr_test_kit/client_groups/resp_assist_device/dtr_questionnaire_response_save_test.rb +31 -0
  18. data/lib/davinci_dtr_test_kit/client_groups/resp_assist_device/dtr_smart_app_questionnaire_workflow_group.rb +22 -0
  19. data/lib/davinci_dtr_test_kit/client_groups/shared/dtr_questionnaire_package_request_test.rb +36 -0
  20. data/lib/davinci_dtr_test_kit/client_groups/shared/dtr_questionnaire_package_request_validation_test.rb +35 -0
  21. data/lib/davinci_dtr_test_kit/client_groups/shared/dtr_questionnaire_response_basic_conformance_test.rb +28 -0
  22. data/lib/davinci_dtr_test_kit/client_groups/shared/dtr_questionnaire_response_pre_population_test.rb +30 -0
  23. data/lib/davinci_dtr_test_kit/cql_test.rb +387 -0
  24. data/lib/davinci_dtr_test_kit/docs/dtr_payer_server_suite_description_v201.md +127 -0
  25. data/lib/davinci_dtr_test_kit/docs/dtr_smart_app_suite_description_v201.md +118 -0
  26. data/lib/davinci_dtr_test_kit/dtr_full_ehr_suite.rb +55 -0
  27. data/lib/davinci_dtr_test_kit/dtr_light_ehr_suite.rb +39 -0
  28. data/lib/davinci_dtr_test_kit/dtr_payer_server_suite.rb +104 -0
  29. data/lib/davinci_dtr_test_kit/dtr_questionnaire_response_validation.rb +180 -0
  30. data/lib/davinci_dtr_test_kit/dtr_smart_app_suite.rb +85 -0
  31. data/lib/davinci_dtr_test_kit/ext/inferno_core/record_response_route.rb +98 -0
  32. data/lib/davinci_dtr_test_kit/ext/inferno_core/request.rb +19 -0
  33. data/lib/davinci_dtr_test_kit/ext/inferno_core/runnable.rb +35 -0
  34. data/lib/davinci_dtr_test_kit/fixture_loader.rb +99 -0
  35. data/lib/davinci_dtr_test_kit/fixtures/dinner_adaptive/dinner_order_adaptive_next_question_burrito.json +170 -0
  36. data/lib/davinci_dtr_test_kit/fixtures/dinner_adaptive/dinner_order_adaptive_next_question_hamburger.json +175 -0
  37. data/lib/davinci_dtr_test_kit/fixtures/dinner_adaptive/dinner_order_adaptive_next_question_initial.json +140 -0
  38. data/lib/davinci_dtr_test_kit/fixtures/dinner_adaptive/questionnaire_dinner_order_adaptive.json +95 -0
  39. data/lib/davinci_dtr_test_kit/fixtures/dinner_static/questionnaire_dinner_order_static.json +283 -0
  40. data/lib/davinci_dtr_test_kit/fixtures/dinner_static/questionnaire_response_dinner_order_static.json +170 -0
  41. data/lib/davinci_dtr_test_kit/fixtures/pre_populated_questionnaire_response.json +581 -0
  42. data/lib/davinci_dtr_test_kit/fixtures/questionnaire_package.json +2121 -0
  43. data/lib/davinci_dtr_test_kit/fixtures.rb +65 -0
  44. data/lib/davinci_dtr_test_kit/mock_ehr.rb +72 -0
  45. data/lib/davinci_dtr_test_kit/mock_payer.rb +142 -0
  46. data/lib/davinci_dtr_test_kit/payer_server_groups/adaptive_form_libraries_test.rb +19 -0
  47. data/lib/davinci_dtr_test_kit/payer_server_groups/adaptive_form_questionnaire_expressions_test.rb +20 -0
  48. data/lib/davinci_dtr_test_kit/payer_server_groups/adaptive_form_questionnaire_extensions_test.rb +19 -0
  49. data/lib/davinci_dtr_test_kit/payer_server_groups/adaptive_next_questionnaire_expressions_test.rb +20 -0
  50. data/lib/davinci_dtr_test_kit/payer_server_groups/adaptive_next_questionnaire_extensions_test.rb +19 -0
  51. data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_adaptive_group.rb +88 -0
  52. data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_adaptive_request_test.rb +41 -0
  53. data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_adaptive_request_validation_test.rb +44 -0
  54. data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_adaptive_response_bundles_validation_test.rb +40 -0
  55. data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_adaptive_response_search_validation_test.rb +42 -0
  56. data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_adaptive_response_validation_test.rb +49 -0
  57. data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_next_request_validation_test.rb +61 -0
  58. data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_next_response_complete_test.rb +17 -0
  59. data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_next_response_validation_test.rb +43 -0
  60. data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_static_group.rb +51 -0
  61. data/lib/davinci_dtr_test_kit/payer_server_groups/static_form_libraries_test.rb +19 -0
  62. data/lib/davinci_dtr_test_kit/payer_server_groups/static_form_questionnaire_expressions_test.rb +20 -0
  63. data/lib/davinci_dtr_test_kit/payer_server_groups/static_form_questionnaire_extensions_test.rb +19 -0
  64. data/lib/davinci_dtr_test_kit/payer_server_groups/static_form_request_test.rb +33 -0
  65. data/lib/davinci_dtr_test_kit/payer_server_groups/static_form_request_validation_test.rb +46 -0
  66. data/lib/davinci_dtr_test_kit/payer_server_groups/static_form_response_validation_test.rb +50 -0
  67. data/lib/davinci_dtr_test_kit/tags.rb +8 -0
  68. data/lib/davinci_dtr_test_kit/urls.rb +50 -0
  69. data/lib/davinci_dtr_test_kit/validation_test.rb +72 -0
  70. data/lib/davinci_dtr_test_kit/version.rb +5 -0
  71. data/lib/davinci_dtr_test_kit.rb +4 -0
  72. 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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