inferno_core 0.1.0 → 0.1.2

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: 9b9bcb584c21004b00bc1ebb9fa2cce3b89f55bd7cb8f1565a9a29242e293e2b
4
- data.tar.gz: b8a2e7ad09a42bb802289859ca6d48ba1c5473cd0553230a53563063b44c2194
3
+ metadata.gz: b15a9d2a0905bfb338974e70ceb0045a096b76dcc1cf795490f2f8b90231016b
4
+ data.tar.gz: 86d7bb32e8ca9a5e56983be39f3e4d7b177237b59624d2c7ac2e45d7cc7f0725
5
5
  SHA512:
6
- metadata.gz: 51d1cfeeed361f0b1647568ed179b9f45eeadb26b635d21fbd59a8d314f9a85141fd8e64d4dce5453fde0d61866b0c55fb6dcac9529caf379af507f7cefaa20c
7
- data.tar.gz: a9479200fa536bf1031d03f47dfda90885caa4135a5aa195de74d9302b2dd8a3ebfefa3ad6b0a265fa24d29bc3ac40fde3ec0e32089cd085a8648dc6ce73274c
6
+ metadata.gz: '090c15c98e9d555cf8ca4c17d7ac246d74effed1463f87ffe6ff3aa1f9f415798a7758b9d8df45713f46bfb586e81c78e87fa32535426372c3a4ee952c5fb353'
7
+ data.tar.gz: b76a85e0633115721f1033724c62e6910a6666bd5f47510f454666da7aff744970b871ea25f7fa216837d14c42fdc94c563cd22a4a6e9d151a36d92af7211bee
@@ -0,0 +1,39 @@
1
+ module Inferno
2
+ module Web
3
+ module Controllers
4
+ module TestRuns
5
+ class Destroy < Controller
6
+ include Import[
7
+ test_runs_repo: 'repositories.test_runs',
8
+ results_repo: 'repositories.results'
9
+ ]
10
+
11
+ def call(params)
12
+ test_run = test_runs_repo.find(params[:id])
13
+
14
+ if test_run.nil? || ['done', 'cancelling'].include?(test_run.status)
15
+ # If it doesn't exist, already finished, or currently being cancelled
16
+ self.status = 204
17
+ return
18
+ end
19
+
20
+ test_run_is_waiting = (test_run.status == 'waiting')
21
+ test_runs_repo.mark_as_cancelling(params[:id])
22
+
23
+ if test_run_is_waiting
24
+ waiting_result = results_repo.find_waiting_result(test_run_id: test_run.id)
25
+ results_repo.cancel_waiting_result(waiting_result.id, 'Test cancelled by user')
26
+ Jobs.perform(Jobs::ResumeTestRun, test_run.id)
27
+ end
28
+
29
+ self.status = 204
30
+ rescue StandardError => e
31
+ Application['logger'].error(e.full_message)
32
+ self.body = { errors: e.message }.to_json
33
+ self.status = 500
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -7,7 +7,7 @@ module Inferno
7
7
 
8
8
  Router = Hanami::Router.new(namespace: Inferno::Web::Controllers) do
9
9
  namespace 'api' do
10
- resources 'test_runs', only: [:create, :show] do
10
+ resources 'test_runs', only: [:create, :show, :destroy] do
11
11
  resources 'results', only: [:index]
12
12
  end
13
13
 
@@ -16,6 +16,7 @@ module Inferno
16
16
  field :result_message, if: :field_present?
17
17
  field :created_at
18
18
  field :updated_at
19
+ field :optional?, name: :optional
19
20
 
20
21
  field :outputs do |result, _options|
21
22
  result.output_json.present? ? JSON.parse(result.output_json) : []
@@ -4,10 +4,14 @@ module Inferno
4
4
  class Test < Serializer
5
5
  identifier :id
6
6
  field :title
7
+ field :short_title
7
8
  field :input_definitions, name: :inputs, extractor: HashValueExtractor, blueprint: Input
8
9
  field :output_definitions, name: :outputs, extractor: HashValueExtractor
9
10
  field :description
11
+ field :short_description
12
+ field :input_instructions
10
13
  field :user_runnable?, name: :user_runnable
14
+ field :optional?, name: :optional
11
15
  end
12
16
  end
13
17
  end
@@ -5,10 +5,14 @@ module Inferno
5
5
  identifier :id
6
6
 
7
7
  field :title
8
+ field :short_title
8
9
  field :description
