inferno_core 0.4.22 → 0.4.23

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 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