Module: DaVinciCRDTestKit::ResponseLogicalModelValidation
- Includes:
- CardsIdentification, LogicalModelsOverrideHelper
- Included in:
- V221::AdditionalOrdersValidationTest, V221::CoverageInformationSystemActionValidationTest, V221::CreateOrUpdateCoverageInfoResponseValidationTest, V221::ExternalReferenceCardValidationTest, V221::FormCompletionResponseValidationTest, V221::InfernoResponseValidationTest, V221::InstructionsCardReceivedTest, V221::LaunchSmartAppCardValidationTest, V221::ProposeAlternateRequestCardValidationTest, V221::ServiceResponseValidationTest
- Defined in:
- lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb
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, validator: :default) ⇒ Object
-
#check_multiple_coverage_info_extension_conformance(action) ⇒ Object
-
#check_questionnaire_actions(card, error_message, error_prefix, validator: :default) ⇒ Object
-
#check_required_action_type(action, required_type, error_prefix, description) ⇒ Object
-
#collect_extensions_id(extensions, url, *properties) ⇒ Object
-
#different_coverage_conformance_error_msg(resource_ref, id_name) ⇒ Object
-
#extract_and_group_coverage_info(resource) ⇒ Object
-
#find_extension_value(extension, url, *properties) ⇒ Object
-
#logical_model_entity_label(response_index, entity_index, kind) ⇒ Object
-
#logical_model_url(profile_name) ⇒ Object
-
#manually_check_action_resources_for_order_profile_conformance(card, validation_issues, request_body, error_prefix, ig_semver, validator: :default) ⇒ Object
-
#manually_check_action_specific_errors(action, validation_issues, action_type, request_body, error_prefix, ig_semver, validator: :default) ⇒ Object
-
#manually_check_additional_orders_errors(card, validation_issues, request_body, error_prefix, ig_semver, validator: :default) ⇒ Object
-
#manually_check_card_specific_errors(card, validation_issues, card_type, request_body, error_prefix, ig_semver, validator: :default) ⇒ Object
------------------------------------------------------------------------- Validator Filtering and Manual Checks Depending on the Card Type -------------------------------------------------------------------------.
-
#manually_check_coverage_information_errors(action, validation_issues, request_body, error_prefix, ig_semver, validator: :default) ⇒ Object
-
#manually_check_form_completion_action_errors(action, validation_issues, error_prefix, ig_semver, validator: :default) ⇒ Object
-
#manually_check_form_completion_errors(card, validation_issues, error_prefix, validator: :default) ⇒ Object
-
#manually_check_launch_smart_app_errors(validation_issues) ⇒ Object
-
#manually_check_propose_alternative_errors(card, validation_issues, request_body, error_prefix, ig_semver, validator: :default) ⇒ Object
-
#manually_check_update_coverage_action_errors(action, validation_issues, error_prefix, ig_semver, validator: :default) ⇒ Object
-
#multiple_extensions_conformance_check(grouped_coverage_info, resource) ⇒ Object
For the same coverage, ensure coverage-assertion-ids and satisfied-pa-ids are the same.
-
#perform_response_logical_model_validation(cards, system_actions, request_body, response_index, ig_semver, validator: :default) ⇒ Object
-
#same_coverage_conformance_error_msg(resource_ref, coverage, id_name) ⇒ Object
-
#validate_card_against_logical_model(card, response_index, request_body, card_index, ig_semver, validator: :default) ⇒ Object
-
#validate_no_smart_suggestions(card, label) ⇒ Object
-
#validate_suggestion_uuid_presence(card, label) ⇒ Object
-
#validate_summary_length(card, label) ⇒ Object
-
#validate_system_action_against_logical_model(action, response_index, request_body, action_index, ig_semver, validator: :default) ⇒ 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, #filter_logical_model_extension_issues, #local_reference?, #logical_model_extension_issue?, #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_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, humanize_response_type, #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
262
263
264
265
266
267
268
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 262
def add_messages_not_excluded(issues, error_prefix)
issues.each do |issue|
next if issue.filtered
add_message(issue.severity, "#{error_prefix}#{issue.message}")
end
end
|
#check_action_target(action, request_body, error_prefix, ig_semver, validator: :default) ⇒ Object
401
402
403
404
405
406
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 401
def check_action_target(action, request_body, error_prefix, ig_semver, validator: :default)
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, validator:)
end
|
173
174
175
176
177
178
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 173
def check_multiple_coverage_info_extension_conformance(action)
resource = FHIR.from_contents(action['resource'].to_json)
grouped_coverage_info = extract_and_group_coverage_info(resource)
multiple_extensions_conformance_check(grouped_coverage_info, resource)
end
|
#check_questionnaire_actions(card, error_message, error_prefix, validator: :default) ⇒ Object
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 324
def check_questionnaire_actions(card, error_message, error_prefix, validator: :default)
=
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:, validator:)
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
436
437
438
439
440
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 436
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
|
#collect_extensions_id(extensions, url, *properties) ⇒ Object
237
238
239
240
241
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 237
def collect_extensions_id(extensions, url, *properties)
extensions.map do |extension|
find_extension_value(extension, url, *properties)
end
end
|
258
259
260
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 258
def different_coverage_conformance_error_msg(resource_ref, id_name)
"#{resource_ref}: extensions referencing differing coverage SHALL have distinct #{id_name}."
end
|
#extract_and_group_coverage_info(resource) ⇒ Object
180
181
182
183
184
185
186
187
188
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 180
def extract_and_group_coverage_info(resource)
resource.extension.each_with_object({}) do |extension, grouped_extensions|
next unless extension.url == COVERAGE_INFO_EXT_URL
coverage_key = find_extension_value(extension, 'coverage', 'valueReference', 'reference')
grouped_extensions[coverage_key] ||= []
grouped_extensions[coverage_key] << extension
end
end
|
#find_extension_value(extension, url, *properties) ⇒ Object
243
244
245
246
247
248
249
250
251
252
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 243
def find_extension_value(extension, url, *properties)
found_extension = extension.extension.find { |ext| ext.url == url }
return nil unless found_extension
properties.reduce(found_extension) do |current, prop|
return current unless current.respond_to?(prop)
current.send(prop)
end
end
|
#logical_model_entity_label(response_index, entity_index, kind) ⇒ Object
270
271
272
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 270
def logical_model_entity_label(response_index, entity_index, kind)
"Server response #{response_index + 1}, #{kind} #{entity_index + 1}"
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
|
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 385
def manually_check_action_resources_for_order_profile_conformance(card, validation_issues, request_body,
error_prefix, ig_semver, validator: :default)
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, validator:)
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, validator: :default) ⇒ Object
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 296
def manually_check_action_specific_errors(action, validation_issues, action_type, request_body,
error_prefix, ig_semver, validator: :default)
case action_type
when DaVinciCRDTestKit::CardsIdentification::COVERAGE_INFORMATION_RESPONSE_TYPE
manually_check_coverage_information_errors(action, validation_issues, request_body,
error_prefix, ig_semver, validator:)
when DaVinciCRDTestKit::CardsIdentification::CREATE_OR_UPDATE_COVERAGE_RESPONSE_TYPE
manually_check_update_coverage_action_errors(action, validation_issues,
error_prefix, ig_semver, validator:)
when DaVinciCRDTestKit::CardsIdentification::FORM_COMPLETION_RESPONSE_TYPE
manually_check_form_completion_action_errors(action, validation_issues,
error_prefix, ig_semver, validator:)
else
validation_issues
end
end
|
#manually_check_additional_orders_errors(card, validation_issues, request_body, error_prefix, ig_semver, validator: :default) ⇒ Object
375
376
377
378
379
380
381
382
383
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 375
def manually_check_additional_orders_errors(card, validation_issues, request_body,
error_prefix, ig_semver, validator: :default)
manually_check_action_resources_for_order_profile_conformance(card,
validation_issues,
request_body,
error_prefix,
ig_semver,
validator:)
end
|
#manually_check_card_specific_errors(card, validation_issues, card_type, request_body, error_prefix, ig_semver, validator: :default) ⇒ Object
Validator Filtering and Manual Checks Depending on the Card Type
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 278
def manually_check_card_specific_errors(card, validation_issues, card_type, request_body, error_prefix,
ig_semver, validator: :default)
case card_type
when CardsIdentification::FORM_COMPLETION_RESPONSE_TYPE
manually_check_form_completion_errors(card, validation_issues, error_prefix, validator:)
when CardsIdentification::PROPOSE_ALTERNATIVE_REQUEST_RESPONSE_TYPE
manually_check_propose_alternative_errors(card, validation_issues, request_body,
error_prefix, ig_semver, validator:)
when CardsIdentification::ADDITIONAL_ORDERS_RESPONSE_TYPE
manually_check_additional_orders_errors(card, validation_issues, request_body,
error_prefix, ig_semver, validator:)
when CardsIdentification::LAUNCH_SMART_APP_RESPONSE_TYPE
manually_check_launch_smart_app_errors(validation_issues)
else
validation_issues
end
end
|
408
409
410
411
412
413
414
415
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 408
def manually_check_coverage_information_errors(action, validation_issues, request_body,
error_prefix, ig_semver, validator: :default)
if action['resource'].present?
check_resource_conformance_to_order_or_encounter_profile(action['resource'], request_body,
error_prefix, ig_semver, validator:)
end
reject_resource_issues(validation_issues)
end
|
426
427
428
429
430
431
432
433
434
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 426
def manually_check_form_completion_action_errors(action, validation_issues,
error_prefix, ig_semver, validator: :default)
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,
validator:)
end
reject_resource_issues(validation_issues)
end
|
313
314
315
316
317
318
319
320
321
322
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 313
def manually_check_form_completion_errors(card, validation_issues, error_prefix, validator: :default)
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, validator:)
true
else
false
end
end
end
|
#manually_check_launch_smart_app_errors(validation_issues) ⇒ Object
344
345
346
347
348
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 344
def manually_check_launch_smart_app_errors(validation_issues)
validation_issues.reject do |issue|
issue.message.match?(/CDSHooksResponse.cards.suggestions: minimum required = 1, but only found 0/)
end
end
|
#manually_check_propose_alternative_errors(card, validation_issues, request_body, error_prefix, ig_semver, validator: :default) ⇒ Object
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 350
def manually_check_propose_alternative_errors(card, validation_issues, request_body,
error_prefix, ig_semver, validator: :default)
no_resource_issues = manually_check_action_resources_for_order_profile_conformance(card,
validation_issues,
request_body,
error_prefix,
ig_semver,
validator:)
no_resource_issues.each do |issue|
next unless issue.message.match?(/Constraint failed: crd-respar-1/)
new_message =
"#{issue.message}. In some cases [additional create " \
'actions](https://hl7.org/fhir/us/davinci-crd/2.2.1/en/cards.html#propose-alternate-request-response-type) ' \
'are permitted. Manually check the suggestion to verify whether this is an actual error.'
issue.instance_variable_set(:@severity, 'warning')
issue.instance_variable_set(:@message, new_message)
end
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, validator: :default) ⇒ Object
417
418
419
420
421
422
423
424
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 417
def manually_check_update_coverage_action_errors(action, validation_issues,
error_prefix, ig_semver, validator: :default)
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, validator:)
end
reject_resource_issues(validation_issues)
end
|
For the same coverage, ensure coverage-assertion-ids and satisfied-pa-ids are the same.
For different coverages, ensure coverage-assertion-ids and satisfied-pa-ids are distinct.
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 192
def multiple_extensions_conformance_check(grouped_coverage_info, resource)
resource_ref = "#{resource.resourceType}/#{resource.id}"
assertion_ids_across_coverages = Set.new
pa_ids_across_coverages = Set.new
grouped_coverage_info.each do |coverage, extensions|
coverage_assertion_ids = collect_extensions_id(extensions, 'coverage-assertion-id', 'valueString').uniq
satisfied_pa_ids = collect_extensions_id(extensions, 'satisfied-pa-id', 'valueString').uniq.compact
if coverage_assertion_ids.length != 1
add_message(
'error',
same_coverage_conformance_error_msg(resource_ref, coverage, 'coverage-assertion-ids')
)
end
if satisfied_pa_ids.length > 1
add_message(
'error',
same_coverage_conformance_error_msg(resource_ref, coverage, 'satisfied-pa-ids')
)
end
assertion_id = coverage_assertion_ids.first
if assertion_ids_across_coverages.include?(assertion_id)
add_message(
'error',
different_coverage_conformance_error_msg(resource_ref, 'coverage-assertion-ids')
)
end
assertion_ids_across_coverages.add(assertion_id)
pa_id = satisfied_pa_ids.first
next unless pa_id
if pa_ids_across_coverages.include?(pa_id)
add_message(
'error',
different_coverage_conformance_error_msg(resource_ref, 'satisfied-pa-ids')
)
end
pa_ids_across_coverages.add(pa_id)
end
end
|
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
# 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,
validator: :default)
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, validator:)
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,
validator:)
end
end
|
254
255
256
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 254
def same_coverage_conformance_error_msg(resource_ref, coverage, id_name)
"#{resource_ref}: extension has multiple repetitions of coverage `#{coverage}` with different #{id_name}."
end
|
#validate_card_against_logical_model(card, response_index, request_body, card_index, ig_semver, validator: :default) ⇒ Object
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 58
def validate_card_against_logical_model(card, response_index, request_body, card_index, ig_semver,
validator: :default)
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,
validator:)
validate_summary_length(card, label)
validate_suggestion_uuid_presence(card, label) unless ['v201', '2.0.1'].include? ig_semver
validate_no_smart_suggestions(card, label) if card_type == CardsIdentification::LAUNCH_SMART_APP_RESPONSE_TYPE
error_prefix = "#{label} (#{card_type || 'uncategorized'}): "
filtered_issues = manually_check_card_specific_errors(card, validation_issues, card_type,
request_body, error_prefix, ig_semver, validator:)
filter_logical_model_extension_issues(filtered_issues, validator)
add_messages_not_excluded(filtered_issues, error_prefix)
end
|
#validate_no_smart_suggestions(card, label) ⇒ Object
119
120
121
122
123
124
125
126
127
128
129
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 119
def validate_no_smart_suggestions(card, label)
suggestion_count = card['suggestions']&.length || 0
return if suggestion_count.zero?
add_message(
'error',
"#{label} CDSHooksResponse.cards.suggestions: max allowed = 0, but found #{suggestion_count} " \
'(from http://hl7.org/fhir/us/davinci-crd/StructureDefinition/CRDHooksResponse-launchSMART|2.2.1)'
)
end
|
#validate_suggestion_uuid_presence(card, label) ⇒ Object
105
106
107
108
109
110
111
112
113
114
115
116
117
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 105
def validate_suggestion_uuid_presence(card, label)
return unless card['suggestions'].presence.is_a? Array
return unless card['suggestions'].all?(Hash)
card['suggestions'].each_with_index do |suggestion, index|
next if suggestion['uuid'].present?
add_message(
'error',
"#{label} suggestion #{index + 1} does not contain a `uuid`"
)
end
end
|
#validate_summary_length(card, label) ⇒ Object
91
92
93
94
95
96
97
98
99
100
101
102
103
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 91
def validate_summary_length(card, label)
return unless card['summary'].is_a? String
summary_length = card['summary'].length
return if summary_length < 140
add_message(
'error',
"#{label} summary length of #{summary_length} characters is longer than " \
'the maximum allowed of 139 characters.'
)
end
|
#validate_system_action_against_logical_model(action, response_index, request_body, action_index, ig_semver, validator: :default) ⇒ Object
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
|
# File 'lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb', line 131
def validate_system_action_against_logical_model(action, response_index, request_body, action_index, ig_semver,
validator: :default)
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,
validator:)
validation_issues
.reject! do |issue|
issue.message.match?(%r{CDSHooksResponse\.systemActions\[\d+\]\.extension: The extension definition http://hl7\.org/fhir/us/davinci-crd/StructureDefinition/CDSHookServiceResponseExtensionIfNoneExist\|2\.2\.1 defines the contexts of use as})
end
if action_type == CardsIdentification::COVERAGE_INFORMATION_RESPONSE_TYPE
check_multiple_coverage_info_extension_conformance(action)
end
error_prefix = "#{label} (#{action_type || 'uncategorized'}): "
filtered_issues = manually_check_action_specific_errors(action, validation_issues, action_type,
request_body, error_prefix, ig_semver, validator:)
filter_logical_model_extension_issues(filtered_issues, validator)
add_messages_not_excluded(filtered_issues, error_prefix)
end
|