inferno_core 0.4.22 → 0.4.23

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e753e1e6cd4a9ef5d59e0bf3c8f53338a7149e5c4735f13d3f135fe8266bdf05
4
- data.tar.gz: 7187514e9564bcd45e98ba7fe490b29448a2897293c63b251ac08137c2ba2717
3
+ metadata.gz: abed552b23b62bfad7ded41bdc4c417c15c8c91b13bd1ed48f462fda0de548db
4
+ data.tar.gz: 2600f94107f338fe9477780e8475482cef12b2b0ce374961bc9f506d8d0cef40
5
5
  SHA512:
6
- metadata.gz: 389ba88c3e2954a713d5caf2092445b72c724c7d1f4544939c41f465ad41e8319d1168f4552a66e4b95280d2eb273ce268af56dc3d317a66510378e9e96870c6
7
- data.tar.gz: 2cddf92c61b4f4cc373b86f4b2c028db1ce4f5e5d1da7026b3ec4c6380080a0617ddba5ae32520f2df72bdbceadc5422d15266a52e190f34915f0722264217de
6
+ metadata.gz: 44cff660ebcec30498385684b088f157f447eba86d22baa684d1320a09ea7356be735d9c74ecf9df15d5ebc65a0f7874ed46139d95950aecdc000a6d6290a621
7
+ data.tar.gz: 378b6716dbd35c00731617a19bd854234a997c219718bba67ef9ef473a8cc86517e0a19c6d97fabeb20f7df71f1d4ecd149d8fab183969f5d0866e6b36d4648b
@@ -3,7 +3,7 @@ module Inferno
3
3
  class Services < Thor
4
4
  no_commands do
5
5
  def base_command
6
- 'docker-compose -f docker-compose.background.yml'
6
+ 'docker compose -f docker-compose.background.yml'
7
7
  end
8
8
  end
9
9
 
@@ -0,0 +1,19 @@
1
+ Inferno::Application.boot(:validator) do
2
+ init do
3
+ use :suites
4
+
5
+ # This process should only run once, to start one job per validator,
6
+ # so skipping it on workers will start it only once from the "web" process
7
+ next if Sidekiq.server?
8
+
9
+ Inferno::Repositories::TestSuites.new.all.each do |suite|
10
+ suite.fhir_validators.each do |name, validators|
11
+ validators.each_with_index do |validator, index|
12
+ if validator.is_a? Inferno::DSL::FHIRResourceValidation::Validator
13
+ Inferno::Jobs.perform(Inferno::Jobs::InvokeValidatorSession, suite.id, name.to_s, index)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,18 @@
1
+ Sequel.migration do
2
+ change do
3
+ create_table :tags do
4
+ column :id, String, primary_key: true, null: false, size: 36
5
+ column :name, String, size: 255, null: false
6
+
7
+ index :name, unique: true
8
+ end
9
+
10
+ create_table :requests_tags do
11
+ foreign_key :tags_id, :tags, index: true, type: String, null: false, size: 36, key: [:id]
12
+ foreign_key :requests_id, :requests, index: true, type: Integer, null: false, key: [:index]
13
+
14
+ index [:tags_id, :requests_id], unique: true
15
+ index [:requests_id, :tags_id], unique: true
16
+ end
17
+ end
18
+ end
@@ -4,6 +4,15 @@ Sequel.migration do
4
4
  Integer :version, :default=>0, :null=>false
5
5
  end
6
6
 
7
+ create_table(:tags, :ignore_index_errors=>true) do
8
+ String :id, :size=>36, :null=>false
9
+ String :name, :size=>255, :null=>false
10
+
11
+ primary_key [:id]
12
+
13
+ index [:name], :unique=>true
14
+ end
15
+
7
16
  create_table(:test_sessions) do
8
17
  String :id, :size=>36, :null=>false
9
18
  String :test_suite_id, :size=>255, :null=>false
@@ -121,5 +130,15 @@ Sequel.migration do
121
130
  index [:requests_id]
122
131
  index [:results_id]
123
132
  end
