inferno_core 0.4.20 → 0.4.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/inferno/dsl/fhir_client.rb +43 -5
- data/lib/inferno/dsl/fhir_validation.rb +51 -6
- data/lib/inferno/exceptions.rb +13 -0
- data/lib/inferno/public/bundle.js +12 -12
- data/lib/inferno/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 13f75c775423384dd5bf4a2b13081bc05a155155fca9a6bcea1986d2baf09b15
|
4
|
+
data.tar.gz: 7b6c586b121fad54caa57fb5ae8d8c7300467b543ece25c4222c21cc65ac83c7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7f0ab91414e4554a430972dd25543339cd39245c0d154dcc42d0a623c83b4aeaccf32709d08074abd4dcae07cf3deb75144a2db3cd3af548a37ddc552b0df909
|
7
|
+
data.tar.gz: 2f328c92cb3d66853eccde4aee267be6e8e668b778f75e1d278a3b5d4ba86840e4f0e260fbc5bf941017ee8bde1cd20699a53153cd9e26ee8e9bee8fa730ab7c
|
@@ -60,26 +60,64 @@ module Inferno
|
|
60
60
|
@fhir_clients ||= {}
|
61
61
|
end
|
62
62
|
|
63
|
+
# Wrapper for checking if parameter contents are primitive
|
64
|
+
#
|
65
|
+
# @param param [FHIR::Parameters::Parameter] Parameter to be checked
|
66
|
+
# @private
|
67
|
+
def primitive_parameter?(param)
|
68
|
+
param_val = param.to_hash.except('name')
|
69
|
+
param_val.any? { |datatype, param_value| FHIR.primitive?(datatype: datatype[5..], value: param_value) }
|
70
|
+
end
|
71
|
+
|
72
|
+
# Converts a list of FHIR Parameters into a query string for GET requests
|
73
|
+
#
|
74
|
+
# @param body [FHIR::Parameters] Must all be primitive if making GET request
|
75
|
+
# @private
|
76
|
+
def body_to_path(body)
|
77
|
+
query_hashes = body.parameter.map do |param|
|
78
|
+
if primitive_parameter?(param)
|
79
|
+
{ param.name => param.to_hash.except('name').values[0] }
|
80
|
+
else
|
81
|
+
Inferno::Application[:logger].error "Cannot use GET request with non-primitive datatype #{param.name}"
|
82
|
+
raise ArgumentError, "Cannot use GET request with non-primitive datatype #{param.name}"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
query_hashes.map(&:to_query).join('&')
|
86
|
+
end
|
87
|
+
|
63
88
|
# Perform a FHIR operation
|
64
89
|
#
|
65
90
|
# @note This is a placeholder method until the FHIR::Client supports
|
66
|
-
# general operations
|
91
|
+
# general operations. Note that while both POST and GET methods are allowed,
|
92
|
+
# GET is only allowed when the operation does not affect the server's state.
|
93
|
+
# See https://build.fhir.org/operationdefinition-definitions.html#OperationDefinition.affectsState
|
94
|
+
#
|
95
|
+
# @note Currently does not allow for repeated parameters if using GET
|
67
96
|
#
|
68
97
|
# @param path [String]
|
69
|
-
# @param body [FHIR::Parameters]
|
98
|
+
# @param body [FHIR::Parameters] Must all be primitive if making GET request
|
70
99
|
# @param client [Symbol]
|
71
100
|
# @param name [Symbol] Name for this request to allow it to be used by
|
72
101
|
# other tests
|
73
102
|
# @param headers [Hash] custom headers for this operation
|
103
|
+
# @param operation_method [Symbol] indicates which request type to use for the operation
|
74
104
|
# @return [Inferno::Entities::Request]
|
75
|
-
def fhir_operation(path, body: nil, client: :default, name: nil, headers: {})
|
105
|
+
def fhir_operation(path, body: nil, client: :default, name: nil, headers: {}, operation_method: :post)
|
76
106
|
store_request_and_refresh_token(fhir_client(client), name) do
|
77
107
|
tcp_exception_handler do
|
78
108
|
operation_headers = fhir_client(client).fhir_headers
|
79
109
|
operation_headers.merge!('Content-Type' => 'application/fhir+json') if body.present?
|
80
110
|
operation_headers.merge!(headers) if headers.present?
|
81
|
-
|
82
|
-
|
111
|
+
case operation_method
|
112
|
+
when :post
|
113
|
+
fhir_client(client).send(:post, path, body, operation_headers)
|
114
|
+
when :get
|
115
|
+
path = "#{path}?#{body_to_path(body)}" if body.present?
|
116
|
+
fhir_client(client).send(:get, path, operation_headers)
|
117
|
+
else
|
118
|
+
Inferno::Application[:logger].error "Cannot perform #{operation_method} requests, use GET or POST"
|
119
|
+
raise ArgumentError, "Cannot perform #{operation_method} requests, use GET or POST"
|
120
|
+
end
|
83
121
|
end
|
84
122
|
end
|
85
123
|
end
|
@@ -116,17 +116,34 @@ module Inferno
|
|
116
116
|
def resource_is_valid?(resource, profile_url, runnable)
|
117
117
|
profile_url ||= FHIR::Definitions.resource_definition(resource.resourceType).url
|
118
118
|
|
119
|
-
|
119
|
+
begin
|
120
|
+
response = call_validator(resource, profile_url)
|
121
|
+
rescue StandardError => e
|
122
|
+
# This could be a complete failure to connect (validator isn't running)
|
123
|
+
# or a timeout (validator took too long to respond).
|
124
|
+
runnable.add_message('error', e.message)
|
125
|
+
raise Inferno::Exceptions::ErrorInValidatorException, "Unable to connect to validator at #{url}."
|
126
|
+
end
|
127
|
+
outcome = operation_outcome_from_validator_response(response.body, runnable)
|
120
128
|
|
121
|
-
message_hashes = outcome
|
129
|
+
message_hashes = message_hashes_from_outcome(outcome, resource, profile_url)
|
122
130
|
|
123
|
-
message_hashes
|
131
|
+
message_hashes
|
132
|
+
.each { |message_hash| runnable.add_message(message_hash[:type], message_hash[:message]) }
|
124
133
|
|
125
|
-
|
134
|
+
unless response.status == 200
|
135
|
+
raise Inferno::Exceptions::ErrorInValidatorException,
|
136
|
+
'Error occurred in the validator. Review Messages tab or validator service logs for more information.'
|
137
|
+
end
|
126
138
|
|
127
139
|
message_hashes
|
128
|
-
.each { |message_hash| runnable.add_message(message_hash[:type], message_hash[:message]) }
|
129
140
|
.none? { |message_hash| message_hash[:type] == 'error' }
|
141
|
+
rescue Inferno::Exceptions::ErrorInValidatorException
|
142
|
+
raise
|
143
|
+
rescue StandardError => e
|
144
|
+
runnable.add_message('error', e.message)
|
145
|
+
raise Inferno::Exceptions::ErrorInValidatorException,
|
146
|
+
'Error occurred in the validator. Review Messages tab or validator service logs for more information.'
|
130
147
|
end
|
131
148
|
|
132
149
|
# @private
|
@@ -134,6 +151,17 @@ module Inferno
|
|
134
151
|
message_hashes.reject! { |message| exclude_message.call(Entities::Message.new(message)) } if exclude_message
|
135
152
|
end
|
136
153
|
|
154
|
+
# @private
|
155
|
+
def message_hashes_from_outcome(outcome, resource, profile_url)
|
156
|
+
message_hashes = outcome.issue&.map { |issue| message_hash_from_issue(issue, resource) } || []
|
157
|
+
|
158
|
+
message_hashes.concat(additional_validation_messages(resource, profile_url))
|
159
|
+
|
160
|
+
filter_messages(message_hashes)
|
161
|
+
|
162
|
+
message_hashes
|
163
|
+
end
|
164
|
+
|
137
165
|
# @private
|
138
166
|
def message_hash_from_issue(issue, resource)
|
139
167
|
{
|
@@ -173,10 +201,27 @@ module Inferno
|
|
173
201
|
# @param profile_url [String]
|
174
202
|
# @return [String] the body of the validation response
|
175
203
|
def validate(resource, profile_url)
|
204
|
+
call_validator(resource, profile_url).body
|
205
|
+
end
|
206
|
+
|
207
|
+
# @private
|
208
|
+
def call_validator(resource, profile_url)
|
176
209
|
Faraday.new(
|
177
210
|
url,
|
178
211
|
params: { profile: profile_url }
|
179
|
-
).post('validate', resource.source_contents)
|
212
|
+
).post('validate', resource.source_contents)
|
213
|
+
end
|
214
|
+
|
215
|
+
# @private
|
216
|
+
def operation_outcome_from_validator_response(response, runnable)
|
217
|
+
if response.start_with? '{'
|
218
|
+
FHIR::OperationOutcome.new(JSON.parse(response))
|
219
|
+
else
|
220
|
+
runnable.add_message('error', "Validator Response:\n#{response}")
|
221
|
+
raise Inferno::Exceptions::ErrorInValidatorException,
|
222
|
+
'Validator response was an unexpected format. '\
|
223
|
+
'Review Messages tab or validator service logs for more information.'
|
224
|
+
end
|
180
225
|
end
|
181
226
|
end
|
182
227
|
|
data/lib/inferno/exceptions.rb
CHANGED
@@ -39,6 +39,19 @@ module Inferno
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
+
# ErrorInValidatorException is used when an exception occurred in
|
43
|
+
# calling the validator service, for example a connection timeout
|
44
|
+
# or an unexpected response format.
|
45
|
+
# Note: This class extends TestResultException instead of RuntimeError
|
46
|
+
# to bypass printing the stack trace in the UI, since
|
47
|
+
# the stack trace of this exception is not likely be useful.
|
48
|
+
# Instead the message should point to where in the validator an error occurred.
|
49
|
+
class ErrorInValidatorException < TestResultException
|
50
|
+
def result
|
51
|
+
'error'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
42
55
|
class ParentNotLoadedException < RuntimeError
|
43
56
|
def initialize(klass, id)
|
44
57
|
super("No #{klass.name.demodulize} found with id '#{id}'")
|