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,95 @@
1
+ require_relative 'mock_ehr/fhir_read_endpoint'
2
+ require_relative 'mock_ehr/fhir_search_endpoint'
3
+ require_relative 'mock_ehr/fhir_create_endpoint'
4
+ require_relative 'mock_ehr/fhir_update_endpoint'
5
+ require_relative 'mock_ehr/fhir_delete_endpoint'
6
+ require_relative 'mock_ehr/fhir_metadata_endpoint'
7
+
8
+ module DaVinciCRDTestKit
9
+ # Include this module within a suite class to add Mock FHIR Server
10
+ # endpoints with data supplied by an input containing a Bundle
11
+ # that can be accessed and updated by calls to the suite's endpoints.
12
+ # Defaults to driving the CapabilityStatement and supported search
13
+ # parameters off of US Core 6.1.0, but a different set of metadata
14
+ # can be provided at inclusion time by using `with` and specifying
15
+ # either a `metadata_dir:` or providing a block that resolves to
16
+ # a list of metadata files to use.
17
+ #
18
+ # @example Default US Core 6.1.0 metadata
19
+ # class MyTestSuite < Inferno::TestSuite
20
+ # include MockEHREndpoints
21
+ # end
22
+ #
23
+ # @example Custom metadata directory (e.g. US Core 7.0.0)
24
+ # US_CORE_7_DIR = File.join(
25
+ # Gem::Specification.find_by_name('us_core_test_kit').gem_dir,
26
+ # 'lib', 'us_core_test_kit', 'generated', 'v7.0.0'
27
+ # )
28
+ #
29
+ # class MyTestSuite < Inferno::TestSuite
30
+ # include MockEHREndpoints.with(metadata_dir: US_CORE_7_DIR)
31
+ # end
32
+ #
33
+ # @example Custom file list via block
34
+ # class MyTestSuite < Inferno::TestSuite
35
+ # include(MockEHREndpoints.with { Dir.glob('/path/to/my/metadata/**/metadata.yml') })
36
+ # end
37
+ module MockEHREndpoints
38
+ def self.included(base)
39
+ configure(base)
40
+ end
41
+
42
+ def self.with(metadata_dir: nil, &block)
43
+ Module.new do
44
+ define_singleton_method(:included) do |base|
45
+ MockEHREndpoints.send(:configure, base, metadata_dir:, metadata_files_proc: block)
46
+ end
47
+ end
48
+ end
49
+
50
+ def self.configure(base, metadata_dir: nil, metadata_files_proc: nil)
51
+ base.route :get, FHIR_METADATA_ROUTE, build_metadata_endpoint(metadata_dir:, metadata_files_proc:)
52
+ search_endpoint =
53
+ if metadata_dir || metadata_files_proc
54
+ build_search_endpoint(metadata_dir:, metadata_files_proc:)
55
+ else
56
+ MockEHR::FHIRSearchEndpoint
57
+ end
58
+ base.suite_endpoint :post, FHIR_SEARCH_POST_ROUTE, search_endpoint
59
+ base.suite_endpoint :get, FHIR_RESOURCE_TYPE_ROUTE, search_endpoint
60
+ base.suite_endpoint :get, FHIR_INSTANCE_ROUTE, MockEHR::FHIRReadEndpoint
61
+ base.suite_endpoint :post, FHIR_RESOURCE_TYPE_ROUTE, MockEHR::FHIRCreateEndpoint
62
+ base.suite_endpoint :put, FHIR_INSTANCE_ROUTE, MockEHR::FHIRUpdateEndpoint
63
+ base.suite_endpoint :delete, FHIR_INSTANCE_ROUTE, MockEHR::FHIRDeleteEndpoint
64
+ end
65
+ private_class_method :configure
66
+
67
+ def self.build_metadata_endpoint(metadata_dir: nil, metadata_files_proc: nil)
68
+ return MockEHR::FHIRMetadataEndpoint unless metadata_dir || metadata_files_proc
69
+
70
+ if metadata_files_proc
71
+ Class.new(MockEHR::FHIRMetadataEndpoint) do
72
+ define_singleton_method(:metadata_files) { metadata_files_proc.call }
73
+ end
74
+ else
75
+ Class.new(MockEHR::FHIRMetadataEndpoint) do
76
+ define_singleton_method(:metadata_dir) { metadata_dir }
77
+ end
78
+ end
79
+ end
80
+ private_class_method :build_metadata_endpoint
81
+
82
+ def self.build_search_endpoint(metadata_dir: nil, metadata_files_proc: nil)
83
+ if metadata_files_proc
84
+ Class.new(MockEHR::FHIRSearchEndpoint) do
85
+ define_singleton_method(:metadata_files) { metadata_files_proc.call }
86
+ end
87
+ else
88
+ Class.new(MockEHR::FHIRSearchEndpoint) do
89
+ define_method(:metadata_directory) { metadata_dir }
90
+ end
91
+ end
92
+ end
93
+ private_class_method :build_search_endpoint
94
+ end
95
+ end
@@ -0,0 +1,225 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../cross_suite/tags'
4
+ require_relative '../../cross_suite/base_urls'
5
+ require_relative '../../cross_suite/cards_identification'
6
+ require_relative '../endpoints/mock_ehr/fhir_request_handler'
7
+ require_relative '../server_base_urls'
8
+
9
+ module DaVinciCRDTestKit
10
+ module Jobs
11
+ class InvokeHook
12
+ include Sidekiq::Job
13
+ include DaVinciCRDTestKit::CardsIdentification
14
+ include DaVinciCRDTestKit::ServerBaseURLs
15
+
16
+ sidekiq_options retry: false
17
+
18
+ def perform(test_session_id, request_bodies, service_endpoint, inferno_base_url, jwks_kid,
19
+ encryption_method, request_tag, continuation_url, failure_url, acknowledge_before_continuing,
20
+ coverage_info_configuration_supported)
21
+ @test_session_id = test_session_id
22
+ @service_endpoint = service_endpoint
23
+ @inferno_base_url = inferno_base_url
24
+ @jwks_kid = jwks_kid
25
+ @encryption_method = encryption_method
26
+ @request_tag = request_tag
27
+ @continuation_url = continuation_url
28
+ @failure_url = failure_url
29
+ @acknowledge_before_continuing = acknowledge_before_continuing
30
+ @coverage_info_configuration_supported = coverage_info_configuration_supported
31
+
32
+ perform_hook_invocations(request_bodies)
33
+ end
34
+
35
+ def perform_hook_invocations(request_bodies)
36
+ await_test_waiting # let Inferno start waiting so it can respond to FHIR requests
37
+
38
+ request_bodies.each do |request|
39
+ break unless test_waiting?
40
+
41
+ request_body = prepare_hook_request(request)
42
+ response = send_hook_invocation(request_body.to_json)
43
+ send_coverage_info_configuration_invocation(request_body, response)
44
+ send_unknown_configuration_invocation(request_body, response)
45
+ send_unknown_context_invocation(request_body, response)
46
+ send_unknown_cds_hooks_element_invocation(request_body, response)
47
+ end
48
+
49
+ return unless test_waiting?
50
+
51
+ # end the wait to continue the tests
52
+ Faraday.get(@continuation_url) unless @acknowledge_before_continuing
53
+ rescue StandardError => e
54
+ Faraday.get(@failure_url, { message: "Hook invocation failed: #{e.message}" })
55
+ end
56
+
57
+ def test_run_id
58
+ @test_run_id ||= test_runs_repo.last_test_run(@test_session_id).id
59
+ end
60
+
61
+ def test_runs_repo
62
+ @test_runs_repo ||= Inferno::Repositories::TestRuns.new
63
+ end
64
+
65
+ def requests_repo
66
+ @requests_repo ||= Inferno::Repositories::Requests.new
67
+ end
68
+
69
+ def results_repo
70
+ @results_repo ||= Inferno::Repositories::Results.new
71
+ end
72
+
73
+ def service_connection
74
+ @service_connection ||= Faraday.new(url: @service_endpoint, request: { open_timeout: 30 })
75
+ end
76
+
77
+ def test_done?
78
+ test_runs_repo.status_for_test_run(test_run_id) == 'done'
79
+ end
80
+
81
+ def await_test_waiting
82
+ sleep 0.5 until test_waiting? || test_done?
83
+
84
+ @result_id = results_repo.find_waiting_result(test_run_id:)&.id
85
+ end
86
+
87
+ def test_waiting?
88
+ results_repo.find_waiting_result(test_run_id:).present?
89
+ end
90
+
91
+ def prepare_hook_request(parsed_request)
92
+ parsed_request['hookInstance'] = SecureRandom.uuid
93
+ parsed_request['fhirServer'] = fhir_url
94
+ update_simulated_server_token(parsed_request)
95
+ parsed_request
96
+ end
97
+
98
+ def update_simulated_server_token(parsed_request)
99
+ parsed_request['fhirAuthorization'] = {} if parsed_request['fhirAuthorization'].nil?
100
+ fhir_authorization = parsed_request['fhirAuthorization']
101
+
102
+ fhir_authorization['expires_in'] = 300 unless fhir_authorization['expires_in'].present?
103
+ fhir_authorization['access_token'] =
104
+ MockEHR::FHIRRequestHandler.session_id_to_token(@test_session_id, fhir_authorization['expires_in'].to_i / 60)
105
+ end
106
+
107
+ def send_hook_invocation(request_body, extra_tags = [])
108
+ token = JwtHelper.build(
109
+ aud: @service_endpoint,
110
+ iss: @inferno_base_url,
111
+ jku: "#{@inferno_base_url}/jwks.json",
112
+ kid: @jwks_kid,
113
+ encryption_method: @encryption_method
114
+ )
115
+ headers = { 'Content-type' => 'application/json', 'Authorization' => "Bearer #{token}" }
116
+ response = invoke_hook(request_body, headers)
117
+ persist_hook_request(response, [@request_tag] + extra_tags, headers)
118
+ response
119
+ end
120
+
121
+ def send_coverage_info_configuration_invocation(request_body, response)
122
+ return unless @coverage_info_configuration_supported
123
+ return if @coverage_info_configuration_invoked
124
+ return unless response.status == 200
125
+ return unless coverage_info_response?(parsed_response_body(response))
126
+ return unless test_waiting?
127
+
128
+ configured_request_body = JSON.parse(request_body.to_json)
129
+ prepare_hook_request(configured_request_body)
130
+ disable_coverage_info_configuration!(configured_request_body)
131
+ send_hook_invocation(configured_request_body.to_json, [COVERAGE_INFO_DISABLED_TAG])
132
+ @coverage_info_configuration_invoked = true
133
+ end
134
+
135
+ def send_unknown_configuration_invocation(request_body, response)
136
+ return if @unknown_configuration_invoked
137
+ return unless response.status == 200
138
+ return unless coverage_info_response?(parsed_response_body(response))
139
+ return unless test_waiting?
140
+
141
+ request_body = JSON.parse(request_body.to_json)
142
+ prepare_hook_request(request_body)
143
+ add_unknown_configuration(request_body)
144
+ send_hook_invocation(request_body.to_json, [UNKNOWN_CONFIGURATION_TAG])
145
+
146
+ @unknown_configuration_invoked = true
147
+ end
148
+
149
+ def send_unknown_context_invocation(request_body, response)
150
+ return if @unknown_context_invoked
151
+ return unless response.status == 200
152
+ return unless coverage_info_response?(parsed_response_body(response))
153
+ return unless test_waiting?
154
+
155
+ request_body = JSON.parse(request_body.to_json)
156
+ prepare_hook_request(request_body)
157
+ add_unknown_context(request_body)
158
+ send_hook_invocation(request_body.to_json, [UNKNOWN_CONTEXT_TAG])
159
+
160
+ @unknown_context_invoked = true
161
+ end
162
+
163
+ def send_unknown_cds_hooks_element_invocation(request_body, response)
164
+ return if @unknown_cds_hooks_element_invoked
165
+ return unless response.status == 200
166
+ return unless coverage_info_response?(parsed_response_body(response))
167
+ return unless test_waiting?
168
+
169
+ request_body = JSON.parse(request_body.to_json)
170
+ prepare_hook_request(request_body)
171
+ add_unknown_element(request_body)
172
+ send_hook_invocation(request_body.to_json, [UNKNOWN_ELEMENT_TAG])
173
+
174
+ @unknown_cds_hooks_element_invoked = true
175
+ end
176
+
177
+ def random_key
178
+ ('a'..'z').to_a.sample(16).join
179
+ end
180
+
181
+ def add_unknown_configuration(request_body)
182
+ request_body['extension'] ||= {}
183
+ request_body['extension']['davinci-crd.configuration'] ||= {}
184
+ request_body['extension']['davinci-crd.configuration'][random_key] = true
185
+ end
186
+
187
+ def add_unknown_context(request_body)
188
+ request_body['context'] ||= {}
189
+ request_body['context'][random_key] ||= random_key
190
+ end
191
+
192
+ def add_unknown_element(request_body)
193
+ request_body[random_key] ||= random_key
194
+ end
195
+
196
+ def parsed_response_body(response)
197
+ JSON.parse(response.env.response_body.to_s)
198
+ rescue JSON::ParserError, TypeError
199
+ nil
200
+ end
201
+
202
+ def invoke_hook(request_body, headers)
203
+ service_connection.post('', request_body, headers)
204
+ end
205
+
206
+ def persist_hook_request(response, tags, headers)
207
+ inferno_request_headers = headers.map { |name, value| { name:, value: } }
208
+ inferno_response_headers = response.headers&.map { |name, value| { name:, value: } }
209
+ requests_repo.create(
210
+ verb: 'POST',
211
+ url: response.env.url.to_s,
212
+ direction: 'outgoing',
213
+ status: response.status,
214
+ request_body: response.env.request_body,
215
+ response_body: response.env.response_body,
216
+ test_session_id: @test_session_id,
217
+ result_id: @result_id,
218
+ request_headers: inferno_request_headers,
219
+ response_headers: inferno_response_headers,
220
+ tags:
221
+ )
222
+ end
223
+ end
224
+ end
225
+ end
@@ -1,4 +1,4 @@
1
- require_relative 'jwks'
1
+ require_relative 'endpoints/jwks'
2
2
 
