davinci_pas_test_kit 0.11.0 → 0.12.0

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 (24) 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 +11 -27
  5. data/lib/davinci_pas_test_kit/docs/PAS Requirements Interpretation.xlsx +0 -0
  6. data/lib/davinci_pas_test_kit/{mock_server.rb → endpoints/claim_endpoint.rb} +32 -45
  7. data/lib/davinci_pas_test_kit/endpoints/token_endpoint.rb +22 -0
  8. data/lib/davinci_pas_test_kit/fhir_resource_navigation.rb +3 -3
  9. data/lib/davinci_pas_test_kit/generated/v2.0.1/server_suite.rb +4 -2
  10. data/lib/davinci_pas_test_kit/generator/templates/group.rb.erb +129 -0
  11. data/lib/davinci_pas_test_kit/generator/templates/must_support.rb.erb +73 -0
  12. data/lib/davinci_pas_test_kit/generator/templates/operation.rb.erb +62 -0
  13. data/lib/davinci_pas_test_kit/generator/templates/resource_list.rb.erb +13 -0
  14. data/lib/davinci_pas_test_kit/generator/templates/suite.rb.erb +91 -0
  15. data/lib/davinci_pas_test_kit/generator/templates/validation.rb.erb +98 -0
  16. data/lib/davinci_pas_test_kit/generator/templates/validation_client.rb.erb +50 -0
  17. data/lib/davinci_pas_test_kit/igs/davinci_pas_2.0.1.tgz +0 -0
  18. data/lib/davinci_pas_test_kit/metadata.rb +87 -0
  19. data/lib/davinci_pas_test_kit/version.rb +2 -1
  20. data/lib/davinci_pas_test_kit.rb +1 -0
  21. metadata +21 -10
  22. data/lib/davinci_pas_test_kit/ext/inferno_core/record_response_route.rb +0 -98
  23. data/lib/davinci_pas_test_kit/ext/inferno_core/request.rb +0 -19
  24. data/lib/davinci_pas_test_kit/ext/inferno_core/runnable.rb +0 -18
@@ -1,25 +1,19 @@
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 'mock_server'
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'
11
9
  require_relative 'custom_groups/v2.0.1/pas_client_pended_group'
12
10
  require_relative 'generated/v2.0.1/pas_client_submit_must_support_use_case_group'
13
11
  require_relative 'generated/v2.0.1/pas_client_inquiry_must_support_use_case_group'
14
- require_relative 'version'
15
12
 
16
13
  module DaVinciPASTestKit
17
14
  class ClientSuite < Inferno::TestSuite
18
- extend MockServer
19
-
20
15
  id :davinci_pas_client_suite_v201
21
16
  title 'Da Vinci PAS Client Suite v2.0.1'
22
- version VERSION
23
17
  description File.read(File.join(__dir__, 'docs', 'client_suite_description_v201.md'))
24
18
 
25
19
  links [
@@ -31,16 +25,16 @@ module DaVinciPASTestKit
31
25
  label: 'Open Source',
32
26
  url: 'https://github.com/inferno-framework/davinci-pas-test-kit/'
33
27
  },
28
+ {
29
+ label: 'Download',
30
+ url: 'https://github.com/inferno-framework/davinci-pas-test-kit/releases'
31
+ },
34
32
  {
35
33
  label: 'Implementation Guide',
36
34
  url: 'https://hl7.org/fhir/us/davinci-pas/STU2/'
37
35
  }
38
36
  ]
39
37
 
40
- def self.test_resumes?(test)
41
- !test.config.options[:accepts_multiple_requests]
42
- end
43
-
44
38
  fhir_resource_validator do
45
39
  igs 'hl7.fhir.us.davinci-pas#2.0.1'
46
40
 
@@ -51,26 +45,16 @@ module DaVinciPASTestKit
51
45
  end
52
46
  end
53
47
 
54
- record_response_route :post, TOKEN_PATH, AUTH_TAG, method(:token_response) do |request|
55
- ClientSuite.extract_client_id(request)
56
- end
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
48
+ suite_endpoint :post, TOKEN_PATH, TokenEndpoint
49
+ suite_endpoint :post, SUBMIT_PATH, ClaimEndpoint
50
+ suite_endpoint :post, INQUIRE_PATH, ClaimEndpoint
67
51
 
68
52
  resume_test_route :get, RESUME_PASS_PATH do |request|
69
- ClientSuite.extract_token_from_query_params(request)
53
+ request.query_parameters['token']
70
54
  end
71
55
 
72
56
  resume_test_route :get, RESUME_FAIL_PATH, result: 'fail' do |request|
73
- ClientSuite.extract_token_from_query_params(request)
57
+ request.query_parameters['token']
74
58
  end
75
59
 
76
60
  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