10
+ field :short_description
11
+ field :input_instructions
9
12
  field :test_count
10
13
  field :run_as_group?, name: :run_as_group
11
14
  field :user_runnable?, name: :user_runnable
15
+ field :optional?, name: :optional
12
16
 
13
17
  association :groups, name: :test_groups, blueprint: TestGroup
14
18
  association :tests, blueprint: Test
@@ -5,7 +5,10 @@ module Inferno
5
5
  view :summary do
6
6
  identifier :id
7
7
  field :title
8
+ field :short_title
8
9
  field :description
10
+ field :short_description
11
+ field :input_instructions
9
12
  field :test_count
10
13
  end
11
14
 
@@ -13,6 +13,10 @@ module Inferno
13
13
  return @config if new_configuration.blank?
14
14
 
15
15
  @config.apply(new_configuration)
16
+
17
+ children.each { |child| child.config(new_configuration) }
18
+
19
+ @config
16
20
  end
17
21
 
18
22
  # @private
@@ -131,6 +131,20 @@ module Inferno
131
131
  end
132
132
  end
133
133
 
134
+ # Perform a FHIR delete interaction.
135
+ #
136
+ # @param resource_type [String, Symbol, Class]
137
+ # @param id [String]
138
+ # @param client [Symbol]
139
+ # @param name [Symbol] Name for this request to allow it to be used by
140
+ # other tests
141
+ # @return [Inferno::Entities::Request]
142
+ def fhir_delete(resource_type, id, client: :default, name: nil)
143
+ store_request('outgoing', name) do
144
+ fhir_client(client).destroy(fhir_class_from_resource_type(resource_type), id)
145
+ end
146
+ end
147
+
134
148
  # @todo Make this a FHIR class method? Something like
135
149
  # FHIR.class_for(resource_type)
136
150
  # @api private
@@ -103,6 +103,68 @@ module Inferno
103
103
  end
104
104
  end
105
105
 
106
+ # Perform an HTTP DELETE request
107
+ #
108
+ # @param url [String] if this request is using a defined client, this will
109
+ # be appended to the client's url. Must be an absolute url for requests
110
+ # made without a defined client
111
+ # @param client [Symbol]
112
+ # @param name [Symbol] Name for this request to allow it to be used by
113
+ # other tests
114
+ # @return [Inferno::Entities::Request]
115
+ def delete(url = '', client: :default, name: :nil, **options)
116
+ 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
+ end
126
+ end
127
+ end
128
+
129
+ # Perform an HTTP GET request and stream the response
130
+ #
131
+ # @param block [Proc] A Proc object whose input will be the string chunks
132
+ # received while streaming response to the get request.
133
+ # @param url [String] If this request is using a defined client, this will
134
+ # be appended to the client's url. Must be an absolute url for requests
135
+ # made without a defined client
136
+ # @param limit [Integer] The number of streamed-in chunks to be stored in
137
+ # the response body. This optional input defaults to 100.
138
+ # @param client [Symbol]
139
+ # @param name [Symbol] Name for this request to allow it to be used by
140
+ # other tests
141
+ # @option options [Hash] Input headers here - headers are optional and
142
+ # must be entered as the last piece of input to this method
143
+ # @return [Inferno::Entities::Request]
144
+ def stream(block, url = '', limit = 100, client: :default, name: nil, **options)
145
+ streamed = []
146
+
147
+ collector = proc do |chunk, bytes|
148
+ streamed << chunk if limit.positive?
149
+ limit -= 1
150
+ block.call(chunk, bytes)
151
+ end
152
+
153
+ 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'
162
+ end
163
+ response.env.body = streamed.join
164
+ response
165
+ end
166
+ end
167
+
106
168
  module ClassMethods
107
169
  # @private
108
170
  def http_client_definitions
@@ -85,7 +85,6 @@ module Inferno
85
85
 
86
86
  klass.parent = self
87
87
 
88
- child_metadata[:collection] << klass
89
88
  children << klass
90
89
 
91
90
  configure_child_class(klass, hash_args)
@@ -164,6 +163,8 @@ module Inferno
164
163
 
165
164
  klass.config(config)
166
165
 
166
+ klass.children.select!(&:required?) if hash_args.delete(:exclude_optional)
167
+
167
168
  hash_args.each do |key, value|
168
169
  if value.is_a? Array
169
170
  klass.send(key, *value)
@@ -212,6 +213,16 @@ module Inferno
212
213
  @title = new_title
213
214
  end
214
215
 
