Skip to content

Commit

Permalink
FI-2236: Support arbitrary fields in HL7 validator cliContext (#413)
Browse files Browse the repository at this point in the history
* FI-2236: support arbitrary fields on hl7 validator cliContext

* Rework method_missing into a separate CliContext class

* review feedback

* Additional review changes, revert merging logic
  • Loading branch information
dehall authored Dec 19, 2023
1 parent 367dab9 commit b3d66d5
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 16 deletions.
93 changes: 80 additions & 13 deletions lib/inferno/dsl/fhir_resource_validation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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<String>]
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<String>]
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
Expand Down Expand Up @@ -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'
}
],
Expand Down Expand Up @@ -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
Expand Down
85 changes: 82 additions & 3 deletions spec/inferno/dsl/fhir_resource_validation_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
outcomes: [{
fileInfo: {
fileName: 'Patient/id.json',
fileContent: resource.to_json,
fileContent: resource.source_contents,
fileType: 'json'
},
issues: []
Expand Down Expand Up @@ -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'
}
],
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit b3d66d5

Please sign in to comment.