133
+
134
+ create_table(:requests_tags, :ignore_index_errors=>true) do
135
+ foreign_key :tags_id, :tags, :type=>String, :size=>36, :null=>false, :key=>[:id]
136
+ foreign_key :requests_id, :requests, :null=>false, :key=>[:index]
137
+
138
+ index [:requests_id]
139
+ index [:requests_id, :tags_id], :unique=>true
140
+ index [:tags_id]
141
+ index [:tags_id, :requests_id], :unique=>true
142
+ end
124
143
  end
125
144
  end
@@ -101,9 +101,18 @@ module Inferno
101
101
  # other tests
102
102
  # @param headers [Hash] custom headers for this operation
103
103
  # @param operation_method [Symbol] indicates which request type to use for the operation
104
+ # @param tags [Array<String>] a list of tags to assign to the request
104
105
  # @return [Inferno::Entities::Request]
105
- def fhir_operation(path, body: nil, client: :default, name: nil, headers: {}, operation_method: :post)
106
- store_request_and_refresh_token(fhir_client(client), name) do
106
+ def fhir_operation(
107
+ path,
108
+ body: nil,
109
+ client: :default,
110
+ name: nil,
111
+ headers: {},
112
+ operation_method: :post,
113
+ tags: []
114
+ )
115
+ store_request_and_refresh_token(fhir_client(client), name, tags) do
107
116
  tcp_exception_handler do
108
117
  operation_headers = fhir_client(client).fhir_headers
109
118
  operation_headers.merge!('Content-Type' => 'application/fhir+json') if body.present?
@@ -127,9 +136,10 @@ module Inferno
127
136
  # @param client [Symbol]
128
137
  # @param name [Symbol] Name for this request to allow it to be used by
129
138
  # other tests
139
+ # @param tags [Array<String>] a list of tags to assign to the request
130
140
  # @return [Inferno::Entities::Request]
131
- def fhir_get_capability_statement(client: :default, name: nil)
132
- store_request_and_refresh_token(fhir_client(client), name) do
141
+ def fhir_get_capability_statement(client: :default, name: nil, tags: [])
142
+ store_request_and_refresh_token(fhir_client(client), name, tags) do
133
143
  tcp_exception_handler do
134
144
  fhir_client(client).conformance_statement
135
145
  fhir_client(client).reply
@@ -143,9 +153,10 @@ module Inferno
143
153
  # @param client [Symbol]
144
154
  # @param name [Symbol] Name for this request to allow it to be used by
145
155
  # other tests
156
+ # @param tags [Array<String>] a list of tags to assign to the request
146
157
  # @return [Inferno::Entities::Request]
147
- def fhir_create(resource, client: :default, name: nil)
148
- store_request_and_refresh_token(fhir_client(client), name) do
158
+ def fhir_create(resource, client: :default, name: nil, tags: [])
159
+ store_request_and_refresh_token(fhir_client(client), name, tags) do
149
160
  tcp_exception_handler do
150
161
  fhir_client(client).create(resource)
151
162
  end
@@ -159,9 +170,10 @@ module Inferno
159
170
  # @param client [Symbol]
160
171
  # @param name [Symbol] Name for this request to allow it to be used by
161
172
  # other tests
173
+ # @param tags [Array<String>] a list of tags to assign to the request
162
174
  # @return [Inferno::Entities::Request]
163
- def fhir_read(resource_type, id, client: :default, name: nil)
164
- store_request_and_refresh_token(fhir_client(client), name) do
175
+ def fhir_read(resource_type, id, client: :default, name: nil, tags: [])
176
+ store_request_and_refresh_token(fhir_client(client), name, tags) do
165
177
  tcp_exception_handler do
166
178
  fhir_client(client).read(fhir_class_from_resource_type(resource_type), id)
167
179
  end
@@ -176,9 +188,10 @@ module Inferno
176
188
  # @param client [Symbol]
177
189
  # @param name [Symbol] Name for this request to allow it to be used by
178
190
  # other tests
191
+ # @param tags [Array<String>] a list of tags to assign to the request
179
192
  # @return [Inferno::Entities::Request]
180
- def fhir_vread(resource_type, id, version_id, client: :default, name: nil)
181
- store_request_and_refresh_token(fhir_client(client), name) do
193
+ def fhir_vread(resource_type, id, version_id, client: :default, name: nil, tags: [])
194
+ store_request_and_refresh_token(fhir_client(client), name, tags) do
182
195
  tcp_exception_handler do
