davinci_pas_test_kit 0.15.0 → 0.15.2

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 (98) hide show
  1. checksums.yaml +4 -4
  2. data/config/presets/pas_client_example.json +2 -2
  3. data/config/presets/pas_client_v201_run_against_pas_server.json +2 -2
  4. data/config/presets/pas_client_v221_run_against_pas_server.json +3 -3
  5. data/config/presets/pas_ri.json +6 -6
  6. data/config/presets/pas_server_v201_run_against_pas_client.json.erb +6 -6
  7. data/config/presets/pas_server_v221_run_against_pas_client.json.erb +10 -10
  8. data/lib/davinci_pas_test_kit/client/abstract_gather_must_support_test.rb +2 -48
  9. data/lib/davinci_pas_test_kit/client/client_input_descriptions.rb +29 -0
  10. data/lib/davinci_pas_test_kit/client/endpoints/claim_endpoint.rb +25 -9
  11. data/lib/davinci_pas_test_kit/client/user_input_response.rb +25 -6
  12. data/lib/davinci_pas_test_kit/client/v2.0.1/client_suite.rb +1 -1
  13. data/lib/davinci_pas_test_kit/client/v2.2.1/client_suite.rb +1 -1
  14. data/lib/davinci_pas_test_kit/cross_suite/fhirpath_utils.rb +13 -3
  15. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/beneficiary/metadata.yml +4 -0
  16. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/claim_inquiry/metadata.yml +15 -0
  17. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/claim_update/metadata.yml +17 -0
  18. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/claiminquiryresponse/metadata.yml +15 -0
  19. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/claimresponse/metadata.yml +15 -0
  20. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/communication_request/metadata.yml +4 -0
  21. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/coverage/metadata.yml +1 -0
  22. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/device_request/metadata.yml +2 -0
  23. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/encounter/metadata.yml +3 -0
  24. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/insurer/metadata.yml +1 -0
  25. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/medication_request/metadata.yml +2 -0
  26. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/metadata.yml +143 -0
  27. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/nutrition_order/metadata.yml +2 -0
  28. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/pas_inquiry_request_bundle/metadata.yml +2 -0
  29. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/pas_inquiry_response_bundle/metadata.yml +2 -0
  30. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/pas_request_bundle/metadata.yml +2 -0
  31. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/pas_response_bundle/metadata.yml +2 -0
  32. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/practitioner/metadata.yml +1 -0
  33. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/practitioner_role/metadata.yml +1 -0
  34. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/requestor/metadata.yml +1 -0
  35. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/service_request/metadata.yml +3 -0
  36. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/subscriber/metadata.yml +4 -0
  37. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/task/metadata.yml +1 -0
  38. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/beneficiary/metadata.yml +1 -0
  39. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/claim_inquiry/metadata.yml +23 -0
  40. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/claim_update/metadata.yml +31 -0
  41. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/claiminquiryresponse/metadata.yml +42 -0
  42. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/claimresponse/metadata.yml +42 -0
  43. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/communication_request/metadata.yml +4 -0
  44. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/coverage/metadata.yml +1 -0
  45. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/device_request/metadata.yml +2 -0
  46. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/encounter/metadata.yml +3 -0
  47. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/insurer/metadata.yml +1 -0
  48. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/medication_request/metadata.yml +2 -0
  49. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/metadata.yml +265 -0
  50. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/nutrition_order/metadata.yml +2 -0
  51. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/pas_inquiry_request_bundle/metadata.yml +2 -0
  52. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/pas_inquiry_response_bundle/metadata.yml +2 -0
  53. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/pas_request_bundle/metadata.yml +2 -0
  54. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/pas_response_bundle/metadata.yml +2 -0
  55. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/practitioner/metadata.yml +1 -0
  56. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/practitioner_role/metadata.yml +1 -0
  57. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/requestor/metadata.yml +1 -0
  58. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/service_request/metadata.yml +3 -0
  59. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/subscriber/metadata.yml +1 -0
  60. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/task/metadata.yml +4 -0
  61. data/lib/davinci_pas_test_kit/cross_suite/pas_bundle_validation.rb +97 -39
  62. data/lib/davinci_pas_test_kit/cross_suite/pas_constants.rb +6 -0
  63. data/lib/davinci_pas_test_kit/cross_suite/pas_datatype_constraints.rb +166 -0
  64. data/lib/davinci_pas_test_kit/cross_suite/response_selection_utils.rb +26 -10
  65. data/lib/davinci_pas_test_kit/cross_suite/validator_suppressions.rb +206 -146
  66. data/lib/davinci_pas_test_kit/docs/demo/PAS Client Suite Demonstration.postman_collection.json +4 -4
  67. data/lib/davinci_pas_test_kit/generator/must_support_test_generator.rb +6 -0
  68. data/lib/davinci_pas_test_kit/generator/pas_must_support_metadata_extractor.rb +1 -2
  69. data/lib/davinci_pas_test_kit/generator/server_must_support_group_generator.rb +23 -0
  70. data/lib/davinci_pas_test_kit/generator/server_suite_generator.rb +6 -0
  71. data/lib/davinci_pas_test_kit/generator/templates/must_support.rb.erb +3 -2
  72. data/lib/davinci_pas_test_kit/generator/templates/server_must_support_group.rb.erb +22 -0
  73. data/lib/davinci_pas_test_kit/generator/templates/server_suite.rb.erb +4 -5
  74. data/lib/davinci_pas_test_kit/generator/templates/use_case_group.rb.erb +3 -0
  75. data/lib/davinci_pas_test_kit/generator/use_case_group_generator.rb +14 -8
  76. data/lib/davinci_pas_test_kit/requirements/generated/davinci_pas_server_suite_v221_requirements_coverage.csv +28 -28
  77. data/lib/davinci_pas_test_kit/server/generated/v2.0.1/pas_server_approval_use_case_group.rb +1 -0
  78. data/lib/davinci_pas_test_kit/server/generated/v2.0.1/pas_server_denial_use_case_group.rb +1 -0
  79. data/lib/davinci_pas_test_kit/server/generated/v2.0.1/pas_server_pended_use_case_group.rb +1 -0
  80. data/lib/davinci_pas_test_kit/server/generated/v2.0.1/server_suite.rb +4 -5
  81. data/lib/davinci_pas_test_kit/server/generated/v2.2.1/claiminquiryresponse/server_inquire_response_must_support_claiminquiryresponse_test.rb +2 -0
  82. data/lib/davinci_pas_test_kit/server/generated/v2.2.1/claimresponse/server_submit_response_must_support_claimresponse_test.rb +2 -0
  83. data/lib/davinci_pas_test_kit/server/generated/v2.2.1/pas_server_approval_use_case_group.rb +2 -0
  84. data/lib/davinci_pas_test_kit/server/generated/v2.2.1/pas_server_denial_use_case_group.rb +2 -0
  85. data/lib/davinci_pas_test_kit/server/generated/v2.2.1/pas_server_must_support_group.rb +12 -0
  86. data/lib/davinci_pas_test_kit/server/generated/v2.2.1/pas_server_pended_use_case_group.rb +5 -0
  87. data/lib/davinci_pas_test_kit/server/generated/v2.2.1/server_suite.rb +4 -5
  88. data/lib/davinci_pas_test_kit/server/server_response_bundle_validation_test.rb +14 -5
  89. data/lib/davinci_pas_test_kit/server/v2.2.1/claim_inquiry/server_claim_inquiry_response_tests.rb +89 -0
  90. data/lib/davinci_pas_test_kit/server/v2.2.1/pas_error_group.rb +2 -0
  91. data/lib/davinci_pas_test_kit/server/v2.2.1/pas_server_claim_inquiry_responses_group.rb +17 -0
  92. data/lib/davinci_pas_test_kit/server/v2.2.1/pas_server_no_custom_extensions_test.rb +241 -0
  93. data/lib/davinci_pas_test_kit/server/v2.2.1/pas_server_subscription_capability_statement_test.rb +40 -0
  94. data/lib/davinci_pas_test_kit/server/v2.2.1/pas_server_subscription_setup.rb +14 -9
  95. data/lib/davinci_pas_test_kit/server/v2.2.1/server_replaced_pa_inquire_reference_input_test.rb +63 -0
  96. data/lib/davinci_pas_test_kit/server/v2.2.1/server_replaced_pa_inquire_reference_test.rb +109 -0
  97. data/lib/davinci_pas_test_kit/version.rb +2 -2
  98. metadata +9 -2
