Module: Inferno::DSL::Assertions

Includes:
Messages
Included in:
Entities::TestGroup, Entities::TestSuite
Defined in:
lib/inferno/dsl/assertions.rb

Overview

This module contains the assertions used within tests to verify the behavior of the systems under test. Failing an assertion causes a test to immediately stop execution and receive a ‘fail` result. Additional assertions added to this module will be available in all tests.

Instance Method Summary collapse

Methods included from Messages

#add_message, #error_messages?, #info, #messages, #warning

Methods included from Utils::MarkdownFormatter

#format_markdown

Instance Method Details

#assert(test, message = '') ⇒ void

This method returns an undefined value.

Make an assertion

Parameters:

  • test

    a value whose truthiness will determine whether the assertion passes or fails

  • message (String) (defaults to: '')

    failure message

Raises:



18
19
20
# File 'lib/inferno/dsl/assertions.rb', line 18

def assert(test, message = '')
  raise Exceptions::AssertionException, message unless test
end

#assert_conformance_to_logical_model(object, model_url, validator: :default, message_prefix: '') ⇒ void

This method returns an undefined value.

Validate an object against a logical model

Parameters:

  • object (Hash)
  • model_url (String)

    canonical url of the model to validate against, may include a version separated by a vertical bar (|),

  • validator (Symbol) (defaults to: :default)

    the name of the validator to use

  • message_prefix (String) (defaults to: '')

    Prefix to add to the start of logged messages



96
97
98
99
# File 'lib/inferno/dsl/assertions.rb', line 96

def assert_conformance_to_logical_model(object, model_url, validator: :default, message_prefix: '')
  assert conforms_to_logical_model?(object, model_url, validator:, message_prefix:),
         invalid_object_message(model_url)
end

#assert_must_support_elements_present(resources, profile_url, validator_name: :default, metadata: nil, requirement_extension: nil) {|Metadata| ... } ⇒ void

This method returns an undefined value.

Check that all Must Support elements defined on the given profile are present in the given resources. Must Support elements are identified on the profile StructureDefinition and pre-parsed into metadata, which may be customized prior to the check by passing a block. Alternate metadata may be provided directly. Set test suite config flag debug_must_support_metadata: true to log the metadata to a file for debugging.

Parameters:

  • resources (Array<FHIR::Resource>)
  • profile_url (String)
  • validator_name (Symbol) (defaults to: :default)

    Name of the FHIR Validator that references the IG the profile is in

  • metadata (Hash) (defaults to: nil)

    MustSupport Metadata (optional), if provided the check will use this instead of re-generating metadata from the profile

  • requirement_extension (String) (defaults to: nil)

    Extension URL that implies “required” as an alternative to the MS flag

Yields:

  • (Metadata)

    Customize the metadata before running the test



254
255
256
257
258
259
# File 'lib/inferno/dsl/assertions.rb', line 254

def assert_must_support_elements_present(resources, profile_url, validator_name: :default, metadata: nil,
                                         requirement_extension: nil, &)
  missing_elements = missing_must_support_elements(resources, profile_url, validator_name:, metadata:,
                                                                           requirement_extension:, &)
  assert missing_elements.empty?, missing_must_support_elements_message(missing_elements, resources)
end

#assert_no_error_messages(message = '', message_list: messages) ⇒ void

This method returns an undefined value.

Check that there are no messages associated with the current runnable with a type of ‘error’

Parameters:

  • message (String) (defaults to: '')

    failure message

  • message_list (Array) (defaults to: messages)

    (optional) list of messages to check for errors, if different from the runnable’s messages



273
274
275
# File 'lib/inferno/dsl/assertions.rb', line 273

def assert_no_error_messages(message = '', message_list: messages)
  assert !error_messages?(message_list:), message.present? ? message : 'Errors found - see Messages for details.'
end

#assert_resource_type(resource_type, resource: self.resource) ⇒ void

This method returns an undefined value.

Check a FHIR resource’s type

Examples:

# The resource type can be a symbol, String, or FHIR::Model class
assert_resource_type(:capability_statement)
assert_resource_type('CapabilityStatement')
assert_resource_type(FHIR::CapabilityStatement)

Parameters:

  • resource_type (String, Symbol, Class)
  • resource (FHIR::Model) (defaults to: self.resource)


54
55
56
57
58
59
# File 'lib/inferno/dsl/assertions.rb', line 54

def assert_resource_type(resource_type, resource: self.resource)
  resource_type_name = normalize_resource_type(resource_type)

  assert resource&.resourceType == resource_type_name,
         bad_resource_type_message(resource_type_name, resource&.resourceType)
end

#assert_response_content_type(type, request: self.request) ⇒ void

This method returns an undefined value.

Check the Content-Type header of a response. This assertion will fail if the response’s content type does not begin with the provided type.

Parameters:



224
225
226
227
228
229
# File 'lib/inferno/dsl/assertions.rb', line 224

def assert_response_content_type(type, request: self.request)
  header = request.response_header('Content-Type')
  assert header.present?, no_content_type_message

  assert header.value.start_with?(type), bad_content_type_message(type, header.value)
end

#assert_response_status(status, request: self.request, response: nil) ⇒ void

This method returns an undefined value.

Check a response’s status

Parameters:

  • status (Integer, Array<Integer>)

    a single integer or an array of integer status codes

  • request (Inferno::Entities::Request) (defaults to: self.request)
  • response (Hash) (defaults to: nil)


34
35
36
37
# File 'lib/inferno/dsl/assertions.rb', line 34

def assert_response_status(status, request: self.request, response: nil)
  response ||= request&.response
  assert Array.wrap(status).include?(response[:status]), bad_response_status_message(status, response[:status])
end

#assert_valid_bundle_entries(bundle: resource, resource_types: {}, message_prefix: '') ⇒ void

This method returns an undefined value.

Validate each entry of a Bundle

String,Symbol,FHIR::Model,Array<String,Symbol,FHIR::Model>,Hash

If a

string, symbol, or FHIR::Model is provided, only that resource type
will be validated. If an array of strings is provided, only those
resource types will be validated. If a hash is provided with resource
types as keys and profile urls (or nil) as values, only those resource
types will be validated against the provided profile url or the base
resource if nil.

Examples:

# Only validate Patient bundle entries
assert_valid_bundle_entries(resource_types: 'Patient')

# Only valiadte Patient and Condition bundle entries
assert_valid_bundle_entries(resource_types: ['Patient', 'Condition'])

# Only validate Patient and Condition bundle entries. Validate Patient
# resources against the given profile, and Codition resources against the
# base FHIR Condition resource.
assert_valid_bundle_entries(
  resource_types: {
    'Patient': 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient',
    'Condition': nil
  }
)

Parameters:

  • bundle (FHIR::Bundle) (defaults to: resource)
  • resource_types (defaults to: {})
  • message_prefix (String) (defaults to: '')

    Prefix to add to the start of logged messages



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/inferno/dsl/assertions.rb', line 130

def assert_valid_bundle_entries(bundle: resource, resource_types: {}, message_prefix: '')
  assert_resource_type('Bundle', resource: bundle)

  types_to_check = normalize_types_to_check(resource_types)

  invalid_resources =
    bundle
      .entry
      .map(&:resource)
      .select { |resource| types_to_check.empty? || types_to_check.include?(resource.resourceType) }
      .reject do |resource|
        validation_params = { resource:, message_prefix: }
        profile = types_to_check[resource.resourceType]
        validation_params[:profile_url] = profile if profile

        resource_is_valid?(**validation_params)
      end

  assert invalid_resources.empty?, invalid_bundle_entries_message(invalid_resources)
end

#assert_valid_http_uri(uri, message = '') ⇒ void

This method returns an undefined value.

Check for a valid http/https uri

Parameters:

  • uri (String)
  • message (String) (defaults to: '')

    custom failure message



213
214
215
216
# File 'lib/inferno/dsl/assertions.rb', line 213

def assert_valid_http_uri(uri, message = '')
  error_message = message.presence || "\"#{uri}\" is not a valid URI"
  assert uri =~ /\A#{URI::DEFAULT_PARSER.make_regexp(['http', 'https'])}\z/, error_message
end

#assert_valid_json(maybe_json_string, message = '') ⇒ void

This method returns an undefined value.

Check for valid JSON

Parameters:

  • maybe_json_string (String)
  • message (String) (defaults to: '')

    extra failure message



186
187
188
# File 'lib/inferno/dsl/assertions.rb', line 186

def assert_valid_json(maybe_json_string, message = '')
  parsed_json_if_valid(maybe_json_string, message, continue: false)
end

#assert_valid_resource(resource: self.resource, profile_url: nil, validator: :default, message_prefix: '') ⇒ void

This method returns an undefined value.

Validate a FHIR resource

Parameters:

  • resource (FHIR::Model) (defaults to: self.resource)
  • profile_url (String) (defaults to: nil)

    canonical url of the profile to validate against, may include a version separated by a vertical bar (|), and defaults to validating against the base FHIR resource type

  • validator (Symbol) (defaults to: :default)

    the name of the validator to use

  • message_prefix (String) (defaults to: '')

    Prefix to add to the start of logged messages



78
79
80
81
# File 'lib/inferno/dsl/assertions.rb', line 78

def assert_valid_resource(resource: self.resource, profile_url: nil, validator: :default, message_prefix: '')
  assert resource_is_valid?(resource:, profile_url:, validator:, message_prefix:),
         invalid_resource_message(resource, profile_url)
end

#bad_content_type_message(expected, received) ⇒ Object



237
238
239
# File 'lib/inferno/dsl/assertions.rb', line 237

def bad_content_type_message(expected, received)
  "Expected `Content-Type` to be `#{expected}`, but found `#{received}`"