- # Serve responses to PAS requests
5
- #
6
- # Note that there are numerous expected validation issues that can safely be ignored.
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 claim_response(request, test = nil, test_result = nil)
16
- request.status = 200
17
- request.response_headers = { 'Content-Type': 'application/json' }
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, test_result)
20
- if test.present? && test_result.present? && user_inputted_response.present?
21
- request.response_body = user_inputted_response
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
- operation = request&.url&.split('$')&.last
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, request)
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, operation, root_url)
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
- request.response_body = res_bundle.to_json
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, operation, root_url)
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 extract_client_id(request)
132
- URI.decode_www_form(request.request_body).to_h['client_id']
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
- request.response_body = FHIR::OperationOutcome.new(
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
@@ -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
@@ -1,6 +1,5 @@
1
1
  require_relative '../../validator_suppressions'
2
2
  require_relative '../../custom_groups/v2.0.1/pas_error_group'
3
- require_relative '../../version'
4
3
  require_relative 'pas_server_approval_use_case_group'
5
4
  require_relative 'pas_server_denial_use_case_group'
6
5
  require_relative 'pas_server_pended_use_case_group'
@@ -11,7 +10,6 @@ module DaVinciPASTestKit
11
10
  class ServerSuite < Inferno::TestSuite
12
11
  id :davinci_pas_server_suite_v201
13
12
  title 'Da Vinci PAS Server Suite v2.0.1'
14
- version DaVinciPASTestKit::VERSION
15
13
  description File.read(File.join(__dir__, '..', '..', 'docs', 'server_suite_description_v201.md'))
16
14
 
17
15
  links [
@@ -23,6 +21,10 @@ module DaVinciPASTestKit
23
21
  label: 'Open Source',
24
22
  url: 'https://github.com/inferno-framework/davinci-pas-test-kit/'
25
23
  },
24
+ {
25
+ label: 'Download',
26
+ url: 'https://github.com/inferno-framework/davinci-pas-test-kit/releases'
27
+ },
26
28
  {
27
29
  label: 'Implementation Guide',
28
30
  url: 'https://hl7.org/fhir/us/davinci-pas/STU2/'
@@ -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
@@ -0,0 +1,62 @@
1
+ module DaVinciPASTestKit
2
+ module <%= module_name %>
3
+ class <%= class_name %> < Inferno::Test
4
+
5
+ id :<%= test_id %>
6
+ title '<%= title %>'
7
+ description %(
8
+ <%=description.gsub("\n", "\n" + " "*8) %>
9
+ )
10
+
11
+ input :pa_<%= request_type %>_payload,
12
+ title: 'PAS <%= request_type.humanize.titleize%> Payload',
13
+ description: 'Insert Bundle to be sent for PAS <%= request_type.humanize.titleize%>',
14
+ type: 'textarea',
15
+ optional: true
16
+ input_order :server_endpoint, :smart_credentials
17
+ <% if operation == 'submit'%>output :response_time<% end %>
18
+ makes_request :pa_<%= operation %>
19
+
20
+ def scratch_resources
21
+ scratch[:<%= operation %>_request_response_pair] ||= {}
22
+ end
23
+
24
+ def request_bundles
25
+ parsed_payload = JSON.parse(pa_<%= request_type %>_payload)
26
+ [parsed_payload].flatten.compact.uniq
27
+ end
28
+
29
+ def perform_operation(request_payload)
30
+ <% if operation == 'submit'%>start_time = Time.now<% end %>
31
+ fhir_operation('/Claim/$<%= operation %>', body: request_payload, name: :pa_<%= operation %>)
32
+ <% if operation == 'submit'%>response_time = Time.now - start_time
33
+
34
+ if response_time > 15
35
+ warning %(
36
+ The server took more that 15 seconds to respond to the Prior Authorization
37
+ request.
38
+
39
+ Response Time: #{response_time}
40
+ )
41
+ end
42
+ <% end %>
43
+ assert_response_status([200, 201])
44
+ assert_valid_json(request.response_body)
45
+
46
+ # Save request/response pair
47
+ scratch_resources[:all] ||= []
48
+ scratch_resources[:all] << {request_bundle: request.request_body, response_bundle: resource}
49
+ <% if operation == 'submit'%>output response_time:<% end %>
50
+ end
51
+
52
+ run do
53
+ skip_if pa_<%= request_type %>_payload.blank?, 'No bundle request provided to perform the <%= operation %> operation'
54
+ assert_valid_json(pa_<%= request_type %>_payload)
55
+
56
+ request_bundles.each do |bundle|
57
+ perform_operation(bundle)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,13 @@
1
+ module DaVinciPASTestKit
2
+ module <%= module_name %>
3
+ module ResourceList
4
+ RESOURCE_LIST = [
5
+ <%= resource_list_string.gsub("\n", "\n" + " "*4) %>
6
+ ].freeze
7
+
8
+ RESOURCE_SUPPORTED_PROFILES = {<% resource_supported_profiles.each do |resource, profile_list| %>
9
+ <%= resource %>: <%= profile_list %>,<% end %>
10
+ }.freeze
11
+ end
12
+ end
13
+ end