@@ -43,58 +43,12 @@ module DaVinciPASTestKit
43
43
  title: 'Must Support $submit Response Bundles',
44
44
  type: 'textarea',
45
45
  optional: true,
46
- description: %(
47
- An optional JSON value specifying response Bundles for Inferno to return when
48
- responding to $submit requests during must support testing. Provide a single entry
49
- or a list of entries, where each entry is either a FHIR Bundle or a wrapper object
50
- of the form `{"criteria": {...}, "bundle": {...}}` pairing a FHIR Bundle with the
51
- selection criteria that a request must meet for that Bundle to be returned.
52
-
53
- For each request, Inferno will respond with the Bundle of the first entry whose
54
- criteria are all met. An entry with no criteria (including a bare Bundle) matches
55
- any request, and an entry with multiple criteria must meet all of them. If no entry
56
- matches, or none are provided, Inferno will generate a default response. Supported
57
- `criteria` keys:
58
-
59
- - `requestRange`: a string of comma-separated request numbers or ranges, e.g.,
60
- `"1-2,4"`. Met when the number of $submit requests received during this test,
61
- counting this one, is among the listed values.
62
- - `fhirpath`: a FHIRPath expression evaluated against the incoming request Bundle.
63
- Met when the expression evaluates to a single truthy value.
64
-
65
- A Bundle may also contain tokens of the form `{{fhirpath}}`, e.g.,
66
- `{{Bundle.entry.first().resource.id}}`. Inferno replaces each token in the returned
67
- Bundle with the result of evaluating the FHIRPath expression against the incoming
68
- request Bundle.
69
- )
46
+ description: DaVinciPASTestKit.ms_responses_input_description('$submit')
70
47
  input :ms_inquire_responses,
