diff --git a/lib/inferno/dsl/fhir_resource_validation.rb b/lib/inferno/dsl/fhir_resource_validation.rb index 86fbd0526..425866524 100644 --- a/lib/inferno/dsl/fhir_resource_validation.rb +++ b/lib/inferno/dsl/fhir_resource_validation.rb @@ -50,12 +50,52 @@ def url(validator_url = nil) end # Set the IGs that the validator will need to load - # Example: ["hl7.fhir.us.core#4.0.0"] - # @param igs [Array] - def igs(validator_igs = nil) - @igs = validator_igs if validator_igs + # @example + # igs "hl7.fhir.us.core#4.0.0" + # @example + # igs("hl7.fhir.us.core#3.1.1", "hl7.fhir.us.core#6.0.0") + # @param validator_igs [Array] + def igs(*validator_igs) + cli_context(igs: validator_igs) if validator_igs - @igs + cli_context.igs + end + + # Set the cliContext used as part of each validation request. + # Fields may be passed as either a Hash or block. + # Note that all fields included here will be sent directly in requests, + # there is no check that the fields are correct. + # + # @example + # fhir_resource_validator do + # url 'http://example.com/validator' + # cli_context do + # noExtensibleBindingMessages true + # txServer nil + # end + # end + # + # @example + # fhir_resource_validator do + # url 'http://example.org/validator' + # cli_context({ + # noExtensibleBindingMessages: true, + # txServer: nil + # }) + # end + # + # @param definition [Hash] raw fields to set, optional + def cli_context(definition = nil, &) + if @cli_context + if definition + @cli_context.definition.merge!(definition.deep_symbolize_keys) + elsif block_given? + @cli_context.instance_eval(&) + end + else + @cli_context = CliContext.new(definition || {}, &) + end + @cli_context end # @private @@ -193,19 +233,13 @@ def issue_message(issue, resource) def wrap_resource_for_hl7_wrapper(resource, profile_url) wrapped_resource = { cliContext: { - # TODO: these should be configurable as well - sv: '4.0.1', - # displayWarnings: true, # -display-issues-are-warnings - # txServer: nil, # -tx n/a - igs: @igs || [], - # NOTE: this profile must be part of a loaded IG, - # otherwise the response is an HTTP 500 with no content + **cli_context.definition, profiles: [profile_url] }, filesToValidate: [ { fileName: "#{resource.resourceType}/#{resource.id}.json", - fileContent: resource.to_json, + fileContent: resource.source_contents, fileType: 'json' } ], @@ -259,6 +293,39 @@ def operation_outcome_from_validator_response(response, runnable) end end + # @private + class CliContext + attr_reader :definition + + CLICONTEXT_DEFAULTS = { + sv: '4.0.1', + doNative: false, + extensions: ['any'] + }.freeze + + # @private + def initialize(definition, &) + @definition = CLICONTEXT_DEFAULTS.merge(definition.deep_symbolize_keys) + instance_eval(&) if block_given? + end + + # @private + def method_missing(method_name, *args) + # Interpret any other method as setting a field on cliContext. + # Follow the same format as `Validator.url` here: + # only set the value if one is provided. + # args will be an empty array if no value is provided. + definition[method_name] = args[0] unless args.empty? + + definition[method_name] + end + + # @private + def respond_to_missing?(_method_name, _include_private = false) + true + end + end + module ClassMethods # @private def fhir_validators diff --git a/spec/inferno/dsl/fhir_resource_validation_spec.rb b/spec/inferno/dsl/fhir_resource_validation_spec.rb index e039452bb..98c1b3893 100644 --- a/spec/inferno/dsl/fhir_resource_validation_spec.rb +++ b/spec/inferno/dsl/fhir_resource_validation_spec.rb @@ -18,7 +18,7 @@ outcomes: [{ fileInfo: { fileName: 'Patient/id.json', - fileContent: resource.to_json, + fileContent: resource.source_contents, fileType: 'json' }, issues: [] @@ -104,13 +104,14 @@ { cliContext: { sv: '4.0.1', - igs: [], + doNative: false, + extensions: ['any'], profiles: [profile_url] }, filesToValidate: [ { fileName: 'Patient/0000.json', - fileContent: resource2.to_json, + fileContent: resource2.source_contents, fileType: 'json' } ], @@ -170,6 +171,84 @@ end end + describe '.cli_context' do + it 'applies the correct settings to cli_context' do + v1 = Inferno::DSL::FHIRResourceValidation::Validator.new do + url 'http://example.com' + cli_context do + txServer nil + end + end + + v2 = Inferno::DSL::FHIRResourceValidation::Validator.new do + url 'http://example.com' + cli_context({ + displayWarnings: true + }) + end + + v3 = Inferno::DSL::FHIRResourceValidation::Validator.new do + url 'http://example.com' + cli_context({ + 'igs' => ['hl7.fhir.us.core#1.0.1'], + 'extensions' => [] + }) + end + + expect(v1.cli_context.definition.fetch(:txServer, :missing)).to eq(nil) + expect(v1.cli_context.definition.fetch(:displayWarnings, :missing)).to eq(:missing) + expect(v1.cli_context.txServer).to eq(nil) + + expect(v2.cli_context.definition.fetch(:txServer, :missing)).to eq(:missing) + expect(v2.cli_context.definition[:displayWarnings]).to eq(true) + expect(v2.cli_context.displayWarnings).to eq(true) + + expect(v3.cli_context.igs).to eq(['hl7.fhir.us.core#1.0.1']) + expect(v3.cli_context.extensions).to eq([]) + end + + it 'uses the right cli_context when submitting the validation request' do + v4 = Inferno::DSL::FHIRResourceValidation::Validator.new do + url 'http://example.com' + igs 'hl7.fhir.us.core#1.0.1' + cli_context do + txServer nil + displayWarnings true + doNative true + igs ['hl7.fhir.us.core#3.1.1'] + end + end + + expected_request_body = { + cliContext: { + sv: '4.0.1', + doNative: true, + extensions: ['any'], + igs: ['hl7.fhir.us.core#3.1.1'], + txServer: nil, + displayWarnings: true, + profiles: [profile_url] + }, + filesToValidate: [ + { + fileName: 'Patient/.json', + fileContent: resource.source_contents, + fileType: 'json' + } + ], + sessionId: nil + }.to_json + + stub_request(:post, 'http://example.com/validate') + .with(body: expected_request_body) + .to_return(status: 200, body: '{}') + + expect(v4.validate(resource, profile_url)).to eq('{}') + # if the request body doesn't match the stub, + # validate will throw an exception + end + end + describe '.find_validator' do it 'finds the correct validator based on suite options' do suite = OptionsSuite::Suite