diff --git a/lib/davinci_crd_test_kit/cross_suite/tags.rb b/lib/davinci_crd_test_kit/cross_suite/tags.rb index 0cadf40f..c3038018 100644 --- a/lib/davinci_crd_test_kit/cross_suite/tags.rb +++ b/lib/davinci_crd_test_kit/cross_suite/tags.rb @@ -16,6 +16,15 @@ module DaVinciCRDTestKit DUPLICATED_HOOK_INSTANCE_TAG = 'duplicate_hook_instance'.freeze COVERAGE_INFO_DISABLED_TAG = 'coverage-info-disabled'.freeze + ALL_HOOK_TAGS = [ + APPOINTMENT_BOOK_TAG, + ENCOUNTER_START_TAG, + ENCOUNTER_DISCHARGE_TAG, + ORDER_DISPATCH_TAG, + ORDER_SELECT_TAG, + ORDER_SIGN_TAG + ].freeze + module TagMethods def hook_instance_tag(hook_instance) "#{HOOK_INSTANCE_TAG_PREFIX}#{hook_instance}" diff --git a/lib/davinci_crd_test_kit/requirements/generated/crd_server_v221_requirements_coverage.csv b/lib/davinci_crd_test_kit/requirements/generated/crd_server_v221_requirements_coverage.csv index 0ff60314..edfae99a 100644 --- a/lib/davinci_crd_test_kit/requirements/generated/crd_server_v221_requirements_coverage.csv +++ b/lib/davinci_crd_test_kit/requirements/generated/crd_server_v221_requirements_coverage.csv @@ -1,5 +1,5 @@ Req Set,ID,URL,Requirement,Conformance,Actors,Conditionality,Not Tested Reason,Not Tested Details,Da Vinci CRD Server v2.2.1 Test Suite Short ID(s),Da Vinci CRD Server v2.2.1 Test Suite Full ID(s) -hl7.fhir.us.davinci-crd_2.2.1,billopt-2,https://hl7.org/fhir/us/davinci-crd/2.2.1/en/StructureDefinition-ext-billing-options.html#ci-c-billopt-2,CRD servers **SHALL NOT** depend on the billing-options extension being present in order to provide a response.,SHALL NOT,CRD Server,true,,,"","" +hl7.fhir.us.davinci-crd_2.2.1,billopt-2,https://hl7.org/fhir/us/davinci-crd/2.2.1/en/StructureDefinition-ext-billing-options.html#ci-c-billopt-2,CRD servers **SHALL NOT** depend on the billing-options extension being present in order to provide a response.,SHALL NOT,CRD Server,true,,,3.7.03,crd_server_v221-crd_v221_server_hooks-crd_v221_server_required_card_response_validation-verify_response_without_billing_options hl7.fhir.us.davinci-crd_2.2.1,billopt-3-A,https://hl7.org/fhir/us/davinci-crd/2.2.1/en/StructureDefinition-ext-billing-options.html#ci-c-billopt-3,"If codes are provided with the billing-options extension, CRD servers **SHALL** consider any codes provided",SHALL,CRD Server,false,,,"","" hl7.fhir.us.davinci-crd_2.2.1,billopt-3-B,https://hl7.org/fhir/us/davinci-crd/2.2.1/en/StructureDefinition-ext-billing-options.html#ci-c-billopt-3,"If codes are provided with the billing-options extension, CRD servers ... **MAY** consider additional codes determined by their own mapping when returning coverage information responses.",MAY,CRD Server,false,,,"","" hl7.fhir.us.davinci-crd_2.2.1,conf-2,https://hl7.org/fhir/us/davinci-crd/2.2.1/en/conformance.html#ci-c-conf-2,CRD servers **SHALL** be able to handle all three US Core versions.,SHALL,CRD Server,false,,,"","" diff --git a/lib/davinci_crd_test_kit/server/server_test_helper.rb b/lib/davinci_crd_test_kit/server/server_test_helper.rb index 64de97f9..bc4474dc 100644 --- a/lib/davinci_crd_test_kit/server/server_test_helper.rb +++ b/lib/davinci_crd_test_kit/server/server_test_helper.rb @@ -1,3 +1,5 @@ +require_relative '../cross_suite/tags' + module DaVinciCRDTestKit module ServerTestHelper def parse_json(input) @@ -5,9 +7,9 @@ def parse_json(input) JSON.parse(input) end - def verify_at_least_one_test_passes(test_groups, id_pattern, error_message, id_exclude_pattern = nil) + def verify_at_least_one_test_passes(test_groups, id_pattern, error_message, id_exclude_pattern = nil) # rubocop:disable Metrics/CyclomaticComplexity runnables = test_groups.map do |group| - next unless group.title.include?('-') # all hook group names have hyphens + next if ALL_HOOK_TAGS.none? { |hook_name| group.title.include?(hook_name) } group.groups[2].tests.find do |test| # response verification subgroup test.id.include?(id_pattern) && (!id_exclude_pattern || !test.id.include?(id_exclude_pattern)) diff --git a/lib/davinci_crd_test_kit/server/v2.2.1/server_required_card_response_validation_group.rb b/lib/davinci_crd_test_kit/server/v2.2.1/server_required_card_response_validation_group.rb index 521c38ff..1c8a4987 100644 --- a/lib/davinci_crd_test_kit/server/v2.2.1/server_required_card_response_validation_group.rb +++ b/lib/davinci_crd_test_kit/server/v2.2.1/server_required_card_response_validation_group.rb @@ -1,16 +1,14 @@ require_relative 'must_support/coverage_information_system_action_across_hooks_validation_test' require_relative 'must_support/coverage_information_must_support_test' +require_relative 'verify_response/verify_response_without_billing_options_test' module DaVinciCRDTestKit module V221 class ServerRequiredCardResponseValidationGroup < Inferno::TestGroup - title 'Required Card Response Validation' + title 'Cross-Hook Response Validation' description %( - This group contains tests to verify the presence and validity of required response types - across all hooks invoked. As per the [Da Vinci CRD Implementation Guide](https://hl7.org/fhir/us/davinci-crd/2.2.1/en/hooks.html#ci-c-hook-26), - CRD clients and servers SHALL, at minimum, support returning and - processing the Coverage Information system action for all invocations of - the appointment-book hook. + This group contains tests to verify the behavior of the server responses + across all hooks. ) # verifies_requirements 'hl7.fhir.us.davinci-crd_2.0.1@247', 'hl7.fhir.us.davinci-crd_2.0.1@248', # 'hl7.fhir.us.davinci-crd_2.0.1@249' @@ -20,6 +18,7 @@ class ServerRequiredCardResponseValidationGroup < Inferno::TestGroup test from: :crd_v221_coverage_info_system_action_across_hooks_validation test from: :crd_v221_coverage_information_must_support + test from: :verify_response_without_billing_options end end end diff --git a/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/verify_response_without_billing_options_test.rb b/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/verify_response_without_billing_options_test.rb new file mode 100644 index 00000000..fa715c5a --- /dev/null +++ b/lib/davinci_crd_test_kit/server/v2.2.1/verify_response/verify_response_without_billing_options_test.rb @@ -0,0 +1,43 @@ +require_relative '../../server_hook_helper' +require_relative '../../../cross_suite/tags' + +module DaVinciCRDTestKit + module V221 + class VerifyResponseWithoutBillingOptionsTest < Inferno::Test + include DaVinciCRDTestKit::ServerHookHelper + + title 'Server does not require Billing Options Extension' + id :verify_response_without_billing_options + description <<~DESCRIPTION + The IG states that, "CRD servers **SHALL NOT** depend on the + billing-options extension being present in order to provide a response." + + This test verifies that a successful response was received for a request + without any billing-options extensions. + DESCRIPTION + + verifies_requirements 'hl7.fhir.us.davinci-crd_2.2.1@billopt-2' + + BILLING_OPTIONS_URL = 'http://hl7.org/fhir/us/davinci-crd/StructureDefinition/ext-billing-options'.freeze + + run do + ALL_HOOK_TAGS.each do |tag| + load_tagged_requests(tag) + end + + skip_if requests.blank?, 'No requests were made in a previous test as expected.' + + successful_requests = requests.select { |request| request.status == 200 } + skip_if successful_requests.empty?, 'All service requests were unsuccessful.' + + requests_without_billing_options = + successful_requests.reject { |request| request.request_body.include? BILLING_OPTIONS_URL } + + skip_if requests_without_billing_options.blank?, + 'All successful requests included the billing options extension. ' \ + 'Provide service call inputs which do not include the billing options extension ' \ + 'to verify that the server does not require the extension.' + end + end + end +end diff --git a/spec/davinci_crd_test_kit/v2.2.1/verify_response_without_billing_options_test_spec.rb b/spec/davinci_crd_test_kit/v2.2.1/verify_response_without_billing_options_test_spec.rb new file mode 100644 index 00000000..b71255a5 --- /dev/null +++ b/spec/davinci_crd_test_kit/v2.2.1/verify_response_without_billing_options_test_spec.rb @@ -0,0 +1,126 @@ +RSpec.describe DaVinciCRDTestKit::V221::VerifyResponseWithoutBillingOptionsTest do + let(:suite_id) { 'crd_server_v221' } + let(:result) { repo_create(:result, test_session_id: test_session.id) } + let(:runnable) { described_class } + let(:appointment) { { resourceType: 'Appointment' } } + let(:appointment_with_coverage_info) do + appointment.merge( + extension: [ + { url: 'http://hl7.org/fhir/us/davinci-crd/StructureDefinition/ext-coverage-information' } + ] + ) + end + + it 'passes if a successful request without a billing options extension has been made' do + bundle = FHIR::Bundle.new( + entry: [ + { + resource: FHIR::Appointment.new(appointment) + } + ] + ) + + request_body = { context: { appointments: bundle.to_hash } }.to_json + + repo_create( + :request, + direction: 'outgoing', + test_session_id: test_session.id, + result:, + request_body:, + response_body: '', + tags: [DaVinciCRDTestKit::APPOINTMENT_BOOK_TAG], + status: 200 + ) + + result = run(runnable) + + expect(result.result).to eq('pass'), result.result_message + end + + it 'skips if no requests could be found' do + result = run(runnable) + + expect(result.result).to eq('skip'), result.result_message + expect(result.result_message).to match(/No requests were made/) + end + + it 'skips if no successful requests were made' do + bundle = FHIR::Bundle.new( + entry: [ + { + resource: FHIR::Appointment.new(appointment) + } + ] + ) + + request_body = { context: { appointments: bundle.to_hash } }.to_json + + repo_create( + :request, + direction: 'outgoing', + test_session_id: test_session.id, + result:, + request_body:, + response_body: '', + tags: [DaVinciCRDTestKit::APPOINTMENT_BOOK_TAG], + status: 500 + ) + + result = run(runnable) + + expect(result.result).to eq('skip'), result.result_message + expect(result.result_message).to match(/were unsuccessful/) + end + + it 'skips if all successful requests contain the billing options extension' do + appointment.merge!( + serviceType: [ + { + coding: [ + { + code: 'ABC' + } + ], + extension: [ + { + url: 'http://hl7.org/fhir/us/davinci-crd/StructureDefinition/ext-billing-options', + valueCodeableConcept: { + coding: [ + { + code: 'DEF' + } + ] + } + } + ] + } + ] + ) + bundle = FHIR::Bundle.new( + entry: [ + { + resource: FHIR::Appointment.new(appointment) + } + ] + ) + + request_body = { context: { appointments: bundle.to_hash } }.to_json + + repo_create( + :request, + direction: 'outgoing', + test_session_id: test_session.id, + result:, + request_body:, + response_body: '', + tags: [DaVinciCRDTestKit::APPOINTMENT_BOOK_TAG], + status: 200 + ) + + result = run(runnable) + + expect(result.result).to eq('skip'), result.result_message + expect(result.result_message).to match(/All successful requests included the billing options extension/) + end +end