71
48
  title: 'Must Support $inquire Response Bundles',
72
49
  type: 'textarea',
73
50
  optional: true,
74
- description: %(
75
- An optional JSON value specifying response Bundles for Inferno to return when
76
- responding to $inquire requests during must support testing. Provide a single entry
77
- or a list of entries, where each entry is either a FHIR Bundle or a wrapper object
78
- of the form `{"criteria": {...}, "bundle": {...}}` pairing a FHIR Bundle with the
79
- selection criteria that a request must meet for that Bundle to be returned.
80
-
81
- For each request, Inferno will respond with the Bundle of the first entry whose
82
- criteria are all met. An entry with no criteria (including a bare Bundle) matches
83
- any request, and an entry with multiple criteria must meet all of them. If no entry
84
- matches, or none are provided, Inferno will generate a default response. Supported
85
- `criteria` keys:
86
-
87
- - `requestRange`: a string of comma-separated request numbers or ranges, e.g.,
88
- `"1-2,4"`. Met when the number of $inquire requests received during this test,
89
- counting this one, is among the listed values.
90
- - `fhirpath`: a FHIRPath expression evaluated against the incoming request Bundle.
91
- Met when the expression evaluates to a single truthy value.
92
-
93
- A Bundle may also contain tokens of the form `{{fhirpath}}`, e.g.,
94
- `{{Bundle.entry.first().resource.id}}`. Inferno replaces each token in the returned
95
- Bundle with the result of evaluating the FHIRPath expression against the incoming
96
- request Bundle.
97
- )
51
+ description: DaVinciPASTestKit.ms_responses_input_description('$inquire')
98
52
  config options: { accepts_multiple_requests: true }
99
53
  output :confirmation_url
100
54
 
@@ -7,4 +7,33 @@ module DaVinciPASTestKit
7
7
  INPUT_SESSION_URL_PATH_LOCKED =
8
8
  'The additional path used to create session-specific endpoints. Run the ' \
9
9
  '**1** Client Registration group to configure this input.'
10
+
11
+ # Shared documentation for the must support response inputs, which differ only
12
+ # in the operation whose responses they configure ('$submit' or '$inquire').
13
+ def self.ms_responses_input_description(operation)
14
+ <<~DESCRIPTION
15
+ An optional JSON value specifying response Bundles for Inferno to return when
16
+ responding to #{operation} requests during must support testing. Provide a single entry
17
+ or a list of entries, where each entry is either a FHIR Bundle or a wrapper object
18
+ of the form `{"criteria": {...}, "bundle": {...}}` pairing a FHIR Bundle with the
19
+ selection criteria that a request must meet for that Bundle to be returned.
20
+
21
+ For each request, Inferno will respond with the Bundle of the first entry whose
22
+ criteria are all met. An entry with no criteria (including a bare Bundle) matches
23
+ any request, and an entry with multiple criteria must meet all of them. If no entry
24
+ matches, or none are provided, Inferno will generate a default response. Supported
25
+ `criteria` keys:
26
+
27
+ - `requestRange`: a string of comma-separated request numbers or ranges, e.g.,
28
+ `"1-2,4"`. Met when the number of #{operation} requests received during this test,
29
+ counting this one, is among the listed values.
30
+ - `fhirpath`: a FHIRPath expression evaluated against the incoming request Bundle.
31
+ Met when the expression evaluates to a single truthy value.
32
+
33
+ A Bundle may also contain tokens of the form `{{fhirpath}}`, e.g.,
34
+ `{{Bundle.entry.first().resource.id}}`. Inferno replaces each token in the returned
35
+ Bundle with the result of evaluating the FHIRPath expression against the incoming
36
+ request Bundle.
37
+ DESCRIPTION
38
+ end
10
39
  end
@@ -165,14 +165,16 @@ module DaVinciPASTestKit
165
165
  # match the incoming request, extracts its response Bundle (unwrapping it when the
166
166
  # candidate pairs the Bundle with criteria), and replaces {{fhirpath}} tokens with
167
167
  # values from the request. Returns nil, causing Inferno to generate a default
168
- # response, if no candidates are provided or none match.
168
+ # response, if no candidates are provided or none match. Problems with the
169
+ # tester-provided input or the FHIRPath service also result in nil, with a warning
170
+ # on the waiting test so that the tester can see what went wrong.
169
171
  def select_must_support_response(req_bundle)
170
- candidates = UserInputResponse.response_candidates(result, operation)
172
+ candidates = UserInputResponse.response_candidates(test, operation, result)
171
173
  return if candidates.blank?
