inferno_core 0.0.5 → 0.0.6
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 +4 -4
- data/lib/inferno/apps/web/controllers/test_runs/create.rb +15 -2
- data/lib/inferno/apps/web/serializers/hash_value_extractor.rb +11 -0
- data/lib/inferno/apps/web/serializers/test.rb +3 -4
- data/lib/inferno/apps/web/serializers/test_group.rb +4 -6
- data/lib/inferno/config/application.rb +1 -0
- data/lib/inferno/config/boot/suites.rb +4 -6
- data/lib/inferno/dsl/assertions.rb +20 -0
- data/lib/inferno/dsl/configurable.rb +126 -0
- data/lib/inferno/dsl/fhir_client.rb +4 -2
- data/lib/inferno/dsl/http_client.rb +10 -8
- data/lib/inferno/dsl/request_storage.rb +21 -12
- data/lib/inferno/dsl/resume_test_route.rb +1 -1
- data/lib/inferno/dsl/runnable.rb +69 -21
- data/lib/inferno/entities/request.rb +2 -2
- data/lib/inferno/entities/test.rb +16 -2
- data/lib/inferno/entities/test_group.rb +8 -0
- data/lib/inferno/exceptions.rb +12 -0
- data/lib/inferno/public/bundle.js +1 -1
- data/lib/inferno/repositories/test_runs.rb +15 -0
- data/lib/inferno/test_runner.rb +20 -18
- data/lib/inferno/utils/markdown_formatter.rb +15 -0
- data/lib/inferno/version.rb +1 -1
- data/spec/factories/request.rb +14 -7
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 40769c54fd3854730eb080d1bb9e0755ff1551b00761968155d463dd3a6ce3e0
|
4
|
+
data.tar.gz: 8bbf5aaa2b09d7d5ff54e56a3ed33ce4e1f4df29fc53e3737f18e9972dc34f1e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 35fe2518d3856f01b3358da68d862318784f05ab067b579d3ac62053dc1deed2be2895e3cfb5ff8efbc97e71d2495a11ebf66eadf23c5b8b4edb502707334838
|
7
|
+
data.tar.gz: 04e37af9daf40c01f0d4182f055e4ddf187d72f0e9d8a43e8858af5c549a4a60900d71f034a8e027e20f53a56f6b5e835bce1fca3a0b98870b07e0681793a2d9
|
@@ -5,7 +5,8 @@ module Inferno
|
|
5
5
|
class Create < Controller
|
6
6
|
include Import[
|
7
7
|
test_sessions_repo: 'repositories.test_sessions',
|
8
|
-
session_data_repo: 'repositories.session_data'
|
8
|
+
session_data_repo: 'repositories.session_data',
|
9
|
+
test_runs_repo: 'repositories.test_runs'
|
9
10
|
]
|
10
11
|
|
11
12
|
PARAMS = [:test_session_id, :test_suite_id, :test_group_id, :test_id].freeze
|
@@ -14,8 +15,18 @@ module Inferno
|
|
14
15
|
test_session = test_sessions_repo.find(params[:test_session_id])
|
15
16
|
|
16
17
|
# if testsession.nil?
|
18
|
+
if test_runs_repo.active_test_run_for_session?(test_session.id)
|
19
|
+
self.status = 409
|
20
|
+
self.body = { error: 'Cannot run new test while another test run is in progress' }.to_json
|
21
|
+
return
|
22
|
+
end
|
17
23
|
|
18
24
|
test_run = repo.create(create_params(params).merge(status: 'queued'))
|
25
|
+
missing_inputs = test_run.runnable.missing_inputs(params[:inputs])
|
26
|
+
|
27
|
+
raise Inferno::Exceptions::RequiredInputsNotFound, missing_inputs if missing_inputs.any?
|
28
|
+
raise Inferno::Exceptions::NotUserRunnableException unless test_run.runnable.user_runnable?
|
29
|
+
|
19
30
|
self.body = serialize(test_run)
|
20
31
|
|
21
32
|
params[:inputs]&.each do |input|
|
@@ -27,7 +38,9 @@ module Inferno
|
|
27
38
|
end
|
28
39
|
|
29
40
|
Jobs.perform(Jobs::ExecuteTestRun, test_run.id)
|
30
|
-
rescue Sequel::ValidationFailed, Sequel::ForeignKeyConstraintViolation
|
41
|
+
rescue Sequel::ValidationFailed, Sequel::ForeignKeyConstraintViolation,
|
42
|
+
Inferno::Exceptions::RequiredInputsNotFound,
|
43
|
+
Inferno::Exceptions::NotUserRunnableException => e
|
31
44
|
self.body = { errors: e.message }.to_json
|
32
45
|
self.status = 422
|
33
46
|
rescue StandardError => e
|
@@ -4,11 +4,10 @@ module Inferno
|
|
4
4
|
class Test < Serializer
|
5
5
|
identifier :id
|
6
6
|
field :title
|
7
|
-
field :inputs
|
8
|
-
field :
|
9
|
-
test.outputs.map { |output| { name: output } }
|
10
|
-
end
|
7
|
+
field :input_definitions, name: :inputs, extractor: HashValueExtractor, blueprint: Input
|
8
|
+
field :output_definitions, name: :outputs, extractor: HashValueExtractor
|
11
9
|
field :description
|
10
|
+
field :user_runnable?, name: :user_runnable
|
12
11
|
end
|
13
12
|
end
|
14
13
|
end
|
@@ -4,18 +4,16 @@ module Inferno
|
|
4
4
|
class TestGroup < Serializer
|
5
5
|
identifier :id
|
6
6
|
|
7
|
-
# TODO: fill out test group
|
8
7
|
field :title
|
9
8
|
field :description
|
10
9
|
field :test_count
|
11
|
-
|
10
|
+
field :run_as_group?, name: :run_as_group
|
11
|
+
field :user_runnable?, name: :user_runnable
|
12
12
|
|
13
13
|
association :groups, name: :test_groups, blueprint: TestGroup
|
14
14
|
association :tests, blueprint: Test
|
15
|
-
field :inputs
|
16
|
-
field :
|
17
|
-
group.outputs.map { |input| { name: input } }
|
18
|
-
end
|
15
|
+
field :input_definitions, name: :inputs, extractor: HashValueExtractor, blueprint: Input
|
16
|
+
field :output_definitions, name: :outputs, extractor: HashValueExtractor
|
19
17
|
end
|
20
18
|
end
|
21
19
|
end
|
@@ -9,6 +9,7 @@ module Inferno
|
|
9
9
|
|
10
10
|
Application.register('js_host', ENV.fetch('JS_HOST', ''))
|
11
11
|
Application.register('async_jobs', ENV['ASYNC_JOBS'] != 'false')
|
12
|
+
Application.register('inferno_host', ENV.fetch('INFERNO_HOST', 'http://localhost:4567'))
|
12
13
|
|
13
14
|
configure do |config|
|
14
15
|
config.root = File.expand_path('../../..', __dir__)
|
@@ -4,12 +4,10 @@ Inferno::Application.boot(:suites) do
|
|
4
4
|
|
5
5
|
files_to_load = Dir.glob(File.join(Dir.pwd, 'lib', '*.rb'))
|
6
6
|
|
7
|
-
if ENV['LOAD_DEV_SUITES']
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
if ENV['LOAD_UI_SUITES'] == 'true'
|
12
|
-
files_to_load.concat Dir.glob(File.join(Inferno::Application.root, 'ui_suites', '**', '*.rb'))
|
7
|
+
if ENV['LOAD_DEV_SUITES'].present?
|
8
|
+
ENV['LOAD_DEV_SUITES'].split(',').map(&:strip).reject(&:empty?).each do |suite|
|
9
|
+
files_to_load.concat Dir.glob(File.join(Inferno::Application.root, 'dev_suites', suite, '**', '*.rb'))
|
10
|
+
end
|
13
11
|
end
|
14
12
|
|
15
13
|
if ENV['APP_ENV'] == 'test'
|
@@ -88,6 +88,26 @@ module Inferno
|
|
88
88
|
rescue JSON::ParserError
|
89
89
|
assert false, "Invalid JSON. #{message}"
|
90
90
|
end
|
91
|
+
|
92
|
+
def assert_valid_http_uri(uri, message = '')
|
93
|
+
error_message = message || "\"#{uri}\" is not a valid URI"
|
94
|
+
assert uri =~ /\A#{URI::DEFAULT_PARSER.make_regexp(['http', 'https'])}\z/, error_message
|
95
|
+
end
|
96
|
+
|
97
|
+
def assert_response_content_type(type, request: self.request)
|
98
|
+
header = request.response_header('Content-Type')
|
99
|
+
assert header.present?, no_content_type_message
|
100
|
+
|
101
|
+
assert header.value.start_with?(type), bad_content_type_message(type, header.value)
|
102
|
+
end
|
103
|
+
|
104
|
+
def no_content_type_message
|
105
|
+
'Response did not contain a `Content-Type` header.'
|
106
|
+
end
|
107
|
+
|
108
|
+
def bad_content_type_message(expected, received)
|
109
|
+
"Expected `Content-Type` to be `#{expected}`, but found `#{received}`"
|
110
|
+
end
|
91
111
|
end
|
92
112
|
end
|
93
113
|
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module Inferno
|
2
|
+
module DSL
|
3
|
+
# This module contains the DSL for managing runnable configuration.
|
4
|
+
module Configurable
|
5
|
+
def self.extended(klass)
|
6
|
+
klass.extend Forwardable
|
7
|
+
klass.def_delegator 'self.class', :config
|
8
|
+
end
|
9
|
+
|
10
|
+
def config(new_configuration = {})
|
11
|
+
@config ||= Configuration.new
|
12
|
+
|
13
|
+
return @config if new_configuration.blank?
|
14
|
+
|
15
|
+
@config.apply(new_configuration)
|
16
|
+
end
|
17
|
+
|
18
|
+
# @api private
|
19
|
+
class Configuration
|
20
|
+
attr_accessor :configuration
|
21
|
+
|
22
|
+
def initialize(configuration = {})
|
23
|
+
self.configuration = configuration
|
24
|
+
end
|
25
|
+
|
26
|
+
def apply(new_configuration)
|
27
|
+
config_to_apply =
|
28
|
+
if new_configuration.is_a? Configuration
|
29
|
+
new_configuration.configuration
|
30
|
+
else
|
31
|
+
new_configuration
|
32
|
+
end
|
33
|
+
|
34
|
+
self.configuration = configuration.deep_merge(config_to_apply)
|
35
|
+
end
|
36
|
+
|
37
|
+
def options
|
38
|
+
configuration[:options] ||= {}
|
39
|
+
end
|
40
|
+
|
41
|
+
### Input Configuration ###
|
42
|
+
|
43
|
+
def inputs
|
44
|
+
configuration[:inputs] ||= {}
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_input(identifier, new_config = {})
|
48
|
+
existing_config = input_config(identifier) || {}
|
49
|
+
inputs[identifier] = default_input_config(identifier).merge(existing_config, new_config)
|
50
|
+
end
|
51
|
+
|
52
|
+
def default_input_config(identifier)
|
53
|
+
{ name: identifier, type: 'text' }
|
54
|
+
end
|
55
|
+
|
56
|
+
def input_config_exists?(identifier)
|
57
|
+
inputs.key? identifier
|
58
|
+
end
|
59
|
+
|
60
|
+
def input_config(identifier)
|
61
|
+
inputs[identifier]
|
62
|
+
end
|
63
|
+
|
64
|
+
def input_name(identifier)
|
65
|
+
inputs.dig(identifier, :name) || identifier
|
66
|
+
end
|
67
|
+
|
68
|
+
### Output Configuration ###
|
69
|
+
|
70
|
+
def outputs
|
71
|
+
configuration[:outputs] ||= {}
|
72
|
+
end
|
73
|
+
|
74
|
+
def add_output(identifier)
|
75
|
+
return if output_config_exists?(identifier)
|
76
|
+
|
77
|
+
outputs[identifier] = default_output_config(identifier)
|
78
|
+
end
|
79
|
+
|
80
|
+
def default_output_config(identifier)
|
81
|
+
{ name: identifier }
|
82
|
+
end
|
83
|
+
|
84
|
+
def output_config_exists?(identifier)
|
85
|
+
outputs.key? identifier
|
86
|
+
end
|
87
|
+
|
88
|
+
def output_config(identifier)
|
89
|
+
outputs[identifier]
|
90
|
+
end
|
91
|
+
|
92
|
+
def output_name(identifier)
|
93
|
+
outputs.dig(identifier, :name) || identifier
|
94
|
+
end
|
95
|
+
|
96
|
+
### Request Configuration ###
|
97
|
+
|
98
|
+
def requests
|
99
|
+
configuration[:requests] ||= {}
|
100
|
+
end
|
101
|
+
|
102
|
+
def add_request(identifier)
|
103
|
+
return if request_config_exists?(identifier)
|
104
|
+
|
105
|
+
requests[identifier] = default_request_config(identifier)
|
106
|
+
end
|
107
|
+
|
108
|
+
def default_request_config(identifier)
|
109
|
+
{ name: identifier }
|
110
|
+
end
|
111
|
+
|
112
|
+
def request_config_exists?(identifier)
|
113
|
+
requests.key? identifier
|
114
|
+
end
|
115
|
+
|
116
|
+
def request_config(identifier)
|
117
|
+
requests[identifier]
|
118
|
+
end
|
119
|
+
|
120
|
+
def request_name(identifier)
|
121
|
+
requests.dig(identifier, :name) || identifier
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -69,12 +69,14 @@ module Inferno
|
|
69
69
|
# @param client [Symbol]
|
70
70
|
# @param name [Symbol] Name for this request to allow it to be used by
|
71
71
|
# other tests
|
72
|
-
# @
|
72
|
+
# @option options [Hash] Input headers here - headers are optional and
|
73
|
+
# must be entered as the last piece of input to this method
|
73
74
|
# @return [Inferno::Entities::Request]
|
74
|
-
def fhir_operation(path, body: nil, client: :default, name: nil, **
|
75
|
+
def fhir_operation(path, body: nil, client: :default, name: nil, **options)
|
75
76
|
store_request('outgoing', name) do
|
76
77
|
headers = fhir_client(client).fhir_headers
|
77
78
|
headers.merge!('Content-Type' => 'application/fhir+json') if body.present?
|
79
|
+
headers.merge!(options[:headers]) if options[:headers].present?
|
78
80
|
fhir_client(client).send(:post, path, body, headers)
|
79
81
|
end
|
80
82
|
end
|
@@ -60,16 +60,17 @@ module Inferno
|
|
60
60
|
# @param client [Symbol]
|
61
61
|
# @param name [Symbol] Name for this request to allow it to be used by
|
62
62
|
# other tests
|
63
|
-
# @
|
63
|
+
# @option options [Hash] Input headers here - headers are optional and
|
64
|
+
# must be entered as the last piece of input to this method
|
64
65
|
# @return [Inferno::Entities::Request]
|
65
|
-
def get(url = '', client: :default, name: nil, **
|
66
|
+
def get(url = '', client: :default, name: nil, **options)
|
66
67
|
store_request('outgoing', name) do
|
67
68
|
client = http_client(client)
|
68
69
|
|
69
70
|
if client
|
70
|
-
client.get(url)
|
71
|
+
client.get(url, nil, options[:headers])
|
71
72
|
elsif url.match?(%r{\Ahttps?://})
|
72
|
-
Faraday.get(url)
|
73
|
+
Faraday.get(url, nil, options[:headers])
|
73
74
|
else
|
74
75
|
raise StandardError, 'Must use an absolute url or define an HTTP client with a base url'
|
75
76
|
end
|
@@ -85,16 +86,17 @@ module Inferno
|
|
85
86
|
# @param client [Symbol]
|
86
87
|
# @param name [Symbol] Name for this request to allow it to be used by
|
87
88
|
# other tests
|
88
|
-
# @
|
89
|
+
# @option options [Hash] Input headers here - headers are optional and
|
90
|
+
# must be entered as the last piece of input to this method
|
89
91
|
# @return [Inferno::Entities::Request]
|
90
|
-
def post(url = '', body: nil, client: :default, name: nil, **
|
92
|
+
def post(url = '', body: nil, client: :default, name: nil, **options)
|
91
93
|
store_request('outgoing', name) do
|
92
94
|
client = http_client(client)
|
93
95
|
|
94
96
|
if client
|
95
|
-
client.post(url, body)
|
97
|
+
client.post(url, body, options[:headers])
|
96
98
|
elsif url.match?(%r{\Ahttps?://})
|
97
|
-
Faraday.post(url, body)
|
99
|
+
Faraday.post(url, body, options[:headers])
|
98
100
|
else
|
99
101
|
raise StandardError, 'Must use an absolute url or define an HTTP client with a base url'
|
100
102
|
end
|
@@ -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
44
|
# @api 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(
|
@@ -64,8 +65,9 @@ module Inferno
|
|
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
|
-
|
68
|
-
|
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
|
@@ -84,16 +86,20 @@ module Inferno
|
|
84
86
|
|
85
87
|
# Specify the named requests made by a test
|
86
88
|
#
|
87
|
-
# @param *
|
88
|
-
def makes_request(*
|
89
|
-
named_requests_made.concat(
|
89
|
+
# @param *identifiers [Symbol] one or more Symbols
|
90
|
+
def makes_request(*identifiers)
|
91
|
+
named_requests_made.concat(identifiers).uniq!
|
92
|
+
identifiers.each do |identifier|
|
93
|
+
config.add_request(identifier)
|
94
|
+
end
|
90
95
|
end
|
91
96
|
|
92
97
|
# Specify the name for a request received by a test
|
93
98
|
#
|
94
|
-
# @param *
|
95
|
-
def receives_request(
|
96
|
-
|
99
|
+
# @param *identifiers [Symbol] one or more Symbols
|
100
|
+
def receives_request(identifier)
|
101
|
+
config.add_request(identifier)
|
102
|
+
@incoming_request_name = identifier
|
97
103
|
end
|
98
104
|
|
99
105
|
# @api private
|
@@ -103,9 +109,12 @@ module Inferno
|
|
103
109
|
|
104
110
|
# Specify the named requests used by a test
|
105
111
|
#
|
106
|
-
# @param *
|
107
|
-
def uses_request(*
|
108
|
-
named_requests_used.concat(
|
112
|
+
# @param *identifiers [Symbol] one or more Symbols
|
113
|
+
def uses_request(*identifiers)
|
114
|
+
named_requests_used.concat(identifiers).uniq!
|
115
|
+
identifiers.each do |identifier|
|
116
|
+
config.add_request(identifier)
|
117
|
+
end
|
109
118
|
end
|
110
119
|
end
|
111
120
|
end
|
data/lib/inferno/dsl/runnable.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
+
require_relative 'configurable'
|
1
2
|
require_relative 'resume_test_route'
|
3
|
+
require_relative '../utils/markdown_formatter'
|
2
4
|
|
3
5
|
module Inferno
|
4
6
|
module DSL
|
@@ -7,6 +9,8 @@ module Inferno
|
|
7
9
|
module Runnable
|
8
10
|
attr_accessor :parent
|
9
11
|
|
12
|
+
include Inferno::Utils::MarkdownFormatter
|
13
|
+
|
10
14
|
# When a class (e.g. TestSuite/TestGroup) uses this module, set it up
|
11
15
|
# so that subclassing it works correctly.
|
12
16
|
# - add the subclass to the relevant repository when it is created
|
@@ -15,6 +19,7 @@ module Inferno
|
|
15
19
|
# @api private
|
16
20
|
def self.extended(extending_class)
|
17
21
|
super
|
22
|
+
extending_class.extend Configurable
|
18
23
|
|
19
24
|
extending_class.define_singleton_method(:inherited) do |subclass|
|
20
25
|
copy_instance_variables(subclass)
|
@@ -39,11 +44,13 @@ module Inferno
|
|
39
44
|
# @api private
|
40
45
|
def copy_instance_variables(subclass)
|
41
46
|
instance_variables.each do |variable|
|
42
|
-
next if [:@id, :@groups, :@tests, :@parent, :@children, :@test_count].include?(variable)
|
47
|
+
next if [:@id, :@groups, :@tests, :@parent, :@children, :@test_count, :@config].include?(variable)
|
43
48
|
|
44
49
|
subclass.instance_variable_set(variable, instance_variable_get(variable).dup)
|
45
50
|
end
|
46
51
|
|
52
|
+
subclass.config(config)
|
53
|
+
|
47
54
|
child_types.each do |child_type|
|
48
55
|
new_children = send(child_type).map do |child|
|
49
56
|
Class.new(child).tap do |subclass_child|
|
@@ -126,16 +133,16 @@ module Inferno
|
|
126
133
|
|
127
134
|
# @api private
|
128
135
|
def configure_child_class(klass, hash_args) # rubocop:disable Metrics/CyclomaticComplexity
|
129
|
-
inputs.each do |
|
130
|
-
next if klass.inputs.any? { |
|
136
|
+
inputs.each do |name|
|
137
|
+
next if klass.inputs.any? { |klass_input_name| klass_input_name == name }
|
131
138
|
|
132
|
-
klass.input
|
139
|
+
klass.input name
|
133
140
|
end
|
134
141
|
|
135
|
-
outputs.each do |
|
136
|
-
next if klass.outputs.include?
|
142
|
+
outputs.each do |output_name|
|
143
|
+
next if klass.outputs.include? output_name
|
137
144
|
|
138
|
-
klass.output
|
145
|
+
klass.output output_name
|
139
146
|
end
|
140
147
|
|
141
148
|
new_fhir_client_definitions = klass.instance_variable_get(:@fhir_client_definitions) || {}
|
@@ -154,8 +161,14 @@ module Inferno
|
|
154
161
|
end
|
155
162
|
klass.instance_variable_set(:@http_client_definitions, new_http_client_definitions)
|
156
163
|
|
164
|
+
klass.config(config)
|
165
|
+
|
157
166
|
hash_args.each do |key, value|
|
158
|
-
|
167
|
+
if value.is_a? Array
|
168
|
+
klass.send(key, *value)
|
169
|
+
else
|
170
|
+
klass.send(key, value)
|
171
|
+
end
|
159
172
|
end
|
160
173
|
|
161
174
|
klass.children.each do |child_class|
|
@@ -193,43 +206,48 @@ module Inferno
|
|
193
206
|
def description(new_description = nil)
|
194
207
|
return @description if new_description.nil?
|
195
208
|
|
196
|
-
@description = new_description
|
209
|
+
@description = format_markdown(new_description)
|
197
210
|
end
|
198
211
|
|
199
212
|
# Define inputs
|
200
213
|
#
|
201
|
-
# @param
|
202
|
-
# @param
|
214
|
+
# @param identifier [Symbol] identifier for the input
|
215
|
+
# @param other_identifiers [Symbol] array of symbols if specifying multiple inputs
|
203
216
|
# @param input_definition [Hash] options for input such as type, description, or title
|
204
217
|
# @option input_definition [String] :title Human readable title for input
|
205
218
|
# @option input_definition [String] :description Description for the input
|
206
219
|
# @option input_definition [String] :type text | textarea
|
207
220
|
# @option input_definition [String] :default The default value for the input
|
221
|
+
# @option input_definition [Boolean] :optional Set to true to not require input for test execution
|
208
222
|
# @return [void]
|
209
223
|
# @example
|
210
224
|
# input :patientid, title: 'Patient ID', description: 'The ID of the patient being searched for',
|
211
225
|
# default: 'default_patient_id'
|
212
226
|
# @example
|
213
|
-
# input :textarea, title: 'Textarea Input Example', type: 'textarea'
|
214
|
-
def input(
|
215
|
-
if
|
216
|
-
[
|
217
|
-
inputs
|
227
|
+
# input :textarea, title: 'Textarea Input Example', type: 'textarea', optional: true
|
228
|
+
def input(identifier, *other_identifiers, **input_definition)
|
229
|
+
if other_identifiers.present?
|
230
|
+
[identifier, *other_identifiers].compact.each do |input_identifier|
|
231
|
+
inputs << input_identifier
|
232
|
+
config.add_input(input_identifier)
|
218
233
|
end
|
219
234
|
else
|
220
|
-
|
221
|
-
|
235
|
+
inputs << identifier
|
236
|
+
config.add_input(identifier, input_definition)
|
222
237
|
end
|
223
238
|
end
|
224
239
|
|
225
240
|
# Define outputs
|
226
241
|
#
|
227
|
-
# @param
|
242
|
+
# @param output_lists [Symbol]
|
228
243
|
# @return [void]
|
229
244
|
# @example
|
230
245
|
# output :patient_id, :bearer_token
|
231
|
-
def output(*
|
232
|
-
|
246
|
+
def output(*output_list)
|
247
|
+
output_list.each do |output_identifier|
|
248
|
+
outputs << output_identifier
|
249
|
+
config.add_output(output_identifier)
|
250
|
+
end
|
233
251
|
end
|
234
252
|
|
235
253
|
# @api private
|
@@ -242,6 +260,14 @@ module Inferno
|
|
242
260
|
@inputs ||= []
|
243
261
|
end
|
244
262
|
|
263
|
+
def input_definitions
|
264
|
+
config.inputs.slice(*inputs)
|
265
|
+
end
|
266
|
+
|
267
|
+
def output_definitions
|
268
|
+
config.outputs.slice(*outputs)
|
269
|
+
end
|
270
|
+
|
245
271
|
# @api private
|
246
272
|
def outputs
|
247
273
|
@outputs ||= []
|
@@ -334,6 +360,28 @@ module Inferno
|
|
334
360
|
def test_count
|
335
361
|
@test_count ||= children&.reduce(0) { |sum, child| sum + child.test_count } || 0
|
336
362
|
end
|
363
|
+
|
364
|
+
def required_inputs(prior_outputs = [])
|
365
|
+
required_inputs = inputs.select do |input|
|
366
|
+
!input_definitions[input][:optional] && !prior_outputs.include?(input)
|
367
|
+
end
|
368
|
+
required_inputs.map! { |input_identifier| input_definitions[input_identifier][:name] }
|
369
|
+
children_required_inputs = children.flat_map { |child| child.required_inputs(prior_outputs) }
|
370
|
+
prior_outputs.concat(outputs)
|
371
|
+
(required_inputs + children_required_inputs).flatten.uniq
|
372
|
+
end
|
373
|
+
|
374
|
+
def missing_inputs(submitted_inputs)
|
375
|
+
submitted_inputs = [] if submitted_inputs.nil?
|
376
|
+
|
377
|
+
required_inputs.map(&:to_s) - submitted_inputs.map { |input| input[:name] }
|
378
|
+
end
|
379
|
+
|
380
|
+
def user_runnable?
|
381
|
+
@user_runnable ||= parent.nil? ||
|
382
|
+
!parent.respond_to?(:run_as_group?) ||
|
383
|
+
(parent.user_runnable? && !parent.run_as_group?)
|
384
|
+
end
|
337
385
|
end
|
338
386
|
end
|
339
387
|
end
|
@@ -46,7 +46,7 @@ module Inferno
|
|
46
46
|
# @param name [String] the header name
|
47
47
|
# @return [Inferno::Entities::RequestHeader, nil]
|
48
48
|
def response_header(name)
|
49
|
-
response_headers.find { |header| header.name
|
49
|
+
response_headers.find { |header| header.name.casecmp(name).zero? }
|
50
50
|
end
|
51
51
|
|
52
52
|
# Find a request header
|
@@ -54,7 +54,7 @@ module Inferno
|
|
54
54
|
# @param name [String] the header name
|
55
55
|
# @return [Inferno::Entities::RequestHeader, nil]
|
56
56
|
def request_header(name)
|
57
|
-
request_headers.find { |header| header.name
|
57
|
+
request_headers.find { |header| header.name.casecmp(name).zero? }
|
58
58
|
end
|
59
59
|
|
60
60
|
# All of the request headers
|