davinci_dtr_test_kit 0.16.0 → 0.16.2

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 (88) hide show
  1. checksums.yaml +4 -4
  2. data/config/presets/full_ehr_postman_dinner_order_example.json.erb +41 -0
  3. data/config/presets/full_ehr_postman_respiratory_device_example.json +1 -1
  4. data/config/presets/smart_app_postman_dinner_order_example.json +8 -1
  5. data/config/presets/smart_app_postman_respiratory_device_example.json +1 -1
  6. data/lib/davinci_dtr_test_kit/certs/InfernoCA.key +52 -0
  7. data/lib/davinci_dtr_test_kit/certs/InfernoCA.pem +35 -0
  8. data/lib/davinci_dtr_test_kit/certs/TestKit.pem +32 -0
  9. data/lib/davinci_dtr_test_kit/certs/TestKitPrivateKey.key +28 -0
  10. data/lib/davinci_dtr_test_kit/client_groups/adaptive_questionnaire/custom/dtr_custom_next_question_response_validation_test.rb +95 -0
  11. data/lib/davinci_dtr_test_kit/client_groups/adaptive_questionnaire/custom/dtr_full_ehr_custom_adaptive_request_test.rb +87 -0
  12. data/lib/davinci_dtr_test_kit/client_groups/adaptive_questionnaire/custom/dtr_full_ehr_custom_adaptive_workflow_group.rb +136 -0
  13. data/lib/davinci_dtr_test_kit/client_groups/adaptive_questionnaire/custom/dtr_smart_app_custom_adaptive_request_test.rb +171 -0
  14. data/lib/davinci_dtr_test_kit/client_groups/adaptive_questionnaire/custom/dtr_smart_app_custom_adaptive_workflow_group.rb +146 -0
  15. data/lib/davinci_dtr_test_kit/client_groups/{dinner_adaptive → adaptive_questionnaire/dinner_order}/dtr_adaptive_next_question_retrieval_group.rb +3 -3
  16. data/lib/davinci_dtr_test_kit/client_groups/{dinner_adaptive → adaptive_questionnaire/dinner_order}/dtr_full_ehr_adaptive_dinner_workflow_group.rb +21 -11
  17. data/lib/davinci_dtr_test_kit/client_groups/{dinner_adaptive → adaptive_questionnaire/dinner_order}/dtr_full_ehr_adaptive_initial_retrieval_group.rb +6 -6
  18. data/lib/davinci_dtr_test_kit/client_groups/{dinner_adaptive → adaptive_questionnaire/dinner_order}/dtr_smart_app_adaptive_dinner_workflow_group.rb +5 -5
  19. data/lib/davinci_dtr_test_kit/client_groups/{dinner_adaptive → adaptive_questionnaire/dinner_order}/dtr_smart_app_adaptive_initial_retrieval_group.rb +5 -5
  20. data/lib/davinci_dtr_test_kit/client_groups/{dinner_adaptive → adaptive_questionnaire}/dtr_adaptive_next_question_request_test.rb +10 -25
  21. data/lib/davinci_dtr_test_kit/client_groups/{dinner_adaptive → adaptive_questionnaire}/dtr_adaptive_next_question_request_validation_test.rb +37 -18
  22. data/lib/davinci_dtr_test_kit/client_groups/adaptive_questionnaire/dtr_adaptive_response_validation_test.rb +130 -0
  23. data/lib/davinci_dtr_test_kit/client_groups/auth/dtr_client_payer_auth_smart_group.rb +29 -0
  24. data/lib/davinci_dtr_test_kit/client_groups/auth/dtr_client_payer_auth_udap_group.rb +29 -0
  25. data/lib/davinci_dtr_test_kit/client_groups/custom_static/dtr_full_ehr_custom_static_workflow_group.rb +15 -14
  26. data/lib/davinci_dtr_test_kit/client_groups/custom_static/dtr_smart_app_custom_static_workflow_group.rb +5 -5
  27. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_full_ehr_static_dinner_workflow_group.rb +14 -10
  28. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_smart_app_static_dinner_workflow_group.rb +1 -1
  29. data/lib/davinci_dtr_test_kit/client_groups/{dinner_adaptive → full_ehr}/dtr_full_ehr_adaptive_request_test.rb +13 -16
  30. data/lib/davinci_dtr_test_kit/client_groups/full_ehr/dtr_full_ehr_questionnaire_package_request_test.rb +10 -18
  31. data/lib/davinci_dtr_test_kit/client_groups/full_ehr/dtr_full_ehr_questionnaire_response_correctness_test.rb +10 -1
  32. data/lib/davinci_dtr_test_kit/client_groups/full_ehr/dtr_full_ehr_store_attestation_test.rb +3 -3
  33. data/lib/davinci_dtr_test_kit/client_groups/light_ehr/fhir_context_references_test.rb +4 -5
  34. data/lib/davinci_dtr_test_kit/client_groups/must_support/dtr_full_ehr_ms_questionnaire_package_request_test.rb +75 -0
  35. data/lib/davinci_dtr_test_kit/client_groups/must_support/dtr_full_ehr_questionnaire_must_support_group.rb +85 -0
  36. data/lib/davinci_dtr_test_kit/client_groups/must_support/dtr_must_support_attestation_test.rb +39 -0
  37. data/lib/davinci_dtr_test_kit/client_groups/must_support/dtr_questionnaire_must_support_test.rb +42 -0
  38. data/lib/davinci_dtr_test_kit/client_groups/must_support/dtr_smart_app_ms_questionnaire_package_request_test.rb +148 -0
  39. data/lib/davinci_dtr_test_kit/client_groups/must_support/dtr_smart_app_questionnaire_must_support_group.rb +85 -0
  40. data/lib/davinci_dtr_test_kit/client_groups/must_support/questionnaire_must_support_elements.rb +55 -0
  41. data/lib/davinci_dtr_test_kit/client_groups/payer_registration/configuration_display_smart_test.rb +35 -0
  42. data/lib/davinci_dtr_test_kit/client_groups/payer_registration/configuration_display_udap_test.rb +35 -0
  43. data/lib/davinci_dtr_test_kit/client_groups/payer_registration/dtr_client_registration_group.rb +48 -0
  44. data/lib/davinci_dtr_test_kit/client_groups/shared/dtr_custom_questionnaire_expressions_test.rb +36 -0
  45. data/lib/davinci_dtr_test_kit/client_groups/shared/dtr_custom_questionnaire_extensions_test.rb +32 -0
  46. data/lib/davinci_dtr_test_kit/client_groups/{custom_static → shared}/dtr_custom_questionnaire_libraries_test.rb +7 -2
  47. data/lib/davinci_dtr_test_kit/client_groups/{custom_static → shared}/dtr_custom_questionnaire_package_validation_test.rb +6 -2
  48. data/lib/davinci_dtr_test_kit/client_groups/shared/dtr_questionnaire_package_request_validation_test.rb +6 -2
  49. data/lib/davinci_dtr_test_kit/client_groups/shared/dtr_questionnaire_response_prepopulation_test.rb +7 -1
  50. data/lib/davinci_dtr_test_kit/client_groups/smart_app/dtr_smart_app_questionnaire_response_correctness_test.rb +4 -3
  51. data/lib/davinci_dtr_test_kit/descriptions.rb +8 -0
  52. data/lib/davinci_dtr_test_kit/docs/dtr_full_ehr_suite_description_v201.md +145 -78
  53. data/lib/davinci_dtr_test_kit/docs/dtr_smart_app_suite_description_v201.md +4 -3
  54. data/lib/davinci_dtr_test_kit/dtr_client_options.rb +13 -0
  55. data/lib/davinci_dtr_test_kit/dtr_full_ehr_suite.rb +55 -7
  56. data/lib/davinci_dtr_test_kit/dtr_light_ehr_suite.rb +8 -0
  57. data/lib/davinci_dtr_test_kit/dtr_payer_server_suite.rb +8 -0
  58. data/lib/davinci_dtr_test_kit/dtr_questionnaire_response_validation.rb +33 -21
  59. data/lib/davinci_dtr_test_kit/dtr_smart_app_suite.rb +15 -4
  60. data/lib/davinci_dtr_test_kit/endpoints/mock_ehr.rb +1 -1
  61. data/lib/davinci_dtr_test_kit/endpoints/mock_payer/full_ehr_next_question_endpoint.rb +20 -1
  62. data/lib/davinci_dtr_test_kit/endpoints/mock_payer/full_ehr_questionnaire_package_endpoint.rb +21 -1
  63. data/lib/davinci_dtr_test_kit/endpoints/mock_payer/next_question_endpoint.rb +29 -4
  64. data/lib/davinci_dtr_test_kit/endpoints/mock_payer/questionnaire_package_endpoint.rb +1 -1
  65. data/lib/davinci_dtr_test_kit/endpoints/mock_udap_smart_server/token_endpoint.rb +36 -0
  66. data/lib/davinci_dtr_test_kit/requirements/{davinci-dtr-test-kit_requirements.csv → davinci_dtr_test_kit_requirements.csv} +375 -357
  67. data/lib/davinci_dtr_test_kit/requirements/generated/dtr_full_ehr_requirements_coverage.csv +140 -0
  68. data/lib/davinci_dtr_test_kit/requirements/generated/dtr_light_ehr_requirements_coverage.csv +69 -0
  69. data/lib/davinci_dtr_test_kit/requirements/generated/dtr_payer_server_requirements_coverage.csv +147 -0
  70. data/lib/davinci_dtr_test_kit/requirements/generated/dtr_smart_app_requirements_coverage.csv +214 -0
  71. data/lib/davinci_dtr_test_kit/requirements/hl7.fhir.us.davinci-dtr_2.0.1_requirements.xlsx +0 -0
  72. data/lib/davinci_dtr_test_kit/urls.rb +21 -4
  73. data/lib/davinci_dtr_test_kit/version.rb +2 -2
  74. data/lib/davinci_dtr_test_kit.rb +0 -1
  75. metadata +67 -30
  76. data/config/presets/full_ehr_postman_dinner_order_example_postman.json +0 -19
  77. data/lib/davinci_dtr_test_kit/client_groups/custom_static/dtr_custom_questionnaire_expressions_test.rb +0 -22
  78. data/lib/davinci_dtr_test_kit/client_groups/custom_static/dtr_custom_questionnaire_extensions_test.rb +0 -19
  79. data/lib/davinci_dtr_test_kit/client_groups/dinner_adaptive/dtr_adaptive_response_validation_test.rb +0 -68
  80. data/lib/davinci_dtr_test_kit/requirements/davinci-dtr-test-kit_out_of_scope_requirements.csv +0 -13
  81. data/lib/davinci_dtr_test_kit/requirements/generated/davinci-dtr-test-kit_requirements_coverage.csv +0 -372
  82. data/lib/inferno_requirements_tools/ext/inferno_core/runnable.rb +0 -22
  83. data/lib/inferno_requirements_tools/rake/rakefile_template +0 -31
  84. data/lib/inferno_requirements_tools/tasks/requirements_coverage.rb +0 -284
  85. data/lib/requirements_config.yaml +0 -25
  86. /data/lib/davinci_dtr_test_kit/client_groups/{dinner_adaptive → adaptive_questionnaire/dinner_order}/dtr_adaptive_completion_group.rb +0 -0
  87. /data/lib/davinci_dtr_test_kit/client_groups/{dinner_adaptive → adaptive_questionnaire/dinner_order}/dtr_adaptive_followup_questions_group.rb +0 -0
  88. /data/lib/davinci_dtr_test_kit/client_groups/{dinner_adaptive → smart_app}/dtr_smart_app_adaptive_request_test.rb +0 -0