172
174
 
173
175
  operation_url_suffix = "$#{operation}"
174
176
  request_number = count_previous_successful_requests(operation_url_suffix) + 1
175
- selected_index = candidates.index { |candidate| include_entity?(candidate, req_bundle, operation_url_suffix) }
177
+ selected_index = candidates.index { |candidate| include_entity?(candidate, req_bundle, request_number) }
176
178
 
177
179
  if selected_index.nil?
178
180
  Inferno::Application['logger'].info(
@@ -187,16 +189,30 @@ module DaVinciPASTestKit
187
189
  "for #{operation_url_suffix} request ##{request_number}."
188
190
  )
189
191
  replace_tokens(entity_bundle(candidates[selected_index]), req_bundle)
192
+ rescue UserInputResponse::InvalidInputError, FhirpathUtils::FhirpathServiceError => e
193
+ add_result_warning(
194
+ "Unable to select a tester-provided response, so Inferno will generate a default response. #{e.message}"
195
+ )
196
+ nil
190
197
  end
191
198
 
192
- # Round-trips the selected bundle through the FHIR model to normalize it after
193
- # token replacement. Falls back to the replaced string if it no longer parses,
194
- # e.g., when a replaced value breaks the JSON structure.
199
+ # Replaces {{fhirpath}} tokens using values from the incoming request, round-tripping
200
+ # the result through the FHIR model to normalize it. If a replaced value breaks the
201
+ # JSON structure, the result cannot be returned as a FHIR response, so nil is returned
202
+ # with a warning on the waiting test and Inferno generates a default response.
195
203
  def replace_tokens(bundle_hash, req_bundle)
196
- replaced = replace_tokens_in_string(bundle_hash.to_json, req_bundle)
204
+ bundle_json = bundle_hash.to_json
205
+ replaced = replace_tokens_in_string(bundle_json, req_bundle)
206
+ return bundle_json if replaced.equal?(bundle_json)
207
+
197
208
  FHIR.from_contents(replaced)&.to_json || replaced
198
209
  rescue JSON::ParserError
199
- replaced
210
+ add_result_warning(
211
+ 'Unable to use the selected tester-provided response, so Inferno will generate a default response. ' \
212
+ 'The response is not valid JSON after {{fhirpath}} token replacement, for example because a token ' \
213
+ 'value contains a double quote.'
214
+ )
215
+ nil
200
216
  end
201
217
 
202
218
  def handle_missing_required_elements(claim_entry, response)
@@ -255,7 +271,7 @@ module DaVinciPASTestKit
255
271
  end
256
272
 
257
273
  def operation
258
- request.url&.split('$')&.last
274
+ request.path.split('$').last
259
275
  end
260
276
 
261
277
  def start_notification_job(response_bundle_json, decision, generated_claim_response_uuid)
@@ -1,5 +1,9 @@
1
1
  module DaVinciPASTestKit
2
2
  module UserInputResponse
3
+ # Raised when a tester-provided response input is present but cannot be used. The
4
+ # message explains why in terms the tester can act on.
5
+ class InvalidInputError < StandardError; end
6
+
3
7
  def self.included(klass)
4
8
  klass.extend ClassMethods
5
9
  end
@@ -24,17 +28,32 @@ module DaVinciPASTestKit
24
28
  # JSON array of entries, where each entry is either a bare FHIR Bundle or a
25
29
  # wrapper object holding the response Bundle under "bundle" alongside optional
26
30
  # selection "criteria".
27
- # Returns nil if the input is not present, not parseable, or malformed.
28
- def self.response_candidates(result, operation)
31
+ # Returns nil if the input has no value and raises InvalidInputError if the value
32
+ # is present but unusable. The configurable (the waiting test) supplies the input
33
+ # title so that the error names the input as the tester sees it.
34
+ def self.response_candidates(configurable, operation, result)
29
35
  input_name = operation == 'submit' ? 'ms_submit_responses' : 'ms_inquire_responses'
30
- input_value = JSON.parse(result.input_json)&.find { |i| i['name'] == input_name }&.dig('value')
36
+ input_value = read_input(result, input_name)
31
37
  return unless input_value.present?
32
38
 
33
39
  candidates = JSON.parse(input_value)
34
40
  candidates = [candidates] unless candidates.is_a?(Array)
35
- candidates if candidates.all? { |candidate| valid_candidate?(candidate) }
41
+ invalid_index = candidates.index { |candidate| !valid_candidate?(candidate) }
42
+ if invalid_index.present?
43
+ raise InvalidInputError,
44
+ "Entry #{invalid_index + 1} of the '#{input_title(configurable, input_name)}' input is neither " \
45
+ 'a FHIR Bundle nor a wrapper object with a FHIR Bundle in the "bundle" key.'
46
+ end
47
+
48
+ candidates
36
49
  rescue JSON::ParserError
