Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/data/*.db
/data/igs/*.tgz
/data/redis/**/*.rdb
/data/redis/**/*.aof
/data/redis/**/*.manifest
Expand Down
5 changes: 5 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ PATH
inferno_core (~> 1.0, >= 1.0.2)
smart_app_launch_test_kit (~> 1.0)
tls_test_kit (~> 1.0)
us_core_test_kit (~> 1.0)

GEM
remote: https://rubygems.org/
Expand Down Expand Up @@ -344,6 +345,10 @@ GEM
concurrent-ruby (~> 1.0)
unicode-display_width (2.6.0)
unicode_utils (1.4.0)
us_core_test_kit (1.1.1)
inferno_core (~> 1.0, >= 1.0.2)
smart_app_launch_test_kit (~> 1.0)
tls_test_kit (~> 1.0)
webmock (3.23.1)
addressable (>= 2.8.0)
crack (>= 0.3.2)
Expand Down
1 change: 1 addition & 0 deletions davinci_crd_test_kit.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Gem::Specification.new do |spec|
spec.add_runtime_dependency 'inferno_core', '~> 1.0', '>= 1.0.2'
spec.add_runtime_dependency 'smart_app_launch_test_kit', '~> 1.0'
spec.add_runtime_dependency 'tls_test_kit', '~> 1.0'
spec.add_runtime_dependency 'us_core_test_kit', '~> 1.0'
spec.required_ruby_version = Gem::Requirement.new('>= 3.3.6')
spec.metadata['inferno_test_kit'] = 'true'
spec.metadata['homepage_uri'] = spec.homepage
Expand Down
783 changes: 180 additions & 603 deletions lib/davinci_crd_test_kit/client_fhir_api_group.rb

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
require 'us_core_test_kit'