@@ -1,12 +1,19 @@
1
+ require 'udap_security_test_kit'
2
+ require 'smart_app_launch_test_kit'
1
3
  require_relative 'client_groups/custom_static/dtr_full_ehr_custom_static_workflow_group'
2
4
  require_relative 'client_groups/dinner_static/dtr_full_ehr_static_dinner_workflow_group'
3
- require_relative 'client_groups/dinner_adaptive/dtr_full_ehr_adaptive_dinner_workflow_group'
4
- require_relative 'auth_groups/oauth2_authentication_group'
5
+ require_relative 'client_groups/adaptive_questionnaire/dinner_order/dtr_full_ehr_adaptive_dinner_workflow_group'
6
+ require_relative 'client_groups/adaptive_questionnaire/custom/dtr_full_ehr_custom_adaptive_workflow_group'
7
+ require_relative 'client_groups/payer_registration/dtr_client_registration_group'
8
+ require_relative 'client_groups/must_support/dtr_full_ehr_questionnaire_must_support_group'
9
+ require_relative 'client_groups/auth/dtr_client_payer_auth_smart_group'
10
+ require_relative 'client_groups/auth/dtr_client_payer_auth_udap_group'
5
11
  require_relative 'endpoints/cors'
6
- require_relative 'endpoints/mock_authorization/simple_token_endpoint'
12
+ require_relative 'endpoints/mock_udap_smart_server/token_endpoint'
7
13
  require_relative 'endpoints/mock_payer/full_ehr_questionnaire_package_endpoint'
