inferno_core 0.3.2 → 0.3.5
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_sessions/create.rb +7 -3
- data/lib/inferno/apps/web/index.html.erb +6 -1
- data/lib/inferno/apps/web/router.rb +9 -2
- data/lib/inferno/apps/web/serializers/suite_option.rb +13 -0
- data/lib/inferno/apps/web/serializers/test_group.rb +6 -2
- data/lib/inferno/apps/web/serializers/test_session.rb +5 -3
- data/lib/inferno/apps/web/serializers/test_suite.rb +4 -1
- data/lib/inferno/config/boot/db.rb +1 -1
- data/lib/inferno/config/boot.rb +1 -1
- data/lib/inferno/db/migrations/007_add_suite_options.rb +5 -0
- data/lib/inferno/db/schema.rb +1 -0
- data/lib/inferno/dsl/configurable.rb +1 -1
- data/lib/inferno/dsl/fhir_client.rb +22 -10
- data/lib/inferno/dsl/fhir_validation.rb +35 -12
- data/lib/inferno/dsl/http_client.rb +47 -35
- data/lib/inferno/dsl/input_output_handling.rb +22 -2
- data/lib/inferno/dsl/runnable.rb +36 -10
- data/lib/inferno/dsl/suite_option.rb +40 -0
- data/lib/inferno/dsl/tcp_exception_handler.rb +11 -0
- data/lib/inferno/entities/test.rb +7 -3
- data/lib/inferno/entities/test_group.rb +4 -4
- data/lib/inferno/entities/test_session.rb +40 -1
- data/lib/inferno/entities/test_suite.rb +12 -14
- data/lib/inferno/public/bundle.js +15 -15
- data/lib/inferno/repositories/test_sessions.rb +24 -0
- data/lib/inferno/test_runner.rb +9 -3
- data/lib/inferno/version.rb +1 -1
- data/spec/support/factory_bot.rb +6 -0
- metadata +23 -7
- data/lib/inferno/public/bg-header-1920x170.png +0 -0
- data/lib/inferno/public/healthit.gov.logo.png +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 40fa8983d93a7fc191a7d03bdb78c0bd80e138cfe5245d377c15f28360fb6b03
|
4
|
+
data.tar.gz: 4aa592411c216c13bc55ebcef30ce2019522cc3575edc184fcb10593eb28239a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bb0f7e9aafced3a1181cd40d8638f4ac07fefc0239ab771b85ce22aaec3785b7328ca82969cd83b1617051201fa149272ba80a53a05789129e6ee35302cf3a1b
|
7
|
+
data.tar.gz: 5f14e0db2c0a2d3238198600a736790ea549ea11c91bb84578dda2e3de2270c31cb314b44972ec2fbc6635aa77b93f0ce4df2926d45c072745b19a1d6371b34f
|
@@ -3,9 +3,13 @@ module Inferno
|
|
3
3
|
module Controllers
|
4
4
|
module TestSessions
|
5
5
|
class Create < Controller
|
6
|
-
PARAMS = [:test_suite_id].freeze
|
6
|
+
PARAMS = [:test_suite_id, :suite_options].freeze
|
7
|
+
|
8
|
+
def call(raw_params)
|
9
|
+
query_params = raw_params.to_h
|
10
|
+
body_params = JSON.parse(request.body.string).symbolize_keys
|
11
|
+
params = query_params.merge(body_params)
|
7
12
|
|
8
|
-
def call(params)
|
9
13
|
session = repo.create(create_params(params))
|
10
14
|
|
11
15
|
repo.apply_preset(session.id, params[:preset_id]) if params[:preset_id].present?
|
@@ -21,7 +25,7 @@ module Inferno
|
|
21
25
|
end
|
22
26
|
|
23
27
|
def create_params(params)
|
24
|
-
params.
|
28
|
+
params.slice(*PARAMS)
|
25
29
|
end
|
26
30
|
end
|
27
31
|
end
|
@@ -29,6 +29,11 @@
|
|
29
29
|
Learn how to configure a non-root public URL by running `npm run build`.
|
30
30
|
-->
|
31
31
|
<style>
|
32
|
+
@media print {
|
33
|
+
.no-print {
|
34
|
+
display: none;
|
35
|
+
}
|
36
|
+
}
|
32
37
|
.wrapper {
|
33
38
|
height: 100%;
|
34
39
|
display: flex;
|
@@ -49,7 +54,7 @@
|
|
49
54
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
50
55
|
<div class='wrapper'>
|
51
56
|
<% if File.exist? (File.join(Dir.pwd, 'config', 'banner.html.erb')) %>
|
52
|
-
<div class='banner'><%= ERB.new(File.read(File.join(Dir.pwd, 'config', 'banner.html.erb'))).result %></div>
|
57
|
+
<div class='banner no-print'><%= ERB.new(File.read(File.join(Dir.pwd, 'config', 'banner.html.erb'))).result %></div>
|
53
58
|
<% end %>
|
54
59
|
<div class='app' id="root"></div>
|
55
60
|
</div>
|
@@ -36,8 +36,10 @@ module Inferno
|
|
36
36
|
get '/version', to: ->(_env) { [200, {}, [{ 'version' => Inferno::VERSION.to_s }.to_json]] }, as: :api_version
|
37
37
|
end
|
38
38
|
|
39
|
-
|
40
|
-
|
39
|
+
# Should not need Content-Type header but GitHub Codespaces will not work without them.
|
40
|
+
# This could be investigated and likely removed if addressed properly elsewhere.
|
41
|
+
get '/', to: ->(_env) { [200, { 'Content-Type' => 'text/html' }, [client_page]] }
|
42
|
+
get '/test_sessions/:id', to: ->(_env) { [200, { 'Content-Type' => 'text/html' }, [client_page]] }
|
41
43
|
|
42
44
|
Inferno.routes.each do |route|
|
43
45
|
cleaned_id = route[:suite].id.gsub(/[^a-zA-Z\d\-._~]/, '_')
|
@@ -49,6 +51,11 @@ module Inferno
|
|
49
51
|
send(route[:method], path, to: route[:handler])
|
50
52
|
end
|
51
53
|
end
|
54
|
+
|
55
|
+
Inferno::Repositories::TestSuites.all.map { |suite| "/#{suite.id}" }.each do |suite_path|
|
56
|
+
Application['logger'].info("Registering suite route: #{suite_path}")
|
57
|
+
get suite_path, to: ->(_env) { [200, {}, [client_page]] }
|
58
|
+
end
|
52
59
|
end
|
53
60
|
end
|
54
61
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Inferno
|
2
|
+
module Web
|
3
|
+
module Serializers
|
4
|
+
class SuiteOption < Serializer
|
5
|
+
identifier :id
|
6
|
+
field :title, if: :field_present?
|
7
|
+
field :description, if: :field_present?
|
8
|
+
field :list_options, if: :field_present?
|
9
|
+
field :value, if: :field_present?
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -15,8 +15,12 @@ module Inferno
|
|
15
15
|
field :user_runnable?, name: :user_runnable
|
16
16
|
field :optional?, name: :optional
|
17
17
|
|
18
|
-
|
19
|
-
|
18
|
+
field :test_groups do |group, options|
|
19
|
+
TestGroup.render_as_hash(group.groups(options[:suite_options]))
|
20
|
+
end
|
21
|
+
field :tests do |group, options|
|
22
|
+
Test.render_as_hash(group.tests(options[:suite_options]))
|
23
|
+
end
|
20
24
|
field :available_inputs, name: :inputs, extractor: HashValueExtractor, blueprint: Input
|
21
25
|
field :output_definitions, name: :outputs, extractor: HashValueExtractor
|
22
26
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require_relative 'suite_option'
|
1
2
|
require_relative 'test_suite'
|
2
3
|
|
3
4
|
module Inferno
|
@@ -7,10 +8,11 @@ module Inferno
|
|
7
8
|
identifier :id
|
8
9
|
|
9
10
|
field :test_suite_id
|
11
|
+
association :suite_options, blueprint: SuiteOption
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
-
|
13
|
+
field :test_suite do |session, _options|
|
14
|
+
TestSuite.render_as_hash(session.test_suite, view: :full, suite_options: session.suite_options)
|
15
|
+
end
|
14
16
|
end
|
15
17
|
end
|
16
18
|
end
|
@@ -11,12 +11,15 @@ module Inferno
|
|
11
11
|
field :input_instructions
|
12
12
|
field :test_count
|
13
13
|
field :version
|
14
|
+
association :suite_options, blueprint: SuiteOption
|
14
15
|
association :presets, view: :summary, blueprint: Preset
|
15
16
|
end
|
16
17
|
|
17
18
|
view :full do
|
18
19
|
include_view :summary
|
19
|
-
|
20
|
+
field :test_groups do |suite, options|
|
21
|
+
TestGroup.render_as_hash(suite.groups(options[:suite_options]))
|
22
|
+
end
|
20
23
|
field :configuration_messages
|
21
24
|
field :available_inputs, name: :inputs, extractor: HashValueExtractor, blueprint: Input
|
22
25
|
end
|
@@ -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
|
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
|
data/lib/inferno/config/boot.rb
CHANGED
data/lib/inferno/db/schema.rb
CHANGED
@@ -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
|
-
|
77
|
-
|
78
|
-
|
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
|
-
|
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
|
-
|
93
|
-
|
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
|
-
|
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
|
-
|
130
|
-
|
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
|
-
|
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
|
-
"#{
|
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
|
-
|
202
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
69
|
-
|
70
|
-
|
71
|
-
client
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
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
|
-
|
95
|
-
|
96
|
-
|
97
|
-
client
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
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
|
-
|
118
|
-
|
119
|
-
|
120
|
-
client
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
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
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
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
|
|
@@ -24,10 +24,20 @@ module Inferno
|
|
24
24
|
[identifier, *other_identifiers].compact.each do |input_identifier|
|
25
25
|
inputs << input_identifier
|
26
26
|
config.add_input(input_identifier)
|
27
|
+
children
|
28
|
+
.reject { |child| child.inputs.include? input_identifier }
|
29
|
+
.each do |child|
|
30
|
+
child.input(input_identifier)
|
31
|
+
end
|
27
32
|
end
|
28
33
|
else
|
29
34
|
inputs << identifier
|
30
35
|
config.add_input(identifier, input_params)
|
36
|
+
children
|
37
|
+
.reject { |child| child.inputs.include? identifier }
|
38
|
+
.each do |child|
|
39
|
+
child.input(identifier, **input_params)
|
40
|
+
end
|
31
41
|
end
|
32
42
|
end
|
33
43
|
|
@@ -47,10 +57,20 @@ module Inferno
|
|
47
57
|
[identifier, *other_identifiers].compact.each do |output_identifier|
|
48
58
|
outputs << output_identifier
|
49
59
|
config.add_output(output_identifier)
|
60
|
+
children
|
61
|
+
.reject { |child| child.outputs.include? output_identifier }
|
62
|
+
.each do |child|
|
63
|
+
child.output(output_identifier)
|
64
|
+
end
|
50
65
|
end
|
51
66
|
else
|
52
67
|
outputs << identifier
|
53
68
|
config.add_output(identifier, output_definition)
|
69
|
+
children
|
70
|
+
.reject { |child| child.outputs.include? identifier }
|
71
|
+
.each do |child|
|
72
|
+
child.output(identifier, **output_definition)
|
73
|
+
end
|
54
74
|
end
|
55
75
|
end
|
56
76
|
|
@@ -125,7 +145,7 @@ module Inferno
|
|
125
145
|
def all_outputs
|
126
146
|
outputs
|
127
147
|
.map { |output_identifier| config.output_name(output_identifier) }
|
128
|
-
.concat(
|
148
|
+
.concat(all_children.flat_map(&:all_outputs))
|
129
149
|
.uniq
|
130
150
|
end
|
131
151
|
|
@@ -137,7 +157,7 @@ module Inferno
|
|
137
157
|
@children_available_inputs ||=
|
138
158
|
begin
|
139
159
|
child_outputs = []
|
140
|
-
|
160
|
+
all_children.each_with_object({}) do |child, definitions|
|
141
161
|
new_definitions = child.available_inputs.map(&:dup)
|
142
162
|
new_definitions.each do |input, new_definition|
|
143
163
|
existing_definition = definitions[input]
|