37
- nil
50
+ raise InvalidInputError, "The '#{input_title(configurable, input_name)}' input is not valid JSON."
51
+ end
52
+
53
+ # Title of an input as shown to the tester in the Inferno UI, falling back to its name
54
+ def self.input_title(configurable, input_key)
55
+ input = configurable.config.inputs[input_key.to_sym]
56
+ (input&.title || input&.name || input_key).to_s
38
57
  end
39
58
 
40
59
  def self.valid_candidate?(candidate)
@@ -48,7 +67,7 @@ module DaVinciPASTestKit
48
67
  end
49
68
 
50
69
  def input_title(input_key)
51
- config.inputs[input_key]&.title || config.inputs[input_key]&.name
70
+ UserInputResponse.input_title(self, input_key)
52
71
  end
53
72
 
54
73
  module ClassMethods
@@ -98,7 +98,7 @@ module DaVinciPASTestKit
98
98
  exclude_message do |message|
99
99
  # Messages expected of the form `<ResourceType>: <FHIRPath>: <message>`
100
100
  # We strip `<ResourceType>: <FHIRPath>: ` for the sake of matching
101
- SUPPRESSED_MESSAGES.match?(message.message.sub(/\A\S+: \S+: /, ''))
101
+ V201_SUPPRESSED_MESSAGES.match?(message.message.sub(/\A\S+: \S+: /, ''))
102
102
  end
103
103
 
104
104
  validation_context do
@@ -87,7 +87,7 @@ module DaVinciPASTestKit
87
87
  exclude_message do |message|
88
88
  # Messages expected of the form `<ResourceType>: <FHIRPath>: <message>`
89
89
  # We strip `<ResourceType>: <FHIRPath>: ` for the sake of matching
90
- SUPPRESSED_MESSAGES.match?(message.message.sub(/\A\S+: \S+: /, ''))
90
+ V221_SUPPRESSED_MESSAGES.match?(message.message.sub(/\A\S+: \S+: /, ''))
91
91
  end
92
92
  end
93
93
 
@@ -3,6 +3,9 @@ module DaVinciPASTestKit
3
3
  # the FHIRPath evaluation service and for replacing {{fhirpath}} tokens in
4
4
  # serialized resources with values pulled from a request.
5
5
  module FhirpathUtils
6
+ # Raised when the FHIRPath service cannot be reached or does not return a usable
7
+ # result. Messages name the query and end with the service's response or the
8
+ # connection error so that they can be shown to the tester as-is.
6
9
  class FhirpathServiceError < StandardError; end
7
10
 
8
11
  def fhirpath_evaluator
@@ -14,8 +17,10 @@ module DaVinciPASTestKit
14
17
  return fhirpath_result if fhirpath_result.status.to_s.start_with?('2')
15
18
 
16
19
  raise FhirpathServiceError,
17
- "FHIRPath service returned #{fhirpath_result.status} for query '#{query}' " \
18
- "on resource #{body}: #{fhirpath_result.body}"
20
+ "The FHIRPath service returned HTTP #{fhirpath_result.status} for query '#{query}': " \
21
+ "#{fhirpath_result.body}"
22
+ rescue Faraday::Error => e
23
+ raise FhirpathServiceError, "The FHIRPath service request for query '#{query}' failed: #{e.message}"
19
24
  end
20
25
 
21
26
  def interpret_fhirpath_result_as_boolean(fhirpath_result)
@@ -45,11 +50,16 @@ module DaVinciPASTestKit
45
50
  end
46
51
 
47
52
  def calculate_expression_string_value(request, expression)
48
- JSON.parse(execute_fhirpath(request, expression).body)
53
+ fhirpath_result = execute_fhirpath(request, expression)
54
+ JSON.parse(fhirpath_result.body)
49
55
  .map { |result| result['element'] }
50
56
  .map { |element| element.is_a?(Array) || element.is_a?(Hash) ? nil : element }
51
57
  .compact
52
58
  .join(',')
59
+ rescue JSON::ParserError
60
+ raise FhirpathServiceError,
61
+ "The FHIRPath service returned an unparseable response for query '#{expression}': " \
62
+ "#{fhirpath_result.body}"
53
63
  end
54
64
  end
55
65
  end
@@ -16,14 +16,17 @@
16
16
  :must_supports:
17
17
  :extensions:
18
18
  - :id: Patient.extension:race
19
+ :slice_name: race
19
20
  :path: extension
20
21
  :url: http://hl7.org/fhir/us/core/StructureDefinition/us-core-race
21
22
  :modifier_extension: false
22
23
  - :id: Patient.extension:ethnicity
24
+ :slice_name: ethnicity
23
25
  :path: extension
24
26
  :url: http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity
25
27
  :modifier_extension: false
26
28
  - :id: Patient.extension:birthsex
29
+ :slice_name: birthsex
27
30
  :path: extension
28
31
  :url: http://hl7.org/fhir/us/core/StructureDefinition/us-core-birthsex
29
32
  :modifier_extension: false
@@ -59,6 +62,7 @@
59
62
  - :path: address.period