3
3
  module DaVinciCRDTestKit
4
4
  class JwtHelper
@@ -6,17 +6,6 @@ module DaVinciCRDTestKit
6
6
  new(...).signed_jwt
7
7
  end
8
8
 
9
- def self.decode_jwt(token, jwks_hash, kid = nil)
10
- jwks = JWT::JWK::Set.new(jwks_hash)
11
- jwks.filter! { |key| key[:use] == 'sig' }
12
- algorithms = jwks.map { |key| key[:alg] }.compact.uniq
13
- begin
14
- JWT.decode(token, kid, true, algorithms:, jwks:)
15
- rescue StandardError => e
16
- raise Inferno::Exceptions::AssertionException, e.message
17
- end
18
- end
19
-
20
9
  attr_reader :aud, :encryption_method, :exp, :iat, :iss, :jku, :jti, :kid
21
10
 
22
11
  def initialize(
@@ -0,0 +1,68 @@
1
+ module DaVinciCRDTestKit
2
+ module ResourceExtractor
3
+ def resources_from_request(request)
4
+ request_body = JSON.parse(request.request_body)
5
+ return [] unless request_body.is_a?(Hash)
6
+
7
+ context_resources(request_body) + prefetch_resources(request_body)
8
+ rescue JSON::ParserError
9
+ []
10
+ end
11
+
12
+ def context_resources(request_body)
13
+ context = request_body['context']
14
+ return [] unless context.is_a?(Hash)
15
+
16
+ bundle_entry_resources(parse_fhir_data(context['appointments'])) +
17
+ bundle_entry_resources(parse_fhir_data(context['draftOrders'])) +
18
+ resources_from_value(context['fulfillmentTasks'])
19
+ end
20
+
21
+ def prefetch_resources(request_body)
22
+ prefetch = request_body['prefetch']
23
+ return [] unless prefetch.is_a?(Hash)
24
+
25
+ prefetch.values.flat_map { |value| resources_from_value(value) }
26
+ end
27
+
28
+ def resources_from_value(value)
29
+ case value
30
+ when Array
31
+ value.flat_map { |entry| resources_from_value(entry) }
32
+ when Hash
33
+ resources_from_hash(value)
34
+ else
35
+ []
36
+ end
37
+ end
38
+
39
+ def resources_from_hash(contents)
40
+ return [] unless contents['resourceType'].present?
41
+
42
+ fhir_data = parse_fhir_data(contents)
43
+ return [] unless fhir_data.present?
44
+
45
+ return bundle_entry_resources(fhir_data) if fhir_data.is_a?(FHIR::Bundle)
46
+
47
+ [fhir_data]
48
+ end
49
+
50
+ def bundle_entry_resources(bundle)
51
+ return [] unless bundle.is_a?(FHIR::Bundle)
52
+
53
+ bundle.entry.filter_map do |entry|
54
+ next unless entry&.resource.present?
55
+
56
+ entry.resource
57
+ end
58
+ end
59
+
60
+ def parse_fhir_data(contents)
61
+ return unless contents.present?
62
+
63
+ FHIR.from_contents(contents.to_json)
64
+ rescue StandardError
65
+ nil
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,165 @@
1
+ require_relative 'server_hook_helper'
2
+ require_relative '../cross_suite/tags'
3
+ require_relative 'jobs/invoke_hook'
4
+
5
+ module DaVinciCRDTestKit
6
+ class ServerAbstractInvokeHookTest < Inferno::Test
7
+ include ServerHookHelper
8
+
9
+ # must include the corresponding server_urls class when using in a suite
10
+
11
+ title 'Invoke Hook'
12
+ id :crd_server_invoke_hook_test
13
+ description %(
14
+ This test initiates POST request(s) to a specified CDS Service using the JSON body list provided by the user.
15
+ As indicated in the [CDS Hooks specification section on Calling a CDS Service](https://cds-hooks.hl7.org/2.0/#calling-a-cds-service),
16
+ the service endpoint is constructed by appending the individual service id to the CDS Service base URL,
17
+ following the format `{baseUrl}/cds-services/{service.id}`. While the requests are being made,
18
+ Inferno will enable FHIR endpoints that serve the data indicated in the Mock EHR Bundle so that the
19
+ tested server can access additional information not provided in the hook request.
20
+
21
+ If running this group only, the user will need to provide the `service.id` to call the specified service.
22
+ Otherwise, the `service.id` is derived from the CDS Services that are retrieved through a query to the
23
+ discovery endpoint.
24
+
25
+ The test will be skipped if the CRD server does not host a CDS Service corresponding to the hook that
26
+ is being tested.
27
+
28
+ The test is deemed successful if the CRD server returns a 200 HTTP response for all requests.
29
+ )
30
+ input_order :base_url, :encryption_method, :jwks_kid
31
+ input :base_url
32
+ input :service_ids,
33
+ description: %(
34
+ If blank, Inferno will attempt to infer the service id to use by finding a service entry in the
35
+ Discovery response for the target hook. If it cannot be inferred, the tests will be skipped.
36
+ ),
37
+ optional: true
38
+ input :service_request_bodies,
39
+ optional: true,
40
+ type: 'textarea',
41
+ description: 'To send multiple requests, provide as a JSON list, e.g., [json_body_1, json_body_2].'
42
+ input :encryption_method,
43
+ title: 'JWT Signing Algorithm',
44
+ description: <<~DESCRIPTION,
45
+ CDS Hooks recommends ES384 and RS384 for JWT signature verification.
46
+ Select which method to use.
47
+ DESCRIPTION
48
+ type: 'radio',
49
+ options: {
50
+ list_options: [
51
+ {
52
+ label: 'ES384',
53
+ value: 'ES384'
54
+ },
55
+ {
56
+ label: 'RS384',
57
+ value: 'RS384'
58
+ }
59
+ ]
60
+ }
61
+ input :jwks_kid,
62
+ title: 'CDS Services JWKS kid',
63
+ description: <<~DESCRIPTION,
64
+ The key ID of the JWKS private key to use for signing the JWTs when invoking a CDS service endpoint
65
+ requiring authentication.
66
+ Defaults to the first JWK in the list if no kid is supplied.
67
+ DESCRIPTION
68
+ optional: true
69
+ input :mock_ehr_bundle,
70
+ title: 'Mock EHR Data',
71
+ description: <<~DESCRIPTION,
72
+ A FHIR Bundle containing resources that Inferno will make available via the FHIR API hosted
73
+ by its simulated CRD client that will initiate the CDS Hooks requests.
74
+ DESCRIPTION
75
+ type: 'textarea',
76
+ optional: true,
77
+ default: '{"resourceType":"Bundle","type":"collection"}'
78
+ input :manual_continuation,
79
+ title: 'Require acknowledgement of completed hook requests?',
80
+ description: %(
81
+ By default, Inferno will continue evaluation of the hook response(s) immediately after completing
82
+ the request(s). To keep Inferno's simulated CRD Client and its FHIR endpoints active longer,
83
+ select the "Continue on user acknowledgement" option and you will be asked to click a link when
84
+ you are ready for Inferno to continue.
85
+ ),
86
+ type: 'radio',
87
+ default: 'no',
88
+ options: {
89
+ list_options: [
90
+ {
91
+ label: 'Continue when hook invocation(s) complete',
92
+ value: 'no'
93
+ }, {
94
+ label: 'Continue on user acknowledgement',
95
+ value: 'yes'
96
+ }
97
+ ]
98
+ },
99
+ optional: true
100
+
101
+ output :invoked_hook
102
+ output :continuation_url
103
+
104
+ run do
105
+ discovery_url = "#{base_url.chomp('/')}/cds-services"
106
+
107
+ begin
108
+ bundle_resource = FHIR.from_contents(mock_ehr_bundle)
109
+ rescue StandardError
110
+ bundle_resource = nil
111
+ end
112
+ skip_if !bundle_resource.is_a?(FHIR::Bundle),
113
+ 'mock_ehr_bundle input must be a FHIR Bundle resource; skipping test.'
114
+
115
+ skip_if service_request_bodies.blank?,
116
+ 'Request body not provided, skipping test.'
117
+ assert_valid_json(service_request_bodies)
118
+
119
+ payloads = [JSON.parse(service_request_bodies)].flatten
120
+ skip_if tested_hook_name == ANY_HOOK_TAG && payloads.length != 1,
121
+ 'The *Demonstrate a Hook Invocation* test supports only one request body.'
122
+ invoked_hook = identify_hook(payloads)
123
+ output(invoked_hook:)
124
+ service_id = target_service_id(service_ids, invoked_hook)
125
+ skip_if service_id.blank?, "No service id provided or discovered for the #{invoked_hook} hook"
126
+
127
+ service_endpoint = "#{discovery_url}/#{service_id}"
128
+ continuation_url = "#{resume_pass_url}?token=#{test_session_id}"
129
+ output(continuation_url:)
130
+ failure_url = "#{resume_fail_url}?token=#{test_session_id}"
131
+
132
+ acknowledge_before_continuing = manual_continuation == 'yes'
133
+ Inferno::Jobs.perform(DaVinciCRDTestKit::Jobs::InvokeHook, test_session_id,
134
+ payloads, service_endpoint, inferno_base_url, jwks_kid, encryption_method,
135
+ tested_hook_name, continuation_url, failure_url, acknowledge_before_continuing,
136
+ coverage_info_configuration_supported?)
137
+
138
+ wait(
139
+ identifier: test_session_id,
140
+ timeout: acknowledge_before_continuing ? 900 : 300,
141
+ message: wait_message(acknowledge_before_continuing, continuation_url)
142
+ )
143
+ end
144
+
145
+ def wait_message(acknowledge_before_continuing, continuation_url)
146
+ message = "Inferno's simulated CRD Client will initiate hook requests to the server. " \
147
+ 'During these invocations the server will be able to make FHIR requests ' \
148
+ "against Inferno's simulated CRD Client."
149
+
150
+ return message unless acknowledge_before_continuing
151
+
152
+ "#{message}\n\n#{continuation_message(continuation_url)}"
153
+ end
154
+
155
+ def continuation_message(continuation_url)
156
+ 'Once all hook requests have been made and the server has gathered all desired information ' \
157
+ "from the FHIR server of Inferno's simulated CRD Client, [click here](#{continuation_url}) " \
158
+ 'to continue the tests.'
159
+ end
160
+
161
+ def coverage_info_configuration_supported?
162
+ false
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,30 @@
1
+ require_relative '../cross_suite/base_urls'
2
+
3
+ module DaVinciCRDTestKit
4
+ FHIR_ROUTE = '/fhir'.freeze
5
+ FHIR_METADATA_ROUTE = "#{FHIR_ROUTE}/metadata".freeze
6
+ FHIR_INSTANCE_ROUTE = "#{FHIR_ROUTE}/:resource_type/:resource_id".freeze
7
+ FHIR_RESOURCE_TYPE_ROUTE = "#{FHIR_ROUTE}/:resource_type".freeze
8
+ FHIR_SEARCH_POST_ROUTE = "#{FHIR_ROUTE}/:resource_type/_search".freeze
9
+
10
+ module ServerBaseURLs
11
+ include BaseURLs
12
+
13
+ def fhir_url
14
+ inferno_base_url + FHIR_ROUTE
15
+ end
16
+
17
+ # alias for OIDC from SMART client tests
18
+ def client_fhir_base_url
19
+ fhir_url
20
+ end
21
+
22
+ def instance_url
23
+ inferno_base_url + INSTANCE_ROUTE
24
+ end
25
+
26
+ def search_url
27
+ inferno_base_url + RESOURCE_TYPE_ROUTE
28
+ end
29
+ end
30
+ end
@@ -1,4 +1,4 @@
1
- require_relative 'tags'
1
+ require_relative '../cross_suite/tags'
2
2
 
3
3
  module DaVinciCRDTestKit
4
4
  module ServerHookHelper
@@ -1,4 +1,4 @@
1
- require_relative 'hook_request_field_validation'
1
+ require_relative '../cross_suite/hook_request_field_validation'
2
2
 
3
3
  module DaVinciCRDTestKit
4
4
  module ServerHookRequestValidation
@@ -1,13 +1,17 @@
1
+ require_relative '../cross_suite/tags'
2
+
1
3
  module DaVinciCRDTestKit
2
- module TestHelper
4
+ module ServerTestHelper
3
5
  def parse_json(input)
4
6
  assert_valid_json(input)
5
7
  JSON.parse(input)
6
8
  end
7
9
 
8
- def verify_at_least_one_test_passes(test_groups, id_pattern, error_message, id_exclude_pattern = nil)
10
+ def verify_at_least_one_test_passes(test_groups, id_pattern, error_message, id_exclude_pattern = nil) # rubocop:disable Metrics/CyclomaticComplexity
9
11
  runnables = test_groups.map do |group|
10
- group.tests.find do |test|
12
+ next if ALL_HOOK_TAGS.none? { |hook_name| group.title.include?(hook_name) }
13
+
14
+ group.groups[2].tests.find do |test| # response verification subgroup
11
15
  test.id.include?(id_pattern) && (!id_exclude_pattern || !test.id.include?(id_exclude_pattern))
12
16
  end
13
17
  end.compact
@@ -0,0 +1,5 @@
1
+ ---
2
+ :resource: Appointment
3
+ :profile_url: http://hl7.org/fhir/us/davinci-crd/StructureDefinition/profile-appointment
4
+ :profile_name: CRD Appointment
5
+ :profile_version: 2.0.1
@@ -0,0 +1,5 @@
1
+ ---
2
+ :resource: ClaimResponse
3
+ :profile_url: http://hl7.org/fhir/us/davinci-hrex/StructureDefinition/hrex-claimresponse
4
+ :profile_name: HRex Prior authorization
5
+ :profile_version: 2.0.1
@@ -0,0 +1,5 @@
1
+ ---
2
+ :resource: CommunicationRequest
3
+ :profile_url: http://hl7.org/fhir/us/davinci-crd/StructureDefinition/profile-communicationrequest
4
+ :profile_name: CRD CommunicationRequest
5
+ :profile_version: 2.0.1
@@ -0,0 +1,21 @@
1
+ ---
2
+ :resource: Coverage
3
+ :profile_url: http://hl7.org/fhir/us/davinci-crd/StructureDefinition/profile-coverage
4
+ :profile_name: CRD Coverage
5
+ :profile_version: 2.0.1
6
+ :search_definitions:
7
+ :patient:
8
+ :paths:
9
+ - beneficiary
10
+ :full_paths:
11
+ - Coverage.beneficiary
12
+ :type: Reference
13
+ :status:
14
+ :paths:
15
+ - status
16
+ :full_paths:
17
+ - Coverage.status
18
+ :type: code
19
+ :include_params: []
20
+ :revincludes:
21
+ - Provenance:target