inferno_core 0.5.3 → 0.6.0
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 +37 -4
- data/lib/inferno/apps/cli/execute/console_outputter.rb +2 -2
- data/lib/inferno/apps/cli/main.rb +1 -1
- data/lib/inferno/apps/cli/new.rb +8 -3
- data/lib/inferno/apps/cli/suites.rb +0 -2
- data/lib/inferno/apps/cli/templates/%library_name%.gemspec.tt +3 -14
- data/lib/inferno/apps/cli/templates/.rubocop.yml +77 -0
- data/lib/inferno/apps/cli/templates/.ruby-version +1 -1
- data/lib/inferno/apps/cli/templates/.tool-versions +1 -1
- data/lib/inferno/apps/cli/templates/Dockerfile.tt +1 -1
- data/lib/inferno/apps/cli/templates/Gemfile.tt +7 -0
- data/lib/inferno/apps/cli/templates/lib/%library_name%/suite.rb.tt +1 -1
- data/lib/inferno/config/boot/suites.rb +1 -0
- data/lib/inferno/dsl/fhir_resource_validation.rb +2 -2
- data/lib/inferno/dsl/fhir_validation.rb +2 -2
- data/lib/inferno/dsl/suite_endpoint.rb +1 -1
- data/lib/inferno/entities/ig.rb +149 -0
- data/lib/inferno/entities.rb +1 -0
- data/lib/inferno/public/bundle.js +34 -34
- data/lib/inferno/repositories/igs.rb +9 -0
- data/lib/inferno/route_storage.rb +10 -0
- data/lib/inferno/spec_support.rb +2 -0
- data/lib/inferno/utils/ig_downloader.rb +3 -3
- data/lib/inferno/version.rb +1 -1
- data/lib/inferno.rb +1 -3
- data/spec/extract_tgz_helper.rb +13 -0
- data/spec/shared/test_kit_examples.rb +133 -0
- metadata +10 -6
- data/lib/inferno/public/175.bundle.js +0 -1
- data/lib/inferno/public/217.bundle.js +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ee348703cfa562d9316b03c470d62aebd0d4ac232d8dc6029bbac392cb5a64d1
|
4
|
+
data.tar.gz: 666f20e627f22eea29c764f9d10c6a2e421142edd0525631566a678f73ed3a45
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85323238cd047bd7408aa5e50dcbf8bd7ff4bca02bbc985928627bf5431189bb6cee9f0d660218d7bd0684fb38e0f6bfd49aea164cdd08352c463cadaa30ed58
|
7
|
+
data.tar.gz: 8cd139293bf774f09749cbe3e723df226b2b74b79a3141ae144e09e573afcc8712495d9fa80eb62b901e05f5f0e2c7cc2810ea4b2e47ee70b53571964ad04683
|
@@ -1,14 +1,21 @@
|
|
1
1
|
require_relative '../../../inferno/dsl/fhir_evaluation/evaluator'
|
2
|
+
require_relative '../../../inferno/entities'
|
3
|
+
require_relative '../../utils/ig_downloader'
|
4
|
+
|
5
|
+
require 'tempfile'
|
2
6
|
|
3
7
|
module Inferno
|
4
8
|
module CLI
|
5
|
-
class Evaluate
|
6
|
-
|
9
|
+
class Evaluate < Thor::Group
|
10
|
+
include Thor::Actions
|
11
|
+
include Inferno::Utils::IgDownloader
|
12
|
+
|
13
|
+
def evaluate(ig_path, data_path, _log_level)
|
7
14
|
validate_args(ig_path, data_path)
|
15
|
+
_ig = get_ig(ig_path)
|
8
16
|
|
9
|
-
#
|
17
|
+
# Rule execution, and result output below will be integrated soon.
|
10
18
|
|
11
|
-
# @ig = File.join(__dir__, 'ig', ig_path)
|
12
19
|
# if data_path
|
13
20
|
# DatasetLoader.from_path(File.join(__dir__, data_path))
|
14
21
|
# else
|
@@ -30,6 +37,32 @@ module Inferno
|
|
30
37
|
raise "Provided path '#{data_path}' is not a directory"
|
31
38
|
end
|
32
39
|
|
40
|
+
def get_ig(ig_path)
|
41
|
+
if File.exist?(ig_path)
|
42
|
+
ig = Inferno::Entities::IG.from_file(ig_path)
|
43
|
+
elsif in_user_package_cache?(ig_path.sub('@', '#'))
|
44
|
+
# NPM syntax for a package identifier is id@version (eg, hl7.fhir.us.core@3.1.1)
|
45
|
+
# but in the cache the separator is # (hl7.fhir.us.core#3.1.1)
|
46
|
+
cache_directory = File.join(user_package_cache, ig_path.sub('@', '#'))
|
47
|
+
ig = Inferno::Entities::IG.from_file(cache_directory)
|
48
|
+
else
|
49
|
+
Tempfile.create('package.tgz') do |temp_file|
|
50
|
+
load_ig(ig_path, nil, { force: true }, temp_file.path)
|
51
|
+
ig = Inferno::Entities::IG.from_file(temp_file.path)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
ig.add_self_to_repository
|
55
|
+
ig
|
56
|
+
end
|
57
|
+
|
58
|
+
def user_package_cache
|
59
|
+
File.join(Dir.home, '.fhir', 'packages')
|
60
|
+
end
|
61
|
+
|
62
|
+
def in_user_package_cache?(ig_identifier)
|
63
|
+
File.directory?(File.join(user_package_cache, ig_identifier))
|
64
|
+
end
|
65
|
+
|
33
66
|
def output_results(results, output)
|
34
67
|
if output&.end_with?('json')
|
35
68
|
oo = FhirEvaluator::EvaluationResult.to_operation_outcome(results)
|
@@ -45,7 +45,7 @@ module Inferno
|
|
45
45
|
type: :string,
|
46
46
|
desc: 'Export evaluation result to outcome.json as an OperationOutcome'
|
47
47
|
def evaluate(ig_path)
|
48
|
-
Evaluate.new.
|
48
|
+
Evaluate.new.evaluate(ig_path, options[:data_path], Logger::INFO)
|
49
49
|
end
|
50
50
|
|
51
51
|
desc 'console', 'Start an interactive console session with Inferno'
|
data/lib/inferno/apps/cli/new.rb
CHANGED
@@ -71,6 +71,7 @@ module Inferno
|
|
71
71
|
inside(root_name) do
|
72
72
|
bundle_install
|
73
73
|
inferno_migrate
|
74
|
+
initialize_git_repo
|
74
75
|
load_igs
|
75
76
|
end
|
76
77
|
|
@@ -85,7 +86,7 @@ module Inferno
|
|
85
86
|
private
|
86
87
|
|
87
88
|
def authors
|
88
|
-
options['author'].presence || [default_author]
|
89
|
+
(options['author'].presence || [default_author]).to_json.gsub('"', "'")
|
89
90
|
end
|
90
91
|
|
91
92
|
def default_author
|
@@ -106,6 +107,10 @@ module Inferno
|
|
106
107
|
run 'bundle exec inferno migrate', verbose: !options['quiet'], capture: options['quiet']
|
107
108
|
end
|
108
109
|
|
110
|
+
def initialize_git_repo
|
111
|
+
run 'git init -q && git add . && git commit -aqm "initial commit"'
|
112
|
+
end
|
113
|
+
|
109
114
|
def load_igs
|
110
115
|
config = { verbose: !options['quiet'] }
|
111
116
|
options['implementation_guide']&.each_with_index do |ig, idx|
|
@@ -119,8 +124,8 @@ module Inferno
|
|
119
124
|
end
|
120
125
|
end
|
121
126
|
|
122
|
-
def say_unless_quiet(*
|
123
|
-
say(*
|
127
|
+
def say_unless_quiet(*)
|
128
|
+
say(*) unless options['quiet']
|
124
129
|
end
|
125
130
|
end
|
126
131
|
end
|
@@ -5,29 +5,18 @@ Gem::Specification.new do |spec|
|
|
5
5
|
spec.version = <%= module_name %>::VERSION
|
6
6
|
spec.authors = <%= authors %>
|
7
7
|
# spec.email = ['TODO']
|
8
|
-
spec.date = Time.now.utc.strftime('%Y-%m-%d')
|
9
8
|
spec.summary = '<%= title_name %>'
|
10
9
|
# spec.description = <<~DESCRIPTION
|
11
10
|
# This is a big markdown description of the test kit.
|
12
11
|
# DESCRIPTION
|
13
12
|
# spec.homepage = 'TODO'
|
14
13
|
spec.license = 'Apache-2.0'
|
15
|
-
spec.
|
16
|
-
spec.
|
17
|
-
spec.add_development_dependency 'factory_bot', '~> 6.1'
|
18
|
-
spec.add_development_dependency 'rspec', '~> 3.10'
|
19
|
-
spec.add_development_dependency 'webmock', '~> 3.11'
|
20
|
-
spec.required_ruby_version = Gem::Requirement.new('>= 3.1.2')
|
14
|
+
spec.add_dependency 'inferno_core', '~> <%= Inferno::VERSION %>'
|
15
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 3.3.6')
|
21
16
|
spec.metadata['inferno_test_kit'] = 'true'
|
22
17
|
# spec.metadata['homepage_uri'] = spec.homepage
|
23
18
|
# spec.metadata['source_code_uri'] = 'TODO'
|
24
|
-
spec.files
|
25
|
-
Dir['lib/**/*.rb'],
|
26
|
-
Dir['lib/**/*.json'],
|
27
|
-
Dir['config/presets/*.json'],
|
28
|
-
Dir['config/presets/*.json.erb'],
|
29
|
-
'LICENSE'
|
30
|
-
].flatten
|
19
|
+
spec.files = `[ -d .git ] && git ls-files -z lib config/presets LICENSE`.split("\x0")
|
31
20
|
|
32
21
|
spec.require_paths = ['lib']
|
33
22
|
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require:
|
2
|
+
- rubocop-rspec
|
3
|
+
|
4
|
+
AllCops:
|
5
|
+
NewCops: enable
|
6
|
+
SuggestExtensions: false
|
7
|
+
TargetRubyVersion: 3.3
|
8
|
+
Exclude:
|
9
|
+
- 'Gemfile'
|
10
|
+
- 'vendor/**/*'
|
11
|
+
|
12
|
+
Layout/LineLength:
|
13
|
+
Max: 120
|
14
|
+
|
15
|
+
Layout/MultilineMethodCallIndentation:
|
16
|
+
EnforcedStyle: 'indented'
|
17
|
+
|
18
|
+
Style/Documentation:
|
19
|
+
Enabled: false
|
20
|
+
|
21
|
+
Style/FrozenStringLiteralComment:
|
22
|
+
Enabled: false
|
23
|
+
|
24
|
+
Style/NumericLiterals:
|
25
|
+
Enabled: false
|
26
|
+
|
27
|
+
Style/OpenStructUse:
|
28
|
+
Exclude:
|
29
|
+
- 'spec/**/*'
|
30
|
+
|
31
|
+
Style/SymbolArray:
|
32
|
+
Enabled: false
|
33
|
+
|
34
|
+
Style/WordArray:
|
35
|
+
Enabled: false
|
36
|
+
|
37
|
+
Metrics/AbcSize:
|
38
|
+
Enabled: false
|
39
|
+
|
40
|
+
Metrics/BlockLength:
|
41
|
+
Enabled: false
|
42
|
+
|
43
|
+
Metrics/ClassLength:
|
44
|
+
Enabled: false
|
45
|
+
|
46
|
+
Metrics/MethodLength:
|
47
|
+
Enabled: false
|
48
|
+
|
49
|
+
Metrics/ModuleLength:
|
50
|
+
Enabled: false
|
51
|
+
|
52
|
+
Metrics/PerceivedComplexity:
|
53
|
+
Enabled: false
|
54
|
+
|
55
|
+
Metrics/ParameterLists:
|
56
|
+
Enabled: false
|
57
|
+
|
58
|
+
RSpec/AnyInstance:
|
59
|
+
Enabled: false
|
60
|
+
|
61
|
+
RSpec/ExampleLength:
|
62
|
+
Enabled: false
|
63
|
+
|
64
|
+
RSpec/MultipleExpectations:
|
65
|
+
Enabled: false
|
66
|
+
|
67
|
+
RSpec/MultipleMemoizedHelpers:
|
68
|
+
Enabled: false
|
69
|
+
|
70
|
+
RSpec/NestedGroups:
|
71
|
+
Enabled: false
|
72
|
+
|
73
|
+
RSpec/NotToNot:
|
74
|
+
EnforcedStyle: to_not
|
75
|
+
|
76
|
+
Gemspec/RequireMFA:
|
77
|
+
Enabled: false
|
@@ -1 +1 @@
|
|
1
|
-
3.
|
1
|
+
3.3.6
|
@@ -1 +1 @@
|
|
1
|
-
ruby 3.
|
1
|
+
ruby 3.3.6
|
@@ -6,8 +6,15 @@ gemspec
|
|
6
6
|
|
7
7
|
group :development, :test do
|
8
8
|
gem 'debug'
|
9
|
+
gem 'rubocop', '~> 1.9'
|
10
|
+
gem 'rubocop-rspec', require: false
|
9
11
|
end
|
10
12
|
|
11
13
|
group :test do
|
14
|
+
gem 'database_cleaner-sequel', '~> 1.8'
|
15
|
+
gem 'factory_bot', '~> 6.1'
|
12
16
|
gem 'rack-test'
|
17
|
+
gem 'rspec', '~> 3.10'
|
18
|
+
gem 'simplecov', '0.21.2', require: false
|
19
|
+
gem 'webmock', '~> 3.11'
|
13
20
|
end
|
@@ -6,6 +6,7 @@ Inferno::Application.register_provider(:suites) do
|
|
6
6
|
require 'inferno/entities/test_group'
|
7
7
|
require 'inferno/entities/test_suite'
|
8
8
|
require 'inferno/entities/test_kit'
|
9
|
+
require 'inferno/route_storage'
|
9
10
|
|
10
11
|
files_to_load = Dir.glob(File.join(Dir.pwd, 'lib', '*.rb'))
|
11
12
|
|
@@ -380,10 +380,10 @@ module Inferno
|
|
380
380
|
# using multiple validators
|
381
381
|
# @param required_suite_options [Hash] suite options that must be
|
382
382
|
# selected in order to use this validator
|
383
|
-
def fhir_resource_validator(name = :default, required_suite_options: nil, &
|
383
|
+
def fhir_resource_validator(name = :default, required_suite_options: nil, &)
|
384
384
|
current_validators = fhir_validators[name] || []
|
385
385
|
|
386
|
-
new_validator = Inferno::DSL::FHIRResourceValidation::Validator.new(name, id, required_suite_options, &
|
386
|
+
new_validator = Inferno::DSL::FHIRResourceValidation::Validator.new(name, id, required_suite_options, &)
|
387
387
|
|
388
388
|
current_validators.reject! { |validator| validator.requirements == required_suite_options }
|
389
389
|
current_validators << new_validator
|
@@ -254,10 +254,10 @@ module Inferno
|
|
254
254
|
# using multiple validators
|
255
255
|
# @param required_suite_options [Hash] suite options that must be
|
256
256
|
# selected in order to use this validator
|
257
|
-
def validator(name = :default, required_suite_options: nil, &
|
257
|
+
def validator(name = :default, required_suite_options: nil, &)
|
258
258
|
current_validators = fhir_validators[name] || []
|
259
259
|
|
260
|
-
new_validator = Inferno::DSL::FHIRValidation::Validator.new(required_suite_options, &
|
260
|
+
new_validator = Inferno::DSL::FHIRValidation::Validator.new(required_suite_options, &)
|
261
261
|
|
262
262
|
current_validators.reject! { |validator| validator.requirements == required_suite_options }
|
263
263
|
current_validators << new_validator
|
@@ -12,7 +12,7 @@ module Inferno
|
|
12
12
|
# class AuthorizedEndpoint < Inferno::DSL::SuiteEndpoint
|
13
13
|
# # Identify the incoming request based on a bearer token
|
14
14
|
# def test_run_identifier
|
15
|
-
# request.
|
15
|
+
# request.headers['authorization']&.delete_prefix('Bearer ')
|
16
16
|
# end
|
17
17
|
#
|
18
18
|
# # Return a json FHIR Patient resource
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'fhir_models'
|
4
|
+
require 'pathname'
|
5
|
+
require 'rubygems/package'
|
6
|
+
require 'zlib'
|
7
|
+
|
8
|
+
require_relative '../repositories/igs'
|
9
|
+
|
10
|
+
module Inferno
|
11
|
+
module Entities
|
12
|
+
# IG is a wrapper class around the relevant concepts inside an IG.
|
13
|
+
# Not everything within an IG is currently used by Inferno.
|
14
|
+
class IG < Entity
|
15
|
+
ATTRIBUTES = [
|
16
|
+
:id,
|
17
|
+
:profiles,
|
18
|
+
:extensions,
|
19
|
+
:value_sets,
|
20
|
+
:search_params,
|
21
|
+
:examples
|
22
|
+
].freeze
|
23
|
+
|
24
|
+
include Inferno::Entities::Attributes
|
25
|
+
|
26
|
+
def initialize(**params)
|
27
|
+
super(params, ATTRIBUTES)
|
28
|
+
|
29
|
+
@profiles = []
|
30
|
+
@extensions = []
|
31
|
+
@value_sets = []
|
32
|
+
@examples = []
|
33
|
+
@search_params = []
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.from_file(ig_path)
|
37
|
+
raise "#{ig_path} does not exist" unless File.exist?(ig_path)
|
38
|
+
|
39
|
+
# fhir_models by default logs the entire content of non-FHIR files
|
40
|
+
# which could be things like a package.json
|
41
|
+
original_logger = FHIR.logger
|
42
|
+
FHIR.logger = Logger.new('/dev/null')
|
43
|
+
|
44
|
+
if File.directory?(ig_path)
|
45
|
+
from_directory(ig_path)
|
46
|
+
elsif ig_path.end_with? '.tgz'
|
47
|
+
from_tgz(ig_path)
|
48
|
+
else
|
49
|
+
raise "Unable to load #{ig_path} as it does not appear to be a directory or a .tgz file"
|
50
|
+
end
|
51
|
+
ensure
|
52
|
+
FHIR.logger = original_logger if defined? original_logger
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.from_tgz(ig_path)
|
56
|
+
tar = Gem::Package::TarReader.new(
|
57
|
+
Zlib::GzipReader.open(ig_path)
|
58
|
+
)
|
59
|
+
|
60
|
+
ig = IG.new
|
61
|
+
|
62
|
+
tar.each do |entry|
|
63
|
+
next if skip_item?(entry.full_name, entry.directory?)
|
64
|
+
|
65
|
+
begin
|
66
|
+
resource = FHIR::Json.from_json(entry.read)
|
67
|
+
next if resource.nil?
|
68
|
+
|
69
|
+
ig.handle_resource(resource, entry.full_name)
|
70
|
+
rescue StandardError
|
71
|
+
next
|
72
|
+
end
|
73
|
+
end
|
74
|
+
ig
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.from_directory(ig_directory)
|
78
|
+
ig = IG.new
|
79
|
+
|
80
|
+
ig_path = Pathname.new(ig_directory)
|
81
|
+
Dir.glob("#{ig_path}/**/*") do |f|
|
82
|
+
relative_path = Pathname.new(f).relative_path_from(ig_path).to_s
|
83
|
+
next if skip_item?(relative_path, File.directory?(f))
|
84
|
+
|
85
|
+
begin
|
86
|
+
resource = FHIR::Json.from_json(File.read(f))
|
87
|
+
next if resource.nil?
|
88
|
+
|
89
|
+
ig.handle_resource(resource, relative_path)
|
90
|
+
rescue StandardError
|
91
|
+
next
|
92
|
+
end
|
93
|
+
end
|
94
|
+
ig
|
95
|
+
end
|
96
|
+
|
97
|
+
# These files aren't FHIR resources
|
98
|
+
FILES_TO_SKIP = ['package.json', 'validation-summary.json'].freeze
|
99
|
+
|
100
|
+
def self.skip_item?(relative_path, is_directory)
|
101
|
+
return true if is_directory
|
102
|
+
|
103
|
+
file_name = relative_path.split('/').last
|
104
|
+
|
105
|
+
return true unless file_name.end_with? '.json'
|
106
|
+
return true unless relative_path.start_with? 'package/'
|
107
|
+
|
108
|
+
return true if file_name.start_with? '.' # ignore hidden files
|
109
|
+
return true if file_name.end_with? '.openapi.json'
|
110
|
+
return true if FILES_TO_SKIP.include? file_name
|
111
|
+
|
112
|
+
false
|
113
|
+
end
|
114
|
+
|
115
|
+
def handle_resource(resource, relative_path)
|
116
|
+
case resource.resourceType
|
117
|
+
when 'StructureDefinition'
|
118
|
+
if resource.type == 'Extension'
|
119
|
+
extensions.push resource
|
120
|
+
else
|
121
|
+
profiles.push resource
|
122
|
+
end
|
123
|
+
when 'ValueSet'
|
124
|
+
value_sets.push resource
|
125
|
+
when 'SearchParameter'
|
126
|
+
search_params.push resource
|
127
|
+
when 'ImplementationGuide'
|
128
|
+
@id = extract_package_id(resource)
|
129
|
+
else
|
130
|
+
examples.push(resource) if relative_path.start_with? 'package/example'
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def extract_package_id(ig_resource)
|
135
|
+
"#{ig_resource.id}##{ig_resource.version || 'current'}"
|
136
|
+
end
|
137
|
+
|
138
|
+
# @private
|
139
|
+
def add_self_to_repository
|
140
|
+
repository.insert(self)
|
141
|
+
end
|
142
|
+
|
143
|
+
# @private
|
144
|
+
def repository
|
145
|
+
Inferno::Repositories::IGs.new
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
data/lib/inferno/entities.rb
CHANGED
@@ -2,6 +2,7 @@ require_relative 'entities/attributes'
|
|
2
2
|
require_relative 'entities/has_runnable'
|
3
3
|
require_relative 'entities/entity'
|
4
4
|
require_relative 'entities/header'
|
5
|
+
require_relative 'entities/ig'
|
5
6
|
require_relative 'entities/message'
|
6
7
|
require_relative 'entities/request'
|
7
8
|
require_relative 'entities/result'
|