183
196
  fhir_client(client).vread(fhir_class_from_resource_type(resource_type), id, version_id)
184
197
  end
@@ -192,9 +205,10 @@ module Inferno
192
205
  # @param client [Symbol]
193
206
  # @param name [Symbol] Name for this request to allow it to be used by
194
207
  # other tests
208
+ # @param tags [Array<String>] a list of tags to assign to the request
195
209
  # @return [Inferno::Entities::Request]
196
- def fhir_update(resource, id, client: :default, name: nil)
197
- store_request_and_refresh_token(fhir_client(client), name) do
210
+ def fhir_update(resource, id, client: :default, name: nil, tags: [])
211
+ store_request_and_refresh_token(fhir_client(client), name, tags) do
198
212
  tcp_exception_handler do
199
213
  fhir_client(client).update(resource, id)
200
214
  end
@@ -209,9 +223,10 @@ module Inferno
209
223
  # @param client [Symbol]
210
224
  # @param name [Symbol] Name for this request to allow it to be used by
211
225
  # other tests
226
+ # @param tags [Array<String>] a list of tags to assign to the request
212
227
  # @return [Inferno::Entities::Request]
213
- def fhir_patch(resource_type, id, patchset, client: :default, name: nil)
214
- store_request_and_refresh_token(fhir_client(client), name) do
228
+ def fhir_patch(resource_type, id, patchset, client: :default, name: nil, tags: [])
229
+ store_request_and_refresh_token(fhir_client(client), name, tags) do
215
230
  tcp_exception_handler do
216
231
  fhir_client(client).partial_update(fhir_class_from_resource_type(resource_type), id, patchset)
217
232
  end
@@ -225,9 +240,10 @@ module Inferno
225
240
  # @param client [Symbol]
226
241
  # @param name [Symbol] Name for this request to allow it to be used by
227
242
  # other tests
243
+ # @param tags [Array<String>] a list of tags to assign to the request
228
244
  # @return [Inferno::Entities::Request]
229
- def fhir_history(resource_type = nil, id = nil, client: :default, name: nil)
230
- store_request_and_refresh_token(fhir_client(client), name) do
245
+ def fhir_history(resource_type = nil, id = nil, client: :default, name: nil, tags: [])
246
+ store_request_and_refresh_token(fhir_client(client), name, tags) do
231
247
  tcp_exception_handler do
232
248
  if id
233
249
  fhir_client(client).resource_instance_history(fhir_class_from_resource_type(resource_type), id)
@@ -248,8 +264,16 @@ module Inferno
248
264
  # @param name [Symbol] Name for this request to allow it to be used by
249
265
  # other tests
250
266
  # @param search_method [Symbol] Use `:post` to search via POST
267
+ # @param tags [Array<String>] a list of tags to assign to the request
251
268
  # @return [Inferno::Entities::Request]
252
- def fhir_search(resource_type = nil, client: :default, params: {}, name: nil, search_method: :get)
269
+ def fhir_search(
270
+ resource_type = nil,
271
+ client: :default,
272
+ params: {},
273
+ name: nil,
274
+ search_method: :get,
275
+ tags: []
276
+ )
253
277
  search =
254
278
  if search_method == :post
255
279
  { body: params }
@@ -257,7 +281,7 @@ module Inferno
257
281
  { parameters: params }
258
282
  end
259
283
 
260
- store_request_and_refresh_token(fhir_client(client), name) do
284
+ store_request_and_refresh_token(fhir_client(client), name, tags) do
261
285
  tcp_exception_handler do
262
286
  if resource_type
263
287
  fhir_client(client)
@@ -276,9 +300,10 @@ module Inferno
276
300
  # @param client [Symbol]
277
301
  # @param name [Symbol] Name for this request to allow it to be used by
278
302
  # other tests
303
+ # @param tags [Array<String>] a list of tags to assign to the request
279
304
  # @return [Inferno::Entities::Request]
280
- def fhir_delete(resource_type, id, client: :default, name: nil)
281
- store_request('outgoing', name) do
305
+ def fhir_delete(resource_type, id, client: :default, name: nil, tags: [])
306
+ store_request('outgoing', name:, tags:) do
282
307
  tcp_exception_handler do
283
308
  fhir_client(client).destroy(fhir_class_from_resource_type(resource_type), id)
