davinci_pas_test_kit 0.11.0 → 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/{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/version.rb +1 -1
- metadata +4 -6
- 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
|
@@ -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
|
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.11.
|
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
|
@@ -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
|