60
63
  - :path: communication
61
64
  - :path: communication.language
65
+ :recursive_elements: []
62
66
  :mandatory_elements:
63
67
  - Patient.identifier
64
68
  - Patient.identifier.system
@@ -32,58 +32,72 @@
32
32
  :must_supports:
33
33
  :extensions:
34
34
  - :id: Claim.extension:levelOfServiceType
35
+ :slice_name: levelOfServiceType
35
36
  :path: extension
36
37
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-levelOfServiceCode
37
38
  :modifier_extension: false
38
39
  - :id: Claim.extension:certificationType
40
+ :slice_name: certificationType
39
41
  :path: extension
40
42
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-certificationType
41
43
  :modifier_extension: false
42
44
  - :id: Claim.careTeam.extension:careTeamClaimScope
45
+ :slice_name: careTeamClaimScope
43
46
  :path: careTeam.extension
44
47
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-careTeamClaimScope
45
48
  :modifier_extension: false
46
49
  - :id: Claim.careTeam:OverallClaimMember.extension:careTeamClaimScope
50
+ :slice_name: careTeamClaimScope
47
51
  :path: careTeam.extension
48
52
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-careTeamClaimScope
49
53
  :modifier_extension: false
50
54
  - :id: Claim.careTeam:ItemClaimMember.extension:careTeamClaimScope
55
+ :slice_name: careTeamClaimScope
51
56
  :path: careTeam.extension
52
57
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-careTeamClaimScope
53
58
  :modifier_extension: false
54
59
  - :id: Claim.item.extension:itemTraceNumber
60
+ :slice_name: itemTraceNumber
55
61
  :path: item.extension
56
62
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemTraceNumber
57
63
  :modifier_extension: false
58
64
  - :id: Claim.item.extension:authorizationNumber
65
+ :slice_name: authorizationNumber
59
66
  :path: item.extension
60
67
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-authorizationNumber
61
68
  :modifier_extension: false
62
69
  - :id: Claim.item.extension:administrationReferenceNumber
70
+ :slice_name: administrationReferenceNumber
63
71
  :path: item.extension
64
72
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-administrationReferenceNumber
65
73
  :modifier_extension: false
66
74
  - :id: Claim.item.extension:requestType
75
+ :slice_name: requestType
67
76
  :path: item.extension
68
77
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-serviceItemRequestType
69
78
  :modifier_extension: false
70
79
  - :id: Claim.item.extension:certificationType
80
+ :slice_name: certificationType
71
81
  :path: item.extension
72
82
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-certificationType
73
83
  :modifier_extension: false
74
84
  - :id: Claim.item.extension:certIssueDate
85
+ :slice_name: certIssueDate
75
86
  :path: item.extension
76
87
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemCertificationIssueDate
77
88
  :modifier_extension: false
78
89
  - :id: Claim.item.extension:certExpirationDate
90
+ :slice_name: certExpirationDate
79
91
  :path: item.extension
80
92
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemCertificationExpirationDate
81
93
  :modifier_extension: false
82
94
  - :id: Claim.item.extension:certEffectiveDate
95
+ :slice_name: certEffectiveDate
83
96
  :path: item.extension
84
97
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemCertificationEffectiveDate
85
98
  :modifier_extension: false
86
99
  - :id: Claim.item.extension:reviewActionCode
100
+ :slice_name: reviewActionCode
87
101
  :path: item.extension
88
102
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-reviewActionCode
89
103
  :modifier_extension: false
@@ -177,6 +191,7 @@
177
191
  - :path: item.serviced[x]
178
192
  - :path: item.location[x]
179
193
  - :path: item.quantity
194
+ :recursive_elements: []
180
195
  :mandatory_elements:
181
196
  - Claim.status
182
197
  - Claim.type
@@ -33,66 +33,82 @@
33
33
  :must_supports:
34
34
  :extensions:
35
35
  - :id: Claim.extension:levelOfServiceType
36
+ :slice_name: levelOfServiceType
36
37
  :path: extension
37
38
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-levelOfServiceCode
38
39
  :modifier_extension: false
39
40
  - :id: Claim.extension:encounter
41
+ :slice_name: encounter
40
42
  :path: extension
41
43
  :url: http://hl7.org/fhir/5.0/StructureDefinition/extension-Claim.encounter
42
44
  :modifier_extension: false
43
45
  - :id: Claim.careTeam.extension:careTeamClaimScope
46
+ :slice_name: careTeamClaimScope
44
47
  :path: careTeam.extension
45
48
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-careTeamClaimScope
46
49
  :modifier_extension: false
47
50
  - :id: Claim.careTeam:OverallClaimMember.extension:careTeamClaimScope
51
+ :slice_name: careTeamClaimScope
48
52
  :path: careTeam.extension
49
53
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-careTeamClaimScope
50
54
  :modifier_extension: false
51
55
  - :id: Claim.careTeam:ItemClaimMember.extension:careTeamClaimScope
