inferno_core 0.0.3 → 0.0.7

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 (81) hide show
  1. checksums.yaml +4 -4
  2. data/bin/inferno +7 -0
  3. data/lib/inferno/apps/cli/console.rb +12 -0
  4. data/lib/inferno/apps/cli/main.rb +18 -0
  5. data/lib/inferno/apps/cli/migration.rb +14 -0
  6. data/lib/inferno/apps/cli.rb +8 -0
  7. data/lib/inferno/apps/web/controllers/test_runs/create.rb +30 -10
  8. data/lib/inferno/apps/web/controllers/test_runs/show.rb +10 -0
  9. data/lib/inferno/apps/web/controllers/test_sessions/create.rb +1 -0
  10. data/lib/inferno/apps/web/controllers/test_sessions/last_test_run.rb +22 -0
  11. data/lib/inferno/apps/web/controllers/test_sessions/results/index.rb +6 -1
  12. data/lib/inferno/apps/web/controllers/test_sessions/session_data/index.rb +21 -0
  13. data/lib/inferno/apps/web/router.rb +15 -0
  14. data/lib/inferno/apps/web/serializers/hash_value_extractor.rb +11 -0
  15. data/lib/inferno/apps/web/serializers/request.rb +1 -0
  16. data/lib/inferno/apps/web/serializers/result.rb +8 -0
  17. data/lib/inferno/apps/web/serializers/session_data.rb +10 -0
  18. data/lib/inferno/apps/web/serializers/test.rb +3 -6
  19. data/lib/inferno/apps/web/serializers/test_group.rb +5 -8
  20. data/lib/inferno/apps/web/serializers/test_run.rb +1 -0
  21. data/lib/inferno/apps/web/serializers/test_session.rb +1 -1
  22. data/lib/inferno/apps/web/serializers/test_suite.rb +1 -0
  23. data/lib/inferno/config/application.rb +8 -2
  24. data/lib/inferno/config/boot/db.rb +3 -2
  25. data/lib/inferno/config/boot/logging.rb +2 -0
  26. data/lib/inferno/config/boot/sidekiq.rb +11 -0
  27. data/lib/inferno/config/boot/suites.rb +4 -6
  28. data/lib/inferno/config/boot.rb +2 -0
  29. data/lib/inferno/db/migrations/001_create_initial_structure.rb +0 -21
  30. data/lib/inferno/db/migrations/002_add_wait_support.rb +7 -0
  31. data/lib/inferno/db/migrations/003_update_session_data.rb +18 -0
  32. data/lib/inferno/db/migrations/004_add_request_results_table.rb +9 -0
  33. data/lib/inferno/db/migrations/005_add_updated_at_index_to_results.rb +5 -0
  34. data/lib/inferno/db/schema.rb +154 -0
  35. data/lib/inferno/dsl/assertions.rb +85 -0
  36. data/lib/inferno/dsl/configurable.rb +126 -0
  37. data/lib/inferno/dsl/fhir_client.rb +8 -6
  38. data/lib/inferno/dsl/fhir_client_builder.rb +19 -3
  39. data/lib/inferno/dsl/fhir_validation.rb +1 -1
  40. data/lib/inferno/dsl/http_client.rb +14 -12
  41. data/lib/inferno/dsl/http_client_builder.rb +3 -3
  42. data/lib/inferno/dsl/request_storage.rb +34 -13
  43. data/lib/inferno/dsl/results.rb +49 -0
  44. data/lib/inferno/dsl/resume_test_route.rb +89 -0
  45. data/lib/inferno/dsl/runnable.rb +183 -28
  46. data/lib/inferno/dsl.rb +1 -3
  47. data/lib/inferno/entities/header.rb +14 -7
  48. data/lib/inferno/entities/message.rb +16 -6
  49. data/lib/inferno/entities/request.rb +59 -20
  50. data/lib/inferno/entities/result.rb +45 -22
  51. data/lib/inferno/entities/session_data.rb +39 -0
  52. data/lib/inferno/entities/test.rb +48 -8
  53. data/lib/inferno/entities/test_group.rb +8 -0
  54. data/lib/inferno/entities/test_run.rb +36 -6
  55. data/lib/inferno/entities/test_session.rb +17 -11
  56. data/lib/inferno/entities.rb +1 -1
  57. data/lib/inferno/exceptions.rb +24 -0
  58. data/lib/inferno/jobs/execute_test_run.rb +14 -0
  59. data/lib/inferno/jobs/resume_test_run.rb +14 -0
  60. data/lib/inferno/jobs.rb +16 -0
  61. data/lib/inferno/public/bundle.js +1 -1
  62. data/lib/inferno/repositories/in_memory_repository.rb +1 -1
  63. data/lib/inferno/repositories/repository.rb +13 -0
  64. data/lib/inferno/repositories/requests.rb +5 -4
  65. data/lib/inferno/repositories/results.rb +151 -3
  66. data/lib/inferno/repositories/session_data.rb +47 -0
  67. data/lib/inferno/repositories/test_runs.rb +81 -0
  68. data/lib/inferno/spec_support.rb +1 -1
  69. data/lib/inferno/test_runner.rb +126 -32
  70. data/lib/inferno/utils/markdown_formatter.rb +15 -0
  71. data/lib/inferno/utils/middleware/request_logger.rb +17 -4
  72. data/lib/inferno/utils/migration.rb +17 -0
  73. data/lib/inferno/version.rb +1 -1
  74. data/lib/inferno.rb +4 -4
  75. data/spec/factories/request.rb +14 -7
  76. data/spec/factories/result.rb +8 -0
  77. data/spec/factories/test_run.rb +2 -0
  78. metadata +84 -7
  79. data/bin/inferno-console +0 -8
  80. data/lib/inferno/dsl/fhir_manipulation.rb +0 -25
  81. data/lib/inferno/entities/test_input.rb +0 -20
