davinci_pas_test_kit 0.11.1 → 0.12.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/config/presets/pas_client_example.json +30 -0
- data/config/presets/pas_ri.json +69 -0
- data/lib/davinci_pas_test_kit/client_suite.rb +28 -2
- data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_approval_submit_test.rb +29 -1
- data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_denial_submit_test.rb +27 -4
- data/lib/davinci_pas_test_kit/{generated/v2.0.1/client_tests/client_pended_pas_inquiry_request_bundle_validation_test.rb → custom_groups/v2.0.1/client_tests/pas_client_inquire_request_bundle_validation_test.rb} +22 -20
- data/lib/davinci_pas_test_kit/{generated/v2.0.1/client_tests/client_denial_pas_response_bundle_validation_test.rb → custom_groups/v2.0.1/client_tests/pas_client_inquire_response_bundle_validation_test.rb} +34 -21
- data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_pended_submit_test.rb +124 -5
- data/lib/davinci_pas_test_kit/{generated/v2.0.1/client_tests/client_pas_request_bundle_validation_test.rb → custom_groups/v2.0.1/client_tests/pas_client_request_bundle_validation_test.rb} +22 -20
- data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/{pas_client_approval_submit_response_attest.rb → pas_client_response_attest.rb} +26 -9
- data/lib/davinci_pas_test_kit/{generated/v2.0.1/client_tests/client_pended_pas_response_bundle_validation_test.rb → custom_groups/v2.0.1/client_tests/pas_client_response_bundle_validation_test.rb} +44 -20
- data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_subscription_create_test.rb +49 -0
- data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_subscription_pas_conformance_test.rb +48 -0
- data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/pas_client_approval_group.rb +21 -9
- data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/pas_client_authentication_group.rb +2 -2
- data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/pas_client_denial_group.rb +21 -22
- data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/pas_client_pended_group.rb +97 -31
- data/lib/davinci_pas_test_kit/docs/PAS Requirements Interpretation.xlsx +0 -0
- data/lib/davinci_pas_test_kit/docs/client_suite_description_v201.md +213 -72
- data/lib/davinci_pas_test_kit/endpoints/claim_endpoint.rb +85 -134
- data/lib/davinci_pas_test_kit/endpoints/subscription_create_endpoint.rb +96 -0
- data/lib/davinci_pas_test_kit/endpoints/subscription_status_endpoint.rb +90 -0
- data/lib/davinci_pas_test_kit/fhir_resource_navigation.rb +3 -3
- data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_inquiry_request_bundle/metadata.yml +0 -2
- data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_inquiry_request_bundle/server_pas_inquiry_request_bundle_validation_test.rb +3 -1
- data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_inquiry_response_bundle/server_pas_inquiry_response_bundle_validation_test.rb +2 -1
- data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_request_bundle/metadata.yml +0 -2
- data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_request_bundle/server_pas_request_bundle_validation_test.rb +3 -1
- data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_response_bundle/metadata.yml +0 -4
- data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_response_bundle/server_pas_response_bundle_validation_test.rb +2 -1
- data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_server_denial_use_case_group.rb +1 -1
- data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_server_pended_use_case_group.rb +6 -5
- data/lib/davinci_pas_test_kit/generated/v2.0.1/server_suite.rb +5 -2
- data/lib/davinci_pas_test_kit/generator/group_generator.rb +9 -8
- data/lib/davinci_pas_test_kit/generator/group_metadata_extractor.rb +7 -3
- data/lib/davinci_pas_test_kit/generator/templates/group.rb.erb +129 -0
- data/lib/davinci_pas_test_kit/generator/templates/must_support.rb.erb +73 -0
- data/lib/davinci_pas_test_kit/generator/templates/operation.rb.erb +62 -0
- data/lib/davinci_pas_test_kit/generator/templates/resource_list.rb.erb +13 -0
- data/lib/davinci_pas_test_kit/generator/templates/suite.rb.erb +92 -0
- data/lib/davinci_pas_test_kit/generator/templates/validation.rb.erb +98 -0
- data/lib/davinci_pas_test_kit/generator/validation_test_generator.rb +19 -56
- data/lib/davinci_pas_test_kit/generator/value_extractor.rb +4 -1
- data/lib/davinci_pas_test_kit/generator.rb +1 -1
- data/lib/davinci_pas_test_kit/igs/davinci_pas_2.0.1.tgz +0 -0
- data/lib/davinci_pas_test_kit/jobs/send_pas_subscription_notification.rb +136 -0
- data/lib/davinci_pas_test_kit/jobs/send_subscription_handshake.rb +139 -0
- data/lib/davinci_pas_test_kit/metadata.rb +87 -0
- data/lib/davinci_pas_test_kit/pas_bundle_validation.rb +8 -7
- data/lib/davinci_pas_test_kit/response_generator.rb +397 -0
- data/lib/davinci_pas_test_kit/tags.rb +9 -0
- data/lib/davinci_pas_test_kit/urls.rb +8 -0
- data/lib/davinci_pas_test_kit/user_input_response.rb +11 -8
- data/lib/davinci_pas_test_kit/validation_test.rb +0 -1
- data/lib/davinci_pas_test_kit/version.rb +2 -1
- data/lib/davinci_pas_test_kit.rb +1 -0
- metadata +44 -15
- data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_denial_submit_response_attest.rb +0 -38
- data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_pended_inquire_response_attest.rb +0 -39
- data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_pended_inquire_test.rb +0 -35
- data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_pended_submit_response_attest.rb +0 -39
@@ -0,0 +1,96 @@
|
|
1
|
+
require_relative '../tags'
|
2
|
+
require_relative '../jobs/send_subscription_handshake'
|
3
|
+
require 'subscriptions_test_kit'
|
4
|
+
|
5
|
+
module DaVinciPASTestKit
|
6
|
+
class SubscriptionCreateEndpoint < Inferno::DSL::SuiteEndpoint
|
7
|
+
include SubscriptionsTestKit::SubscriptionsR5BackportR4Client::SubscriptionSimulationUtils
|
8
|
+
|
9
|
+
def test_run_identifier
|
10
|
+
request.headers['authorization']&.delete_prefix('Bearer ')
|
11
|
+
end
|
12
|
+
|
13
|
+
def make_response
|
14
|
+
response.format = :json
|
15
|
+
response.status = 400
|
16
|
+
|
17
|
+
begin
|
18
|
+
subscription = FHIR.from_contents(request.body.string)
|
19
|
+
rescue StandardError
|
20
|
+
response.body = operation_outcome('error', 'invalid', 'No recognized R4 Subscription in request body').to_json
|
21
|
+
return
|
22
|
+
end
|
23
|
+
|
24
|
+
verification_outcome = verify_subscription(subscription)
|
25
|
+
if verification_outcome.present?
|
26
|
+
response.body = verification_outcome.to_json
|
27
|
+
return
|
28
|
+
end
|
29
|
+
|
30
|
+
# Deny subscription if one already created
|
31
|
+
requests = requests_repo.tagged_requests(test_run.test_session_id, tags)
|
32
|
+
existing_subscription_request = requests.find { |r| r.status == 201 }
|
33
|
+
if existing_subscription_request.present?
|
34
|
+
subscription_hash = JSON.parse(existing_subscription_request.response_body)
|
35
|
+
error_text = 'Inferno only supports one subscription per test run. Subscription already created with ' \
|
36
|
+
"ID #{subscription_hash['id']}"
|
37
|
+
response.body = operation_outcome('error', 'business-rule', error_text).to_json
|
38
|
+
return
|
39
|
+
end
|
40
|
+
|
41
|
+
# Form response
|
42
|
+
notification_json = nil # no notification
|
43
|
+
subscription_id = SecureRandom.uuid
|
44
|
+
# We have to manipulate the raw hash so that we don't lose the _payload primitive extension
|
45
|
+
subscription_hash = JSON.parse(request.body.string).merge('id' => subscription_id, 'status' => 'requested')
|
46
|
+
subscription_hash['channel']['payload'] = actual_mime_type(subscription)
|
47
|
+
response.status = 201
|
48
|
+
response.body = subscription_hash.to_json
|
49
|
+
|
50
|
+
# Kick off handshake job
|
51
|
+
subscription_url = "#{request.url}/#{subscription_id}"
|
52
|
+
client_endpoint = subscription.channel.endpoint
|
53
|
+
bearer_token = client_access_token_input(result)
|
54
|
+
test_suite_base_url = request.url.chomp('/').chomp(FHIR_SUBSCRIPTION_PATH)
|
55
|
+
Inferno::Jobs.perform(Jobs::SendSubscriptionHandshake, test_run.id, test_run.test_session_id, result.id,
|
56
|
+
subscription_id, subscription_url, client_endpoint, bearer_token, notification_json,
|
57
|
+
test_run_identifier, test_suite_base_url)
|
58
|
+
end
|
59
|
+
|
60
|
+
def tags
|
61
|
+
[SUBSCRIPTION_CREATE_TAG]
|
62
|
+
end
|
63
|
+
|
64
|
+
def verify_subscription(subscription)
|
65
|
+
unless subscription.is_a? FHIR::Subscription
|
66
|
+
return operation_outcome('error', 'invalid', 'No recognized R4 Subscription in request body')
|
67
|
+
end
|
68
|
+
|
69
|
+
unless subscription.channel&.type == 'rest-hook'
|
70
|
+
return operation_outcome('error', 'business-rule', 'channel.type must be rest-hook')
|
71
|
+
end
|
72
|
+
|
73
|
+
unless valid_url?(subscription.channel&.endpoint)
|
74
|
+
return operation_outcome('error', 'value', 'channel.endpoint is not recognized as a conformant URL')
|
75
|
+
end
|
76
|
+
|
77
|
+
heartbeat_period = find_heartbeat_period(subscription)
|
78
|
+
operation_outcome('error', 'not-supported', 'heartbeatPeriod is not supported') unless heartbeat_period.nil?
|
79
|
+
end
|
80
|
+
|
81
|
+
def find_heartbeat_period(subscription)
|
82
|
+
return unless subscription.present?
|
83
|
+
|
84
|
+
subscription.channel&.extension&.find do |e|
|
85
|
+
e.url == 'http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-heartbeat-period'
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def valid_url?(url)
|
90
|
+
uri = URI.parse(url)
|
91
|
+
%w[http https].include?(uri.scheme)
|
92
|
+
rescue URI::InvalidURIError
|
93
|
+
false
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require_relative '../tags'
|
2
|
+
require 'subscriptions_test_kit'
|
3
|
+
|
4
|
+
module DaVinciPASTestKit
|
5
|
+
class SubscriptionStatusEndpoint < Inferno::DSL::SuiteEndpoint
|
6
|
+
include SubscriptionsTestKit::SubscriptionsR5BackportR4Client::SubscriptionSimulationUtils
|
7
|
+
include ResponseGenerator
|
8
|
+
|
9
|
+
def test_run_identifier
|
10
|
+
request.headers['authorization']&.delete_prefix('Bearer ')
|
11
|
+
end
|
12
|
+
|
13
|
+
def make_response
|
14
|
+
response.format = :json
|
15
|
+
subscription = find_subscription(test_run.test_session_id)
|
16
|
+
|
17
|
+
unless subscription.present?
|
18
|
+
not_found
|
19
|
+
return
|
20
|
+
end
|
21
|
+
|
22
|
+
subscription_id = request.params[:id]
|
23
|
+
|
24
|
+
# Handle resource-level status params
|
25
|
+
unless subscription_id.present?
|
26
|
+
begin
|
27
|
+
params = FHIR.from_contents(request.body.string)
|
28
|
+
rescue StandardError
|
29
|
+
response.status = 400
|
30
|
+
response.body = operation_outcome('error', 'invalid', 'Invalid Parameters in request body').to_json
|
31
|
+
return
|
32
|
+
end
|
33
|
+
|
34
|
+
unless subscription_params_match?(params, subscription)
|
35
|
+
not_found
|
36
|
+
return
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
subscription_url = "#{base_subscription_url}/#{subscription.id}"
|
41
|
+
subscription_topic = subscription.criteria
|
42
|
+
status_code = determine_subscription_status_code(subscription_id)
|
43
|
+
event_count = determine_event_count(test_run.test_session_id)
|
44
|
+
|
45
|
+
notification_json = notification_bundle_input(result)
|
46
|
+
if notification_json.blank?
|
47
|
+
notification_timestamp = Time.now.utc
|
48
|
+
mock_status_bundle = FHIR::Bundle.new(
|
49
|
+
id: SecureRandom.uuid,
|
50
|
+
timestamp: notification_timestamp.iso8601,
|
51
|
+
type: 'history'
|
52
|
+
)
|
53
|
+
mock_notification_status = build_mock_notification_status(notification_timestamp, subscription_url,
|
54
|
+
subscription_topic, nil, nil)
|
55
|
+
mock_status_bundle.entry << build_mock_notification_status_entry(mock_notification_status, subscription_url)
|
56
|
+
notification_json = mock_status_bundle.to_json
|
57
|
+
end
|
58
|
+
response.body = derive_status_bundle(notification_json, subscription_url, subscription_topic, status_code,
|
59
|
+
event_count, request.url).to_json
|
60
|
+
response.status = 200
|
61
|
+
end
|
62
|
+
|
63
|
+
def subscription_params_match?(params, subscription)
|
64
|
+
id_params = find_params(params, 'id')
|
65
|
+
|
66
|
+
return false if id_params&.any? && id_params&.none? { |p| p.valueString == subscription.id }
|
67
|
+
|
68
|
+
status_params = find_params(params, 'status')
|
69
|
+
subscription_status = determine_subscription_status_code(subscription.id)
|
70
|
+
status_params.blank? || status_params.any? { |p| p.valueString == subscription_status }
|
71
|
+
end
|
72
|
+
|
73
|
+
def tags
|
74
|
+
[SUBSCRIPTION_STATUS_TAG]
|
75
|
+
end
|
76
|
+
|
77
|
+
def not_found
|
78
|
+
response.status = 404
|
79
|
+
response.body = operation_outcome('error', 'not-found').to_json
|
80
|
+
end
|
81
|
+
|
82
|
+
def find_params(params, name)
|
83
|
+
params&.parameter&.filter { |p| p.name == name }
|
84
|
+
end
|
85
|
+
|
86
|
+
def base_subscription_url
|
87
|
+
request.url.sub(/(#{Regexp.escape(FHIR_SUBSCRIPTION_PATH)}).*/, '\1')
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -20,7 +20,7 @@ module DaVinciPASTestKit
|
|
20
20
|
end.compact
|
21
21
|
end
|
22
22
|
|
23
|
-
def find_a_value_at(element, path, include_dar: false, &
|
23
|
+
def find_a_value_at(element, path, include_dar: false, &)
|
24
24
|
return nil if element.nil?
|
25
25
|
|
26
26
|
elements = Array.wrap(element)
|
@@ -32,7 +32,7 @@ module DaVinciPASTestKit
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
return elements.find(&
|
35
|
+
return elements.find(&) if block_given?
|
36
36
|
|
37
37
|
return elements.first
|
38
38
|
end
|
@@ -52,7 +52,7 @@ module DaVinciPASTestKit
|
|
52
52
|
elements.each do |elmt|
|
53
53
|
child = get_next_value(elmt, segment)
|
54
54
|
element_found = if block_given?
|
55
|
-
find_a_value_at(child, remaining_path, include_dar:, &
|
55
|
+
find_a_value_at(child, remaining_path, include_dar:, &)
|
56
56
|
else
|
57
57
|
find_a_value_at(child, remaining_path, include_dar:)
|
58
58
|
end
|
@@ -68,8 +68,6 @@
|
|
68
68
|
:tests:
|
69
69
|
- :id: pas_server_v201_pas_inquiry_request_bundle_validation_test
|
70
70
|
:file_name: server_pas_inquiry_request_bundle_validation_test.rb
|
71
|
-
- :id: pas_client_v201_pended_pas_inquiry_request_bundle_validation_test
|
72
|
-
:file_name: client_pended_pas_inquiry_request_bundle_validation_test.rb
|
73
71
|
- :id: pas_server_inquire_request_v201_pas_inquiry_request_bundle_must_support_test
|
74
72
|
:file_name: server_inquire_request_pas_inquiry_request_bundle_must_support_test.rb
|
75
73
|
- :id: pas_client_inquire_request_v201_pas_inquiry_request_bundle_must_support_test
|
@@ -11,9 +11,11 @@ module DaVinciPASTestKit
|
|
11
11
|
**USER INPUT VALIDATION**: This test validates input provided by the user instead of the system under test.
|
12
12
|
Errors encountered will be treated as a skip instead of a failure.
|
13
13
|
|
14
|
+
|
14
15
|
This test validates the conformity of the
|
15
16
|
user input to the
|
16
|
-
[PAS Inquiry Request Bundle](http://hl7.org/fhir/us/davinci-pas/StructureDefinition/profile-pas-inquiry-request-bundle)
|
17
|
+
[PAS Inquiry Request Bundle](http://hl7.org/fhir/us/davinci-pas/StructureDefinition/profile-pas-inquiry-request-bundle)
|
18
|
+
structure, ensuring subsequent tests can accurately simulate content.
|
17
19
|
|
18
20
|
It also checks that other conformance requirements defined in the [PAS Formal
|
19
21
|
Specification](https://hl7.org/fhir/us/davinci-pas/STU2/specification.html),
|
@@ -10,7 +10,8 @@ module DaVinciPASTestKit
|
|
10
10
|
description %(
|
11
11
|
This test validates the conformity of the
|
12
12
|
server's response to the
|
13
|
-
[PAS Inquiry Response Bundle](http://hl7.org/fhir/us/davinci-pas/StructureDefinition/profile-pas-inquiry-response-bundle)
|
13
|
+
[PAS Inquiry Response Bundle](http://hl7.org/fhir/us/davinci-pas/StructureDefinition/profile-pas-inquiry-response-bundle)
|
14
|
+
structure.
|
14
15
|
|
15
16
|
It also checks that other conformance requirements defined in the [PAS Formal
|
16
17
|
Specification](https://hl7.org/fhir/us/davinci-pas/STU2/specification.html),
|
@@ -68,8 +68,6 @@
|
|
68
68
|
:tests:
|
69
69
|
- :id: pas_server_v201_pas_request_bundle_validation_test
|
70
70
|
:file_name: server_pas_request_bundle_validation_test.rb
|
71
|
-
- :id: pas_client_v201_pas_request_bundle_validation_test
|
72
|
-
:file_name: client_pas_request_bundle_validation_test.rb
|
73
71
|
- :id: pas_server_submit_request_v201_pas_request_bundle_must_support_test
|
74
72
|
:file_name: server_submit_request_pas_request_bundle_must_support_test.rb
|
75
73
|
- :id: pas_client_submit_request_v201_pas_request_bundle_must_support_test
|
@@ -11,9 +11,11 @@ module DaVinciPASTestKit
|
|
11
11
|
**USER INPUT VALIDATION**: This test validates input provided by the user instead of the system under test.
|
12
12
|
Errors encountered will be treated as a skip instead of a failure.
|
13
13
|
|
14
|
+
|
14
15
|
This test validates the conformity of the
|
15
16
|
user input to the
|
16
|
-
[PAS Request Bundle](http://hl7.org/fhir/us/davinci-pas/StructureDefinition/profile-pas-request-bundle)
|
17
|
+
[PAS Request Bundle](http://hl7.org/fhir/us/davinci-pas/StructureDefinition/profile-pas-request-bundle)
|
18
|
+
structure, ensuring subsequent tests can accurately simulate content.
|
17
19
|
|
18
20
|
It also checks that other conformance requirements defined in the [PAS Formal
|
19
21
|
Specification](https://hl7.org/fhir/us/davinci-pas/STU2/specification.html),
|
@@ -62,10 +62,6 @@
|
|
62
62
|
:tests:
|
63
63
|
- :id: pas_server_v201_pas_response_bundle_validation_test
|
64
64
|
:file_name: server_pas_response_bundle_validation_test.rb
|
65
|
-
- :id: pas_client_v201_denial_pas_response_bundle_validation_test
|
66
|
-
:file_name: client_denial_pas_response_bundle_validation_test.rb
|
67
|
-
- :id: pas_client_v201_pended_pas_response_bundle_validation_test
|
68
|
-
:file_name: client_pended_pas_response_bundle_validation_test.rb
|
69
65
|
- :id: pas_server_submit_response_v201_pas_response_bundle_must_support_test
|
70
66
|
:file_name: server_submit_response_pas_response_bundle_must_support_test.rb
|
71
67
|
:delayed_references: []
|
@@ -10,7 +10,8 @@ module DaVinciPASTestKit
|
|
10
10
|
description %(
|
11
11
|
This test validates the conformity of the
|
12
12
|
server's response to the
|
13
|
-
[PAS Response Bundle](http://hl7.org/fhir/us/davinci-pas/StructureDefinition/profile-pas-response-bundle)
|
13
|
+
[PAS Response Bundle](http://hl7.org/fhir/us/davinci-pas/StructureDefinition/profile-pas-response-bundle)
|
14
|
+
structure.
|
14
15
|
|
15
16
|
It also checks that other conformance requirements defined in the [PAS Formal
|
16
17
|
Specification](https://hl7.org/fhir/us/davinci-pas/STU2/specification.html),
|
@@ -13,12 +13,13 @@ module DaVinciPASTestKit
|
|
13
13
|
title 'Successful Pended Workflow'
|
14
14
|
description %(
|
15
15
|
Demonstrate a complete prior authorization workflow including a period
|
16
|
-
during which the final decision is pending. This includes
|
16
|
+
during which the final decision is pending. This includes demonstrating
|
17
|
+
the ability of the server to
|
17
18
|
|
18
|
-
-
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
- Respond to a prior authorization request with a `pended` status.
|
20
|
+
- Accept a Subscription creation request and send a notification when
|
21
|
+
the pended claim has been finalized.
|
22
|
+
- Respond to a subsequent inquiry request with a final decision for the request.
|
22
23
|
|
23
24
|
)
|
24
25
|
|
@@ -1,6 +1,6 @@
|
|
1
|
+
require 'subscriptions_test_kit'
|
1
2
|
require_relative '../../validator_suppressions'
|
2
3
|
require_relative '../../custom_groups/v2.0.1/pas_error_group'
|
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'
|
@@ -11,7 +11,6 @@ module DaVinciPASTestKit
|
|
11
11
|
class ServerSuite < Inferno::TestSuite
|
12
12
|
id :davinci_pas_server_suite_v201
|
13
13
|
title 'Da Vinci PAS Server Suite v2.0.1'
|
14
|
-
version DaVinciPASTestKit::VERSION
|
15
14
|
description File.read(File.join(__dir__, '..', '..', 'docs', 'server_suite_description_v201.md'))
|
16
15
|
|
17
16
|
links [
|
@@ -23,6 +22,10 @@ module DaVinciPASTestKit
|
|
23
22
|
label: 'Open Source',
|
24
23
|
url: 'https://github.com/inferno-framework/davinci-pas-test-kit/'
|
25
24
|
},
|
25
|
+
{
|
26
|
+
label: 'Download',
|
27
|
+
url: 'https://github.com/inferno-framework/davinci-pas-test-kit/releases'
|
28
|
+
},
|
26
29
|
{
|
27
30
|
label: 'Implementation Guide',
|
28
31
|
url: 'https://hl7.org/fhir/us/davinci-pas/STU2/'
|
@@ -276,7 +276,7 @@ module DaVinciPASTestKit
|
|
276
276
|
else
|
277
277
|
client_inquiry_request_must_support_test_ids
|
278
278
|
end
|
279
|
-
elsif
|
279
|
+
elsif ['approval', 'denial'].include?(use_case)
|
280
280
|
grouped_approval_denial_test_ids
|
281
281
|
elsif use_case == 'pended'
|
282
282
|
grouped_pended_test_ids
|
@@ -292,7 +292,7 @@ module DaVinciPASTestKit
|
|
292
292
|
else
|
293
293
|
client_inquiry_request_must_support_test_file_list
|
294
294
|
end
|
295
|
-
elsif
|
295
|
+
elsif ['approval', 'denial'].include?(use_case)
|
296
296
|
approval_denial_test_file_list
|
297
297
|
elsif use_case == 'pended'
|
298
298
|
pended_test_file_list
|
@@ -375,17 +375,18 @@ module DaVinciPASTestKit
|
|
375
375
|
when 'denial'
|
376
376
|
<<~DESCRIPTION
|
377
377
|
Demonstrate the ability of the server to respond to a prior
|
378
|
-
authorization request with
|
378
|
+
authorization request with a `denied` decision.
|
379
379
|
DESCRIPTION
|
380
380
|
when 'pended'
|
381
381
|
<<~DESCRIPTION
|
382
382
|
Demonstrate a complete prior authorization workflow including a period
|
383
|
-
during which the final decision is pending. This includes
|
383
|
+
during which the final decision is pending. This includes demonstrating
|
384
|
+
the ability of the server to
|
384
385
|
|
385
|
-
-
|
386
|
-
|
387
|
-
|
388
|
-
|
386
|
+
- Respond to a prior authorization request with a `pended` status.
|
387
|
+
- Accept a Subscription creation request and send a notification when
|
388
|
+
the pended claim has been finalized.
|
389
|
+
- Respond to a subsequent inquiry request with a final decision for the request.
|
389
390
|
DESCRIPTION
|
390
391
|
else # must_support
|
391
392
|
<<~DESCRIPTION
|
@@ -130,7 +130,9 @@ module DaVinciPASTestKit
|
|
130
130
|
end
|
131
131
|
|
132
132
|
def conformance_expectation
|
133
|
-
resource_capabilities
|
133
|
+
return unless resource_capabilities.present?
|
134
|
+
|
135
|
+
resource_capabilities.extension&.first&.valueCode
|
134
136
|
end
|
135
137
|
|
136
138
|
def profile_name
|
@@ -155,7 +157,8 @@ module DaVinciPASTestKit
|
|
155
157
|
resource_capabilities.interaction.map do |interaction|
|
156
158
|
{
|
157
159
|
code: interaction.code,
|
158
|
-
|
160
|
+
# TODO: fix expectation extension finding
|
161
|
+
expectation: interaction.present? ? interaction.extension&.first&.valueCode : nil
|
159
162
|
}
|
160
163
|
end
|
161
164
|
end
|
@@ -165,7 +168,8 @@ module DaVinciPASTestKit
|
|
165
168
|
resource_capabilities.operation.map do |operation|
|
166
169
|
{
|
167
170
|
code: operation.name,
|
168
|
-
|
171
|
+
# TODO: fix expectation extension finding
|
172
|
+
expectation: operation.present? ? operation.extension&.first&.valueCode : nil
|
169
173
|
}
|
170
174
|
end
|
171
175
|
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
<% test_file_list.each do |file_name| %>require_relative '<%= file_name %>'
|
2
|
+
<% end %>
|
3
|
+
module DaVinciPASTestKit
|
4
|
+
module <%= module_name %>
|
5
|
+
class <%= class_name %> < Inferno::TestGroup
|
6
|
+
title '<%= title %>'
|
7
|
+
description %(
|
8
|
+
<%=description.gsub("\n", "\n" + " "*8) %>
|
9
|
+
)
|
10
|
+
|
11
|
+
id :<%= group_id %>
|
12
|
+
<% if run_as_group %>run_as_group<% end %>
|
13
|
+
<% if system == 'client'%>
|
14
|
+
<% test_id_list.each do |id| %>
|
15
|
+
test from: :<%= id %><% end %>
|
16
|
+
<% else %>
|
17
|
+
def use_case
|
18
|
+
'<%= use_case %>'
|
19
|
+
end
|
20
|
+
<% if use_case != 'must_support'%>
|
21
|
+
<% test_id_list.each do |category, id_list| %>
|
22
|
+
group do
|
23
|
+
title '<%= category %>'
|
24
|
+
<% id_list.each do |id| %>
|
25
|
+
test from: :<%= id %><% if rename_input?(id) %> do
|
26
|
+
id :<%= alt_test_id(id, use_case) %>
|
27
|
+
config(
|
28
|
+
inputs: {
|
29
|
+
pa_submit_request_payload: {
|
30
|
+
name: :<%= alt_request_input_name(use_case, 'submit')%> ,
|
31
|
+
title: '<%= alt_request_input_title(use_case, 'submit')%>'
|
32
|
+
}
|
33
|
+
}
|
34
|
+
)
|
35
|
+
end<% end %><% end %>
|
36
|
+
end<% end %>
|
37
|
+
<% else %>
|
38
|
+
<% test_id_list.each do |group, subgroup|%>
|
39
|
+
group do
|
40
|
+
title '<%= group%>'
|
41
|
+
<% if group == '$submit Element Support' %>description %(
|
42
|
+
Check that the provided `$submit` requests both themselves contain
|
43
|
+
and elicit server responses that contain all PAS-defined profiles
|
44
|
+
and their must support elements.
|
45
|
+
|
46
|
+
For `$submit` requests, this includes the following profiles:
|
47
|
+
|
48
|
+
- [PAS Request Bundle](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-pas-request-bundle.html)
|
49
|
+
- [PAS Claim Update](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-claim-update.html)
|
50
|
+
- [PAS Coverage](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-coverage.html)
|
51
|
+
- [PAS Beneficiary Patient](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-beneficiary.html)
|
52
|
+
- [PAS Subscriber Patient](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-subscriber.html)
|
53
|
+
- [PAS Insurer Organization](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-insurer.html)
|
54
|
+
- [PAS Requestor Organization](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-requestor.html)
|
55
|
+
- [PAS Practitioner](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-practitioner.html)
|
56
|
+
- [PAS PractitionerRole](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-practitionerrole.html)
|
57
|
+
- [PAS Encounter](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-encounter.html)
|
58
|
+
- At least one of the following request profiles
|
59
|
+
- [PAS Device Request](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-devicerequest.html)
|
60
|
+
- [PAS Medication Request](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-medicationrequest.html)
|
61
|
+
- [PAS Nutrition Order](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-nutritionorder.html)
|
62
|
+
- [PAS Service Request](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-servicerequest.html)
|
63
|
+
|
64
|
+
For `$submit` responses, this includes the following profiles (NOTE: request-specific
|
65
|
+
profiles that may be echoed from `$submit` requests, such as the Claim instance or request instances,
|
66
|
+
are not currently checked):
|
67
|
+
|
68
|
+
- [PAS Response Bundle](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-pas-response-bundle.html)
|
69
|
+
- [PAS Claim Response](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-claimresponse.html)
|
70
|
+
- [PAS CommunicationRequest](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-communicationrequest.html)
|
71
|
+
- [PAS Task](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-task.html)
|
72
|
+
- [PAS Beneficiary Patient](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-beneficiary.html)
|
73
|
+
- [PAS Insurer Organization](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-insurer.html)
|
74
|
+
- [PAS Requestor Organization](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-requestor.html)
|
75
|
+
- [PAS Practitioner](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-practitioner.html)
|
76
|
+
- [PAS PractitionerRole](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-practitionerrole.html)
|
77
|
+
)<% elsif group == '$inquire Element Support' %>description %(
|
78
|
+
Check that the provided `$inquire` requests both themselves contain
|
79
|
+
and elicit server responses that contain all PAS-defined profiles
|
80
|
+
and their must support elements.
|
81
|
+
|
82
|
+
For `$inquire` requests, this includes the following profiles:
|
83
|
+
|
84
|
+
- [PAS Inquiry Request Bundle](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-pas-inquiry-request-bundle.html)
|
85
|
+
- [PAS Claim Inquiry](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-claim-inquiry.html)
|
86
|
+
- [PAS Coverage](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-coverage.html)
|
87
|
+
- [PAS Beneficiary Patient](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-beneficiary.html)
|
88
|
+
- [PAS Subscriber Patient](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-subscriber.html)
|
89
|
+
- [PAS Insurer Organization](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-insurer.html)
|
90
|
+
- [PAS Requestor Organization](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-requestor.html)
|
91
|
+
- [PAS Practitioner](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-practitioner.html)
|
92
|
+
- [PAS PractitionerRole](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-practitionerrole.html)
|
93
|
+
|
94
|
+
For `$inquire` responses, this includes the following profiles (NOTE: request-specific
|
95
|
+
profiles that may be echoed from `$submit` requests, such as the Claim instance or request instances,
|
96
|
+
are not currently checked):
|
97
|
+
|
98
|
+
- [PAS Inquiry Response Bundle](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-pas-inquiry-request-bundle.html)
|
99
|
+
- [PAS Claim Inquiry Response](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-claiminquiryresponse.html)
|
100
|
+
- [PAS Task](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-task.html)
|
101
|
+
- [PAS Beneficiary Patient](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-beneficiary.html)
|
102
|
+
- [PAS Insurer Organization](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-insurer.html)
|
103
|
+
- [PAS Requestor Organization](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-requestor.html)
|
104
|
+
- [PAS Practitioner](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-practitioner.html)
|
105
|
+
- [PAS PractitionerRole](https://hl7.org/fhir/us/davinci-pas/STU2/StructureDefinition-profile-practitionerrole.html)
|
106
|
+
)<% end %>
|
107
|
+
run_as_group
|
108
|
+
<% subgroup.each do |category, id_list| %>
|
109
|
+
group do
|
110
|
+
title '<%= category%>'
|
111
|
+
<% id_list.each do |id|%>
|
112
|
+
test from: :<%= id%><% if must_support_rename_input?(id) %> do
|
113
|
+
id :<%= alt_test_id(id, use_case) %>
|
114
|
+
config(
|
115
|
+
inputs: {<% request_type = id.include?('inquiry') ? 'inquire' : 'submit' %>
|
116
|
+
pa_<%= request_type%>_request_payload: {
|
117
|
+
name: :<%= alt_request_input_name(use_case, request_type)%>,
|
118
|
+
title: '<%= alt_request_input_title(use_case, request_type)%>',
|
119
|
+
description: 'Insert an additional request bundle or a list of bundles (e.g. [bundle_1, bundle_2])'
|
120
|
+
}
|
121
|
+
}
|
122
|
+
)
|
123
|
+
end<%end%><% end %>
|
124
|
+
end<% end %>
|
125
|
+
end<%end%>
|
126
|
+
<% end %><% end %>
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require_relative '../../../must_support_test'
|
2
|
+
require_relative '../../../generator/group_metadata'
|
3
|
+
require_relative '../../../tags'
|
4
|
+
|
5
|
+
module DaVinciPASTestKit
|
6
|
+
module <%= module_name %>
|
7
|
+
class <%= class_name %> < Inferno::Test
|
8
|
+
include DaVinciPASTestKit::MustSupportTest
|
9
|
+
|
10
|
+
title 'All must support elements for Profile <%= profile_name %> are observed across all instances <%= request_type.include?('request') ? 'submitted' : 'returned' %>'
|
11
|
+
description %(
|
12
|
+
<% if system == 'client' && request_type.include?('request') %>
|
13
|
+
PAS client systems are required to be able to populate all
|
14
|
+
must support elements on instances of all profiles included in <% request_type.include?('submit') ? 'Submit' : 'Inquiry' %>
|
15
|
+
requests, including instances of the <%= profile_name %> Profile.
|
16
|
+
This test checks all identified instances of the <%= profile_name %>
|
17
|
+
Profile on requests sent by the client to ensure that the following
|
18
|
+
must support elements are observed: <% end %><% if system == 'client' && request_type.include?('response') %>
|
19
|
+
PAS client systems are required to be able to receive all
|
20
|
+
must support elements on instances of all profiles included in <% request_type.include?('submit') ? 'Submit' : 'Inquiry' %>
|
21
|
+
responses, including instances of the <%= profile_name %> Profile.
|
22
|
+
This test checks all identified instances of the <%= profile_name %>
|
23
|
+
Profile on responses sent to the client to ensure that the following
|
24
|
+
must support elements are observed:<% end %><% if system == 'server' && request_type.include?('request') %>
|
25
|
+
**USER INPUT VALIDATION**: This test validates input provided by the user instead of the system under test. Errors encountered will be treated as a skip instead of a failure.
|
26
|
+
|
27
|
+
PAS server systems are required to be able to receive all
|
28
|
+
must support elements on instances of all profiles included in <% request_type.include?('submit') ? 'Submit' : 'Inquiry' %>
|
29
|
+
requests, including instances of the <%= profile_name %> Profile.
|
30
|
+
This test checks all identified instances of the <%= profile_name %>
|
31
|
+
Profile on requests sent to the server to ensure that the following
|
32
|
+
must support elements are observed:<% end %><% if system == 'server' && request_type.include?('response') %>
|
33
|
+
PAS server systems are required to be able to populate all
|
34
|
+
must support elements on instances of all profiles included in <% request_type.include?('submit') ? 'Submit' : 'Inquiry' %>
|
35
|
+
responses, including instances of the <%= profile_name %> Profile.
|
36
|
+
This test checks all identified instances of the <%= profile_name %>
|
37
|
+
Profile on responses returned by the server to ensure that the following
|
38
|
+
must support elements are observed:<% end %>
|
39
|
+
|
40
|
+
<%= must_support_list_string %>
|
41
|
+
)
|
42
|
+
|
43
|
+
id :<%= test_id %>
|
44
|
+
|
45
|
+
def resource_type
|
46
|
+
'<%= resource_type %>'
|
47
|
+
end
|
48
|
+
|
49
|
+
def user_input_validation
|
50
|
+
<% if system == 'server' && request_type.include?('request') %>true<% else %>false<% end %>
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.metadata
|
54
|
+
@metadata ||= Generator::GroupMetadata.new(YAML.load_file(File.join(__dir__, 'metadata.yml'), aliases: true))
|
55
|
+
end
|
56
|
+
|
57
|
+
def scratch_resources
|
58
|
+
# The scratch key in MS test should be the same as the scratch key in the validation test for a given profile.
|
59
|
+
scratch[:<%= request_type %>_resources] ||= {}
|
60
|
+
end
|
61
|
+
|
62
|
+
def resources_of_interest
|
63
|
+
collection = tagged_resources(<%= request_type.include?('submit') ? 'SUBMIT_TAG' : 'INQUIRE_TAG' %>).presence || <%= resource_collection_string %>
|
64
|
+
collection.select { |res| res.resourceType == resource_type }
|
65
|
+
end
|
66
|
+
|
67
|
+
run do
|
68
|
+
perform_must_support_test(resources_of_interest)
|
69
|
+
validate_must_support(user_input_validation)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|