davinci_plan_net_test_kit 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/config/presets/plan_net_reference_server_v110_preset.json +50 -0
- data/lib/davinci_plan_net_test_kit/custom_groups/reverse_chain_tests/examples.md +17 -0
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/davinci_plan_net_test_suite.rb +5 -2
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/endpoint/endpoint_forward_chain_organization_address_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/endpoint/endpoint_forward_chain_organization_name_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/endpoint/endpoint_forward_chain_organization_partof_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/endpoint/endpoint_forward_chain_organization_type_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/endpoint/metadata.yml +4 -4
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/endpoint_group.rb +4 -4
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service/healthcare_service_forward_chain_endpoint_organization_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service/healthcare_service_forward_chain_location_address_city_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service/healthcare_service_forward_chain_location_address_postalcode_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service/healthcare_service_forward_chain_location_address_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service/healthcare_service_forward_chain_location_address_state_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service/healthcare_service_forward_chain_location_organization_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service/healthcare_service_forward_chain_location_type_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service/healthcare_service_forward_chain_organization_address_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service/healthcare_service_forward_chain_organization_name_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service/healthcare_service_forward_chain_organization_partof_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service/healthcare_service_forward_chain_organization_type_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service/metadata.yml +11 -11
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service_group.rb +11 -11
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/insurance_plan/insurance_plan_forward_chain_administered_by_name_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/insurance_plan/insurance_plan_forward_chain_administered_by_partof_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/insurance_plan/insurance_plan_forward_chain_owned_by_name_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/insurance_plan/insurance_plan_forward_chain_owned_by_partof_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/insurance_plan/metadata.yml +4 -4
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/insurance_plan_group.rb +4 -4
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/location/location_forward_chain_endpoint_organization_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/location/location_forward_chain_organization_address_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/location/location_forward_chain_organization_name_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/location/location_forward_chain_organization_partof_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/location/location_forward_chain_organization_type_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/location/location_forward_chain_partof_address_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/location/location_forward_chain_partof_organization_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/location/location_forward_chain_partof_type_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/location/metadata.yml +8 -8
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/location_group.rb +8 -8
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/metadata.yml +6 -6
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/network/metadata.yml +4 -4
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/network/network_forward_chain_endpoint_organization_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/network/network_forward_chain_partof_address_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/network/network_forward_chain_partof_name_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/network/network_forward_chain_partof_type_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/network_group.rb +4 -4
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/metadata.yml +20 -20
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_endpoint_organization_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_location_address_city_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_location_address_postalcode_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_location_address_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_location_address_state_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_location_organization_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_location_type_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_network_name_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_network_partof_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_participating_organization_address_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_participating_organization_name_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_participating_organization_partof_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_participating_organization_type_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_primary_organization_address_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_primary_organization_name_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_primary_organization_partof_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_primary_organization_type_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_service_location_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_service_organization_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_service_service_category_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil_group.rb +20 -20
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/organization/metadata.yml +4 -4
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/organization/organization_forward_chain_endpoint_organization_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/organization/organization_forward_chain_partof_address_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/organization/organization_forward_chain_partof_name_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/organization/organization_forward_chain_partof_type_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/organization_group.rb +4 -4
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/metadata.yml +25 -25
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_endpoint_organization_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_location_address_city_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_location_address_postalcode_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_location_address_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_location_address_state_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_location_organization_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_location_type_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_network_address_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_network_name_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_network_partof_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_network_type_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_organization_address_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_organization_name_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_organization_partof_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_organization_type_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_practitioner_name_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_service_location_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_service_organization_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_service_service_category_search_test.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role_group.rb +19 -19
- data/lib/davinci_plan_net_test_kit/generator/forward_chain_test_generator.rb +1 -1
- data/lib/davinci_plan_net_test_kit/generator/templates/combination_search_test.rb.erb +49 -0
- data/lib/davinci_plan_net_test_kit/generator/templates/forward_chain_test.rb.erb +51 -0
- data/lib/davinci_plan_net_test_kit/generator/templates/group.rb.erb +24 -0
- data/lib/davinci_plan_net_test_kit/generator/templates/include_search.rb.erb +48 -0
- data/lib/davinci_plan_net_test_kit/generator/templates/must_support.rb.erb +41 -0
- data/lib/davinci_plan_net_test_kit/generator/templates/read.rb.erb +26 -0
- data/lib/davinci_plan_net_test_kit/generator/templates/reference_resolution.rb.erb +42 -0
- data/lib/davinci_plan_net_test_kit/generator/templates/resource_list.rb.erb +9 -0
- data/lib/davinci_plan_net_test_kit/generator/templates/reverse_chain_search.rb.erb +57 -0
- data/lib/davinci_plan_net_test_kit/generator/templates/revinclude_search.rb.erb +55 -0
- data/lib/davinci_plan_net_test_kit/generator/templates/search.rb.erb +40 -0
- data/lib/davinci_plan_net_test_kit/generator/templates/search_no_params.rb.erb +45 -0
- data/lib/davinci_plan_net_test_kit/generator/templates/suite.rb.erb +222 -0
- data/lib/davinci_plan_net_test_kit/generator/templates/validation.rb.erb +31 -0
- data/lib/davinci_plan_net_test_kit/igs/Plan Net Requirements Interpretation.xlsx +0 -0
- data/lib/davinci_plan_net_test_kit/igs/README.md +21 -0
- data/lib/davinci_plan_net_test_kit/metadata.rb +64 -0
- data/lib/davinci_plan_net_test_kit/search_test.rb +12 -60
- data/lib/davinci_plan_net_test_kit/version.rb +2 -1
- data/lib/davinci_plan_net_test_kit.rb +1 -0
- metadata +30 -10
@@ -0,0 +1,40 @@
|
|
1
|
+
require_relative '../../../search_test'
|
2
|
+
require_relative '../../../generator/group_metadata'
|
3
|
+
|
4
|
+
module DaVinciPlanNetTestKit
|
5
|
+
module <%= module_name %>
|
6
|
+
class <%= class_name %> < Inferno::Test
|
7
|
+
include DaVinciPlanNetTestKit::SearchTest
|
8
|
+
|
9
|
+
title 'Server returns valid results for <%= resource_type %> search by <%= search_param_name_string %>'
|
10
|
+
description %(
|
11
|
+
<%= description %>
|
12
|
+
)
|
13
|
+
|
14
|
+
id :<%= test_id %><% if optional? %>
|
15
|
+
optional
|
16
|
+
<% end %><% if needs_resource_id? %>
|
17
|
+
input :<%= resource_type %>_ids,
|
18
|
+
title: '<%= resource_type %> IDs',
|
19
|
+
description: 'Comma separated list of <%= resource_type %> IDs that in sum contain all MUST SUPPORT elements'
|
20
|
+
<% end %>
|
21
|
+
def self.properties
|
22
|
+
@properties ||= SearchTestProperties.new(
|
23
|
+
<%= search_test_properties_string %>
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.metadata
|
28
|
+
@metadata ||= Generator::GroupMetadata.new(YAML.load_file(File.join(__dir__, 'metadata.yml'), aliases: true))
|
29
|
+
end
|
30
|
+
|
31
|
+
def scratch_resources
|
32
|
+
scratch[:<%= profile_identifier %>_resources] ||= {}
|
33
|
+
end
|
34
|
+
|
35
|
+
run do
|
36
|
+
run_search_test
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative '../../../search_test'
|
2
|
+
require_relative '../../../generator/group_metadata'
|
3
|
+
|
4
|
+
module DaVinciPlanNetTestKit
|
5
|
+
module <%= module_name %>
|
6
|
+
class <%= class_name %> < Inferno::Test
|
7
|
+
include DaVinciPlanNetTestKit::SearchTest
|
8
|
+
|
9
|
+
title 'Client can identify instances of <%= profile_name %> on the server'
|
10
|
+
description %(
|
11
|
+
<%= description %>
|
12
|
+
)
|
13
|
+
|
14
|
+
id :<%= test_id %><% if optional? %>
|
15
|
+
optional
|
16
|
+
<% end %>
|
17
|
+
|
18
|
+
input :<%= test_id %>_ids,
|
19
|
+
title: 'ids of <%= profile_name %> instances',
|
20
|
+
optional: true,
|
21
|
+
description: 'Required if parameterless searches are not being used for instance gathering.'
|
22
|
+
input :no_param_search
|
23
|
+
input :max_instances
|
24
|
+
input :max_pages
|
25
|
+
|
26
|
+
def self.properties
|
27
|
+
@properties ||= SearchTestProperties.new(
|
28
|
+
<%= search_test_properties_string %>
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.metadata
|
33
|
+
@metadata ||= Generator::GroupMetadata.new(YAML.load_file(File.join(__dir__, 'metadata.yml'), aliases: true))
|
34
|
+
end
|
35
|
+
|
36
|
+
def scratch_resources
|
37
|
+
scratch[:<%= profile_identifier %>_resources] ||= {}
|
38
|
+
end
|
39
|
+
|
40
|
+
run do
|
41
|
+
run_search_no_params_test(<%= test_id %>_ids)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,222 @@
|
|
1
|
+
require 'inferno/dsl/oauth_credentials'
|
2
|
+
require_relative '../../version'
|
3
|
+
require_relative '<%= capability_statement_file_name %>'
|
4
|
+
<% group_file_list.each do |file_name| %>require_relative '<%= file_name %>'
|
5
|
+
<% end %>
|
6
|
+
module DaVinciPlanNetTestKit
|
7
|
+
module <%= module_name %>
|
8
|
+
class <%= class_name %> < Inferno::TestSuite
|
9
|
+
title '<%= title %>'
|
10
|
+
description %(
|
11
|
+
The Plan Net Test Kit tests servers for their conformance to the [Plan Net
|
12
|
+
Implementation Guide](<%=ig_link %>).
|
13
|
+
|
14
|
+
## Scope
|
15
|
+
|
16
|
+
These tests are a **DRAFT** intended to allow Plan Net server implementers to perform
|
17
|
+
preliminary checks of their servers against Plan Net IG requirements and [provide
|
18
|
+
feedback](https://github.com/inferno-framework/davinci-plan-net-test-kit/issues)
|
19
|
+
to ONC on the tests. Future versions of these tests may validate other
|
20
|
+
requirements and may change the test validation logic.
|
21
|
+
|
22
|
+
## Test Methodology
|
23
|
+
|
24
|
+
Inferno will act as a client and make a series of requests to the
|
25
|
+
server under test. The responses will be checked for conformance to the Plan
|
26
|
+
Net IG requirements individually and used in aggregate to determine whether
|
27
|
+
required features and functionality are present.
|
28
|
+
|
29
|
+
HL7® FHIR® resources are validated with the Java validator using
|
30
|
+
`tx.fhir.org` as the terminology server.
|
31
|
+
|
32
|
+
## Running the Tests
|
33
|
+
|
34
|
+
### Quick Start
|
35
|
+
|
36
|
+
The tests are designed to be runnable with a single input from the user:
|
37
|
+
the base FHIR URL of the server under test. To run in this mode:
|
38
|
+
1. Click the `RUN ALL TESTS` button in the upper right
|
39
|
+
2. Provide the URL for the server in the first "FHIR Endpoint (required)" input
|
40
|
+
3. Click the `Submit` button in the lower right of the input display
|
41
|
+
4. Wait for Inferno to run the tests (will take several minutes)
|
42
|
+
5. Expand tests with failures to determine the reason
|
43
|
+
|
44
|
+
If you would like to try out the tests but don't have a Plan Net server implementation,
|
45
|
+
you can use the publicly available reference implementation available at URL
|
46
|
+
https://plan-net-ri.davinci.hl7.org/fhir. Select this endpoint by using that URL as the
|
47
|
+
"FHIR Endpoint (required)" input or prepopulating it by selecting the
|
48
|
+
`Da Vinci Plan Net Reference Server` preset in the upper left. Note that this
|
49
|
+
system is not currently expected to pass all of the tests.
|
50
|
+
|
51
|
+
The feedback provided may require
|
52
|
+
- Configuration updates (see *Test Configuration Details* below) to better guide Inferno's test execution.
|
53
|
+
- Additional data within the system under test, e.g., to demonstrate all Must Support elements.
|
54
|
+
- Fixes to the system under test.
|
55
|
+
|
56
|
+
Note that this mode requires that the server support parameterless searches against
|
57
|
+
Plan Net resource types (e.g., `GET [FHIR Endpoint]/InsurancePlan`), which are not required
|
58
|
+
by the Plan Net IG. If your server does not support these searches, or some returned instances
|
59
|
+
will not conform to Plan Net profiles, see the *Instance Gathering* section under
|
60
|
+
*Test Configuration Details* below for how to disable these searches and direct the tests
|
61
|
+
toward specific instances of each profile instead.
|
62
|
+
|
63
|
+
### Running Groups Individually
|
64
|
+
|
65
|
+
Each test group listed on the left can be run individually using the `RUN TESTS`
|
66
|
+
button in the upper right of the group page. However, note that running
|
67
|
+
them individually requires additional inputs so that Inferno can find appropriate values for searches
|
68
|
+
(see *Determination of Search Values When Running Single Groups* below for details).
|
69
|
+
|
70
|
+
## Test Configuration Details
|
71
|
+
|
72
|
+
The details provided here supplement the documentation of individual inputs in the input dialog
|
73
|
+
that appears when initiating a test run.
|
74
|
+
|
75
|
+
### Authentication
|
76
|
+
|
77
|
+
The Plan Net IG requires that "A conformant Plan-Net service SHALL NOT
|
78
|
+
require a directory mobile application to send consumer identifying information
|
79
|
+
in order to query content." A simple way to ensure this is to not require authentication,
|
80
|
+
which is safe because the information in scope does not include PHI. Thus, the
|
81
|
+
tests do not send authentication details by default.
|
82
|
+
|
83
|
+
If a server under test requires authentication information to be sent, an access token
|
84
|
+
may be provided using the "OAuth Credentials - Access Token" input. When populated,
|
85
|
+
requests to the server will include an HTTP header of the form `Authorization: Bearer [access token]`.
|
86
|
+
|
87
|
+
### Instance Gathering
|
88
|
+
|
89
|
+
Inferno needs to identify instances of each profile to use to validate conformance to
|
90
|
+
structural and search API requirements. Inferno will use one or a combination of the
|
91
|
+
following two approaches as directed by the inputs.
|
92
|
+
|
93
|
+
#### Parameterless searches (default)
|
94
|
+
|
95
|
+
Inferno will use a search against the base resource type without any search
|
96
|
+
parameters (`GET [FHIR Endpoint]/[Resource Type]`) to identify instances of each profile.
|
97
|
+
This behavior can be controlled using the following inputs:
|
98
|
+
- "Use parameterless searches to identify instances?": if the server under test does not support
|
99
|
+
parameterless searches, this can be set to `No` to disable parameterless searches.
|
100
|
+
- "Maximum number of instances to gather using parameterless searches (required)" and
|
101
|
+
"Maximum pages of results to consider when using parameterless searches (required)": if fewer
|
102
|
+
instances (e.g., to improve performance) or more instances (e.g., to improve Must Support
|
103
|
+
element coverage) should be gathered, these inputs can be adjusted to tune the number
|
104
|
+
of instances that Inferno will gather using parameterless searches.
|
105
|
+
|
106
|
+
#### Specific instance ids
|
107
|
+
|
108
|
+
Inputs of the form "ids of [profile] instances" can be used by the user to specify particular
|
109
|
+
instances for Inferno to gather for use in testing. Inferno will perform a read on each provided id
|
110
|
+
to gather the instances. When parameterless searches are not used, all inputs of this form must be populated.
|
111
|
+
When instance ids are provided in addition to parameterless searches, instances provided by the user
|
112
|
+
are prioritized for use in determining search values for search tests.
|
113
|
+
|
114
|
+
### Determination of Search Values When Running Single Groups
|
115
|
+
|
116
|
+
Validation of search parameters requires Inferno to identify values that are expected
|
117
|
+
to return instances. By default, Inferno does this by examining gathered instances of each profile
|
118
|
+
to identify search values that should return results when performed against the server under
|
119
|
+
test. For `_revinclude` and reverse chaining tests, Inferno needs access to instances of other profiles
|
120
|
+
in order to determine appropriate search values. When test groups are run individually, Inferno will not
|
121
|
+
have access to instances identified while running other groups. Thus, when running at the group level,
|
122
|
+
two additional inputs are required to allow the tests to identify appropriate search values:
|
123
|
+
- "[target profile] instance ids referenced in [referencing profile].[reference element]":
|
124
|
+
used by `_revinclude` tests on [target profile] when run as a group to identify
|
125
|
+
instances of the [target profile] that have instances of [referencing profile] that reference it.
|
126
|
+
- "'[constraining element]' value from a [referencing profile] instance with '[reference element]' populated": used by reverse chaining tests
|
127
|
+
on the [target profile] referenced in the [reference element] element when run as a single group
|
128
|
+
to identify the value to use when performing the reverse chain search.
|
129
|
+
)
|
130
|
+
version VERSION
|
131
|
+
|
132
|
+
VALIDATION_MESSAGE_FILTERS = [
|
133
|
+
%r{Sub-extension url 'introspect' is not defined by the Extension http://fhir-registry\.smarthealthit\.org/StructureDefinition/oauth-uris},
|
134
|
+
%r{Sub-extension url 'revoke' is not defined by the Extension http://fhir-registry\.smarthealthit\.org/StructureDefinition/oauth-uris},
|
135
|
+
/Observation\.effective\.ofType\(Period\): .*us-core-1:/, # Invalid invariant in US Core v3.1.1
|
136
|
+
/\A\S+: \S+: URL value '.*' does not resolve/,
|
137
|
+
].freeze
|
138
|
+
|
139
|
+
VERSION_SPECIFIC_MESSAGE_FILTERS = <%=version_specific_message_filters%>.freeze
|
140
|
+
|
141
|
+
def self.metadata
|
142
|
+
@metadata ||= YAML.load_file(File.join(__dir__, 'metadata.yml'), aliases: true)[:groups].map do |raw_metadata|
|
143
|
+
Generator::GroupMetadata.new(raw_metadata)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
id :<%= suite_id %>
|
148
|
+
|
149
|
+
fhir_resource_validator do
|
150
|
+
igs '<%= ig_identifier %>'
|
151
|
+
|
152
|
+
message_filters = VALIDATION_MESSAGE_FILTERS + VERSION_SPECIFIC_MESSAGE_FILTERS
|
153
|
+
|
154
|
+
exclude_message do |message|
|
155
|
+
|
156
|
+
message_filters.any? { |filter| filter.match? message.message }
|
157
|
+
end
|
158
|
+
|
159
|
+
perform_additional_validation do |resource, profile_url|
|
160
|
+
ProvenanceValidator.validate(resource) if resource.instance_of?(FHIR::Provenance)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
links [
|
165
|
+
{
|
166
|
+
label: 'Report Issue',
|
167
|
+
url: 'https://github.com/inferno-framework/davinci-plan-net-test-kit/issues'
|
168
|
+
},
|
169
|
+
{
|
170
|
+
label: 'Source Code',
|
171
|
+
url: 'https://github.com/inferno-framework/davinci-plan-net-test-kit'
|
172
|
+
},
|
173
|
+
{
|
174
|
+
label: 'Implementation Guide',
|
175
|
+
url: '<%=ig_link %>'
|
176
|
+
}
|
177
|
+
]
|
178
|
+
|
179
|
+
input :url,
|
180
|
+
title: 'FHIR Endpoint',
|
181
|
+
description: 'URL of the FHIR endpoint'
|
182
|
+
input :smart_credentials,
|
183
|
+
title: 'OAuth Credentials',
|
184
|
+
type: :oauth_credentials,
|
185
|
+
optional: true
|
186
|
+
input :no_param_search,
|
187
|
+
title: 'Use parameterless searches to identify instances?',
|
188
|
+
type: 'radio',
|
189
|
+
options: {
|
190
|
+
list_options: [
|
191
|
+
{
|
192
|
+
label: 'Yes',
|
193
|
+
value: 'true'
|
194
|
+
},
|
195
|
+
{
|
196
|
+
label: 'No',
|
197
|
+
value: 'false'
|
198
|
+
}
|
199
|
+
]
|
200
|
+
},
|
201
|
+
default: 'true',
|
202
|
+
description: 'If `Yes`, Inferno will gather instances of each profile using searches of the form `GET [FHIR Endpoint]/[resource type]`. If searches of this form are not supported or some instances on the server will not be expected to conform to Plan Net profiles, select `No` and enter instance ids of each profile in the "ids of [profile] instances" inputs.'
|
203
|
+
input :max_instances,
|
204
|
+
title: 'Maximum number of instances to gather using parameterless searches',
|
205
|
+
default: '200',
|
206
|
+
description: 'Only used with parameterless searches. A higher number will gather more instances for the tests, if they are available. The test will stop looking when the page limit has been reached.'
|
207
|
+
input :max_pages,
|
208
|
+
title: 'Maximum pages of results to consider when using parameterless searches',
|
209
|
+
default: '20',
|
210
|
+
description: 'Only used with parameterless searches. A higher number will gather more instances for the tests, if they are available. The test will not consider further pages once the maximum number of instances has been reached.'
|
211
|
+
|
212
|
+
fhir_client do
|
213
|
+
url :url
|
214
|
+
oauth_credentials :smart_credentials
|
215
|
+
end
|
216
|
+
|
217
|
+
group from: :<%= capability_statement_group_id %>
|
218
|
+
<% group_id_list.each do |id| %>
|
219
|
+
group from: :<%= id %><% end %>
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require_relative '../../../validation_test'
|
2
|
+
|
3
|
+
module DaVinciPlanNetTestKit
|
4
|
+
module <%= module_name %>
|
5
|
+
class <%= class_name %> < Inferno::Test
|
6
|
+
include DaVinciPlanNetTestKit::ValidationTest
|
7
|
+
|
8
|
+
id :<%= test_id %>
|
9
|
+
title '<%= resource_type %> resources returned during previous tests conform to the <%= profile_name %>'
|
10
|
+
description %(
|
11
|
+
<%= description %>
|
12
|
+
)
|
13
|
+
output :dar_code_found, :dar_extension_found
|
14
|
+
|
15
|
+
def resource_type
|
16
|
+
'<%= resource_type %>'
|
17
|
+
end
|
18
|
+
|
19
|
+
def scratch_resources
|
20
|
+
scratch[:<%= profile_identifier %>_resources] ||= {}
|
21
|
+
end
|
22
|
+
|
23
|
+
run do
|
24
|
+
perform_validation_test(scratch_resources[:all] || [],
|
25
|
+
'<%= profile_url %>',
|
26
|
+
'<%= profile_version %>',
|
27
|
+
skip_if_empty: <%= skip_if_empty %>)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# Note on this IGs folder
|
2
|
+
|
3
|
+
There are three reasons why it would be necessary to put an IG package.tgz in this folder. If none of these apply, you do not need to put any files here, or can consider removing any existing files to make it clear they are unused.
|
4
|
+
|
5
|
+
## 1. Generated Test Suites
|
6
|
+
Some test kits use a "generator" to automatically generate the contents of a test suite for an IG. The IG files are required every time the test suites need to be regenerated. Examples of test kits that use this approach are the US Core Test Kit and CARIN IG for Blue Button® Test Kit.
|
7
|
+
|
8
|
+
|
9
|
+
## 2. Non-published IG
|
10
|
+
If your IG, or the specific version of the IG you want to test against, is not published, then the validator service needs to load the IG from file in order to be able to validate resources with it. The IG must be referenced in the `fhir_resource_validator` block in the test suite definition by filename, ie:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
fhir_resource_validator do
|
14
|
+
igs 'igs/filename.tgz'
|
15
|
+
|
16
|
+
...
|
17
|
+
end
|
18
|
+
```
|
19
|
+
|
20
|
+
## 3. Inferno Validator UI
|
21
|
+
The Inferno Validator UI is configured to auto-load any IGs present in the igs folder and include them in all validations. The Inferno Validator UI is currently disabled by default, so this is only relevant if you choose to re-enable it. In general, the Inferno team is currently leaving IGs in this folder even if not otherwise necessary to make it easy to re-enable the validator UI.
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module DaVinciPlanNetTestKit
|
2
|
+
class Metadata < Inferno::TestKit
|
3
|
+
id :davinci_plan_net_test_kit
|
4
|
+
title 'Da Vinci Plan Net Test Kit'
|
5
|
+
suite_ids [ 'davinci_plan_net_server_v110' ]
|
6
|
+
tags ['Da Vinci']
|
7
|
+
last_updated ::DaVinciPlanNetTestKit::LAST_UPDATED
|
8
|
+
version ::DaVinciPlanNetTestKit::VERSION
|
9
|
+
maturity 'Low'
|
10
|
+
authors ['Karl Naden']
|
11
|
+
repo 'https://github.com/inferno-framework/davinci-plan-net-test-kit'
|
12
|
+
description <<~DESCRIPTION
|
13
|
+
The DaVinci Plan Net Test Kit validates the conformance of a server
|
14
|
+
implementation to version 1.1.0 of the
|
15
|
+
[DaVinci PDEX Plan Net Implementation Guide](http://hl7.org/fhir/us/davinci-pdex-plan-net/STU1.1).
|
16
|
+
|
17
|
+
<!-- break -->
|
18
|
+
|
19
|
+
Inferno will act as a client and make a series of requests to the
|
20
|
+
server under test. The responses will be checked for conformance
|
21
|
+
to the Plan Net IG requirements individually and used in aggregate
|
22
|
+
to determine whether required features and functionality are present.
|
23
|
+
|
24
|
+
The test kit currently tests the following requirements:
|
25
|
+
|
26
|
+
- Support for Must Support Elements
|
27
|
+
- JSON Support
|
28
|
+
- Support for all Plan Net Profiles
|
29
|
+
- Read Interaction
|
30
|
+
- Individual Search Parameters
|
31
|
+
- _include Searches
|
32
|
+
- _revinclude Searches
|
33
|
+
- Forward Chain Searches
|
34
|
+
- Reverse Chain Searches
|
35
|
+
- Search Parameters in Combination
|
36
|
+
|
37
|
+
The DaVinci Plan Net Test Kit is built using the
|
38
|
+
[Inferno Framework](https://inferno-framework.github.io/).
|
39
|
+
The Inferno Framework is designed for reuse and aims to make it easier
|
40
|
+
to build test kits for any FHIR-based data exchange.
|
41
|
+
|
42
|
+
### Known Limitations
|
43
|
+
|
44
|
+
The following areas of the IG are not fully tested in this draft version
|
45
|
+
of the test kit:
|
46
|
+
|
47
|
+
- All search parameter combinations: the tests check for support of only
|
48
|
+
specific combinations of search parameters driven by
|
49
|
+
[anticipated searches listed in the IG](http://hl7.org/fhir/us/davinci-pdex-plan-net/implementation.html#Representing).
|
50
|
+
- Response classes: the Plan Net IG lists HTTP response codes that the
|
51
|
+
server needs to be able to return, but does not indicate specific
|
52
|
+
criteria for requests that elicit these status codes.
|
53
|
+
|
54
|
+
Additional details on these and other areas where the tests may not align
|
55
|
+
with the IGs requirements, see this requirements analysis spreadsheet.
|
56
|
+
|
57
|
+
## Reporting Issues
|
58
|
+
|
59
|
+
Please report any issues with this set of tests in the
|
60
|
+
[GitHub Issues](https://github.com/inferno-framework/davinci-plan-net-test-kit/issues)
|
61
|
+
section of this repository.
|
62
|
+
DESCRIPTION
|
63
|
+
end
|
64
|
+
end
|
@@ -203,7 +203,7 @@ module DaVinciPlanNetTestKit
|
|
203
203
|
|
204
204
|
check_search_response
|
205
205
|
|
206
|
-
returned_resources = fetch_all_bundled_resources(additional_resource_types: [additional_resource_type])
|
206
|
+
returned_resources = fetch_all_bundled_resources(resource_type: self.resource_type, additional_resource_types: [additional_resource_type])
|
207
207
|
|
208
208
|
base_resources = returned_resources
|
209
209
|
.select { |res| res.resourceType == resource_type }
|
@@ -238,7 +238,7 @@ module DaVinciPlanNetTestKit
|
|
238
238
|
|
239
239
|
check_search_response
|
240
240
|
|
241
|
-
matching_resources = fetch_all_bundled_resources(additional_resource_types: [additional_resource_type])
|
241
|
+
matching_resources = fetch_all_bundled_resources(resource_type: self.resource_type, additional_resource_types: [additional_resource_type])
|
242
242
|
.select { |res| res.resourceType == additional_resource_type }
|
243
243
|
.reject { |res| res.id == params[:_id] }
|
244
244
|
|
@@ -306,7 +306,7 @@ module DaVinciPlanNetTestKit
|
|
306
306
|
fhir_search additional_resource_type, params: additional_resource_params
|
307
307
|
|
308
308
|
check_search_response
|
309
|
-
additional_resources = fetch_all_bundled_resources(additional_resource_types: [additional_resource_type])
|
309
|
+
additional_resources = fetch_all_bundled_resources(resource_type: self.resource_type, additional_resource_types: [additional_resource_type])
|
310
310
|
.select { |res| res.resourceType == additional_resource_type }
|
311
311
|
|
312
312
|
additional_resources.each { |res| check_resource_against_params(res, additional_resource_params) }
|
@@ -328,7 +328,7 @@ module DaVinciPlanNetTestKit
|
|
328
328
|
|
329
329
|
check_search_response
|
330
330
|
|
331
|
-
returned_resources = fetch_all_bundled_resources(additional_resource_types: [additional_resource_type])
|
331
|
+
returned_resources = fetch_all_bundled_resources(resource_type: self.resource_type, additional_resource_types: [additional_resource_type])
|
332
332
|
assert !returned_resources.empty?, "No #{resource_type} resources returned"
|
333
333
|
base_resources = returned_resources
|
334
334
|
.select { |res| res.resourceType == resource_type }
|
@@ -356,7 +356,7 @@ module DaVinciPlanNetTestKit
|
|
356
356
|
|
357
357
|
check_search_response
|
358
358
|
|
359
|
-
returned_resources = fetch_all_bundled_resources(additional_resource_types: [additional_resource_type])
|
359
|
+
returned_resources = fetch_all_bundled_resources(resource_type: self.resource_type, additional_resource_types: [additional_resource_type])
|
360
360
|
input_based_skip_assert(returned_resources, "No resources found.")
|
361
361
|
base_resources = returned_resources
|
362
362
|
.select { |res| res.resourceType == resource_type }
|
@@ -380,7 +380,7 @@ module DaVinciPlanNetTestKit
|
|
380
380
|
|
381
381
|
check_search_response
|
382
382
|
|
383
|
-
returned_resources = fetch_all_bundled_resources(additional_resource_types: [additional_resource_type])
|
383
|
+
returned_resources = fetch_all_bundled_resources(resource_type: self.resource_type, additional_resource_types: [additional_resource_type])
|
384
384
|
assert !returned_resources.empty?, "No #{resource_type} resources found"
|
385
385
|
|
386
386
|
base_resources = returned_resources
|
@@ -424,7 +424,7 @@ module DaVinciPlanNetTestKit
|
|
424
424
|
check_search_response
|
425
425
|
|
426
426
|
resources_returned =
|
427
|
-
fetch_all_bundled_resources.select { |resource| resource.resourceType == resource_type }
|
427
|
+
fetch_all_bundled_resources(resource_type: self.resource_type).select { |resource| resource.resourceType == resource_type }
|
428
428
|
|
429
429
|
return [] if resources_returned.blank?
|
430
430
|
|
@@ -456,7 +456,7 @@ module DaVinciPlanNetTestKit
|
|
456
456
|
|
457
457
|
check_search_response
|
458
458
|
|
459
|
-
post_search_resources = fetch_all_bundled_resources.select { |resource| resource.resourceType == resource_type }
|
459
|
+
post_search_resources = fetch_all_bundled_resources(resource_type: self.resource_type).select { |resource| resource.resourceType == resource_type }
|
460
460
|
|
461
461
|
filter_conditions(post_search_resources) if resource_type == 'Condition' && metadata.version == 'v5.0.1'
|
462
462
|
filter_devices(post_search_resources) if resource_type == 'Device'
|
@@ -562,7 +562,7 @@ module DaVinciPlanNetTestKit
|
|
562
562
|
|
563
563
|
search_and_check_response(params_with_comparator)
|
564
564
|
|
565
|
-
fetch_all_bundled_resources.each do |resource|
|
565
|
+
fetch_all_bundled_resources(resource_type: self.resource_type).each do |resource|
|
566
566
|
check_resource_against_params(resource, params_with_comparator) if resource.resourceType == resource_type
|
567
567
|
end
|
568
568
|
end
|
@@ -578,7 +578,7 @@ module DaVinciPlanNetTestKit
|
|
578
578
|
new_search_params = params.merge(resource_type.underscore => "#{resource_type}/#{params['resource']}")
|
579
579
|
search_and_check_response(new_search_params)
|
580
580
|
|
581
|
-
reference_with_type_resources = fetch_all_bundled_resources.select { |resource| resource.resourceType == resource_type }
|
581
|
+
reference_with_type_resources = fetch_all_bundled_resources(resource_type: self.resource_type).select { |resource| resource.resourceType == resource_type }
|
582
582
|
|
583
583
|
|
584
584
|
new_resource_count = reference_with_type_resources.count
|
@@ -601,7 +601,7 @@ module DaVinciPlanNetTestKit
|
|
601
601
|
search_and_check_response(search_params)
|
602
602
|
|
603
603
|
resources_returned =
|
604
|
-
fetch_all_bundled_resources
|
604
|
+
fetch_all_bundled_resources(resource_type: self.resource_type)
|
605
605
|
.select { |resource| resource.resourceType == resource_type }
|
606
606
|
|
607
607
|
assert resources_returned.present?, "No resources were returned when searching by `system|code`"
|
@@ -672,7 +672,7 @@ module DaVinciPlanNetTestKit
|
|
672
672
|
search_and_check_response(search_params)
|
673
673
|
|
674
674
|
resources_returned =
|
675
|
-
fetch_all_bundled_resources
|
675
|
+
fetch_all_bundled_resources(resource_type: self.resource_type)
|
676
676
|
.select { |resource| resource.resourceType == resource_type }
|
677
677
|
|
678
678
|
multiple_or_search_params.each do |param_name|
|
@@ -855,54 +855,6 @@ module DaVinciPlanNetTestKit
|
|
855
855
|
"#{msg}."
|
856
856
|
end
|
857
857
|
|
858
|
-
def fetch_all_bundled_resources(
|
859
|
-
reply_handler: nil,
|
860
|
-
max_pages: 0,
|
861
|
-
additional_resource_types: [],
|
862
|
-
resource_type: self.resource_type
|
863
|
-
)
|
864
|
-
page_count = 1
|
865
|
-
resources = []
|
866
|
-
bundle = resource
|
867
|
-
resources += bundle&.entry&.map { |entry| entry&.resource }
|
868
|
-
|
869
|
-
until bundle.nil? || (page_count == max_pages && max_pages != 0)
|
870
|
-
|
871
|
-
next_bundle_link = bundle&.link&.find { |link| link.relation == 'next' }&.url
|
872
|
-
reply_handler&.call(response)
|
873
|
-
|
874
|
-
break if next_bundle_link.blank?
|
875
|
-
|
876
|
-
reply = fhir_client.raw_read_url(next_bundle_link)
|
877
|
-
|
878
|
-
store_request('outgoing') { reply }
|
879
|
-
error_message = cant_resolve_next_bundle_message(next_bundle_link)
|
880
|
-
|
881
|
-
assert_response_status(200)
|
882
|
-
assert_valid_json(reply.body, error_message)
|
883
|
-
|
884
|
-
bundle = fhir_client.parse_reply(FHIR::Bundle, fhir_client.default_format, reply)
|
885
|
-
resources += bundle&.entry&.map { |entry| entry&.resource }
|
886
|
-
|
887
|
-
page_count += 1
|
888
|
-
end
|
889
|
-
|
890
|
-
valid_resource_types = [resource_type, 'OperationOutcome'].concat(additional_resource_types)
|
891
|
-
|
892
|
-
invalid_resource_types =
|
893
|
-
resources.reject { |entry| valid_resource_types.include? entry.resourceType }
|
894
|
-
.map(&:resourceType)
|
895
|
-
.uniq
|
896
|
-
|
897
|
-
if invalid_resource_types.any?
|
898
|
-
info "Received resource type(s) #{invalid_resource_types.join(', ')} in search bundle, " \
|
899
|
-
"but only expected resource types #{valid_resource_types.join(', ')}. " + \
|
900
|
-
"This is unusual but allowed if the server believes additional resource types are relevant."
|
901
|
-
end
|
902
|
-
|
903
|
-
resources
|
904
|
-
end
|
905
|
-
|
906
858
|
def fetch_matching_bundled_resources(
|
907
859
|
max_pages: 20,
|
908
860
|
max_instances: 200,
|