end

#bad_resource_type_message(expected, received) ⇒ Object



40
41
42
# File 'lib/inferno/dsl/assertions.rb', line 40

def bad_resource_type_message(expected, received)
  "Unexpected resource type: expected #{expected}, but received #{received}"
end

#bad_response_status_message(expected, received) ⇒ Object



23
24
25
# File 'lib/inferno/dsl/assertions.rb', line 23

def bad_response_status_message(expected, received)
  "Unexpected response status: expected #{Array.wrap(expected).join(', ')}, but received #{received}"
end

#invalid_bundle_entries_message(invalid_resources) ⇒ Object



152
153
154
155
156
157
158
# File 'lib/inferno/dsl/assertions.rb', line 152

def invalid_bundle_entries_message(invalid_resources)
  identifier_strings =
    invalid_resources
      .map { |resource| "#{resource.resourceType}##{resource.id}" }
      .join(', ')
  "The following bundle entries are invalid: #{identifier_strings}"
end

#invalid_object_message(model_url) ⇒ Object



84
85
86
# File 'lib/inferno/dsl/assertions.rb', line 84

def invalid_object_message(model_url)
  "Object does not conform to the logical model: #{model_url}"
end

#invalid_resource_message(resource, profile_url) ⇒ Object



62
63
64
65
66
67
# File 'lib/inferno/dsl/assertions.rb', line 62