@@ -38,13 +38,14 @@ module Inferno
38
38
 
39
39
  # TODO: do a check in the test runner
40
40
  def named_request(name)
41
- requests.find { |request| request.name == name.to_sym }
41
+ requests.find { |request| request.name == self.class.config.request_name(name.to_sym) }
42
42
  end
43
43
 
44
- # @api private
44
+ # @private
45
45
  def store_request(direction, name = nil, &block)
46
46
  response = block.call
47
47
 
48
+ name = self.class.config.request_name(name)
48
49
  request =
49
50
  if response.is_a? FHIR::ClientReply
50
51
  Entities::Request.from_fhir_client_reply(
@@ -60,40 +61,60 @@ module Inferno
60
61
  request
61
62
  end
62
63
 
63
- # @api private
64
+ # @private
64
65
  def load_named_requests
65
66
  requests_repo = Inferno::Repositories::Requests.new
66
67
  self.class.named_requests_used.map do |request_name|
67
- request = requests_repo.find_named_request(test_session_id, request_name)
68
- raise StandardError, "Unable to find '#{request_name}' request" if request.nil?
68
+ request_alias = self.class.config.request_name(request_name)
69
+ request = requests_repo.find_named_request(test_session_id, request_alias)
70
+ raise StandardError, "Unable to find '#{request_alias}' request" if request.nil?
69
71
 
70
72
  requests << request
71
73
  end
72
74
  end
73
75
 
74
76
  module ClassMethods
75
- # @api private
77
+ # @private
76
78
  def named_requests_made
77
79
  @named_requests_made ||= []
78
80
  end
79
81
 
80
- # @api private
82
+ # @private
81
83
  def named_requests_used
82
84
  @named_requests_used ||= []
83
85
  end
84
86
 
85
87
  # Specify the named requests made by a test
86
88
  #
87
- # @param *names [Symbol] one or more Symbols
88
- def makes_request(*names)
89
- named_requests_made.concat(names)
89
+ # @param identifiers [Symbol] one or more request identifiers
90
+ def makes_request(*identifiers)
91
+ named_requests_made.concat(identifiers).uniq!
92
+ identifiers.each do |identifier|
93
+ config.add_request(identifier)
94
+ end
95
+ end
96
+
97
+ # Specify the name for a request received by a test
98
+ #
99
+ # @param identifier [Symbol]
100
+ def receives_request(identifier)
101
+ config.add_request(identifier)
102
+ @incoming_request_name = identifier
103
+ end
104
+
105
+ # @private
106
+ def incoming_request_name
107
+ @incoming_request_name
90
108
  end
91
109
 
92
110
  # Specify the named requests used by a test
93
111
  #
94
- # @param *names [Symbol] one or more Symbols
95
- def uses_request(*names)
96
- named_requests_used.concat(names)
112
+ # @param identifiers [Symbol] one or more request identifiers
113
+ def uses_request(*identifiers)
114
+ named_requests_used.concat(identifiers).uniq!
115
+ identifiers.each do |identifier|
116
+ config.add_request(identifier)
117
+ end
97
118
  end
98
119
  end
99
120
  end
@@ -49,6 +49,55 @@ module Inferno
49
49
  def omit_if(test, message = '')
50
50
  raise Exceptions::OmitException, message if test
51
51
  end
52
+
53
+ # Halt execution of the current test and wait for execution to resume.
54
+ #
55
+ # @see Inferno::DSL::Runnable#resume_test_route
56
+ # @example
57
+ # resume_test_route :get, '/launch' do
58
+ # request.query_parameters['iss']
59
+ # end
60
+ #
61
+ # test do
62
+ # input :issuer
63
+ # receives_request :launch
64
+ #
65
+ # run do
66
+ # wait(
67
+ # identifier: issuer,
68
+ # message: "Wating to receive a request with an issuer of #{issuer}"
69
+ # )
70
+ # end
71
+ # end
72
+ # @param identifier [String] An identifier which can uniquely identify
73
+ # this test run based on an incoming request. This is necessary so that
74
+ # the correct test run can be resumed.
75
+ # @param message [String]
76
+ # @param timeout [Integer] Number of seconds to wait for an incoming
77
+ # request
78
+ def wait(identifier:, message: '', timeout: 300)
79
+ identifier(identifier)
80
+ wait_timeout(timeout)
81
+
82
+ raise Exceptions::WaitException, message
83
+ end
84
+
85
+ def identifier(identifier = nil)
86
+ @identifier ||= identifier
87
+ end
88
+
89
+ def wait_timeout(timeout = nil)
90
+ @wait_timeout ||= timeout
91
+ end
92
+
93
+ # Halt execution of the current test. This provided for testing purposes
94
+ # and should not be used in real tests.
95
+ #
96
+ # @param message [String]
97
+ # @private
98
+ def cancel(message = '')
99
+ raise Exceptions::CancelException, message
100
+ end
52
101
  end
53
102
  end
54
103
  end
@@ -0,0 +1,89 @@
1
+ require 'hanami-controller'
2
+
3
+ module Inferno
4
+ module DSL
5
+ # A base class for creating routes to resume test execution upon receiving
6
+ # an incoming request.
7
+ # @private
8
+ # @see Inferno::DSL::Runnable#resume_test_route
9
+ class ResumeTestRoute
10
+ include Hanami::Action
11
+ include Import[
12
+ requests_repo: 'repositories.requests',
13
+ results_repo: 'repositories.results',
14
+ test_runs_repo: 'repositories.test_runs',
15
+ tests_repo: 'repositories.tests'
16
+ ]
17
+
18
+ def self.call(params)
19
+ new.call(params)
20
+ end
21
+
22
+ # The incoming request
23
+ #
24
+ # @return [Inferno::Entities::Request]
25
+ def request
26
+ @request ||= Inferno::Entities::Request.from_rack_env(@params.env)
27
+ end
28
+
29
+ # @private
30
+ def test_run
31
+ @test_run ||=
32
+ test_runs_repo.find_latest_waiting_by_identifier(test_run_identifier)
33
+ end
34
+
35
+ # @private
36
+ def waiting_result
37
+ @waiting_result ||= results_repo.find_waiting_result(test_run_id: test_run.id)
38
+ end
39
+
40
+ # @private
41
+ def update_result
42
+ results_repo.pass_waiting_result(waiting_result.id)
43
+ end
44
+
45
+ # @private
46
+ def persist_request
47
+ requests_repo.create(
48
+ request.to_hash.merge(
49
+ test_session_id: test_run.test_session_id,
50
+ result_id: waiting_result.id,
51
+ name: test.config.request_name(test.incoming_request_name)
52
+ )
53
+ )
54
+ end
55
+
56
+ # @private
57
+ def redirect_route
58
+ "/test_sessions/#{test_run.test_session_id}##{waiting_group_id}"
59
+ end
60
+
61
+ # @private
62
+ def test
63
+ @test ||= tests_repo.find(waiting_result.test_id)
64
+ end
65
+
66
+ # @private
67
+ def waiting_group_id
68
+ test.parent.id
69
+ end
70
+
71
+ # @private
72
+ def call(_params)
73
+ if test_run.nil?
74
+ status(500, "Unable to find test run with identifier '#{test_run_identifier}'.")
75
+ return
76
+ end
77
+
78
+ test_runs_repo.mark_as_no_longer_waiting(test_run.id)
79
+
80
+ update_result
81
+ persist_request
82
+
83
+ Jobs.perform(Jobs::ResumeTestRun, test_run.id)
84
+
85
+ redirect_to redirect_route
86
+ end
87
+ end
88
+ end
89
+ end
@@ -1,3 +1,7 @@
1
+ require_relative 'configurable'
2
+ require_relative 'resume_test_route'
3
+ require_relative '../utils/markdown_formatter'
4
+
1
5
  module Inferno
2
6
  module DSL
3
7
  # This module contains the DSL for defining child entities in the test
@@ -5,14 +9,17 @@ module Inferno
5
9
  module Runnable
6
10
  attr_accessor :parent
7
11
 
12
+ include Inferno::Utils::MarkdownFormatter
13
+
8
14
  # When a class (e.g. TestSuite/TestGroup) uses this module, set it up
9
15
  # so that subclassing it works correctly.
10
16
  # - add the subclass to the relevant repository when it is created
11
17
  # - copy the class instance variables from the superclass
12
18
  # - add a hook to the subclass so that its subclasses do the same
13
- # @api private
19
+ # @private
14
20
  def self.extended(extending_class)
15
21
  super
22
+ extending_class.extend Configurable
16
23
 
17
24
  extending_class.define_singleton_method(:inherited) do |subclass|
18
25
  copy_instance_variables(subclass)
@@ -34,14 +41,16 @@ module Inferno
34
41
  # classes. When inheriting from a Runnable class, these class instance
35
42
  # variables need to be copied. Any child Runnable classes will themselves
36
43
  # need to be subclassed so that their parent can be updated.
37
- # @api private
44
+ # @private
38
45
  def copy_instance_variables(subclass)
39
46
  instance_variables.each do |variable|
40
- next if [:@id, :@groups, :@tests, :@parent, :@children].include?(variable)
47
+ next if [:@id, :@groups, :@tests, :@parent, :@children, :@test_count, :@config].include?(variable)
41
48
 
42
49
  subclass.instance_variable_set(variable, instance_variable_get(variable).dup)
43
50
  end
44
51
 
52
+ subclass.config(config)
53
+
45
54
  child_types.each do |child_type|
46
55
  new_children = send(child_type).map do |child|
47
56
  Class.new(child).tap do |subclass_child|
@@ -54,12 +63,13 @@ module Inferno
54
63
  end
55
64
  end
56
65
 
57
- # @api private
66
+ # @private
58
67
  def add_self_to_repository
59
68
  repository.insert(self)
60
69
  end
61
70
 
62
71
  # An instance of the repository for the class using this module
72
+ # @private
63
73
  def repository
64
74
  nil
65
75
  end
@@ -67,7 +77,7 @@ module Inferno
67
77
  # This method defines a child entity. Classes using this module should
68
78
  # alias the method name they wish to use to define child entities to this
69
79
  # method.
70
- # @api private
80
+ # @private
71
81
  def define_child(*args, &block)
72
82
  hash_args = process_args(args)
73
83
 
@@ -87,7 +97,7 @@ module Inferno
87
97
  klass
88
98
  end
89
99
 
90
- # @api private
100
+ # @private
91
101
  def process_args(args)
92
102
  hash_args =
93
103
  if args[0].is_a? Hash
@@ -103,13 +113,13 @@ module Inferno
103
113
  hash_args
104
114
  end
105
115
 
106
- # @api private
116
+ # @private
107
117
  def child_metadata(metadata = nil)
108
118
  @child_metadata = metadata if metadata
109
119
  @child_metadata
110
120
  end
111
121
 
112
- # @api private
122
+ # @private
113
123
  def create_child_class(hash_args)
114
124
  superclass_id = hash_args.delete :from
115
125
 
@@ -122,18 +132,18 @@ module Inferno
122
132
  Class.new(superclass)
123
133
  end
124
134
 
125
- # @api private
135
+ # @private
126
136
  def configure_child_class(klass, hash_args) # rubocop:disable Metrics/CyclomaticComplexity
127
- inputs.each do |input_definition|
128
- next if klass.inputs.include? input_definition
137
+ inputs.each do |name|
138
+ next if klass.inputs.any? { |klass_input_name| klass_input_name == name }
129
139
 
130
- klass.input input_definition
140
+ klass.input name
131
141
  end
132
142
 
133
- outputs.each do |output_definition|
134
- next if klass.outputs.include? output_definition
143
+ outputs.each do |output_name|
144
+ next if klass.outputs.include? output_name
135
145
 
136
- klass.output output_definition
146
+ klass.output output_name
137
147
  end
138
148
 
139
149
  new_fhir_client_definitions = klass.instance_variable_get(:@fhir_client_definitions) || {}
@@ -152,8 +162,14 @@ module Inferno
152
162
  end
153
163
  klass.instance_variable_set(:@http_client_definitions, new_http_client_definitions)
154
164
 
165
+ klass.config(config)
166
+
155
167
  hash_args.each do |key, value|
156
- klass.send(key, *value)
168
+ if value.is_a? Array
169
+ klass.send(key, *value)
170
+ else
171
+ klass.send(key, value)
172
+ end
157
173
  end
158
174
 
159
175
  klass.children.each do |child_class|
@@ -162,11 +178,15 @@ module Inferno
162
178
  end
163
179
  end
164
180
 
165
- # @api private
181
+ # @private
166
182
  def handle_child_definition_block(klass, &block)
167
183
  klass.class_eval(&block) if block_given?
168
184
  end
169
185
 
186
+ # Set/Get a runnable's id
187
+ #
188
+ # @param new_id [String,Symbol]
189
+ # @return [String,Symbol] the id
170
190
  def id(new_id = nil)
171
191
  return @id if new_id.nil? && @id.present?
172
192
 
@@ -182,53 +202,93 @@ module Inferno
182
202
  @id = "#{prefix}#{@base_id}"
183
203
  end
184
204
 
205
+ # Set/Get a runnable's title
206
+ #
207
+ # @param new_title [String]
208
+ # @return [String] the title
185
209
  def title(new_title = nil)
186
210
  return @title if new_title.nil?
187
211
 
188
212
  @title = new_title
189
213
  end
190
214
 
215
+ # Set/Get a runnable's description
216
+ #
217
+ # @param new_description [String]
218
+ # @return [String] the description
191
219
  def description(new_description = nil)
192
220
  return @description if new_description.nil?
193
221
 
194
- @description = new_description
222
+ @description = format_markdown(new_description)
195
223
  end
196
224
 
197
225
  # Define inputs
198
226
  #
199
- # @param inputs [Symbol]
227
+ # @param identifier [Symbol] identifier for the input
228
+ # @param other_identifiers [Symbol] array of symbols if specifying multiple inputs
229
+ # @param input_definition [Hash] options for input such as type, description, or title
230
+ # @option input_definition [String] :title Human readable title for input
231
+ # @option input_definition [String] :description Description for the input
232
+ # @option input_definition [String] :type text | textarea
233
+ # @option input_definition [String] :default The default value for the input
234
+ # @option input_definition [Boolean] :optional Set to true to not require input for test execution
200
235
  # @return [void]
201
236
  # @example
202
- # input :patient_id, :bearer_token
203
- def input(*input_definitions)
204
- inputs.concat(input_definitions)
237
+ # input :patientid, title: 'Patient ID', description: 'The ID of the patient being searched for',
238
+ # default: 'default_patient_id'
239
+ # @example
240
+ # input :textarea, title: 'Textarea Input Example', type: 'textarea', optional: true
241
+ def input(identifier, *other_identifiers, **input_definition)
242
+ if other_identifiers.present?
243
+ [identifier, *other_identifiers].compact.each do |input_identifier|
244
+ inputs << input_identifier
245
+ config.add_input(input_identifier)
246
+ end
247
+ else
248
+ inputs << identifier
249
+ config.add_input(identifier, input_definition)
250
+ end
205
251
  end
206
252
 
207
253
  # Define outputs
208
254
  #
209
- # @param output_definitions [Symbol]
255
+ # @param output_list [Symbol]
210
256
  # @return [void]
211
257
  # @example
212
258
  # output :patient_id, :bearer_token
213
- def output(*output_definitions)
214
- outputs.concat(output_definitions)
259
+ def output(*output_list)
260
+ output_list.each do |output_identifier|
261
+ outputs << output_identifier
262
+ config.add_output(output_identifier)
263
+ end
215
264
  end
216
265
 
217
- # @api private
266
+ # @private
218
267
  def default_id
219
268
  to_s
220
269
  end
221
270
 
222
- # @api private
271
+ # @private
223
272
  def inputs
224
273
  @inputs ||= []
225
274
  end
226
275
 
227
- # @api private
276
+ # @private
277
+ def input_definitions
278
+ config.inputs.slice(*inputs)
279
+ end
280
+
281
+ # @private
282
+ def output_definitions
283
+ config.outputs.slice(*outputs)
284
+ end
285
+
286
+ # @private
228
287
  def outputs
229
288
  @outputs ||= []
230
289
  end
231
290
 
291
+ # @private
232
292
  def child_types
233
293
  return [] if ancestors.include? Inferno::Entities::Test
234
294
  return [:groups] if ancestors.include? Inferno::Entities::TestSuite
@@ -236,6 +296,7 @@ module Inferno
236
296
  [:groups, :tests]
237
297
  end
238
298
 
299
+ # @private
239
300
  def children
240
301
  @children ||= []
241
302
  end
@@ -245,6 +306,100 @@ module Inferno
245
306
 
246
307
  @validator_url = url
247
308
  end
309
+
310
+ # @private
311
+ def suite
312
+ return self if ancestors.include? Inferno::Entities::TestSuite
313
+
314
+ parent.suite
315
+ end
316
+
317
+ # Create a route which will resume a test run when a request is received
318
+ #
319
+ # @see Inferno::DSL::Results#wait
320
+ # @example
321
+ # resume_test_route :get, '/launch' do
322
+ # request.query_parameters['iss']
323
+ # end
324
+ #
325
+ # test do
326
+ # input :issuer
327
+ # receives_request :launch
328
+ #
329
+ # run do
330
+ # wait(
331
+ # identifier: issuer,
332
+ # message: "Wating to receive a request with an issuer of #{issuer}"
333
+ # )
334
+ # end
335
+ # end
336
+ #
337
+ # @param method [Symbol] the HTTP request type (:get, :post, etc.) for the
338
+ # incoming request
339
+ # @param path [String] the path for this request. The route will be served
340
+ # with a prefix of `/custom/TEST_SUITE_ID` to prevent path conflicts.
341
+ # [Any of the path options available in Hanami
342
+ # Router](https://github.com/hanami/router/tree/f41001d4c3ee9e2d2c7bb142f74b43f8e1d3a265#a-beautiful-dsl)
343
+ # can be used here.
344
+ # @yield This method takes a block which must return the identifier
345
+ # defined when a test was set to wait for the test run that hit this
346
+ # route. The block has access to the `request` method which returns a
347
+ # {Inferno::Entities::Request} object with the information for the
348
+ # incoming request.
349
+ def resume_test_route(method, path, &block)
350
+ route_class = Class.new(ResumeTestRoute) do
351
+ define_method(:test_run_identifier, &block)
352
+ define_method(:request_name, -> { options[:name] })
353
+ end
354
+
355
+ route(method, path, route_class)
356
+ end
357
+
358
+ # Create a route to handle a request
359
+ #
360
+ # @param method [Symbol] the HTTP request type (:get, :post, etc.) for the
361
+ # incoming request. `:all` will accept all HTTP request types.
362
+ # @param path [String] the path for this request. The route will be served
363
+ # with a prefix of `/custom/TEST_SUITE_ID` to prevent path conflicts.
364
+ # [Any of the path options available in Hanami
365
+ # Router](https://github.com/hanami/router/tree/f41001d4c3ee9e2d2c7bb142f74b43f8e1d3a265#a-beautiful-dsl)
366
+ # can be used here.
367
+ # @param handler [#call] the route handler. This can be any Rack
368
+ # compatible object (e.g. a `Proc` object, a [Sinatra
369
+ # app](http://sinatrarb.com/)) as described in the [Hanami Router
370
+ # documentation.](https://github.com/hanami/router/tree/f41001d4c3ee9e2d2c7bb142f74b43f8e1d3a265#mount-rack-applications)
371
+ def route(method, path, handler)
372
+ Inferno.routes << { method: method, path: path, handler: handler, suite: suite }
373
+ end
374
+
375
+ # @private
376
+ def test_count
377
+ @test_count ||= children&.reduce(0) { |sum, child| sum + child.test_count } || 0
378
+ end
379
+
380
+ # @private
381
+ def required_inputs(prior_outputs = [])
382
+ required_inputs = inputs.select do |input|
383
+ !input_definitions[input][:optional] && !prior_outputs.include?(input)
384
+ end
385
+ required_inputs.map! { |input_identifier| input_definitions[input_identifier][:name] }
386
+ children_required_inputs = children.flat_map { |child| child.required_inputs(prior_outputs) }
387
+ prior_outputs.concat(outputs)
388
+ (required_inputs + children_required_inputs).flatten.uniq
389
+ end
390
+
391
+ # @private
392
+ def missing_inputs(submitted_inputs)
393
+ submitted_inputs = [] if submitted_inputs.nil?
394
+
395
+ required_inputs.map(&:to_s) - submitted_inputs.map { |input| input[:name] }
396
+ end
397
+
398
+ def user_runnable?
399
+ @user_runnable ||= parent.nil? ||
400
+ !parent.respond_to?(:run_as_group?) ||
401
+ (parent.user_runnable? && !parent.run_as_group?)
402
+ end
248
403
  end
249
404
  end
250
405
  end
data/lib/inferno/dsl.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  require_relative 'dsl/assertions'
2
2
  require_relative 'dsl/fhir_client'
3
- require_relative 'dsl/fhir_manipulation'
4
3
  require_relative 'dsl/fhir_validation'
5
4
  require_relative 'dsl/http_client'
6
5
  require_relative 'dsl/results'
@@ -14,8 +13,7 @@ module Inferno
14
13
  FHIRClient,
15
14
  HTTPClient,
16
15
  Results,
17
- FHIRValidation,
18
- FHIRManipulation
16
+ FHIRValidation
19
17
  ].freeze
