inferno_core 0.3.3 → 0.3.4

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: 884936b347ee4892198605b7ae408f3889e74bed0a4e33b6ec2a5ee7ed3adcd9
4
- data.tar.gz: b0e30f11313a6a5b690e96a08fdb083ba9d85b94b512ec105fce75631802f0cb
3
+ metadata.gz: 5c905fd9a450198c42daa6a7f3119277d1eeb1e39acb788856d90c3817719d02
4
+ data.tar.gz: e11d6fcfa8acb3c487c62d512b9210db18f5d7bba5c9148063587de8a3e78420
5
5
  SHA512:
6
- metadata.gz: 13b145c224d9b762b2ae8019048d6775dea2bd0ce47abcb3450959e3148224a523914eaf06b480a25d1a065c449e32b9c64ed83056118b611e8be2c4d9640755
7
- data.tar.gz: 78a7bd5437739a2e1e7384dc500d46a99c8795f03638023839fdf4c24131fcc9a6ba8ca1ec507cd0b0bd559d8c9741e07ce2c6e3b04954b72bf6ba4ce7158805
6
+ metadata.gz: d62c7ebc7b9f9ac2024bfb933254cd54010b869fde72d15c77e935e7228096e2ba45844e3f8ba2f7b28f71315120d7a194b63d7e95675600e26efd1bbe822cc1
7
+ data.tar.gz: ed6b0d392219155cd2cd6865e01d9ba838c067f36bfdd86ac10e80e923b51ddf688cff4f8e8a67e62e53a1d28c151f1c76d5e791166e920ff9832676fa1239c0
@@ -11,7 +11,7 @@ Inferno::Application.boot(:db) do
11
11
 
12
12
  config_path = File.expand_path('database.yml', File.join(Dir.pwd, 'config'))
13
13
  config_contents = ERB.new(File.read(config_path)).result
14
- config = YAML.safe_load(config_contents)[ENV['APP_ENV']]
14
+ config = YAML.safe_load(config_contents)[ENV.fetch('APP_ENV', nil)]
15
15
  .merge(logger: Inferno::Application['logger'])
16
16
  connection_attempts_remaining = ENV.fetch('MAX_DB_CONNECTION_ATTEMPTS', '10').to_i
17
17
  connection_retry_delay = ENV.fetch('DB_CONNECTION_RETRY_DELAY', '5').to_i
@@ -4,4 +4,4 @@ ENV['APP_ENV'] ||= 'development'
4
4
 
5
5
  root_path = Dir.pwd
6
6
 
7
- Dotenv.load(File.join(root_path, '.env'), File.join(root_path, ".env.#{ENV['APP_ENV']}"))
7
+ Dotenv.load(File.join(root_path, '.env'), File.join(root_path, ".env.#{ENV.fetch('APP_ENV', nil)}"))
@@ -16,7 +16,7 @@ module Inferno
16
16
 
17
17
  @config.apply(new_configuration)
18
18
 
19
- children.each { |child| child.config(new_configuration) }
19
+ all_children.each { |child| child.config(new_configuration) }
20
20
 
21
21
  @config
22
22
  end
@@ -1,4 +1,5 @@
1
1
  require_relative 'request_storage'
2
+ require_relative 'tcp_exception_handler'
2
3
 
3
4
  module Inferno
4
5
  module DSL
@@ -40,6 +41,7 @@ module Inferno
40
41
  klass.extend ClassMethods
41
42
  klass.extend Forwardable
42
43
  klass.include RequestStorage
44
+ klass.include TCPExceptionHandler
43
45
 
44
46
  klass.def_delegators 'self.class', :profile_url, :validator_url
45
47
  end
@@ -73,11 +75,13 @@ module Inferno
73
75
  # @return [Inferno::Entities::Request]
74
76
  def fhir_operation(path, body: nil, client: :default, name: nil, headers: {})
75
77
  store_request_and_refresh_token(fhir_client(client), name) do
76
- operation_headers = fhir_client(client).fhir_headers
77
- operation_headers.merge!('Content-Type' => 'application/fhir+json') if body.present?
78
- operation_headers.merge!(headers) if headers.present?
78
+ tcp_exception_handler do
79
+ operation_headers = fhir_client(client).fhir_headers
80
+ operation_headers.merge!('Content-Type' => 'application/fhir+json') if body.present?
81
+ operation_headers.merge!(headers) if headers.present?
79
82
 