284
309
  end
@@ -291,9 +316,10 @@ module Inferno
291
316
  # @param client [Symbol]
292
317
  # @param name [Symbol] Name for this request to allow it to be used by
293
318
  # other tests
319
+ # @param tags [Array<String>] a list of tags to assign to the request
294
320
  # @return [Inferno::Entities::Request]
295
- def fhir_transaction(bundle = nil, client: :default, name: nil)
296
- store_request('outgoing', name) do
321
+ def fhir_transaction(bundle = nil, client: :default, name: nil, tags: [])
322
+ store_request('outgoing', name:, tags:) do
297
323
  tcp_exception_handler do
298
324
  fhir_client(client).transaction_bundle = bundle if bundle.present?
299
325
  fhir_client(client).end_transaction
@@ -312,8 +338,8 @@ module Inferno
312
338
  # expired. It's combined with `store_request` so that all of the fhir
313
339
  # request methods don't have to be wrapped twice.
314
340
  # @private
315
- def store_request_and_refresh_token(client, name, &block)
316
- store_request('outgoing', name) do
341
+ def store_request_and_refresh_token(client, name, tags, &block)
342
+ store_request('outgoing', name:, tags:) do
317
343
  perform_refresh(client) if client.need_to_refresh? && client.able_to_refresh?
318
344
  block.call
319
345
  end
