davinci_crd_test_kit 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (341) hide show
  1. checksums.yaml +4 -4
  2. data/config/presets/inferno_crd_client_suite.json.erb +20 -14
  3. data/config/presets/inferno_crd_client_suite_prefetch_subset_v221.json.erb +125 -0
  4. data/config/presets/inferno_crd_client_suite_v221.json.erb +124 -0
  5. data/config/presets/inferno_crd_server_suite.json.erb +58 -1
  6. data/config/presets/inferno_crd_server_suite_v221.json.erb +94 -0
  7. data/config/presets/ri_crd_request_generator.json_v221.json.erb +13 -0
  8. data/config/presets/ri_crd_server.json.erb +19 -19
  9. data/lib/davinci_crd_test_kit/client/client_base_urls.rb +80 -0
  10. data/lib/davinci_crd_test_kit/{client_hook_request_validation.rb → client/client_hook_request_validation.rb} +1 -1
  11. data/lib/davinci_crd_test_kit/client/crd_client_options.rb +30 -0
  12. data/lib/davinci_crd_test_kit/client/endpoints/cds_services_discovery_handler.rb +34 -0
  13. data/lib/davinci_crd_test_kit/client/endpoints/custom_service_response.rb +342 -0
  14. data/lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb +410 -0
  15. data/lib/davinci_crd_test_kit/client/endpoints/hook_request_endpoint.rb +233 -0
  16. data/lib/davinci_crd_test_kit/{mock_service_response.rb → client/endpoints/mock_service_response.rb} +165 -59
  17. data/lib/davinci_crd_test_kit/{card_responses → client/endpoints/mocked_card_responses}/companions_prerequisites.json +1 -0
  18. data/lib/davinci_crd_test_kit/{card_responses → client/endpoints/mocked_card_responses}/create_update_coverage_information.json +3 -2
  19. data/lib/davinci_crd_test_kit/{card_responses → client/endpoints/mocked_card_responses}/launch_smart_app.json +8 -1
  20. data/lib/davinci_crd_test_kit/{card_responses → client/endpoints/mocked_card_responses}/propose_alternate_request.json +1 -0
  21. data/lib/davinci_crd_test_kit/{card_responses → client/endpoints/mocked_card_responses}/request_form_completion.json +17 -16
  22. data/lib/davinci_crd_test_kit/client/multi_request_message_helper.rb +35 -0
  23. data/lib/davinci_crd_test_kit/client/tagged_request_load_helper.rb +38 -0
  24. data/lib/davinci_crd_test_kit/client/v2.0.1/api/client_fhir_api_create_test.rb +43 -0
  25. data/lib/davinci_crd_test_kit/client/v2.0.1/api/client_fhir_api_read_test.rb +43 -0
  26. data/lib/davinci_crd_test_kit/client/v2.0.1/api/client_fhir_api_search_test.rb +234 -0
  27. data/lib/davinci_crd_test_kit/client/v2.0.1/api/client_fhir_api_update_test.rb +43 -0
  28. data/lib/davinci_crd_test_kit/client/v2.0.1/api/client_fhir_api_validation_test.rb +63 -0
  29. data/lib/davinci_crd_test_kit/client/v2.0.1/auth/decode_auth_token_test.rb +65 -0
  30. data/lib/davinci_crd_test_kit/client/v2.0.1/auth/retrieve_jwks_test.rb +109 -0
  31. data/lib/davinci_crd_test_kit/client/v2.0.1/auth/token_header_test.rb +70 -0
  32. data/lib/davinci_crd_test_kit/client/v2.0.1/auth/token_payload_test.rb +85 -0
  33. data/lib/davinci_crd_test_kit/{routes/cds-services.json → client/v2.0.1/cds-services-v201.json} +1 -1
  34. data/lib/davinci_crd_test_kit/client/v2.0.1/client_appointment_book_group.rb +108 -0
  35. data/lib/davinci_crd_test_kit/client/v2.0.1/client_card_must_support_group.rb +31 -0
  36. data/lib/davinci_crd_test_kit/client/v2.0.1/client_encounter_discharge_group.rb +105 -0
  37. data/lib/davinci_crd_test_kit/client/v2.0.1/client_encounter_start_group.rb +105 -0
  38. data/lib/davinci_crd_test_kit/client/v2.0.1/client_fhir_api_group.rb +790 -0
  39. data/lib/davinci_crd_test_kit/client/v2.0.1/client_hooks_group.rb +74 -0
  40. data/lib/davinci_crd_test_kit/client/v2.0.1/client_order_dispatch_group.rb +111 -0
  41. data/lib/davinci_crd_test_kit/client/v2.0.1/client_order_select_group.rb +116 -0
  42. data/lib/davinci_crd_test_kit/client/v2.0.1/client_order_sign_group.rb +113 -0
  43. data/lib/davinci_crd_test_kit/{client_registration_group.rb → client/v2.0.1/client_registration_group.rb} +12 -8
  44. data/lib/davinci_crd_test_kit/client/v2.0.1/client_urls.rb +13 -0
  45. data/lib/davinci_crd_test_kit/client/v2.0.1/crd_client_suite.rb +134 -0
  46. data/lib/davinci_crd_test_kit/client/v2.0.1/invocation/appointment_book_receive_request_test.rb +129 -0
  47. data/lib/davinci_crd_test_kit/client/v2.0.1/invocation/encounter_discharge_receive_request_test.rb +126 -0
  48. data/lib/davinci_crd_test_kit/client/v2.0.1/invocation/encounter_start_receive_request_test.rb +126 -0
  49. data/lib/davinci_crd_test_kit/client/v2.0.1/invocation/order_dispatch_receive_request_test.rb +138 -0
  50. data/lib/davinci_crd_test_kit/client/v2.0.1/invocation/order_select_receive_request_test.rb +134 -0
  51. data/lib/davinci_crd_test_kit/client/v2.0.1/invocation/order_sign_receive_request_test.rb +136 -0
  52. data/lib/davinci_crd_test_kit/client/v2.0.1/must_support/client_card_must_support_coverage_information.rb +93 -0
  53. data/lib/davinci_crd_test_kit/client/v2.0.1/must_support/client_card_must_support_external_reference.rb +62 -0
  54. data/lib/davinci_crd_test_kit/client/v2.0.1/must_support/client_card_must_support_instructions.rb +62 -0
  55. data/lib/davinci_crd_test_kit/client/v2.0.1/registration/client_registration_verification_test.rb +94 -0
  56. data/lib/davinci_crd_test_kit/client/v2.0.1/registration/client_service_registration_attestation_test.rb +40 -0
  57. data/lib/davinci_crd_test_kit/client/v2.0.1/verify_request/hook_request_fetched_data_test.rb +86 -0
  58. data/lib/davinci_crd_test_kit/client/v2.0.1/verify_request/hook_request_optional_fields_test.rb +63 -0
  59. data/lib/davinci_crd_test_kit/client/v2.0.1/verify_request/hook_request_prefetch_equals_queried_test.rb +96 -0
  60. data/lib/davinci_crd_test_kit/client/v2.0.1/verify_request/hook_request_required_fields_test.rb +55 -0
  61. data/lib/davinci_crd_test_kit/client/v2.0.1/verify_request/hook_request_valid_context_test.rb +70 -0
  62. data/lib/davinci_crd_test_kit/client/v2.0.1/verify_request/hook_request_valid_prefetch_test.rb +62 -0
  63. data/lib/davinci_crd_test_kit/client/v2.0.1/verify_response/client_display_cards_attest.rb +83 -0
  64. data/lib/davinci_crd_test_kit/client/v2.0.1/verify_response/inferno_response_validation.rb +79 -0
  65. data/lib/davinci_crd_test_kit/client/v2.2.1/api/client_coverage_info_update_test.rb +212 -0
  66. data/lib/davinci_crd_test_kit/client/v2.2.1/api/client_crd_update_verification_group.rb +18 -0
  67. data/lib/davinci_crd_test_kit/client/v2.2.1/auth/decode_auth_token_test.rb +69 -0
  68. data/lib/davinci_crd_test_kit/client/v2.2.1/auth/retrieve_jwks_test.rb +120 -0
  69. data/lib/davinci_crd_test_kit/client/v2.2.1/auth/token_header_test.rb +92 -0
  70. data/lib/davinci_crd_test_kit/client/v2.2.1/auth/token_payload_test.rb +93 -0
  71. data/lib/davinci_crd_test_kit/client/v2.2.1/cds-services-prefetch-subset-v221.json +198 -0
  72. data/lib/davinci_crd_test_kit/client/v2.2.1/cds-services-v221.json +202 -0
  73. data/lib/davinci_crd_test_kit/client/v2.2.1/client_appointment_book_group.rb +102 -0
  74. data/lib/davinci_crd_test_kit/client/v2.2.1/client_cross_hook_group.rb +28 -0
  75. data/lib/davinci_crd_test_kit/client/v2.2.1/client_encounter_discharge_group.rb +96 -0
  76. data/lib/davinci_crd_test_kit/client/v2.2.1/client_encounter_start_group.rb +95 -0
  77. data/lib/davinci_crd_test_kit/client/v2.2.1/client_fhir_api_group.rb +88 -0
  78. data/lib/davinci_crd_test_kit/client/v2.2.1/client_hooks_group.rb +64 -0
  79. data/lib/davinci_crd_test_kit/client/v2.2.1/client_long_running_hook_group.rb +32 -0
  80. data/lib/davinci_crd_test_kit/client/v2.2.1/client_order_dispatch_group.rb +101 -0
  81. data/lib/davinci_crd_test_kit/client/v2.2.1/client_order_select_group.rb +102 -0
  82. data/lib/davinci_crd_test_kit/client/v2.2.1/client_order_sign_group.rb +107 -0
  83. data/lib/davinci_crd_test_kit/client/v2.2.1/client_registration_group.rb +27 -0
  84. data/lib/davinci_crd_test_kit/client/v2.2.1/client_urls.rb +27 -0
  85. data/lib/davinci_crd_test_kit/client/v2.2.1/crd_client_suite.rb +229 -0
  86. data/lib/davinci_crd_test_kit/client/v2.2.1/cross_hook/client_card_must_support_coverage_information_test.rb +63 -0
  87. data/lib/davinci_crd_test_kit/client/v2.2.1/cross_hook/client_fhirpath_collection_as_comma_delimited_string_test.rb +60 -0
  88. data/lib/davinci_crd_test_kit/client/v2.2.1/cross_hook/client_hook_instances_unique_test.rb +45 -0
  89. data/lib/davinci_crd_test_kit/client/v2.2.1/cross_hook/client_location_address_propagation_test.rb +135 -0
  90. data/lib/davinci_crd_test_kit/client/v2.2.1/cross_hook/client_prefetch_complete_and_subset_test.rb +103 -0
  91. data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/appointment_book_receive_request_test.rb +156 -0
  92. data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/encounter_discharge_receive_request_test.rb +157 -0
  93. data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/encounter_start_receive_request_test.rb +157 -0
  94. data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/order_dispatch_receive_request_test.rb +165 -0
  95. data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/order_select_receive_request_test.rb +165 -0
  96. data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/order_sign_receive_request_test.rb +165 -0
  97. data/lib/davinci_crd_test_kit/client/v2.2.1/long_running/client_long_running_receive_request_test.rb +64 -0
  98. data/lib/davinci_crd_test_kit/client/v2.2.1/long_running/client_skip_long_running_attestation_test.rb +49 -0
  99. data/lib/davinci_crd_test_kit/client/v2.2.1/registration/client_registration_verification_test.rb +161 -0
  100. data/lib/davinci_crd_test_kit/client/v2.2.1/registration/client_service_registration_attestation_test.rb +107 -0
  101. data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_conformance_test.rb +47 -0
  102. data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_coverage_verification_test.rb +152 -0
  103. data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_data_fetch_verification_test.rb +55 -0
  104. data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_granted_scopes_test.rb +123 -0
  105. data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_prefetch_complete_test.rb +127 -0
  106. data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_prefetch_profiles_test.rb +55 -0
  107. data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_requested_version_test.rb +54 -0
  108. data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_secured_transport_test.rb +48 -0
  109. data/lib/davinci_crd_test_kit/client/v2.2.1/verify_response/client_display_cards_attest.rb +74 -0
  110. data/lib/davinci_crd_test_kit/client/v2.2.1/verify_response/hook_response_support_coverage_information_test.rb +30 -0
  111. data/lib/davinci_crd_test_kit/client/v2.2.1/verify_response/inferno_response_validation.rb +77 -0
  112. data/lib/davinci_crd_test_kit/cross_suite/base_urls.rb +20 -0
  113. data/lib/davinci_crd_test_kit/cross_suite/cards_identification.rb +312 -0
  114. data/lib/davinci_crd_test_kit/{cards_validation.rb → cross_suite/cards_validation.rb} +104 -47
  115. data/lib/davinci_crd_test_kit/cross_suite/coverage-information_stu201_metadata.yml +27 -0
  116. data/lib/davinci_crd_test_kit/cross_suite/coverage-information_stu221_metadata.yml +60 -0
  117. data/lib/davinci_crd_test_kit/cross_suite/fhirpath_on_cds_request.rb +177 -0
  118. data/lib/davinci_crd_test_kit/{hook_request_field_validation.rb → cross_suite/hook_request_field_validation.rb} +282 -203
  119. data/lib/davinci_crd_test_kit/cross_suite/logical_models_override_helper.rb +220 -0
  120. data/lib/davinci_crd_test_kit/cross_suite/prefetch_completeness_checker.rb +462 -0
  121. data/lib/davinci_crd_test_kit/cross_suite/prefetch_contents_validation.rb +81 -0
  122. data/lib/davinci_crd_test_kit/cross_suite/prefetch_profile_validation.rb +48 -0
  123. data/lib/davinci_crd_test_kit/cross_suite/profiles_and_resource_types.rb +63 -0
  124. data/lib/davinci_crd_test_kit/cross_suite/replace_tokens.rb +38 -0
  125. data/lib/davinci_crd_test_kit/cross_suite/requests_logical_model_validation.rb +202 -0
  126. data/lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb +274 -0
  127. data/lib/davinci_crd_test_kit/{suggestion_actions_validation.rb → cross_suite/suggestion_actions_validation.rb} +70 -50
  128. data/lib/davinci_crd_test_kit/cross_suite/tags.rb +42 -0
  129. data/lib/davinci_crd_test_kit/metadata.rb +10 -44
  130. data/lib/davinci_crd_test_kit/requirements/cds-hooks-library_1.0.1_requirements.xlsx +0 -0
  131. data/lib/davinci_crd_test_kit/requirements/cds-hooks_2.0_requirements.xlsx +0 -0
  132. data/lib/davinci_crd_test_kit/requirements/cds-hooks_3.0.0-ballot_requirements.xlsx +0 -0
  133. data/lib/davinci_crd_test_kit/requirements/davinci_crd_test_kit_requirements.csv +742 -65
  134. data/lib/davinci_crd_test_kit/requirements/generated/crd_client_requirements_coverage.csv +279 -54
  135. data/lib/davinci_crd_test_kit/requirements/generated/crd_client_v221_requirements_coverage.csv +1430 -0
  136. data/lib/davinci_crd_test_kit/requirements/generated/crd_server_requirements_coverage.csv +36 -45
  137. data/lib/davinci_crd_test_kit/requirements/generated/crd_server_v221_requirements_coverage.csv +143 -0
  138. data/lib/davinci_crd_test_kit/requirements/hl7.fhir.us.davinci-crd_2.0.1_requirements.xlsx +0 -0
  139. data/lib/davinci_crd_test_kit/requirements/hl7.fhir.us.davinci-crd_2.2.1_requirements.xlsx +0 -0
  140. data/lib/davinci_crd_test_kit/server/endpoints/jwk_set_endpoint_handler.rb +13 -0
  141. data/lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_create_endpoint.rb +23 -0
  142. data/lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_delete_endpoint.rb +30 -0
  143. data/lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_metadata_endpoint.rb +112 -0
  144. data/lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_read_endpoint.rb +21 -0
  145. data/lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb +261 -0
  146. data/lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_search_endpoint.rb +561 -0
  147. data/lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_update_endpoint.rb +24 -0
  148. data/lib/davinci_crd_test_kit/server/endpoints/mock_ehr/stress-test-Bundle.json +54687 -0
  149. data/lib/davinci_crd_test_kit/server/endpoints/mock_ehr_endpoints.rb +95 -0
  150. data/lib/davinci_crd_test_kit/server/jobs/invoke_hook.rb +225 -0
  151. data/lib/davinci_crd_test_kit/{jwt_helper.rb → server/jwt_helper.rb} +1 -12
  152. data/lib/davinci_crd_test_kit/server/resource_extractor.rb +68 -0
  153. data/lib/davinci_crd_test_kit/server/server_abstract_invoke_hook_test.rb +165 -0
  154. data/lib/davinci_crd_test_kit/server/server_base_urls.rb +30 -0
  155. data/lib/davinci_crd_test_kit/{server_hook_helper.rb → server/server_hook_helper.rb} +1 -1
  156. data/lib/davinci_crd_test_kit/{server_hook_request_validation.rb → server/server_hook_request_validation.rb} +1 -1
  157. data/lib/davinci_crd_test_kit/{test_helper.rb → server/server_test_helper.rb} +7 -3
  158. data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/Appointment.yml +5 -0
  159. data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/ClaimResponse.yml +5 -0
  160. data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/CommunicationRequest.yml +5 -0
  161. data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/Coverage.yml +21 -0
  162. data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/Device.yml +5 -0
  163. data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/DeviceRequest.yml +5 -0
  164. data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/Encounter.yml +7 -0
  165. data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/Location.yml +5 -0
  166. data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/MedicationRequest.yml +5 -0
  167. data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/NutritionOrder.yml +5 -0
  168. data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/Organization.yml +5 -0
  169. data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/Patient.yml +5 -0
  170. data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/Practitioner.yml +5 -0
  171. data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/PractitionerRole.yml +40 -0
  172. data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/ServiceRequest.yml +5 -0
  173. data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/Task.yml +5 -0
  174. data/lib/davinci_crd_test_kit/server/v2.0.1/crd_metadata/VisionPrescription.yml +5 -0
  175. data/lib/davinci_crd_test_kit/server/v2.0.1/crd_server_suite.rb +99 -0
  176. data/lib/davinci_crd_test_kit/server/v2.0.1/discovery/discovery_endpoint_test.rb +90 -0
  177. data/lib/davinci_crd_test_kit/server/v2.0.1/discovery/discovery_services_validation_test.rb +67 -0
  178. data/lib/davinci_crd_test_kit/server/v2.0.1/interaction/server_invoke_hook_test.rb +12 -0
  179. data/lib/davinci_crd_test_kit/server/v2.0.1/must_support/coverage_information_system_action_across_hooks_validation_test.rb +34 -0
  180. data/lib/davinci_crd_test_kit/server/v2.0.1/must_support/external_reference_card_across_hooks_validation_test.rb +30 -0
  181. data/lib/davinci_crd_test_kit/server/v2.0.1/must_support/instructions_card_received_across_hooks_test.rb +27 -0
  182. data/lib/davinci_crd_test_kit/server/v2.0.1/server_appointment_book_group.rb +191 -0
  183. data/lib/davinci_crd_test_kit/server/v2.0.1/server_demonstrate_hook_response_group.rb +93 -0
  184. data/lib/davinci_crd_test_kit/server/v2.0.1/server_discovery_group.rb +62 -0
  185. data/lib/davinci_crd_test_kit/server/v2.0.1/server_encounter_discharge_group.rb +186 -0
  186. data/lib/davinci_crd_test_kit/server/v2.0.1/server_encounter_start_group.rb +186 -0
  187. data/lib/davinci_crd_test_kit/server/v2.0.1/server_hooks_group.rb +73 -0
  188. data/lib/davinci_crd_test_kit/server/v2.0.1/server_order_dispatch_group.rb +191 -0
  189. data/lib/davinci_crd_test_kit/server/v2.0.1/server_order_select_group.rb +211 -0
  190. data/lib/davinci_crd_test_kit/server/v2.0.1/server_order_sign_group.rb +216 -0
  191. data/lib/davinci_crd_test_kit/server/v2.0.1/server_required_card_response_validation_group.rb +28 -0
  192. data/lib/davinci_crd_test_kit/server/v2.0.1/server_urls.rb +13 -0
  193. data/lib/davinci_crd_test_kit/server/v2.0.1/verify_request/service_request_context_validation_test.rb +30 -0
  194. data/lib/davinci_crd_test_kit/server/v2.0.1/verify_request/service_request_optional_fields_validation_test.rb +39 -0
  195. data/lib/davinci_crd_test_kit/server/v2.0.1/verify_request/service_request_required_fields_validation_test.rb +40 -0
  196. data/lib/davinci_crd_test_kit/server/v2.0.1/verify_response/additional_orders_validation_test.rb +59 -0
  197. data/lib/davinci_crd_test_kit/server/v2.0.1/verify_response/card_optional_fields_validation_test.rb +51 -0
  198. data/lib/davinci_crd_test_kit/server/v2.0.1/verify_response/coverage_information_system_action_received_test.rb +65 -0
  199. data/lib/davinci_crd_test_kit/server/v2.0.1/verify_response/coverage_information_system_action_validation_test.rb +120 -0
  200. data/lib/davinci_crd_test_kit/server/v2.0.1/verify_response/create_or_update_coverage_info_response_validation_test.rb +70 -0
  201. data/lib/davinci_crd_test_kit/server/v2.0.1/verify_response/external_reference_card_validation_test.rb +37 -0
  202. data/lib/davinci_crd_test_kit/server/v2.0.1/verify_response/form_completion_response_validation_test.rb +67 -0
  203. data/lib/davinci_crd_test_kit/server/v2.0.1/verify_response/instructions_card_received_test.rb +30 -0
  204. data/lib/davinci_crd_test_kit/server/v2.0.1/verify_response/launch_smart_app_card_validation_test.rb +39 -0
  205. data/lib/davinci_crd_test_kit/server/v2.0.1/verify_response/propose_alternate_request_card_validation_test.rb +46 -0
  206. data/lib/davinci_crd_test_kit/server/v2.0.1/verify_response/service_response_validation_test.rb +83 -0
  207. data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/Appointment_withorder.yml +5 -0
  208. data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/Appointment_withoutorder.yml +5 -0
  209. data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/CommunicationRequest.yml +5 -0
  210. data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/Coverage.yml +5 -0
  211. data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/Device.yml +5 -0
  212. data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/DeviceRequest.yml +5 -0
  213. data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/Encounter.yml +5 -0
  214. data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/Location.yml +5 -0
  215. data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/MedicationRequest.yml +5 -0
  216. data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/NutritionOrder.yml +5 -0
  217. data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/Organization.yml +5 -0
  218. data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/Patient.yml +5 -0
  219. data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/PractitionerRole.yml +5 -0
  220. data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/ServiceRequest.yml +5 -0
  221. data/lib/davinci_crd_test_kit/server/v2.2.1/crd_metadata/VisionPrescription.yml +5 -0
  222. data/lib/davinci_crd_test_kit/server/v2.2.1/crd_server_suite.rb +115 -0
  223. data/lib/davinci_crd_test_kit/server/v2.2.1/discovery/discovery_configuration_test.rb +159 -0
  224. data/lib/davinci_crd_test_kit/server/v2.2.1/discovery/discovery_endpoint_test.rb +90 -0
  225. data/lib/davinci_crd_test_kit/server/v2.2.1/discovery/discovery_prefetch_support_test.rb +43 -0
  226. data/lib/davinci_crd_test_kit/server/v2.2.1/discovery/discovery_services_validation_test.rb +121 -0
  227. data/lib/davinci_crd_test_kit/server/v2.2.1/interaction/server_invoke_hook_test.rb +17 -0
  228. data/lib/davinci_crd_test_kit/server/v2.2.1/must_support/coverage_information_must_support_test.rb +71 -0
  229. data/lib/davinci_crd_test_kit/server/v2.2.1/must_support/coverage_information_system_action_across_hooks_validation_test.rb +36 -0
  230. data/lib/davinci_crd_test_kit/server/v2.2.1/must_support/supported_us_core_versions_test.rb +118 -0
  231. data/lib/davinci_crd_test_kit/server/v2.2.1/server_appointment_book_group.rb +213 -0
  232. data/lib/davinci_crd_test_kit/server/v2.2.1/server_demonstrate_hook_response_group.rb +93 -0
  233. data/lib/davinci_crd_test_kit/server/v2.2.1/server_discovery_group.rb +69 -0
  234. data/lib/davinci_crd_test_kit/server/v2.2.1/server_encounter_discharge_group.rb +194 -0
  235. data/lib/davinci_crd_test_kit/server/v2.2.1/server_encounter_start_group.rb +194 -0
  236. data/lib/davinci_crd_test_kit/server/v2.2.1/server_hooks_group.rb +73 -0
  237. data/lib/davinci_crd_test_kit/server/v2.2.1/server_order_dispatch_group.rb +214 -0
  238. data/lib/davinci_crd_test_kit/server/v2.2.1/server_order_select_group.rb +219 -0
  239. data/lib/davinci_crd_test_kit/server/v2.2.1/server_order_sign_group.rb +241 -0
  240. data/lib/davinci_crd_test_kit/server/v2.2.1/server_required_card_response_validation_group.rb +30 -0
  241. data/lib/davinci_crd_test_kit/server/v2.2.1/server_urls.rb +13 -0
  242. data/lib/davinci_crd_test_kit/server/v2.2.1/verify_request/service_request_context_validation_test.rb +30 -0
  243. data/lib/davinci_crd_test_kit/server/v2.2.1/verify_request/service_request_no_custom_extensions_test.rb +120 -0
  244. data/lib/davinci_crd_test_kit/server/v2.2.1/verify_request/service_request_optional_fields_validation_test.rb +39 -0
  245. data/lib/davinci_crd_test_kit/server/v2.2.1/verify_request/service_request_required_fields_validation_test.rb +40 -0
  246. data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/additional_orders_validation_test.rb +66 -0
  247. data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/all_responses_include_coverage_information_test.rb +123 -0
  248. data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/card_optional_fields_validation_test.rb +57 -0
  249. data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/coverage_info_configuration_test.rb +83 -0
  250. data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/coverage_information_system_action_received_test.rb +65 -0
  251. data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/coverage_information_system_action_validation_test.rb +184 -0
  252. data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/create_or_update_coverage_info_response_validation_test.rb +75 -0
  253. data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/external_reference_card_validation_test.rb +47 -0
  254. data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/form_completion_response_validation_test.rb +91 -0
  255. data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/hook_request_resource_resolution.rb +137 -0
  256. data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/instructions_card_received_test.rb +32 -0
  257. data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/launch_smart_app_card_validation_test.rb +49 -0
  258. data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/order_dispatch_coverage_information_test.rb +38 -0
  259. data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/propose_alternate_request_card_validation_test.rb +54 -0
  260. data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/service_response_validation_test.rb +97 -0
  261. data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/unknown_cds_hooks_elements_test.rb +78 -0
  262. data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/unknown_configuration_test.rb +78 -0
  263. data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/unknown_context_test.rb +78 -0
  264. data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/verify_response_without_billing_options_test.rb +43 -0
  265. data/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/verify_response_without_configuration_test.rb +44 -0
  266. data/lib/davinci_crd_test_kit/version.rb +2 -2
  267. data/lib/davinci_crd_test_kit.rb +4 -2
  268. metadata +297 -93
  269. data/lib/davinci_crd_test_kit/client_fhir_api_group.rb +0 -785
  270. data/lib/davinci_crd_test_kit/client_hooks_group.rb +0 -74
  271. data/lib/davinci_crd_test_kit/client_tests/appointment_book_receive_request_test.rb +0 -93
  272. data/lib/davinci_crd_test_kit/client_tests/client_appointment_book_group.rb +0 -75
  273. data/lib/davinci_crd_test_kit/client_tests/client_display_cards_attest.rb +0 -48
  274. data/lib/davinci_crd_test_kit/client_tests/client_encounter_discharge_group.rb +0 -73
  275. data/lib/davinci_crd_test_kit/client_tests/client_encounter_start_group.rb +0 -73
  276. data/lib/davinci_crd_test_kit/client_tests/client_fhir_api_create_test.rb +0 -42
  277. data/lib/davinci_crd_test_kit/client_tests/client_fhir_api_read_test.rb +0 -40
  278. data/lib/davinci_crd_test_kit/client_tests/client_fhir_api_search_test.rb +0 -232
  279. data/lib/davinci_crd_test_kit/client_tests/client_fhir_api_update_test.rb +0 -42
  280. data/lib/davinci_crd_test_kit/client_tests/client_fhir_api_validation_test.rb +0 -61
  281. data/lib/davinci_crd_test_kit/client_tests/client_order_dispatch_group.rb +0 -79
  282. data/lib/davinci_crd_test_kit/client_tests/client_order_select_group.rb +0 -82
  283. data/lib/davinci_crd_test_kit/client_tests/client_order_sign_group.rb +0 -81
  284. data/lib/davinci_crd_test_kit/client_tests/client_registration_verification_test.rb +0 -88
  285. data/lib/davinci_crd_test_kit/client_tests/decode_auth_token_test.rb +0 -60
  286. data/lib/davinci_crd_test_kit/client_tests/encounter_discharge_receive_request_test.rb +0 -90
  287. data/lib/davinci_crd_test_kit/client_tests/encounter_start_receive_request_test.rb +0 -90
  288. data/lib/davinci_crd_test_kit/client_tests/hook_request_optional_fields_test.rb +0 -57
  289. data/lib/davinci_crd_test_kit/client_tests/hook_request_required_fields_test.rb +0 -49
  290. data/lib/davinci_crd_test_kit/client_tests/hook_request_valid_context_test.rb +0 -68
  291. data/lib/davinci_crd_test_kit/client_tests/hook_request_valid_prefetch_test.rb +0 -69
  292. data/lib/davinci_crd_test_kit/client_tests/order_dispatch_receive_request_test.rb +0 -102
  293. data/lib/davinci_crd_test_kit/client_tests/order_select_receive_request_test.rb +0 -98
  294. data/lib/davinci_crd_test_kit/client_tests/order_sign_receive_request_test.rb +0 -101
  295. data/lib/davinci_crd_test_kit/client_tests/retrieve_jwks_test.rb +0 -105
  296. data/lib/davinci_crd_test_kit/client_tests/submitted_response_validation.rb +0 -48
  297. data/lib/davinci_crd_test_kit/client_tests/token_header_test.rb +0 -65
  298. data/lib/davinci_crd_test_kit/client_tests/token_payload_test.rb +0 -78
  299. data/lib/davinci_crd_test_kit/crd_client_suite.rb +0 -193
  300. data/lib/davinci_crd_test_kit/crd_options.rb +0 -9
  301. data/lib/davinci_crd_test_kit/crd_server_suite.rb +0 -125
  302. data/lib/davinci_crd_test_kit/igs/davinci-crd-2.0.1.tgz +0 -0
  303. data/lib/davinci_crd_test_kit/routes/cds_services_discovery_handler.rb +0 -18
  304. data/lib/davinci_crd_test_kit/routes/hook_request_endpoint.rb +0 -77
  305. data/lib/davinci_crd_test_kit/routes/jwk_set_endpoint_handler.rb +0 -15
  306. data/lib/davinci_crd_test_kit/server_appointment_book_group.rb +0 -176
  307. data/lib/davinci_crd_test_kit/server_demonstrate_hook_response_group.rb +0 -77
  308. data/lib/davinci_crd_test_kit/server_discovery_group.rb +0 -60
  309. data/lib/davinci_crd_test_kit/server_encounter_discharge_group.rb +0 -170
  310. data/lib/davinci_crd_test_kit/server_encounter_start_group.rb +0 -170
  311. data/lib/davinci_crd_test_kit/server_hooks_group.rb +0 -71
  312. data/lib/davinci_crd_test_kit/server_order_dispatch_group.rb +0 -176
  313. data/lib/davinci_crd_test_kit/server_order_select_group.rb +0 -195
  314. data/lib/davinci_crd_test_kit/server_order_sign_group.rb +0 -201
  315. data/lib/davinci_crd_test_kit/server_required_card_response_validation_group.rb +0 -26
  316. data/lib/davinci_crd_test_kit/server_tests/additional_orders_validation_test.rb +0 -68
  317. data/lib/davinci_crd_test_kit/server_tests/card_optional_fields_validation_test.rb +0 -47
  318. data/lib/davinci_crd_test_kit/server_tests/coverage_information_system_action_across_hooks_validation_test.rb +0 -32
  319. data/lib/davinci_crd_test_kit/server_tests/coverage_information_system_action_received_test.rb +0 -63
  320. data/lib/davinci_crd_test_kit/server_tests/coverage_information_system_action_validation_test.rb +0 -118
  321. data/lib/davinci_crd_test_kit/server_tests/create_or_update_coverage_info_response_validation_test.rb +0 -71
  322. data/lib/davinci_crd_test_kit/server_tests/discovery_endpoint_test.rb +0 -88
  323. data/lib/davinci_crd_test_kit/server_tests/discovery_services_validation_test.rb +0 -65
  324. data/lib/davinci_crd_test_kit/server_tests/external_reference_card_across_hooks_validation_test.rb +0 -28
  325. data/lib/davinci_crd_test_kit/server_tests/external_reference_card_validation_test.rb +0 -36
  326. data/lib/davinci_crd_test_kit/server_tests/form_completion_response_validation_test.rb +0 -78
  327. data/lib/davinci_crd_test_kit/server_tests/instructions_card_received_across_hooks_test.rb +0 -25
  328. data/lib/davinci_crd_test_kit/server_tests/instructions_card_received_test.rb +0 -26
  329. data/lib/davinci_crd_test_kit/server_tests/launch_smart_app_card_validation_test.rb +0 -38
  330. data/lib/davinci_crd_test_kit/server_tests/propose_alternate_request_card_validation_test.rb +0 -63
  331. data/lib/davinci_crd_test_kit/server_tests/service_call_test.rb +0 -101
  332. data/lib/davinci_crd_test_kit/server_tests/service_request_context_validation_test.rb +0 -28
  333. data/lib/davinci_crd_test_kit/server_tests/service_request_optional_fields_validation_test.rb +0 -37
  334. data/lib/davinci_crd_test_kit/server_tests/service_request_required_fields_validation_test.rb +0 -38
  335. data/lib/davinci_crd_test_kit/server_tests/service_response_validation_test.rb +0 -81
  336. data/lib/davinci_crd_test_kit/tags.rb +0 -10
  337. data/lib/davinci_crd_test_kit/urls.rb +0 -52
  338. /data/lib/davinci_crd_test_kit/{card_responses → client/endpoints/mocked_card_responses}/external_reference.json +0 -0
  339. /data/lib/davinci_crd_test_kit/{card_responses → client/endpoints/mocked_card_responses}/instructions.json +0 -0
  340. /data/lib/davinci_crd_test_kit/{crd_jwks.json → server/endpoints/crd_jwks.json} +0 -0
  341. /data/lib/davinci_crd_test_kit/{jwks.rb → server/endpoints/jwks.rb} +0 -0
