Module: DaVinciCRDTestKit::ResponseLogicalModelValidation
Constant Summary
collapse
- CRD_LOGICAL_MODEL_BASE =
'http://hl7.org/fhir/us/davinci-crd/StructureDefinition'.freeze
- CRD_RESPONSE_BASE_LOGICAL_MODEL =
'CRDHooksResponseBase'.freeze
- CARD_TYPE_TO_LOGICAL_MODEL =
{
DaVinciCRDTestKit::CardsIdentification::ADDITIONAL_ORDERS_RESPONSE_TYPE =>
'CRDHooksResponse-additionalOrders',
DaVinciCRDTestKit::CardsIdentification::CREATE_OR_UPDATE_COVERAGE_RESPONSE_TYPE =>
'CRDHooksResponse-adjustCoverage',
DaVinciCRDTestKit::CardsIdentification::EXTERNAL_REFERENCE_RESPONSE_TYPE =>
'CRDHooksResponse-externalReference',
DaVinciCRDTestKit::CardsIdentification::FORM_COMPLETION_RESPONSE_TYPE =>
'CRDHooksResponse-formCompletion',
DaVinciCRDTestKit::CardsIdentification::INSTRUCTIONS_RESPONSE_TYPE =>
'CRDHooksResponse-instructions',
DaVinciCRDTestKit::CardsIdentification::LAUNCH_SMART_APP_RESPONSE_TYPE =>
'CRDHooksResponse-launchSMART',
DaVinciCRDTestKit::CardsIdentification::PROPOSE_ALTERNATIVE_REQUEST_RESPONSE_TYPE =>
'CRDHooksResponse-alternateRequest'
}.freeze
- ACTION_TYPE_TO_LOGICAL_MODEL =
{
DaVinciCRDTestKit::CardsIdentification::COVERAGE_INFORMATION_RESPONSE_TYPE =>
'CRDHooksResponse-coverageInformation',
DaVinciCRDTestKit::CardsIdentification::CREATE_OR_UPDATE_COVERAGE_RESPONSE_TYPE =>
'CRDHooksResponse-adjustCoverage',
DaVinciCRDTestKit::CardsIdentification::FORM_COMPLETION_RESPONSE_TYPE =>
'CRDHooksResponse-formCompletion'
}.freeze
CardsIdentification::ADDITIONAL_ORDERS_EXPECTED_RESOURCE_TYPES, CardsIdentification::ADDITIONAL_ORDERS_RESPONSE_TYPE, CardsIdentification::COVERAGE_INFORMATION_RESPONSE_TYPE, CardsIdentification::COVERAGE_INFO_CONFIGURATION_CODE, CardsIdentification::COVERAGE_INFO_EXPECTED_RESOURCE_TYPES, CardsIdentification::COVERAGE_INFO_EXT_URL, CardsIdentification::CREATE_OR_UPDATE_COVERAGE_RESPONSE_TYPE, CardsIdentification::EXTERNAL_REFERENCE_RESPONSE_TYPE, CardsIdentification::FORM_COMPLETION_RESPONSE_TYPE, CardsIdentification::INSTRUCTIONS_RESPONSE_TYPE, CardsIdentification::LAUNCH_SMART_APP_RESPONSE_TYPE, CardsIdentification::PROPOSE_ALTERNATIVE_REQUEST_EXPECTED_RESOURCE_TYPES, CardsIdentification::PROPOSE_ALTERNATIVE_REQUEST_RESPONSE_TYPE
ProfilesAndResourceTypes::ORDER_OR_ENCOUNTER_RESOURCE_CLASSES, ProfilesAndResourceTypes::ORDER_RESOURCE_CLASSES, ProfilesAndResourceTypes::ORDER_RESOURCE_TYPES
DaVinciCRDTestKit::RequestsLogicalModelValidation::CRD_CDS_HOOK_REQUEST_MODEL_URL, DaVinciCRDTestKit::RequestsLogicalModelValidation::PERFORMER_ALLOWED_RESOURCE_TYPES, DaVinciCRDTestKit::RequestsLogicalModelValidation::USER_ID_ALLOWED_RESOURCE_TYPES
Instance Method Summary
collapse
-
#add_messages_not_excluded(issues, error_prefix) ⇒ Object
-
#check_action_target(action, request_body, error_prefix, ig_semver) ⇒ Object
-
#check_questionnaire_actions(card, error_message, error_prefix) ⇒ Object
-
#check_required_action_type(action, required_type, error_prefix, description) ⇒ Object
-
#logical_model_entity_label(response_index, entity_index, kind) ⇒ Object
-
#logical_model_extension_issue?(issue) ⇒ Boolean
————————————————————————- Validator Filtering and Manual Checks Depending on the Card Type ————————————————————————-.
-
#logical_model_url(profile_name) ⇒ Object
-
#manually_check_action_resources_for_order_profile_conformance(card, validation_issues, request_body, error_prefix, ig_semver) ⇒ Object
-
#manually_check_action_specific_errors(action, validation_issues, action_type, request_body, error_prefix, ig_semver) ⇒ Object
-
#manually_check_additional_orders_errors(card, validation_issues, request_body, error_prefix, ig_semver) ⇒ Object
-
#manually_check_card_specific_errors(card, validation_issues, card_type, request_body, error_prefix, ig_semver) ⇒ Object
-
#manually_check_coverage_information_errors(action, validation_issues, request_body, error_prefix, ig_semver) ⇒ Object
-
#manually_check_form_completion_action_errors(action, validation_issues, error_prefix, ig_semver) ⇒ Object
-
#manually_check_form_completion_errors(card, validation_issues, error_prefix) ⇒ Object
-
#manually_check_propose_alternative_errors(card, validation_issues, request_body, error_prefix, ig_semver) ⇒ Object
-
#manually_check_update_coverage_action_errors(action, validation_issues, error_prefix, ig_semver) ⇒ Object
-
#perform_response_logical_model_validation(cards, system_actions, request_body, response_index, ig_semver) ⇒ Object
-
#validate_card_against_logical_model(card, response_index, request_body, card_index, ig_semver) ⇒ Object
-
#validate_system_action_against_logical_model(action, response_index, request_body, action_index, ig_semver) ⇒ Object
#allowed_resource_type?, #check_appointment_conformance, #check_order_like_resource_conformance, #check_resource_conformance_to_coverage_profile, #check_resource_conformance_to_order_or_encounter_profile, #check_resource_conformance_to_order_profile, #check_resource_conformance_to_questionnaire_task_profile, #check_resource_type_and_validate, #local_reference?, #manually_check_appointment_validation_errors, #parse_action_resource, #primary_performer_type?, #referenced_resource_present_in_bundle?, #reject_resource_issues, #resolved_participant_patient_slice_issue?, #resolved_participant_primary_performer_slice_issue?
#additional_orders_response_type?, #cache_sorted_cards, #check_action_type, #coverage_info_card_type?, #coverage_info_configuration_disabled?, #coverage_info_content, #coverage_info_response?, #coverage_info_system_action_type?, #coverage_information_response_type?, #create_or_update_coverage_action_response_type?, #create_or_update_coverage_card_response_type?, #create_questionnaire_action_response_type?, #disable_coverage_info_configuration!, #extension_url, #external_reference_response_type?, #extract_coverage_information_extensions, #form_completion_action_response_type?, #form_completion_card_response_type?, #form_completion_task_questionnaire?, #hook_instances_from_requests, #identify_action_type, #identify_card_type, #initialize_sorted_cards_hash, #instructions_response_type?, #launch_smart_app_response_type?, #list_card_types_in_requests, #propose_alternative_request_response_type?, #sort_card_types_from_request, #sorted_cards_cached?, #sorted_cards_from_cache, #sorted_cards_from_requests
#hook_request_context_check, #hook_request_optional_fields_check, #hook_request_prefetch_check, #hook_request_required_fields_check, #json_parse, #no_error_validation
#structure_definition_map, #structure_definition_map_v201, #structure_definition_map_v221
#client_fhir_base_url, #fhir_url, #instance_url, #search_url
Methods included from BaseURLs
#inferno_base_url, #resume_fail_url, #resume_pass_url
#validate_request_against_logical_model
#action_fields_validation, #action_resource_type_check, #actions_check
Instance Method Details
#add_messages_not_excluded(issues, error_prefix) ⇒ Object
113
114
115
116
117
118
119
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 113
def add_messages_not_excluded(issues, error_prefix)
issues.each do |issue|
next if issue.filtered || logical_model_extension_issue?(issue)
add_message(issue.severity, "#{error_prefix}#{issue.message}")
end
end
|
#check_action_target(action, request_body, error_prefix, ig_semver) ⇒ Object
234
235
236
237
238
239
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 234
def check_action_target(action, request_body, error_prefix, ig_semver)
local_reference?(action['resourceId'], error_prefix) if action['resourceId'].present?
return unless action['resource'].present?
check_resource_conformance_to_order_profile(action['resource'], request_body, error_prefix, ig_semver)
end
|
#check_questionnaire_actions(card, error_message, error_prefix) ⇒ Object
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 177
def check_questionnaire_actions(card, error_message, error_prefix)
=
error_message.match(/CDSHooksResponse\.cards\[0\]\.suggestions\[(\d+)\]\.actions\[(\d+)\]\.resource/)
unless
raise 'Unexpected validator error message format in check_questionnaire_actions: ' \
"'#{error_message}'. This indicates an implementation problem in the test kit — please log a ticket."
end
suggestion_index = [1].to_i
action_index = [2].to_i
message_prefix = "#{error_prefix} suggestion #{suggestion_index + 1}, action #{action_index + 1} - "
resource = FHIR.from_contents(card['suggestions'][suggestion_index]['actions'][action_index]['resource'].to_json)
resource_is_valid?(resource:, message_prefix:)
return if resource.id.present?
add_message('error', "#{message_prefix}Questionnaire must have an id.")
end
|
#check_required_action_type(action, required_type, error_prefix, description) ⇒ Object
268
269
270
271
272
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 268
def check_required_action_type(action, required_type, error_prefix, description)
return if action['type'] == required_type
add_message('error', "#{error_prefix}action type must be '#{required_type}' for a #{description}.")
end
|
#logical_model_entity_label(response_index, entity_index, kind) ⇒ Object
121
122
123
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 121
def logical_model_entity_label(response_index, entity_index, kind)
"Server response #{response_index + 1}, #{kind} #{entity_index + 1}"
end
|
#logical_model_extension_issue?(issue) ⇒ Boolean
Validator Filtering and Manual Checks Depending on the Card Type
129
130
131
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 129
def logical_model_extension_issue?(issue)
issue.message.match(/\.extension: Unrecognized property/).present?
end
|
#logical_model_url(profile_name) ⇒ Object
38
39
40
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 38
def logical_model_url(profile_name)
"#{CRD_LOGICAL_MODEL_BASE}/#{profile_name}"
end
|
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 218
def manually_check_action_resources_for_order_profile_conformance(card, validation_issues, request_body,
error_prefix, ig_semver)
if card['suggestions'].present?
card['suggestions'].each_with_index do |suggestion, suggestion_index|
next unless suggestion['actions'].present?
suggestion['actions'].each_with_index do |action, action_index|
action_error_prefix = "#{error_prefix}suggestion #{suggestion_index + 1}, action #{action_index + 1} - "
check_action_target(action, request_body, action_error_prefix, ig_semver)
end
end
end
reject_resource_issues(validation_issues)
end
|
#manually_check_action_specific_errors(action, validation_issues, action_type, request_body, error_prefix, ig_semver) ⇒ Object
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 149
def manually_check_action_specific_errors(action, validation_issues, action_type, request_body,
error_prefix, ig_semver)
case action_type
when DaVinciCRDTestKit::CardsIdentification::COVERAGE_INFORMATION_RESPONSE_TYPE
manually_check_coverage_information_errors(action, validation_issues, request_body,
error_prefix, ig_semver)
when DaVinciCRDTestKit::CardsIdentification::CREATE_OR_UPDATE_COVERAGE_RESPONSE_TYPE
manually_check_update_coverage_action_errors(action, validation_issues,
error_prefix, ig_semver)
when DaVinciCRDTestKit::CardsIdentification::FORM_COMPLETION_RESPONSE_TYPE
manually_check_form_completion_action_errors(action, validation_issues,
error_prefix, ig_semver)
else
validation_issues
end
end
|
#manually_check_additional_orders_errors(card, validation_issues, request_body, error_prefix, ig_semver) ⇒ Object
209
210
211
212
213
214
215
216
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 209
def manually_check_additional_orders_errors(card, validation_issues, request_body,
error_prefix, ig_semver)
manually_check_action_resources_for_order_profile_conformance(card,
validation_issues,
request_body,
error_prefix,
ig_semver)
end
|
#manually_check_card_specific_errors(card, validation_issues, card_type, request_body, error_prefix, ig_semver) ⇒ Object
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 133
def manually_check_card_specific_errors(card, validation_issues, card_type, request_body, error_prefix,
ig_semver)
case card_type
when DaVinciCRDTestKit::CardsIdentification::FORM_COMPLETION_RESPONSE_TYPE
manually_check_form_completion_errors(card, validation_issues, error_prefix)
when DaVinciCRDTestKit::CardsIdentification::PROPOSE_ALTERNATIVE_REQUEST_RESPONSE_TYPE
manually_check_propose_alternative_errors(card, validation_issues, request_body,
error_prefix, ig_semver)
when DaVinciCRDTestKit::CardsIdentification::ADDITIONAL_ORDERS_RESPONSE_TYPE
manually_check_additional_orders_errors(card, validation_issues, request_body,
error_prefix, ig_semver)
else
validation_issues
end
end
|
241
242
243
244
245
246
247
248
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 241
def manually_check_coverage_information_errors(action, validation_issues, request_body,
error_prefix, ig_semver)
if action['resource'].present?
check_resource_conformance_to_order_or_encounter_profile(action['resource'], request_body,
error_prefix, ig_semver)
end
reject_resource_issues(validation_issues)
end
|
259
260
261
262
263
264
265
266
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 259
def manually_check_form_completion_action_errors(action, validation_issues,
error_prefix, ig_semver)
check_required_action_type(action, 'create', error_prefix, 'form completion action response type')
if action['resource'].present?
check_resource_conformance_to_questionnaire_task_profile(action['resource'], error_prefix, ig_semver)
end
reject_resource_issues(validation_issues)
end
|
166
167
168
169
170
171
172
173
174
175
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 166
def manually_check_form_completion_errors(card, validation_issues, error_prefix)
validation_issues.reject do |issue|
if issue.message.match?(/The type 'Questionnaire' is not valid - must be Task/)
check_questionnaire_actions(card, issue.message, error_prefix)
true
else
false
end
end
end
|
#manually_check_propose_alternative_errors(card, validation_issues, request_body, error_prefix, ig_semver) ⇒ Object
197
198
199
200
201
202
203
204
205
206
207
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 197
def manually_check_propose_alternative_errors(card, validation_issues, request_body,
error_prefix, ig_semver)
no_resource_issues = manually_check_action_resources_for_order_profile_conformance(card,
validation_issues,
request_body,
error_prefix,
ig_semver)
no_resource_issues.reject do |issue|
issue.message.match?(/but is fixed to 'create' in the profile/)
end
end
|
#manually_check_update_coverage_action_errors(action, validation_issues, error_prefix, ig_semver) ⇒ Object
250
251
252
253
254
255
256
257
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 250
def manually_check_update_coverage_action_errors(action, validation_issues,
error_prefix, ig_semver)
check_required_action_type(action, 'update', error_prefix, 'coverage update action response type')
if action['resource'].present?
check_resource_conformance_to_coverage_profile(action['resource'], error_prefix, ig_semver)
end
reject_resource_issues(validation_issues)
end
|
42
43
44
45
46
47
48
49
50
51
52
53
54
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 42
def perform_response_logical_model_validation(cards, system_actions, request_body, response_index, ig_semver)
if cards.is_a?(Array)
cards.each_with_index do |card, card_index|
validate_card_against_logical_model(card, response_index, request_body, card_index, ig_semver)
end
end
return unless system_actions.is_a?(Array)
system_actions.each_with_index do |action, action_index|
validate_system_action_against_logical_model(action, response_index, request_body, action_index, ig_semver)
end
end
|
#validate_card_against_logical_model(card, response_index, request_body, card_index, ig_semver) ⇒ Object
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 56
def validate_card_against_logical_model(card, response_index, request_body, card_index, ig_semver)
label = logical_model_entity_label(response_index, card_index, 'card')
unless card.is_a?(Hash)
add_message('error', "#{label} is not a JSON object; skipping logical model validation.")
return
end
card_type = identify_card_type(card)
profile_name = CARD_TYPE_TO_LOGICAL_MODEL[card_type]
unless profile_name
add_message('warning',
"#{label} could not be categorized as a known CRD response type; " \
'validating against the base CRD response logical model.')
profile_name = CRD_RESPONSE_BASE_LOGICAL_MODEL
end
validation_issues = []
conforms_to_logical_model?({ 'cards' => [card] }, logical_model_url(profile_name),
add_messages_to_runnable: false, validator_response_details: validation_issues)
error_prefix = "#{label} (#{card_type || 'uncategorized'}): "
filtered_issues = manually_check_card_specific_errors(card, validation_issues, card_type,
request_body, error_prefix, ig_semver)
add_messages_not_excluded(filtered_issues, error_prefix)
end
|
#validate_system_action_against_logical_model(action, response_index, request_body, action_index, ig_semver) ⇒ Object
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 82
def validate_system_action_against_logical_model(action, response_index, request_body, action_index, ig_semver)
label = logical_model_entity_label(response_index, action_index, 'systemAction')
unless action.is_a?(Hash)
add_message('error', "#{label} is not a JSON object; skipping logical model validation.")
return
end
action_type = identify_action_type(action)
profile_name = ACTION_TYPE_TO_LOGICAL_MODEL[action_type]
unless profile_name
add_message('warning',
"#{label} could not be categorized as a known CRD response type; " \
'validating against the base CRD response logical model.')
profile_name = CRD_RESPONSE_BASE_LOGICAL_MODEL
end
if [DaVinciCRDTestKit::CardsIdentification::CREATE_OR_UPDATE_COVERAGE_RESPONSE_TYPE,
DaVinciCRDTestKit::CardsIdentification::FORM_COMPLETION_RESPONSE_TYPE]
.include?(action_type)
profile_name = CRD_RESPONSE_BASE_LOGICAL_MODEL
end
validation_issues = []
conforms_to_logical_model?({ 'systemActions' => [action] }, logical_model_url(profile_name),
add_messages_to_runnable: false, validator_response_details: validation_issues)
error_prefix = "#{label} (#{action_type || 'uncategorized'}): "
filtered_issues = manually_check_action_specific_errors(action, validation_issues, action_type,
request_body, error_prefix, ig_semver)
add_messages_not_excluded(filtered_issues, error_prefix)
end
|