inferno_core 0.6.11 → 0.6.12
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/cli/evaluate.rb +8 -7
- data/lib/inferno/apps/cli/main.rb +12 -1
- data/lib/inferno/apps/cli/requirements.rb +49 -0
- data/lib/inferno/apps/cli/requirements_coverage_checker.rb +238 -0
- data/lib/inferno/apps/cli/suite.rb +9 -0
- data/lib/inferno/apps/web/controllers/test_sessions/results/io_value.rb +68 -0
- data/lib/inferno/apps/web/router.rb +3 -0
- data/lib/inferno/apps/web/serializers/result.rb +2 -2
- data/lib/inferno/dsl/fhir_client.rb +9 -1
- data/lib/inferno/dsl/http_client.rb +9 -1
- data/lib/inferno/dsl/runnable.rb +15 -30
- data/lib/inferno/dsl/suite_requirements.rb +26 -26
- data/lib/inferno/entities/result.rb +39 -0
- data/lib/inferno/entities/test_kit.rb +4 -0
- data/lib/inferno/public/bundle.js +11 -11
- data/lib/inferno/repositories/repository.rb +19 -0
- data/lib/inferno/repositories/requirements.rb +4 -3
- data/lib/inferno/repositories/results.rb +6 -3
- data/lib/inferno/repositories/runnable_repository.rb +29 -0
- data/lib/inferno/repositories/test_groups.rb +2 -2
- data/lib/inferno/repositories/test_sessions.rb +1 -0
- data/lib/inferno/repositories/test_suites.rb +2 -2
- data/lib/inferno/repositories/tests.rb +2 -2
- data/lib/inferno/repositories.rb +1 -0
- data/lib/inferno/version.rb +1 -1
- 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: a7e5f22313a778dd7b70ba70eae9513bda158a7c0cd6beba9a2d195b3a37f077
|
4
|
+
data.tar.gz: 8e7d6155fad17e00ccc48257853f4df2cc816d0965cc0b18a50515bbd26d343f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 56b26537ac370a6b475ab33895ad91e3d5cf5ff588cd3fa5be979c6e250e5aa703a76c093ea46c787ecd2c4f061f1f55e39c43ba245219618c18b9a44e522f3e
|
7
|
+
data.tar.gz: a1549f23c6e8c501286bc490c6821be19da1a730b950a497bdd7a2c7d61c392090e0ac1603f251e4d033abedbc4457e1dfcbf7ecac5bcfcd875392e7125ca4ef
|
@@ -27,10 +27,11 @@ module Inferno
|
|
27
27
|
|
28
28
|
ig_path = absolute_path_with_home_expansion(ig_path)
|
29
29
|
data_path = absolute_path_with_home_expansion(data_path) if data_path
|
30
|
+
config_path = absolute_path_with_home_expansion(options[:config]) if options[:config]
|
30
31
|
|
31
32
|
Dir.chdir(tmpdir) do
|
32
33
|
Migration.new.run(Logger::FATAL) # Hide migration output for evaluator
|
33
|
-
evaluate(ig_path, data_path, options)
|
34
|
+
evaluate(ig_path, data_path, config_path, options)
|
34
35
|
end
|
35
36
|
ensure
|
36
37
|
system("#{services_base_command} down #{services_names}")
|
@@ -57,14 +58,14 @@ module Inferno
|
|
57
58
|
end
|
58
59
|
|
59
60
|
# @see Inferno::CLI::Main#evaluate
|
60
|
-
def evaluate(ig_path, data_path, options)
|
61
|
+
def evaluate(ig_path, data_path, config_path, options)
|
61
62
|
# NOTE: repositories is required here rather than at the top of the file because
|
62
63
|
# the tree of requires means that this file and its requires get required by every CLI app.
|
63
64
|
# Sequel::Model, used in some repositories, fetches the table schema at instantiation.
|
64
65
|
# This breaks the `migrate` task by fetching a table before the task runs/creates it.
|
65
66
|
require_relative '../../repositories'
|
66
67
|
|
67
|
-
validate_args(ig_path, data_path)
|
68
|
+
validate_args(ig_path, data_path, config_path)
|
68
69
|
ig = Inferno::Repositories::IGs.new.find_or_load(ig_path)
|
69
70
|
|
70
71
|
check_ig_version(ig)
|
@@ -80,17 +81,17 @@ module Inferno
|
|
80
81
|
|
81
82
|
evaluator = Inferno::DSL::FHIREvaluation::Evaluator.new(ig, validator)
|
82
83
|
|
83
|
-
config = Inferno::DSL::FHIREvaluation::Config.new
|
84
|
+
config = Inferno::DSL::FHIREvaluation::Config.new(config_path)
|
84
85
|
results = evaluator.evaluate(data, config)
|
85
86
|
output_results(results, options[:output])
|
86
87
|
end
|
87
88
|
|
88
|
-
def validate_args(ig_path, data_path)
|
89
|
+
def validate_args(ig_path, data_path, config_path)
|
89
90
|
raise 'A path to an IG is required!' unless ig_path
|
90
91
|
|
91
|
-
|
92
|
+
raise "Provided path '#{data_path}' is not a directory" if data_path && (!File.directory? data_path)
|
92
93
|
|
93
|
-
raise "Provided path '#{
|
94
|
+
raise "Provided path '#{config_path}' does not exist" if config_path && (!File.exist? config_path)
|
94
95
|
end
|
95
96
|
|
96
97
|
def check_ig_version(ig)
|
@@ -6,8 +6,8 @@ require_relative 'services'
|
|
6
6
|
require_relative 'suite'
|
7
7
|
require_relative 'suites'
|
8
8
|
require_relative 'new'
|
9
|
-
require_relative '../../version'
|
10
9
|
require_relative 'execute'
|
10
|
+
require_relative '../../version'
|
11
11
|
|
12
12
|
module Inferno
|
13
13
|
module CLI
|
@@ -34,6 +34,9 @@ module Inferno
|
|
34
34
|
|
35
35
|
# Loads the us core ig and evaluate the data included in the IG's example folder, with results redirected to outcome.json as an OperationOutcome
|
36
36
|
`bundle exec inferno evaluate ./uscore.tgz --output outcome.json`
|
37
|
+
|
38
|
+
# Loads the us core ig and evaluate the data included in the IG's example folder using a custom configuration file
|
39
|
+
`bundle exec inferno evaluate ./uscore.tgz --config ./custom_config.yml`
|
37
40
|
LONGDESC
|
38
41
|
# TODO: Add options below as arguments
|
39
42
|
option :data_path,
|
@@ -45,6 +48,10 @@ module Inferno
|
|
45
48
|
aliases: ['-o'],
|
46
49
|
type: :string,
|
47
50
|
desc: 'Export evaluation result to outcome.json as an OperationOutcome'
|
51
|
+
option :config,
|
52
|
+
aliases: ['-c'],
|
53
|
+
type: :string,
|
54
|
+
desc: 'Path to a custom configuration file'
|
48
55
|
def evaluate(ig_path)
|
49
56
|
Evaluate.new.run(ig_path, options[:data_path], options)
|
50
57
|
end
|
@@ -92,6 +99,10 @@ module Inferno
|
|
92
99
|
|
93
100
|
desc 'suites', 'List available test suites'
|
94
101
|
def suites
|
102
|
+
ENV['NO_DB'] = 'true'
|
103
|
+
|
104
|
+
require_relative '../../../inferno'
|
105
|
+
|
95
106
|
Suites.new.run
|
96
107
|
end
|
97
108
|
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require_relative 'requirements_coverage_checker'
|
1
2
|
require_relative 'requirements_exporter'
|
2
3
|
|
3
4
|
module Inferno
|
@@ -23,6 +24,54 @@ module Inferno
|
|
23
24
|
ENV['NO_DB'] = 'true'
|
24
25
|
RequirementsExporter.new.run_check
|
25
26
|
end
|
27
|
+
|
28
|
+
desc 'coverage [TEST_SUITE_ID]',
|
29
|
+
"Check whether all of a test suite's requirements are tested. If no test suite id is provided, " \
|
30
|
+
'all test suites in the current test kit will be checked.'
|
31
|
+
long_desc <<~LONGDESC
|
32
|
+
Check whether all of the requirements declared by a test suite are
|
33
|
+
tested by the tests in the test suite
|
34
|
+
LONGDESC
|
35
|
+
def coverage(test_suite_id = nil)
|
36
|
+
ENV['NO_DB'] = 'true'
|
37
|
+
|
38
|
+
require_relative '../../../inferno'
|
39
|
+
|
40
|
+
Inferno::Application.start(:requirements)
|
41
|
+
|
42
|
+
if test_suite_id.present?
|
43
|
+
RequirementsCoverageChecker.new(test_suite_id).run
|
44
|
+
else
|
45
|
+
Inferno::Repositories::TestSuites.all.each do |test_suite|
|
46
|
+
if Object.const_source_location(test_suite.to_s).first.start_with? Dir.pwd
|
47
|
+
RequirementsCoverageChecker.new(test_suite.id).run
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
desc 'check_coverage [TEST_SUITE_ID]',
|
54
|
+
'Check whether the coverage CSV files are up to date'
|
55
|
+
long_desc <<~LONGDESC
|
56
|
+
Check whether the coverage CSV files are up to date
|
57
|
+
LONGDESC
|
58
|
+
def check_coverage(test_suite_id = nil)
|
59
|
+
ENV['NO_DB'] = 'true'
|
60
|
+
|
61
|
+
require_relative '../../../inferno'
|
62
|
+
|
63
|
+
Inferno::Application.start(:requirements)
|
64
|
+
|
65
|
+
if test_suite_id.present?
|
66
|
+
RequirementsCoverageChecker.new(test_suite_id).run_check
|
67
|
+
else
|
68
|
+
Inferno::Repositories::TestSuites.all.each do |test_suite|
|
69
|
+
if Object.const_source_location(test_suite.to_s).first.start_with? Dir.pwd
|
70
|
+
RequirementsCoverageChecker.new(test_suite.id).run_check
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
26
75
|
end
|
27
76
|
end
|
28
77
|
end
|
@@ -0,0 +1,238 @@
|
|
1
|
+
require_relative 'requirements_exporter'
|
2
|
+
|
3
|
+
module Inferno
|
4
|
+
module CLI
|
5
|
+
class RequirementsCoverageChecker
|
6
|
+
attr_accessor :test_suite_id, :test_suite
|
7
|
+
|
8
|
+
def initialize(test_suite_id)
|
9
|
+
self.test_suite_id = test_suite_id
|
10
|
+
self.test_suite = Inferno::Repositories::TestSuites.new.find(test_suite_id)
|
11
|
+
end
|
12
|
+
|
13
|
+
def short_id_header
|
14
|
+
"#{test_suite.title} Short ID(s)"
|
15
|
+
end
|
16
|
+
|
17
|
+
def full_id_header
|
18
|
+
"#{test_suite.title} Full ID(s)"
|
19
|
+
end
|
20
|
+
|
21
|
+
def output_headers
|
22
|
+
[
|
23
|
+
*(RequirementsExporter::REQUIREMENTS_OUTPUT_HEADERS - ['Sub-Requirement(s)']),
|
24
|
+
short_id_header,
|
25
|
+
full_id_header
|
26
|
+
]
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_kit_name
|
30
|
+
local_test_kit_gem.name
|
31
|
+
end
|
32
|
+
|
33
|
+
def base_requirements_folder
|
34
|
+
RequirementsExporter.new.base_requirements_folder
|
35
|
+
end
|
36
|
+
|
37
|
+
def output_folder
|
38
|
+
@output_folder ||= File.join(base_requirements_folder, 'generated')
|
39
|
+
end
|
40
|
+
|
41
|
+
def output_file_name
|
42
|
+
"#{test_suite_id}_requirements_coverage.csv"
|
43
|
+
end
|
44
|
+
|
45
|
+
def output_file_path
|
46
|
+
@output_file_path ||= File.join(output_folder, output_file_name)
|
47
|
+
end
|
48
|
+
|
49
|
+
def suite_requirements
|
50
|
+
@suite_requirements ||=
|
51
|
+
Inferno::Repositories::Requirements.new.requirements_for_suite(test_suite_id)
|
52
|
+
end
|
53
|
+
|
54
|
+
def tested_requirement_ids
|
55
|
+
@tested_requirement_ids ||= test_suite.all_verified_requirements
|
56
|
+
end
|
57
|
+
|
58
|
+
def suite_runnables
|
59
|
+
@suite_runnables ||= [test_suite] + test_suite.all_descendants
|
60
|
+
end
|
61
|
+
|
62
|
+
def untested_requirements
|
63
|
+
@untested_requirements ||= []
|
64
|
+
end
|
65
|
+
|
66
|
+
def new_csv # rubocop:disable Metrics/CyclomaticComplexity
|
67
|
+
@new_csv ||=
|
68
|
+
CSV.generate(+"\xEF\xBB\xBF") do |csv|
|
69
|
+
csv << output_headers
|
70
|
+
|
71
|
+
suite_requirements.each do |requirement|
|
72
|
+
if requirement.not_tested_reason.present?
|
73
|
+
long_ids = 'NA'
|
74
|
+
short_ids = 'NA'
|
75
|
+
else
|
76
|
+
runnables_for_requirement =
|
77
|
+
suite_runnables.select { |runnable| runnable.verifies_requirements.include? requirement.id }
|
78
|
+
long_ids = runnables_for_requirement&.map(&:id)&.join(', ')
|
79
|
+
short_ids =
|
80
|
+
runnables_for_requirement
|
81
|
+
&.map { |runnable| runnable < Inferno::Entities::TestSuite ? 'suite' : runnable.short_id }
|
82
|
+
&.join(', ')
|
83
|
+
end
|
84
|
+
|
85
|
+
untested_requirements << runnables_for_requirement if runnables_for_requirement.blank?
|
86
|
+
|
87
|
+
row = [
|
88
|
+
requirement.requirement_set,
|
89
|
+
requirement.id.delete_prefix("#{requirement.requirement_set}@"),
|
90
|
+
requirement.url,
|
91
|
+
requirement.requirement,
|
92
|
+
requirement.conformance,
|
93
|
+
requirement.actor,
|
94
|
+
requirement.conditionality,
|
95
|
+
requirement.not_tested_reason,
|
96
|
+
requirement.not_tested_details,
|
97
|
+
short_ids,
|
98
|
+
long_ids
|
99
|
+
]
|
100
|
+
|
101
|
+
csv << row
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def input_requirement_ids
|
107
|
+
@input_requirement_ids ||= input_rows.map { |row| "#{row['Req Set']}@#{row['ID']}" }
|
108
|
+
end
|
109
|
+
|
110
|
+
# The requirements present in Inferno that aren't in the input spreadsheet
|
111
|
+
def unmatched_requirement_ids
|
112
|
+
@unmatched_requirement_ids ||=
|
113
|
+
tested_requirement_ids - suite_requirements.map(&:id)
|
114
|
+
end
|
115
|
+
|
116
|
+
def unmatched_requirement_rows
|
117
|
+
unmatched_requirement_ids.flat_map do |requirement_id|
|
118
|
+
runnables_for_requirement =
|
119
|
+
suite_runnables.select { |runnable| runnable.verifies_requirements.include? requirement_id }
|
120
|
+
|
121
|
+
runnables_for_requirement.map do |runnable|
|
122
|
+
[requirement_id, runnable.short_id, runnable.id]
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def old_csv
|
128
|
+
@old_csv ||= File.read(output_file_path)
|
129
|
+
end
|
130
|
+
|
131
|
+
def run
|
132
|
+
unless test_suite.present?
|
133
|
+
puts "Could not find test suite: #{test_suite_id}. Aborting requirements coverage generation..."
|
134
|
+
exit(1)
|
135
|
+
end
|
136
|
+
|
137
|
+
puts
|
138
|
+
|
139
|
+
if unmatched_requirement_ids.present?
|
140
|
+
puts "WARNING: The following requirements indicated in the test suite #{test_suite_id} are not present in " \
|
141
|
+
"the suite's requirement sets:"
|
142
|
+
output_requirements_map_table(unmatched_requirement_rows)
|
143
|
+
end
|
144
|
+
|
145
|
+
if File.exist?(output_file_path)
|
146
|
+
if old_csv == new_csv
|
147
|
+
puts "'#{output_file_name}' file is up to date."
|
148
|
+
return
|
149
|
+
else
|
150
|
+
puts 'Requirements coverage has changed.'
|
151
|
+
end
|
152
|
+
else
|
153
|
+
puts "No existing #{output_file_name}."
|
154
|
+
end
|
155
|
+
|
156
|
+
puts "Writing to file #{output_file_path}..."
|
157
|
+
FileUtils.mkdir_p(output_folder)
|
158
|
+
File.write(output_file_path, new_csv)
|
159
|
+
puts 'Done.'
|
160
|
+
end
|
161
|
+
|
162
|
+
def run_check
|
163
|
+
unless test_suite.present?
|
164
|
+
puts "Could not find test suite: #{test_suite_id}. Aborting requirements coverage generation..."
|
165
|
+
exit(1)
|
166
|
+
end
|
167
|
+
|
168
|
+
puts
|
169
|
+
|
170
|
+
if unmatched_requirement_ids.any?
|
171
|
+
puts "WARNING: The following requirements indicated in the test suite #{test_suite_id} are not present in " \
|
172
|
+
"the suite's requirement sets:"
|
173
|
+
output_requirements_map_table(unmatched_requirement_rows)
|
174
|
+
end
|
175
|
+
|
176
|
+
if File.exist?(output_file_path)
|
177
|
+
if old_csv == new_csv
|
178
|
+
puts "'#{output_file_name}' file is up to date."
|
179
|
+
return unless unmatched_requirement_ids.present?
|
180
|
+
else
|
181
|
+
puts <<~MESSAGE
|
182
|
+
#{output_file_name} file is out of date.
|
183
|
+
To regenerate the file, run:
|
184
|
+
|
185
|
+
bundle exec inferno requirements coverage
|
186
|
+
|
187
|
+
MESSAGE
|
188
|
+
end
|
189
|
+
else
|
190
|
+
puts <<~MESSAGE
|
191
|
+
No existing #{output_file_name} file.
|
192
|
+
To generate the file, run:
|
193
|
+
|
194
|
+
bundle exec inferno requirements coverage
|
195
|
+
|
196
|
+
MESSAGE
|
197
|
+
end
|
198
|
+
|
199
|
+
puts 'Check failed.'
|
200
|
+
exit(1)
|
201
|
+
end
|
202
|
+
|
203
|
+
# Output the requirements in the map like so:
|
204
|
+
#
|
205
|
+
# requirement_id | short_id | full_id
|
206
|
+
# ---------------+------------+----------
|
207
|
+
# req-id-1 | short-id-1 | full-id-1
|
208
|
+
# req-id-2 | short-id-2 | full-id-2
|
209
|
+
#
|
210
|
+
def output_requirements_map_table(requirements_rows)
|
211
|
+
headers = %w[requirement_id short_id full_id]
|
212
|
+
col_widths = headers.map(&:length)
|
213
|
+
col_widths[0] = [col_widths[0], *requirements_rows.map { |row| row[0].length }].max
|
214
|
+
col_widths[1] = [col_widths[1], *requirements_rows.map { |row| row[1].length }].max
|
215
|
+
col_widths[2] = [col_widths[2], *requirements_rows.map { |row| row[2].length }].max
|
216
|
+
col_widths.map! { |width| width + 3 }
|
217
|
+
|
218
|
+
puts [
|
219
|
+
headers[0].ljust(col_widths[0]),
|
220
|
+
headers[1].ljust(col_widths[1]),
|
221
|
+
headers[2].ljust(col_widths[2])
|
222
|
+
].join(' | ')
|
223
|
+
puts col_widths.map { |width| '-' * width }.join('-+-')
|
224
|
+
output_requirements_map_table_contents(requirements_rows, col_widths)
|
225
|
+
end
|
226
|
+
|
227
|
+
def output_requirements_map_table_contents(requirements_rows, col_widths)
|
228
|
+
requirements_rows.each do |requirements_row|
|
229
|
+
puts [
|
230
|
+
requirements_row[0].ljust(col_widths[0]),
|
231
|
+
requirements_row[1].ljust(col_widths[1]),
|
232
|
+
requirements_row[2].ljust(col_widths[2])
|
233
|
+
].join(' | ')
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
@@ -15,6 +15,9 @@ module Inferno
|
|
15
15
|
option :filename, banner: '<filename>', aliases: [:f]
|
16
16
|
def input_template(suite_id)
|
17
17
|
ENV['NO_DB'] = 'true'
|
18
|
+
|
19
|
+
require_relative '../../../inferno'
|
20
|
+
|
18
21
|
SuiteInputTemplate.new.run(suite_id, options)
|
19
22
|
end
|
20
23
|
|
@@ -24,6 +27,9 @@ module Inferno
|
|
24
27
|
LONGDESC
|
25
28
|
def describe(suite_id)
|
26
29
|
ENV['NO_DB'] = 'true'
|
30
|
+
|
31
|
+
require_relative '../../../inferno'
|
32
|
+
|
27
33
|
Inferno::Application.start(:suites)
|
28
34
|
|
29
35
|
suite = Inferno::Repositories::TestSuites.new.find(suite_id)
|
@@ -59,6 +65,9 @@ module Inferno
|
|
59
65
|
LONGDESC
|
60
66
|
def lock_short_ids(suite_id)
|
61
67
|
ENV['NO_DB'] = 'true'
|
68
|
+
|
69
|
+
require_relative '../../../inferno'
|
70
|
+
|
62
71
|
Inferno::Application.start(:suites)
|
63
72
|
|
64
73
|
suite = Inferno::Repositories::TestSuites.new.find(suite_id)
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Inferno
|
2
|
+
module Web
|
3
|
+
module Controllers
|
4
|
+
module TestSessions
|
5
|
+
module Results
|
6
|
+
class IoValue < Controller
|
7
|
+
include Import[
|
8
|
+
test_sessions_repo: 'inferno.repositories.test_sessions',
|
9
|
+
results_repo: 'inferno.repositories.results'
|
10
|
+
]
|
11
|
+
|
12
|
+
def handle(req, res)
|
13
|
+
test_session_id = req.params[:id]
|
14
|
+
result_id = req.params[:result_id]
|
15
|
+
type = req.params[:type]
|
16
|
+
name = req.params[:name]
|
17
|
+
|
18
|
+
unless %w[inputs outputs].include?(type)
|
19
|
+
res.status = 400
|
20
|
+
res.body = { error: 'Invalid I/O type. Must be "inputs" or "outputs".' }.to_json
|
21
|
+
return
|
22
|
+
end
|
23
|
+
|
24
|
+
test_session_results = results_repo.current_results_for_test_session(test_session_id)
|
25
|
+
result = test_session_results.find { |r| r.id == result_id }
|
26
|
+
|
27
|
+
if result.nil?
|
28
|
+
res.status = 404
|
29
|
+
res.body = { error: "Result '#{result_id}' not found for test session '#{test_session_id}'." }.to_json
|
30
|
+
return
|
31
|
+
end
|
32
|
+
|
33
|
+
entry = result_io_by_name(result, type, name)
|
34
|
+
value = entry&.dig('value')
|
35
|
+
|
36
|
+
if value.blank?
|
37
|
+
res.status = 404
|
38
|
+
res.body = { error: "#{type.singularize.capitalize} '#{name}' not found or missing value." }.to_json
|
39
|
+
return
|
40
|
+
end
|
41
|
+
|
42
|
+
res.body = value.is_a?(Hash) ? value.to_json : value
|
43
|
+
res.content_type = content_type_for(value)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def result_io_by_name(result, io_type, name)
|
49
|
+
result.public_send(io_type)
|
50
|
+
.find { |item| item['name'] == name }
|
51
|
+
end
|
52
|
+
|
53
|
+
def content_type_for(value)
|
54
|
+
return 'application/json' if value.is_a?(Hash)
|
55
|
+
|
56
|
+
trimmed = value&.strip
|
57
|
+
|
58
|
+
return 'application/json' if trimmed&.start_with?('{', '[')
|
59
|
+
return 'application/xml' if trimmed&.start_with?('<') && trimmed.end_with?('>')
|
60
|
+
|
61
|
+
'text/plain'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -34,6 +34,9 @@ module Inferno
|
|
34
34
|
get '/:id/results',
|
35
35
|
to: Inferno::Web::Controllers::TestSessions::Results::Index,
|
36
36
|
as: :results
|
37
|
+
get '/:id/results/:result_id/io/:type/:name',
|
38
|
+
to: Inferno::Web::Controllers::TestSessions::Results::IoValue,
|
39
|
+
as: :result_io_value
|
37
40
|
get '/:id/session_data',
|
38
41
|
to: Inferno::Web::Controllers::TestSessions::SessionData::Index
|
39
42
|
put '/:id/session_data/apply_preset',
|
@@ -21,11 +21,11 @@ module Inferno
|
|
21
21
|
field :optional?, name: :optional
|
22
22
|
|
23
23
|
field :inputs do |result, _options|
|
24
|
-
result.
|
24
|
+
result.handle_large_io('inputs')
|
25
25
|
end
|
26
26
|
|
27
27
|
field :outputs do |result, _options|
|
28
|
-
result.
|
28
|
+
result.handle_large_io('outputs')
|
29
29
|
end
|
30
30
|
|
31
31
|
association :messages, blueprint: Message, if: :field_present?
|
@@ -52,7 +52,11 @@ module Inferno
|
|
52
52
|
# @see Inferno::DSL::FHIRClientBuilder
|
53
53
|
def fhir_client(client = :default)
|
54
54
|
fhir_clients[client] ||=
|
55
|
-
FHIRClientBuilder.new.build(self,
|
55
|
+
FHIRClientBuilder.new.build(self, find_fhir_client_definition(client))
|
56
|
+
end
|
57
|
+
|
58
|
+
def find_fhir_client_definition(client)
|
59
|
+
self.class.find_fhir_client_definition(client)
|
56
60
|
end
|
57
61
|
|
58
62
|
# @private
|
@@ -443,6 +447,10 @@ module Inferno
|
|
443
447
|
@fhir_client_definitions ||= {}
|
444
448
|
end
|
445
449
|
|
450
|
+
def find_fhir_client_definition(client)
|
451
|
+
fhir_client_definitions[client] || parent&.find_fhir_client_definition(client)
|
452
|
+
end
|
453
|
+
|
446
454
|
# Define a FHIR client to be used by a Runnable.
|
447
455
|
#
|
448
456
|
# @param name [Symbol] a name used to reference this particular client
|
@@ -46,7 +46,7 @@ module Inferno
|
|
46
46
|
def http_client(client = :default)
|
47
47
|
return http_clients[client] if http_clients[client]
|
48
48
|
|
49
|
-
definition =
|
49
|
+
definition = find_http_client_definition(client)
|
50
50
|
return nil if definition.nil?
|
51
51
|
|
52
52
|
tcp_exception_handler do
|
@@ -54,6 +54,10 @@ module Inferno
|
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
+
def find_http_client_definition(client)
|
58
|
+
self.class.find_http_client_definition(client)
|
59
|
+
end
|
60
|
+
|
57
61
|
# @private
|
58
62
|
def http_clients
|
59
63
|
@http_clients ||= {}
|
@@ -196,6 +200,10 @@ module Inferno
|
|
196
200
|
@http_client_definitions ||= {}
|
197
201
|
end
|
198
202
|
|
203
|
+
def find_http_client_definition(client)
|
204
|
+
http_client_definitions[client] || parent&.find_http_client_definition(client)
|
205
|
+
end
|
206
|
+
|
199
207
|
# Define a HTTP client to be used by a Runnable.
|
200
208
|
#
|
201
209
|
# @param name [Symbol] a name used to reference this particular client
|
data/lib/inferno/dsl/runnable.rb
CHANGED
@@ -39,6 +39,7 @@ module Inferno
|
|
39
39
|
# @private
|
40
40
|
VARIABLES_NOT_TO_COPY = [
|
41
41
|
:@id, # New runnable will have a different id
|
42
|
+
:@database_id, # New runnable will have a different database_id
|
42
43
|
:@parent, # New runnable unlikely to have the same parent
|
43
44
|
:@all_children, # New subclasses have to be made for each child
|
44
45
|
:@test_count, # Needs to be recalculated
|
@@ -164,22 +165,6 @@ module Inferno
|
|
164
165
|
klass.output output_name
|
165
166
|
end
|
166
167
|
|
167
|
-
new_fhir_client_definitions = klass.instance_variable_get(:@fhir_client_definitions) || {}
|
168
|
-
fhir_client_definitions.each do |name, definition|
|
169
|
-
next if new_fhir_client_definitions.include? name
|
170
|
-
|
171
|
-
new_fhir_client_definitions[name] = definition.dup
|
172
|
-
end
|
173
|
-
klass.instance_variable_set(:@fhir_client_definitions, new_fhir_client_definitions)
|
174
|
-
|
175
|
-
new_http_client_definitions = klass.instance_variable_get(:@http_client_definitions) || {}
|
176
|
-
http_client_definitions.each do |name, definition|
|
177
|
-
next if new_http_client_definitions.include? name
|
178
|
-
|
179
|
-
new_http_client_definitions[name] = definition.dup
|
180
|
-
end
|
181
|
-
klass.instance_variable_set(:@http_client_definitions, new_http_client_definitions)
|
182
|
-
|
183
168
|
klass.config(config)
|
184
169
|
|
185
170
|
klass.all_children.select!(&:required?) if hash_args.delete(:exclude_optional)
|
@@ -210,20 +195,20 @@ module Inferno
|
|
210
195
|
def id(new_id = nil)
|
211
196
|
return @id if new_id.nil? && @id.present?
|
212
197
|
|
213
|
-
prefix =
|
214
|
-
if parent
|
215
|
-
"#{parent.id}-"
|
216
|
-
else
|
217
|
-
''
|
218
|
-
end
|
219
|
-
|
198
|
+
prefix = parent ? "#{parent.id}-" : ''
|
220
199
|
@base_id = new_id || @base_id || default_id
|
200
|
+
@id = "#{prefix}#{@base_id}"
|
221
201
|
|
222
|
-
|
202
|
+
if @id.length > 255
|
203
|
+
hash = Digest::SHA1.hexdigest(@id)[0...10]
|
204
|
+
@database_id = "#{@id[0...244]}-#{hash}"
|
205
|
+
end
|
223
206
|
|
224
|
-
|
207
|
+
@id
|
208
|
+
end
|
225
209
|
|
226
|
-
|
210
|
+
def database_id
|
211
|
+
@database_id ||= id
|
227
212
|
end
|
228
213
|
|
229
214
|
# Set/Get a runnable's title
|
@@ -571,10 +556,10 @@ module Inferno
|
|
571
556
|
end
|
572
557
|
|
573
558
|
# @private
|
574
|
-
def
|
575
|
-
children(suite_options).flat_map do |child|
|
576
|
-
child.
|
577
|
-
end
|
559
|
+
def all_verified_requirements(suite_options = [])
|
560
|
+
verifies_requirements + children(suite_options).flat_map do |child|
|
561
|
+
child.all_verified_requirements(suite_options)
|
562
|
+
end.uniq
|
578
563
|
end
|
579
564
|
|
580
565
|
# @private
|