80
- fhir_client(client).send(:post, path, body, operation_headers)
83
+ fhir_client(client).send(:post, path, body, operation_headers)
84
+ end
81
85
  end
82
86
  end
83
87
 
@@ -89,8 +93,10 @@ module Inferno
89
93
  # @return [Inferno::Entities::Request]
90
94
  def fhir_get_capability_statement(client: :default, name: nil)
91
95
  store_request_and_refresh_token(fhir_client(client), name) do
92
- fhir_client(client).conformance_statement
93
- fhir_client(client).reply
96
+ tcp_exception_handler do
97
+ fhir_client(client).conformance_statement
98
+ fhir_client(client).reply
99
+ end
94
100
  end
95
101
  end
96
102
 
@@ -104,7 +110,9 @@ module Inferno
104
110
  # @return [Inferno::Entities::Request]
105
111
  def fhir_read(resource_type, id, client: :default, name: nil)
106
112
  store_request_and_refresh_token(fhir_client(client), name) do
107
- fhir_client(client).read(fhir_class_from_resource_type(resource_type), id)
113
+ tcp_exception_handler do
114
+ fhir_client(client).read(fhir_class_from_resource_type(resource_type), id)
115
+ end
108
116
  end
109
117
  end
110
118
 
@@ -126,8 +134,10 @@ module Inferno
126
134
  end
127
135
 
128
136
  store_request_and_refresh_token(fhir_client(client), name) do
129
- fhir_client(client)
130
- .search(fhir_class_from_resource_type(resource_type), { search: search })
137
+ tcp_exception_handler do
138
+ fhir_client(client)
139
+ .search(fhir_class_from_resource_type(resource_type), { search: search })
140
+ end
131
141
  end
132
142
  end
133
143
 
@@ -141,7 +151,9 @@ module Inferno
141
151
  # @return [Inferno::Entities::Request]
142
152
  def fhir_delete(resource_type, id, client: :default, name: nil)
143
153
  store_request('outgoing', name) do
144
- fhir_client(client).destroy(fhir_class_from_resource_type(resource_type), id)
154
+ tcp_exception_handler do
155
+ fhir_client(client).destroy(fhir_class_from_resource_type(resource_type), id)
156
+ end
145
157
  end
146
158
  end
147
159
 
@@ -1,5 +1,4 @@
1
1
  require_relative '../ext/fhir_models'
2
-
3
2
  module Inferno
4
3
  module DSL
5
4
  # This module contains the methods needed to configure a validator to
@@ -39,13 +38,16 @@ module Inferno
39
38
  # Find a particular validator. Looks through a runnable's parents up to
40
39
  # the suite to find a validator with a particular name
41
40
  def find_validator(validator_name)
42
- self.class.find_validator(validator_name)
41
+ self.class.find_validator(validator_name, suite_options)
43
42
  end
44
43
 
45
44
  class Validator
45
+ attr_reader :requirements
46
+
46
47
  # @private
47
- def initialize(&block)
48
+ def initialize(requirements = nil, &block)
48
49
  instance_eval(&block)
50
+ @requirements = requirements
49
51
  end
50
52
 
51
53
  # @private
@@ -115,7 +117,7 @@ module Inferno
115
117
 
116
118
  outcome = FHIR::OperationOutcome.new(JSON.parse(validate(resource, profile_url)))
117
119
 
118
- message_hashes = outcome.issue&.map { |issue| message_hash_from_issue(issue) } || []
120
+ message_hashes = outcome.issue&.map { |issue| message_hash_from_issue(issue, resource) } || []
119
121
 
120
122
  message_hashes.concat(additional_validation_messages(resource, profile_url))
121
123
 
@@ -132,10 +134,10 @@ module Inferno
132
134
  end
133
135
 
134
136
  # @private
135
- def message_hash_from_issue(issue)
137
+ def message_hash_from_issue(issue, resource)
136
138
  {
137
139
  type: issue_severity(issue),
138
- message: issue_message(issue)
140
+ message: issue_message(issue, resource)
139
141
  }
