davinci_pas_test_kit 0.10.1 → 0.11.1
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/lib/davinci_pas_test_kit/client_suite.rb +7 -25
- data/lib/davinci_pas_test_kit/docs/client_suite_description_v201.md +1 -1
- data/lib/davinci_pas_test_kit/docs/server_suite_description_v201.md +1 -1
- data/lib/davinci_pas_test_kit/{mock_server.rb → endpoints/claim_endpoint.rb} +32 -45
- data/lib/davinci_pas_test_kit/endpoints/token_endpoint.rb +22 -0
- data/lib/davinci_pas_test_kit/generated/v2.0.1/client_tests/client_denial_pas_response_bundle_validation_test.rb +3 -3
- data/lib/davinci_pas_test_kit/generated/v2.0.1/client_tests/client_pas_request_bundle_validation_test.rb +8 -0
- data/lib/davinci_pas_test_kit/generated/v2.0.1/client_tests/client_pended_pas_inquiry_request_bundle_validation_test.rb +8 -0
- data/lib/davinci_pas_test_kit/generated/v2.0.1/client_tests/client_pended_pas_response_bundle_validation_test.rb +3 -3
- data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_inquiry_request_bundle/server_pas_inquiry_request_bundle_validation_test.rb +8 -0
- data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_inquiry_response_bundle/server_pas_inquiry_response_bundle_validation_test.rb +3 -3
- data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_request_bundle/server_pas_request_bundle_validation_test.rb +8 -0
- data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_response_bundle/server_pas_response_bundle_validation_test.rb +3 -3
- data/lib/davinci_pas_test_kit/generated/v2.0.1/server_suite.rb +17 -8
- data/lib/davinci_pas_test_kit/generator/validation_test_generator.rb +8 -0
- data/lib/davinci_pas_test_kit/pas_bundle_validation.rb +7 -31
- data/lib/davinci_pas_test_kit/version.rb +2 -2
- metadata +6 -8
- data/lib/davinci_pas_test_kit/ext/inferno_core/record_response_route.rb +0 -98
- data/lib/davinci_pas_test_kit/ext/inferno_core/request.rb +0 -19
- data/lib/davinci_pas_test_kit/ext/inferno_core/runnable.rb +0 -18
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c4814f5a03b2688fac37d470bfa033640ba717a566897bf1d037c618cd404a66
|
|
4
|
+
data.tar.gz: 7d346d15fcbac4c5032263ed40da6ae018792cbbc9c5dd2589cbb0eee193897f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 99ad90a6c99758c1bcc61d0d67529676c4a63f328e73ec527bd5b429e5509d0133848a884220dc7e82a064c229879eff7a42233966a4ff254dd2f41a9eb3bf4b
|
|
7
|
+
data.tar.gz: 9fe9a036b193b5a201515881a40f657325a0535730c89a70c32acdc936eb6c9210d93b698393aff135eb25a309f27e583073b0f5f90789469f6b152a0e2f0cda
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
require_relative 'ext/inferno_core/record_response_route'
|
|
2
|
-
require_relative 'ext/inferno_core/runnable'
|
|
3
|
-
require_relative 'ext/inferno_core/request'
|
|
4
1
|
require_relative 'validator_suppressions'
|
|
5
2
|
require_relative 'tags'
|
|
6
3
|
require_relative 'urls'
|
|
7
|
-
require_relative '
|
|
4
|
+
require_relative 'endpoints/claim_endpoint'
|
|
5
|
+
require_relative 'endpoints/token_endpoint'
|
|
8
6
|
require_relative 'custom_groups/v2.0.1/pas_client_authentication_group'
|
|
9
7
|
require_relative 'custom_groups/v2.0.1/pas_client_approval_group'
|
|
10
8
|
require_relative 'custom_groups/v2.0.1/pas_client_denial_group'
|
|
@@ -15,8 +13,6 @@ require_relative 'version'
|
|
|
15
13
|
|
|
16
14
|
module DaVinciPASTestKit
|
|
17
15
|
class ClientSuite < Inferno::TestSuite
|
|
18
|
-
extend MockServer
|
|
19
|
-
|
|
20
16
|
id :davinci_pas_client_suite_v201
|
|
21
17
|
title 'Da Vinci PAS Client Suite v2.0.1'
|
|
22
18
|
version VERSION
|
|
@@ -37,10 +33,6 @@ module DaVinciPASTestKit
|
|
|
37
33
|
}
|
|
38
34
|
]
|
|
39
35
|
|
|
40
|
-
def self.test_resumes?(test)
|
|
41
|
-
!test.config.options[:accepts_multiple_requests]
|
|
42
|
-
end
|
|
43
|
-
|
|
44
36
|
fhir_resource_validator do
|
|
45
37
|
igs 'hl7.fhir.us.davinci-pas#2.0.1'
|
|
46
38
|
|
|
@@ -51,26 +43,16 @@ module DaVinciPASTestKit
|
|
|
51
43
|
end
|
|
52
44
|
end
|
|
53
45
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
record_response_route :post, SUBMIT_PATH, SUBMIT_TAG, method(:claim_response),
|
|
59
|
-
resumes: method(:test_resumes?) do |request|
|
|
60
|
-
ClientSuite.extract_bearer_token(request)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
record_response_route :post, INQUIRE_PATH, INQUIRE_TAG, method(:claim_response),
|
|
64
|
-
resumes: method(:test_resumes?) do |request|
|
|
65
|
-
ClientSuite.extract_bearer_token(request)
|
|
66
|
-
end
|
|
46
|
+
suite_endpoint :post, TOKEN_PATH, TokenEndpoint
|
|
47
|
+
suite_endpoint :post, SUBMIT_PATH, ClaimEndpoint
|
|
48
|
+
suite_endpoint :post, INQUIRE_PATH, ClaimEndpoint
|
|
67
49
|
|
|
68
50
|
resume_test_route :get, RESUME_PASS_PATH do |request|
|
|
69
|
-
|
|
51
|
+
request.query_parameters['token']
|
|
70
52
|
end
|
|
71
53
|
|
|
72
54
|
resume_test_route :get, RESUME_FAIL_PATH, result: 'fail' do |request|
|
|
73
|
-
|
|
55
|
+
request.query_parameters['token']
|
|
74
56
|
end
|
|
75
57
|
|
|
76
58
|
group from: :pas_client_v201_authentication_group
|
|
@@ -176,4 +176,4 @@ These and any other requirements found in the PAS IG may be tested in future ver
|
|
|
176
176
|
Testing has identified issues with the source IG that result in spurious failures.
|
|
177
177
|
Tests impacted by these issues have an indication in their documentations. The full
|
|
178
178
|
list of known issues can be found on the [repository's issues page with the 'source ig issue'
|
|
179
|
-
|
|
179
|
+
label](https://github.com/inferno-framework/davinci-pas-test-kit/labels/source%20ig%20issue).
|
|
@@ -154,4 +154,4 @@ These and any other requirements found in the PAS IG may be tested in future ver
|
|
|
154
154
|
Testing has identified issues with the source IG that result in spurious failures.
|
|
155
155
|
Tests impacted by these issues have an indication in their documentations. The full
|
|
156
156
|
list of known issues can be found on the [repository's issues page with the 'source ig issue'
|
|
157
|
-
|
|
157
|
+
label](https://github.com/inferno-framework/davinci-pas-test-kit/labels/source%20ig%20issue).
|
|
@@ -1,38 +1,35 @@
|
|
|
1
|
-
require_relative 'user_input_response'
|
|
1
|
+
require_relative '../user_input_response'
|
|
2
2
|
|
|
3
3
|
module DaVinciPASTestKit
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
# See here for full list: https://hl7.org/fhir/us/davinci-pas/STU2/qa.html#suppressed
|
|
8
|
-
module MockServer
|
|
9
|
-
def token_response(request, _test = nil, _test_result = nil)
|
|
10
|
-
# Placeholder for a more complete mock token endpoint
|
|
11
|
-
request.response_body = { access_token: SecureRandom.hex, token_type: 'bearer', expires_in: 300 }.to_json
|
|
12
|
-
request.status = 200
|
|
4
|
+
class ClaimEndpoint < Inferno::DSL::SuiteEndpoint
|
|
5
|
+
def test_run_identifier
|
|
6
|
+
request.headers['authorization']&.delete_prefix('Bearer ')
|
|
13
7
|
end
|
|
14
8
|
|
|
15
|
-
def
|
|
16
|
-
|
|
17
|
-
|
|
9
|
+
def tags
|
|
10
|
+
[operation == 'submit' ? SUBMIT_TAG : INQUIRE_TAG]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def make_response
|
|
14
|
+
response.status = 200
|
|
15
|
+
response.format = :json
|
|
18
16
|
|
|
19
|
-
user_inputted_response = UserInputResponse.user_inputted_response(test,
|
|
20
|
-
if
|
|
21
|
-
|
|
17
|
+
user_inputted_response = UserInputResponse.user_inputted_response(test, result)
|
|
18
|
+
if user_inputted_response.present?
|
|
19
|
+
response.body = user_inputted_response
|
|
22
20
|
return
|
|
23
21
|
end
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
req_bundle = FHIR.from_contents(request&.request_body)
|
|
23
|
+
req_bundle = FHIR.from_contents(request.body.string)
|
|
27
24
|
claim_entry = req_bundle&.entry&.find { |e| e&.resource&.resourceType == 'Claim' }
|
|
28
25
|
claim_full_url = claim_entry&.fullUrl
|
|
29
26
|
if claim_entry.blank? || claim_full_url.blank?
|
|
30
|
-
handle_missing_required_elements(claim_entry,
|
|
27
|
+
handle_missing_required_elements(claim_entry, response)
|
|
31
28
|
return
|
|
32
29
|
end
|
|
33
30
|
|
|
34
31
|
root_url = base_url(claim_full_url)
|
|
35
|
-
claim_response = mock_claim_response(claim_entry.resource, req_bundle,
|
|
32
|
+
claim_response = mock_claim_response(claim_entry.resource, req_bundle, root_url)
|
|
36
33
|
|
|
37
34
|
res_bundle = FHIR::Bundle.new(
|
|
38
35
|
id: SecureRandom.uuid,
|
|
@@ -51,16 +48,20 @@ module DaVinciPASTestKit
|
|
|
51
48
|
|
|
52
49
|
res_bundle.entry.concat(referenced_entities(claim_response, req_bundle.entry, root_url))
|
|
53
50
|
|
|
54
|
-
|
|
55
|
-
request.status = 200
|
|
56
|
-
request.response_headers = { 'Content-Type': 'application/json' }
|
|
51
|
+
response.body = res_bundle.to_json
|
|
57
52
|
end
|
|
58
53
|
|
|
54
|
+
def update_result
|
|
55
|
+
results_repo.update_result(result.id, 'pass') unless test.config.options[:accepts_multiple_requests]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
59
60
|
# Note that references from the claim to other resources in the bundle need to be changed to absolute URLs
|
|
60
61
|
# if they are relative, because the ClaimResponse's fullUrl is a urn:uuid
|
|
61
62
|
#
|
|
62
63
|
# @private
|
|
63
|
-
def mock_claim_response(claim, bundle,
|
|
64
|
+
def mock_claim_response(claim, bundle, root_url)
|
|
64
65
|
return FHIR::ClaimResponse.new(id: SecureRandom.uuid) if claim.blank?
|
|
65
66
|
|
|
66
67
|
now = Time.now.utc
|
|
@@ -128,33 +129,23 @@ module DaVinciPASTestKit
|
|
|
128
129
|
)
|
|
129
130
|
end
|
|
130
131
|
|
|
131
|
-
def
|
|
132
|
-
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
# Header expected to be a bearer token of the form "Bearer: <token>"
|
|
136
|
-
def extract_bearer_token(request)
|
|
137
|
-
request.request_header('Authorization')&.value&.split&.last
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
def extract_token_from_query_params(request)
|
|
141
|
-
request.query_parameters['token']
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def handle_missing_required_elements(claim_entry, request)
|
|
145
|
-
request.status = 400
|
|
146
|
-
request.response_headers = { 'Content-Type': 'application/json' }
|
|
132
|
+
def handle_missing_required_elements(claim_entry, response)
|
|
133
|
+
response.status = 400
|
|
147
134
|
details = if claim_entry.blank?
|
|
148
135
|
'Required Claim entry missing from bundle'
|
|
149
136
|
else
|
|
150
137
|
'Required element fullUrl missing from Claim entry'
|
|
151
138
|
end
|
|
152
|
-
|
|
139
|
+
response.body = FHIR::OperationOutcome.new(
|
|
153
140
|
issue: FHIR::OperationOutcome::Issue.new(severity: 'fatal', code: 'required',
|
|
154
141
|
details: FHIR::CodeableConcept.new(text: details))
|
|
155
142
|
).to_json
|
|
156
143
|
end
|
|
157
144
|
|
|
145
|
+
def operation
|
|
146
|
+
request.url&.split('$')&.last
|
|
147
|
+
end
|
|
148
|
+
|
|
158
149
|
# Drop the last two segments of a URL, i.e. the resource type and ID of a FHIR resource
|
|
159
150
|
# e.g. http://example.org/fhir/Patient/123 -> http://example.org/fhir
|
|
160
151
|
# @private
|
|
@@ -165,7 +156,6 @@ module DaVinciPASTestKit
|
|
|
165
156
|
url.sub(%r{/[^/]*/[^/]*(/)?\z}, '')
|
|
166
157
|
end
|
|
167
158
|
|
|
168
|
-
# @private
|
|
169
159
|
def referenced_entities(resource, entries, root_url)
|
|
170
160
|
matches = []
|
|
171
161
|
attributes = resource&.source_hash&.keys
|
|
@@ -185,21 +175,18 @@ module DaVinciPASTestKit
|
|
|
185
175
|
matches
|
|
186
176
|
end
|
|
187
177
|
|
|
188
|
-
# @private
|
|
189
178
|
def absolute_reference(ref, entries, root_url)
|
|
190
179
|
url = find_matching_entry(ref&.reference, entries, root_url)&.fullUrl
|
|
191
180
|
ref.reference = url if url
|
|
192
181
|
ref
|
|
193
182
|
end
|
|
194
183
|
|
|
195
|
-
# @private
|
|
196
184
|
def find_matching_entry(ref, entries, root_url = '')
|
|
197
185
|
ref = "#{root_url}/#{ref}" if relative_reference?(ref) && root_url&.present?
|
|
198
186
|
|
|
199
187
|
entries&.find { |entry| entry&.fullUrl == ref }
|
|
200
188
|
end
|
|
201
189
|
|
|
202
|
-
# @private
|
|
203
190
|
def relative_reference?(ref)
|
|
204
191
|
ref&.count('/') == 1
|
|
205
192
|
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module DaVinciPASTestKit
|
|
2
|
+
class TokenEndpoint < Inferno::DSL::SuiteEndpoint
|
|
3
|
+
def test_run_identifier
|
|
4
|
+
URI.decode_www_form(request.body.string).to_h['client_id']
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def tags
|
|
8
|
+
[AUTH_TAG]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def make_response
|
|
12
|
+
# Placeholder for a more complete mock token endpoint
|
|
13
|
+
response.status = 200
|
|
14
|
+
response.format = :json
|
|
15
|
+
response.body = { access_token: SecureRandom.hex, token_type: 'bearer', expires_in: 300 }.to_json
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def update_result
|
|
19
|
+
results_repo.update_result(result.id, 'pass')
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -29,10 +29,10 @@ module DaVinciPASTestKit
|
|
|
29
29
|
|
|
30
30
|
Note that because X12 value sets are not public, elements bound to value
|
|
31
31
|
sets containing X12 codes are not validated.
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
**Limitations**
|
|
34
|
-
|
|
35
|
-
Due to recognized errors in the
|
|
34
|
+
|
|
35
|
+
Due to recognized errors in the PAS IG around extension context definitions,
|
|
36
36
|
this test may not pass due to spurious errors of the form "The extension
|
|
37
37
|
[extension url] is not allowed at this point". See [this
|
|
38
38
|
issue](https://github.com/inferno-framework/davinci-pas-test-kit/issues/11)
|
|
@@ -26,6 +26,14 @@ module DaVinciPASTestKit
|
|
|
26
26
|
|
|
27
27
|
Note that because X12 value sets are not public, elements bound to value
|
|
28
28
|
sets containing X12 codes are not validated.
|
|
29
|
+
|
|
30
|
+
**Limitations**
|
|
31
|
+
|
|
32
|
+
Due to recognized errors in the PAS IG around extension context definitions,
|
|
33
|
+
this test may not pass due to spurious errors of the form "The extension
|
|
34
|
+
[extension url] is not allowed at this point". See [this
|
|
35
|
+
issue](https://github.com/inferno-framework/davinci-pas-test-kit/issues/11)
|
|
36
|
+
for additional details.
|
|
29
37
|
)
|
|
30
38
|
|
|
31
39
|
def resource_type
|
|
@@ -26,6 +26,14 @@ module DaVinciPASTestKit
|
|
|
26
26
|
|
|
27
27
|
Note that because X12 value sets are not public, elements bound to value
|
|
28
28
|
sets containing X12 codes are not validated.
|
|
29
|
+
|
|
30
|
+
**Limitations**
|
|
31
|
+
|
|
32
|
+
Due to recognized errors in the PAS IG around extension context definitions,
|
|
33
|
+
this test may not pass due to spurious errors of the form "The extension
|
|
34
|
+
[extension url] is not allowed at this point". See [this
|
|
35
|
+
issue](https://github.com/inferno-framework/davinci-pas-test-kit/issues/11)
|
|
36
|
+
for additional details.
|
|
29
37
|
)
|
|
30
38
|
|
|
31
39
|
def resource_type
|
|
@@ -29,10 +29,10 @@ module DaVinciPASTestKit
|
|
|
29
29
|
|
|
30
30
|
Note that because X12 value sets are not public, elements bound to value
|
|
31
31
|
sets containing X12 codes are not validated.
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
**Limitations**
|
|
34
|
-
|
|
35
|
-
Due to recognized errors in the
|
|
34
|
+
|
|
35
|
+
Due to recognized errors in the PAS IG around extension context definitions,
|
|
36
36
|
this test may not pass due to spurious errors of the form "The extension
|
|
37
37
|
[extension url] is not allowed at this point". See [this
|
|
38
38
|
issue](https://github.com/inferno-framework/davinci-pas-test-kit/issues/11)
|
|
@@ -28,6 +28,14 @@ module DaVinciPASTestKit
|
|
|
28
28
|
|
|
29
29
|
Note that because X12 value sets are not public, elements bound to value
|
|
30
30
|
sets containing X12 codes are not validated.
|
|
31
|
+
|
|
32
|
+
**Limitations**
|
|
33
|
+
|
|
34
|
+
Due to recognized errors in the PAS IG around extension context definitions,
|
|
35
|
+
this test may not pass due to spurious errors of the form "The extension
|
|
36
|
+
[extension url] is not allowed at this point". See [this
|
|
37
|
+
issue](https://github.com/inferno-framework/davinci-pas-test-kit/issues/11)
|
|
38
|
+
for additional details.
|
|
31
39
|
)
|
|
32
40
|
|
|
33
41
|
input :pa_inquire_request_payload,
|
|
@@ -25,10 +25,10 @@ module DaVinciPASTestKit
|
|
|
25
25
|
|
|
26
26
|
Note that because X12 value sets are not public, elements bound to value
|
|
27
27
|
sets containing X12 codes are not validated.
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
**Limitations**
|
|
30
|
-
|
|
31
|
-
Due to recognized errors in the
|
|
30
|
+
|
|
31
|
+
Due to recognized errors in the PAS IG around extension context definitions,
|
|
32
32
|
this test may not pass due to spurious errors of the form "The extension
|
|
33
33
|
[extension url] is not allowed at this point". See [this
|
|
34
34
|
issue](https://github.com/inferno-framework/davinci-pas-test-kit/issues/11)
|
|
@@ -28,6 +28,14 @@ module DaVinciPASTestKit
|
|
|
28
28
|
|
|
29
29
|
Note that because X12 value sets are not public, elements bound to value
|
|
30
30
|
sets containing X12 codes are not validated.
|
|
31
|
+
|
|
32
|
+
**Limitations**
|
|
33
|
+
|
|
34
|
+
Due to recognized errors in the PAS IG around extension context definitions,
|
|
35
|
+
this test may not pass due to spurious errors of the form "The extension
|
|
36
|
+
[extension url] is not allowed at this point". See [this
|
|
37
|
+
issue](https://github.com/inferno-framework/davinci-pas-test-kit/issues/11)
|
|
38
|
+
for additional details.
|
|
31
39
|
)
|
|
32
40
|
|
|
33
41
|
input :pa_submit_request_payload,
|
|
@@ -25,10 +25,10 @@ module DaVinciPASTestKit
|
|
|
25
25
|
|
|
26
26
|
Note that because X12 value sets are not public, elements bound to value
|
|
27
27
|
sets containing X12 codes are not validated.
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
**Limitations**
|
|
30
|
-
|
|
31
|
-
Due to recognized errors in the
|
|
30
|
+
|
|
31
|
+
Due to recognized errors in the PAS IG around extension context definitions,
|
|
32
32
|
this test may not pass due to spurious errors of the form "The extension
|
|
33
33
|
[extension url] is not allowed at this point". See [this
|
|
34
34
|
issue](https://github.com/inferno-framework/davinci-pas-test-kit/issues/11)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require_relative '../../validator_suppressions'
|
|
2
2
|
require_relative '../../custom_groups/v2.0.1/pas_error_group'
|
|
3
|
-
require_relative '../../version
|
|
3
|
+
require_relative '../../version'
|
|
4
4
|
require_relative 'pas_server_approval_use_case_group'
|
|
5
5
|
require_relative 'pas_server_denial_use_case_group'
|
|
6
6
|
require_relative 'pas_server_pended_use_case_group'
|
|
@@ -15,12 +15,12 @@ module DaVinciPASTestKit
|
|
|
15
15
|
description File.read(File.join(__dir__, '..', '..', 'docs', 'server_suite_description_v201.md'))
|
|
16
16
|
|
|
17
17
|
links [
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
{
|
|
19
|
+
label: 'Report Issue',
|
|
20
|
+
url: 'https://github.com/inferno-framework/davinci-pas-test-kit/issues/'
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
|
-
|
|
23
|
+
label: 'Open Source',
|
|
24
24
|
url: 'https://github.com/inferno-framework/davinci-pas-test-kit/'
|
|
25
25
|
},
|
|
26
26
|
{
|
|
@@ -50,12 +50,21 @@ module DaVinciPASTestKit
|
|
|
50
50
|
|
|
51
51
|
input :smart_credentials,
|
|
52
52
|
title: 'OAuth Credentials',
|
|
53
|
-
type: :
|
|
53
|
+
type: :auth_info,
|
|
54
|
+
options: {
|
|
55
|
+
mode: 'access',
|
|
56
|
+
components: [
|
|
57
|
+
{
|
|
58
|
+
name: :auth_type,
|
|
59
|
+
default: 'backend_services'
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
},
|
|
54
63
|
optional: true
|
|
55
64
|
|
|
56
65
|
fhir_client do
|
|
57
66
|
url :server_endpoint
|
|
58
|
-
|
|
67
|
+
auth_info :smart_credentials
|
|
59
68
|
end
|
|
60
69
|
|
|
61
70
|
# Used for attestation experiment - see pas_claim_response_decision_test.rb
|
|
@@ -66,7 +75,7 @@ module DaVinciPASTestKit
|
|
|
66
75
|
# resume_test_route :get, RESUME_FAIL_PATH, result: 'fail' do |request|
|
|
67
76
|
# request.query_parameters['token']
|
|
68
77
|
# end
|
|
69
|
-
|
|
78
|
+
|
|
70
79
|
group 'Demonstrate Workflow Support' do
|
|
71
80
|
description %(
|
|
72
81
|
The workflow tests validate that the server can participate in complete
|
|
@@ -151,6 +151,14 @@ module DaVinciPASTestKit
|
|
|
151
151
|
|
|
152
152
|
Note that because X12 value sets are not public, elements bound to value
|
|
153
153
|
sets containing X12 codes are not validated.
|
|
154
|
+
|
|
155
|
+
**Limitations**
|
|
156
|
+
|
|
157
|
+
Due to recognized errors in the PAS IG around extension context definitions,
|
|
158
|
+
this test may not pass due to spurious errors of the form "The extension
|
|
159
|
+
[extension url] is not allowed at this point". See [this
|
|
160
|
+
issue](https://github.com/inferno-framework/davinci-pas-test-kit/issues/11)
|
|
161
|
+
for additional details.
|
|
154
162
|
DESCRIPTION
|
|
155
163
|
end
|
|
156
164
|
|
|
@@ -282,10 +282,14 @@ module DaVinciPASTestKit
|
|
|
282
282
|
# @param bundle_map [Hash] A map of the bundle contents.
|
|
283
283
|
# @param version [String] The FHIR version.
|
|
284
284
|
def process_reference_element(reference_element, current_entry, bundle_entry, bundle_map, version)
|
|
285
|
-
|
|
286
|
-
|
|
285
|
+
fhirpath_result = evaluate_fhirpath(resource: current_entry.resource, path: reference_element[:path])
|
|
286
|
+
reference_element_values = fhirpath_result.filter_map do |entry|
|
|
287
|
+
entry['element']&.reference if entry['type'] == 'Reference'
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
referenced_instances = reference_element_values.filter_map do |value|
|
|
287
291
|
find_referenced_instance_in_bundle(value, current_entry.fullUrl, bundle_map)
|
|
288
|
-
end
|
|
292
|
+
end
|
|
289
293
|
|
|
290
294
|
referenced_instances.each do |instance|
|
|
291
295
|
process_instance_profiles(instance, bundle_entry, reference_element, version)
|
|
@@ -363,34 +367,6 @@ module DaVinciPASTestKit
|
|
|
363
367
|
end
|
|
364
368
|
end
|
|
365
369
|
|
|
366
|
-
# Evaluates a FHIRPath expression against a FHIR resource using an external FHIRPath validator.
|
|
367
|
-
# @param resource [Object] The FHIR resource to be evaluated.
|
|
368
|
-
# @param expression [String] The FHIRPath expression to evaluate.
|
|
369
|
-
# @return [Array] An array of references extracted from the evaluation result, or an empty array in case of failure.
|
|
370
|
-
def evaluate_fhirpath_expression(resource, expression)
|
|
371
|
-
return [] unless expression && resource
|
|
372
|
-
|
|
373
|
-
logger = Logger.new($stdout)
|
|
374
|
-
begin
|
|
375
|
-
fhirpath_url = ENV.fetch('FHIRPATH_URL')
|
|
376
|
-
path = "#{fhirpath_url}/evaluate?path=#{expression}"
|
|
377
|
-
|
|
378
|
-
response = Faraday.post(path, resource.to_json, 'Content-Type' => 'application/json')
|
|
379
|
-
if response.status.to_s.start_with? '2'
|
|
380
|
-
result = JSON.parse(response.body)
|
|
381
|
-
return result.map { |entry| entry.dig('element', 'reference') if entry['type'] == 'Reference' }.compact
|
|
382
|
-
else
|
|
383
|
-
logger.error "External FHIRPath service failed: #{response.status}"
|
|
384
|
-
raise 'FHIRPath service not available'
|
|
385
|
-
end
|
|
386
|
-
rescue Faraday::Error => e
|
|
387
|
-
logger.error "HTTP request failed: #{e.message}"
|
|
388
|
-
raise 'FHIRPath service not available'
|
|
389
|
-
end
|
|
390
|
-
|
|
391
|
-
[]
|
|
392
|
-
end
|
|
393
|
-
|
|
394
370
|
# Finds a referenced instance in a FHIR bundle based on a reference and the full URL of the enclosing entry.
|
|
395
371
|
# @param reference [String] The reference to find.
|
|
396
372
|
# @param enclosing_entry_fullurl [String] The full URL of the enclosing entry.
|
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.11.1
|
|
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-12-06 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.
|
|
19
|
+
version: 0.5.0
|
|
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.
|
|
26
|
+
version: 0.5.0
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: database_cleaner-sequel
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -120,9 +120,8 @@ files:
|
|
|
120
120
|
- lib/davinci_pas_test_kit/custom_groups/v2.0.1/pas_error_group.rb
|
|
121
121
|
- lib/davinci_pas_test_kit/docs/client_suite_description_v201.md
|
|
122
122
|
- lib/davinci_pas_test_kit/docs/server_suite_description_v201.md
|
|
123
|
-
- lib/davinci_pas_test_kit/
|
|
124
|
-
- lib/davinci_pas_test_kit/
|
|
125
|
-
- lib/davinci_pas_test_kit/ext/inferno_core/runnable.rb
|
|
123
|
+
- lib/davinci_pas_test_kit/endpoints/claim_endpoint.rb
|
|
124
|
+
- lib/davinci_pas_test_kit/endpoints/token_endpoint.rb
|
|
126
125
|
- lib/davinci_pas_test_kit/fhir_resource_navigation.rb
|
|
127
126
|
- lib/davinci_pas_test_kit/generated/v2.0.1/beneficiary/client_inquire_request_beneficiary_must_support_test.rb
|
|
128
127
|
- lib/davinci_pas_test_kit/generated/v2.0.1/beneficiary/client_submit_request_beneficiary_must_support_test.rb
|
|
@@ -248,7 +247,6 @@ files:
|
|
|
248
247
|
- lib/davinci_pas_test_kit/generator/validation_test_generator.rb
|
|
249
248
|
- lib/davinci_pas_test_kit/generator/value_extractor.rb
|
|
250
249
|
- lib/davinci_pas_test_kit/igs/README.md
|
|
251
|
-
- lib/davinci_pas_test_kit/mock_server.rb
|
|
252
250
|
- lib/davinci_pas_test_kit/must_support_test.rb
|
|
253
251
|
- lib/davinci_pas_test_kit/pas_bundle_validation.rb
|
|
254
252
|
- lib/davinci_pas_test_kit/tags.rb
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
require 'hanami/controller'
|
|
2
|
-
|
|
3
|
-
module Inferno
|
|
4
|
-
module DSL
|
|
5
|
-
# A base class for creating routes with custom response logic. Requests and responses are tagged and saved.
|
|
6
|
-
# @private
|
|
7
|
-
# @see Inferno::DSL::Runnable#resume_test_route
|
|
8
|
-
class RecordResponseRoute < Hanami::Action
|
|
9
|
-
include Import[
|
|
10
|
-
requests_repo: 'inferno.repositories.requests',
|
|
11
|
-
results_repo: 'inferno.repositories.results',
|
|
12
|
-
test_runs_repo: 'inferno.repositories.test_runs',
|
|
13
|
-
tests_repo: 'inferno.repositories.tests'
|
|
14
|
-
]
|
|
15
|
-
|
|
16
|
-
def self.call(...)
|
|
17
|
-
new.call(...)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
# @private
|
|
21
|
-
def test_run_identifier_block
|
|
22
|
-
self.class.singleton_class.instance_variable_get(:@test_run_identifier_block)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
# @private
|
|
26
|
-
def build_response_block
|
|
27
|
-
self.class.singleton_class.instance_variable_get(:@build_response_block)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# @private
|
|
31
|
-
def tags
|
|
32
|
-
self.class.singleton_class.instance_variable_get(:@tags)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
# @private
|
|
36
|
-
def resumes?(test)
|
|
37
|
-
instance_exec(test, &self.class.singleton_class.instance_variable_get(:@resumes))
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
# @private
|
|
41
|
-
def find_test_run(test_run_identifier)
|
|
42
|
-
test_runs_repo.find_latest_waiting_by_identifier(test_run_identifier)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# @private
|
|
46
|
-
def find_waiting_result(test_run)
|
|
47
|
-
results_repo.find_waiting_result(test_run_id: test_run.id)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# @private
|
|
51
|
-
def update_result(waiting_result)
|
|
52
|
-
results_repo.update_result(waiting_result.id, 'pass')
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# @private
|
|
56
|
-
def persist_request(request, test_run, waiting_result, test)
|
|
57
|
-
requests_repo.create(
|
|
58
|
-
request.to_hash.merge(
|
|
59
|
-
test_session_id: test_run.test_session_id,
|
|
60
|
-
result_id: waiting_result.id,
|
|
61
|
-
name: test.config.request_name(test.incoming_request_name),
|
|
62
|
-
tags:
|
|
63
|
-
)
|
|
64
|
-
)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# @private
|
|
68
|
-
def find_test(waiting_result)
|
|
69
|
-
tests_repo.find(waiting_result.test_id)
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
# @private
|
|
73
|
-
def handle(req, res)
|
|
74
|
-
request = Inferno::Entities::Request.from_hanami_request(req)
|
|
75
|
-
|
|
76
|
-
test_run_identifier = instance_exec(request, &test_run_identifier_block)
|
|
77
|
-
|
|
78
|
-
test_run = find_test_run(test_run_identifier)
|
|
79
|
-
|
|
80
|
-
halt 500, "Unable to find test run with identifier '#{test_run_identifier}'." if test_run.nil?
|
|
81
|
-
|
|
82
|
-
waiting_result = find_waiting_result(test_run)
|
|
83
|
-
test = find_test(waiting_result)
|
|
84
|
-
|
|
85
|
-
test_runs_repo.mark_as_no_longer_waiting(test_run.id) if resumes? test
|
|
86
|
-
|
|
87
|
-
update_result(waiting_result) if resumes? test
|
|
88
|
-
|
|
89
|
-
instance_exec(request, test, waiting_result, &build_response_block)
|
|
90
|
-
|
|
91
|
-
Inferno::Entities::Request.to_hanami_response(request, res)
|
|
92
|
-
persist_request(request, test_run, waiting_result, test)
|
|
93
|
-
|
|
94
|
-
Jobs.perform(Jobs::ResumeTestRun, test_run.id) if resumes? test
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
end
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
module Inferno
|
|
2
|
-
module Entities
|
|
3
|
-
class Request
|
|
4
|
-
def self.to_hanami_response(request, response)
|
|
5
|
-
response.status = request.status
|
|
6
|
-
response.body = request.response_body
|
|
7
|
-
request.response_headers.each do |header|
|
|
8
|
-
response.headers[header.name] = header.value
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
response
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def response_headers=(headers_hash)
|
|
15
|
-
headers.concat(headers_hash.map { |key, value| Header.new(name: key.to_s, value:, type: 'response') })
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
require_relative 'record_response_route'
|
|
2
|
-
|
|
3
|
-
module Inferno
|
|
4
|
-
module DSL
|
|
5
|
-
module Runnable
|
|
6
|
-
def record_response_route(method, path, tags, build_response, resumes: ->(_) { true }, &block)
|
|
7
|
-
route_class = Class.new(Inferno::DSL::RecordResponseRoute) do |klass|
|
|
8
|
-
klass.singleton_class.instance_variable_set(:@build_response_block, build_response)
|
|
9
|
-
klass.singleton_class.instance_variable_set(:@test_run_identifier_block, block)
|
|
10
|
-
klass.singleton_class.instance_variable_set(:@tags, Array.wrap(tags))
|
|
11
|
-
klass.singleton_class.instance_variable_set(:@resumes, resumes)
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
route(method, path, route_class)
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|