def invalid_resource_message(resource, profile_url)
  return "Resource does not conform to the profile: #{profile_url}" if profile_url.present?
  return 'No resource to validate.' unless resource.present?

  "Resource does not conform to the base #{resource&.resourceType} profile."
end

#missing_must_support_elements_message(missing_elements, resources) ⇒ Object



262
263
264
265
# File 'lib/inferno/dsl/assertions.rb', line 262

def missing_must_support_elements_message(missing_elements, resources)
  "Could not find #{missing_elements.join(', ')} in the #{resources.length} " \
    'provided resource(s)'
end

#no_content_type_messageObject



232
233
234
# File 'lib/inferno/dsl/assertions.rb', line 232

def no_content_type_message
  'Response did not contain a `Content-Type` header.'
end

#normalize_resource_type(resource_type) ⇒ Object



161
162
163
164
165
166
167
# File 'lib/inferno/dsl/assertions.rb', line 161

def normalize_resource_type(resource_type)
  if resource_type.is_a? Class
    resource_type.name.demodulize
  else
    resource_type.to_s.camelize
  end
end

#normalize_types_to_check(resource_types) ⇒ Object



170
171
172
173
174
175
176
177
178
179
# File 'lib/inferno/dsl/assertions.rb', line 170

def normalize_types_to_check(resource_types)
  case resource_types
  when Hash
    resource_types.transform_keys { |type| normalize_resource_type(type) }
  when String
    { normalize_resource_type(resource_types) => nil }
  when Array
    resource_types.each_with_object({}) { |type, types| types[normalize_resource_type(type)] = nil }
  end
end

#parsed_json_if_valid(maybe_json_string, message = '', continue: true) ⇒ void

This method returns an undefined value.

Return parsed json Hash if valid, or indicate an error with an error message or a failed assert

Parameters:

  • maybe_json_string (String)
  • message (String) (defaults to: '')

    extra failure message

  • continue (Boolean) (defaults to: true)

    if true will log an error message and continue, otherwise will raise an assert exception



197
198
199
200
201
202
203
204
205
206
# File 'lib/inferno/dsl/assertions.rb', line 197

def parsed_json_if_valid(maybe_json_string, message = '', continue: true)
  JSON.parse(maybe_json_string)
rescue JSON::ParserError
  if continue
    add_message(:error, "Invalid JSON. #{message}")
    nil
  else
    assert false, "Invalid JSON. #{message}"
  end
end