56
+ :slice_name: careTeamClaimScope
52
57
  :path: careTeam.extension
53
58
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-careTeamClaimScope
54
59
  :modifier_extension: false
55
60
  - :id: Claim.diagnosis.extension:recordedDate
61
+ :slice_name: recordedDate
56
62
  :path: diagnosis.extension
57
63
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-diagnosisRecordedDate
58
64
  :modifier_extension: false
59
65
  - :id: Claim.item.extension:itemTraceNumber
66
+ :slice_name: itemTraceNumber
60
67
  :path: item.extension
61
68
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemTraceNumber
62
69
  :modifier_extension: false
63
70
  - :id: Claim.item.extension:authorizationNumber
71
+ :slice_name: authorizationNumber
64
72
  :path: item.extension
65
73
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-authorizationNumber
66
74
  :modifier_extension: false
67
75
  - :id: Claim.item.extension:administrationReferenceNumber
76
+ :slice_name: administrationReferenceNumber
68
77
  :path: item.extension
69
78
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-administrationReferenceNumber
70
79
  :modifier_extension: false
71
80
  - :id: Claim.item.extension:requestType
81
+ :slice_name: requestType
72
82
  :path: item.extension
73
83
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-serviceItemRequestType
74
84
  :modifier_extension: false
75
85
  - :id: Claim.item.extension:certificationType
86
+ :slice_name: certificationType
76
87
  :path: item.extension
77
88
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-certificationType
78
89
  :modifier_extension: false
79
90
  - :id: Claim.item.extension:epsdtIndicator
91
+ :slice_name: epsdtIndicator
80
92
  :path: item.extension
81
93
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-epsdtIndicator
82
94
  :modifier_extension: false
83
95
  - :id: Claim.item.extension:nursingHomeResidentialStatus
96
+ :slice_name: nursingHomeResidentialStatus
84
97
  :path: item.extension
85
98
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-nursingHomeResidentialStatus
86
99
  :modifier_extension: false
87
100
  - :id: Claim.item.extension:nursingHomeLevelOfCare
101
+ :slice_name: nursingHomeLevelOfCare
88
102
  :path: item.extension
89
103
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-nursingHomeLevelOfCare
90
104
  :modifier_extension: false
91
105
  - :id: Claim.item.extension:revenueUnitRateLimit
106
+ :slice_name: revenueUnitRateLimit
92
107
  :path: item.extension
93
108
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-revenueUnitRateLimit
94
109
  :modifier_extension: false
95
110
  - :id: Claim.item.extension:requestedService
111
+ :slice_name: requestedService
96
112
  :path: item.extension
97
113
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-requestedService
98
114
  :modifier_extension: false
@@ -211,6 +227,7 @@
211
227
  - :path: item.location[x]
212
228
  - :path: item.quantity
213
229
  - :path: item.unitPrice
230
+ :recursive_elements: []
214
231
  :mandatory_elements:
215
232
  - Claim.extension.url
216
233
  - Claim.extension.value[x]
@@ -17,54 +17,67 @@
17
17
  :must_supports:
18
18
  :extensions:
19
19
  - :id: ClaimResponse.item.extension:itemTraceNumber
20
+ :slice_name: itemTraceNumber
20
21
  :path: item.extension
21
22
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemTraceNumber
22
23
  :modifier_extension: false
23
24
  - :id: ClaimResponse.item.extension:preAuthIssueDate
25
+ :slice_name: preAuthIssueDate
24
26
  :path: item.extension
25
27
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemPreAuthIssueDate
26
28
  :modifier_extension: false
27
29
  - :id: ClaimResponse.item.extension:preAuthPeriod
30
+ :slice_name: preAuthPeriod
28
31
  :path: item.extension
29
32
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemPreAuthPeriod
30
33
  :modifier_extension: false
31
34
  - :id: ClaimResponse.item.extension:previousAuthorizationNumber
35
+ :slice_name: previousAuthorizationNumber
32
36
  :path: item.extension
33
37
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-authorizationNumber
34
38
  :modifier_extension: false
35
39
  - :id: ClaimResponse.item.extension:administrationReferenceNumber
40
+ :slice_name: administrationReferenceNumber
36
41
  :path: item.extension
37
42
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-administrationReferenceNumber
38
43
  :modifier_extension: false
39
44
  - :id: ClaimResponse.item.extension:requestedServiceDate
45
+ :slice_name: requestedServiceDate
40
46
  :path: item.extension
41
47
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemRequestedServiceDate
42
48
  :modifier_extension: false
43
49
  - :id: ClaimResponse.item.extension:authorizedItemDetail
50
+ :slice_name: authorizedItemDetail
44
51
  :path: item.extension
45
52
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemAuthorizedDetail
46
53
  :modifier_extension: false
47
54
  - :id: ClaimResponse.item.extension:authorizedProvider
55
+ :slice_name: authorizedProvider
48
56
  :path: item.extension
49
57
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemAuthorizedProvider
50
58
  :modifier_extension: false