8
14
  require_relative 'endpoints/mock_payer/full_ehr_next_question_endpoint'
9
15
  require_relative 'version'
16
+ require_relative 'dtr_client_options'
10
17
 
11
18
  module DaVinciDTRTestKit
12
19
  class DTRFullEHRSuite < Inferno::TestSuite
@@ -35,9 +42,30 @@ module DaVinciDTRTestKit
35
42
  }
36
43
  ]
37
44
 
45
+ requirement_sets(
46
+ {
47
+ identifier: 'hl7.fhir.us.davinci-dtr_2.0.1',
48
+ title: 'Da Vinci Documentation Templates and Rules (DTR) v2.0.1',
49
+ actor: 'Full EHR'
50
+ }
51
+ )
52
+
53
+ suite_option :client_type,
54
+ title: 'Client Security Type',
55
+ list_options: [
56
+ {
57
+ label: 'SMART Backend Services',
58
+ value: DTRClientOptions::SMART_BACKEND_SERVICES_CONFIDENTIAL_ASYMMETRIC
59
+ },
60
+ {
61
+ label: 'UDAP B2B Client Credentials',
62
+ value: DTRClientOptions::UDAP_CLIENT_CREDENTIALS
63
+ }
64
+ ]
65
+
38
66
  # Hl7 Validator Wrapper:
