davinci_pas_test_kit 0.9.2 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/davinci_pas_test_kit/client_suite.rb +2 -2
- data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_approval_submit_response_attest.rb +1 -0
- data/lib/davinci_pas_test_kit/docs/client_suite_description_v201.md +5 -0
- data/lib/davinci_pas_test_kit/generated/v2.0.1/server_suite.rb +2 -2
- data/lib/davinci_pas_test_kit/generator/suite_generator.rb +5 -0
- data/lib/davinci_pas_test_kit/igs/README.md +21 -0
- data/lib/davinci_pas_test_kit/mock_server.rb +21 -3
- data/lib/davinci_pas_test_kit/pas_bundle_validation.rb +10 -6
- data/lib/davinci_pas_test_kit/validator_suppressions.rb +2 -0
- data/lib/davinci_pas_test_kit/version.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e45ca8e36bad87d4e457eb2b49c26eb0170c7877e059e9a8cb8e5bda906972b9
|
4
|
+
data.tar.gz: 6dbf634eb8484ea7dc442a7bd9b016392ea70316e3635ae4fe7c2e2bd884772a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 29e35d93edbabe076d85521e36829951c15ae73645c262a334a3abf3a1c1abaf6752ab7e56488c4edc519dfa95a2a228312e467a25f9b78822efa1f2abb96d7c
|
7
|
+
data.tar.gz: af2de00d7c19bc247f8834f185a702b942b939947e4aa2c16323ab044b67ccffcd9cd315fe6ec8d26cc98e410e05ed12548f8796e9d9d01da9da72c3d0b29410
|
@@ -41,8 +41,8 @@ module DaVinciPASTestKit
|
|
41
41
|
!test.config.options[:accepts_multiple_requests]
|
42
42
|
end
|
43
43
|
|
44
|
-
|
45
|
-
|
44
|
+
fhir_resource_validator do
|
45
|
+
igs 'hl7.fhir.us.davinci-pas#2.0.1'
|
46
46
|
|
47
47
|
exclude_message do |message|
|
48
48
|
# Messages expected of the form `<ResourceType>: <FHIRPath>: <message>`
|
@@ -77,6 +77,11 @@ json-encoded FHIR bundle in the "Claim pended response JSON" and "Claim deny res
|
|
77
77
|
clicking the '*Run All Tests*' button. These responses will be echoed back when a request
|
78
78
|
is made during the corresponding test.
|
79
79
|
|
80
|
+
Selecting the *Example PAS Server Responses* Preset in the dropdown in the upper left will fill in example
|
81
|
+
FHIR bundles for the pended and deny responses. It will also fill in a sample value for the Client ID,
|
82
|
+
which is only necessary for the *Demonstrate Authorization* test group, which can be skipped in favor of
|
83
|
+
manual bearer token input in subsequent tests as described above.
|
84
|
+
|
80
85
|
### Postman-based Demo
|
81
86
|
|
82
87
|
If you do not have a PAS client but would like to try the tests out, you can use
|
@@ -33,8 +33,8 @@ module DaVinciPASTestKit
|
|
33
33
|
request.query_parameters['use_case']
|
34
34
|
end
|
35
35
|
|
36
|
-
|
37
|
-
|
36
|
+
fhir_resource_validator do
|
37
|
+
igs 'hl7.fhir.us.davinci-pas#2.0.1'
|
38
38
|
|
39
39
|
exclude_message do |message|
|
40
40
|
# Messages expected of the form `<ResourceType>: <FHIRPath>: <message>`
|
@@ -48,6 +48,11 @@ module DaVinciPASTestKit
|
|
48
48
|
"Da Vinci PAS Server Suite #{ig_metadata.ig_version}"
|
49
49
|
end
|
50
50
|
|
51
|
+
def ig_identifier
|
52
|
+
version = ig_metadata.ig_version[1..] # Remove leading 'v'
|
53
|
+
"hl7.fhir.us.davinci-pas##{version}"
|
54
|
+
end
|
55
|
+
|
51
56
|
def ig_link
|
52
57
|
case ig_metadata.ig_version
|
53
58
|
when 'v2.0.1'
|
@@ -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.
|
@@ -25,9 +25,13 @@ module DaVinciPASTestKit
|
|
25
25
|
operation = request&.url&.split('$')&.last
|
26
26
|
req_bundle = FHIR.from_contents(request&.request_body)
|
27
27
|
claim_entry = req_bundle&.entry&.find { |e| e&.resource&.resourceType == 'Claim' }
|
28
|
-
|
29
|
-
|
28
|
+
claim_full_url = claim_entry&.fullUrl
|
29
|
+
if claim_entry.blank? || claim_full_url.blank?
|
30
|
+
handle_missing_required_elements(claim_entry, request)
|
31
|
+
return
|
32
|
+
end
|
30
33
|
|
34
|
+
root_url = base_url(claim_full_url)
|
31
35
|
claim_response = mock_claim_response(claim_entry.resource, req_bundle, operation, root_url)
|
32
36
|
|
33
37
|
res_bundle = FHIR::Bundle.new(
|
@@ -137,11 +141,25 @@ module DaVinciPASTestKit
|
|
137
141
|
request.query_parameters['token']
|
138
142
|
end
|
139
143
|
|
144
|
+
def handle_missing_required_elements(claim_entry, request)
|
145
|
+
request.status = 400
|
146
|
+
request.response_headers = { 'Content-Type': 'application/json' }
|
147
|
+
details = if claim_entry.blank?
|
148
|
+
'Required Claim entry missing from bundle'
|
149
|
+
else
|
150
|
+
'Required element fullUrl missing from Claim entry'
|
151
|
+
end
|
152
|
+
request.response_body = FHIR::OperationOutcome.new(
|
153
|
+
issue: FHIR::OperationOutcome::Issue.new(severity: 'fatal', code: 'required',
|
154
|
+
details: FHIR::CodeableConcept.new(text: details))
|
155
|
+
).to_json
|
156
|
+
end
|
157
|
+
|
140
158
|
# Drop the last two segments of a URL, i.e. the resource type and ID of a FHIR resource
|
141
159
|
# e.g. http://example.org/fhir/Patient/123 -> http://example.org/fhir
|
142
160
|
# @private
|
143
161
|
def base_url(url)
|
144
|
-
return unless url
|
162
|
+
return unless url&.start_with?('http://', 'https://')
|
145
163
|
|
146
164
|
# Drop everything after the second to last '/', ignoring a trailing slash
|
147
165
|
url.sub(%r{/[^/]*/[^/]*(/)?\z}, '')
|
@@ -210,9 +210,11 @@ module DaVinciPASTestKit
|
|
210
210
|
# @param version [String] The version of the IG.
|
211
211
|
def validate_bundle_entries_against_profiles(version)
|
212
212
|
bundle_resources_target_profile_map.each_value do |item|
|
213
|
+
resource = item[:resource]
|
214
|
+
base_profile = FHIR::Definitions.resource_definition(resource.resourceType).url
|
213
215
|
success_profile = item[:profile_urls].find do |url|
|
214
|
-
|
215
|
-
resource_is_valid?(resource
|
216
|
+
profile_to_validate = url == base_profile ? url : "#{url}|#{version}"
|
217
|
+
resource_is_valid?(resource:, profile_url: profile_to_validate)
|
216
218
|
end
|
217
219
|
|
218
220
|
validation_error_messages << generate_non_conformance_message(item) unless success_profile
|
@@ -370,18 +372,20 @@ module DaVinciPASTestKit
|
|
370
372
|
|
371
373
|
logger = Logger.new($stdout)
|
372
374
|
begin
|
373
|
-
|
374
|
-
path = "#{
|
375
|
+
fhirpath_url = ENV.fetch('FHIRPATH_URL')
|
376
|
+
path = "#{fhirpath_url}/evaluate?path=#{expression}"
|
375
377
|
|
376
378
|
response = Faraday.post(path, resource.to_json, 'Content-Type' => 'application/json')
|
377
379
|
if response.status.to_s.start_with? '2'
|
378
380
|
result = JSON.parse(response.body)
|
379
381
|
return result.map { |entry| entry.dig('element', 'reference') if entry['type'] == 'Reference' }.compact
|
380
382
|
else
|
381
|
-
logger.error "External
|
383
|
+
logger.error "External FHIRPath service failed: #{response.status}"
|
384
|
+
raise 'FHIRPath service not available'
|
382
385
|
end
|
383
386
|
rescue Faraday::Error => e
|
384
387
|
logger.error "HTTP request failed: #{e.message}"
|
388
|
+
raise 'FHIRPath service not available'
|
385
389
|
end
|
386
390
|
|
387
391
|
[]
|
@@ -465,7 +469,7 @@ module DaVinciPASTestKit
|
|
465
469
|
url_regex = /\A#{URI::DEFAULT_PARSER.make_regexp(%w[http https])}\z/
|
466
470
|
urn_uuid_regex = /\Aurn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\z/i
|
467
471
|
|
468
|
-
string
|
472
|
+
string&.match?(url_regex) || string&.match?(urn_uuid_regex)
|
469
473
|
end
|
470
474
|
|
471
475
|
# This method traverses references within a FHIR resource, ensuring that referenced resources
|
@@ -133,6 +133,8 @@ module DaVinciPASTestKit
|
|
133
133
|
# no real content
|
134
134
|
/Details for (.+) matching against profile/,
|
135
135
|
': All OK',
|
136
|
+
# This was ignored natively in the Inferno validator but needs to be ignored by the test kit with the HL7 validator
|
137
|
+
/URL value '.*' does not resolve/,
|
136
138
|
# addition validator clean-up based on Bundle sub-validations where Inferno error supression doesn't
|
137
139
|
# work. The test kit validates these instances individually as well, so they are still checked,
|
138
140
|
# but in a way that Inferno can supress errors
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: davinci_pas_test_kit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Inferno Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-07-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: inferno_core
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.4.
|
19
|
+
version: 0.4.37
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.4.
|
26
|
+
version: 0.4.37
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: database_cleaner-sequel
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -247,6 +247,7 @@ files:
|
|
247
247
|
- lib/davinci_pas_test_kit/generator/terminology_binding_metadata_extractor.rb
|
248
248
|
- lib/davinci_pas_test_kit/generator/validation_test_generator.rb
|
249
249
|
- lib/davinci_pas_test_kit/generator/value_extractor.rb
|
250
|
+
- lib/davinci_pas_test_kit/igs/README.md
|
250
251
|
- lib/davinci_pas_test_kit/mock_server.rb
|
251
252
|
- lib/davinci_pas_test_kit/must_support_test.rb
|
252
253
|
- lib/davinci_pas_test_kit/pas_bundle_validation.rb
|