@@ -0,0 +1,96 @@
1
+ require_relative '../../../cross_suite/prefetch_contents_validation'
2
+
3
+ module DaVinciCRDTestKit
4
+ module V201
5
+ class HookRequestPrefetchEqualsQueriedTest < Inferno::Test
6
+ include PrefetchContentsValidation
7
+
8
+ id :crd_v201_hook_request_prefetch_equals_queried
9
+ title 'Prefetched data is equivalent to queried data'
10
+ description %(
11
+ This test verifies that each key present in the incoming hook request's `prefetch` field is equivalent to the
12
+ data returned by a query to the fhir server using the parameterized prefetch template.
13
+
14
+ The queries will be performed after the hook response has been returned.
15
+ )
16
+ verifies_requirements 'cds-hooks_2.0@45'
17
+
18
+ input :client_fhir_server,
19
+ optional: true
20
+ input :client_access_token,
21
+ optional: true
22
+ input :override_access_token,
23
+ title: 'Prefetch Validation Override Bearer Token',
24
+ description: %(
25
+ Optionally provide a bearer token to use in place of the one provided in the hook request
26
+ when checking that the prefetched data is equivalent to what can be access via FHIR.
27
+ Use only if the bearer token in the request will not be valid even right after the hook
28
+ request is made. If provided it must have the same scope as the bearer token provided
29
+ in the hook request.
30
+ ),
31
+ optional: true
32
+
33
+ fhir_client do
34
+ url :client_fhir_server
35
+ bearer_token access_token
36
+ end
37
+
38
+ def access_token
39
+ override_access_token.present? ? override_access_token : client_access_token
40
+ end
41
+
42
+ def hook_name
43
+ config.options[:hook_name]
44
+ end
45
+
46
+ def crd_test_group
47
+ config.options[:crd_test_group]
48
+ end
49
+
50
+ def tags_to_load
51
+ crd_test_group.present? ? [hook_name, crd_test_group] : [hook_name]
52
+ end
53
+
54
+ def cds_services_json
55
+ JSON.parse(File.read(File.join(
56
+ __dir__, '..', 'cds-services-v201.json'
57
+ )))['services']
58
+ end
59
+
60
+ def advertised_prefetch_fields
61
+ advertised_hook_service = cds_services_json.find { |service| service['hook'] == hook_name }
62
+ advertised_hook_service['prefetch']
63
+ end
64
+
65
+ def no_error_validation(message)
66
+ assert messages.none? { |msg| msg[:type] == 'error' }, message
67
+ end
68
+
69
+ run do
70
+ hook_requests = load_tagged_requests(*tags_to_load)
71
+
72
+ skip_if hook_requests.blank?, 'No Hook Requests to verify.'
73
+
74
+ pass_if !prefetched_data?(hook_requests), 'No prefetched data provided.'
75
+
76
+ skip_if client_fhir_server.blank?,
77
+ 'No FHIR server provided in the hook request to use to validate the prefetch data.'
78
+
79
+ if override_access_token.present?
80
+ add_message(:warning,
81
+ 'Override access token provided. Ensure that it has the same scope as used when ' \
82
+ 'prefetching data for the hook request.')
83
+ end
84
+
85
+ hook_requests.each_with_index do |request, index|
86
+ @request_number = index + 1
87
+ check_prefetch_data_against_query(request, advertised_prefetch_fields)
88
+ end
89
+
90
+ no_error_validation('Prefetched data does not match the requested queries.')
91
+
92
+ pass 'Prefetched data matches the requested queries.'
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,55 @@
1
+ require_relative '../../client_hook_request_validation'
2
+ require_relative '../client_urls'
3
+
4
+ module DaVinciCRDTestKit
5
+ module V201
6
+ class HookRequestRequiredFieldsTest < Inferno::Test
7
+ include ClientHookRequestValidation
8
+ include ClientURLs
9
+
10
+ id :crd_v201_hook_request_required_fields
11
+ title 'Hook request contains required fields'
12
+ description %(
13
+ Under the [CDS hooks HTTP Request section](https://cds-hooks.hl7.org/2.0/#http-request_1), the specification
14
+ requires that a CDS service request SHALL include a JSON POST body with the following input fields:
15
+ * `hook` - *string*
16
+ * `hookInstance` - *string* containing a globally unique UUID
17
+ * `context` - *object*
18
+
19
+ Additionally, if the optional `fhirAuthorization` field is present, then the `fhirServer` field is required.
20
+
21
+ This test also checks that the `hook` field contains the correct CDS service name that the CDS client
22
+ is sending a request for
23
+ )
24
+
25
+ verifies_requirements 'cds-hooks_2.0@1', 'cds-hooks_2.0@18', 'cds-hooks_2.0@19',
26
+ 'cds-hooks_2.0@20', 'cds-hooks_2.0@22', 'cds-hooks_2.0@25'
27
+
28
+ def hook_name
29
+ config.options[:hook_name]
30
+ end
31
+
32
+ output :contexts, :prefetches
33
+
34
+ run do
35
+ load_tagged_requests(hook_name)
36
+ skip_if requests.empty?, "No #{hook_name} requests were made in a previous test as expected."
37
+ contexts = []
38
+ prefetches = []
39
+ requests.each_with_index do |request, index|
40
+ @request_number = index + 1
41
+ request_body = json_parse(request.request_body)
42
+ next if request_body.blank?
43
+
44
+ contexts << request_body['context'] if request_body['context'].is_a?(Hash)
45
+ prefetches << request_body['prefetch'] if request_body['prefetch'].is_a?(Hash)
46
+ hook_request_required_fields_check(request_body, hook_name, ig_version: 'v201')
47
+ end
48
+
49
+ output contexts: contexts.to_json,
50
+ prefetches: prefetches.to_json
51
+ no_error_validation('Some service requests made are not valid.')
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,70 @@
1
+ require_relative '../../client_hook_request_validation'
2
+ require_relative '../client_urls'
3
+
4
+ module DaVinciCRDTestKit
5
+ module V201
6
+ class HookRequestValidContextTest < Inferno::Test
7
+ include ClientURLs
8
+ include ClientHookRequestValidation
9
+
10
+ id :crd_v201_hook_request_valid_context
11
+ title 'Hook request contains valid context'
12
+ description %(
13
+ As stated in the [CDS hooks specification](https://cds-hooks.hl7.org/2.0#http-request), a CDS service request's
14
+ `context` field contains hook-specific contextual data that the CDS service will need. The context is
15
+ specified in the hook definition to guide developers on the information available at the point in the
16
+ workflow when the hook is triggered.
17
+
18
+ The `context` requirements for each [hook specified in the CRD IG](https://hl7.org/fhir/us/davinci-crd/STU2/hooks.html)
19
+ can be found below:
20
+ * [appointment-book](https://cds-hooks.hl7.org/hooks/appointment-book/2023SepSTU1Ballot/appointment-book/)
21
+ * [encounter-start](https://cds-hooks.hl7.org/hooks/encounter-start/2023SepSTU1Ballot/encounter-start/)
22
+ * [encounter-discharge](https://cds-hooks.hl7.org/hooks/encounter-discharge/2023SepSTU1Ballot/encounter-discharge/)
23
+ * [order-select](https://cds-hooks.hl7.org/hooks/order-select/2023SepSTU1Ballot/order-select/)
24
+ * [order-dispatch](https://cds-hooks.hl7.org/hooks/order-dispatch/2023SepSTU1Ballot/order-dispatch/)
25
+ * [order-sign](https://cds-hooks.org/hooks/order-sign/)
26
+
27
+ This test performs the following:
28
+ * Verifies that the incoming hook request's `context` field contains the fields required by each hook and
29
+ that they are in the correct format
30
+ * Checks the optional fields and ensures they are in the correct format
31
+ * Validates any resources contained in a `context` field that contains a Bundle or FHIR resource
32
+ * Makes FHIR requests for any `context` fields that contain an id or reference and validates each resource
33
+ response against its corresponding CRD resource profile
34
+ * Check some specific `context` requirements for hooks that have special requirements for certain fields
35
+
36
+ The client must provide its FHIR server URL and access token in the hook request in order to run
37
+ this test.
38
+ )
39
+
40
+ input :contexts, :client_fhir_server
41
+ input :client_access_token,
42
+ optional: true
43
+
44
+ fhir_client do
45
+ url :client_fhir_server
46
+ bearer_token :client_access_token
47
+ end
48
+
49
+ def hook_name
50
+ config.options[:hook_name]
51
+ end
52
+
53
+ run do
54
+ hook_contexts = json_parse(contexts)
55
+ if hook_contexts
56
+ skip_if(hook_contexts.none?(&:present?), "No #{hook_name} requests contained the `context` field.")
57
+ hook_contexts.each_with_index do |context, index|
58
+ @request_number = index + 1
59
+ if context.blank?
60
+ add_message('error', "#{request_number}Missing required context field.")
61
+ next
62
+ end
63
+ hook_request_context_check(context, hook_name, ig_version: 'v201')
64
+ end
65
+ end
66
+ no_error_validation('Context is not valid.')
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,62 @@
1
+ require_relative '../../client_hook_request_validation'
2
+ require_relative '../client_urls'
3
+
4
+ module DaVinciCRDTestKit
5
+ module V201
6
+ class HookRequestValidPrefetchTest < Inferno::Test
7
+ include ClientHookRequestValidation
8
+ include ClientURLs
9
+
10
+ id :crd_v201_hook_request_valid_prefetch
11
+ title 'Hook request contains valid prefetched data'
12
+ description %(
13
+ As stated in the [CDS hooks specification](https://cds-hooks.hl7.org/2.0#http-request), a CDS service request's
14
+ `prefetch` field is an optional field that contains key/value pairs of FHIR queries that the service is
15
+ requesting the CDS client to perform and provide on each service call. The key is a string that describes
16
+ the type of data being requested and the value is a string representing the FHIR query.
17
+ See [Prefetch Template](https://cds-hooks.hl7.org/2.0#prefetch-template)
18
+ for more information about how the `prefetch` formatting works.
19
+
20
+ This test verifies that the incoming hook request's `prefetch` field is in a valid JSON format,
21
+ validates each contained resource against its corresponding CRD resource profile, and checks
22
+ that the data matches what is requested in by the
23
+ [prefetch templates published by Inferno's simulated CRD server](https://github.com/inferno-framework/davinci-crd-test-kit/blob/main/lib/davinci_crd_test_kit/client/v2.0.1/cds-services-v201.json).
24
+ Since prefetch support is not required, this test will pass if `prefetch` is not present or has no entries.
25
+ )
26
+ verifies_requirements 'hl7.fhir.us.davinci-crd_2.0.1@54', 'cds-hooks_2.0@30', 'cds-hooks_2.0@47'
27
+
28
+ input :contexts, :prefetches
29
+
30
+ def hook_name
31
+ config.options[:hook_name]
32
+ end
33
+
34
+ def cds_services_json
35
+ JSON.parse(File.read(File.join(
36
+ __dir__, '..', 'cds-services-v201.json'
37
+ )))['services']
38
+ end
39
+
40
+ def advertised_prefetch_fields
41
+ advertised_hook_service = cds_services_json.find { |service| service['hook'] == hook_name }
42
+ advertised_hook_service['prefetch']
43
+ end
44
+
45
+ run do
46
+ hook_contexts = json_parse(contexts)
47
+ hook_prefetches = json_parse(prefetches)
48
+
49
+ pass_if hook_prefetches.blank?, 'No prefetched data provided.'
50
+
51
+ hook_prefetches.each_with_index do |prefetch, index|
52
+ next if prefetch.blank?
53
+
54
+ @request_number = index + 1
55
+ context = hook_contexts[index].present? ? hook_contexts[index] : {}
56
+ hook_request_prefetch_check(advertised_prefetch_fields, prefetch, context, ig_version: 'v201')
57
+ end
58
+ no_error_validation('Prefetch is not valid.')
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,83 @@
1
+ require_relative '../client_urls'
2
+ require_relative '../../../cross_suite/cards_identification'
3
+
4
+ module DaVinciCRDTestKit
5
+ module V201
6
+ class ClientCardDisplayAttest < Inferno::Test
7
+ include ClientURLs
8
+ include CardsIdentification
9
+
10
+ id :crd_v201_card_display_attest_test
11
+ title 'Check that returned decision support details are displayed to the user'
12
+ description %(
13
+ Since Inferno has no way to evaluate the client's UI, testers must manually
14
+ verify that the cards and system actions returned by Inferno are presented
15
+ to the user in an appopriate way that allows for consideration and action
16
+ if warranted.
17
+ )
18
+
19
+ def hook_name
20
+ config.options[:hook_name]
21
+ end
22
+
23
+ def crd_test_group
24
+ config.options[:crd_test_group]
25
+ end
26
+
27
+ def tags_to_load
28
+ crd_test_group.present? ? [hook_name, crd_test_group] : [hook_name]
29
+ end
30
+
31
+ def responded_card_types
32
+ list_card_types_in_requests(requests)
33
+ end
34
+
35
+ def format_responded_response_types
36
+ responded_card_types
37
+ .map do |response_type|
38
+ response_type_string =
39
+ response_type.split('_')
40
+ .map(&:capitalize)
41
+ .join(' ')
42
+ .prepend('- ')
43
+ .sub('Smart', 'SMART')
44
+ .sub('Create Update', 'Create/Update')
45
+ .sub('Companions Prerequisites', 'Companions/Prerequisites')
46
+ .sub('Card', '(card)')
47
+ .sub('Action', '(systemAction)')
48
+ response_type_string
49
+ end
50
+ .join("\n")
51
+ end
52
+
53
+ output :attest_true_url
54
+ output :attest_false_url
55
+
56
+ run do
57
+ load_tagged_requests(*tags_to_load)
58
+ skip_if responded_card_types.blank?, 'No responses sent to the client.'
59
+
60
+ identifier = SecureRandom.hex(32)
61
+ attest_true_url = "#{resume_pass_url}?token=#{identifier}"
62
+ attest_false_url = "#{resume_fail_url}?token=#{identifier}"
63
+ output(attest_true_url:)
64
+ output(attest_false_url:)
65
+ wait(
66
+ identifier:,
67
+ message: <<~MESSAGE
68
+ **Card Display Attestation**:
69
+
70
+ I attest that the following CDS response types returned were processed by the
71
+ client system and displayed to the user:
72
+
73
+ #{format_responded_response_types}
74
+
75
+ [Click here](#{attest_true_url}) if the above statement is **true**.
76
+
77
+ [Click here](#{attest_false_url}) if the above statement is **false**.
78
+ MESSAGE
79
+ )
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,79 @@
1
+ require_relative '../../../cross_suite/cards_validation'
2
+
3
+ module DaVinciCRDTestKit
4
+ module V201
5
+ class InfernoResponseValidationTest < Inferno::Test
6
+ include CardsValidation
7
+
8
+ title 'Inferno CDS Service Response is Conformant'
9
+ description %(
10
+ This test verifies that each service response built by Inferno and returned to the client is conformant.
11
+ These responses must be conformant for the client to demonstrate its ability to accept CDS Service responses.
12
+
13
+ If this test fails when a custom response was provided, adjust the custom response template
14
+ and the submitted requests so that the response built by Inferno is conformant. See
15
+ the documentation for details on how Inferno builds a response from the provided
16
+ custom template.
17
+
18
+ If this test fails when Inferno mocked the response based on selected card types, please
19
+ report this failure to the Inferno team via github issues.
20
+ )
21
+ id :crd_v201_inferno_response_validation
22
+
23
+ input :custom_response_template, optional: true
24
+
25
+ def hook_name
26
+ config.options[:hook_name]
27
+ end
28
+
29
+ def crd_test_group
30
+ config.options[:crd_test_group]
31
+ end
32
+
33
+ def tags_to_load
34
+ crd_test_group.present? ? [hook_name, crd_test_group] : [hook_name]
35
+ end
36
+
37
+ def response_label(index = nil)
38
+ response_type = (custom_response_template.present? ? 'Custom built' : 'Mocked')
39
+ "#{response_type} response#{" #{index}" if index.present?}"
40
+ end
41
+
42
+ def valid_cards
43
+ @valid_cards ||= []
44
+ end
45
+
46
+ def validate_system_actions(system_actions)
47
+ return if system_actions.nil?
48
+
49
+ system_actions.each do |action|
50
+ action_fields_validation(action, ig_version: 'v201')
51
+ end
52
+ end
53
+
54
+ run do
55
+ load_tagged_requests(*tags_to_load)
56
+
57
+ skip_if request.blank?, "No #{response_label.downcase}s to verify."
58
+
59
+ entity_validated = false
60
+ requests.each_with_index do |request, index|
61
+ response_hash = JSON.parse(request.response_body)
62
+
63
+ next unless response_hash['cards'].present? || response_hash['systemActions'].present?
64
+
65
+ entity_validated = true
66
+ perform_cards_validation(response_hash['cards'], response_hash['systemActions'].present?, 'v201', index)
67
+ validate_system_actions(response_hash['systemActions'])
68
+ rescue JSON::ParserError
69
+ next
70
+ end
71
+
72
+ skip_if !entity_validated,
73
+ "No #{response_label.downcase} cards or system actions to verify returned by Inferno."
74
+
75
+ no_error_validation("Invalid Inferno #{response_label.downcase}(s). Check messages for issues found.")
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,212 @@
1
+ require_relative '../../../cross_suite/cards_identification'
2
+ require_relative '../../tagged_request_load_helper'
3
+
4
+ module DaVinciCRDTestKit
5
+ module V221
6
+ class ClientCoverageInfoUpdateTest < Inferno::Test
7
+ include CardsIdentification
8
+ include TaggedRequestLoadHelper
9
+
10
+ title "Client's FHIR server stores updates from coverage-information responses"
11
+ id :crd_v221_client_coverage_info_update
12
+ description <<~DESCRIPTION
13
+ This test verifies that when the client receives a [Coverage Information response type](https://hl7.org/fhir/us/davinci-crd/2.2.1/en/cards.html#coverage-information-response-type),
14
+ it stores the [coverage-information extension](https://hl7.org/fhir/us/davinci-crd/2.2.1/en/StructureDefinition-ext-coverage-information.html)
15
+ and makes it available when accessing the associated resource.
16
+
17
+ During this test, Inferno will find all [Coverage Information responses](https://hl7.org/fhir/us/davinci-crd/2.2.1/en/cards.html#coverage-information-response-type),
18
+ attempt to read the updated FHIR resource from the client's FHIR server, and verify
19
+ that the [coverage-information extension](https://hl7.org/fhir/us/davinci-crd/2.2.1/en/StructureDefinition-ext-coverage-information.html)
20
+ in the response is now present in the returned resource. When comparing the
21
+ [coverage-information extension](https://hl7.org/fhir/us/davinci-crd/2.2.1/en/StructureDefinition-ext-coverage-information.html)
22
+ in the response with what is returned from the client FHIR server, Inferno
23
+ expects that client stores and exposes the extension without modification, meaning
24
+ that the exact set of sub-extensions in the response and their values are present
25
+ in the stored version.
26
+
27
+ Inferno will not always be able to perform this check. CRD clients are not required
28
+ to expose FHIR read APIs for all request resource types, so resource types for which
29
+ the client's CapabilityStatement does not indicate read interaction support will be omitted.
30
+ Additionally, Inferno will not check complex cases where determining the expected
31
+ stored extensions is difficult. For example, when there are multiple Coverage Information
32
+ responses for a single resource or multiple coverage-information extensions in a
33
+ single Coverage Information response. Implementers are still responsible for storing updates
34
+ in these cases. To pass this test at least one target resource that Inferno can access must be found.
35
+ The stored [coverage-information extension](https://hl7.org/fhir/us/davinci-crd/2.2.1/en/StructureDefinition-ext-coverage-information.html)
36
+ must be correct for all resources checked by Inferno.
37
+ DESCRIPTION
38
+
39
+ verifies_requirements 'hl7.fhir.us.davinci-crd_2.2.1@found-36-B', 'hl7.fhir.us.davinci-crd_2.2.1@resp-46'
40
+
41
+ uses_request :capability_statement
42
+
43
+ run do
44
+ supported_resource_types = extract_supported_resource_types(resource) # extract before loading other requests
45
+
46
+ loaded_requests = requests_to_analyze # all requests for one hook or all requests for all hooks
47
+ skip_if loaded_requests.blank?, 'No hook requests found, run hook tests first.'
48
+
49
+ resources_to_check, unsupported = find_coverage_info_responses(loaded_requests)
50
+ .partition { |request_details| supported_resource_types.include?(request_details[:resource_type]) }
51
+ unsupported.each do |request_details|
52
+ add_message('info', "#{error_prefix(request_details)}Resource type #{request_details[:resource_type]} " \
53
+ 'is not supported by the client\'s FHIR API. This resource will not be verified.')
54
+ end
55
+ skip_if resources_to_check.blank?,
56
+ 'No coverage-info responses found that Inferno could verify: ' \
57
+ 're-run hook tests generating responses that Inferno can verify.'
58
+
59
+ resources_to_check.each do |resource_details|
60
+ check_for_stored_coverage_information_extension(resource_details)
61
+ end
62
+
63
+ assert_no_error_messages('Not all coverage-information extensions stored. See Messages for details.')
64
+ end
65
+
66
+ # important information to record:
67
+ # - relative resource reference (resource type + id)
68
+ # - coverage-information extension
69
+ # - position (response index + systemAction index)
70
+ def find_coverage_info_responses(requests)
71
+ all_responses = requests.flat_map.with_index do |request, request_index|
72
+ find_coverage_info_actions_in_response(request, request_index)
73
+ end
74
+
75
+ all_responses.group_by { |resource_details| [resource_details[:resource_type], resource_details[:target_id]] }
76
+ .filter_map do |(_type, _id), entries|
77
+ if entries.size > 1
78
+ add_message('info',
79
+ "#{error_prefix(entries.first)}Multiple coverage-info responses found. Due to the " \
80
+ 'complexity of determining the expected state, this resource will not be verified.')
81
+ next
82
+ end
83
+
84
+ if entries.first[:coverage_information_extensions].size > 1
85
+ add_message('info',
86
+ "#{error_prefix(entries.first)}Multiple coverage-information extensions found. Due to the " \
87
+ 'complexity of determining the expected state, this resource will not be verified.')
88
+ next
89
+ end
90
+
91
+ entries.first
92
+ end
93
+ end
94
+
95
+ def find_coverage_info_actions_in_response(request, request_index)
96
+ response = JSON.parse(request.response_body)
97
+ return [] unless response.is_a?(Hash) && response.key?('systemActions')
98
+
99
+ response['systemActions'].map.with_index do |action, action_index|
100
+ if coverage_information_response_type?(action)
101
+ extract_coverage_information_details(action, action_index, request_index)
102
+ end
103
+ end.compact
104
+ rescue JSON::ParserError
105
+ [] # no responses to check, error registered elsewhere
106
+ end
107
+
108
+ def extract_coverage_information_details(action, action_index, request_index)
109
+ {
110
+ request_index:,
111
+ action_index:,
112
+ resource_type: action.dig('resource', 'resourceType'),
113
+ target_id: action.dig('resource', 'id'),
114
+ coverage_information_extensions: FHIR.from_contents(action['resource'].to_json).extension.select do |ext|
115
+ ext.url == COVERAGE_INFO_EXT_URL
116
+ end
117
+ }
118
+ end
119
+
120
+ def extract_supported_resource_types(capability_statement)
121
+ return [] unless capability_statement.rest.is_a?(Array)
122
+
123
+ capability_statement.rest.select { |rest| rest.mode == 'server' }.flat_map do |rest|
124
+ next [] unless rest.resource.is_a?(Array)
125
+
126
+ rest.resource.select do |resource|
127
+ supports_read?(resource)
128
+ end.flat_map(&:type).compact
129
+ end.uniq
130
+ end
131
+
132
+ def supports_read?(resource)
133
+ resource.interaction&.any? do |interaction|
134
+ interaction.code == 'read'
135
+ end
136
+ end
137
+
138
+ def check_for_stored_coverage_information_extension(resource_details)
139
+ fhir_read resource_details[:resource_type], resource_details[:target_id]
140
+ unless resource.present? && resource.resourceType == resource_details[:resource_type]
141
+ add_message('error', "#{error_prefix(resource_details)}Unable to read target resource.")
142
+ return
143
+ end
144
+
145
+ stored_extensions = resource.extension.select { |ext| ext.url == COVERAGE_INFO_EXT_URL }
146
+ if stored_extensions.blank?
147
+ add_message('error', "#{error_prefix(resource_details)}coverage-information extension(s) not stored.")
148
+ return
149
+ end
150
+
151
+ difference_string = coverage_info_extension_differences(
152
+ resource_details[:coverage_information_extensions],
153
+ stored_extensions
154
+ )
155
+ return unless difference_string.present?
156
+
157
+ add_message('error', "#{error_prefix(resource_details)}#{difference_string}.")
158
+ end
159
+
160
+ def coverage_info_extension_differences(expected, actual)
161
+ raise ArgumentError, 'expected must contain exactly one coverage-information extension' if expected.size != 1
162
+
163
+ if expected.size != actual.size
164
+ return "Expected #{expected.size} coverage-information extension(s), found #{actual.size}."
165
+ end
166
+
167
+ differences = compare_coverage_info_sub_extensions(expected[0], actual[0])
168
+ return unless differences.present?
169
+
170
+ "Stored coverage-information extension does not match what was sent by the server: #{differences.join(', ')}"
171
+ end
172
+
173
+ def compare_coverage_info_sub_extensions(expected, actual)
174
+ expected_by_url = expected.extension.group_by(&:url)
175
+ actual_by_url = actual.extension.group_by(&:url)
176
+
177
+ (expected_by_url.keys | actual_by_url.keys).filter_map do |url|
178
+ compare_url_sub_extensions(url, expected_by_url, actual_by_url)
179
+ end
180
+ end
181
+
182
+ def compare_url_sub_extensions(url, expected_by_url, actual_by_url)
183
+ if !expected_by_url.key?(url)
184
+ "unexpected sub-extension '#{url}' found in stored resource"
185
+ elsif !actual_by_url.key?(url)
186
+ "sub-extension '#{url}' missing from stored resource"
187
+ elsif normalized_extensions(expected_by_url[url]) != normalized_extensions(actual_by_url[url])
188
+ "sub-extension '#{url}' value differs"
189
+ end
190
+ end
191
+
192
+ def normalized_extensions(extensions)
193
+ extensions.map { |e| normalize_extension(e.to_hash) }.sort_by(&:to_json)
194
+ end
195
+
196
+ # Recursively sort nested arrays so sub-extension order doesn't affect equality.
197
+ def normalize_extension(value)
198
+ case value
199
+ when Hash then value.transform_values { |v| normalize_extension(v) }
200
+ when Array then value.map { |item| normalize_extension(item) }.sort_by(&:to_json)
201
+ else value
202
+ end
203
+ end
204
+
205
+ def error_prefix(resource_details)
206
+ "(Request #{resource_details[:request_index] + 1}) " \
207
+ "coverage-info systemAction #{resource_details[:action_index] + 1} " \
208
+ "targeting resource #{resource_details[:resource_type]}/#{resource_details[:target_id]}: "
209
+ end
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,18 @@
1
+ require_relative 'client_coverage_info_update_test'
2
+
3
+ module DaVinciCRDTestKit
4
+ module V221
5
+ class ClientCRDUpdateVerificationGroup < Inferno::TestGroup
6
+ id :crd_v221_client_update_verification
7
+ title 'CRD Update Tests'
8
+ description %(
9
+ This CRD-specific group verifies that the client was able to
10
+ persist updates provided by the payer server as a part of
11
+ decision support responses.
12
+ )
13
+ run_as_group
14
+
15
+ test from: :crd_v221_client_coverage_info_update
16
+ end
17
+ end
18
+ end