39
67
  fhir_resource_validator do
40
- igs 'hl7.fhir.us.davinci-dtr#2.0.1'
68
+ igs 'igs/davinci_dtr_2.0.1.tgz'
41
69
 
42
70
  exclude_message do |message|
43
71
  message.message.match?(/\A\S+: \S+: URL value '.*' does not resolve/)
@@ -46,7 +74,16 @@ module DaVinciDTRTestKit
46
74
 
47
75
  allow_cors QUESTIONNAIRE_PACKAGE_PATH, NEXT_PATH
48
76
 
49
- suite_endpoint :post, PAYER_TOKEN_PATH, MockAuthorization::SimpleTokenEndpoint
77
+ route(:get, UDAPSecurityTestKit::UDAP_DISCOVERY_PATH, lambda { |_env|
78
+ UDAPSecurityTestKit::MockUDAPServer.udap_server_metadata(id)
79
+ })
80
+ route(:get, SMARTAppLaunch::SMART_DISCOVERY_PATH, lambda { |_env|
81
+ SMARTAppLaunch::MockSMARTServer.smart_server_metadata(id)
82
+ })
83
+
84
+ suite_endpoint :post, UDAPSecurityTestKit::REGISTRATION_PATH,
85
+ UDAPSecurityTestKit::MockUDAPServer::RegistrationEndpoint
86
+ suite_endpoint :post, UDAPSecurityTestKit::TOKEN_PATH, MockUdapSmartServer::TokenEndpoint
50
87
 
51
88
  suite_endpoint :post, QUESTIONNAIRE_PACKAGE_PATH, MockPayer::FullEHRQuestionnairePackageEndpoint
52
89
  suite_endpoint :post, NEXT_PATH, MockPayer::FullEHRNextQuestionEndpoint
@@ -59,13 +96,13 @@ module DaVinciDTRTestKit
59
96
  request.query_parameters['token']
60
97
  end
61
98
 
62
- group from: :oauth2_authentication
99
+ group from: :dtr_client_payer_registration
63
100
  group do
64
101
  id :dtr_full_ehr_basic_workflows
65
102
  title 'Basic Workflows'
66
103
 
67
104
  group from: :dtr_full_ehr_custom_static_workflow
68
- group from: :dtr_full_ehr_adaptive_dinner_workflow
105
+ group from: :dtr_full_ehr_custom_adaptive_workflow
69
106
  end
70
107
  group do
71
108
  id :dtr_full_ehr_questionnaire_functionality
@@ -75,6 +112,17 @@ module DaVinciDTRTestKit
75
112
  covering additional pre-population features of questionnaires.
76
113
  )
77
114
  group from: :dtr_full_ehr_static_dinner_workflow
115
+ group from: :dtr_full_ehr_adaptive_dinner_workflow
78
116
  end
117
+ group from: :dtr_full_ehr_questionnaire_ms
118
+
119
+ group from: :dtr_client_payer_auth_smart,
120
+ required_suite_options: {
121
+ client_type: DTRClientOptions::SMART_BACKEND_SERVICES_CONFIDENTIAL_ASYMMETRIC
122
+ }
123
+ group from: :dtr_client_payer_auth_udap,
124
+ required_suite_options: {
125
+ client_type: DTRClientOptions::UDAP_CLIENT_CREDENTIALS
126
+ }
79
127
  end
80
128
  end
@@ -43,6 +43,14 @@ module DaVinciDTRTestKit
43
43
  }
44
44
  ]
45
45
 