51
59
  - :id: ClaimResponse.item.extension:communicatedDiagnosis
60
+ :slice_name: communicatedDiagnosis
52
61
  :path: item.extension
53
62
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-communicatedDiagnosis
54
63
  :modifier_extension: false
55
64
  - :id: ClaimResponse.item.adjudication.extension:reviewAction
65
+ :slice_name: reviewAction
56
66
  :path: item.adjudication.extension
57
67
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-reviewAction
58
68
  :modifier_extension: false
59
69
  - :id: ClaimResponse.error.extension:followupAction
70
+ :slice_name: followupAction
60
71
  :path: error.extension
61
72
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-errorFollowupAction
62
73
  :modifier_extension: false
63
74
  - :id: ClaimResponse.error.extension:errorElement
75
+ :slice_name: errorElement
64
76
  :path: error.extension
65
77
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-errorElement
66
78
  :modifier_extension: false
67
79
  - :id: ClaimResponse.error.extension:errorPath
80
+ :slice_name: errorPath
68
81
  :path: error.extension
69
82
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-errorPath
70
83
  :modifier_extension: false
@@ -97,6 +110,8 @@
97
110
  - :path: item.adjudication
98
111
  - :path: error
99
112
  - :path: error.code
113
+ :recursive_elements:
114
+ - adjudication
100
115
  :mandatory_elements:
101
116
  - ClaimResponse.status
102
117
  - ClaimResponse.type
@@ -17,54 +17,67 @@
17
17
  :must_supports:
18
18
  :extensions:
19
19
  - :id: ClaimResponse.item.extension:itemTraceNumber
20
+ :slice_name: itemTraceNumber
20
21
  :path: item.extension
21
22
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemTraceNumber
22
23
  :modifier_extension: false
23
24
  - :id: ClaimResponse.item.extension:preAuthIssueDate
25
+ :slice_name: preAuthIssueDate
24
26
  :path: item.extension
25
27
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemPreAuthIssueDate
26
28
  :modifier_extension: false
27
29
  - :id: ClaimResponse.item.extension:preAuthPeriod
30
+ :slice_name: preAuthPeriod
28
31
  :path: item.extension
29
32
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemPreAuthPeriod
30
33
  :modifier_extension: false
31
34
  - :id: ClaimResponse.item.extension:previousAuthorizationNumber
35
+ :slice_name: previousAuthorizationNumber
32
36
  :path: item.extension
33
37
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-authorizationNumber
34
38
  :modifier_extension: false
35
39
  - :id: ClaimResponse.item.extension:administrationReferenceNumber
40
+ :slice_name: administrationReferenceNumber
36
41
  :path: item.extension
37
42
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-administrationReferenceNumber
38
43
  :modifier_extension: false
39
44
  - :id: ClaimResponse.item.extension:requestedServiceDate
45
+ :slice_name: requestedServiceDate
40
46
  :path: item.extension
41
47
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemRequestedServiceDate
42
48
  :modifier_extension: false
43
49
  - :id: ClaimResponse.item.extension:authorizedItemDetail
50
+ :slice_name: authorizedItemDetail
44
51
  :path: item.extension
45
52
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemAuthorizedDetail
46
53
  :modifier_extension: false
47
54
  - :id: ClaimResponse.item.extension:authorizedProvider
55
+ :slice_name: authorizedProvider
48
56
  :path: item.extension
49
57
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemAuthorizedProvider
50
58
  :modifier_extension: false
51
59
  - :id: ClaimResponse.item.extension:communicatedDiagnosis
60
+ :slice_name: communicatedDiagnosis
52
61
  :path: item.extension
53
62
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-communicatedDiagnosis
54
63
  :modifier_extension: false
55
64
  - :id: ClaimResponse.item.adjudication.extension:reviewAction
65
+ :slice_name: reviewAction
56
66
  :path: item.adjudication.extension
57
67
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-reviewAction
58
68
  :modifier_extension: false
59
69
  - :id: ClaimResponse.error.extension:followupAction
70
+ :slice_name: followupAction
60
71
  :path: error.extension
61
72
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-errorFollowupAction
62
73
  :modifier_extension: false
63
74
  - :id: ClaimResponse.error.extension:errorElement
75
+ :slice_name: errorElement
64
76
  :path: error.extension
65
77
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-errorElement
66
78
  :modifier_extension: false
67
79
  - :id: ClaimResponse.error.extension:errorPath
80
+ :slice_name: errorPath
68
81
  :path: error.extension
69
82
  :url: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-errorPath
70
83
  :modifier_extension: false
@@ -103,6 +116,8 @@
103
116
  - http://hl7.org/fhir/us/davinci-pas/StructureDefinition/profile-communicationrequest
104
117
  - :path: error
105
118
  - :path: error.code
119
+ :recursive_elements:
120
+ - adjudication
106
121
  :mandatory_elements:
107
122
  - ClaimResponse.status
108
123
  - ClaimResponse.type