inferno_core 0.5.1 → 0.5.3
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 +64 -0
- data/lib/inferno/apps/cli/execute.rb +49 -4
- data/lib/inferno/apps/cli/main.rb +48 -2
- data/lib/inferno/apps/cli/templates/%library_name%.gemspec.tt +10 -3
- data/lib/inferno/apps/cli/templates/Dockerfile.tt +3 -2
- data/lib/inferno/apps/cli/templates/lib/%library_name%/metadata.rb.tt +18 -0
- data/lib/inferno/apps/cli/templates/lib/%library_name%/suite.rb.tt +59 -0
- data/lib/inferno/apps/cli/templates/lib/%library_name%/version.rb.tt +3 -0
- data/lib/inferno/apps/cli/templates/lib/%library_name%.rb.tt +1 -58
- data/lib/inferno/apps/web/application.rb +4 -0
- data/lib/inferno/apps/web/index.html.erb +12 -4
- data/lib/inferno/apps/web/serializers/input.rb +2 -1
- data/lib/inferno/apps/web/serializers/markdown_extractor.rb +16 -0
- data/lib/inferno/config/boot/executor.rb +1 -0
- data/lib/inferno/config/boot/presets.rb +18 -1
- data/lib/inferno/dsl/fhir_evaluation/config.rb +21 -0
- data/lib/inferno/dsl/fhir_evaluation/dataset_loader.rb +33 -0
- data/lib/inferno/dsl/fhir_evaluation/evaluation_context.rb +25 -0
- data/lib/inferno/dsl/fhir_evaluation/evaluation_result.rb +62 -0
- data/lib/inferno/dsl/fhir_evaluation/evaluator.rb +36 -0
- data/lib/inferno/dsl/fhir_evaluation/rule.rb +13 -0
- data/lib/inferno/dsl/suite_endpoint.rb +58 -58
- data/lib/inferno/dsl.rb +2 -0
- data/lib/inferno/entities/test_kit.rb +4 -2
- data/lib/inferno/entities/test_suite.rb +23 -3
- data/lib/inferno/entities.rb +1 -0
- data/lib/inferno/ext/json_parser.rb +11 -0
- data/lib/inferno/repositories/presets.rb +12 -6
- data/lib/inferno/result_summarizer.rb +2 -0
- data/lib/inferno/utils/named_thor_actions.rb +5 -1
- data/lib/inferno/version.rb +1 -1
- metadata +14 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '090f68164e2fc19d1f97f62dd0fb13c12c77eb12c29bb9b528c9b9cb56f48770'
|
4
|
+
data.tar.gz: e239a1702ee11a85229db5355ad7c8a415d71b40018c052bb3e2c972c824d12c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2491100649bba23576a442fdeeef561b407e5f7b0b89fbd0827b55ced37e1dcf29c1f5b908c316e44c38301a74d760b5fa8bba4b2cfdf5e039d36fab4c3c181f
|
7
|
+
data.tar.gz: e05eb12863387acecd5782267f25700d3a2e233ed8f581bda98627a76822c33b5e6a1f0ed8e770a6a9d971c88be610453f0aac9a13245b8412f2cb7673431327
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require_relative '../../../inferno/dsl/fhir_evaluation/evaluator'
|
2
|
+
|
3
|
+
module Inferno
|
4
|
+
module CLI
|
5
|
+
class Evaluate
|
6
|
+
def run(ig_path, data_path, _log_level)
|
7
|
+
validate_args(ig_path, data_path)
|
8
|
+
|
9
|
+
# IG Import, rule execution, and result output below will be integrated at phase 2 and 3.
|
10
|
+
|
11
|
+
# @ig = File.join(__dir__, 'ig', ig_path)
|
12
|
+
# if data_path
|
13
|
+
# DatasetLoader.from_path(File.join(__dir__, data_path))
|
14
|
+
# else
|
15
|
+
# ig.examples
|
16
|
+
# end
|
17
|
+
|
18
|
+
# config = Config.new
|
19
|
+
# evaluator = Inferno::DSL::FHIREvaluation::Evaluator.new(data, config)
|
20
|
+
|
21
|
+
# results = evaluate()
|
22
|
+
# output_results(results, options[:output])
|
23
|
+
end
|
24
|
+
|
25
|
+
def validate_args(ig_path, data_path)
|
26
|
+
raise 'A path to an IG is required!' unless ig_path
|
27
|
+
|
28
|
+
return unless data_path && (!File.directory? data_path)
|
29
|
+
|
30
|
+
raise "Provided path '#{data_path}' is not a directory"
|
31
|
+
end
|
32
|
+
|
33
|
+
def output_results(results, output)
|
34
|
+
if output&.end_with?('json')
|
35
|
+
oo = FhirEvaluator::EvaluationResult.to_operation_outcome(results)
|
36
|
+
File.write(output, oo.to_json)
|
37
|
+
puts "Results written to #{output}"
|
38
|
+
else
|
39
|
+
counts = results.group_by(&:severity).transform_values(&:count)
|
40
|
+
print(counts, 'Result Count')
|
41
|
+
puts "\n"
|
42
|
+
puts results
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def print(output_fields, title)
|
47
|
+
puts("╔══════════════ #{title} ═══════════════╗")
|
48
|
+
puts('║ ╭────────────────┬──────────────────────╮ ║')
|
49
|
+
output_fields.each_with_index do |(key, value), i|
|
50
|
+
field_name = pad(key, 14)
|
51
|
+
field_value = pad(value.to_s, 20)
|
52
|
+
puts("║ │ #{field_name} │ #{field_value} │ ║")
|
53
|
+
puts('║ ├────────────────┼──────────────────────┤ ║') unless i == output_fields.length - 1
|
54
|
+
end
|
55
|
+
puts('║ ╰────────────────┴──────────────────────╯ ║')
|
56
|
+
puts('╚═══════════════════════════════════════════╝')
|
57
|
+
end
|
58
|
+
|
59
|
+
def pad(string, length)
|
60
|
+
format("%#{length}.#{length}s", string)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -44,10 +44,12 @@ module Inferno
|
|
44
44
|
|
45
45
|
self.options = options
|
46
46
|
|
47
|
-
outputter.print_start_message(options)
|
47
|
+
outputter.print_start_message(self.options)
|
48
|
+
|
49
|
+
load_preset_file_and_set_preset_id
|
48
50
|
|
49
51
|
results = []
|
50
|
-
outputter.print_around_run(options) do
|
52
|
+
outputter.print_around_run(self.options) do
|
51
53
|
if all_selected_groups_and_tests.empty?
|
52
54
|
test_run = create_test_run(suite)
|
53
55
|
run_one(suite, test_run)
|
@@ -102,6 +104,18 @@ module Inferno
|
|
102
104
|
@outputter ||= OUTPUTTERS[options[:outputter]].new
|
103
105
|
end
|
104
106
|
|
107
|
+
def load_preset_file_and_set_preset_id
|
108
|
+
return unless options[:preset_file]
|
109
|
+
raise StandardError, 'Cannot use `--preset-id` and `--preset-file` options together' if options[:preset_id]
|
110
|
+
|
111
|
+
raise StandardError, "File #{options[:preset_file]} not found" unless File.exist? options[:preset_file]
|
112
|
+
|
113
|
+
options[:preset_id] = JSON.parse(File.read(options[:preset_file]))['id']
|
114
|
+
raise StandardError, "Preset #{options[:preset_file]} is missing id" if options[:preset_id].nil?
|
115
|
+
|
116
|
+
presets_repo.insert_from_file(options[:preset_file])
|
117
|
+
end
|
118
|
+
|
105
119
|
def all_selected_groups_and_tests
|
106
120
|
@all_selected_groups_and_tests ||= runnables_by_short_id + groups + tests
|
107
121
|
end
|
@@ -109,7 +123,7 @@ module Inferno
|
|
109
123
|
def run_one(runnable, test_run)
|
110
124
|
verify_runnable(
|
111
125
|
runnable,
|
112
|
-
thor_hash_to_inputs_array(
|
126
|
+
thor_hash_to_inputs_array(inputs_and_preset),
|
113
127
|
test_session.suite_options
|
114
128
|
)
|
115
129
|
|
@@ -118,6 +132,33 @@ module Inferno
|
|
118
132
|
dispatch_job(test_run)
|
119
133
|
end
|
120
134
|
|
135
|
+
def inputs_and_preset
|
136
|
+
if preset
|
137
|
+
preset_inputs = preset.inputs.to_h do |preset_input|
|
138
|
+
[preset_input[:name], preset_input[:value]]
|
139
|
+
end
|
140
|
+
|
141
|
+
options.fetch(:inputs, {}).reverse_merge(preset_inputs)
|
142
|
+
else
|
143
|
+
options.fetch(:inputs, {})
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def preset
|
148
|
+
return unless options[:preset_id]
|
149
|
+
|
150
|
+
@preset ||= presets_repo.find(options[:preset_id])
|
151
|
+
|
152
|
+
raise StandardError, "Preset #{options[:preset_id]} not found" if @preset.nil?
|
153
|
+
|
154
|
+
unless presets_repo.presets_for_suite(suite.id).include?(@preset)
|
155
|
+
raise StandardError,
|
156
|
+
"Preset #{options[:preset_id]} is incompatible with suite #{suite.id}"
|
157
|
+
end
|
158
|
+
|
159
|
+
@preset
|
160
|
+
end
|
161
|
+
|
121
162
|
def suite
|
122
163
|
@suite ||= Inferno::Repositories::TestSuites.new.find(options[:suite])
|
123
164
|
|
@@ -156,6 +197,10 @@ module Inferno
|
|
156
197
|
@session_data_repo ||= Inferno::Repositories::SessionData.new
|
157
198
|
end
|
158
199
|
|
200
|
+
def presets_repo
|
201
|
+
@presets_repo ||= Inferno::Repositories::Presets.new
|
202
|
+
end
|
203
|
+
|
159
204
|
def test_session
|
160
205
|
@test_session ||= test_sessions_repo.create({
|
161
206
|
test_suite_id: suite.id,
|
@@ -169,7 +214,7 @@ module Inferno
|
|
169
214
|
{
|
170
215
|
test_session_id: test_session.id,
|
171
216
|
runnable_id_key(runnable) => runnable.id,
|
172
|
-
inputs: thor_hash_to_inputs_array(
|
217
|
+
inputs: thor_hash_to_inputs_array(inputs_and_preset)
|
173
218
|
}
|
174
219
|
end
|
175
220
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require_relative 'console'
|
2
|
+
require_relative 'evaluate'
|
2
3
|
require_relative 'migration'
|
3
4
|
require_relative 'services'
|
4
5
|
require_relative 'suite'
|
@@ -10,6 +11,43 @@ require_relative 'execute'
|
|
10
11
|
module Inferno
|
11
12
|
module CLI
|
12
13
|
class Main < Thor
|
14
|
+
desc 'evaluate', 'Run a FHIR Data Evaluator.'
|
15
|
+
long_desc <<-LONGDESC
|
16
|
+
Evaluate FHIR data in the context of a given Implementation Guide,
|
17
|
+
by applying a set of predefined rules designed to check that datasets are comprehensive.
|
18
|
+
Issues identified will be printed to console or to a json file.
|
19
|
+
|
20
|
+
You must have background services running: `bundle exec inferno services start`
|
21
|
+
|
22
|
+
Run the evaluation CLI with
|
23
|
+
|
24
|
+
`bundle exec inferno evaluate ig_path`
|
25
|
+
|
26
|
+
Examples:
|
27
|
+
|
28
|
+
# Load the us core ig and evaluate the data in the provided example folder. If there are examples in the IG already, they will be ignored.
|
29
|
+
`bundle exec inferno evaluate ./uscore.tgz -d ./package/example`
|
30
|
+
|
31
|
+
# Loads the us core ig and evaluate the data included in the IG's example folder
|
32
|
+
`bundle exec inferno evaluate ./uscore.tgz`
|
33
|
+
|
34
|
+
# 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
|
35
|
+
`bundle exec inferno evaluate ./uscore.tgz --output outcome.json`
|
36
|
+
LONGDESC
|
37
|
+
# TODO: Add options below as arguments
|
38
|
+
option :data_path,
|
39
|
+
aliases: ['-d'],
|
40
|
+
type: :string,
|
41
|
+
desc: 'Example FHIR data path'
|
42
|
+
# TODO: implement option of exporting result as OperationOutcome
|
43
|
+
option :output,
|
44
|
+
aliases: ['-o'],
|
45
|
+
type: :string,
|
46
|
+
desc: 'Export evaluation result to outcome.json as an OperationOutcome'
|
47
|
+
def evaluate(ig_path)
|
48
|
+
Evaluate.new.run(ig_path, options[:data_path], Logger::INFO)
|
49
|
+
end
|
50
|
+
|
13
51
|
desc 'console', 'Start an interactive console session with Inferno'
|
14
52
|
def console
|
15
53
|
Migration.new.run(Logger::INFO)
|
@@ -125,7 +163,15 @@ module Inferno
|
|
125
163
|
option :inputs,
|
126
164
|
aliases: ['-i'],
|
127
165
|
type: :hash,
|
128
|
-
desc: 'Inputs (i.e: --inputs=foo:bar goo:baz)'
|
166
|
+
desc: 'Inputs (i.e: --inputs=foo:bar goo:baz); will merge and override preset inputs'
|
167
|
+
option :preset_id,
|
168
|
+
aliases: ['-P'],
|
169
|
+
type: :string,
|
170
|
+
desc: 'Inferno preset id; cannot be used with `--preset-file`'
|
171
|
+
option :preset_file,
|
172
|
+
aliases: ['-p'],
|
173
|
+
type: :string,
|
174
|
+
desc: 'Path to an Inferno preset file for inputs; cannot be used with `--preset-id`'
|
129
175
|
option :outputter,
|
130
176
|
aliases: ['-o'],
|
131
177
|
default: 'console',
|
@@ -142,7 +188,7 @@ module Inferno
|
|
142
188
|
desc: 'Display this message'
|
143
189
|
def execute
|
144
190
|
Execute.boot_full_inferno
|
145
|
-
Execute.new.run(options)
|
191
|
+
Execute.new.run(options.dup) # dup to unfreeze Thor options
|
146
192
|
end
|
147
193
|
|
148
194
|
# https://github.com/rails/thor/issues/244 - Make Thor exit(1) on Errors/Exceptions
|
@@ -1,11 +1,15 @@
|
|
1
|
+
require_relative 'lib/<%= library_name %>/version'
|
2
|
+
|
1
3
|
Gem::Specification.new do |spec|
|
2
4
|
spec.name = '<%= library_name %>'
|
3
|
-
spec.version =
|
5
|
+
spec.version = <%= module_name %>::VERSION
|
4
6
|
spec.authors = <%= authors %>
|
5
7
|
# spec.email = ['TODO']
|
6
8
|
spec.date = Time.now.utc.strftime('%Y-%m-%d')
|
7
|
-
spec.summary = '<%= title_name %>
|
8
|
-
spec.description =
|
9
|
+
spec.summary = '<%= title_name %>'
|
10
|
+
# spec.description = <<~DESCRIPTION
|
11
|
+
# This is a big markdown description of the test kit.
|
12
|
+
# DESCRIPTION
|
9
13
|
# spec.homepage = 'TODO'
|
10
14
|
spec.license = 'Apache-2.0'
|
11
15
|
spec.add_runtime_dependency 'inferno_core', '~> <%= Inferno::VERSION %>'
|
@@ -14,11 +18,14 @@ Gem::Specification.new do |spec|
|
|
14
18
|
spec.add_development_dependency 'rspec', '~> 3.10'
|
15
19
|
spec.add_development_dependency 'webmock', '~> 3.11'
|
16
20
|
spec.required_ruby_version = Gem::Requirement.new('>= 3.1.2')
|
21
|
+
spec.metadata['inferno_test_kit'] = 'true'
|
17
22
|
# spec.metadata['homepage_uri'] = spec.homepage
|
18
23
|
# spec.metadata['source_code_uri'] = 'TODO'
|
19
24
|
spec.files = [
|
20
25
|
Dir['lib/**/*.rb'],
|
21
26
|
Dir['lib/**/*.json'],
|
27
|
+
Dir['config/presets/*.json'],
|
28
|
+
Dir['config/presets/*.json.erb'],
|
22
29
|
'LICENSE'
|
23
30
|
].flatten
|
24
31
|
|
@@ -6,12 +6,13 @@ RUN mkdir -p $INSTALL_PATH
|
|
6
6
|
|
7
7
|
WORKDIR $INSTALL_PATH
|
8
8
|
|
9
|
+
ADD lib/<%= library_name %>/metadata.rb $INSTALL_PATH/lib/<%= library_name %>/metadata.rb
|
9
10
|
ADD *.gemspec $INSTALL_PATH
|
10
11
|
ADD Gemfile* $INSTALL_PATH
|
11
12
|
RUN gem install bundler
|
12
|
-
# The below RUN line is commented out for development purposes, because any change to the
|
13
|
+
# The below RUN line is commented out for development purposes, because any change to the
|
13
14
|
# required gems will break the dockerfile build process.
|
14
|
-
# If you want to run in Deploy mode, just run `bundle install` locally to update
|
15
|
+
# If you want to run in Deploy mode, just run `bundle install` locally to update
|
15
16
|
# Gemfile.lock, and uncomment the following line.
|
16
17
|
# RUN bundle config set --local deployment 'true'
|
17
18
|
RUN bundle install
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative 'version'
|
2
|
+
|
3
|
+
module <%= module_name %>
|
4
|
+
class Metadata < Inferno::TestKit
|
5
|
+
id :<%= test_kit_id %>
|
6
|
+
title '<%= title_name %>'
|
7
|
+
description <<~DESCRIPTION
|
8
|
+
This is a big markdown description of the test kit.
|
9
|
+
DESCRIPTION
|
10
|
+
suite_ids [:<%= test_suite_id %>]
|
11
|
+
# tags ['SMART App Launch', 'US Core']
|
12
|
+
# last_updated '2024-03-07'
|
13
|
+
version VERSION
|
14
|
+
maturity 'Low'
|
15
|
+
authors <%= authors %>
|
16
|
+
# repo 'TODO'
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require_relative 'metadata'
|
2
|
+
require_relative 'patient_group'
|
3
|
+
|
4
|
+
module <%= module_name %>
|
5
|
+
class Suite < Inferno::TestSuite
|
6
|
+
id :<%= test_suite_id %>
|
7
|
+
title '<%= title_name %> Test Suite'
|
8
|
+
description '<%= human_name %> test suite.'
|
9
|
+
|
10
|
+
# These inputs will be available to all tests in this suite
|
11
|
+
input :url,
|
12
|
+
title: 'FHIR Server Base Url'
|
13
|
+
|
14
|
+
input :credentials,
|
15
|
+
title: 'OAuth Credentials',
|
16
|
+
type: :oauth_credentials,
|
17
|
+
optional: true
|
18
|
+
|
19
|
+
# All FHIR requests in this suite will use this FHIR client
|
20
|
+
fhir_client do
|
21
|
+
url :url
|
22
|
+
oauth_credentials :credentials
|
23
|
+
end
|
24
|
+
|
25
|
+
# All FHIR validation requests will use this FHIR validator
|
26
|
+
fhir_resource_validator do
|
27
|
+
# igs 'identifier#version' # Use this method for published IGs/versions
|
28
|
+
# igs 'igs/filename.tgz' # Use this otherwise
|
29
|
+
|
30
|
+
exclude_message do |message|
|
31
|
+
message.message.match?(/\A\S+: \S+: URL value '.*' does not resolve/)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Tests and TestGroups can be defined inline
|
36
|
+
group do
|
37
|
+
id :capability_statement
|
38
|
+
title 'Capability Statement'
|
39
|
+
description 'Verify that the server has a CapabilityStatement'
|
40
|
+
|
41
|
+
test do
|
42
|
+
id :capability_statement_read
|
43
|
+
title 'Read CapabilityStatement'
|
44
|
+
description 'Read CapabilityStatement from /metadata endpoint'
|
45
|
+
|
46
|
+
run do
|
47
|
+
fhir_get_capability_statement
|
48
|
+
|
49
|
+
assert_response_status(200)
|
50
|
+
assert_resource_type(:capability_statement)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Tests and TestGroups can be written in separate files and then included
|
56
|
+
# using their id
|
57
|
+
group from: :patient_group
|
58
|
+
end
|
59
|
+
end
|
@@ -1,58 +1 @@
|
|
1
|
-
require_relative '<%= library_name %>/
|
2
|
-
|
3
|
-
module <%= module_name %>
|
4
|
-
class Suite < Inferno::TestSuite
|
5
|
-
id :<%= test_suite_id %>
|
6
|
-
title '<%= title_name %> Test Suite'
|
7
|
-
description '<%= human_name %> test suite.'
|
8
|
-
|
9
|
-
# These inputs will be available to all tests in this suite
|
10
|
-
input :url,
|
11
|
-
title: 'FHIR Server Base Url'
|
12
|
-
|
13
|
-
input :credentials,
|
14
|
-
title: 'OAuth Credentials',
|
15
|
-
type: :oauth_credentials,
|
16
|
-
optional: true
|
17
|
-
|
18
|
-
# All FHIR requests in this suite will use this FHIR client
|
19
|
-
fhir_client do
|
20
|
-
url :url
|
21
|
-
oauth_credentials :credentials
|
22
|
-
end
|
23
|
-
|
24
|
-
# All FHIR validation requests will use this FHIR validator
|
25
|
-
fhir_resource_validator do
|
26
|
-
# igs 'identifier#version' # Use this method for published IGs/versions
|
27
|
-
# igs 'igs/filename.tgz' # Use this otherwise
|
28
|
-
|
29
|
-
exclude_message do |message|
|
30
|
-
message.message.match?(/\A\S+: \S+: URL value '.*' does not resolve/)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
# Tests and TestGroups can be defined inline
|
35
|
-
group do
|
36
|
-
id :capability_statement
|
37
|
-
title 'Capability Statement'
|
38
|
-
description 'Verify that the server has a CapabilityStatement'
|
39
|
-
|
40
|
-
test do
|
41
|
-
id :capability_statement_read
|
42
|
-
title 'Read CapabilityStatement'
|
43
|
-
description 'Read CapabilityStatement from /metadata endpoint'
|
44
|
-
|
45
|
-
run do
|
46
|
-
fhir_get_capability_statement
|
47
|
-
|
48
|
-
assert_response_status(200)
|
49
|
-
assert_resource_type(:capability_statement)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
# Tests and TestGroups can be written in separate files and then included
|
55
|
-
# using their id
|
56
|
-
group from: :patient_group
|
57
|
-
end
|
58
|
-
end
|
1
|
+
require_relative '<%= library_name %>/suite'
|
@@ -1,6 +1,10 @@
|
|
1
1
|
require 'hanami/middleware/body_parser'
|
2
2
|
require_relative 'router'
|
3
3
|
|
4
|
+
# Only required to monkey patch the JSON parser to support application/fhir+json
|
5
|
+
require 'hanami/middleware/body_parser/json_parser'
|
6
|
+
require_relative '../../ext/json_parser'
|
7
|
+
|
4
8
|
module Inferno
|
5
9
|
module Web
|
6
10
|
def self.app
|
@@ -9,10 +9,18 @@
|
|
9
9
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
10
10
|
<meta name="theme-color" content="#000000" />
|
11
11
|
<meta id="base-path" name="base-path" content="<%= Inferno::Application['base_path'] %>">
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
/>
|
12
|
+
|
13
|
+
<!-- Social media link unfurling meta tags -->
|
14
|
+
<title>Inferno Test Session</title>
|
15
|
+
<link rel="canonical" href="<%= Inferno::Application['base_url'] %>" />
|
16
|
+
<meta name="application-name" content="Inferno" />
|
17
|
+
<meta name="og:image" content="<%= Inferno::Application['inferno_host'] %><%= Inferno::Application['public_path'] %>/logo192.png" />
|
18
|
+
<meta name="og:type" content="website" />
|
19
|
+
<meta name="og:url" content="<%= Inferno::Application['base_url'] %>" />
|
20
|
+
<meta name="og:site_name" content="Inferno" />
|
21
|
+
<meta name="twitter:card" content="summary" />
|
22
|
+
<meta name="twitter:image" content="<%= Inferno::Application['inferno_host'] %><%= Inferno::Application['public_path'] %>/logo192.png" />
|
23
|
+
|
16
24
|
<link rel="apple-touch-icon" href="<%= Inferno::Application['public_path'] %>/logo192.png" />
|
17
25
|
<!--
|
18
26
|
manifest.json provides metadata used when your web app is installed on a
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require_relative 'markdown_extractor'
|
1
2
|
require_relative 'serializer'
|
2
3
|
|
3
4
|
module Inferno
|
@@ -7,7 +8,7 @@ module Inferno
|
|
7
8
|
identifier :name
|
8
9
|
|
9
10
|
field :title, if: :field_present?
|
10
|
-
field :description, if: :field_present?
|
11
|
+
field :description, extractor: MarkdownExtractor, if: :field_present?
|
11
12
|
field :type, if: :field_present?
|
12
13
|
field :default, if: :field_present?
|
13
14
|
field :optional, if: :field_present?
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'blueprinter'
|
2
|
+
require_relative '../../../utils/markdown_formatter'
|
3
|
+
|
4
|
+
module Inferno
|
5
|
+
module Web
|
6
|
+
module Serializers
|
7
|
+
class MarkdownExtractor < Blueprinter::Extractor
|
8
|
+
include Inferno::Utils::MarkdownFormatter
|
9
|
+
|
10
|
+
def extract(field_name, object, _local_options, _options = {})
|
11
|
+
format_markdown(object.send(field_name))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -4,9 +4,26 @@ Inferno::Application.register_provider(:presets) do
|
|
4
4
|
prepare do
|
5
5
|
target_container.start :suites
|
6
6
|
|
7
|
+
presets_repo = Inferno::Repositories::Presets.new
|
8
|
+
|
9
|
+
test_kit_gems =
|
10
|
+
Bundler
|
11
|
+
.definition
|
12
|
+
.specs
|
13
|
+
.select { |spec| spec.metadata.fetch('inferno_test_kit', 'false').casecmp? 'true' }
|
14
|
+
|
7
15
|
files_to_load = Dir.glob(['config/presets/*.json', 'config/presets/*.json.erb'])
|
16
|
+
files_to_load +=
|
17
|
+
test_kit_gems.flat_map do |gem|
|
18
|
+
[
|
19
|
+
Dir.glob([File.join(gem.full_gem_path, 'config', 'presets', '*.json')]),
|
20
|
+
Dir.glob([File.join(gem.full_gem_path, 'config', 'presets', '*.json.erb')])
|
21
|
+
].flatten
|
22
|
+
end
|
23
|
+
|
24
|
+
files_to_load.compact!
|
25
|
+
files_to_load.uniq!
|
8
26
|
files_to_load.map! { |path| File.realpath(path) }
|
9
|
-
presets_repo = Inferno::Repositories::Presets.new
|
10
27
|
|
11
28
|
files_to_load.each do |path|
|
12
29
|
presets_repo.insert_from_file(path)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Inferno
|
2
|
+
module DSL
|
3
|
+
module FHIREvaluation
|
4
|
+
class Config
|
5
|
+
DEFAULT_FILE = File.join(__dir__, 'default.yml')
|
6
|
+
attr_accessor :data
|
7
|
+
|
8
|
+
# To-do: add config_file as arguments
|
9
|
+
def initialize(config_file = nil)
|
10
|
+
@data = if config_file.nil?
|
11
|
+
YAML.load_file(File.absolute_path(DEFAULT_FILE))
|
12
|
+
else
|
13
|
+
YAML.load_file(File.absolute_path(config_file))
|
14
|
+
end
|
15
|
+
|
16
|
+
raise(TypeError, 'Malformed configuration') unless @data.is_a?(Hash)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Inferno
|
2
|
+
module DSL
|
3
|
+
module FHIREvaluation
|
4
|
+
module DatasetLoader
|
5
|
+
def self.from_contents(source_array)
|
6
|
+
dataset = []
|
7
|
+
|
8
|
+
source_array.each do |json|
|
9
|
+
resource = FHIR::Json.from_json(json)
|
10
|
+
next if resource.nil?
|
11
|
+
|
12
|
+
dataset.push resource
|
13
|
+
end
|
14
|
+
|
15
|
+
dataset
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.from_path(path)
|
19
|
+
dataset = []
|
20
|
+
|
21
|
+
Dir["#{path}/*.json"].each do |f|
|
22
|
+
resource = FHIR::Json.from_json(File.read(f))
|
23
|
+
next if resource.nil?
|
24
|
+
|
25
|
+
dataset.push resource
|
26
|
+
end
|
27
|
+
|
28
|
+
dataset
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Inferno
|
2
|
+
module DSL
|
3
|
+
module FHIREvaluation
|
4
|
+
# EvaluationContext is a wrapper class around the concepts needed to perform an evaluation:
|
5
|
+
# - The IG used as the basis for evaluation
|
6
|
+
# - The data being evaluated
|
7
|
+
# - A summary/characterization of the data
|
8
|
+
# - Evaluation results
|
9
|
+
class EvaluationContext
|
10
|
+
attr_reader :ig, :data, :results, :config
|
11
|
+
|
12
|
+
def initialize(ig, data, config) # rubocop:disable Naming/MethodParameterName
|
13
|
+
@ig = ig
|
14
|
+
@data = data
|
15
|
+
@results = []
|
16
|
+
@config = config
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_result(result)
|
20
|
+
results.push result
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Inferno
|
2
|
+
module DSL
|
3
|
+
module FHIREvaluation
|
4
|
+
# The result of a Rule evaluating a data set.
|
5
|
+
class EvaluationResult
|
6
|
+
attr_accessor :message,
|
7
|
+
:severity, # fatal | error | warning | information | success
|
8
|
+
:issue_type, # https://www.hl7.org/fhir/valueset-issue-type.html
|
9
|
+
:threshold, # quantitative value that a rule checks for
|
10
|
+
:value, # actual observed value
|
11
|
+
:rule # Rule that produced this result
|
12
|
+
|
13
|
+
def initialize(message, severity: 'warning', issue_type: 'business-rule', threshold: nil, value: nil, rule: nil)
|
14
|
+
@message = message
|
15
|
+
@severity = severity
|
16
|
+
@issue_type = issue_type
|
17
|
+
@threshold = threshold
|
18
|
+
@value = value
|
19
|
+
@rule = rule
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
"#{severity.upcase}: #{message}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_oo_issue
|
27
|
+
issue = {
|
28
|
+
severity:,
|
29
|
+
code: issue_type,
|
30
|
+
details: { text: message }
|
31
|
+
}
|
32
|
+
|
33
|
+
if threshold
|
34
|
+
issue[:extension] ||= []
|
35
|
+
issue[:extension].push({
|
36
|
+
# TODO: pick real extension for this
|
37
|
+
url: 'https://inferno-framework.github.io/fhir_evaluator/StructureDefinition/operationoutcome-issue-threshold',
|
38
|
+
valueDecimal: threshold
|
39
|
+
})
|
40
|
+
end
|
41
|
+
|
42
|
+
if value
|
43
|
+
issue[:extension] ||= []
|
44
|
+
issue[:extension].push({
|
45
|
+
# TODO: pick real extension for this
|
46
|
+
url: 'https://inferno-framework.github.io/fhir_evaluator/StructureDefinition/operationoutcome-issue-value',
|
47
|
+
valueDecimal: value
|
48
|
+
})
|
49
|
+
end
|
50
|
+
|
51
|
+
issue
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.to_operation_outcome(results)
|
55
|
+
FHIR::OperationOutcome.new({
|
56
|
+
issue: results.map(&:to_oo_issue)
|
57
|
+
})
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'config'
|
4
|
+
require_relative 'rule'
|
5
|
+
require_relative 'evaluation_context'
|
6
|
+
require_relative 'evaluation_result'
|
7
|
+
require_relative 'dataset_loader'
|
8
|
+
|
9
|
+
module Inferno
|
10
|
+
module DSL
|
11
|
+
module FHIREvaluation
|
12
|
+
class Evaluator
|
13
|
+
attr_accessor :ig
|
14
|
+
|
15
|
+
def initialize(ig) # rubocop:disable Naming/MethodParameterName
|
16
|
+
@ig = ig
|
17
|
+
end
|
18
|
+
|
19
|
+
def evaluate(data, config = Config.new)
|
20
|
+
context = EvaluationContext.new(@ig, data, config)
|
21
|
+
|
22
|
+
active_rules = []
|
23
|
+
config.data['Rule'].each do |rulename, rule_details|
|
24
|
+
active_rules << rulename if rule_details['Enabled']
|
25
|
+
end
|
26
|
+
|
27
|
+
Rule.descendants.each do |rule|
|
28
|
+
rule.new.check(context) if active_rules.include?(rule.name.demodulize)
|
29
|
+
end
|
30
|
+
|
31
|
+
context.results
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -9,54 +9,54 @@ module Inferno
|
|
9
9
|
# endpoint](https://github.com/hanami/controller/tree/v2.0.0).
|
10
10
|
#
|
11
11
|
# @example
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
12
|
+
# class AuthorizedEndpoint < Inferno::DSL::SuiteEndpoint
|
13
|
+
# # Identify the incoming request based on a bearer token
|
14
|
+
# def test_run_identifier
|
15
|
+
# request.header['authorization']&.delete_prefix('Bearer ')
|
16
|
+
# end
|
17
17
|
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
18
|
+
# # Return a json FHIR Patient resource
|
19
|
+
# def make_response
|
20
|
+
# response.status = 200
|
21
|
+
# response.body = FHIR::Patient.new(id: 'abcdef').to_json
|
22
|
+
# response.format = :json
|
23
|
+
# end
|
24
24
|
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
25
|
+
# # Update the waiting test to pass when the incoming request is received.
|
26
|
+
# # This will resume the test run.
|
27
|
+
# def update_result
|
28
|
+
# results_repo.update(result.id, result: 'pass')
|
29
|
+
# end
|
30
30
|
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
31
|
+
# # Apply the 'authorized' tag to the incoming request so that it may be
|
32
|
+
# # used by later tests.
|
33
|
+
# def tags
|
34
|
+
# ['authorized']
|
35
|
+
# end
|
36
|
+
# end
|
37
37
|
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
38
|
+
# class AuthorizedRequestSuite < Inferno::TestSuite
|
39
|
+
# id :authorized_suite
|
40
|
+
# suite_endpoint :get, '/authorized_endpoint', AuthorizedEndpoint
|
41
41
|
#
|
42
|
-
#
|
43
|
-
#
|
42
|
+
# group do
|
43
|
+
# title 'Authorized Request Group'
|
44
44
|
#
|
45
|
-
#
|
46
|
-
#
|
45
|
+
# test do
|
46
|
+
# title 'Wait for authorized request'
|
47
47
|
#
|
48
|
-
#
|
48
|
+
# input :bearer_token
|
49
49
|
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
50
|
+
# run do
|
51
|
+
# wait(
|
52
|
+
# identifier: bearer_token,
|
53
|
+
# message: "Waiting to receive a request with bearer_token: #{bearer_token}" \
|
54
|
+
# "at `#{Inferno::Application['base_url']}/custom/authorized_suite/authorized_endpoint`"
|
55
|
+
# )
|
56
|
+
# end
|
57
|
+
# end
|
56
58
|
# end
|
57
59
|
# end
|
58
|
-
# end
|
59
|
-
# end
|
60
60
|
class SuiteEndpoint < Hanami::Action
|
61
61
|
attr_reader :req, :res
|
62
62
|
|
@@ -69,11 +69,11 @@ module Inferno
|
|
69
69
|
# @return [String]
|
70
70
|
#
|
71
71
|
# @example
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
72
|
+
# def test_run_identifier
|
73
|
+
# # Identify the test session of an incoming request based on the bearer
|
74
|
+
# # token
|
75
|
+
# request.headers['authorization']&.delete_prefix('Bearer ')
|
76
|
+
# end
|
77
77
|
def test_run_identifier
|
78
78
|
nil
|
79
79
|
end
|
@@ -83,11 +83,11 @@ module Inferno
|
|
83
83
|
# @return [Void]
|
84
84
|
#
|
85
85
|
# @example
|
86
|
-
#
|
87
|
-
#
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
86
|
+
# def make_response
|
87
|
+
# response.status = 200
|
88
|
+
# response.body = { abc: 123 }.to_json
|
89
|
+
# response.format = :json
|
90
|
+
# end
|
91
91
|
def make_response
|
92
92
|
nil
|
93
93
|
end
|
@@ -113,9 +113,9 @@ module Inferno
|
|
113
113
|
# @return [Void]
|
114
114
|
#
|
115
115
|
# @example
|
116
|
-
#
|
117
|
-
#
|
118
|
-
#
|
116
|
+
# def update_result
|
117
|
+
# results_repo.update(result.id, result: 'pass')
|
118
|
+
# end
|
119
119
|
def update_result
|
120
120
|
nil
|
121
121
|
end
|
@@ -165,9 +165,9 @@ module Inferno
|
|
165
165
|
# @return [Hanami::Action::Request]
|
166
166
|
#
|
167
167
|
# @example
|
168
|
-
#
|
169
|
-
#
|
170
|
-
#
|
168
|
+
# request.params # Get url/query params
|
169
|
+
# request.body.read # Get body
|
170
|
+
# request.headers['accept'] # Get Accept header
|
171
171
|
def request
|
172
172
|
req
|
173
173
|
end
|
@@ -178,10 +178,10 @@ module Inferno
|
|
178
178
|
# @return [Hanami::Action::Response]
|
179
179
|
#
|
180
180
|
# @example
|
181
|
-
#
|
182
|
-
#
|
183
|
-
#
|
184
|
-
#
|
181
|
+
# response.status = 200 # Set the status
|
182
|
+
# response.body = 'Ok' # Set the body
|
183
|
+
# # Set headers
|
184
|
+
# response.headers.merge!('X-Custom-Header' => 'CUSTOM_HEADER_VALUE')
|
185
185
|
def response
|
186
186
|
res
|
187
187
|
end
|
data/lib/inferno/dsl.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require_relative 'dsl/assertions'
|
2
2
|
require_relative 'dsl/fhir_client'
|
3
3
|
require_relative 'dsl/fhir_validation'
|
4
|
+
require_relative 'dsl/fhir_evaluation/evaluator'
|
4
5
|
require_relative 'dsl/fhir_resource_validation'
|
5
6
|
require_relative 'dsl/fhirpath_evaluation'
|
6
7
|
require_relative 'dsl/http_client'
|
@@ -18,6 +19,7 @@ module Inferno
|
|
18
19
|
HTTPClient,
|
19
20
|
Results,
|
20
21
|
FHIRValidation,
|
22
|
+
FHIREvaluation,
|
21
23
|
FHIRResourceValidation,
|
22
24
|
FhirpathEvaluation,
|
23
25
|
Messages
|
@@ -6,7 +6,7 @@ module Inferno
|
|
6
6
|
# @example
|
7
7
|
#
|
8
8
|
# module USCoreTestKit
|
9
|
-
# class
|
9
|
+
# class Metadata < Inferno::Entities::TestKit
|
10
10
|
# id :us_core
|
11
11
|
# title 'US Core Test Kit'
|
12
12
|
# description <<~DESCRIPTION
|
@@ -156,7 +156,7 @@ module Inferno
|
|
156
156
|
|
157
157
|
# @private
|
158
158
|
def repository
|
159
|
-
@repository ||= Inferno::Repositories::TestKits
|
159
|
+
@repository ||= Inferno::Repositories::TestKits.new
|
160
160
|
end
|
161
161
|
|
162
162
|
# @private
|
@@ -168,4 +168,6 @@ module Inferno
|
|
168
168
|
end
|
169
169
|
end
|
170
170
|
end
|
171
|
+
|
172
|
+
TestKit = Entities::TestKit
|
171
173
|
end
|
@@ -84,15 +84,16 @@ module Inferno
|
|
84
84
|
}
|
85
85
|
end
|
86
86
|
|
87
|
-
# Set/get the version of this test suite.
|
87
|
+
# Set/get the version of this test suite. Defaults to the TestKit
|
88
|
+
# version.
|
88
89
|
#
|
89
90
|
# @param version [String]
|
90
91
|
#
|
91
92
|
# @return [String, nil]
|
92
93
|
def version(version = nil)
|
93
|
-
|
94
|
+
@version = version if version.present?
|
94
95
|
|
95
|
-
@version
|
96
|
+
@version || test_kit&.version
|
96
97
|
end
|
97
98
|
|
98
99
|
# @private
|
@@ -186,6 +187,25 @@ module Inferno
|
|
186
187
|
|
187
188
|
@suite_summary = format_markdown(suite_summary)
|
188
189
|
end
|
190
|
+
|
191
|
+
# Get the TestKit this suite belongs to
|
192
|
+
#
|
193
|
+
# @return [Inferno::Entities::TestKit]
|
194
|
+
def test_kit
|
195
|
+
return @test_kit if @test_kit
|
196
|
+
|
197
|
+
module_name = name
|
198
|
+
|
199
|
+
while module_name.present? && @test_kit.nil?
|
200
|
+
module_name = module_name.deconstantize
|
201
|
+
|
202
|
+
next unless const_defined?("#{module_name}::Metadata")
|
203
|
+
|
204
|
+
@test_kit = const_get("#{module_name}::Metadata")
|
205
|
+
end
|
206
|
+
|
207
|
+
@test_kit
|
208
|
+
end
|
189
209
|
end
|
190
210
|
end
|
191
211
|
end
|
data/lib/inferno/entities.rb
CHANGED
@@ -8,6 +8,7 @@ require_relative 'entities/result'
|
|
8
8
|
require_relative 'entities/session_data'
|
9
9
|
require_relative 'entities/test'
|
10
10
|
require_relative 'entities/test_group'
|
11
|
+
require_relative 'entities/test_kit'
|
11
12
|
require_relative 'entities/test_run'
|
12
13
|
require_relative 'entities/test_session'
|
13
14
|
require_relative 'entities/test_suite'
|
@@ -8,14 +8,20 @@ module Inferno
|
|
8
8
|
# Repository that deals with persistence for the `Preset` entity.
|
9
9
|
class Presets < InMemoryRepository
|
10
10
|
def insert_from_file(path)
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
11
|
+
raw_contents =
|
12
|
+
case path
|
13
|
+
when /\.json$/
|
14
|
+
File.read(path)
|
15
|
+
when /\.erb$/
|
16
|
+
ERB.new(File.read(path)).result
|
17
|
+
end
|
18
|
+
|
19
|
+
if Application['base_url'].start_with? 'https://inferno-qa.healthit.gov'
|
20
|
+
raw_contents.gsub!('https://inferno.healthit.gov', 'https://inferno-qa.healthit.gov')
|
17
21
|
end
|
18
22
|
|
23
|
+
preset_hash = JSON.parse(raw_contents)
|
24
|
+
|
19
25
|
preset_hash.deep_symbolize_keys!
|
20
26
|
preset_hash[:id] ||= SecureRandom.uuid
|
21
27
|
preset = Entities::Preset.new(preset_hash)
|
@@ -12,6 +12,8 @@ module Inferno
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def summarize
|
15
|
+
return 'wait' if results.any? { |result| result.result == 'wait' }
|
16
|
+
|
15
17
|
return 'pass' if optional_results_passing_criteria_met?
|
16
18
|
|
17
19
|
prioritized_result_strings.find { |result_string| unique_result_strings.include? result_string }
|
data/lib/inferno/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inferno_core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen MacVicar
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2024-
|
13
|
+
date: 2024-12-17 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
@@ -390,6 +390,7 @@ files:
|
|
390
390
|
- lib/inferno.rb
|
391
391
|
- lib/inferno/apps/cli.rb
|
392
392
|
- lib/inferno/apps/cli/console.rb
|
393
|
+
- lib/inferno/apps/cli/evaluate.rb
|
393
394
|
- lib/inferno/apps/cli/execute.rb
|
394
395
|
- lib/inferno/apps/cli/execute/console_outputter.rb
|
395
396
|
- lib/inferno/apps/cli/execute/json_outputter.rb
|
@@ -432,7 +433,10 @@ files:
|
|
432
433
|
- lib/inferno/apps/cli/templates/lib/%library_name%/igs/.keep
|
433
434
|
- lib/inferno/apps/cli/templates/lib/%library_name%/igs/README.md
|
434
435
|
- lib/inferno/apps/cli/templates/lib/%library_name%/igs/put_ig_package_dot_tgz_here
|
436
|
+
- lib/inferno/apps/cli/templates/lib/%library_name%/metadata.rb.tt
|
435
437
|
- lib/inferno/apps/cli/templates/lib/%library_name%/patient_group.rb.tt
|
438
|
+
- lib/inferno/apps/cli/templates/lib/%library_name%/suite.rb.tt
|
439
|
+
- lib/inferno/apps/cli/templates/lib/%library_name%/version.rb.tt
|
436
440
|
- lib/inferno/apps/cli/templates/run.sh
|
437
441
|
- lib/inferno/apps/cli/templates/setup.sh
|
438
442
|
- lib/inferno/apps/cli/templates/spec/%library_name%/patient_group_spec.rb.tt
|
@@ -461,6 +465,7 @@ files:
|
|
461
465
|
- lib/inferno/apps/web/serializers/hash_value_extractor.rb
|
462
466
|
- lib/inferno/apps/web/serializers/header.rb
|
463
467
|
- lib/inferno/apps/web/serializers/input.rb
|
468
|
+
- lib/inferno/apps/web/serializers/markdown_extractor.rb
|
464
469
|
- lib/inferno/apps/web/serializers/message.rb
|
465
470
|
- lib/inferno/apps/web/serializers/preset.rb
|
466
471
|
- lib/inferno/apps/web/serializers/request.rb
|
@@ -500,6 +505,12 @@ files:
|
|
500
505
|
- lib/inferno/dsl/configurable.rb
|
501
506
|
- lib/inferno/dsl/fhir_client.rb
|
502
507
|
- lib/inferno/dsl/fhir_client_builder.rb
|
508
|
+
- lib/inferno/dsl/fhir_evaluation/config.rb
|
509
|
+
- lib/inferno/dsl/fhir_evaluation/dataset_loader.rb
|
510
|
+
- lib/inferno/dsl/fhir_evaluation/evaluation_context.rb
|
511
|
+
- lib/inferno/dsl/fhir_evaluation/evaluation_result.rb
|
512
|
+
- lib/inferno/dsl/fhir_evaluation/evaluator.rb
|
513
|
+
- lib/inferno/dsl/fhir_evaluation/rule.rb
|
503
514
|
- lib/inferno/dsl/fhir_resource_validation.rb
|
504
515
|
- lib/inferno/dsl/fhir_validation.rb
|
505
516
|
- lib/inferno/dsl/fhirpath_evaluation.rb
|
@@ -539,6 +550,7 @@ files:
|
|
539
550
|
- lib/inferno/exceptions.rb
|
540
551
|
- lib/inferno/ext/fhir_client.rb
|
541
552
|
- lib/inferno/ext/fhir_models.rb
|
553
|
+
- lib/inferno/ext/json_parser.rb
|
542
554
|
- lib/inferno/ext/rack.rb
|
543
555
|
- lib/inferno/jobs.rb
|
544
556
|
- lib/inferno/jobs/execute_test_run.rb
|