46
+ requirement_sets(
47
+ {
48
+ identifier: 'hl7.fhir.us.davinci-dtr_2.0.1',
49
+ title: 'Da Vinci Documentation Templates and Rules (DTR) v2.0.1',
50
+ actor: 'Light EHR'
51
+ }
52
+ )
53
+
46
54
  # Hl7 Validator Wrapper:
47
55
  fhir_resource_validator do
48
56
  igs('hl7.fhir.us.davinci-dtr#2.0.1', 'hl7.fhir.us.davinci-pas#2.0.1', 'hl7.fhir.us.davinci-crd#2.0.1')
@@ -34,6 +34,14 @@ module DaVinciDTRTestKit
34
34
  }
35
35
  ]
36
36
 
37
+ requirement_sets(
38
+ {
39
+ identifier: 'hl7.fhir.us.davinci-dtr_2.0.1',
40
+ title: 'Da Vinci Documentation Templates and Rules (DTR) v2.0.1',
41
+ actor: 'Payer Service'
42
+ }
43
+ )
44
+
37
45
  # These inputs will be available to all tests in this suite
38
46
 
39
47
  input :retrieval_method,
@@ -29,14 +29,7 @@ module DaVinciDTRTestKit
29
29
  "Couldn't find Questionnaire #{qr.questionnaire} in the provided custom questionnaire package
30
30
  to validate the QuestionnaireResponse."
31
31
 
32
- missing_origin_sources = ['auto', 'manual', 'override'] - extract_origin_sources(qr.item)
33
- unless missing_origin_sources.empty?
34
- add_message(
35
- 'error',
36
- 'All origin sources (auto, manual, override) must be present in the QuestionnaireResponse. ' \
37
- "Missing #{missing_origin_sources.to_sentence}"
38
- )
39
- end
32
+ check_missing_origin_sources(qr)
40
33
  end
41
34
 
42
35
  check_origin_sources(questionnaire.item, qr.item, expected_overrides:)
@@ -46,6 +39,18 @@ module DaVinciDTRTestKit
46
39
  assert(messages.none? { |m| m[:type] == 'error' }, 'QuestionnaireResponse is not correct, see error message(s)')
47
40
  end
48
41
 
42
+ def check_missing_origin_sources(questionnaire_response, index = nil)
43
+ missing_origin_sources = ['auto', 'manual', 'override'] - extract_origin_sources(questionnaire_response.item)
44
+ return if missing_origin_sources.empty?
45
+
46
+ prefix = index ? "Request #{index}: " : ''
47
+ add_message(
48
+ 'error',
49
+ "#{prefix}All origin sources (auto, manual, override) must be present in the QuestionnaireResponse. " \
50
+ "Missing #{missing_origin_sources.to_sentence}"
51
+ )
52
+ end
53
+
49
54
  def check_is_questionnaire_response(questionnaire_response_json)
50
55
  assert_valid_json(questionnaire_response_json)
51
56
  questionnaire_response = begin
@@ -65,9 +70,10 @@ module DaVinciDTRTestKit
65
70
  end
66
71
 
67
72
  # This only checks answers in the questionnaire response, meaning it does not catch missing answers
68
- def check_origin_sources(questionnaire_items, response_items, expected_overrides: [])
73
+ def check_origin_sources(questionnaire_items, response_items, expected_overrides: [], index: nil)
74
+ prefix = index ? "Request #{index}: " : ''
69
75
  response_items&.each do |response_item|
70
- check_origin_sources(questionnaire_items, response_item.item, expected_overrides:)
76
+ check_origin_sources(questionnaire_items, response_item.item, expected_overrides:, index:)
71
77
  next unless response_item.answer&.any?
72
78
 
73
79
  link_id = response_item.linkId
@@ -76,20 +82,25 @@ module DaVinciDTRTestKit
76
82
  is_cql_expression = item_is_cql_expression?(questionnaire_item)
77
83
 
78
84
  if origin_source.nil?
79
- add_message('error', "Required `origin.source` extension not present on answer to item `#{link_id}`")
85
+ add_message('error', "#{prefix}Required `origin.source` extension not present on answer to item `#{link_id}`")
80
86
  else
81
- check_origin_source(origin_source, link_id, is_cql_expression, override: expected_overrides.include?(link_id))
87
+ check_origin_source(
88
+ origin_source, link_id, is_cql_expression,
89
+ override: expected_overrides.include?(link_id),
90
+ index:
91
+ )
82
92
  end
83
93
  end
84
94
  end
85
95
 
