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.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/config/presets/pas_client_example.json +30 -0
  3. data/config/presets/pas_ri.json +69 -0
  4. data/lib/davinci_pas_test_kit/client_suite.rb +28 -2
  5. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_approval_submit_test.rb +29 -1
  6. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_denial_submit_test.rb +27 -4
  7. 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
  8. 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
  9. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_pended_submit_test.rb +124 -5
  10. 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
  11. 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
  12. 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
  13. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_subscription_create_test.rb +49 -0
  14. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_subscription_pas_conformance_test.rb +48 -0
  15. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/pas_client_approval_group.rb +21 -9
  16. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/pas_client_authentication_group.rb +2 -2
  17. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/pas_client_denial_group.rb +21 -22
  18. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/pas_client_pended_group.rb +97 -31
  19. data/lib/davinci_pas_test_kit/docs/PAS Requirements Interpretation.xlsx +0 -0
  20. data/lib/davinci_pas_test_kit/docs/client_suite_description_v201.md +213 -72
  21. data/lib/davinci_pas_test_kit/endpoints/claim_endpoint.rb +85 -134
  22. data/lib/davinci_pas_test_kit/endpoints/subscription_create_endpoint.rb +96 -0
  23. data/lib/davinci_pas_test_kit/endpoints/subscription_status_endpoint.rb +90 -0
  24. data/lib/davinci_pas_test_kit/fhir_resource_navigation.rb +3 -3
  25. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_inquiry_request_bundle/metadata.yml +0 -2
  26. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_inquiry_request_bundle/server_pas_inquiry_request_bundle_validation_test.rb +3 -1
  27. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_inquiry_response_bundle/server_pas_inquiry_response_bundle_validation_test.rb +2 -1
  28. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_request_bundle/metadata.yml +0 -2
  29. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_request_bundle/server_pas_request_bundle_validation_test.rb +3 -1
  30. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_response_bundle/metadata.yml +0 -4
  31. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_response_bundle/server_pas_response_bundle_validation_test.rb +2 -1
  32. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_server_denial_use_case_group.rb +1 -1
  33. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_server_pended_use_case_group.rb +6 -5
  34. data/lib/davinci_pas_test_kit/generated/v2.0.1/server_suite.rb +5 -2
  35. data/lib/davinci_pas_test_kit/generator/group_generator.rb +9 -8
  36. data/lib/davinci_pas_test_kit/generator/group_metadata_extractor.rb +7 -3
  37. data/lib/davinci_pas_test_kit/generator/templates/group.rb.erb +129 -0
  38. data/lib/davinci_pas_test_kit/generator/templates/must_support.rb.erb +73 -0
  39. data/lib/davinci_pas_test_kit/generator/templates/operation.rb.erb +62 -0
  40. data/lib/davinci_pas_test_kit/generator/templates/resource_list.rb.erb +13 -0
  41. data/lib/davinci_pas_test_kit/generator/templates/suite.rb.erb +92 -0
  42. data/lib/davinci_pas_test_kit/generator/templates/validation.rb.erb +98 -0
  43. data/lib/davinci_pas_test_kit/generator/validation_test_generator.rb +19 -56
  44. data/lib/davinci_pas_test_kit/generator/value_extractor.rb +4 -1
  45. data/lib/davinci_pas_test_kit/generator.rb +1 -1
  46. data/lib/davinci_pas_test_kit/igs/davinci_pas_2.0.1.tgz +0 -0
  47. data/lib/davinci_pas_test_kit/jobs/send_pas_subscription_notification.rb +136 -0
  48. data/lib/davinci_pas_test_kit/jobs/send_subscription_handshake.rb +139 -0
  49. data/lib/davinci_pas_test_kit/metadata.rb +87 -0
  50. data/lib/davinci_pas_test_kit/pas_bundle_validation.rb +8 -7
  51. data/lib/davinci_pas_test_kit/response_generator.rb +397 -0
  52. data/lib/davinci_pas_test_kit/tags.rb +9 -0
  53. data/lib/davinci_pas_test_kit/urls.rb +8 -0
  54. data/lib/davinci_pas_test_kit/user_input_response.rb +11 -8
  55. data/lib/davinci_pas_test_kit/validation_test.rb +0 -1
  56. data/lib/davinci_pas_test_kit/version.rb +2 -1
  57. data/lib/davinci_pas_test_kit.rb +1 -0
  58. metadata +44 -15
  59. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_denial_submit_response_attest.rb +0 -38
  60. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_pended_inquire_response_attest.rb +0 -39
  61. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_pended_inquire_test.rb +0 -35
  62. 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, &block)
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(&block) if block_given?
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:, &block)
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) structure, ensuring subsequent tests can accurately simulate content.
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) structure.
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) structure, ensuring subsequent tests can accurately simulate content.
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) structure.
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),
@@ -9,7 +9,7 @@ module DaVinciPASTestKit
9
9
  title 'Successful Denial Workflow'
10
10
  description %(
11
11
  Demonstrate the ability of the server to respond to a prior
12
- authorization request with an `denied` decision.
12
+ authorization request with a `denied` decision.
13
13
 
14
14
  )
15
15
 
@@ -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
- - Demonstrating the ability of the server to respond to a prior
19
- authorization request with an `pended` status.
20
- - Demonstrating the ability of the server to respond to a subsequent
21
- inquiry request with a final decision for the request
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 use_case == 'approval' || use_case == 'denial'
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 use_case == 'approval' || use_case == 'denial'
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 an `denied` decision.
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
- - Demonstrating the ability of the server to respond to a prior
386
- authorization request with an `pended` status.
387
- - Demonstrating the ability of the server to respond to a subsequent
388
- inquiry request with a final decision for the request
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&.extension&.first&.valueCode
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
- expectation: interaction&.extension&.first&.valueCode # TODO: fix expectation extension finding
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
- expectation: operation&.extension&.first&.valueCode # TODO: fix expectation extension finding
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