140
142
  end
141
143
 
@@ -152,14 +154,16 @@ module Inferno
152
154
  end
153
155
 
154
156
  # @private
155
- def issue_message(issue)
157
+ def issue_message(issue, resource)
156
158
  location = if issue.respond_to?(:expression)
157
159
  issue.expression&.join(', ')
158
160
  else
159
161
  issue.location&.join(', ')
160
162
  end
161
163
 
162
- "#{location}: #{issue&.details&.text}"
164
+ location_prefix = resource.id ? "#{resource.resourceType}/#{resource.id}" : resource.resourceType
165
+
166
+ "#{location_prefix}: #{location}: #{issue&.details&.text}"
163
167
  end
164
168
 
165
169
  # Post a resource to the validation service for validating.
@@ -198,14 +202,33 @@ module Inferno
198
202
  #
199
203
  # @param name [Symbol] the name of the validator, only needed if you are
200
204
  # using multiple validators
201
- def validator(name = :default, &block)
202
- fhir_validators[name] = Inferno::DSL::FHIRValidation::Validator.new(&block)
205
+ # @param required_suite_options [Hash] suite options that must be
206
+ # selected in order to use this validator
207
+ def validator(name = :default, required_suite_options: nil, &block)
208
+ current_validators = fhir_validators[name] || []
209
+
210
+ new_validator = Inferno::DSL::FHIRValidation::Validator.new(required_suite_options, &block)
211
+
212
+ current_validators.reject! { |validator| validator.requirements == required_suite_options }
213
+ current_validators << new_validator
214
+
215
+ fhir_validators[name] = current_validators
203
216
  end
204
217
 
205
218
  # Find a particular validator. Looks through a runnable's parents up to
206
219
  # the suite to find a validator with a particular name
207
- def find_validator(validator_name)
208
- validator = fhir_validators[validator_name] || parent&.find_validator(validator_name)
220
+ def find_validator(validator_name, selected_suite_options = nil)
221
+ validators = fhir_validators[validator_name] ||
222
+ Array.wrap(parent&.find_validator(validator_name, selected_suite_options))
223
+
224
+ validator =
225
+ if selected_suite_options.present?
226
+ validators.find do |possible_validator|
227
+ possible_validator.requirements.nil? || selected_suite_options >= possible_validator.requirements
228
+ end
229
+ else
230
+ validators.first
231
+ end
209
232
 
210
233
  raise Exceptions::ValidatorNotFoundException, validator_name if validator.nil?
211
234
 
@@ -1,4 +1,5 @@
1
1
  require_relative 'request_storage'
2
+ require_relative 'tcp_exception_handler'
2
3
 
3
4
  module Inferno
4
5
  module DSL
@@ -31,6 +32,7 @@ module Inferno
31
32
  def self.included(klass)
32
33
  klass.extend ClassMethods
33
34
  klass.include RequestStorage
35
+ klass.include TCPExceptionHandler
34
36
  end
35
37
 
36
38
  # Return a previously defined HTTP client
@@ -44,7 +46,9 @@ module Inferno
44
46
  definition = self.class.http_client_definitions[client]
45
47
  return nil if definition.nil?
46
48
 
47
- http_clients[client] = HTTPClientBuilder.new.build(self, definition)
49
+ tcp_exception_handler do
50
+ http_clients[client] = HTTPClientBuilder.new.build(self, definition)
51
+ end
48
52
  end
49
53
 
50
54
  # @private
@@ -65,14 +69,16 @@ module Inferno
65
69
  # @return [Inferno::Entities::Request]
66
70
  def get(url = '', client: :default, name: nil, **options)
67
71
  store_request('outgoing', name) do