20
18
 
21
19
  EXTENDABLE_DSL_MODULES = [
@@ -2,13 +2,20 @@ module Inferno
2
2
  module Entities
3
3
  # A `Header` represents an HTTP request/response header
4
4
  #
5
- # @attr_reader [String] id of the header
6
- # @attr_reader [String] request_id index of the HTTP request
7
- # @attr_reader [String] name header name
8
- # @attr_reader [String] value header value
9
- # @attr_reader [String] type request/response
10
- # @attr_reader [Time] created_at
11
- # @attr_reader [Time] updated_at
5
+ # @!attribute id
6
+ # @return [String] id of the header
7
+ # @!attribute request_id
8
+ # @return [String] index of the HTTP request
9
+ # @!attribute name
10
+ # @return [String] header name
11
+ # @!attribute value
12
+ # @return [String] header value
13
+ # @!attribute type
14
+ # @return [String] request/response
15
+ # @!attribute created_at
16
+ # @return [Time]
17
+ # @!attribute updated_at
18
+ # @return [Time]
12
19
  class Header < Entity
13
20
  ATTRIBUTES = [:id, :request_id, :name, :type, :value, :created_at, :updated_at].freeze
14
21
 
@@ -2,12 +2,22 @@ module Inferno
2
2
  module Entities
3
3
  # A `Message` represents a message generated during a test.
4
4
  #
5
- # @attr_reader [String] id of the message
6
- # @attr_reader [String] index of the message. Used for ordering.
7
- # @attr_reader [String] result_id
8
- # @attr_reader [Inferno::Entities::Result] result
9
- # @attr_reader [String] type
10
- # @attr_reader [String] message
5
+ # @!attribute id
6
+ # @return [String] id of the message
7
+ # @!attribute index
8
+ # @return [String] index of the message. Used for ordering.
9
+ # @!attribute result_id
10
+ # @return [String]
11
+ # @!attribute result
12
+ # @return [Inferno::Entities::Result]
13
+ # @!attribute type
14
+ # @return [String]
15
+ # @!attribute message
16
+ # @return [String]
17
+ # @!attribute created_at
18
+ # @return [Time]
19
+ # @!attribute updated_at
20
+ # @return [Time]
11
21
  class Message < Entity
12
22
  ATTRIBUTES = [:id, :index, :message, :result_id, :result, :type, :created_at, :updated_at].freeze
13
23
  TYPES = ['error', 'warning', 'info'].freeze