86
- def check_origin_source(origin_source, link_id, is_cql_expression, override: false)
96
+ def check_origin_source(origin_source, link_id, is_cql_expression, override: false, index: nil) # rubocop:disable Metrics/CyclomaticComplexity
97
+ prefix = index ? "Request #{index}: " : ''
87
98
  if override
88
- origin_source_error(link_id, ['override'], origin_source) unless origin_source == 'override'
99
+ origin_source_error(link_id, ['override'], origin_source, prefix) unless origin_source == 'override'
89
100
  elsif is_cql_expression && !['auto', 'override'].include?(origin_source)
90
- origin_source_error(link_id, 'auto or override', origin_source)
101
+ origin_source_error(link_id, 'auto or override', origin_source, prefix)
91
102
  elsif !is_cql_expression && origin_source != 'manual'
92
- origin_source_error(link_id, 'manual', origin_source)
103
+ origin_source_error(link_id, 'manual', origin_source, prefix)
93
104
  end
94
105
  end
95
106
 
@@ -104,11 +115,13 @@ module DaVinciDTRTestKit
104
115
 
105
116
  # Ensures that all required questions have been answered.
106
117
  # If required_link_ids not provided, all questions are treated as optional.
107
- def check_answer_presence(response_items, required_link_ids = [])
118
+ def check_answer_presence(response_items, required_link_ids = [], index = nil)
119
+ prefix = index ? "Request #{index}: " : ''
120
+
108
121
  required_link_ids.each do |link_id|
109
122
  item = find_item_by_link_id(response_items, link_id)
110
123
  unless item&.answer&.any? { |answer| answer.value.present? }
111
- add_message('error', "No answer for item #{link_id}")
124
+ add_message('error', "#{prefix}No answer for item #{link_id}")
112
125
  end
113
126
  end
114
127
  end
@@ -176,7 +189,6 @@ module DaVinciDTRTestKit
176
189
  questionnaire_cql_expression_link_ids,
177
190
  expected_prepopulated = {},
178
191
  expected_overrides = {})
179
-
180
192
  questionnaire_cql_expression_link_ids.each do |target_link_id|
181
193
  target_item = find_item_by_link_id(template_questionnaire_response.item, target_link_id)
182
194
  raise "Template QuestionnaireResponse missing item with link id `#{target_link_id}`" unless target_item.present?
@@ -235,8 +247,8 @@ module DaVinciDTRTestKit
235
247
  end
236
248
  end
237
249
 