@@ -0,0 +1,299 @@
1
+ require_relative '../ext/fhir_models'
2
+ module Inferno
3
+ module DSL
4
+ # This module contains the methods needed to configure a validator to
5
+ # perform validation of FHIR resources. The actual validation is performed
6
+ # by an external FHIR validation service. Tests will typically rely on
7
+ # `assert_valid_resource` for validation rather than directly calling
8
+ # methods on a validator.
9
+ #
10
+ # @example
11
+ #
12
+ # validator do
13
+ # url 'http://example.com/validator'
14
+ # exclude_message { |message| message.type == 'info' }
15
+ # perform_additional_validation do |resource, profile_url|
16
+ # if something_is_wrong
17
+ # { type: 'error', message: 'something is wrong' }
18
+ # else
19
+ # { type: 'info', message: 'everything is ok' }
20
+ # end
21
+ # end
22
+ # end
23
+ module FHIRResourceValidation
24
+ def self.included(klass)
25
+ klass.extend ClassMethods
26
+ end
27
+
28
+ class Validator
29
+ attr_reader :requirements
30
+ attr_accessor :session_id
31
+
32
+ # @private
33
+ def initialize(requirements = nil, &)
34
+ instance_eval(&)
35
+ @requirements = requirements
36
+ end
37
+
38
+ # @private
39
+ def default_validator_url
40
+ ENV.fetch('FHIR_RESOURCE_VALIDATOR_URL')
41
+ end
42
+
43
+ # Set the url of the validator service
44
+ #
45
+ # @param validator_url [String]
46
+ def url(validator_url = nil)
47
+ @url = validator_url if validator_url
48
+
49
+ @url
50
+ end
51
+
52
+ # Set the IGs that the validator will need to load
53
+ # Example: ["hl7.fhir.us.core#4.0.0"]
54
+ # @param igs [Array<String>]
55
+ def igs(validator_igs = nil)
56
+ @igs = validator_igs if validator_igs
57
+
58
+ @igs
59
+ end
60
+
61
+ # @private
62
+ def additional_validations
63
+ @additional_validations ||= []
64
+ end
65
+
66
+ # Perform validation steps in addition to FHIR validation.
67
+ #
68
+ # @example
69
+ # perform_additional_validation do |resource, profile_url|
70
+ # if something_is_wrong
71
+ # { type: 'error', message: 'something is wrong' }
72
+ # else
73
+ # { type: 'info', message: 'everything is ok' }
74
+ # end
75
+ # end
76
+ # @yieldparam resource [FHIR::Model] the resource being validated
77
+ # @yieldparam profile_url [String] the profile the resource is being
78
+ # validated against
79
+ # @yieldreturn [Array<Hash<Symbol, String>>,Hash<Symbol, String>] The
80
+ # block should return a Hash or an Array of Hashes if any validation
81
+ # messages should be added. The Hash must contain two keys: `:type`
82
+ # and `:message`. `:type` can have a value of `'info'`, `'warning'`,
83
+ # or `'error'`. A type of `'error'` means the resource is invalid.
84
+ # `:message` contains the message string itself.
85
+ def perform_additional_validation(&block)
86
+ additional_validations << block
87
+ end
88
+
89
+ # @private
90
+ def additional_validation_messages(resource, profile_url)
91
+ additional_validations
92
+ .flat_map { |step| step.call(resource, profile_url) }
93
+ .select { |message| message.is_a? Hash }
94
+ end
95
+
96
+ # Filter out unwanted validation messages. Any messages for which the
97
+ # block evalutates to a truthy value will be excluded.
98
+ #
99
+ # @example
100
+ # validator do
101
+ # exclude_message { |message| message.type == 'info' }
102
+ # end
103
+ # @yieldparam message [Inferno::Entities::Message]
104
+ def exclude_message(&block)
105
+ @exclude_message = block if block_given?
106
+ @exclude_message
107
+ end
108
+
109
+ # @see Inferno::DSL::FHIRResourceValidation#resource_is_valid?
110
+ def resource_is_valid?(resource, profile_url, runnable)
111
+ profile_url ||= FHIR::Definitions.resource_definition(resource.resourceType).url
112
+
113
+ begin
114
+ response = call_validator(resource, profile_url)
115
+ rescue StandardError => e
116
+ # This could be a complete failure to connect (validator isn't running)
117
+ # or a timeout (validator took too long to respond).
118
+ runnable.add_message('error', e.message)
119
+ raise Inferno::Exceptions::ErrorInValidatorException, "Unable to connect to validator at #{url}."
120
+ end
121
+ outcome = operation_outcome_from_validator_response(response, runnable)
122
+
123
+ message_hashes = message_hashes_from_outcome(outcome, resource, profile_url)
124
+
125
+ message_hashes
126
+ .each { |message_hash| runnable.add_message(message_hash[:type], message_hash[:message]) }
127
+
128
+ unless response.status == 200
129
+ raise Inferno::Exceptions::ErrorInValidatorException,
130
+ 'Error occurred in the validator. Review Messages tab or validator service logs for more information.'
131
+ end
132
+
133
+ message_hashes
134
+ .none? { |message_hash| message_hash[:type] == 'error' }
135
+ rescue Inferno::Exceptions::ErrorInValidatorException
136
+ raise
137
+ rescue StandardError => e
138
+ runnable.add_message('error', e.message)
139
+ raise Inferno::Exceptions::ErrorInValidatorException,
140
+ 'Error occurred in the validator. Review Messages tab or validator service logs for more information.'
141
+ end
142
+
143
+ # @private
144
+ def filter_messages(message_hashes)
145
+ message_hashes.reject! { |message| exclude_message.call(Entities::Message.new(message)) } if exclude_message
146
+ end
147
+
148
+ # @private
149
+ def message_hashes_from_outcome(outcome, resource, profile_url)
150
+ message_hashes = outcome.issue&.map { |issue| message_hash_from_issue(issue, resource) } || []
151
+
152
+ message_hashes.concat(additional_validation_messages(resource, profile_url))
153
+
154
+ filter_messages(message_hashes)
155
+
156
+ message_hashes
157
+ end
158
+
159
+ # @private
160
+ def message_hash_from_issue(issue, resource)
161
+ {
162
+ type: issue_severity(issue),
163
+ message: issue_message(issue, resource)
164
+ }
165
+ end
166
+
167
+ # @private
168
+ def issue_severity(issue)
169
+ case issue.severity
170
+ when 'warning'
171
+ 'warning'
172
+ when 'information'
173
+ 'info'
174
+ else
175
+ 'error'
176
+ end
177
+ end
178
+
179
+ # @private
180
+ def issue_message(issue, resource)
181
+ location = if issue.respond_to?(:expression)
182
+ issue.expression&.join(', ')
183
+ else
184
+ issue.location&.join(', ')
185
+ end
186
+
187
+ location_prefix = resource.id ? "#{resource.resourceType}/#{resource.id}" : resource.resourceType
188
+
189
+ "#{location_prefix}: #{location}: #{issue&.details&.text}"
190
+ end
191
+
192
+ # @private
193
+ def wrap_resource_for_hl7_wrapper(resource, profile_url)
194
+ wrapped_resource = {
195
+ cliContext: {
196
+ # TODO: these should be configurable as well
197
+ sv: '4.0.1',
198
+ # displayWarnings: true, # -display-issues-are-warnings
199
+ # txServer: nil, # -tx n/a
200
+ igs: @igs || [],
201
+ # NOTE: this profile must be part of a loaded IG,
202
+ # otherwise the response is an HTTP 500 with no content
203
+ profiles: [profile_url]
204
+ },
205
+ filesToValidate: [
206
+ {
207
+ fileName: "#{resource.resourceType}/#{resource.id}.json",
208
+ fileContent: resource.to_json,
209
+ fileType: 'json'
210
+ }
211
+ ],
212
+ sessionId: @session_id
213
+ }
214
+ wrapped_resource.to_json
215
+ end
216
+
217
+ # Post a resource to the validation service for validating.
218
+ #
219
+ # @param resource [FHIR::Model]
220
+ # @param profile_url [String]
221
+ # @return [String] the body of the validation response
222
+ def validate(resource, profile_url)
223
+ call_validator(resource, profile_url).body
224
+ end
225
+
226
+ # @private
227
+ def call_validator(resource, profile_url)
228
+ request_body = wrap_resource_for_hl7_wrapper(resource, profile_url)
229
+ Faraday.new(
230
+ url,
231
+ request: { timeout: 600 }
232
+ ).post('validate', request_body, content_type: 'application/json')
233
+ end
234
+
235
+ # @private
236
+ def operation_outcome_from_hl7_wrapped_response(response)
237
+ res = JSON.parse(response)
238
+
239
+ @session_id = res['sessionId']
240
+
241
+ # assume for now that one resource -> one request
242
+ issues = res['outcomes'][0]['issues']&.map do |i|
243
+ { severity: i['level'].downcase, expression: i['location'], details: { text: i['message'] } }
244
+ end
245
+ # this is circuitous, ideally we would map this response directly to message_hashes
246
+ FHIR::OperationOutcome.new(issue: issues)
247
+ end
248
+
249
+ # @private
250
+ def operation_outcome_from_validator_response(response, runnable)
251
+ if response.body.start_with? '{'
252
+ operation_outcome_from_hl7_wrapped_response(response.body)
253
+ else
254
+ runnable.add_message('error', "Validator Response: HTTP #{response.status}\n#{response.body}")
255
+ raise Inferno::Exceptions::ErrorInValidatorException,
256
+ 'Validator response was an unexpected format. '\
257
+ 'Review Messages tab or validator service logs for more information.'
258
+ end
259
+ end
260
+ end
261
+
262
+ module ClassMethods
263
+ # @private
264
+ def fhir_validators
265
+ @fhir_validators ||= {}
266
+ end
267
+
268
+ # Define a validator
269
+ # @example
270
+ # fhir_resource_validator do
271
+ # url 'http://example.com/validator'
272
+ # exclude_message { |message| message.type == 'info' }
273
+ # perform_additional_validation do |resource, profile_url|
274
+ # if something_is_wrong
275
+ # { type: 'error', message: 'something is wrong' }
276
+ # else
277
+ # { type: 'info', message: 'everything is ok' }
278
+ # end
279
+ # end
280
+ # end
281
+ #
282
+ # @param name [Symbol] the name of the validator, only needed if you are
283
+ # using multiple validators
284
+ # @param required_suite_options [Hash] suite options that must be
285
+ # selected in order to use this validator
286
+ def fhir_resource_validator(name = :default, required_suite_options: nil, &block)
287
+ current_validators = fhir_validators[name] || []
288
+
289
+ new_validator = Inferno::DSL::FHIRResourceValidation::Validator.new(required_suite_options, &block)
290
+
291
+ current_validators.reject! { |validator| validator.requirements == required_suite_options }
292
+ current_validators << new_validator
293
+
294
+ fhir_validators[name] = current_validators
295
+ end
296
+ end
297
+ end
298
+ end
299
+ end
@@ -68,9 +68,10 @@ module Inferno
68
68
  # @param name [Symbol] Name for this request to allow it to be used by
