davinci_crd_test_kit 0.14.0 → 0.14.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.
- checksums.yaml +4 -4
- data/config/presets/{inferno_crd_server_suite.json.erb → client_against_inferno_crd_server_suite.json.erb} +0 -33
- data/config/presets/{ri_crd_request_generator.json.erb → client_against_ri_crd_request_generator.json.erb} +1 -14
- data/config/presets/client_v221_against_inferno_crd_server_suite.json.erb +84 -0
- data/config/presets/client_v221_against_ri_br_provider.json.erb +31 -0
- data/config/presets/{ri_crd_request_generator.json_v221.json.erb → client_v221_against_ri_crd_request_generator.json.erb} +1 -1
- data/config/presets/{inferno_crd_client_suite.json.erb → server_against_inferno_crd_client_suite.json.erb} +0 -43
- data/config/presets/{ri_crd_server.json.erb → server_against_ri_crd_server.json.erb} +1 -44
- data/config/presets/{inferno_crd_client_suite_v221.json.erb → server_v221_against_inferno_crd_client_suite.json.erb} +48 -45
- data/config/presets/{inferno_crd_client_suite_prefetch_subset_v221.json.erb → server_v221_against_inferno_crd_client_suite_prefetch_subset.json.erb} +0 -46
- data/config/presets/server_v221_against_inferno_g31_suite.json.erb +49 -0
- data/lib/davinci_crd_test_kit/client/cross_hook_helper.rb +26 -0
- data/lib/davinci_crd_test_kit/client/endpoints/custom_service_response.rb +7 -7
- data/lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb +4 -1
- data/lib/davinci_crd_test_kit/client/endpoints/hook_request_endpoint.rb +70 -39
- data/lib/davinci_crd_test_kit/client/endpoints/mock_service_response.rb +26 -7
- data/lib/davinci_crd_test_kit/client/endpoints/mocked_card_responses/external_reference.json +1 -1
- data/lib/davinci_crd_test_kit/client/endpoints/mocked_card_responses/launch_smart_app.json +0 -7
- data/lib/davinci_crd_test_kit/client/endpoints/scenario_service_response.rb +54 -0
- data/lib/davinci_crd_test_kit/client/tagged_request_load_helper.rb +8 -27
- data/lib/davinci_crd_test_kit/client/v2.0.1/auth/retrieve_jwks_test.rb +35 -23
- data/lib/davinci_crd_test_kit/client/v2.0.1/auth/token_payload_test.rb +34 -21
- data/lib/davinci_crd_test_kit/client/v2.0.1/cds-services-v201.json +20 -20
- data/lib/davinci_crd_test_kit/client/v2.0.1/client_appointment_book_group.rb +12 -10
- data/lib/davinci_crd_test_kit/client/v2.0.1/client_encounter_discharge_group.rb +12 -10
- data/lib/davinci_crd_test_kit/client/v2.0.1/client_encounter_start_group.rb +12 -10
- data/lib/davinci_crd_test_kit/client/v2.0.1/client_hooks_group.rb +5 -5
- data/lib/davinci_crd_test_kit/client/v2.0.1/client_order_dispatch_group.rb +12 -10
- data/lib/davinci_crd_test_kit/client/v2.0.1/client_order_select_group.rb +12 -10
- data/lib/davinci_crd_test_kit/client/v2.0.1/client_order_sign_group.rb +12 -10
- data/lib/davinci_crd_test_kit/client/v2.0.1/must_support/client_card_must_support_coverage_information.rb +3 -36
- data/lib/davinci_crd_test_kit/client/v2.0.1/must_support/client_card_must_support_external_reference.rb +3 -36
- data/lib/davinci_crd_test_kit/client/v2.0.1/must_support/client_card_must_support_instructions.rb +3 -36
- data/lib/davinci_crd_test_kit/client/v2.0.1/verify_request/hook_request_fetched_data_test.rb +4 -13
- data/lib/davinci_crd_test_kit/client/v2.0.1/verify_request/hook_request_prefetch_equals_queried_test.rb +3 -13
- data/lib/davinci_crd_test_kit/client/v2.0.1/verify_response/client_display_cards_attest.rb +3 -13
- data/lib/davinci_crd_test_kit/client/v2.0.1/verify_response/inferno_response_validation.rb +3 -13
- data/lib/davinci_crd_test_kit/client/v2.2.1/api/client_coverage_info_update_test.rb +1 -1
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/attestation_instructions.rb +10 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/client_authorized_scope_attestation_test.rb +45 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/client_coverage_based_invocation_attestation_test.rb +44 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/client_data_element_expectations_attestation_test.rb +44 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/client_hook_invocation_logging_attestation_test.rb +43 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/client_must_support_exposure_attestation_test.rb +43 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/client_must_support_use_attestation_test.rb +41 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/client_order_sign_support_attestation_test.rb +42 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/client_prefetch_key_omission_attestation_test.rb +42 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/client_resource_identifiers_attestation_test.rb +43 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/client_response_case_distinction_attestation_test.rb +43 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/client_security_and_privacy_attestation_test.rb +43 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/client_workflow_integration_attestation_test.rb +44 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/auth/decode_auth_token_test.rb +1 -1
- data/lib/davinci_crd_test_kit/client/v2.2.1/auth/retrieve_jwks_test.rb +29 -18
- data/lib/davinci_crd_test_kit/client/v2.2.1/auth/token_payload_test.rb +35 -22
- data/lib/davinci_crd_test_kit/client/v2.2.1/cds-services-prefetch-subset-v221.json +47 -47
- data/lib/davinci_crd_test_kit/client/v2.2.1/cds-services-v221.json +50 -50
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_appointment_book_group.rb +24 -15
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_attestations_group.rb +49 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_cross_hook_group.rb +22 -6
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_cross_hook_interaction_group.rb +98 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_encounter_discharge_group.rb +19 -11
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_encounter_start_group.rb +19 -11
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_fhir_api_group.rb +14 -12
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_hooks_group.rb +25 -5
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_long_running_hook_group.rb +3 -2
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_order_dispatch_group.rb +23 -15
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_order_select_group.rb +19 -11
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_order_sign_group.rb +23 -15
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_registration_group.rb +6 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_scenarios_group.rb +26 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_self_pay_hook_group.rb +36 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_unknown_content_hook_group.rb +34 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/crd_client_suite.rb +24 -3
- data/lib/davinci_crd_test_kit/client/v2.2.1/cross_hook/client_card_must_support_coverage_information_test.rb +1 -1
- data/lib/davinci_crd_test_kit/client/v2.2.1/cross_hook/client_fhirpath_collection_as_comma_delimited_string_test.rb +4 -11
- data/lib/davinci_crd_test_kit/client/v2.2.1/cross_hook/client_hook_instances_unique_test.rb +1 -9
- data/lib/davinci_crd_test_kit/client/v2.2.1/cross_hook/client_location_address_propagation_test.rb +6 -2
- data/lib/davinci_crd_test_kit/client/v2.2.1/cross_hook/client_prefetch_complete_and_subset_test.rb +3 -12
- data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/appointment_book_receive_request_test.rb +8 -89
- data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/base_hook_invocation_receive_request_test.rb +163 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/cross_hooks_receive_request_test.rb +97 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/encounter_discharge_receive_request_test.rb +8 -90
- data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/encounter_start_receive_request_test.rb +8 -90
- data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/order_dispatch_receive_request_test.rb +8 -98
- data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/order_select_receive_request_test.rb +8 -98
- data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/order_sign_receive_request_test.rb +8 -98
- data/lib/davinci_crd_test_kit/client/v2.2.1/long_running/client_long_running_receive_request_test.rb +10 -2
- data/lib/davinci_crd_test_kit/client/v2.2.1/long_running/client_skip_long_running_attestation_test.rb +11 -6
- data/lib/davinci_crd_test_kit/client/v2.2.1/registration/client_service_registration_attestation_test.rb +2 -1
- data/lib/davinci_crd_test_kit/client/v2.2.1/self_pay/client_self_pay_no_request_test.rb +30 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/self_pay/client_self_pay_workflow_test.rb +55 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/unknown_content/client_unknown_content_attestation_test.rb +99 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/unknown_content/client_unknown_content_receive_request_test.rb +62 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_conformance_test.rb +1 -1
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_coverage_verification_test.rb +10 -2
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_data_fetch_verification_test.rb +1 -1
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_granted_scopes_test.rb +1 -1
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_prefetch_complete_test.rb +7 -1
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_prefetch_profiles_test.rb +1 -1
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_requested_version_test.rb +1 -1
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_secured_transport_test.rb +1 -1
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_response/client_display_cards_attest.rb +54 -21
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_response/hook_response_support_coverage_information_test.rb +1 -1
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_response/inferno_response_validation.rb +6 -3
- data/lib/davinci_crd_test_kit/cross_suite/cards_identification.rb +18 -0
- data/lib/davinci_crd_test_kit/cross_suite/logical_models_override_helper.rb +30 -13
- data/lib/davinci_crd_test_kit/cross_suite/prefetch_completeness_checker.rb +25 -11
- data/lib/davinci_crd_test_kit/cross_suite/prefetch_profile_validation.rb +2 -0
- data/lib/davinci_crd_test_kit/cross_suite/requests_logical_model_validation.rb +28 -28
- data/lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb +211 -43
- data/lib/davinci_crd_test_kit/cross_suite/tags.rb +7 -0
- data/lib/davinci_crd_test_kit/requirements/cds-hooks_3.0.0-ballot_requirements.xlsx +0 -0
- data/lib/davinci_crd_test_kit/requirements/davinci_crd_test_kit_requirements.csv +6 -2
- data/lib/davinci_crd_test_kit/requirements/generated/crd_client_requirements_coverage.csv +107 -107
- data/lib/davinci_crd_test_kit/requirements/generated/crd_client_v221_requirements_coverage.csv +101 -97
- data/lib/davinci_crd_test_kit/requirements/generated/crd_server_requirements_coverage.csv +18 -18
- data/lib/davinci_crd_test_kit/requirements/generated/crd_server_v221_requirements_coverage.csv +43 -39
- data/lib/davinci_crd_test_kit/requirements/hl7.fhir.us.davinci-crd_2.2.1_requirements.xlsx +0 -0
- data/lib/davinci_crd_test_kit/server/jobs/invoke_hook.rb +3 -3
- data/lib/davinci_crd_test_kit/server/jobs/invoke_hook_no_special_requests.rb +17 -0
- data/lib/davinci_crd_test_kit/server/jobs/invoke_hook_with_bad_auth.rb +14 -0
- data/lib/davinci_crd_test_kit/server/server_abstract_invoke_hook_test.rb +24 -6
- data/lib/davinci_crd_test_kit/server/server_hook_helper.rb +2 -2
- data/lib/davinci_crd_test_kit/server/v2.0.1/crd_server_suite.rb +1 -1
- data/lib/davinci_crd_test_kit/server/v2.0.1/server_hooks_group.rb +5 -5
- data/lib/davinci_crd_test_kit/server/v2.2.1/crd_server_suite.rb +3 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/discovery/discovery_standard_prefetch_expressions_test.rb +165 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/interaction/server_invoke_hook_single_request_test.rb +22 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/server_appointment_book_group.rb +10 -102
- data/lib/davinci_crd_test_kit/server/v2.2.1/server_demonstrate_hook_response_group.rb +3 -2
- data/lib/davinci_crd_test_kit/server/v2.2.1/server_discovery_group.rb +2 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/server_encounter_discharge_group.rb +10 -97
- data/lib/davinci_crd_test_kit/server/v2.2.1/server_encounter_start_group.rb +10 -97
- data/lib/davinci_crd_test_kit/server/v2.2.1/server_hooks_group.rb +5 -5
- data/lib/davinci_crd_test_kit/server/v2.2.1/server_order_dispatch_group.rb +10 -103
- data/lib/davinci_crd_test_kit/server/v2.2.1/server_order_select_group.rb +12 -116
- data/lib/davinci_crd_test_kit/server/v2.2.1/server_order_sign_group.rb +12 -121
- data/lib/davinci_crd_test_kit/server/v2.2.1/specific_coverage_response_group.rb +23 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/specific_coverage_responses/coverage_info_reason_test.rb +108 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/specific_coverage_responses/coverage_not_found_group.rb +116 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/specific_coverage_responses/no_active_coverage_group.rb +115 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/specific_coverage_responses/no_member_found_group.rb +117 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/specific_coverage_responses/technical_issues_group.rb +121 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/specific_coverage_responses/technical_issues_invoke_test.rb +22 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_request/service_request_context_validation_test.rb +1 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_request/service_request_optional_fields_validation_test.rb +1 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_request/service_request_required_fields_validation_test.rb +1 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/additional_orders_validation_test.rb +78 -35
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/coverage_information_card_absence_test.rb +76 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/coverage_information_system_action_validation_test.rb +70 -124
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/create_or_update_coverage_info_response_validation_test.rb +83 -39
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/external_reference_card_validation_test.rb +59 -17
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/form_completion_response_validation_test.rb +80 -45
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/hook_request_resource_resolution.rb +37 -0
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/instructions_card_received_test.rb +57 -6
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/launch_smart_app_card_validation_test.rb +56 -17
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/propose_alternate_request_card_validation_test.rb +52 -25
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/service_response_validation_test.rb +17 -51
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/unknown_cds_hooks_elements_test.rb +1 -1
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/unknown_configuration_test.rb +1 -1
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/unknown_context_test.rb +1 -1
- data/lib/davinci_crd_test_kit/version.rb +2 -2
- metadata +54 -16
- data/config/presets/inferno_crd_server_suite_v221.json.erb +0 -94
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/card_optional_fields_validation_test.rb +0 -57
- data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/coverage_information_system_action_received_test.rb +0 -65
data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_prefetch_complete_test.rb
CHANGED
|
@@ -29,6 +29,12 @@ module DaVinciCRDTestKit
|
|
|
29
29
|
During this test, Inferno will verify that each hook request body includes a `prefetch` field populated with
|
|
30
30
|
valid JSON that contains exactly the requested prefetch keys and data sets described in the service description
|
|
31
31
|
for the invoked service as calculated by Inferno based on the resources provided in the request.
|
|
32
|
+
|
|
33
|
+
Note that Inferno requires **all** requested prefetch keys to be present in the request even if there is no
|
|
34
|
+
data for that key. This because the [CDS Hook specification requires](https://cds-hooks.hl7.org/2026Jan/en/#example-of-pagination-in-prefetch)
|
|
35
|
+
that if "the CDS Client has no data to populate a template prefetch key, the prefetch template key MUST have a
|
|
36
|
+
value of null." For templates that request the results of a FHIR search interaction, an empty Bundle is also
|
|
37
|
+
acceptable.
|
|
32
38
|
)
|
|
33
39
|
verifies_requirements 'cds-hooks_3.0.0-ballot@30', 'cds-hooks_3.0.0-ballot@231', 'cds-hooks_3.0.0-ballot@45',
|
|
34
40
|
'cds-hooks_3.0.0-ballot@46', 'cds-hooks_3.0.0-ballot@47', 'cds-hooks_3.0.0-ballot@232',
|
|
@@ -83,7 +89,7 @@ module DaVinciCRDTestKit
|
|
|
83
89
|
end
|
|
84
90
|
|
|
85
91
|
run do
|
|
86
|
-
hook_requests =
|
|
92
|
+
hook_requests = load_interaction_group_requests
|
|
87
93
|
|
|
88
94
|
skip_if hook_requests.blank?, "No #{hook_name} hook requests received."
|
|
89
95
|
|
data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_prefetch_profiles_test.rb
CHANGED
|
@@ -34,7 +34,7 @@ module DaVinciCRDTestKit
|
|
|
34
34
|
'hl7.fhir.us.davinci-crd_2.2.1@prof-10', 'hl7.fhir.us.davinci-crd_2.2.1@prof-11',
|
|
35
35
|
'hl7.fhir.us.davinci-crd_2.2.1@prof-12'
|
|
36
36
|
run do
|
|
37
|
-
hook_requests =
|
|
37
|
+
hook_requests = load_interaction_group_requests
|
|
38
38
|
|
|
39
39
|
skip_if hook_requests.blank?, "No #{hook_name} hook requests received."
|
|
40
40
|
|
|
@@ -10,40 +10,73 @@ module DaVinciCRDTestKit
|
|
|
10
10
|
include DaVinciCRDTestKit::TaggedRequestLoadHelper
|
|
11
11
|
|
|
12
12
|
id :crd_v221_card_display_attest_test
|
|
13
|
-
title 'Client displays returned decision support details to the user
|
|
13
|
+
title 'Client displays returned decision support details to the user'
|
|
14
14
|
description %(
|
|
15
15
|
During this test, the tester will confirm that the received cards and actions in the
|
|
16
16
|
hook responses have been displayed or otherwise made available to users of the client system
|
|
17
17
|
in an appopriate way that allows for consideration and action if warranted.
|
|
18
18
|
)
|
|
19
|
+
attestation
|
|
20
|
+
|
|
21
|
+
verifies_requirements 'hl7.fhir.us.davinci-crd_2.2.1@resp-49'
|
|
19
22
|
|
|
20
23
|
def responded_card_types
|
|
21
|
-
list_card_types_in_requests(requests)
|
|
24
|
+
@responded_card_types ||= list_card_types_in_requests(requests)
|
|
22
25
|
end
|
|
23
26
|
|
|
24
|
-
def format_responded_response_types
|
|
25
|
-
|
|
27
|
+
def format_responded_response_types(response_types = responded_card_types)
|
|
28
|
+
response_types
|
|
26
29
|
.map do |response_type|
|
|
27
|
-
|
|
28
|
-
response_type.split('_')
|
|
29
|
-
.map(&:capitalize)
|
|
30
|
-
.join(' ')
|
|
30
|
+
DaVinciCRDTestKit::CardsIdentification.humanize_response_type(response_type)
|
|
31
31
|
.prepend('- ')
|
|
32
|
-
.sub('
|
|
33
|
-
.sub('
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
.sub(' Card', '')
|
|
33
|
+
.sub(' Action', '')
|
|
34
|
+
end.join("\n")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def format_responded_card_types
|
|
38
|
+
@format_responded_card_types ||=
|
|
39
|
+
format_responded_response_types(responded_card_types.select do |type|
|
|
40
|
+
type.end_with?('_card')
|
|
41
|
+
end)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def format_responded_system_action_types
|
|
45
|
+
@format_responded_system_action_types ||=
|
|
46
|
+
format_responded_response_types(responded_card_types.select do |type|
|
|
47
|
+
type.end_with?('_action')
|
|
48
|
+
end)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
CARD_AND_SYSTEM_ACTION_DISPLAY_PREFIX = "\n\n By attesting true, ".freeze
|
|
52
|
+
CARD_AND_SYSTEM_ACTION_DISPLAY_CLAUSE_PREFIX = 'you confirm that the following '.freeze
|
|
53
|
+
CARD_AND_SYSTEM_ACTION_DISPLAY_CLAUSE_CONNECTOR = "\n\n Additionally, ".freeze
|
|
54
|
+
CARD_AND_SYSTEM_ACTION_DISPLAY_CARD_CLAUSE =
|
|
55
|
+
'card types observed in Inferno\'s responses were displayed to users:'.freeze
|
|
56
|
+
CARD_AND_SYSTEM_ACTION_DISPLAY_SYSTEM_ACTION_CLAUSE =
|
|
57
|
+
'system action types observed in Inferno\'s responses were displayed to users ' \
|
|
58
|
+
'through standard card display, icons, flyovers, or another alternate mechanism:'.freeze
|
|
59
|
+
|
|
60
|
+
def card_and_system_action_details_display
|
|
61
|
+
if format_responded_card_types.present? && format_responded_system_action_types.present?
|
|
62
|
+
"#{CARD_AND_SYSTEM_ACTION_DISPLAY_PREFIX}#{CARD_AND_SYSTEM_ACTION_DISPLAY_CLAUSE_PREFIX}" \
|
|
63
|
+
"#{CARD_AND_SYSTEM_ACTION_DISPLAY_CARD_CLAUSE}\n#{format_responded_card_types}" \
|
|
64
|
+
"#{CARD_AND_SYSTEM_ACTION_DISPLAY_CLAUSE_CONNECTOR}#{CARD_AND_SYSTEM_ACTION_DISPLAY_CLAUSE_PREFIX}" \
|
|
65
|
+
"#{CARD_AND_SYSTEM_ACTION_DISPLAY_SYSTEM_ACTION_CLAUSE}\n#{format_responded_system_action_types}"
|
|
66
|
+
elsif format_responded_card_types.present?
|
|
67
|
+
"#{CARD_AND_SYSTEM_ACTION_DISPLAY_PREFIX}#{CARD_AND_SYSTEM_ACTION_DISPLAY_CLAUSE_PREFIX}" \
|
|
68
|
+
"#{CARD_AND_SYSTEM_ACTION_DISPLAY_CARD_CLAUSE}\n#{format_responded_card_types}"
|
|
69
|
+
else
|
|
70
|
+
"#{CARD_AND_SYSTEM_ACTION_DISPLAY_PREFIX}#{CARD_AND_SYSTEM_ACTION_DISPLAY_CLAUSE_PREFIX}" \
|
|
71
|
+
"#{CARD_AND_SYSTEM_ACTION_DISPLAY_SYSTEM_ACTION_CLAUSE}\n#{format_responded_system_action_types}"
|
|
38
72
|
end
|
|
39
|
-
.join("\n")
|
|
40
73
|
end
|
|
41
74
|
|
|
42
75
|
output :attest_true_url
|
|
43
76
|
output :attest_false_url
|
|
44
77
|
|
|
45
78
|
run do
|
|
46
|
-
|
|
79
|
+
load_interaction_group_requests
|
|
47
80
|
skip_if responded_card_types.blank?, 'No responses sent to the client.'
|
|
48
81
|
|
|
49
82
|
identifier = SecureRandom.hex(32)
|
|
@@ -56,12 +89,12 @@ module DaVinciCRDTestKit
|
|
|
56
89
|
message: <<~MESSAGE
|
|
57
90
|
**Card Display Attestation**:
|
|
58
91
|
|
|
59
|
-
I attest that the
|
|
60
|
-
|
|
61
|
-
available to users of the
|
|
62
|
-
|
|
92
|
+
I attest that the simulated CRD responses returned by Inferno during this
|
|
93
|
+
group were successfully processed by the client system and that they were
|
|
94
|
+
made available to users of the system in an appropriate way that allowed for
|
|
95
|
+
user review and action if warranted.
|
|
63
96
|
|
|
64
|
-
#{
|
|
97
|
+
#{card_and_system_action_details_display}
|
|
65
98
|
|
|
66
99
|
[Click here](#{attest_true_url}) if the above statement is **true**.
|
|
67
100
|
|
|
@@ -18,7 +18,7 @@ module DaVinciCRDTestKit
|
|
|
18
18
|
DESCRIPTION
|
|
19
19
|
|
|
20
20
|
run do
|
|
21
|
-
hook_requests =
|
|
21
|
+
hook_requests = load_interaction_group_requests
|
|
22
22
|
skip_if hook_requests.blank?, "No #{hook_name} hook requests received."
|
|
23
23
|
|
|
24
24
|
sorted_cards = sorted_cards_from_requests(hook_requests)
|
|
@@ -14,6 +14,8 @@ module DaVinciCRDTestKit
|
|
|
14
14
|
During this test, Inferno will verify that each hook response built by Inferno's simulated CRD servers
|
|
15
15
|
and returned to the client conforms to CDS Hooks and CRD requirements. These responses must be conformant
|
|
16
16
|
for the client to demonstrate its ability to accept and process valid CRD responses.
|
|
17
|
+
To prevent the injection of non-standard information into Inferno responses, these validations will
|
|
18
|
+
strictly check that all extensions are allowed at the locations they appear by the CRD specification.
|
|
17
19
|
|
|
18
20
|
If this test fails when the tester provided a custom response template, adjust the
|
|
19
21
|
provided template and the submitted requests so that the response built by Inferno
|
|
@@ -29,7 +31,7 @@ module DaVinciCRDTestKit
|
|
|
29
31
|
simulation_verification
|
|
30
32
|
|
|
31
33
|
verifies_requirements 'cds-hooks_3.0.0-ballot@3', 'cds-hooks_3.0.0-ballot@222', 'cds-hooks_3.0.0-ballot@223',
|
|
32
|
-
'cds-hooks_3.0.0-ballot@224'
|
|
34
|
+
'cds-hooks_3.0.0-ballot@224', 'hl7.fhir.us.davinci-crd_2.2.1@conf-10'
|
|
33
35
|
|
|
34
36
|
input :custom_response_template, optional: true
|
|
35
37
|
|
|
@@ -45,7 +47,7 @@ module DaVinciCRDTestKit
|
|
|
45
47
|
end
|
|
46
48
|
|
|
47
49
|
run do
|
|
48
|
-
|
|
50
|
+
load_interaction_group_requests
|
|
49
51
|
|
|
50
52
|
skip_if request.blank?, "No #{response_label.downcase}s to verify."
|
|
51
53
|
|
|
@@ -62,7 +64,8 @@ module DaVinciCRDTestKit
|
|
|
62
64
|
response_hash['systemActions'],
|
|
63
65
|
request_hash,
|
|
64
66
|
index,
|
|
65
|
-
'2.2.1'
|
|
67
|
+
'2.2.1',
|
|
68
|
+
validator: :no_custom_extensions)
|
|
66
69
|
rescue JSON::ParserError
|
|
67
70
|
next
|
|
68
71
|
end
|
|
@@ -35,6 +35,15 @@ module DaVinciCRDTestKit
|
|
|
35
35
|
NutritionOrder ServiceRequest VisionPrescription
|
|
36
36
|
].freeze
|
|
37
37
|
|
|
38
|
+
def self.humanize_response_type(response_type)
|
|
39
|
+
response_type.split('_')
|
|
40
|
+
.map(&:capitalize)
|
|
41
|
+
.join(' ')
|
|
42
|
+
.sub('Smart', 'SMART')
|
|
43
|
+
.sub('Create Update', 'Create/Update')
|
|
44
|
+
.sub('Companions Prerequisites', 'Companions/Prerequisites')
|
|
45
|
+
end
|
|
46
|
+
|
|
38
47
|
def identify_card_type(card) # rubocop:disable Metrics/CyclomaticComplexity
|
|
39
48
|
return nil if card['type'].present? # action, not a card
|
|
40
49
|
return ADDITIONAL_ORDERS_RESPONSE_TYPE if additional_orders_response_type?(card)
|
|
@@ -88,6 +97,14 @@ module DaVinciCRDTestKit
|
|
|
88
97
|
[cards, actions]
|
|
89
98
|
end
|
|
90
99
|
|
|
100
|
+
def coverage_info_system_action_response?(response_body)
|
|
101
|
+
return false unless response_body.is_a?(Hash)
|
|
102
|
+
|
|
103
|
+
return false unless response_body['systemActions'].is_a?(Array)
|
|
104
|
+
|
|
105
|
+
response_body['systemActions'].any? { |action| coverage_information_response_type?(action) }
|
|
106
|
+
end
|
|
107
|
+
|
|
91
108
|
def coverage_info_response?(response_body)
|
|
92
109
|
cards, actions = coverage_info_content(response_body)
|
|
93
110
|
|
|
@@ -123,6 +140,7 @@ module DaVinciCRDTestKit
|
|
|
123
140
|
|
|
124
141
|
def coverage_information_response_type?(action) # rubocop:disable Metrics/CyclomaticComplexity
|
|
125
142
|
return false unless action.respond_to?(:[])
|
|
143
|
+
return false unless action['type'] == 'update'
|
|
126
144
|
|
|
127
145
|
resource = action['resource']&.to_hash
|
|
128
146
|
return false unless COVERAGE_INFO_EXPECTED_RESOURCE_TYPES.include? resource&.dig('resourceType')
|
|
@@ -13,27 +13,44 @@ module DaVinciCRDTestKit
|
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
def filter_logical_model_extension_issues(issues, validator)
|
|
17
|
+
return if validator == :no_custom_extensions
|
|
18
|
+
|
|
19
|
+
issues.each { |issue| issue.filtered = issue.filtered || logical_model_extension_issue?(issue) }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Logical models validation doesn't currently respect the `"extensions": ["any"]`
|
|
23
|
+
# validator flag
|
|
24
|
+
def logical_model_extension_issue?(issue)
|
|
25
|
+
issue.message.match(/\.extension: Unrecognized property/).present?
|
|
26
|
+
end
|
|
27
|
+
|
|
16
28
|
# -------------------------------------------------------------------------
|
|
17
29
|
# Check resource conformance outside the logical models
|
|
18
30
|
# -------------------------------------------------------------------------
|
|
19
31
|
|
|
20
|
-
def check_resource_conformance_to_coverage_profile(resource_hash, error_prefix, ig_semver)
|
|
21
|
-
check_resource_type_and_validate(resource_hash, error_prefix, ig_semver, FHIR::Coverage)
|
|
32
|
+
def check_resource_conformance_to_coverage_profile(resource_hash, error_prefix, ig_semver, validator: :default)
|
|
33
|
+
check_resource_type_and_validate(resource_hash, error_prefix, ig_semver, FHIR::Coverage, validator:)
|
|
22
34
|
end
|
|
23
35
|
|
|
24
|
-
def check_resource_conformance_to_questionnaire_task_profile(resource_hash, error_prefix, ig_semver
|
|
25
|
-
|
|
36
|
+
def check_resource_conformance_to_questionnaire_task_profile(resource_hash, error_prefix, ig_semver,
|
|
37
|
+
validator: :default)
|
|
38
|
+
check_resource_type_and_validate(resource_hash, error_prefix, ig_semver, FHIR::Task, validator:)
|
|
26
39
|
end
|
|
27
40
|
|
|
28
|
-
def check_resource_conformance_to_order_or_encounter_profile(resource_hash, request_body, error_prefix, ig_semver
|
|
41
|
+
def check_resource_conformance_to_order_or_encounter_profile(resource_hash, request_body, error_prefix, ig_semver,
|
|
42
|
+
validator: :default)
|
|
29
43
|
check_order_like_resource_conformance(resource_hash, request_body, error_prefix, ig_semver,
|
|
44
|
+
validator:,
|
|
30
45
|
allowed_types: ProfilesAndResourceTypes::ORDER_OR_ENCOUNTER_RESOURCE_CLASSES,
|
|
31
46
|
disallowed_message: 'is not allowed as a target ' \
|
|
32
47
|
'for a coverage-information action')
|
|
33
48
|
end
|
|
34
49
|
|
|
35
|
-
def check_resource_conformance_to_order_profile(resource_hash, request_body, error_prefix, ig_semver
|
|
50
|
+
def check_resource_conformance_to_order_profile(resource_hash, request_body, error_prefix, ig_semver,
|
|
51
|
+
validator: :default)
|
|
36
52
|
check_order_like_resource_conformance(resource_hash, request_body, error_prefix, ig_semver,
|
|
53
|
+
validator:,
|
|
37
54
|
allowed_types: ProfilesAndResourceTypes::ORDER_RESOURCE_CLASSES,
|
|
38
55
|
disallowed_message: 'is not allowed for CRD orders')
|
|
39
56
|
end
|
|
@@ -51,11 +68,11 @@ module DaVinciCRDTestKit
|
|
|
51
68
|
yield resource
|
|
52
69
|
end
|
|
53
70
|
|
|
54
|
-
def check_resource_type_and_validate(resource_hash, error_prefix, ig_semver, expected_class)
|
|
71
|
+
def check_resource_type_and_validate(resource_hash, error_prefix, ig_semver, expected_class, validator: :default)
|
|
55
72
|
parse_action_resource(resource_hash, error_prefix) do |resource|
|
|
56
73
|
if resource.is_a?(expected_class)
|
|
57
74
|
resource_is_valid?(resource:, profile_url: structure_definition_map(ig_semver)[resource.resourceType],
|
|
58
|
-
message_prefix: error_prefix)
|
|
75
|
+
message_prefix: error_prefix, validator:)
|
|
59
76
|
else
|
|
60
77
|
add_message('error', "#{error_prefix}found resource type '#{resource.resourceType}' " \
|
|
61
78
|
"expected '#{expected_class.name.split('::').last}'.")
|
|
@@ -64,14 +81,14 @@ module DaVinciCRDTestKit
|
|
|
64
81
|
end
|
|
65
82
|
|
|
66
83
|
def check_order_like_resource_conformance(resource_hash, request_body, error_prefix, ig_semver,
|
|
67
|
-
allowed_types:, disallowed_message:)
|
|
84
|
+
allowed_types:, disallowed_message:, validator: :default)
|
|
68
85
|
parse_action_resource(resource_hash, error_prefix) do |resource|
|
|
69
86
|
case resource
|
|
70
87
|
when FHIR::Appointment
|
|
71
|
-
check_appointment_conformance(resource, request_body, error_prefix, ig_semver)
|
|
88
|
+
check_appointment_conformance(resource, request_body, error_prefix, ig_semver, validator:)
|
|
72
89
|
when *allowed_types
|
|
73
90
|
resource_is_valid?(resource:, profile_url: structure_definition_map(ig_semver)[resource.resourceType],
|
|
74
|
-
message_prefix: error_prefix)
|
|
91
|
+
message_prefix: error_prefix, validator:)
|
|
75
92
|
else
|
|
76
93
|
add_message('error', "#{error_prefix}resource type '#{resource.resourceType}' #{disallowed_message}.")
|
|
77
94
|
end
|
|
@@ -82,7 +99,7 @@ module DaVinciCRDTestKit
|
|
|
82
99
|
# Appointment conformance (requires extra help to decide profile and check profile-based slicing)
|
|
83
100
|
# -------------------------------------------------------------------------
|
|
84
101
|
|
|
85
|
-
def check_appointment_conformance(appointment, request_body, error_prefix, ig_semver)
|
|
102
|
+
def check_appointment_conformance(appointment, request_body, error_prefix, ig_semver, validator: :default)
|
|
86
103
|
target_appointment_profile =
|
|
87
104
|
if appointment.basedOn.present?
|
|
88
105
|
'http://hl7.org/fhir/us/davinci-crd/StructureDefinition/profile-appointment-with-order'
|
|
@@ -92,7 +109,7 @@ module DaVinciCRDTestKit
|
|
|
92
109
|
|
|
93
110
|
validation_issues = []
|
|
94
111
|
resource_is_valid?(resource: appointment, profile_url: "#{target_appointment_profile}|#{ig_semver}",
|
|
95
|
-
add_messages_to_runnable: false, validator_response_details: validation_issues)
|
|
112
|
+
add_messages_to_runnable: false, validator_response_details: validation_issues, validator:)
|
|
96
113
|
|
|
97
114
|
manually_check_appointment_validation_errors(validation_issues, appointment, request_body)
|
|
98
115
|
.each do |issue|
|
|
@@ -172,12 +172,16 @@ module DaVinciCRDTestKit
|
|
|
172
172
|
end
|
|
173
173
|
|
|
174
174
|
check_is_fhir_resource(prefetched_value, target_resource_type: 'Bundle')
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
175
|
+
if prefetched_value['resourceType'] == 'Bundle'
|
|
176
|
+
unless prefetched_value['entry']&.size == 1
|
|
177
|
+
errors << "#{error_prefix} exactly one Coverage must be provided."
|
|
178
|
+
return
|
|
179
|
+
end
|
|
179
180
|
|
|
180
|
-
|
|
181
|
+
check_coverage(prefetched_value.dig('entry', 0, 'resource'))
|
|
182
|
+
elsif prefetched_value['resourceType'] == 'Coverage'
|
|
183
|
+
check_coverage(prefetched_value)
|
|
184
|
+
end
|
|
181
185
|
end
|
|
182
186
|
|
|
183
187
|
def check_coverage(prefetched_coverage)
|
|
@@ -197,16 +201,26 @@ module DaVinciCRDTestKit
|
|
|
197
201
|
"expected active, got #{prefetched_coverage['status']}."
|
|
198
202
|
end
|
|
199
203
|
|
|
200
|
-
|
|
201
|
-
unless prefetched_coverage.dig('beneficiary', 'reference') == "Patient/#{target_patient_id}"
|
|
202
|
-
errors << "#{error_prefix} prefetched Coverage has an unexpected beneficiary reference: " \
|
|
203
|
-
"expected Patient/#{target_patient_id}, got #{prefetched_coverage.dig('beneficiary',
|
|
204
|
-
'reference')}."
|
|
205
|
-
end
|
|
204
|
+
check_coverage_beneficiary(prefetched_coverage)
|
|
206
205
|
|
|
207
206
|
nil
|
|
208
207
|
end
|
|
209
208
|
|
|
209
|
+
def check_coverage_beneficiary(prefetched_coverage)
|
|
210
|
+
target_patient_id = hook_request.dig('context', 'patientId')
|
|
211
|
+
patient_id = target_patient_id&.delete_prefix('Patient/')
|
|
212
|
+
relative_ref = "Patient/#{patient_id}"
|
|
213
|
+
fhir_server = hook_request['fhirServer']&.chomp('/')
|
|
214
|
+
absolute_ref = "#{fhir_server}/#{relative_ref}" if fhir_server.present?
|
|
215
|
+
|
|
216
|
+
actual_ref = prefetched_coverage.dig('beneficiary', 'reference')
|
|
217
|
+
return if actual_ref == relative_ref || (absolute_ref && actual_ref == absolute_ref)
|
|
218
|
+
|
|
219
|
+
expected_refs = [relative_ref, absolute_ref].compact.join(' or ')
|
|
220
|
+
errors << "#{error_prefix} prefetched Coverage has an unexpected beneficiary reference: " \
|
|
221
|
+
"expected #{expected_refs}, got #{actual_ref}."
|
|
222
|
+
end
|
|
223
|
+
|
|
210
224
|
def check_read(prefetched_value, instantiated_request)
|
|
211
225
|
resource_type, resource_id = instantiated_request.split('/')
|
|
212
226
|
|
|
@@ -34,6 +34,8 @@ module DaVinciCRDTestKit
|
|
|
34
34
|
profile_url: target_crd_profile,
|
|
35
35
|
validator_response_details: validation_details, add_messages_to_runnable: false)
|
|
36
36
|
validation_details.each do |issue|
|
|
37
|
+
next if issue.filtered
|
|
38
|
+
|
|
37
39
|
prefix = prefetch_profile_error_prefix(request_index, bundle_entry_index)
|
|
38
40
|
add_message(issue.severity, "#{prefix}#{issue.message}")
|
|
39
41
|
end
|
|
@@ -13,15 +13,10 @@ module DaVinciCRDTestKit
|
|
|
13
13
|
'Practitioner', 'PractitionerRole'
|
|
14
14
|
].freeze
|
|
15
15
|
|
|
16
|
-
def validate_request_against_logical_model(request_body, request_index, ig_semver)
|
|
17
|
-
|
|
18
|
-
check_logical_model_conformance_no_resource_checks(request_body, request_index, ig_semver)
|
|
19
|
-
else
|
|
20
|
-
conforms_to_logical_model?(request_body, "#{CRD_CDS_HOOK_REQUEST_MODEL_URL}|#{ig_semver}",
|
|
21
|
-
message_prefix: "(Request #{request_index + 1}) ")
|
|
22
|
-
end
|
|
16
|
+
def validate_request_against_logical_model(request_body, request_index, ig_semver, validator: :default)
|
|
17
|
+
check_logical_model_conformance_no_resource_checks(request_body, request_index, ig_semver, validator:)
|
|
23
18
|
|
|
24
|
-
perform_version_specific_additional_verification(request_body, request_index, ig_semver)
|
|
19
|
+
perform_version_specific_additional_verification(request_body, request_index, ig_semver, validator:)
|
|
25
20
|
end
|
|
26
21
|
|
|
27
22
|
private
|
|
@@ -30,83 +25,88 @@ module DaVinciCRDTestKit
|
|
|
30
25
|
# Additional Validation to cover areas not checked or checked incorrectly by the logical models
|
|
31
26
|
# -------------------------------------------------------------------------
|
|
32
27
|
|
|
33
|
-
def perform_version_specific_additional_verification(request_body, request_index, ig_semver)
|
|
28
|
+
def perform_version_specific_additional_verification(request_body, request_index, ig_semver, validator: :default)
|
|
34
29
|
case ig_semver
|
|
35
30
|
when '2.2.1'
|
|
36
|
-
perform_v221_additional_verification(request_body, request_index)
|
|
31
|
+
perform_v221_additional_verification(request_body, request_index, validator:)
|
|
37
32
|
end
|
|
38
33
|
end
|
|
39
34
|
|
|
40
|
-
def perform_v221_additional_verification(request_body, request_index)
|
|
35
|
+
def perform_v221_additional_verification(request_body, request_index, validator: :default)
|
|
41
36
|
check_context_resources_for_ids(request_body, request_index)
|
|
42
37
|
check_relative_references(request_body, request_index)
|
|
43
|
-
check_context_resource_profiles(request_body, request_index, '2.2.1')
|
|
38
|
+
check_context_resource_profiles(request_body, request_index, '2.2.1', validator:)
|
|
44
39
|
end
|
|
45
40
|
|
|
46
41
|
# -------------------------------------------------------------------------
|
|
47
42
|
# Context resources profile check (not working in v2.2.1 logical models)
|
|
48
43
|
# -------------------------------------------------------------------------
|
|
49
44
|
|
|
50
|
-
def check_logical_model_conformance_no_resource_checks(request_body, request_index, ig_semver)
|
|
45
|
+
def check_logical_model_conformance_no_resource_checks(request_body, request_index, ig_semver, validator: :default)
|
|
51
46
|
validation_issues = []
|
|
52
47
|
conforms_to_logical_model?(request_body, "#{CRD_CDS_HOOK_REQUEST_MODEL_URL}|#{ig_semver}",
|
|
53
|
-
add_messages_to_runnable: false, validator_response_details: validation_issues
|
|
48
|
+
add_messages_to_runnable: false, validator_response_details: validation_issues,
|
|
49
|
+
validator:)
|
|
54
50
|
|
|
55
|
-
reject_resource_issues(validation_issues)
|
|
51
|
+
filtered_issues = reject_resource_issues(validation_issues)
|
|
52
|
+
filter_logical_model_extension_issues(filtered_issues, validator)
|
|
53
|
+
filtered_issues.each do |issue|
|
|
56
54
|
next if issue.filtered
|
|
57
55
|
|
|
58
56
|
add_message(issue.severity, "(Request #{request_index + 1}) #{issue.message}")
|
|
59
57
|
end
|
|
60
58
|
end
|
|
61
59
|
|
|
62
|
-
def check_context_resource_profiles(request_body, request_index, ig_semver)
|
|
60
|
+
def check_context_resource_profiles(request_body, request_index, ig_semver, validator: :default)
|
|
63
61
|
case request_body['hook']
|
|
64
62
|
when 'order-sign', 'order-select'
|
|
65
|
-
draft_orders_conform_to_profiles?(request_body, request_index, ig_semver)
|
|
63
|
+
draft_orders_conform_to_profiles?(request_body, request_index, ig_semver, validator:)
|
|
66
64
|
when 'order-dispatch'
|
|
67
65
|
request_body.dig('context', 'fulfillmentTasks')&.each_with_index do |task, index|
|
|
68
66
|
resource = FHIR.from_contents(task.to_json)
|
|
69
67
|
resource_is_valid?(resource:, profile_url: "http://hl7.org/fhir/us/davinci-crd/StructureDefinition/profile-task-dispatch|#{ig_semver}",
|
|
70
|
-
message_prefix: "(Request #{request_index + 1}) " \
|
|
71
|
-
|
|
68
|
+
validator:, message_prefix: "(Request #{request_index + 1}) " \
|
|
69
|
+
"context.fulfillmentTasks entry #{index + 1} - ")
|
|
72
70
|
end
|
|
73
71
|
when 'appointment-book'
|
|
74
|
-
check_appointments_profiles(request_body, request_index, ig_semver)
|
|
72
|
+
check_appointments_profiles(request_body, request_index, ig_semver, validator:)
|
|
75
73
|
end
|
|
76
74
|
rescue JSON::ParserError
|
|
77
75
|
nil # no resource to validate - error found elsewhere
|
|
78
76
|
end
|
|
79
77
|
|
|
80
|
-
def draft_orders_conform_to_profiles?(request_body, request_index, ig_semver)
|
|
81
|
-
|
|
78
|
+
def draft_orders_conform_to_profiles?(request_body, request_index, ig_semver, validator: :default)
|
|
79
|
+
draft_orders = request_body.dig('context', 'draftOrders').to_json
|
|
80
|
+
resource = FHIR.from_contents(draft_orders)
|
|
82
81
|
resource_is_valid?(resource:, profile_url: "http://hl7.org/fhir/us/davinci-crd/StructureDefinition/profile-bundle-request|#{ig_semver}",
|
|
83
|
-
message_prefix: "(Request #{request_index + 1}) context.draftOrders - ")
|
|
82
|
+
message_prefix: "(Request #{request_index + 1}) context.draftOrders - ", validator:)
|
|
84
83
|
end
|
|
85
84
|
|
|
86
85
|
# -------------------------------------------------------------------------
|
|
87
86
|
# Appointment conformance (requires extra help to decide profile and check profile-based slicing)
|
|
88
87
|
# -------------------------------------------------------------------------
|
|
89
88
|
|
|
90
|
-
def check_appointments_profiles(request_body, request_index, ig_semver)
|
|
89
|
+
def check_appointments_profiles(request_body, request_index, ig_semver, validator: :default)
|
|
91
90
|
resource = FHIR.from_contents(request_body.dig('context', 'appointments')&.to_json)
|
|
92
91
|
return unless resource.is_a?(FHIR::Bundle)
|
|
93
92
|
|
|
94
93
|
check_bundle_non_entry_resource_conformance(resource,
|
|
95
94
|
"(Request #{request_index + 1}) context.appointments - ",
|
|
96
|
-
ig_semver
|
|
95
|
+
ig_semver,
|
|
96
|
+
validator:)
|
|
97
97
|
|
|
98
98
|
resource.entry.each_with_index do |entry, entry_index|
|
|
99
99
|
next unless entry.resource.present? # error caught on Bundle validation
|
|
100
100
|
|
|
101
101
|
error_prefix = "(Request #{request_index + 1}) context.appointments entry #{entry_index + 1} - "
|
|
102
|
-
check_appointment_conformance(entry.resource, request_body, error_prefix, ig_semver)
|
|
102
|
+
check_appointment_conformance(entry.resource, request_body, error_prefix, ig_semver, validator:)
|
|
103
103
|
end
|
|
104
104
|
end
|
|
105
105
|
|
|
106
|
-
def check_bundle_non_entry_resource_conformance(bundle, error_prefix, ig_semver)
|
|
106
|
+
def check_bundle_non_entry_resource_conformance(bundle, error_prefix, ig_semver, validator: :default)
|
|
107
107
|
validation_issues = []
|
|
108
108
|
resource_is_valid?(resource: bundle, profile_url: "http://hl7.org/fhir/us/davinci-crd/StructureDefinition/profile-bundle-base|#{ig_semver}",
|
|
109
|
-
add_messages_to_runnable: false, validator_response_details: validation_issues)
|
|
109
|
+
add_messages_to_runnable: false, validator_response_details: validation_issues, validator:)
|
|
110
110
|
|
|
111
111
|
reject_entry_resource_issues(validation_issues).each do |issue|
|
|
112
112
|
add_message(issue.severity, "#{error_prefix}#{issue.message}")
|