cancer_pathology_data_sharing_test_kit 0.9.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 +7 -0
- data/LICENSE +201 -0
- data/config/presets/demo_report.json +14 -0
- data/config/presets/inferno_reference_server_preset.json.erb +39 -0
- data/lib/cancer_pathology_data_sharing_test_kit/bundle_parse.rb +53 -0
- data/lib/cancer_pathology_data_sharing_test_kit/docs/data_access_suite_description.md +83 -0
- data/lib/cancer_pathology_data_sharing_test_kit/docs/report_generation_suite_description.md +118 -0
- data/lib/cancer_pathology_data_sharing_test_kit/fhir_resource_navigation.rb +174 -0
- data/lib/cancer_pathology_data_sharing_test_kit/group_metadata.rb +82 -0
- data/lib/cancer_pathology_data_sharing_test_kit/igs/.keep +0 -0
- data/lib/cancer_pathology_data_sharing_test_kit/igs/README.md +21 -0
- data/lib/cancer_pathology_data_sharing_test_kit/metadata.rb +75 -0
- data/lib/cancer_pathology_data_sharing_test_kit/must_support_test.rb +239 -0
- data/lib/cancer_pathology_data_sharing_test_kit/primitive_type.rb +5 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/data_absent/data_absent_reason_code_system.rb +22 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/data_absent/data_absent_reason_extension.rb +20 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/data_absent/sending_hide_missing.rb +28 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/data_absent_group.rb +27 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/exchange_bundle/encounter/encounter_must_support_test.rb +53 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/exchange_bundle/encounter/encounter_validation_test.rb +48 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/exchange_bundle/encounter/metadata.yml +281 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/exchange_bundle/patient/metadata.yml +305 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/exchange_bundle/patient/patient_must_support_test.rb +58 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/exchange_bundle/patient/patient_validation_test.rb +47 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/exchange_bundle/practitioner_role/metadata.yml +44 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/exchange_bundle/practitioner_role/practitioner_role_must_support_test.rb +45 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/exchange_bundle/practitioner_role/practitioner_role_validation_test.rb +47 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/exchange_bundle/service_request/metadata.yml +75 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/exchange_bundle/service_request/service_request_must_support_test.rb +52 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/exchange_bundle/service_request/service_request_validation_test.rb +47 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/exchange_bundle/specimen/metadata.yml +51 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/exchange_bundle/specimen/specimen_must_support_test.rb +53 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/exchange_bundle/specimen/specimen_validation_test.rb +47 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/exchange_bundle/us_pathology_diagnostic_report/diagnostic_report_validation_test.rb +47 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/exchange_bundle/us_pathology_diagnostic_report/metadata.yml +77 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/exchange_bundle/us_pathology_diagnostic_report/us_pathology_diagnostic_report_must_support_test.rb +51 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/exchange_bundle/us_pathology_exchange_bundle/exchange_bundle_validation_test.rb +56 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/exchange_bundle/us_pathology_exchange_bundle/metadata.yml +78 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/exchange_bundle/us_pathology_exchange_bundle/us_pathology_exchange_bundle_must_support_test.rb +41 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/exchange_bundle_group.rb +104 -0
- data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite.rb +73 -0
- data/lib/cancer_pathology_data_sharing_test_kit/urls.rb +25 -0
- data/lib/cancer_pathology_data_sharing_test_kit/us_core_data_access_suite/us_core_group.rb +72 -0
- data/lib/cancer_pathology_data_sharing_test_kit/us_core_data_access_suite.rb +58 -0
- data/lib/cancer_pathology_data_sharing_test_kit/validation_test.rb +96 -0
- data/lib/cancer_pathology_data_sharing_test_kit/version.rb +4 -0
- data/lib/cancer_pathology_data_sharing_test_kit.rb +3 -0
- metadata +124 -0
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../bundle_parse'
|
4
|
+
require_relative '../../../validation_test'
|
5
|
+
|
6
|
+
module CancerPathologyDataSharingTestKit
|
7
|
+
class ContentBundleValidationTest < Inferno::Test
|
8
|
+
include CancerPathologyDataSharingTestKit::ValidationTest
|
9
|
+
include CancerPathologyDataSharingTestKit::BundleParse
|
10
|
+
title 'Provided Bundle resources conform to the US Pathology Exchange Bundle Profile'
|
11
|
+
id :cpds_exchange_bundle_validation_test
|
12
|
+
|
13
|
+
description %(
|
14
|
+
Verify that all the generated report(s) are a conformant
|
15
|
+
[Pathology Exchange Bundle](http://hl7.org/fhir/us/cancer-reporting/StructureDefinition/us-pathology-exchange-bundle.html).
|
16
|
+
)
|
17
|
+
|
18
|
+
def resource_type
|
19
|
+
'Bundle'
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_to_scratch(bundles_array)
|
23
|
+
scratch[:cpds_resources] ||= {}
|
24
|
+
scratch[:cpds_exchange_bundles] ||= []
|
25
|
+
bundles_array.each do |report|
|
26
|
+
bundle = FHIR.from_contents(report.to_json)
|
27
|
+
assert_resource_type('Bundle', resource: bundle)
|
28
|
+
bundle_id = bundle.id
|
29
|
+
scratch[:cpds_exchange_bundles] << bundle
|
30
|
+
scratch[:cpds_resources][bundle_id] = parse_bundle(bundle)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
run do
|
35
|
+
# Put reports into array to process
|
36
|
+
bundles_array = JSON.parse("[#{reports}]")
|
37
|
+
add_to_scratch(bundles_array)
|
38
|
+
|
39
|
+
invalid_bundles = []
|
40
|
+
profile_with_version = 'http://hl7.org/fhir/us/cancer-reporting/StructureDefinition/us-pathology-exchange-bundle|1.0.1'
|
41
|
+
bundles_array.each do |bundle|
|
42
|
+
fhir_bundle = FHIR.from_contents(bundle.to_json)
|
43
|
+
invalid_bundles << fhir_bundle.id unless resource_is_valid?(resource: fhir_bundle, profile_url: profile_with_version)
|
44
|
+
end
|
45
|
+
|
46
|
+
# filter errors related to entry resources and Bundle slices - these are handled elsewhere
|
47
|
+
messages.reject! { |message| /Bundle\.entry\[\d+\]\.resource/.match?(message[:message]) }
|
48
|
+
messages.reject! do |message|
|
49
|
+
/Bundle: Slice 'Bundle\.entry:[a-zA-Z]+': a matching slice is required/.match?(message[:message])
|
50
|
+
end
|
51
|
+
|
52
|
+
errors_found = messages.any? { |message| message[:type] == 'error' }
|
53
|
+
assert !errors_found, "Bundle(s) #{invalid_bundles.join(', ')} do not conform to the profile #{profile_with_version}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
---
|
2
|
+
:name: us_pathology_exchange_bundle
|
3
|
+
:class_name: UsPathologyExchangeBundleSequence
|
4
|
+
:version: v1.0.1
|
5
|
+
:reformatted_version: v101
|
6
|
+
:resource: Bundle
|
7
|
+
:profile_url: http://hl7.org/fhir/us/cancer-reporting/StructureDefinition/us-pathology-exchange-bundle
|
8
|
+
:profile_name: US Pathology Exchange Bundle
|
9
|
+
:profile_version: 1.0.1
|
10
|
+
:title: Bundle US Pathology Exchange
|
11
|
+
:short_description: Verify support for the server capabilities required by the US
|
12
|
+
Pathology Exchange Bundle.
|
13
|
+
:must_supports:
|
14
|
+
:extensions: []
|
15
|
+
:slices:
|
16
|
+
- :slice_id: Bundle.entry:us_core_patient
|
17
|
+
:slice_name: us_core_patient
|
18
|
+
:path: entry
|
19
|
+
:discriminator:
|
20
|
+
:type: type
|
21
|
+
:code: Patient
|
22
|
+
- :slice_id: Bundle.entry:us_core_patient
|
23
|
+
:slice_name: us_core_patient
|
24
|
+
:path: entry
|
25
|
+
:discriminator:
|
26
|
+
:type: type
|
27
|
+
:code: Patient
|
28
|
+
- :slice_id: Bundle.entry:us_core_encounter
|
29
|
+
:slice_name: us_core_encounter
|
30
|
+
:path: entry
|
31
|
+
:discriminator:
|
32
|
+
:type: type
|
33
|
+
:code: Encounter
|
34
|
+
- :slice_id: Bundle.entry:diagnosticreport
|
35
|
+
:slice_name: diagnosticreport
|
36
|
+
:path: entry
|
37
|
+
:discriminator:
|
38
|
+
:type: type
|
39
|
+
:code: DiagnosticReport
|
40
|
+
- :slice_id: Bundle.entry:specimen
|
41
|
+
:slice_name: specimen
|
42
|
+
:path: entry
|
43
|
+
:discriminator:
|
44
|
+
:type: type
|
45
|
+
:code: Specimen
|
46
|
+
- :slice_id: Bundle.entry:service-request
|
47
|
+
:slice_name: service-request
|
48
|
+
:path: entry
|
49
|
+
:discriminator:
|
50
|
+
:type: type
|
51
|
+
:code: ServiceRequest
|
52
|
+
- :slice_id: Bundle.entry:pathology-related-practitioner
|
53
|
+
:slice_name: pathology-related-practitioner
|
54
|
+
:path: entry
|
55
|
+
:discriminator:
|
56
|
+
:type: type
|
57
|
+
:code: Practitioner
|
58
|
+
:elements:
|
59
|
+
- :path: type
|
60
|
+
:fixed_value: transaction
|
61
|
+
- :path: timestamp
|
62
|
+
- :path: entry
|
63
|
+
- :path: entry:us_core_patient.resource
|
64
|
+
- :path: entry:us_core_encounter.resource
|
65
|
+
- :path: entry:service-request.resource
|
66
|
+
- :path: entry:pathology-related-practitioner.resource
|
67
|
+
:mandatory_elements:
|
68
|
+
- Bundle.type
|
69
|
+
- Bundle.link.relation
|
70
|
+
- Bundle.link.url
|
71
|
+
- Bundle.entry
|
72
|
+
- Bundle.entry.request.method
|
73
|
+
- Bundle.entry.request.url
|
74
|
+
- Bundle.entry.response.status
|
75
|
+
- Bundle.entry.resource
|
76
|
+
:tests: []
|
77
|
+
:id: v101_us_pathology_exchange_bundle
|
78
|
+
:file_name: us_pathology_exchange_bundle_group.rb
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require_relative '../../../must_support_test'
|
2
|
+
require_relative '../../../group_metadata'
|
3
|
+
|
4
|
+
module CancerPathologyDataSharingTestKit
|
5
|
+
module V101
|
6
|
+
class UsPathologyExchangeBundleMustSupportTest < Inferno::Test
|
7
|
+
include CancerPathologyDataSharingTestKit::MustSupportTest
|
8
|
+
|
9
|
+
title 'All must support elements are provided in the US Pathology Exchange Bundle resources'
|
10
|
+
description %(
|
11
|
+
Report generators SHALL be capable of populating all must support data elements
|
12
|
+
defined in the [US Pathology ExchangeBundle profile](https://hl7.org/fhir/us/cancer-reporting/STU1.0.1/StructureDefinition-us-pathology-exchange-bundle.html)
|
13
|
+
and profiles it references. This test will look through the Bundle resources
|
14
|
+
found in the provided report Bundles for the following must support elements:
|
15
|
+
|
16
|
+
* Bundle.entry
|
17
|
+
* Bundle.entry:pathology-related-practitioner.resource
|
18
|
+
* Bundle.entry:service-request.resource
|
19
|
+
* Bundle.entry:us_core_encounter.resource
|
20
|
+
* Bundle.entry:us_core_patient.resource
|
21
|
+
* Bundle.timestamp
|
22
|
+
* Bundle.type
|
23
|
+
)
|
24
|
+
|
25
|
+
id :cpds_v101_us_pathology_exchange_bundle_must_support_test
|
26
|
+
|
27
|
+
def resource_type
|
28
|
+
'Bundle'
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.metadata
|
32
|
+
@metadata ||= GroupMetadata.new(YAML.load_file(File.join(__dir__, 'metadata.yml'), aliases: true))
|
33
|
+
end
|
34
|
+
|
35
|
+
run do
|
36
|
+
all_resources = scratch[:cpds_exchange_bundles]
|
37
|
+
perform_must_support_test(all_resources&.flatten)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/cancer_pathology_data_sharing_test_kit/report_generation_suite/exchange_bundle_group.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
require_relative 'exchange_bundle/us_pathology_exchange_bundle/exchange_bundle_validation_test'
|
2
|
+
require_relative 'exchange_bundle/us_pathology_diagnostic_report/diagnostic_report_validation_test'
|
3
|
+
require_relative 'exchange_bundle/encounter/encounter_validation_test'
|
4
|
+
require_relative 'exchange_bundle/practitioner_role/practitioner_role_validation_test'
|
5
|
+
require_relative 'exchange_bundle/patient/patient_validation_test'
|
6
|
+
require_relative 'exchange_bundle/service_request/service_request_validation_test'
|
7
|
+
require_relative 'exchange_bundle/specimen/specimen_validation_test'
|
8
|
+
|
9
|
+
require_relative 'exchange_bundle/us_pathology_exchange_bundle/us_pathology_exchange_bundle_must_support_test'
|
10
|
+
require_relative 'exchange_bundle/patient/patient_must_support_test'
|
11
|
+
require_relative 'exchange_bundle/encounter/encounter_must_support_test'
|
12
|
+
require_relative 'exchange_bundle/us_pathology_diagnostic_report/us_pathology_diagnostic_report_must_support_test'
|
13
|
+
require_relative 'exchange_bundle/specimen/specimen_must_support_test'
|
14
|
+
require_relative 'exchange_bundle/service_request/service_request_must_support_test'
|
15
|
+
require_relative 'exchange_bundle/practitioner_role/practitioner_role_must_support_test'
|
16
|
+
|
17
|
+
require_relative 'data_absent_group'
|
18
|
+
|
19
|
+
module CancerPathologyDataSharingTestKit
|
20
|
+
class ExchangeBundleGroup < Inferno::TestGroup
|
21
|
+
title 'Exchange Bundle Group'
|
22
|
+
id :cpds_exchange_bundle_group
|
23
|
+
description %(
|
24
|
+
# Background
|
25
|
+
|
26
|
+
Theses tests verify that the system under test can generate conformant and complete cancer pathology reports
|
27
|
+
following the requirements in the [Cancer Pathology Exchange Bundle profile](https://hl7.org/fhir/us/cancer-reporting/STU1.0.1/StructureDefinition-us-pathology-exchange-bundle.html).
|
28
|
+
The tester will provide a list of Bundles generated by the system under test in the **Cancer Reports** input.
|
29
|
+
Inferno will verify the conformance of each report and that the set of reports contains examples
|
30
|
+
of all entry slices and each element that the Bundle profile and referenced profiles indicate must be supported.
|
31
|
+
|
32
|
+
# Testing Methodology
|
33
|
+
The provided Bundles are parsed and the individual resources within them are separated out
|
34
|
+
and assigned a target profile based on their resource type.
|
35
|
+
|
36
|
+
## Profile Validation
|
37
|
+
Each resource extracted from the bundles is expected to conform to
|
38
|
+
its target profile. Each element in each resource is checked against
|
39
|
+
teminology binding and cardinality requirements by the HL7 FHIR validator.
|
40
|
+
|
41
|
+
While the [Cancer Pathology Exchange Bundle profile](https://hl7.org/fhir/us/cancer-reporting/STU1.0.1/StructureDefinition-us-pathology-exchange-bundle.html)
|
42
|
+
slices entries by profile, Inferno checks that any instances of the profiled resource type
|
43
|
+
conform to the indicated profile and there are not more instances of the profiled resource type than allowed
|
44
|
+
by the slice cardinality. Specifically, each report must contain:
|
45
|
+
- Exactly one Patient, which must conform to the [US Core Patient profile](http://hl7.org/fhir/us/core/STU5.0.1/StructureDefinition-us-core-patient.html).
|
46
|
+
- At most one Encounter, which, if present, must conform to the [US Core Encounter profile](http://hl7.org/fhir/us/core/STU5.0.1/StructureDefinition-us-core-encounter.html).
|
47
|
+
- Exactly one DiagnosticReport, which must conform to the [US Pathology Diagnostic Report profile](https://hl7.org/fhir/us/cancer-reporting/STU1.0.1/StructureDefinition-us-pathology-diagnostic-report.html).
|
48
|
+
- One or more Specimens, each of which must conform to the [US Pathology Specimen profile](https://hl7.org/fhir/us/cancer-reporting/STU1.0.1/StructureDefinition-us-pathology-specimen.html).
|
49
|
+
|
50
|
+
Additionally, each report may include:
|
51
|
+
- Any number of ServiceRequests, each of which must conform to the [US Pathology Service Requests profile](https://hl7.org/fhir/us/cancer-reporting/STU1.0.1/StructureDefinition-us-pathology-service-request.html).
|
52
|
+
- Any number of PractitionRoles, each of which must conform to the [US Pathology Related Practitioner Roles profile](https://hl7.org/fhir/us/cancer-reporting/STU1.0.1/StructureDefinition-us-pathology-related-practitioner-role.html).
|
53
|
+
|
54
|
+
## Must Support
|
55
|
+
Must Support tests in this group check that each element of the target profile marked
|
56
|
+
as "must support" is observed at least once across instances assigned to that profile.
|
57
|
+
If one or more elements are not observed, the test will fail.
|
58
|
+
)
|
59
|
+
run_as_group
|
60
|
+
|
61
|
+
group do
|
62
|
+
title 'Report'
|
63
|
+
test from: :cpds_exchange_bundle_validation_test
|
64
|
+
test from: :cpds_v101_us_pathology_exchange_bundle_must_support_test
|
65
|
+
end
|
66
|
+
|
67
|
+
group do
|
68
|
+
title 'Patient'
|
69
|
+
test from: :cpds_patient_validation_test
|
70
|
+
test from: :cpds_v101_us_core_v311_patient_must_support_test
|
71
|
+
end
|
72
|
+
|
73
|
+
group do
|
74
|
+
title 'Encounter'
|
75
|
+
test from: :cpds_encounter_validation_test
|
76
|
+
test from: :cpds_v101_us_core_v311_encounter_must_support_test
|
77
|
+
end
|
78
|
+
|
79
|
+
group do
|
80
|
+
title 'Diagnostic Report'
|
81
|
+
test from: :cpds_diagnostic_report_validation_test
|
82
|
+
test from: :cpds_v101_us_pathology_diagnostic_report_must_support_test
|
83
|
+
end
|
84
|
+
|
85
|
+
group do
|
86
|
+
title 'Specimen'
|
87
|
+
test from: :cpds_specimen_validation_test
|
88
|
+
test from: :cpds_v101_specimen_must_support_test
|
89
|
+
end
|
90
|
+
|
91
|
+
group do
|
92
|
+
title 'Service Request'
|
93
|
+
test from: :cpds_service_request_validation_test
|
94
|
+
test from: :cpds_v101_service_request_must_support_test
|
95
|
+
end
|
96
|
+
|
97
|
+
group do
|
98
|
+
title 'Practitioner Role'
|
99
|
+
test from: :cpds_practitioner_role_validation_test
|
100
|
+
test from: :cpds_v101_practitioner_role_must_support_test
|
101
|
+
end
|
102
|
+
group from: :cpds_data_absent_reason
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'inferno/dsl/oauth_credentials'
|
2
|
+
require_relative 'urls'
|
3
|
+
require_relative 'version'
|
4
|
+
require_relative 'report_generation_suite/exchange_bundle_group'
|
5
|
+
|
6
|
+
module CancerPathologyDataSharingTestKit
|
7
|
+
class ReportGenerationSuite < Inferno::TestSuite
|
8
|
+
include URLs
|
9
|
+
id :cpds_report_generation
|
10
|
+
title 'Cancer Pathology Data Sharing Report Generation Test Suite'
|
11
|
+
short_title 'CPDS Report Generation Test Suite'
|
12
|
+
description File.read(File.join(__dir__, 'docs', 'report_generation_suite_description.md'))
|
13
|
+
links [
|
14
|
+
{
|
15
|
+
label: 'Report Issue',
|
16
|
+
url: 'https://github.com/inferno-framework/cancer-pathology-data-sharing-test-kit/issues/'
|
17
|
+
},
|
18
|
+
{
|
19
|
+
label: 'Open Source',
|
20
|
+
url: 'https://github.com/inferno-framework/cancer-pathology-data-sharing-test-kit/'
|
21
|
+
},
|
22
|
+
{
|
23
|
+
label: 'Download',
|
24
|
+
url: 'https://github.com/inferno-framework/cancer-pathology-data-sharing-test-kit/releases'
|
25
|
+
},
|
26
|
+
{
|
27
|
+
label: 'Implementation Guide',
|
28
|
+
url: 'https://hl7.org/fhir/us/cancer-reporting/STU1.0.1/'
|
29
|
+
}
|
30
|
+
]
|
31
|
+
|
32
|
+
GENERAL_MESSAGE_FILTERS = [
|
33
|
+
%r{Sub-extension url 'introspect' is not defined by the Extension http://fhir-registry\.smarthealthit\.org/StructureDefinition/oauth-uris},
|
34
|
+
%r{Sub-extension url 'revoke' is not defined by the Extension http://fhir-registry\.smarthealthit\.org/StructureDefinition/oauth-uris},
|
35
|
+
/Observation\.effective\.ofType\(Period\): .*vs-1:/, # Invalid invariant in FHIR v4.0.1
|
36
|
+
/Observation\.effective\.ofType\(Period\): .*us-core-1:/, # Invalid invariant in US Core v3.1.1
|
37
|
+
/Provenance.agent\[\d*\]: Constraint failed: provenance-1/, # Invalid invariant in US Core v5.0.1
|
38
|
+
%r{Unknown Code System 'http://hl7.org/fhir/us/core/CodeSystem/us-core-tags'}, # Validator has an issue with this US Core 5 code system in US Core 6 resource # rubocop:disable Layout/LineLength
|
39
|
+
%r{URL value 'http://hl7.org/fhir/us/core/CodeSystem/us-core-tags' does not resolve}, # Validator has an issue with this US Core 5 code system in US Core 6 resource # rubocop:disable Layout/LineLength
|
40
|
+
/\A\S+: \S+: URL value '.*' does not resolve/,
|
41
|
+
%r{Observation.component\[\d+\].value.ofType\(Quantity\): The code provided \(http://unitsofmeasure.org#L/min\) was not found in the value set 'Vital Signs Units'} # Known issue with the Pulse Oximetry Profile # rubocop:disable Layout/LineLength
|
42
|
+
].freeze
|
43
|
+
VALIDATION_MESSAGE_FILTERS = GENERAL_MESSAGE_FILTERS
|
44
|
+
|
45
|
+
fhir_resource_validator do
|
46
|
+
igs 'hl7.fhir.us.cancer-reporting#1.0.1', 'hl7.fhir.us.core#5.0.1'
|
47
|
+
message_filters = VALIDATION_MESSAGE_FILTERS
|
48
|
+
|
49
|
+
exclude_message do |message|
|
50
|
+
message_filters.any? { |filter| filter.match? message.message }
|
51
|
+
end
|
52
|
+
|
53
|
+
perform_additional_validation do |resource, _profile_url|
|
54
|
+
ProvenanceValidator.validate(resource) if resource.instance_of?(FHIR::Provenance)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
resume_test_route :get, RESUME_PASS_PATH do |request|
|
59
|
+
request.query_parameters['token']
|
60
|
+
end
|
61
|
+
resume_test_route :get, RESUME_FAIL_PATH, result: 'fail' do |request|
|
62
|
+
request.query_parameters['token']
|
63
|
+
end
|
64
|
+
|
65
|
+
input :reports,
|
66
|
+
title: 'Cancer Reports',
|
67
|
+
description: 'A comma-Separated list of one or more FHIR Pathology Cancer Exchange Bundles ' \
|
68
|
+
'in JSON format generated by the system under test.',
|
69
|
+
type: 'textarea'
|
70
|
+
|
71
|
+
group from: :cpds_exchange_bundle_group
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CancerPathologyDataSharingTestKit
|
4
|
+
RESUME_PASS_PATH = '/resume_pass'
|
5
|
+
RESUME_FAIL_PATH = '/resume_fail'
|
6
|
+
|
7
|
+
# URLs
|
8
|
+
module URLs
|
9
|
+
def base_url
|
10
|
+
@base_url ||= "#{Inferno::Application['base_url']}/custom/#{suite_id}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def resume_pass_url
|
14
|
+
@resume_pass_url ||= base_url + RESUME_PASS_PATH
|
15
|
+
end
|
16
|
+
|
17
|
+
def resume_fail_url
|
18
|
+
@resume_fail_url ||= base_url + RESUME_FAIL_PATH
|
19
|
+
end
|
20
|
+
|
21
|
+
def suite_id
|
22
|
+
self.class.suite.id
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'us_core_test_kit'
|
2
|
+
|
3
|
+
module CancerPathologyDataSharingTestKit
|
4
|
+
class USCoreDataAccessGroup < Inferno::TestGroup
|
5
|
+
id :cpds_us_core_data_access
|
6
|
+
title 'US Core FHIR API Tests'
|
7
|
+
short_description 'Verify that cancer patient data are available via US Core API.'
|
8
|
+
description %(
|
9
|
+
During these tests, Inferno will simulate a FHIR client and verify that it can use the target systems's
|
10
|
+
FHIR APIs to access [US Core v5](http://hl7.org/fhir/us/core/STU3.1.1/index.html) data.
|
11
|
+
)
|
12
|
+
input :url,
|
13
|
+
title: 'FHIR Endpoint',
|
14
|
+
description: 'URL of the FHIR endpoint'
|
15
|
+
|
16
|
+
input :smart_credentials,
|
17
|
+
title: 'OAuth Credentials',
|
18
|
+
type: :auth_info,
|
19
|
+
optional: true
|
20
|
+
|
21
|
+
fhir_client do
|
22
|
+
url :url
|
23
|
+
auth_info :smart_credentials
|
24
|
+
end
|
25
|
+
|
26
|
+
group from: :us_core_v501_capability_statement
|
27
|
+
|
28
|
+
group from: :us_core_v501_patient
|
29
|
+
group from: :us_core_v501_allergy_intolerance
|
30
|
+
group from: :us_core_v501_care_plan
|
31
|
+
group from: :us_core_v501_care_team
|
32
|
+
group from: :us_core_v501_condition_encounter_diagnosis
|
33
|
+
group from: :us_core_v501_condition_problems_health_concerns
|
34
|
+
group from: :us_core_v501_device
|
35
|
+
group from: :us_core_v501_diagnostic_report_note
|
36
|
+
group from: :us_core_v501_diagnostic_report_lab
|
37
|
+
group from: :us_core_v501_document_reference
|
38
|
+
group from: :us_core_v501_encounter
|
39
|
+
group from: :us_core_v501_goal
|
40
|
+
group from: :us_core_v501_immunization
|
41
|
+
group from: :us_core_v501_medication_request
|
42
|
+
group from: :us_core_v501_observation_lab
|
43
|
+
group from: :us_core_v501_observation_sdoh_assessment
|
44
|
+
group from: :us_core_v501_respiratory_rate
|
45
|
+
group from: :us_core_v501_observation_social_history
|
46
|
+
group from: :us_core_v501_heart_rate
|
47
|
+
group from: :us_core_v501_body_temperature
|
48
|
+
group from: :us_core_v501_pediatric_weight_for_height
|
49
|
+
group from: :us_core_v501_pulse_oximetry
|
50
|
+
group from: :us_core_v501_smokingstatus
|
51
|
+
group from: :us_core_v501_observation_sexual_orientation
|
52
|
+
group from: :us_core_v501_head_circumference
|
53
|
+
group from: :us_core_v501_body_height
|
54
|
+
group from: :us_core_v501_bmi
|
55
|
+
group from: :us_core_v501_blood_pressure
|
56
|
+
group from: :us_core_v501_observation_imaging
|
57
|
+
group from: :us_core_v501_observation_clinical_test
|
58
|
+
group from: :us_core_v501_pediatric_bmi_for_age
|
59
|
+
group from: :us_core_v501_head_circumference_percentile
|
60
|
+
group from: :us_core_v501_body_weight
|
61
|
+
group from: :us_core_v501_procedure
|
62
|
+
group from: :us_core_v501_questionnaire_response
|
63
|
+
group from: :us_core_v501_service_request
|
64
|
+
group from: :us_core_v501_organization
|
65
|
+
group from: :us_core_v501_practitioner
|
66
|
+
group from: :us_core_v501_practitioner_role
|
67
|
+
group from: :us_core_v501_provenance
|
68
|
+
group from: :us_core_v501_related_person
|
69
|
+
group from: :us_core_v400_clinical_notes_guidance
|
70
|
+
group from: :us_core_311_data_absent_reason
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require_relative 'us_core_data_access_suite/us_core_group'
|
2
|
+
module CancerPathologyDataSharingTestKit
|
3
|
+
class USCoreDataAccessSuite < Inferno::TestSuite
|
4
|
+
id :cpds_data_access
|
5
|
+
title 'Cancer Pathology Data Sharing Data Access Test Suite'
|
6
|
+
short_title 'CPDS Data Access Suite'
|
7
|
+
description File.read(File.join(__dir__, 'docs', 'data_access_suite_description.md'))
|
8
|
+
links [
|
9
|
+
{
|
10
|
+
label: 'Report Issue',
|
11
|
+
url: 'https://github.com/inferno-framework/cancer-pathology-data-sharing-test-kit/issues/'
|
12
|
+
},
|
13
|
+
{
|
14
|
+
label: 'Open Source',
|
15
|
+
url: 'https://github.com/inferno-framework/cancer-pathology-data-sharing-test-kit/'
|
16
|
+
},
|
17
|
+
{
|
18
|
+
label: 'Download',
|
19
|
+
url: 'https://github.com/inferno-framework/cancer-pathology-data-sharing-test-kit/releases'
|
20
|
+
},
|
21
|
+
{
|
22
|
+
label: 'Implementation Guide',
|
23
|
+
url: 'https://hl7.org/fhir/us/cancer-reporting/STU1.0.1/'
|
24
|
+
}
|
25
|
+
]
|
26
|
+
|
27
|
+
GENERAL_MESSAGE_FILTERS = [
|
28
|
+
%r{Sub-extension url 'introspect' is not defined by the Extension http://fhir-registry\.smarthealthit\.org/StructureDefinition/oauth-uris},
|
29
|
+
%r{Sub-extension url 'revoke' is not defined by the Extension http://fhir-registry\.smarthealthit\.org/StructureDefinition/oauth-uris},
|
30
|
+
/Observation\.effective\.ofType\(Period\): .*vs-1:/, # Invalid invariant in FHIR v4.0.1
|
31
|
+
/Observation\.effective\.ofType\(Period\): .*us-core-1:/, # Invalid invariant in US Core v3.1.1
|
32
|
+
/Provenance.agent\[\d*\]: Constraint failed: provenance-1/, # Invalid invariant in US Core v5.0.1
|
33
|
+
%r{Unknown Code System 'http://hl7.org/fhir/us/core/CodeSystem/us-core-tags'}, # Validator has an issue with this US Core 5 code system in US Core 6 resource # rubocop:disable Layout/LineLength
|
34
|
+
%r{URL value 'http://hl7.org/fhir/us/core/CodeSystem/us-core-tags' does not resolve}, # Validator has an issue with this US Core 5 code system in US Core 6 resource # rubocop:disable Layout/LineLength
|
35
|
+
/\A\S+: \S+: URL value '.*' does not resolve/,
|
36
|
+
%r{Observation.component\[\d+\].value.ofType\(Quantity\): The code provided \(http://unitsofmeasure.org#L/min\) was not found in the value set 'Vital Signs Units'} # Known issue with the Pulse Oximetry Profile # rubocop:disable Layout/LineLength
|
37
|
+
].freeze
|
38
|
+
|
39
|
+
VERSION_SPECIFIC_MESSAGE_FILTERS = [].freeze
|
40
|
+
|
41
|
+
VALIDATION_MESSAGE_FILTERS = GENERAL_MESSAGE_FILTERS + VERSION_SPECIFIC_MESSAGE_FILTERS
|
42
|
+
|
43
|
+
fhir_resource_validator do
|
44
|
+
igs('hl7.fhir.us.core#5.0.1')
|
45
|
+
message_filters = VALIDATION_MESSAGE_FILTERS
|
46
|
+
|
47
|
+
exclude_message do |message|
|
48
|
+
message_filters.any? { |filter| filter.match? message.message }
|
49
|
+
end
|
50
|
+
|
51
|
+
perform_additional_validation do |resource, _profile_url|
|
52
|
+
USCoreTestKit::ProvenanceValidator.validate(resource) if resource.instance_of?(FHIR::Provenance)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
group from: :cpds_us_core_data_access
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module CancerPathologyDataSharingTestKit
|
2
|
+
module ValidationTest
|
3
|
+
DAR_CODE_SYSTEM_URL = 'http://terminology.hl7.org/CodeSystem/data-absent-reason'.freeze
|
4
|
+
DAR_EXTENSION_URL = 'http://hl7.org/fhir/StructureDefinition/data-absent-reason'.freeze
|
5
|
+
|
6
|
+
CARDINALITY_RESTRICTIONS = {
|
7
|
+
'exactly_one' =>
|
8
|
+
['==', 1,
|
9
|
+
'There must be exactly one (1) %<resource_type>s resource per bundle. Bundle `%<bundle_id>s` has %<resources_length>s resource(s)'],
|
10
|
+
'no_more_than_one' =>
|
11
|
+
['<=', 1,
|
12
|
+
'There must be no more than one (1) %<resource_type>s resource per bundle. Bundle `%<bundle_id>s` has %<resources_length>s resource(s)'],
|
13
|
+
'at_least_one' =>
|
14
|
+
['>=', 1,
|
15
|
+
'There must be at least one (1) %<resource_type>s resource per bundle. Bundle `%<bundle_id>s` has %<resources_length>s resource(s)']
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
def perform_strict_validation_test(the_resource_type = resource_type, # rubocop:disable Metrics/CyclomaticComplexity,Style/OptionalArguments
|
19
|
+
bundle_id,
|
20
|
+
resources,
|
21
|
+
profile_url,
|
22
|
+
profile_version,
|
23
|
+
skip_if_empty: true,
|
24
|
+
restriction: nil)
|
25
|
+
if !restriction.nil? && !resources.length.public_send(CARDINALITY_RESTRICTIONS[restriction][0], CARDINALITY_RESTRICTIONS[restriction][1])
|
26
|
+
messages << {
|
27
|
+
type: 'error',
|
28
|
+
message: format(CARDINALITY_RESTRICTIONS[restriction][2], resource_type: resource_type, bundle_id: bundle_id,
|
29
|
+
resources_length: resources.length)
|
30
|
+
}
|
31
|
+
return true
|
32
|
+
end
|
33
|
+
|
34
|
+
skip_if skip_if_empty && resources.blank?,
|
35
|
+
"No #{the_resource_type} resources in bundle `#{bundle_id}` were provided so the #{profile_url} profile does not apply"
|
36
|
+
|
37
|
+
if resources.blank?
|
38
|
+
messages << {
|
39
|
+
type: 'info',
|
40
|
+
message: "No #{the_resource_type} resources in bundle `#{bundle_id}` were provided so the #{profile_url} profile does not apply"
|
41
|
+
}
|
42
|
+
return false
|
43
|
+
end
|
44
|
+
|
45
|
+
not_valid = false
|
46
|
+
profile_with_version = "#{profile_url}|#{profile_version}"
|
47
|
+
resources.each do |resource|
|
48
|
+
not_valid == true unless resource_is_valid?(resource: resource, profile_url: profile_with_version)
|
49
|
+
check_for_dar(resource)
|
50
|
+
end
|
51
|
+
|
52
|
+
if not_valid
|
53
|
+
messages << {
|
54
|
+
type: 'error',
|
55
|
+
message: "At least one of the #{the_resource_type} resource(s) in bundle `#{bundle_id}` does not " \
|
56
|
+
"conform to the profile #{profile_with_version}"
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
not_valid
|
61
|
+
end
|
62
|
+
|
63
|
+
def check_for_dar(resource)
|
64
|
+
unless scratch[:dar_code_found]
|
65
|
+
resource.each_element do |element, _meta, _path|
|
66
|
+
next unless element.is_a?(FHIR::Coding)
|
67
|
+
|
68
|
+
check_for_dar_code(element)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
return if scratch[:dar_extension_found]
|
73
|
+
|
74
|
+
check_for_dar_extension(resource)
|
75
|
+
end
|
76
|
+
|
77
|
+
def check_for_dar_code(coding)
|
78
|
+
return unless coding.code == 'unknown' && coding.system == DAR_CODE_SYSTEM_URL
|
79
|
+
|
80
|
+
scratch[:dar_code_found] = true
|
81
|
+
output dar_code_found: 'true'
|
82
|
+
end
|
83
|
+
|
84
|
+
def check_for_dar_extension(resource)
|
85
|
+
return unless resource.source_contents&.include? DAR_EXTENSION_URL
|
86
|
+
|
87
|
+
scratch[:dar_extension_found] = true
|
88
|
+
output dar_extension_found: 'true'
|
89
|
+
end
|
90
|
+
|
91
|
+
def check_for_errors(invalid_bundles)
|
92
|
+
assert invalid_bundles.empty?, "Issues found in Bundle(s): #{invalid_bundles.join(', ')}"
|
93
|
+
assert messages.none? { |message| message[:type] == 'error' }, 'Non-conformant instances detected.'
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|