68
- client = http_client(client)
69
-
70
- if client
71
- client.get(url, nil, options[:headers])
72
- elsif url.match?(%r{\Ahttps?://})
73
- Faraday.get(url, nil, options[:headers])
74
- else
75
- raise StandardError, 'Must use an absolute url or define an HTTP client with a base url'
72
+ tcp_exception_handler do
73
+ client = http_client(client)
74
+
75
+ if client
76
+ client.get(url, nil, options[:headers])
77
+ elsif url.match?(%r{\Ahttps?://})
78
+ Faraday.get(url, nil, options[:headers])
79
+ else
80
+ raise StandardError, 'Must use an absolute url or define an HTTP client with a base url'
81
+ end
76
82
  end
77
83
  end
78
84
  end
@@ -91,14 +97,16 @@ module Inferno
91
97
  # @return [Inferno::Entities::Request]
92
98
  def post(url = '', body: nil, client: :default, name: nil, **options)
93
99
  store_request('outgoing', name) do
94
- client = http_client(client)
95
-
96
- if client
97
- client.post(url, body, options[:headers])
98
- elsif url.match?(%r{\Ahttps?://})
99
- Faraday.post(url, body, options[:headers])
100
- else
101
- raise StandardError, 'Must use an absolute url or define an HTTP client with a base url'
100
+ tcp_exception_handler do
101
+ client = http_client(client)
102
+
103
+ if client
104
+ client.post(url, body, options[:headers])
105
+ elsif url.match?(%r{\Ahttps?://})
106
+ Faraday.post(url, body, options[:headers])
107
+ else
108
+ raise StandardError, 'Must use an absolute url or define an HTTP client with a base url'
109
+ end
102
110
  end
103
111
  end
104
112
  end
@@ -114,14 +122,16 @@ module Inferno
114
122
  # @return [Inferno::Entities::Request]
115
123
  def delete(url = '', client: :default, name: :nil, **options)
116
124
  store_request('outgoing', name) do
117
- client = http_client(client)
118
-
119
- if client
120
- client.delete(url, nil, options[:headers])
121
- elsif url.match?(%r{\Ahttps?://})
122
- Faraday.delete(url, nil, options[:headers])
123
- else
124
- raise StandardError, 'Must use an absolute url or define an HTTP client with a base url'
125
+ tcp_exception_handler do
126
+ client = http_client(client)
127
+
128
+ if client
129
+ client.delete(url, nil, options[:headers])
130
+ elsif url.match?(%r{\Ahttps?://})
131
+ Faraday.delete(url, nil, options[:headers])
132
+ else
133
+ raise StandardError, 'Must use an absolute url or define an HTTP client with a base url'
134
+ end
125
135
  end
126
136
  end
127
137
  end
@@ -151,17 +161,19 @@ module Inferno
151
161
  end
152
162
 
153
163
  store_request('outgoing', name) do
154
- client = http_client(client)
155
-
156
- if client
157
- response = client.get(url, nil, options[:headers]) { |req| req.options.on_data = collector }
158
- elsif url.match?(%r{\Ahttps?://})
159
- response = Faraday.get(url, nil, options[:headers]) { |req| req.options.on_data = collector }
160
- else
161
- raise StandardError, 'Must use an absolute url or define an HTTP client with a base url'
164
+ tcp_exception_handler do
165
+ client = http_client(client)
166
+
167
+ if client
168
+ response = client.get(url, nil, options[:headers]) { |req| req.options.on_data = collector }
169
+ elsif url.match?(%r{\Ahttps?://})
170
+ response = Faraday.get(url, nil, options[:headers]) { |req| req.options.on_data = collector }
171
+ else
172
+ raise StandardError, 'Must use an absolute url or define an HTTP client with a base url'
173
+ end
174
+ response.env.body = streamed.join
175
+ response
162
176
  end
163
- response.env.body = streamed.join
164
- response
165
177
  end
166
178
  end
167
179
 
@@ -125,7 +125,7 @@ module Inferno
125
125
  def all_outputs
126
126
  outputs
127
127
  .map { |output_identifier| config.output_name(output_identifier) }
128
- .concat(children.flat_map(&:all_outputs))
128
+ .concat(all_children.flat_map(&:all_outputs))
129
129
  .uniq
130
130
  end
131
131
 
@@ -137,7 +137,7 @@ module Inferno
137
137
  @children_available_inputs ||=
138
138
  begin
139
139
  child_outputs = []
140
- children.each_with_object({}) do |child, definitions|
140
+ all_children.each_with_object({}) do |child, definitions|
141
141
  new_definitions = child.available_inputs.map(&:dup)
142
142
  new_definitions.each do |input, new_definition|
143
143
  existing_definition = definitions[input]
@@ -9,6 +9,7 @@ module Inferno
9
9
  # definition framework.
10
10
  module Runnable
11
11
  attr_accessor :parent
12
+ attr_reader :suite_option_requirements
12
13
 
13
14
  include Inferno::Utils::MarkdownFormatter
14
15
 
@@ -48,7 +49,7 @@ module Inferno
48
49
  VARIABLES_NOT_TO_COPY = [
49
50
  :@id, # New runnable will have a different id
50
51
  :@parent, # New runnable unlikely to have the same parent
51
- :@children, # New subclasses have to be made for each child
52
+ :@all_children, # New subclasses have to be made for each child
52
53
  :@test_count, # Needs to be recalculated
53
54
  :@config, # Needs to be set by calling .config, which does extra work
54
55
  :@available_inputs, # Needs to be recalculated
@@ -63,13 +64,13 @@ module Inferno
63
64
 
64
65
  subclass.config(config)
65
66
 
66
- new_children = children.map do |child|
67
+ new_children = all_children.map do |child|
67
68
  Class.new(child).tap do |subclass_child|
68
69
  subclass_child.parent = subclass
69
70
  end
70
71
  end
71
72
 
72
- subclass.instance_variable_set(:@children, new_children)
73
+ subclass.instance_variable_set(:@all_children, new_children)
73
74
  end
74
75
 
75
76
  # @private
@@ -94,7 +95,7 @@ module Inferno
94
95
 
95
96
  klass.parent = self
96
97
 
97
- children << klass
98
+ all_children << klass
98
99
 
99
100
  configure_child_class(klass, hash_args)
100
101
 
@@ -172,7 +173,7 @@ module Inferno
172
173
 
173
174
  klass.config(config)
174
175
 
175
- klass.children.select!(&:required?) if hash_args.delete(:exclude_optional)
176
+ klass.all_children.select!(&:required?) if hash_args.delete(:exclude_optional)
176
177
 
177
178
  hash_args.each do |key, value|
178
179
  if value.is_a? Array
@@ -182,7 +183,7 @@ module Inferno
182
183
  end
183
184
  end
184
185
 
185
- klass.children.each do |child_class|
186
+ klass.all_children.each do |child_class|
186
187
  klass.configure_child_class(child_class, {})
187
188
  child_class.add_self_to_repository
188
189
  end
@@ -302,8 +303,8 @@ module Inferno
302
303
  end
303
304
 
304
305
  # @private
305
- def children
306
- @children ||= []
306
+ def all_children
307
+ @all_children ||= []
307
308
  end
308
309
 
309
310
  def validator_url(url = nil)
@@ -378,8 +379,12 @@ module Inferno
378
379
  end
379
380
 
380
381
  # @private
381
- def test_count
382
- @test_count ||= children&.reduce(0) { |sum, child| sum + child.test_count } || 0
382
+ def test_count(selected_suite_options = {})
383
+ @test_counts ||= {}
384
+
385
+ @test_counts[selected_suite_options] ||=
386
+ children(selected_suite_options)
387
+ &.reduce(0) { |sum, child| sum + child.test_count(selected_suite_options) } || 0
383
388
  end
384
389
 
385
390
  # @private
@@ -388,6 +393,21 @@ module Inferno
388
393
  !parent.respond_to?(:run_as_group?) ||
389
394
  (parent.user_runnable? && !parent.run_as_group?)
390
395
  end
396
+
397
+ def required_suite_options(suite_option_requirements)
398
+ @suite_option_requirements = suite_option_requirements
399
+ end
400
+
401
+ def children(selected_suite_options = nil)
402
+ return all_children if selected_suite_options.blank?
403
+
404
+ all_children.select do |child|
405
+ requirements = child.suite_option_requirements || {}
406
+
407
+ # requirements are a subset of selected options or equal to selected options
408
+ selected_suite_options >= requirements
409
+ end
410
+ end
391
411
  end
392
412
  end
393
413
  end
@@ -0,0 +1,11 @@
1
+ module Inferno
2
+ module DSL
3
+ module TCPExceptionHandler
4
+ def tcp_exception_handler(&block)
5
+ block.call
6
+ rescue Faraday::ConnectionFailed, SocketError => e
7
+ e.message.include?('Failed to open TCP') ? raise(Exceptions::AssertionException, e.message) : raise(e)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -13,13 +13,14 @@ module Inferno
13
13
  def_delegators 'self.class', :title, :id, :block, :inputs, :outputs
14
14
 
15
15
  attr_accessor :result_message
16
- attr_reader :test_session_id, :scratch
16
+ attr_reader :test_session_id, :scratch, :suite_options
17
17
 
18
18
  # @private
19
19
  def initialize(**params)
20
20
  params[:inputs]&.each { |key, value| instance_variable_set("@#{key}", value) }
21
21
  @scratch = params[:scratch]
22
22
  @test_session_id = params[:test_session_id]
23
+ @suite_options = params[:suite_options].presence || {}
23
24
  end
24
25
 
25
26
  # @private
@@ -195,7 +196,8 @@ module Inferno
195
196
  end
196
197
 
197
198
  # @private
198
- def test_count
199
+ # Has an unused argument to match the method signature of Runnable#test_count
200
+ def test_count(_ = nil)
199
201
  1
200
202
  end
201
203
 
@@ -32,11 +32,11 @@ module Inferno
32
32
  end
33
33
 
34
34
  def groups
35
- children.select { |child| child < Inferno::Entities::TestGroup }
35
+ all_children.select { |child| child < Inferno::Entities::TestGroup }
36
36
  end
37
37
 
38
38
  def tests
39
- children.select { |child| child < Inferno::Entities::Test }
39
+ all_children.select { |child| child < Inferno::Entities::Test }
40
40
  end
41
41
 
42
42
  # Methods to configure Inferno::DSL::Runnable
@@ -19,8 +19,19 @@ module Inferno
19
19
  # @!attribute results
20
20
  # @return [Array<Inferno::Entities::TestResult>] the `TestResults`
21
21
  # associated with this session
22
+ # @!attribute suite_options
23
+ # @return [Hash] the suite options associated with this session
22
24
  class TestSession < Entity
23
- ATTRIBUTES = [:id, :created_at, :updated_at, :test_suite_id, :test_suite, :test_runs, :results].freeze
25
+ ATTRIBUTES = [
26
+ :id,
27
+ :created_at,
28
+ :updated_at,
29
+ :test_suite_id,
30
+ :test_suite,
31
+ :test_runs,
32
+ :results,
33
+ :suite_options
34
+ ].freeze
24
35
 
25
36
  include Inferno::Entities::Attributes
26
37
 
@@ -22,7 +22,7 @@ module Inferno
22
22
  return @default_group if @default_group
23
23
 
24
24
  @default_group = Class.new(TestGroup)
25
- children << @default_group
25
+ all_children << @default_group
26
26
  @default_group
27
27
  end
28
28
 
@@ -31,7 +31,7 @@ module Inferno
31
31
  end
32
32
 
33
33
  def groups
34
- children.select { |child| child < Inferno::Entities::TestGroup }
34
+ all_children.select { |child| child < Inferno::Entities::TestGroup }
35
35
  end
36
36
 
37
37
  # Methods to configure Inferno::DSL::Runnable
@@ -60,17 +60,6 @@ module Inferno
60
60
  @version = version
61
61
  end
62
62
 
63
- def find_validator(validator_name)
64
- validator = fhir_validators[validator_name]
65
-
66
- return validator if validator
67
-
68
- raise Exceptions::ValidatorNotFoundException, validator_name unless validator_name == :default
69
-
70
- fhir_validators[:default] =
71
- Inferno::DSL::FHIRValidation::Validator.new { |v| v.url default_validator_url }
72
- end
73
-
74
63
  def configuration_messages(new_messages = nil, force_recheck: false)
75
64
  return @configuration_messages = new_messages unless new_messages.nil?
76
65
 
@@ -95,6 +84,14 @@ module Inferno
95
84
  def presets
96
85
  @presets ||= Repositories::Presets.new.presets_for_suite(id)
97
86
  end
87
+
88
+ def suite_option(identifier, **input_params)
89
+ suite_options[identifier] = input_params
90
+ end
91
+
92
+ def suite_options
93
+ @suite_options ||= {}
94
+ end
98
95
  end
99
96
  end
100
97
  end