davinci_crd_test_kit 0.12.2 → 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 +59 -2
  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 +308 -101
  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 -75
  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 -41
  277. data/lib/davinci_crd_test_kit/client_tests/client_fhir_api_read_test.rb +0 -39
  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 -41
  280. data/lib/davinci_crd_test_kit/client_tests/client_fhir_api_validation_test.rb +0 -60
  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 -44
  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 -185
  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,159 @@
1
+ module DaVinciCRDTestKit
2
+ module V221
3
+ class DiscoveryConfigurationTest < Inferno::Test
4
+ title 'Server makes configuration options available'
5
+ id :crd_v221_discovery_configuration
6
+ description %(
7
+ According to the spec:
8
+
9
+ > CRD servers SHALL, at minimum, offer configuration options for each
10
+ type of card they support
11
+
12
+ This test verifies that all primary hook services contain at least one
13
+ valid configuration option for `coverage-info`. Secondary hooks are not
14
+ expected to return cards, so they are ignored in this test.
15
+ )
16
+
17
+ verifies_requirements 'hl7.fhir.us.davinci-crd_2.2.1@dev-4',
18
+ 'hl7.fhir.us.davinci-crd_2.2.1@dev-5',
19
+ 'hl7.fhir.us.davinci-crd_2.2.1@dev-7',
20
+ 'hl7.fhir.us.davinci-crd_2.2.1@dev-8'
21
+
22
+ input :cds_services
23
+ input :crd_discovery_service_ignore_list,
24
+ optional: true
25
+
26
+ def primary_hooks
27
+ ['appointment-book', 'order-sign', 'order-dispatch']
28
+ end
29
+
30
+ def primary_hook?(hook)
31
+ primary_hooks.include? hook
32
+ end
33
+
34
+ def required_fields
35
+ ['code', 'type', 'name', 'description', 'default']
36
+ end
37
+
38
+ def verify_unique_values(hook, service)
39
+ unique_fields = ['code', 'name', 'description']
40
+
41
+ config_options =
42
+ service
43
+ .dig('extension', 'davinci-crd.configuration-options')
44
+
45
+ return if config_options.blank?
46
+
47
+ unique_fields.each do |unique_field|
48
+ value_counts =
49
+ config_options
50
+ .map { |config_option| config_option[unique_field] }
51
+ .tally
52
+
53
+ duplicate_values =
54
+ value_counts
55
+ .select { |_value, count| count > 1 }
56
+ .keys
57
+
58
+ next if duplicate_values.blank?
59
+
60
+ duplicate_values_string = duplicate_values.map { |value| "\n- `#{value}`" }.join
61
+
62
+ add_message(
63
+ 'error',
64
+ "Services for hook `#{hook}` contain duplicate values for `#{unique_field}`:" \
65
+ "#{duplicate_values_string}"
66
+ )
67
+ end
68
+ end
69
+
70
+ def verify_required_fields(hook, service)
71
+ service.dig('extension', 'davinci-crd.configuration-options')&.each do |config_option|
72
+ required_fields.each do |field_name|
73
+ unless config_option.key?(field_name)
74
+ add_message(
75
+ 'error',
76
+ "Hook `#{hook}` service `#{service['id']}` configuration option `#{config_option['code']}` " \
77
+ "does not contain `#{field_name}` field"
78
+ )
79
+ next
80
+ end
81
+
82
+ next if field_name == 'default'
83
+
84
+ next if config_option[field_name].is_a? String
85
+
86
+ type = config_option[field_name].class
87
+ add_message(
88
+ 'error',
89
+ "Expected hook `#{hook}` service `#{service['id']}` configuration option `#{config_option['code']}` " \
90
+ "field `#{field_name}` to be a String, but found #{type}"
91
+ )
92
+ end
93
+ end
94
+ end
95
+
96
+ run do
97
+ ignore_list = crd_discovery_service_ignore_list.to_s.split(',').map(&:strip).reject(&:blank?)
98
+ services =
99
+ JSON.parse(cds_services)['services']
100
+ .reject { |service| ignore_list.include? service['id'] }
101
+
102
+ services_by_hook = services.group_by { |service| service['hook'] }
103
+
104
+ services_by_hook.each do |hook, hook_services|
105
+ hook_services.each do |service|
106
+ verify_required_fields(hook, service)
107
+ verify_unique_values(hook, service)
108
+ end
109
+ end
110
+
111
+ primary_hook_services = services_by_hook.slice(*primary_hooks).values.flatten
112
+
113
+ assert messages.none? { |message| message[:type] == 'error' },
114
+ 'Some services contain invalid configuration options.'
115
+
116
+ omit_if primary_hook_services.blank?, 'No services for primary hooks found'
117
+
118
+ services_without_configuration_options =
119
+ primary_hook_services.reject do |service|
120
+ service['extension'].present? && service['extension']['davinci-crd.configuration-options'].present?
121
+ end
122
+
123
+ if services_without_configuration_options.present?
124
+ add_message(
125
+ 'error',
126
+ 'The following services do not contain any configuration options: ' \
127
+ "#{services_without_configuration_options.map { |service| service['code'] }.join(', ')}"
128
+ )
129
+ end
130
+
131
+ primary_hook_services.each do |service|
132
+ coverage_info_config =
133
+ service.dig('extension', 'davinci-crd.configuration-options')&.find do |config_option|
134
+ config_option['code'] == 'coverage-info'
135
+ end
136
+
137
+ if coverage_info_config.present?
138
+ if coverage_info_config['type'] != 'boolean'
139
+ add_message(
140
+ 'error',
141
+ "Service `#{service['id']}` `coverage-info` configuration option is not of type boolean"
142
+ )
143
+ end
144
+
145
+ next
146
+ end
147
+
148
+ add_message(
149
+ 'error',
150
+ "Service `#{service['id']}` does not contain a `coverage-info` configuration option"
151
+ )
152
+ end
153
+
154
+ assert messages.none? { |message| message[:type] == 'error' },
155
+ 'Not all primary hook services contain valid configuration options.'
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,90 @@
1
+ module DaVinciCRDTestKit
2
+ module V221
3
+ class DiscoveryEndpointTest < Inferno::Test
4
+ title 'Server returns a discovery response'
5
+ id :crd_v221_discovery_endpoint_test
6
+ description %(
7
+ A CDS Service provider must expose its discovery endpoint at `{baseURL}/cds-services`
8
+ as specified in the [CDS Hooks Specification](https://cds-hooks.hl7.org/2.0/#discovery).
9
+
10
+ This test checks that the server responds to a GET request at the following endpoint:
11
+
12
+ `GET {baseURL}/cds-services`
13
+
14
+ It does this by checking that the server responds with an HTTP OK 200 status code
15
+ and that the body of the response is a valid JSON object. This test does not
16
+ inspect the structure and content of the response body to see if it contains the required information.
17
+ It only checks to see if the RESTful interaction is supported and returns a valid JSON object.
18
+ )
19
+
20
+ input_order :base_url, :authentication_required, :encryption_method, :jwks_kid
21
+ input :base_url
22
+ input :authentication_required,
23
+ title: 'Discovery endpoint requires authentication?',
24
+ type: 'radio',
25
+ default: 'no',
26
+ options: {
27
+ list_options: [
28
+ {
29
+ label: 'No',
30
+ value: 'no'
31
+ },
32
+ {
33
+ label: 'Yes',
34
+ value: 'yes'
35
+ }
36
+ ]
37
+ }
38
+ input :encryption_method,
39
+ title: 'JWT Signing Algorithm',
40
+ description: <<~DESCRIPTION,
41
+ CDS Hooks recommends ES384 and RS384 for JWT signature verification.
42
+ Select which method to use.
43
+ DESCRIPTION
44
+ type: 'radio',
45
+ default: 'ES384',
46
+ options: {
47
+ list_options: [
48
+ {
49
+ label: 'ES384',
50
+ value: 'ES384'
51
+ },
52
+ {
53
+ label: 'RS384',
54
+ value: 'RS384'
55
+ }
56
+ ]
57
+ }
58
+ input :jwks_kid,
59
+ title: 'CDS Services JWKS kid',
60
+ description: <<~DESCRIPTION,
61
+ The key ID of the JWKS private key to use for signing the JWTs when invoking a CDS service endpoint
62
+ requiring authentication.
63
+ Defaults to the first JWK in the list if no kid is supplied.
64
+ DESCRIPTION
65
+ optional: true
66
+ output :cds_services
67
+
68
+ run do
69
+ discovery_url = "#{base_url.chomp('/')}/cds-services"
70
+ headers = { 'Accept' => 'application/json' }
71
+
72
+ if authentication_required == 'yes'
73
+ token = JwtHelper.build(
74
+ aud: discovery_url,
75
+ iss: inferno_base_url,
76
+ jku: "#{inferno_base_url}/jwks.json",
77
+ kid: jwks_kid,
78
+ encryption_method:
79
+ )
80
+ headers['Authorization'] = "Bearer #{token}"
81
+ end
82
+ get(discovery_url, headers:, tags: [DISCOVERY_TAG])
83
+ assert_response_status(200)
84
+ assert_valid_json(request.response_body)
85
+
86
+ output cds_services: request.response_body
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,43 @@
1
+ require_relative '../../server_test_helper'
2
+
3
+ module DaVinciCRDTestKit
4
+ module V221
5
+ class DiscoveryPrefetchSupportTest < Inferno::Test
6
+ include DaVinciCRDTestKit::ServerTestHelper
7
+
8
+ title 'Server advertises prefetch support'
9
+ id :crd_v221_discovery_prefetch_support
10
+ description %(
11
+ This test expects the server to demonstrate support for prefetch queries
12
+ by providing a prefetch query in at least one of the advertised service
13
+ in the discovery response.
14
+ )
15
+
16
+ verifies_requirements 'hl7.fhir.us.davinci-crd_2.2.1@found-24'
17
+
18
+ input :cds_services
19
+ input :crd_discovery_service_ignore_list,
20
+ optional: true
21
+
22
+ run do
23
+ object = parse_json(cds_services)
24
+ assert object['services'], 'Discovery response did not contain `services`'
25
+
26
+ services = object['services']
27
+ assert services.is_a?(Array), 'Services field of the CDS Discovery response object is not an array.'
28
+
29
+ ignored_service_ids = crd_discovery_service_ignore_list.to_s.split(',').map(&:strip).reject(&:blank?)
30
+ services
31
+ .select { |service| ignored_service_ids.include?(service['id']) }
32
+ .each do |service|
33
+ info "Ignoring service `#{service['id']}` because it is in the ignore list."
34
+ end
35
+ services_for_crd_validation = services.reject { |service| ignored_service_ids.include?(service['id']) }
36
+
37
+ prefetch_supported = services_for_crd_validation.any? { |service| service['prefetch'].present? }
38
+
39
+ skip_if !prefetch_supported, 'No CRD services advertised prefetch support'
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,121 @@
1
+ require_relative '../../server_test_helper'
2
+
3
+ module DaVinciCRDTestKit
4
+ module V221
5
+ class DiscoveryServicesValidationTest < Inferno::Test
6
+ include DaVinciCRDTestKit::ServerTestHelper
7
+
8
+ title 'Discovery response contains valid services'
9
+ id :crd_v221_discovery_services_validation
10
+ description %(
11
+ As per the [CDS Hooks Spec](https://cds-hooks.hl7.org/2.0/#response),
12
+ the response to the discovery endpoint SHALL be an object containing
13
+ a list of CDS services. If your CDS server hosts no CDS services,
14
+ the discovery endpoint should return a 200 HTTP response with
15
+ an empty array of services.
16
+
17
+ Each CDS service must contain the following required fields:
18
+ `hook`, `description`, and `id`.
19
+
20
+ Additionally, the [CRD
21
+ Spec](https://hl7.org/fhir/us/davinci-crd/2.2.1/en/deviations.html#crd-version-declaration)
22
+ states that "CRD servers SHALL declare at least one supported CRD
23
+ version for each supported hook" using the `davinci-crd.version`
24
+ extension.
25
+
26
+ This test checks for the presence of the required fields and
27
+ validates that they are of the correct type.
28
+
29
+ CDS services provided by the server to support use cases outside the
30
+ scope of the CRD specification can be provided in an ignore list input to
31
+ opt-out of CRD validation.
32
+
33
+ The test will be skipped if the server hosts no CRD CDS services.
34
+ )
35
+
36
+ verifies_requirements 'hl7.fhir.us.davinci-crd_2.2.1@dev-1'
37
+
38
+ input :cds_services
39
+ input :crd_discovery_service_ignore_list,
40
+ title: 'Service ID Ignore List',
41
+ description: %(
42
+ In the case that CDS services advertised on this server support
43
+ use cases outside the scope of the CRD specification, provide a
44
+ comma-separated list of service IDs to opt-out of CRD validation.
45
+ Ignored services will not be stored for use in later tests. If
46
+ blank, all services are checked and saved.
47
+ ),
48
+ optional: true
49
+ output :appointment_book_service_ids, :encounter_start_service_ids, :encounter_discharge_service_ids,
50
+ :order_dispatch_service_ids, :order_select_service_ids, :order_sign_service_ids
51
+
52
+ EXTENSION_KEY = 'davinci-crd.version'.freeze
53
+
54
+ def required_fields
55
+ {
56
+ 'hook' => String,
57
+ 'description' => String,
58
+ 'id' => String,
59
+ 'extension' => Hash
60
+ }
61
+ end
62
+
63
+ run do
64
+ object = parse_json(cds_services)
65
+ assert object['services'], 'Discovery response did not contain `services`'
66
+
67
+ services = object['services']
68
+ assert services.is_a?(Array), 'Services field of the CDS Discovery response object is not an array.'
69
+
70
+ ignored_service_ids = crd_discovery_service_ignore_list.to_s.split(',').map(&:strip).reject(&:blank?)
71
+ services
72
+ .select { |service| ignored_service_ids.include?(service['id']) }
73
+ .each do |service|
74
+ info "Ignoring service `#{service['id']}` because it is in the ignore list."
75
+ end
76
+ services_for_crd_validation = services.reject { |service| ignored_service_ids.include?(service['id']) }
77
+
78
+ service_hooks_to_ids = services_for_crd_validation.each_with_object({}) do |service, hash|
79
+ hash[service['hook']] ||= []
80
+ hash[service['hook']] << service['id'] if service['id']
81
+ end
82
+
83
+ output appointment_book_service_ids: service_hooks_to_ids['appointment-book']&.join(', '),
84
+ encounter_start_service_ids: service_hooks_to_ids['encounter-start']&.join(', '),
85
+ encounter_discharge_service_ids: service_hooks_to_ids['encounter-discharge']&.join(', '),
86
+ order_dispatch_service_ids: service_hooks_to_ids['order-dispatch']&.join(', '),
87
+ order_select_service_ids: service_hooks_to_ids['order-select']&.join(', '),
88
+ order_sign_service_ids: service_hooks_to_ids['order-sign']&.join(', ')
89
+
90
+ skip_if services.empty?, 'Server hosts no CDS Services.'
91
+ skip_if services_for_crd_validation.empty?, 'Ignore list excludes all CDS Services from validation.'
92
+
93
+ services_for_crd_validation.each do |service|
94
+ required_fields.each do |field, type|
95
+ assert(service[field], "Service `#{service['id']}` did not contain required field: `#{field}`")
96
+ assert(service[field].is_a?(type), "Service `#{service['id']}`: field `#{field}` is not of type #{type}")
97
+ end
98
+
99
+ assert service['extension'].key?(EXTENSION_KEY),
100
+ "Service `#{service['id']}`: does not contain a `#{EXTENSION_KEY}` extension"
101
+ assert service['extension'][EXTENSION_KEY].is_a?(Array),
102
+ "Service `#{service['id']}`: `#{EXTENSION_KEY}` extension is not of type Array"
103
+ assert service['extension'][EXTENSION_KEY].present?,
104
+ "Service `#{service['id']}`: `#{EXTENSION_KEY}` extension is empty"
105
+ non_string_values = service['extension'][EXTENSION_KEY].reject { |value| value.is_a? String }
106
+ assert non_string_values.blank?,
107
+ "Service `#{service['id']}`: `#{EXTENSION_KEY}` extension contains non-string values: " \
108
+ "#{non_string_values.join(', ')}"
109
+
110
+ invalid_versions =
111
+ service['extension'][EXTENSION_KEY]
112
+ .reject { |version| version.match?(/\A[1-9]\d*\.\d+\Z/) }
113
+
114
+ assert invalid_versions.blank?,
115
+ "Service `#{service['id']}`: `#{EXTENSION_KEY}` extension contains invalid " \
116
+ "version strings: #{invalid_versions.join(', ')}"
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,17 @@
1
+ require_relative '../server_urls'
2
+ require_relative '../../server_abstract_invoke_hook_test'
3
+
4
+ module DaVinciCRDTestKit
5
+ module V221
6
+ class ServerInvokeHookTest < ServerAbstractInvokeHookTest
7
+ include ServerURLs
8
+
9
+ title 'Inferno invokes the selected hook'
10
+ id :crd_v221_server_invoke_hook_test
11
+
12
+ def coverage_info_configuration_supported?
13
+ true
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,71 @@
1
+ require_relative '../../../cross_suite/cards_identification'
2
+ require_relative '../../../cross_suite/tags'
3
+
4
+ module DaVinciCRDTestKit
5
+ module V221
6
+ class CoverageInformationMustSupportTest < Inferno::Test
7
+ include DaVinciCRDTestKit::CardsIdentification
8
+
9
+ title 'Coverage Information responses demonstrate Must Support elements'
10
+ id :crd_v221_coverage_information_must_support
11
+ description <<~DESCRIPTION
12
+ Checks that the server demonstrated must support coverage for the [Coverage Information](https://hl7.org/fhir/us/davinci-crd/2.2.1/en/cards.html#coverage-information-response-type)
13
+ extension across the hook responses returned during this test session.
14
+
15
+ At least one hook invocation must have returned a Coverage Information system action.
16
+ Additionally, the set of [coverage-information extension](https://hl7.org/fhir/us/davinci-crd/2.2.1/en/StructureDefinition-ext-coverage-information.html)
17
+ instances returned across those actions must collectively demonstrate all must support elements.
18
+
19
+ If this test fails, re-run the hook tests using request payloads that cause the server to return
20
+ Coverage Information system actions that cover the full set of must support elements.
21
+ DESCRIPTION
22
+
23
+ ALL_HOOKS = [
24
+ DaVinciCRDTestKit::APPOINTMENT_BOOK_TAG,
25
+ DaVinciCRDTestKit::ENCOUNTER_START_TAG,
26
+ DaVinciCRDTestKit::ENCOUNTER_DISCHARGE_TAG,
27
+ DaVinciCRDTestKit::ORDER_DISPATCH_TAG,
28
+ DaVinciCRDTestKit::ORDER_SELECT_TAG,
29
+ DaVinciCRDTestKit::ORDER_SIGN_TAG
30
+ ].freeze
31
+
32
+ def metadata
33
+ @metadata ||= YAML.load_file(
34
+ File.join(__dir__, '..', '..', '..', 'cross_suite', 'coverage-information_stu221_metadata.yml')
35
+ )
36
+ end
37
+
38
+ class MustSupportMetadataHolder
39
+ attr_accessor :metadata
40
+
41
+ def initialize(metadata)
42
+ self.metadata = metadata
43
+ end
44
+
45
+ def must_supports
46
+ @must_supports ||= {
47
+ extensions: metadata[:must_supports][:extensions] || [],
48
+ slices: metadata[:must_supports][:slices] || [],
49
+ elements: metadata[:must_supports][:elements] || []
50
+ }
51
+ end
52
+ end
53
+
54
+ run do
55
+ ALL_HOOKS.each { |hook_tag| load_tagged_requests(hook_tag) }
56
+ sorted_cards = sorted_cards_from_requests(requests)
57
+ coverage_info_system_actions = sorted_cards['actions'][COVERAGE_INFORMATION_RESPONSE_TYPE]
58
+
59
+ assert coverage_info_system_actions.present?,
60
+ 'Coverage Information system action support not demonstrated.'
61
+
62
+ coverage_information_extensions = extract_coverage_information_extensions(sorted_cards)
63
+ assert_must_support_elements_present(
64
+ coverage_information_extensions,
65
+ COVERAGE_INFO_EXT_URL,
66
+ metadata: MustSupportMetadataHolder.new(metadata)
67
+ )
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,36 @@
1
+ require_relative '../../server_test_helper'
2
+
3
+ module DaVinciCRDTestKit
4
+ module V221
5
+ class CoverageInformationSystemActionAcrossHooksValidationTest < Inferno::Test
6
+ include DaVinciCRDTestKit::ServerTestHelper
7
+
8
+ title 'Coverage Information system actions are valid across all hooks'
9
+ id :crd_v221_coverage_info_system_action_across_hooks_validation
10
+ description %(
11
+ This test verifies the presence of valid [Coverage Information](https://hl7.org/fhir/us/davinci-crd/STU2/cards.html#coverage-information)
12
+ system action returned by CRD services across all hooks invoked. It verifies the following for each action:
13
+ - The action type is `update`.
14
+ - The resource within the action conforms its respective FHIR profile.
15
+
16
+ Additionally, the test examines the `coverage-info` extensions within the resource to ensure that:
17
+ - Entries referencing differing coverage have distinct `coverage-assertion-ids` and `satisfied-pa-ids`
18
+ (if present).
19
+ - Entries referencing the same coverage have the same `coverage-assertion-ids` and `satisfied-pa-ids`
20
+ (if present).
21
+
22
+ The test will be skipped if no valid Coverage Information system actions are returned across all hooks.
23
+ )
24
+
25
+ verifies_requirements 'hl7.fhir.us.davinci-crd_2.2.1@resp-14'
26
+
27
+ run do
28
+ verify_at_least_one_test_passes(
29
+ self.class.parent.parent.groups,
30
+ 'crd_v221_coverage_info_system_action_validation',
31
+ 'None of the hooks invoked returned valid Coverage Info system actions.'
32
+ )
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,118 @@
1
+ require 'yaml'
2
+ require_relative '../../resource_extractor'
3
+ require_relative '../../server_test_helper'
4
+ require_relative '../../../cross_suite/tags'
5
+
6
+ module DaVinciCRDTestKit
7
+ module V221
8
+ class SupportedUSCoreVersionsTest < Inferno::Test
9
+ include DaVinciCRDTestKit::ResourceExtractor
10
+ include DaVinciCRDTestKit::ServerTestHelper
11
+
12
+ title 'Provided resources demonstrate support for all required US Core versions'
13
+ id :crd_v221_supported_us_core_versions
14
+ description <<~DESCRIPTION
15
+ Checks whether the embedded FHIR resources provided across hook requests during this test
16
+ session demonstrate support for all US Core versions required by the CRD implementation
17
+ guide: 3.1.1, 6.1.0, and 7.0.0.
18
+
19
+ This test does not verify exhaustive support for each US Core version. It inspects FHIR
20
+ resources included in successful hook request `context` and `prefetch` data and verifies
21
+ that at least one provided resource validates against a US Core profile for each required
22
+ version.
23
+ DESCRIPTION
24
+
25
+ verifies_requirements 'hl7.fhir.us.davinci-crd_2.2.1@conf-2'
26
+
27
+ US_CORE_VERSIONS = {
28
+ '3.1.1' => 'v3.1.1',
29
+ '6.1.0' => 'v6.1.0',
30
+ '7.0.0' => 'v7.0.0'
31
+ }.freeze
32
+
33
+ GENERATED_METADATA_DIR = File.join(
34
+ Gem::Specification.find_by_name('us_core_test_kit').gem_dir,
35
+ 'lib', 'us_core_test_kit', 'generated'
36
+ ).freeze
37
+
38
+ run do
39
+ ALL_HOOK_TAGS.each { |hook_tag| load_tagged_requests(hook_tag) }
40
+ skip_if requests.empty?, 'No requests were made in a previous test as expected.'
41
+
42
+ successful_requests = requests.select { |request| request.status == 200 }
43
+ skip_if successful_requests.empty?, 'All service requests were unsuccessful.'
44
+
45
+ embedded_resources = successful_requests.each.flat_map { |request| resources_from_request(request) }
46
+
47
+ skip_if embedded_resources.blank?,
48
+ 'No embedded FHIR resources were found in successful hook requests.'
49
+
50
+ version_matches = determine_version_matches(embedded_resources)
51
+ missing_versions = US_CORE_VERSIONS.keys - version_matches.keys
52
+
53
+ missing_versions.each do |version|
54
+ add_message('error', "Support for US Core #{version} was not demonstrated.")
55
+ end
56
+
57
+ assert missing_versions.empty?,
58
+ 'Support for one or more required US Core versions was not demonstrated.'
59
+ end
60
+
61
+ private
62
+
63
+ def determine_version_matches(embedded_resources)
64
+ embedded_resources.each_with_object({}) do |resource, matches|
65
+ US_CORE_VERSIONS.each_key do |version|
66
+ next if matches.key?(version)
67
+
68
+ matching_profile = us_core_profiles_by_version
69
+ .dig(version, resource.resourceType)
70
+ &.find { |profile_url| resource_valid_for_profile?(resource, profile_url) }
71
+
72
+ next unless matching_profile.present?
73
+
74
+ matches[version] = matching_profile
75
+ end
76
+ end
77
+ end
78
+
79
+ def resource_valid_for_profile?(resource, profile_url)
80
+ validation_details = []
81
+ resource_is_valid?(
82
+ resource:,
83
+ profile_url:,
84
+ validator_response_details: validation_details,
85
+ add_messages_to_runnable: false
86
+ )
87
+ end
88
+
89
+ def us_core_profiles_by_version
90
+ @us_core_profiles_by_version ||= US_CORE_VERSIONS.transform_values do |directory|
91
+ version_profile_metadata(directory).each_with_object(
92
+ Hash.new { |hash, key| hash[key] = [] }
93
+ ) do |metadata, profiles_by_resource|
94
+ profile_identifier = versioned_profile_identifier(metadata)
95
+ next unless profile_identifier.present?
96
+
97
+ profiles_by_resource[metadata[:resource]] << profile_identifier
98
+ end.transform_values(&:uniq)
99
+ end
100
+ end
101
+
102
+ def version_profile_metadata(directory)
103
+ Dir.glob(File.join(GENERATED_METADATA_DIR, directory, '*', 'metadata.yml')).map do |path|
104
+ YAML.load_file(path, aliases: true)
105
+ end
106
+ end
107
+
108
+ def versioned_profile_identifier(metadata)
109
+ resource_type = metadata[:resource]
110
+ profile_url = metadata[:profile_url]
111
+ profile_version = metadata[:profile_version]
112
+ return if resource_type.blank? || profile_url.blank? || profile_version.blank?
113
+
114
+ "#{profile_url}|#{profile_version}"
115
+ end
116
+ end
117
+ end
118
+ end