216
+ # Set/Get a runnable's short title
217
+ #
218
+ # @param new_short_title [String]
219
+ # @return [String] the short title
220
+ def short_title(new_short_title = nil)
221
+ return @short_title if new_short_title.nil?
222
+
223
+ @short_title = new_short_title
224
+ end
225
+
215
226
  # Set/Get a runnable's description
216
227
  #
217
228
  # @param new_description [String]
@@ -222,6 +233,26 @@ module Inferno
222
233
  @description = format_markdown(new_description)
223
234
  end
224
235
 
236
+ # Set/Get a runnable's short one-sentence description
237
+ #
238
+ # @param new_short_description [String]
239
+ # @return [String] the one-sentence description
240
+ def short_description(new_short_description = nil)
241
+ return @short_description if new_short_description.nil?
242
+
243
+ @short_description = format_markdown(new_short_description)
244
+ end
245
+
246
+ # Set/Get a runnable's input instructions
247
+ #
248
+ # @param new_input_instructions [String]
249
+ # @return [String] the input instructions
250
+ def input_instructions(new_input_instructions = nil)
251
+ return @input_instructions if new_input_instructions.nil?
252
+
253
+ @input_instructions = format_markdown(new_input_instructions)
254
+ end
255
+
225
256
  # Define inputs
226
257
  #
227
258
  # @param identifier [Symbol] identifier for the input
@@ -252,6 +283,40 @@ module Inferno
252
283
  end
253
284
  end
254
285
 
286
+ # Mark as optional. Tests are required by default.
287
+ #
288
+ # @param optional [Boolean]
289
+ # @return [void]
290
+ #
291
+ def optional(optional = true) # rubocop:disable Style/OptionalBooleanParameter
292
+ @optional = optional
293
+ end
294
+
295
+ # Mark as required
296
+ #
297
+ # Tests are required by default. This method is provided to make an
298
+ # existing optional test required.
299
+ #
300
+ # @param required[Boolean]
301
+ # @return [void]
302
+ def required(required = true) # rubocop:disable Style/OptionalBooleanParameter
303
+ @optional = !required
304
+ end
305
+
306
+ # The test or group is optional if true
307
+ #
308
+ # @return [Boolean]
309
+ def optional?
310
+ !!@optional
311
+ end
312
+
313
+ # The test or group is required if true
314
+ #
315
+ # @return [Boolean]
316
+ def required?
317
+ !optional?
318
+ end
319
+
255
320
  # Define outputs
256
321
  #
257
322
  # @param identifier [Symbol] identifier for the output
@@ -407,6 +472,7 @@ module Inferno
407
472
  required_inputs.map(&:to_s) - submitted_inputs.map { |input| input[:name] }
408
473
  end
409
474
 
475
+ # @private
410
476
  def user_runnable?
411
477
  @user_runnable ||= parent.nil? ||
412
478
  !parent.respond_to?(:run_as_group?) ||
@@ -0,0 +1,26 @@
1
+ module Inferno
2
+ module Entities
3
+ module HasRunnable
4
+ # Returns the Test, TestGroup, or TestSuite associated with this entity
5
+ #
6
+ # @return [Inferno::Entities::Test, Inferno::Entities::TestGroup, Inferno::Entities::TestSuite]
7
+ def runnable
8
+ return @runnable if @runnable
9
+
10
+ @runnable = (test || test_group || test_suite || load_runnable)
11
+ end
12
+
13
+ private
14
+
15
+ def load_runnable
16
+ if test_id.present?
17
+ @test = Inferno::Repositories::Tests.new.find(test_id)
18
+ elsif test_group_id.present?
19
+ @test_group = Inferno::Repositories::TestGroups.new.find(test_group_id)
20
+ elsif test_suite_id.present?
21
+ @test_suite = Inferno::Repositories::TestSuites.new.find(test_suite_id)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -47,9 +47,10 @@ module Inferno
47
47
  :test_session_id, :result, :result_message, :messages, :requests,
48
48
  :input_json, :output_json
49
49
  ].freeze
50
- RESULT_OPTIONS = ['cancel', 'wait', 'running', 'error', 'fail', 'skip', 'omit', 'pass'].freeze
50
+ RESULT_OPTIONS = ['cancel', 'wait', 'running', 'error', 'fail', 'skip', 'pass', 'omit'].freeze
51
51
 
52
52
  include Inferno::Entities::Attributes
53
+ include Inferno::Entities::HasRunnable
53
54
 