69
69
  # other tests
70
70
  # @param headers [Hash] Input headers here
71
+ # @param tags [Array<String>] a list of tags to assign to the request
71
72
  # @return [Inferno::Entities::Request]
72
- def get(url = '', client: :default, name: nil, headers: nil)
73
- store_request('outgoing', name) do
73
+ def get(url = '', client: :default, name: nil, headers: nil, tags: [])
74
+ store_request('outgoing', name:, tags:) do
74
75
  tcp_exception_handler do
75
76
  client = http_client(client)
76
77
 
@@ -103,9 +104,10 @@ module Inferno
103
104
  # @param name [Symbol] Name for this request to allow it to be used by
104
105
  # other tests
105
106
  # @param headers [Hash] Input headers here
107
+ # @param tags [Array<String>] a list of tags to assign to the request
106
108
  # @return [Inferno::Entities::Request]
107
- def post(url = '', body: nil, client: :default, name: nil, headers: nil)
108
- store_request('outgoing', name) do
109
+ def post(url = '', body: nil, client: :default, name: nil, headers: nil, tags: [])
110
+ store_request('outgoing', name:, tags:) do
109
111
  tcp_exception_handler do
110
112
  client = http_client(client)
111
113
 
@@ -129,9 +131,10 @@ module Inferno
129
131
  # @param name [Symbol] Name for this request to allow it to be used by
