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,43 @@
1
+ module DaVinciCRDTestKit
2
+ module V201
3
+ class ClientFHIRApiCreateTest < Inferno::Test
4
+ id :crd_v201_client_fhir_api_create_test
5
+ title 'Create Interaction'
6
+ description %(
7
+ Verify that the CRD client supports the create interaction for the given resource. The capabilities required
8
+ by each resource can be found here: https://hl7.org/fhir/us/davinci-crd/CapabilityStatement-crd-client.html#resourcesSummary1
9
+ )
10
+
11
+ input :create_resources,
12
+ type: 'textarea',
13
+ description: 'Provide a list of resources to create. e.g., [json_resource_1, json_resource_2]',
14
+ optional: true
15
+
16
+ def resource_type
17
+ config.options[:resource_type]
18
+ end
19
+
20
+ run do
21
+ skip_if create_resources.blank?, 'Provide a list of resources to create to run this test.'
22
+ assert_valid_json(create_resources)
23
+ create_resources_list = JSON.parse(create_resources)
24
+ skip_if(!create_resources_list.is_a?(Array), 'Resources to create not inputted in list format, skipping test.')
25
+
26
+ valid_create_resources =
27
+ create_resources_list
28
+ .compact_blank
29
+ .map { |resource| FHIR.from_contents(resource.to_json) }
30
+ .select { |resource| resource.resourceType == resource_type }
31
+ .select { |resource| resource_is_valid?(resource:) }
32
+
33
+ skip_if(valid_create_resources.blank?,
34
+ %(No valid #{resource_type} resources were provided to send in Create requests, skipping test.))
35
+
36
+ valid_create_resources.each do |create_resource|
37
+ fhir_create(create_resource)
38
+ assert_response_status(201)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,43 @@
1
+ module DaVinciCRDTestKit
2
+ module V201
3
+ class ClientFHIRApiReadTest < Inferno::Test
4
+ id :crd_v201_client_fhir_api_read_test
5
+ title 'Read Interaction'
6
+ description %(
7
+ Verify that the CRD client supports the read interaction for the given resource. The capabilities required by
8
+ each resource can be found here: https://hl7.org/fhir/us/davinci-crd/CapabilityStatement-crd-client.html#resourcesSummary1
9
+ )
10
+
11
+ input :resource_ids,
12
+ optional: true
13
+
14
+ def resource_type
15
+ config.options[:resource_type]
16
+ end
17
+
18
+ def no_resources_skip_message
19
+ "No #{resource_type} resource ids were provided, skipping test. "
20
+ end
21
+
22
+ def bad_resource_id_message(expected_id)
23
+ "Expected resource to have id: `#{expected_id}`, but found `#{resource.id}`"
24
+ end
25
+
26
+ run do
27
+ skip_if resource_ids.blank?, no_resources_skip_message
28
+
29
+ resource_id_list = resource_ids.split(',').map(&:strip)
30
+ assert resource_id_list.present?, "No #{resource_type} id provided."
31
+
32
+ resource_id_list.each do |resource_id_to_read|
33
+ fhir_read resource_type, resource_id_to_read, tags: [resource_type, 'read']
34
+
35
+ assert_response_status(200)
36
+ assert_resource_type(resource_type)
37
+ assert resource.id.present? && resource.id == resource_id_to_read,
38
+ bad_resource_id_message(resource_id_to_read)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,234 @@
1
+ module DaVinciCRDTestKit
2
+ module V201
3
+ class ClientFHIRApiSearchTest < Inferno::Test
4
+ id :crd_v201_client_fhir_api_search_test
5
+ title 'Search Interaction'
6
+ description %(
7
+ Verify that the CRD client supports the specified search interaction for the given resource. The capabilities
8
+ required by each resource can be found here: https://hl7.org/fhir/us/davinci-crd/CapabilityStatement-crd-client.html#resourcesSummary1
9
+ )
10
+
11
+ input :search_param_values,
12
+ optional: true
13
+
14
+ attr_accessor :successful_search
15
+
16
+ def resource_type
17
+ config.options[:resource_type]
18
+ end
19
+
20
+ def search_type
21
+ config.options[:search_type]
22
+ end
23
+
24
+ def include_searches
25
+ ['organization_include', 'practitioner_include', 'location_include']
26
+ end
27
+
28
+ def reference_search_parameters
29
+ ['organization', 'practitioner', 'patient']
30
+ end
31
+
32
+ def bad_resource_id_message(expected_id, actual_id)
33
+ "Expected resource to have id: `#{expected_id}`, but found `#{actual_id}`"
34
+ end
35
+
36
+ def perform_fhir_search(search_params, tags)
37
+ fhir_search(resource_type, params: search_params, tags:)
38
+ assert_response_status(200)
39
+ assert_resource_type(:bundle)
40
+ resource
41
+ end
42
+
43
+ def status_search_result_check(bundle, status)
44
+ return if bundle.entry.empty?
45
+
46
+ self.successful_search = true
47
+
48
+ bundle.entry
49
+ .reject { |entry| entry&.resource&.resourceType == 'OperationOutcome' }
50
+ .map(&:resource)
51
+ .each do |resource|
52
+ assert_resource_type(resource_type, resource:)
53
+ assert(resource.status == status, %(
54
+ Each #{resource_type} resource in search result bundle should have a status of `#{status}`, instead got:
55
+ `#{resource.status}` for resource with id: `#{resource.id}`
56
+ ))
57
+ end
58
+ end
59
+
60
+ def check_id_search_result_entry(bundle_entry, search_id, entry_resource_type)
61
+ assert_resource_type(entry_resource_type, resource: bundle_entry)
62
+
63
+ assert bundle_entry.id.present?, "Expected id field in returned #{entry_resource_type} resource"
64
+
65
+ assert bundle_entry.id == search_id,
66
+ bad_resource_id_message(search_id, bundle_entry.id)
67
+ end
68
+
69
+ def id_search_result_check(bundle, search_id)
70
+ warning do
71
+ assert bundle.entry.any?,
72
+ "Search result bundle is empty for #{resource_type} _id search with an id of `#{search_id}`"
73
+ end
74
+ return if bundle.entry.empty?
75
+
76
+ self.successful_search = true
77
+
78
+ bundle.entry
79
+ .reject { |entry| entry&.resource&.resourceType == 'OperationOutcome' }
80
+ .map(&:resource)
81
+ .each do |resource|
82
+ check_id_search_result_entry(resource, search_id, resource_type)
83
+ end
84
+ end
85
+
86
+ def check_include_reference(base_resource_entry, include_resource_id, include_resource_type)
87
+ base_resource_references = Array.wrap(get_reference_field(include_resource_type, base_resource_entry)).compact
88
+
89
+ assert(base_resource_references.present?, %(
90
+ #{resource_type} resource with id #{base_resource_entry.id} did not include the field that references a
91
+ #{include_resource_type} resource}
92
+ ))
93
+
94
+ base_resource_reference_match_found = base_resource_references.any? do |base_resource_reference|
95
+ base_resource_reference.reference_id == include_resource_id
96
+ end
97
+
98
+ assert(base_resource_reference_match_found, %(
99
+ The #{resource_type} resource in search result bundle with id #{base_resource_entry.id} did not have a
100
+ #{include_resource_type} reference with an id of `#{include_resource_id}`.`
101
+ ))
102
+ end
103
+
104
+ def include_search_result_check(bundle, search_id, included_resource_type) # rubocop:disable Metrics/CyclomaticComplexity
105
+ warning do
106
+ assert bundle.entry.any?,
107
+ "Search result bundle is empty for #{resource_type} _include #{search_type} search with an id
108
+ of `#{search_id}`"
109
+ end
110
+ return if bundle.entry.empty?
111
+
112
+ self.successful_search = true
113
+
114
+ base_resource_entry_list = bundle.entry.select do |entry|
115
+ entry.resource&.resourceType == resource_type
116
+ end
117
+
118
+ assert(base_resource_entry_list.length == 1, %(
119
+ The #{included_resource_type} _include search for #{resource_type} resource with id #{search_id}
120
+ should include exactly 1 #{resource_type} resource, instead got #{base_resource_entry_list.length}.
121
+ ))
122
+
123
+ base_resource_entry = base_resource_entry_list.first.resource
124
+
125
+ bundle.entry
126
+ .map(&:resource)
127
+ .each do |resource|
128
+ entry_resource_type = resource.resourceType
129
+
130
+ if entry_resource_type == resource_type
131
+ check_id_search_result_entry(resource, search_id, entry_resource_type)
132
+ elsif entry_resource_type != 'OperationOutcome'
133
+ entry_resource_type = included_resource_type.capitalize
134
+ assert_resource_type(entry_resource_type, resource:)
135
+
136
+ included_resource_id = resource.id
137
+ assert included_resource_id.present?, "Expected id field in returned #{entry_resource_type} resource"
138
+ check_include_reference(base_resource_entry, included_resource_id, included_resource_type)
139
+ end
140
+ end
141
+ end
142
+
143
+ def get_reference_field(reference_type, entry)
144
+ case reference_type
145
+ when 'patient'
146
+ entry.beneficiary
147
+ when 'practitioner'
148
+ entry.practitioner
149
+ when 'organization'
150
+ if resource_type == 'Encounter'
151
+ entry.serviceProvider
152
+ else
153
+ entry.organization
154
+ end
155
+ when 'location'
156
+ locations = entry.location
157
+ locations.map(&:location)
158
+ end
159
+ end
160
+
161
+ def reference_search_result_check(bundle, reference_id, reference_type)
162
+ warning do
163
+ assert bundle.entry.any?, %(
164
+ Search result bundle is empty for #{resource_type} #{reference_type} search with a #{reference_type} id
165
+ `#{reference_id}`
166
+ )
167
+ end
168
+ return if bundle.entry.empty?
169
+
170
+ self.successful_search = true
171
+
172
+ bundle.entry
173
+ .reject { |entry| entry&.resource&.resourceType == 'OperationOutcome' }
174
+ .map(&:resource)
175
+ .each do |resource|
176
+ assert_resource_type(resource_type, resource:)
177
+
178
+ entry_reference_field = get_reference_field(reference_type, resource)
179
+ assert(
180
+ entry_reference_field.present?,
181
+ %(
182
+ #{resource_type} resource with id #{resource.id} did not include the field that references
183
+ a #{reference_type} resource
184
+ )
185
+ )
186
+
187
+ entry_reference_id = entry_reference_field.reference_id
188
+ assert(
189
+ entry_reference_id == reference_id,
190
+ %(
191
+ The #{resource_type} resource in search result bundle with id #{resource.id} should have a
192
+ #{reference_type} reference with an id of `#{reference_id}`, instead got: `#{entry_reference_id}`
193
+ )
194
+ )
195
+ end
196
+ end
197
+
198
+ run do
199
+ if search_type == 'status'
200
+ coverage_status = ['active', 'cancelled', 'draft', 'entered-in-error']
201
+ coverage_status.each do |status|
202
+ bundle = perform_fhir_search({ status: }, [resource_type, 'status_search'])
203
+ status_search_result_check(bundle, status)
204
+ end
205
+ else
206
+ skip_if search_param_values.blank?, 'No search parameters passed in, skipping test.'
207
+
208
+ search_id_list = search_param_values.split(',').map(&:strip)
209
+ search_id_list.each do |search_id|
210
+ if search_type == '_id'
211
+ bundle = perform_fhir_search({ _id: search_id }, [resource_type, 'id_search'])
212
+ id_search_result_check(bundle, search_id)
213
+ elsif reference_search_parameters.include?(search_type)
214
+ search_params = {}
215
+ search_params[search_type] = "#{search_type.capitalize}/#{search_id}"
216
+ bundle = perform_fhir_search(search_params, [resource_type, "#{search_type}_search"])
217
+ reference_search_result_check(bundle, search_id, search_type)
218
+ elsif include_searches.include?(search_type)
219
+ include_resource_type = search_type.gsub('_include', '')
220
+ bundle = perform_fhir_search({ _id: search_id, _include: "#{resource_type}:#{include_resource_type}" },
221
+ [resource_type, "include_#{include_resource_type}_search"])
222
+ include_search_result_check(bundle, search_id, include_resource_type)
223
+ else
224
+ raise StandardError,
225
+ 'Passed in search_type does not match to any of the search types handled by this search test.'
226
+ end
227
+ end
228
+ end
229
+ skip_if !successful_search,
230
+ 'No resources returned in any of the search result bundles.'
231
+ end
232
+ end
233
+ end
234
+ end
@@ -0,0 +1,43 @@
1
+ module DaVinciCRDTestKit
2
+ module V201
3
+ class ClientFHIRApiUpdateTest < Inferno::Test
4
+ id :crd_v201_client_fhir_api_update_test
5
+ title 'Update Interaction'
6
+ description %(
7
+ Verify that the CRD client supports the update interaction for the given resource. The capabilities required by
8
+ each resource can be found here: https://hl7.org/fhir/us/davinci-crd/CapabilityStatement-crd-client.html#resourcesSummary1
9
+ )
10
+
11
+ input :update_resources,
12
+ type: 'textarea',
13
+ description: 'Provide a list of resources to update. e.g., [json_resource_1, json_resource_2]',
14
+ optional: true
15
+
16
+ def resource_type
17
+ config.options[:resource_type]
18
+ end
19
+
20
+ run do
21
+ skip_if update_resources.blank?, 'Provide a list of resources to update to run this test.'
22
+ assert_valid_json(update_resources)
23
+ update_resources_list = JSON.parse(update_resources)
24
+ skip_if(!update_resources_list.is_a?(Array), 'Resources to update not inputted in list format, skipping test.')
25
+
26
+ valid_update_resources =
27
+ update_resources_list
28
+ .compact_blank
29
+ .map { |resource| FHIR.from_contents(resource.to_json) }
30
+ .select { |resource| resource.resourceType == resource_type }
31
+ .select { |resource| resource_is_valid?(resource:) }
32
+
33
+ skip_if(valid_update_resources.blank?,
34
+ %(No valid #{resource_type} resources were provided to send in Update requests, skipping test.))
35
+
36
+ valid_update_resources.each do |update_resource|
37
+ fhir_update(update_resource, update_resource.id)
38
+ assert_response_status([200, 201])
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,63 @@
1
+ module DaVinciCRDTestKit
2
+ module V201
3
+ class ClientFHIRApiValidationTest < Inferno::Test
4
+ id :crd_v201_client_fhir_api_validation_test
5
+ title 'FHIR Resource Validation'
6
+ description %(
7
+ Verify that the given resources returned from the previous client API interactions are valid resources. Each
8
+ resource is validated against its corresponding [CRD resource profile](https://hl7.org/fhir/us/davinci-crd/STU2/artifacts.html).
9
+ )
10
+
11
+ def resource_type
12
+ config.options[:resource_type]
13
+ end
14
+
15
+ def structure_definition_map
16
+ {
17
+ 'Practitioner' => 'http://hl7.org/fhir/us/davinci-crd/StructureDefinition/profile-practitioner',
18
+ 'PractitionerRole' => 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-practitionerrole',
19
+ 'Patient' => 'http://hl7.org/fhir/us/davinci-crd/StructureDefinition/profile-patient',
20
+ 'Encounter' => 'http://hl7.org/fhir/us/davinci-crd/StructureDefinition/profile-encounter',
21
+ 'Coverage' => 'http://hl7.org/fhir/us/davinci-crd/StructureDefinition/profile-coverage',
22
+ 'Device' => 'http://hl7.org/fhir/us/davinci-crd/StructureDefinition/profile-device',
23
+ 'Location' => 'http://hl7.org/fhir/us/davinci-crd/StructureDefinition/profile-location',
24
+ 'Organization' => 'http://hl7.org/fhir/us/davinci-crd/StructureDefinition/profile-organization'
25
+ }.freeze
26
+ end
27
+
28
+ def profile_url
29
+ structure_definition_map[resource_type]
30
+ end
31
+
32
+ run do
33
+ load_tagged_requests(resource_type)
34
+ skip_if requests.empty?, 'No FHIR api requests were made'
35
+
36
+ requests.keep_if { |req| req.status == 200 }
37
+ skip_if(requests.blank?,
38
+ 'There were no successful FHIR API requests made in previous tests to use in validation.')
39
+
40
+ validated_resources =
41
+ requests
42
+ .map(&:resource)
43
+ .compact
44
+ .flat_map { |resource| resource.is_a?(FHIR::Bundle) ? resource.entry.map(&:resource) : resource }
45
+ .select { |resource| resource.resourceType == resource_type }
46
+ .uniq { |resource| resource.to_reference.reference }
47
+ .map { |resource| resource_is_valid?(resource:, profile_url:) }
48
+
49
+ skip_if(validated_resources.blank?,
50
+ %(No #{resource_type} resources were returned from any of the FHIR API requests made in previous tests
51
+ that could be validated.))
52
+
53
+ validation_error_count = messages.count { |msg| msg[:type] == 'error' }
54
+ invalid_resource_count = validated_resources.reject { |valid| valid }.count
55
+ assert(validation_error_count.zero?,
56
+ %(#{invalid_resource_count}/#{validated_resources.length} #{resource_type} resources returned from
57
+ previous test's FHIR API requests failed validation.))
58
+
59
+ skip_if validated_resources.blank?, 'No FHIR resources were made in previous tests that could be validated.'
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,65 @@
1
+ require_relative '../../client_hook_request_validation'
2
+
3
+ module DaVinciCRDTestKit
4
+ module V201
5
+ class DecodeAuthTokenTest < Inferno::Test
6
+ include ClientHookRequestValidation
7
+
8
+ id :crd_v201_decode_auth_token
9
+ title 'Bearer token can be decoded'
10
+ description %(
11
+ Verify that the Bearer token is a properly constructed JWT. As per the [CDS hooks specification](https://cds-hooks.hl7.org/2.0#trusting-cds-clients),
12
+ each time a CDS client transmits a request to a CDS Service which requires authentication, the request MUST
13
+ include an Authorization header presenting the JWT as a "Bearer" token.
14
+ )
15
+
16
+ verifies_requirements 'cds-hooks_2.0@178'
17
+
18
+ output :auth_tokens, :auth_token_payloads_json, :auth_token_headers_json
19
+
20
+ def hook_name
21
+ config.options[:hook_name]
22
+ end
23
+
24
+ run do
25
+ load_tagged_requests(hook_name)
26
+ skip_if requests.empty?, "No #{hook_name} requests were made in a previous test as expected."
27
+ auth_tokens = []
28
+ auth_token_payloads_json = []
29
+ auth_token_headers_json = []
30
+
31
+ requests.each_with_index do |request, index|
32
+ @request_number = index + 1
33
+
34
+ authorization_header = request.request_header('Authorization')&.value
35
+
36
+ unless authorization_header.start_with?('Bearer ')
37
+ add_message('error', "#{request_number}Authorization token must be a JWT presented as a `Bearer` token")
38
+ end
39
+
40
+ auth_token = authorization_header.delete_prefix('Bearer ')
41
+ auth_tokens << auth_token
42
+
43
+ begin
44
+ payload, header =
45
+ JWT.decode(
46
+ auth_token,
47
+ nil,
48
+ false
49
+ )
50
+
51
+ auth_token_payloads_json << payload.to_json
52
+ auth_token_headers_json << header.to_json
53
+ rescue StandardError => e
54
+ add_message('error', "#{request_number}Token is not a properly constructed JWT: #{e.message}")
55
+ end
56
+ end
57
+ output auth_tokens: auth_tokens.to_json,
58
+ auth_token_payloads_json: auth_token_payloads_json.to_json,
59
+ auth_token_headers_json: auth_token_headers_json.to_json
60
+
61
+ no_error_validation('Decoding Authorization header Bearer tokens failed.')
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,109 @@
1
+ require_relative '../../client_hook_request_validation'
2
+
3
+ module DaVinciCRDTestKit
4
+ module V201
5
+ class RetrieveJWKSTest < Inferno::Test
6
+ include ClientHookRequestValidation
7
+
8
+ id :crd_v201_retrieve_jwks
9
+ title 'JWKS can be retrieved'
10
+ description %(
11
+ Verify that the JWKS can be retrieved from the JWKS uri if it is present in the `jku` field within the JWT token
12
+ header. As per the [CDS hooks specification](https://cds-hooks.hl7.org/2.0#trusting-cds-clients), if the jku
13
+ header field is omitted, the CDS client and CDS service SHALL communicate the JWK Set out-of-band. Therefore,
14
+ if the client does not make their keys publicly available via a uri in the `jku` field, the user must
15
+ submit the jwk_set as an input to the test.
16
+ )
17
+
18
+ verifies_requirements 'cds-hooks_2.0@183', 'cds-hooks_2.0@185', 'cds-hooks_2.0@197', 'cds-hooks_2.0@199'
19
+
20
+ input :auth_token_headers_json
21
+ input :cds_jwk_set,
22
+ title: 'CRD JSON Web Key Set (JWKS)',
23
+ type: 'textarea',
24
+ description: %(
25
+ The client's registered JWK Set containing it's public key, either
26
+ as a publicly accessible url containing the JWKS, or the raw JWKS.
27
+ Run or re-run the **Client Registration** group to set or
28
+ change this value. Used if the `jku` header is not found in the auth token jwt.
29
+ ),
30
+ locked: true,
31
+ optional: true
32
+ output :crd_jwks_json, :crd_jwks_keys_json
33
+
34
+ run do
35
+ auth_token_headers = JSON.parse(auth_token_headers_json)
36
+ skip_if auth_token_headers.empty?, 'No Authorization tokens produced from the previous test.'
37
+
38
+ crd_jwks_json = []
39
+ crd_jwks_keys_json = []
40
+ auth_token_headers.each_with_index do |token_header, index|
41
+ @request_number = index + 1
42
+
43
+ jku = JSON.parse(token_header)['jku']
44
+ if jku.present?
45
+ get(jku)
46
+
47
+ if response[:status] != 200
48
+ add_message('error', %(
49
+ #{request_number}Unexpected response status: expected 200, but received
50
+ #{response[:status]}))
51
+ next
52
+ end
53
+
54
+ @request_number = index + 1
55
+ jwks = json_parse(response[:body])
56
+ next if jwks.blank?
57
+
58
+ crd_jwks_json << response[:body]
59
+
60
+ jwks = JSON.parse(response[:body])
61
+ else
62
+ skip_if cds_jwk_set.blank?,
63
+ %(#{request_number}JWK Set must be inputted if the client's JWK Set is not available via a URL
64
+ identified by the jku header field)
65
+
66
+ jwks = JSON.parse(cds_jwk_set)
67
+ end
68
+
69
+ keys = jwks['keys']
70
+ unless keys.is_a?(Array)
71
+ add_message('error', "#{request_number}JWKS `keys` field must be an array")
72
+ next
73
+ end
74
+
75
+ if keys.blank?
76
+ add_message('error', "#{request_number}The JWK set returned contains no public keys")
77
+ next
78
+ end
79
+
80
+ keys.each do |jwk|
81
+ JWT::JWK.import(jwk.deep_symbolize_keys)
82
+ rescue StandardError
83
+ add_message('error', "#{request_number}Invalid JWK: #{jwk.to_json}")
84
+ end
85
+
86
+ kid_presence = keys.all? { |key| key['kid'].present? }
87
+ if kid_presence.blank?
88
+ add_message('error',
89
+ "#{request_number}`kid` field must be present in each key if JWKS contains multiple keys")
90
+ next
91
+ end
92
+
93
+ kid_uniqueness = keys.map { |key| key['kid'] }.uniq.length == keys.length
94
+ if kid_uniqueness.blank?
95
+ add_message('error', "#{request_number}`kid` must be unique within the client's JWK Set.")
96
+ next
97
+ end
98
+
99
+ crd_jwks_keys_json << keys.to_json
100
+ end
101
+
102
+ output crd_jwks_json: crd_jwks_json.to_json,
103
+ crd_jwks_keys_json: crd_jwks_keys_json.to_json
104
+
105
+ no_error_validation('Retrieving JWKS failed.')
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,70 @@
1
+ require_relative '../../client_hook_request_validation'
2
+
3
+ module DaVinciCRDTestKit
4
+ module V201
5
+ class TokenHeaderTest < Inferno::Test
6
+ include ClientHookRequestValidation
7
+
8
+ id :crd_v201_token_header
9
+ title 'Authorization token header contains required information'
10
+ description %(
11
+ Verify that the JWT header contains the header fields required by the
12
+ [CDS hooks spec](https://cds-hooks.hl7.org/2.0#trusting-cds-clients).
13
+ The `alg`, `kid`, and `typ` fields are required. This test also verifies that the `typ` field is set to
14
+ `JWT` and that the key used to sign the token can be identified in the JWKS.
15
+ )
16
+
17
+ verifies_requirements 'cds-hooks_2.0@182', 'cds-hooks_2.0@184', 'cds-hooks_2.0@202'
18
+
19
+ input :auth_token_headers_json, :crd_jwks_keys_json
20
+ output :auth_tokens_jwk_json
21
+
22
+ run do
23
+ auth_token_headers = JSON.parse(auth_token_headers_json)
24
+ crd_jwks_keys = JSON.parse(crd_jwks_keys_json)
25
+ skip_if auth_token_headers.empty?, 'No Authorization tokens produced from the previous tests.'
26
+ skip_if crd_jwks_keys.empty?, 'No JWKS keys produced from the previous test.'
27
+
28
+ auth_tokens_jwk_json = []
29
+ auth_token_headers.each_with_index do |token_header, index|
30
+ @request_number = index + 1
31
+
32
+ header = JSON.parse(token_header)
33
+ algorithm = header['alg']
34
+
35
+ add_message('error', "#{request_number}Token header must have the `alg` field") if algorithm.blank?
36
+
37
+ add_message('error', "#{request_number}Token header `alg` field cannot be set to none") if algorithm == 'none'
38
+
39
+ if header['typ'].blank?
40
+ add_message('error', "#{request_number}Token header must have the `typ` field")
41
+ elsif header['typ'] != 'JWT'
42
+ add_message('error', %(
43
+ #{request_number}Token header `typ` field must be set to 'JWT', instead was
44
+ #{header['typ']}))
45
+ end
46
+
47
+ if header['kid'].blank?
48
+ add_message('error', "#{request_number}Token header must have the `kid` field")
49
+ next
50
+ end
51
+
52
+ kid = header['kid']
53
+ keys = JSON.parse(crd_jwks_keys[index])
54
+
55
+ jwk = keys.find { |key| key['kid'] == kid }
56
+ if jwk.blank?
57
+ add_message('error', "#{request_number}JWKS did not contain a public key with an id of `#{kid}`")
58
+ next
59
+ end
60
+
61
+ auth_tokens_jwk_json << jwk.to_json
62
+ end
63
+
64
+ output auth_tokens_jwk_json: auth_tokens_jwk_json.to_json
65
+
66
+ no_error_validation('Token headers missing required information.')
67
+ end
68
+ end
69
+ end
70
+ end