54
55
  def initialize(params)
55
56
  super(params, ATTRIBUTES - [:messages, :requests])
@@ -58,9 +59,12 @@ module Inferno
58
59
  @requests = (params[:requests] || []).map { |request| Request.new(request) }
59
60
  end
60
61
 
61
- # @return [Inferno::Entities::Test, Inferno::Entities::TestGroup, Inferno::Entities::TestSuite]
62
- def runnable
63
- test || test_group || test_suite
62
+ def optional?
63
+ runnable.optional?
64
+ end
65
+
66
+ def required?
67
+ !optional?
64
68
  end
65
69
 
66
70
  # @return [Boolean]
@@ -32,11 +32,11 @@ module Inferno
32
32
  end
33
33
 
34
34
  def groups
35
- @groups ||= []
35
+ children.select { |child| child < Inferno::Entities::TestGroup }
36
36
  end
37
37
 
38
38
  def tests
39
- @tests ||= []
39
+ children.select { |child| child < Inferno::Entities::Test }
40
40
  end
41
41
 
42
42
  # Methods to configure Inferno::DSL::Runnable
@@ -54,16 +54,14 @@ module Inferno
54
54
  def group_metadata
55
55
  {
56
56
  class: TestGroup,
57
- repo: repository,
58
- collection: groups
57
+ repo: repository
59
58
  }
60
59
  end
61
60
 
62
61
  def test_metadata
63
62
  {
64
63
  class: Test,
65
- repo: Inferno::Repositories::Tests.new,
66
- collection: tests
64
+ repo: Inferno::Repositories::Tests.new
67
65
  }
68
66
  end
69
67
 
@@ -32,7 +32,7 @@ module Inferno
32
32
  # @return [String, nil] identfier for a waiting `TestRun`
33
33
  # @!attribute wait_timeout
34
34
  class TestRun < Entity
35
- STATUS_OPTIONS = ['queued', 'running', 'waiting', 'done'].freeze
35
+ STATUS_OPTIONS = ['queued', 'running', 'waiting', 'cancelling', 'done'].freeze
36
36
  ATTRIBUTES = [
37
37
  :id,
38
38
  :test_session_id,
@@ -52,6 +52,7 @@ module Inferno
52
52
  ].freeze
53
53
 
54
54
  include Inferno::Entities::Attributes
55
+ include Inferno::Entities::HasRunnable
55
56
 
56
57
  attr_accessor :test_session
57
58
 
@@ -63,12 +64,6 @@ module Inferno
63
64
  @test_session = params[:test_session]
64
65
  end
65
66
 
66
- def runnable
67
- return @runnable if @runnable
68
-
69
- @runnable = (test || test_group || test_suite || load_runnable)
70
- end
71
-
72
67
  def to_hash
73
68
  super.merge(test_session: test_session).compact
74
69
  end
@@ -76,18 +71,6 @@ module Inferno
76
71
  def test_count
77
72
  @test_count ||= runnable.test_count
78
73
  end
79
-
80
- private
81
-
82
- def load_runnable
83
- if test_id.present?
84
- @test = Inferno::Repositories::Tests.new.find(test_id)
85
- elsif test_group_id.present?
86
- @test_group = Inferno::Repositories::TestGroups.new.find(test_group_id)
87
- elsif test_suite_id.present?
88
- @test_suite = Inferno::Repositories::TestSuites.new.find(test_suite_id)
89
- end
90
- end
91
74
  end
92
75
  end
93
76
  end
@@ -22,7 +22,7 @@ module Inferno
22
22
  return @default_group if @default_group
23
23
 
24
24
  @default_group = Class.new(TestGroup)
25
- groups << @default_group
25
+ 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
- @groups ||= []
34
+ children.select { |child| child < Inferno::Entities::TestGroup }
35
35
  end
36
36
 
37
37
  # Methods to configure Inferno::DSL::Runnable
@@ -44,8 +44,7 @@ module Inferno
44
44
  def group_metadata
45
45
  {
46
46
  class: TestGroup,
47
- repo: Inferno::Repositories::TestGroups.new,
48
- collection: groups
47
+ repo: Inferno::Repositories::TestGroups.new
49
48
  }
50
49
  end
51
50
 
@@ -1,4 +1,5 @@
1
1
  require_relative 'entities/attributes'
2
+ require_relative 'entities/has_runnable'
2
3
  require_relative 'entities/entity'
3
4
  require_relative 'entities/header'
4
5
  require_relative 'entities/message'