130
132
  # other tests
131
133
  # @param headers [Hash] Input headers here
134
+ # @param tags [Array<String>] a list of tags to assign to the request
132
135
  # @return [Inferno::Entities::Request]
133
- def delete(url = '', client: :default, name: :nil, headers: nil)
134
- store_request('outgoing', name) do
136
+ def delete(url = '', client: :default, name: :nil, headers: nil, tags: [])
137
+ store_request('outgoing', name:, tags:) do
135
138
  tcp_exception_handler do
136
139
  client = http_client(client)
137
140
 
@@ -159,8 +162,9 @@ module Inferno
159
162
  # @param name [Symbol] Name for this request to allow it to be used by
160
163
  # other tests
161
164
  # @param headers [Hash] Input headers here
165
+ # @param tags [Array<String>] a list of tags to assign to the request
162
166
  # @return [Inferno::Entities::Request]
163
- def stream(block, url = '', limit = 100, client: :default, name: nil, headers: nil)
167
+ def stream(block, url = '', limit = 100, client: :default, name: nil, headers: nil, tags: [])
164
168
  streamed = []
165
169
 
166
170
  collector = proc do |chunk, bytes|
@@ -169,7 +173,7 @@ module Inferno
169
173
  block.call(chunk, bytes)
170
174
  end
171
175
 
172
- store_request('outgoing', name) do
176
+ store_request('outgoing', name:, tags:) do
173
177
  tcp_exception_handler do
174
178
  client = http_client(client)
175
179
 
@@ -36,24 +36,36 @@ module Inferno
36
36
  request&.resource
37
37
  end
38
38
 
39
+ # Returns requests which match all of the given tags
40
+ #
41
+ # @param tags [String]
42
+ # @return [Inferno::Entities::Request]
43
+ def load_tagged_requests(*tags)
44
+ return [] if tags.blank?
45
+
46
+ Repositories::Requests.new.tagged_requests(test_session_id, tags).tap do |tagged_requests|
47
+ requests.concat(tagged_requests)
48
+ end
49
+ end
50
+
39
51
  # @private
40
52
  def named_request(name)
41
53
  requests.find { |request| request.name == self.class.config.request_name(name.to_sym) }
42
54
  end
43
55
 
44
56
  # @private
45
- def store_request(direction, name = nil, &block)
57
+ def store_request(direction, name: nil, tags: [], &block)
46
58
  response = block.call
47
59
 
48
60
  name = self.class.config.request_name(name)
49
61
  request =
50
62
  if response.is_a? FHIR::ClientReply
51
63
  Entities::Request.from_fhir_client_reply(
52
- response, direction:, name:, test_session_id:
64
+ response, direction:, name:, test_session_id:, tags:
53
65
  )
54
66
  else
55
67
  Entities::Request.from_http_response(
56
- response, direction:, name:, test_session_id:
68
+ response, direction:, name:, test_session_id:, tags:
57
69
  )
58
70
  end
59
71