238
- def origin_source_error(link_id, expected, actual)
239
- add_message('error', %(`origin.source` extension on item `#{link_id}` contains unexpected value.
250
+ def origin_source_error(link_id, expected, actual, msg_prefix = nil)
251
+ add_message('error', %(#{msg_prefix}`origin.source` extension on item `#{link_id}` contains unexpected value.
240
252
  Expected: #{expected}. Found: #{actual}))
241
253
  end
242
254
 
@@ -1,8 +1,10 @@
1
1
  require_relative 'auth_groups/oauth2_authentication_group'
2
2
  require_relative 'client_groups/respiratory/dtr_smart_app_respiratory_workflow_group'
3
3
  require_relative 'client_groups/dinner_static/dtr_smart_app_static_dinner_workflow_group'
4
- require_relative 'client_groups/dinner_adaptive/dtr_smart_app_adaptive_dinner_workflow_group'
4
+ require_relative 'client_groups/adaptive_questionnaire/dinner_order/dtr_smart_app_adaptive_dinner_workflow_group'
5
5
  require_relative 'client_groups/custom_static/dtr_smart_app_custom_static_workflow_group'
6
+ require_relative 'client_groups/adaptive_questionnaire/custom/dtr_smart_app_custom_adaptive_workflow_group'
7
+ require_relative 'client_groups/must_support/dtr_smart_app_questionnaire_must_support_group'
6
8
  require_relative 'endpoints/cors'
7
9
  require_relative 'endpoints/mock_authorization'
8
10
  require_relative 'endpoints/mock_authorization/authorize_endpoint'
@@ -41,9 +43,17 @@ module DaVinciDTRTestKit
41
43
  }
42
44
  ]
43
45
 
46
+ requirement_sets(
47
+ {
48
+ identifier: 'hl7.fhir.us.davinci-dtr_2.0.1',
49
+ title: 'Da Vinci Documentation Templates and Rules (DTR) v2.0.1',
50
+ actor: 'SMART Client'
51
+ }
52
+ )
53
+
44
54
  # Hl7 Validator Wrapper:
45
55
  fhir_resource_validator do
46
- igs 'hl7.fhir.us.davinci-dtr#2.0.1'
56
+ igs 'igs/davinci_dtr_2.0.1.tgz'
47
57
 
48
58
  exclude_message do |message|
49
59
  message.message.match?(/\A\S+: \S+: URL value '.*' does not resolve/)
@@ -90,10 +100,9 @@ module DaVinciDTRTestKit
90
100
  )
91
101
 
92
102
  group from: :dtr_smart_app_custom_static_workflow
93
- group from: :dtr_smart_app_adaptive_dinner_workflow
103
+ group from: :dtr_smart_app_custom_adaptive_workflow
94
104
  end
95
105
  group do
96
- id :dtr_smart_app_questionnaire_functionality
97
106
  title 'Questionnaire Functionality Coverage'
98
107
  description %(
99
108
  Tests in this group validate that the client can complete additional DTR workflows
@@ -101,6 +110,8 @@ module DaVinciDTRTestKit
101
110
  )
102
111
  group from: :dtr_smart_app_resp_workflow
103
112
  group from: :dtr_smart_app_static_dinner_workflow
113
+ group from: :dtr_smart_app_adaptive_dinner_workflow
104
114
  end
115
+ group from: :dtr_smart_app_questionnaire_ms
105
116
  end
106
117
  end
@@ -21,7 +21,7 @@ module DaVinciDTRTestKit
21
21
  # Overwrite the OAuth URIs returned by the reference server to point to the suite endpoints instead
22
22
  oauth_uris_url = 'http://fhir-registry.smarthealthit.org/StructureDefinition/oauth-uris'
23
23
  base_url = MockAuthorization.env_base_url(env, METADATA_PATH)
24
- sec_ext = cs.rest.first&.security&.extension&.delete_if { |e| e.url == oauth_uris_url }
24
+ sec_ext = cs.rest.first&.security&.extension&.delete_if { |e| e.url == oauth_uris_url } # rubocop:disable Style/SafeNavigationChainLength
25
25
  sec_ext&.push(
26
26
  FHIR::Extension.new(
27
27
  url: oauth_uris_url,
@@ -4,7 +4,26 @@ module DaVinciDTRTestKit
4
4
  module MockPayer
5
5
  class FullEHRNextQuestionEndpoint < NextQuestionEndpoint
6
6
  def test_run_identifier
7
- request.headers['authorization']&.delete_prefix('Bearer ')
7
+ return request.params[:session_path] if request.params[:session_path].present?
8
+
9
+ UDAPSecurityTestKit::MockUDAPServer.issued_token_to_client_id(
10
+ request.headers['authorization']&.delete_prefix('Bearer ')
11
+ )
12
+ end
13
+
14
+ def make_response
15
+ return if response.status == 401 # set in update_result (expired token handling there)
16
+
17
+ super
18
+ end
19
+
20
+ def update_result
21
+ if UDAPSecurityTestKit::MockUDAPServer.request_has_expired_token?(request)
22
+ UDAPSecurityTestKit::MockUDAPServer.update_response_for_expired_token(response, 'Bearer token')
23
+ return
24
+ end
25
+
26
+ super
8
27
  end
9
28
  end
10
29
  end
@@ -1,10 +1,30 @@
1
+ require 'udap_security_test_kit'
1
2
  require_relative 'questionnaire_package_endpoint'
2
3
 
3
4
  module DaVinciDTRTestKit
4
5
  module MockPayer
5
6
  class FullEHRQuestionnairePackageEndpoint < QuestionnairePackageEndpoint
6
7
  def test_run_identifier
7
- request.headers['authorization']&.delete_prefix('Bearer ')
8
+ return request.params[:session_path] if request.params[:session_path].present?
9
+
10
+ UDAPSecurityTestKit::MockUDAPServer.issued_token_to_client_id(
11
+ request.headers['authorization']&.delete_prefix('Bearer ')
12
+ )
13
+ end
14
+
15
+ def make_response
16
+ return if response.status == 401 # set in update_result (expired token handling there)
17
+
18
+ super
19
+ end
20
+
21
+ def update_result
22
+ if UDAPSecurityTestKit::MockUDAPServer.request_has_expired_token?(request)
23
+ UDAPSecurityTestKit::MockUDAPServer.update_response_for_expired_token(response, 'Bearer token')
24
+ return
25
+ end
26
+
27
+ super
8
28
  end
9
29
  end
10
30
  end
@@ -22,6 +22,29 @@ module DaVinciDTRTestKit
22
22
  response.body = build_questionnaire_next_response.to_json
23
23
  end
24
24
 
25
+ def custom_next_question_requests
26
+ requests_repo.tagged_requests(test_run.test_session_id, ["custom_#{DaVinciDTRTestKit::CLIENT_NEXT_TAG}"])
27
+ end
28
+
29
+ def custom_questionnaires
30
+ return @custom_questionnaires unless @custom_questionnaires.nil?
31
+
32
+ questionnaires = JSON.parse(result.input_json)
33
+ .find { |input| input['name'].include?('custom_next_question_questionnaires') }
34
+ &.dig('value')
35
+ return unless questionnaires
36
+
37
+ @custom_questionnaires = [JSON.parse(questionnaires)].flatten.compact
38
+ end
39
+
40
+ def next_custom_questionnaire
41
+ custom_questionnaires[custom_next_question_requests.length]
42
+ end
43
+
44
+ def complete_questionnaire?
45
+ custom_questionnaires && next_custom_questionnaire.blank?
46
+ end
47
+
25
48
  def update_result
26
49
  results_repo.update_result(result.id, 'pass') unless test.config.options[:accepts_multiple_requests]
27
50
  end
@@ -41,9 +64,9 @@ module DaVinciDTRTestKit
41
64
 
42
65
  questionnaire_response_param = FHIR::Parameters::Parameter.new(name: 'return', resource: questionnaire_response)
43
66
 
44
- if questionnaire_last_dinner_order_question_present?(questionnaire_response)
67
+ if complete_questionnaire? || questionnaire_last_dinner_order_question_present?(questionnaire_response)
45
68
  # change the questionnaire response status to completed and return the parameters
46
- return handle_last_dinner_order(questionnaire_response)
69
+ return complete_questionnaire(questionnaire_response)
47
70
  end
48
71
 
49
72
  next_questionnaire = determine_next_questionnaire(questionnaire_response, test.id)
@@ -103,15 +126,17 @@ module DaVinciDTRTestKit
103
126
  end
104
127
 
105
128
  def determine_next_questionnaire(questionnaire_response, test_id)
129
+ if custom_questionnaires
130
+ FHIR.from_contents(next_custom_questionnaire.to_json)
106
131
  # Retrieve the selected option from the response and determine the next set of questions
107
- if questionnaire_dinner_order_selection_present?(questionnaire_response)
132
+ elsif questionnaire_dinner_order_selection_present?(questionnaire_response)
108
133
  dinner_question_from_selection(questionnaire_response, test_id)
109
134
  else
110
135
  Fixtures.next_question_for_test(test_id)
111
136
  end
112
137
  end
113
138
 
114
- def handle_last_dinner_order(questionnaire_response)
139
+ def complete_questionnaire(questionnaire_response)
115
140
  update_questionnaire_response(questionnaire_response)
116
141
  questionnaire_response
117
142
  end
@@ -12,7 +12,7 @@ module DaVinciDTRTestKit
12
12
  end
13
13
 
14
14
  def tags
15
- [QUESTIONNAIRE_PACKAGE_TAG]
15
+ [test.config.options[:questionnaire_package_tag].presence || QUESTIONNAIRE_PACKAGE_TAG]
16
16
  end
17
17
 
18
18
  def make_response
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'udap_security_test_kit'
4
+ require 'smart_app_launch_test_kit'
5
+ require_relative '../../urls'
6
+ require_relative '../../tags'
7
+
8
+ module DaVinciDTRTestKit
9
+ module MockUdapSmartServer
10
+ class TokenEndpoint < Inferno::DSL::SuiteEndpoint
11
+ include SMARTAppLaunch::MockSMARTServer::SMARTTokenResponseCreation
12
+ include UDAPSecurityTestKit::MockUDAPServer::UDAPTokenResponseCreation
13
+
14
+ def test_run_identifier
15
+ UDAPSecurityTestKit::MockUDAPServer.client_id_from_client_assertion(request.params[:client_assertion])
16
+ end
17
+
18
+ def make_response
19
+ if request.params[:udap].present?
20
+ make_udap_client_credential_token_response
21
+ else
22
+ make_smart_client_credential_token_response
23
+ end
24
+ end
25
+
26
+ def update_result
27
+ nil # never update for now
28
+ end
29
+
30
+ def tags
31
+ type_tag = request.params[:udap].present? ? UDAPSecurityTestKit::UDAP_TAG : SMARTAppLaunch::SMART_TAG
32
+ [UDAPSecurityTestKit::TOKEN_TAG, UDAPSecurityTestKit::CLIENT_CREDENTIALS_TAG, type_tag]
33
+ end
34
+ end
35
+ end
36
+ end