module DaVinciCRDTestKit
class ClientFHIRApiEncounterLocationSearchTest < USCoreTestKit::USCoreV311::EncounterIdentifierSearchTest
title 'Server returns valid results for Encounter search by location'
description %(
A CRD Client (as a FHIR server) SHALL support searching by
location on the Encounter resource. This test
will pass if resources are returned and match the search criteria. If
none are returned, the test is skipped.

[CRD Client CapabilityStatement](https://hl7.org/fhir/us/davinci-crd/STU2/CapabilityStatement-crd-client.html)

)

id :crd_client_fhir_api_encounter_location_search
optional false

output :encounter_id_with_location

def self.properties
@properties ||= USCoreTestKit::SearchTestProperties.new(
resource_type: 'Encounter',
search_param_names: ['location'],
possible_status_search: false
)
end

def add_location_search_to_metadata
metadata.search_definitions[:location] = {
paths: ['location.location'],
full_paths: ['Encounter.location.location'],
comparators: {},
values: [],
type: 'Reference',
contains_multiple: true,
multiple_or: 'MAY'
}
end

run do
add_location_search_to_metadata
run_search_test

return unless requests.present?

search_response_bundle = FHIR.from_contents(requests[0].response_body)
return unless search_response_bundle.is_a?(FHIR::Bundle)

encounter_id_with_location = search_response_bundle.entry&.first&.resource&.id
output(encounter_id_with_location:)
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
module DaVinciCRDTestKit
class ClientFHIRApiIncludeSearchTest < Inferno::Test
id :crd_client_fhir_api_include_search_test
title 'Search Interaction'
description %(
Verify that the CRD client supports the `_include` directive targeting
the specified element on searches for the resource type.
)

input :search_id,
optional: true

def resource_type
config.options[:resource_type]
end

def target_include_element
config.options[:target_include_element]
end

def perform_fhir_search(search_params, tags)
fhir_search(resource_type, params: search_params, tags:)
assert_response_status(200)
assert_resource_type(:bundle)
resource
end

def include_search_result_check(bundle, search_id, included_resource_type) # rubocop:disable Metrics/CyclomaticComplexity
skip_if bundle.entry.blank?,
"_include search not demonstrated - search result bundle is empty for #{resource_type} " \
"_include #{target_include_element} search with an id of `#{search_id}`."

searched_resource_entry = bundle.entry.find do |entry|
entry&.resource&.resourceType == resource_type && entry&.resource&.id == search_id
end
assert(searched_resource_entry.present?,
"The #{included_resource_type} _include search for #{resource_type} resource with id #{search_id} " \
"did not return a #{resource_type} resource matching the searched id #{search_id}.")

searched_resource = searched_resource_entry.resource
base_resource_references = Array.wrap(get_reference_field(included_resource_type, searched_resource)).compact
skip_if base_resource_references.blank?,
"#{resource_type} resource with id #{searched_resource.id} did not include references in " \
"the element targeted to include #{included_resource_type} resources."

base_resource_references.each do |include_target|
target_resource_type, target_id =
if include_target.reference.include?('/')
include_target.reference.split('/')
else
[included_resource_type, include_target.reference]
end

target_entry = bundle.entry.find do |entry|
entry&.resource&.resourceType == target_resource_type && entry&.resource&.id == target_id
end

assert target_entry.present?,
"referenced resource `#{target_resource_type}/#{target_id}` not returned from the search"
end

returned_resources = bundle.entry
.map(&:resource)
.select { |resource| resource.present? && resource.resourceType != 'OperationOutcome' }
warning do
assert returned_resources.length == base_resource_references.length + 1,
'Additional resources returned beyond those requested. While servers are allowed ' \
'to return additional resources that they deem to be relevant, this may be an indication ' \
'that the server is not correctly filtering results.'
end
end

def get_reference_field(reference_type, entry)
case reference_type
when 'practitioner'
entry.practitioner
when 'organization'
if resource_type == 'Encounter'
entry.serviceProvider
else
entry.organization
end
when 'location'
locations = entry.location
locations&.map(&:location)
end
end

run do
skip_if search_id.blank?, 'No target id to use for the search, skipping test.'

bundle = perform_fhir_search({ _id: search_id, _include: "#{resource_type}:#{target_include_element}" },
[resource_type, "include_#{target_include_element}_search"])
include_search_result_check(bundle, search_id, target_include_element)
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
require_relative 'practitioner_role/practitioner_role_read_test'
require_relative 'practitioner_role/practitioner_role_id_search_test'
require_relative 'practitioner_role/practitioner_role_specialty_search_test'
require_relative 'practitioner_role/practitioner_role_organization_search_test'
require_relative 'practitioner_role/practitioner_role_practitioner_search_test'
require_relative 'practitioner_role/practitioner_role_validation_test'
require_relative 'practitioner_role/practitioner_role_must_support_test'
require_relative 'practitioner_role/practitioner_role_reference_resolution_test'

module DaVinciCRDTestKit
class PractitionerRoleGroup < Inferno::TestGroup
title 'PractitionerRole Tests'
short_description 'Verify support for the server capabilities required by the US Core PractitionerRole Profile.'
description %(
# Background

The US Core PractitionerRole sequence verifies that the system under test is
able to provide correct responses for PractitionerRole queries. These queries
must contain resources conforming to the US Core PractitionerRole Profile as
specified in the US Core v3.1.1 Implementation Guide.

# Testing Methodology
## Searching
This test sequence will first perform each required search associated
with this resource. This sequence will perform searches with the
following parameters:

* _id
* specialty
* practitioner
* organization

### Search Parameters
The first search uses the selected patient(s) from the prior launch
sequence. Any subsequent searches will look for its parameter values
from the results of the first search. For example, the `identifier`
search in the patient sequence is performed by looking for an existing
`Patient.identifier` from any of the resources returned in the `_id`
search. If a value cannot be found this way, the search is skipped.

### Search Validation
Inferno will retrieve up to the first 20 bundle pages of the reply for
PractitionerRole resources and save them for subsequent tests. Each of
these resources is then checked to see if it matches the searched
parameters in accordance with [FHIR search
guidelines](https://www.hl7.org/fhir/search.html). The test will fail,
for example, if a Patient search for `gender=male` returns a `female`
patient.


## Must Support
Each profile contains elements marked as "must support". This test
sequence expects to see each of these elements at least once. If at
least one cannot be found, the test will fail. The test will look
through the PractitionerRole resources found in the first test for these
elements.

## Profile Validation
Each resource returned from the first search is expected to conform to
the [US Core PractitionerRole Profile](http://hl7.org/fhir/us/core/StructureDefinition/us-core-practitionerrole).
Each element is checked against teminology binding and cardinality requirements.

Elements with a required binding are validated against their bound
ValueSet. If the code/system in the element is not part of the ValueSet,
then the test will fail.

## Reference Validation
At least one instance of each external reference in elements marked as
"must support" within the resources provided by the system must resolve.
The test will attempt to read each reference found and will fail if no
read succeeds.

)

id :crd_client_fhir_api_practitioner_role
run_as_group

def self.metadata
@metadata ||= Generator::GroupMetadata.new(YAML.load_file(
File.join(__dir__, 'practitioner_role',
'metadata.yml'), aliases: true
))
end

test from: :crd_client_fhir_api_practitioner_role_read_test
test from: :crd_client_fhir_api_practitioner_role_id_search_test
test from: :crd_client_fhir_api_practitioner_role_specialty_search_test
test from: :crd_client_fhir_api_practitioner_role_organization_search_test
test from: :crd_client_fhir_api_practitioner_role_practitioner_search_test
test from: :crd_client_fhir_api_include_search_test,
id: :crd_client_fhir_api_practitioner_role_organization_include_search,
title: 'Search by _id and _include organization',
config: {
options: { resource_type: 'PractitionerRole',
target_include_element: 'organization' },
inputs: { search_ids: { name: :practitioner_role_id_with_organization } }
}
test from: :crd_client_fhir_api_include_search_test,
id: :crd_client_fhir_api_practitioner_role_practitioner_include_search,
title: 'Search by _id and _include practitioner',
config: {
options: { resource_type: 'PractitionerRole',
target_include_element: 'practitioner' },
inputs: { search_ids: { name: :practitioner_role_id_with_practitioner } }
}
test from: :crd_client_fhir_api_practitioner_role_validation_test
test from: :crd_client_fhir_api_practitioner_role_must_support_test
test from: :crd_client_fhir_api_practitioner_role_reference_resolution_test
end
end
40 changes: 0 additions & 40 deletions lib/davinci_crd_test_kit/client_tests/client_fhir_api_read_test.rb

This file was deleted.

Loading