inferno_core 0.6.9 → 0.6.11
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/database.yml +15 -0
- data/lib/inferno/apps/cli/evaluate/docker-compose.evaluate.yml +16 -0
- data/lib/inferno/apps/cli/evaluate.rb +52 -4
- data/lib/inferno/apps/cli/execute.rb +17 -21
- data/lib/inferno/apps/cli/main.rb +5 -1
- data/lib/inferno/apps/cli/requirements.rb +28 -0
- data/lib/inferno/apps/cli/requirements_exporter.rb +194 -0
- data/lib/inferno/apps/cli/suite.rb +21 -0
- data/lib/inferno/apps/cli/templates/lib/%library_name%/example_suite/patient_group.rb.tt +141 -0
- data/lib/inferno/apps/cli/templates/lib/%library_name%/example_suite.rb.tt +128 -0
- data/lib/inferno/apps/cli/templates/lib/%library_name%/metadata.rb.tt +65 -3
- data/lib/inferno/apps/cli/templates/lib/%library_name%/version.rb.tt +1 -0
- data/lib/inferno/apps/cli/templates/lib/%library_name%.rb.tt +1 -1
- data/lib/inferno/apps/web/router.rb +10 -5
- data/lib/inferno/apps/web/serializers/input.rb +1 -0
- data/lib/inferno/apps/web/serializers/serializer.rb +7 -0
- data/lib/inferno/apps/web/serializers/test.rb +1 -0
- data/lib/inferno/apps/web/serializers/test_group.rb +1 -0
- data/lib/inferno/apps/web/serializers/test_suite.rb +2 -1
- data/lib/inferno/config/boot/suites.rb +3 -0
- data/lib/inferno/dsl/fhir_evaluation/default.yml +68 -0
- data/lib/inferno/dsl/fhir_evaluation/evaluator.rb +3 -5
- data/lib/inferno/dsl/fhir_evaluation/rules/all_defined_extensions_have_examples.rb +2 -2
- data/lib/inferno/dsl/fhir_evaluation/rules/all_extensions_used.rb +2 -2
- data/lib/inferno/dsl/fhir_evaluation/rules/all_must_supports_present.rb +1 -1
- data/lib/inferno/dsl/fhir_evaluation/rules/all_profiles_have_examples.rb +1 -1
- data/lib/inferno/dsl/fhir_evaluation/rules/all_references_resolve.rb +2 -2
- data/lib/inferno/dsl/fhir_evaluation/rules/all_resources_reachable.rb +2 -2
- data/lib/inferno/dsl/fhir_evaluation/rules/all_search_parameters_have_examples.rb +22 -11
- data/lib/inferno/dsl/fhir_evaluation/rules/differential_content_has_examples.rb +2 -2
- data/lib/inferno/dsl/fhir_evaluation/rules/value_sets_demonstrate.rb +4 -4
- data/lib/inferno/dsl/fhir_resource_validation.rb +25 -3
- data/lib/inferno/dsl/fhirpath_evaluation.rb +25 -1
- data/lib/inferno/dsl/input_output_handling.rb +1 -0
- data/lib/inferno/dsl/runnable.rb +5 -0
- data/lib/inferno/dsl/short_id_manager.rb +55 -0
- data/lib/inferno/entities/input.rb +14 -5
- data/lib/inferno/entities/requirement.rb +15 -3
- data/lib/inferno/entities/test.rb +3 -1
- data/lib/inferno/entities/test_group.rb +3 -1
- data/lib/inferno/entities/test_suite.rb +2 -0
- data/lib/inferno/exceptions.rb +6 -0
- data/lib/inferno/feature.rb +9 -0
- data/lib/inferno/public/237.bundle.js +1 -1
- data/lib/inferno/public/bundle.js +54 -54
- data/lib/inferno/public/bundle.js.LICENSE.txt +3 -36
- data/lib/inferno/repositories/requirements.rb +6 -2
- data/lib/inferno/version.rb +1 -1
- data/spec/shared/test_kit_examples.rb +32 -0
- metadata +25 -4
- data/lib/inferno/apps/cli/templates/lib/%library_name%/patient_group.rb.tt +0 -44
- data/spec/features_helper.rb +0 -12
@@ -0,0 +1,128 @@
|
|
1
|
+
require_relative 'metadata'
|
2
|
+
require_relative 'example_suite/patient_group'
|
3
|
+
|
4
|
+
module <%= module_name %>
|
5
|
+
class ExampleSuite < Inferno::TestSuite
|
6
|
+
|
7
|
+
id :<%= test_suite_id %>
|
8
|
+
title '<%= title_name %>'
|
9
|
+
short_title '<%= title_name %>'
|
10
|
+
|
11
|
+
# TODO: Update the description below to align with the test suite
|
12
|
+
description <<~DESCRIPTION
|
13
|
+
The Example Test Suite is a testing tool for Health Level 7 (HL7®) Fast Healthcare Interoperability Resources (FHIR®)
|
14
|
+
services seeking to meet the requirements of the API criterion within the Example Certification Program.
|
15
|
+
|
16
|
+
*or*
|
17
|
+
|
18
|
+
The Example Test Suite tests systems for their conformance to the [Example Implementation Guide](https://example.com/example).
|
19
|
+
|
20
|
+
## Organization
|
21
|
+
|
22
|
+
This test suite is organized into testing scenarios that in sum cover all requirements within the Example criterion.
|
23
|
+
The scenarios are intended to be run in order during certification, but can be run out of order to support testing
|
24
|
+
during development or certification preparation. Some scenarios depend on data collected during previous scenarios
|
25
|
+
to function. In these cases, the scenario description describes these dependencies.
|
26
|
+
|
27
|
+
The first three scenarios require the system under test to demonstrate basic SMART App Launch functionality.
|
28
|
+
The fourth uses a valid token provided during earlier tests to verify support for the Single Patient API as
|
29
|
+
described in the criterion. The fifth verifies support for the Multi Patient API, including Backend Services
|
30
|
+
for authorization. Not all authorization-related requirements are verified in the first three scenarios,
|
31
|
+
and the 'Additional Authorization Tests' verify these additional requirements. The last scenario contains
|
32
|
+
a list of 'attestations' and 'visual inspections' for requirements that could not be verified through automated testing.
|
33
|
+
|
34
|
+
*or*
|
35
|
+
|
36
|
+
This test suite is split into three different categories:
|
37
|
+
- All Patients: FHIR Operation to obtain a detailed set of FHIR resources of diverse resource types pertaining to all patients
|
38
|
+
- Group of Patients: FHIR Operation to obtain a detailed set of FHIR resources of diverse resource types pertaining to all members of a specified Group
|
39
|
+
- System Level Export: FHIR Operation to export data from a FHIR server, whether or not it is associated with a patient
|
40
|
+
|
41
|
+
## Getting Started
|
42
|
+
|
43
|
+
The best way to learn about how to use these tests is the [Example Test Kit walkthrough](https://example.com/Walkthrough),
|
44
|
+
which demonstrates the tests running against a simulated system.
|
45
|
+
|
46
|
+
To get started with the first group of scenarios, please first register the Inferno client as a SMART App with the following information:
|
47
|
+
- SMART Launch URI: https://example.com/smart/launch
|
48
|
+
- OAuth Redirect URI: https://example.com/smart/redirect
|
49
|
+
|
50
|
+
For the multi-patient API, register Inferno with the following JWK Set Url:
|
51
|
+
- https://example.com/suites/custom/example/.well-known/jwks.json
|
52
|
+
|
53
|
+
*or*
|
54
|
+
|
55
|
+
To get started, if your server supports SMART backend services authorization, please first register Inferno with the following JWK Set URL:
|
56
|
+
- https://example.com/suites/custom/example/.well-known/jwks.json
|
57
|
+
|
58
|
+
Then, run the full Example test suite containing both the SMART Backend Services test group and the Bulk Data Export Tests test group.
|
59
|
+
If your server does not support SMART Backend Services authorization, only run the second test group, Bulk Data Export Tests.
|
60
|
+
|
61
|
+
## Limitations
|
62
|
+
|
63
|
+
Inferno is unable to determine what requests will result in specific kinds of responses from the server under test
|
64
|
+
(e.g., what will result in Instructions being returned vs. Coverage Information). As a result, the tester must
|
65
|
+
supply the request bodies which will cause the system under test to return the desired response types.
|
66
|
+
|
67
|
+
The ability of an Example Server to request additional FHIR resources is not tested.
|
68
|
+
|
69
|
+
Hook configuration is not tested.
|
70
|
+
|
71
|
+
## *if applicable:* Certification Requirements
|
72
|
+
|
73
|
+
Systems must pass all tests to qualify for Example certification.
|
74
|
+
|
75
|
+
DESCRIPTION
|
76
|
+
|
77
|
+
# These inputs will be available to all tests in this suite
|
78
|
+
input :url,
|
79
|
+
title: 'FHIR Server Base Url'
|
80
|
+
|
81
|
+
input :credentials,
|
82
|
+
title: 'OAuth Credentials',
|
83
|
+
type: :auth_info,
|
84
|
+
optional: true
|
85
|
+
|
86
|
+
# All FHIR requests in this suite will use this FHIR client
|
87
|
+
|
88
|
+
# All FHIR requests in this suite will use this FHIR client
|
89
|
+
fhir_client do
|
90
|
+
url :url
|
91
|
+
auth_info :credentials
|
92
|
+
end
|
93
|
+
|
94
|
+
# All FHIR validation requests will use this FHIR validator
|
95
|
+
fhir_resource_validator do
|
96
|
+
# igs 'identifier#version' # Use this method for published IGs/versions
|
97
|
+
# igs 'igs/filename.tgz' # Use this otherwise
|
98
|
+
|
99
|
+
exclude_message do |message|
|
100
|
+
message.message.match?(/\A\S+: \S+: URL value '.*' does not resolve/)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Tests and TestGroups can be defined inline
|
105
|
+
group do
|
106
|
+
id :capability_statement
|
107
|
+
title 'Capability Statement'
|
108
|
+
description 'See a sample description in the Patient Test Group'
|
109
|
+
|
110
|
+
test do
|
111
|
+
id :capability_statement_read
|
112
|
+
title 'Read CapabilityStatement'
|
113
|
+
description 'Read CapabilityStatement from /metadata endpoint'
|
114
|
+
|
115
|
+
run do
|
116
|
+
fhir_get_capability_statement
|
117
|
+
|
118
|
+
assert_response_status(200)
|
119
|
+
assert_resource_type(:capability_statement)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Tests and TestGroups can be written in separate files and then included
|
125
|
+
# using their id
|
126
|
+
group from: :patient_group
|
127
|
+
end
|
128
|
+
end
|
@@ -5,11 +5,73 @@ module <%= module_name %>
|
|
5
5
|
id :<%= test_kit_id %>
|
6
6
|
title '<%= title_name %>'
|
7
7
|
description <<~DESCRIPTION
|
8
|
-
|
8
|
+
The Example Test Kit is a testing tool for Health IT systems seeking to meet the requirements of API Criterion within the Example Certification Program.
|
9
|
+
|
10
|
+
*or*
|
11
|
+
|
12
|
+
The Example Test Kit validates the conformance of a server implementation to a specific version of the [Example IG](https://example.com/example).
|
13
|
+
Currently, Inferno can test against implementations of following versions of the Example IG: v1.0.0, v1.3.0, v2.0.0, and v3.0.1.
|
14
|
+
|
15
|
+
<!-- break -->
|
16
|
+
|
17
|
+
## Getting Started
|
18
|
+
|
19
|
+
Please select which approved version of each standard to use, and click ‘Create Test Session’ to begin testing.
|
20
|
+
|
21
|
+
This test kit includes a [simulated conformant FHIR API](https://inferno.healthit.gov/reference-server/)
|
22
|
+
that can be used to demonstrate success for all tests. This simulated API is open source and is available on GitHub.
|
23
|
+
Visit the [walkthrough](https://example.com/Walkthrough) for a demonstration
|
24
|
+
of using these tests against the provided simulated FHIR API.
|
25
|
+
|
26
|
+
## Status
|
27
|
+
|
28
|
+
The Example Test Kit is actively developed and updates are released monthly.
|
29
|
+
|
30
|
+
*or*
|
31
|
+
|
32
|
+
These tests are a **DRAFT**. Future versions of these tests may verify other requirements and may change how these requirements are tested.
|
33
|
+
|
34
|
+
## Conformance
|
35
|
+
|
36
|
+
The test kit currently tests all requirements for the
|
37
|
+
[API Criterion within the Example Certification Program](https://example.com/api-criterion).
|
38
|
+
This includes:
|
39
|
+
- The Lorum IG [v1.0.0](https://example.com/lorum/1.0.0)
|
40
|
+
- The Ipsum IG [v2.0.0](https://example.com/ipsum/2.0.0), [v3.0.1](https://example.com/ipsum/3.0.1)
|
41
|
+
- The Dolor IG [v2.0.2](https://example.com/dolor/2.0.2)
|
42
|
+
|
43
|
+
*or*
|
44
|
+
|
45
|
+
The test kit currently tests the following requirements:
|
46
|
+
- Vel mattis erat semper ut
|
47
|
+
- Suspendisse eget tempor
|
48
|
+
- Nulla eu cursus turpis
|
49
|
+
- Praesent orci diam
|
50
|
+
|
51
|
+
|
52
|
+
## Repository
|
53
|
+
|
54
|
+
The Example Kit can be
|
55
|
+
[downloaded from its GitHub repository](https://example.com/example-test-kit-repo),
|
56
|
+
where additional resources and documentation are also available to help users get
|
57
|
+
started with the testing process. The repository [Wiki](https://example.com/example-test-kit-repo/wiki/)
|
58
|
+
provides a [FAQ](https://example.com/example-test-kit-repo/wiki/FAQ) for testers,
|
59
|
+
and the [Releases](https://example.com/example-test-kit-repo/releases) page provides information about each new release.
|
60
|
+
|
61
|
+
## Providing Feedback and Reporting Issues
|
62
|
+
|
63
|
+
We welcome feedback on the tests, including but not limited to the following areas:
|
64
|
+
|
65
|
+
- Validation logic, such as potential bugs, lax checks, and unexpected failures.
|
66
|
+
- Requirements coverage, such as requirements that have been missed, tests that necessitate features that the IG does not require, or other issues with the interpretation of the IG’s requirements.
|
67
|
+
- User experience, such as confusing or missing information in the test UI.
|
68
|
+
|
69
|
+
Please report any issues with this set of tests in the [issues section](https://example.com/example-test-kit-repo/issues) of the repository.
|
9
70
|
DESCRIPTION
|
71
|
+
|
10
72
|
suite_ids [:<%= test_suite_id %>]
|
11
|
-
#
|
12
|
-
|
73
|
+
tags [] # E.g., ['SMART App Launch', 'US Core']
|
74
|
+
last_updated LAST_UPDATED
|
13
75
|
version VERSION
|
14
76
|
maturity 'Low'
|
15
77
|
authors <%= authors %>
|
@@ -1 +1 @@
|
|
1
|
-
require_relative '<%= library_name %>/
|
1
|
+
require_relative '<%= library_name %>/example_suite'
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'erb'
|
2
|
+
require_relative '../../feature'
|
2
3
|
|
3
4
|
Dir.glob(File.join(__dir__, 'controllers', '**', '*.rb')).each { |path| require_relative path }
|
4
5
|
|
@@ -47,13 +48,17 @@ module Inferno
|
|
47
48
|
put '/:id/check_configuration',
|
48
49
|
to: Inferno::Web::Controllers::TestSuites::CheckConfiguration,
|
49
50
|
as: :check_configuration
|
50
|
-
|
51
|
-
|
52
|
-
|
51
|
+
if Feature.requirements_enabled?
|
52
|
+
get ':id/requirements',
|
53
|
+
to: Inferno::Web::Controllers::TestSuites::Requirements::Index,
|
54
|
+
as: :requirements
|
55
|
+
end
|
53
56
|
end
|
54
57
|
|
55
|
-
|
56
|
-
|
58
|
+
if Feature.requirements_enabled?
|
59
|
+
scope 'requirements' do
|
60
|
+
get '/:id', to: Inferno::Web::Controllers::Requirements::Show, as: :show
|
61
|
+
end
|
57
62
|
end
|
58
63
|
|
59
64
|
get '/requests/:id', to: Inferno::Web::Controllers::Requests::Show, as: :requests_show
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'oj'
|
2
2
|
require 'blueprinter'
|
3
|
+
require_relative '../../../feature'
|
3
4
|
|
4
5
|
module Inferno
|
5
6
|
module Web
|
@@ -13,6 +14,12 @@ module Inferno
|
|
13
14
|
result.send(name).present?
|
14
15
|
end
|
15
16
|
end
|
17
|
+
|
18
|
+
# When removing the feature flag, replace all instances of this method
|
19
|
+
# with `.field_present?`
|
20
|
+
def self.field_present_and_requirements_enabled?(field_name, result, options)
|
21
|
+
field_present?(field_name, result, options) && Feature.requirements_enabled?
|
22
|
+
end
|
16
23
|
end
|
17
24
|
end
|
18
25
|
end
|
@@ -32,6 +32,7 @@ module Inferno
|
|
32
32
|
Input.render_as_hash(group.available_inputs(suite_options).values)
|
33
33
|
end
|
34
34
|
field :output_definitions, name: :outputs, extractor: HashValueExtractor
|
35
|
+
field :verifies_requirements, if: :field_present_and_requirements_enabled?
|
35
36
|
end
|
36
37
|
end
|
37
38
|
end
|
@@ -38,7 +38,7 @@ module Inferno
|
|
38
38
|
suite_options = options[:suite_options]
|
39
39
|
Input.render_as_hash(suite.available_inputs(suite_options).values)
|
40
40
|
end
|
41
|
-
field :requirement_sets, if: :
|
41
|
+
field :requirement_sets, if: :field_present_and_requirements_enabled? do |suite, options|
|
42
42
|
selected_options = options[:suite_options] || []
|
43
43
|
requirement_sets = suite.requirement_sets.select do |requirement_set|
|
44
44
|
requirement_set.suite_options.all? { |suite_option| selected_options.include? suite_option }
|
@@ -46,6 +46,7 @@ module Inferno
|
|
46
46
|
|
47
47
|
RequirementSet.render_as_hash(requirement_sets)
|
48
48
|
end
|
49
|
+
field :verifies_requirements, if: :field_present_and_requirements_enabled?
|
49
50
|
end
|
50
51
|
end
|
51
52
|
end
|
@@ -45,6 +45,9 @@ Inferno::Application.register_provider(:suites) do
|
|
45
45
|
if descendant.id.blank? || descendant.id == 'Inferno::Entities::TestSuite'
|
46
46
|
raise StandardError, "Error initializing test suite #{descendant.name}: test suite ID is not set"
|
47
47
|
end
|
48
|
+
|
49
|
+
# This will lock the short IDs if a short ID map for this suite is present
|
50
|
+
descendant.assign_short_ids
|
48
51
|
end
|
49
52
|
end
|
50
53
|
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
Environment:
|
2
|
+
ExternalValidator:
|
3
|
+
Enabled: false
|
4
|
+
Url: ''
|
5
|
+
VSAC:
|
6
|
+
Username: 'apikey'
|
7
|
+
Password: ''
|
8
|
+
|
9
|
+
Rule:
|
10
|
+
AllReferencesResolve:
|
11
|
+
Description: 'All References in Examples resolve to each other'
|
12
|
+
Enabled: true
|
13
|
+
AllResourcesReachable:
|
14
|
+
Description: 'All resources in Examples are reachable'
|
15
|
+
Enabled: true
|
16
|
+
AllMustSupportsPresent:
|
17
|
+
Description: 'An instance of all MustSupport elements, extensions, and slices is present in the given resources'
|
18
|
+
Enabled: true
|
19
|
+
# RequirementExtensionUrl accepts an extension URL which tags element definitions as required for the purposes of this test, even if not Must Support.
|
20
|
+
# For instance, US Core elements with the "http://hl7.org/fhir/us/core/StructureDefinition/uscdi-requirement" extension
|
21
|
+
# may be considered required even if not necessarily tagged Must Support.
|
22
|
+
# An instance of the extension must have valueBoolean=true to be recognized.
|
23
|
+
RequirementExtensionUrl: null
|
24
|
+
|
25
|
+
# Set WriteMetadataForDebugging:true to have the test write out the metadata it used to a temporary file
|
26
|
+
WriteMetadataForDebugging: false
|
27
|
+
|
28
|
+
ConformanceOptions:
|
29
|
+
# ConformanceOptions allows selecting from a few approaches to determine which subset of resources
|
30
|
+
# should be used to search for the MustSupport elements from each profile.
|
31
|
+
# Resources that are not the same type as the target of the profile are never searched, regardless of option.
|
32
|
+
|
33
|
+
# - If considerMetaProfile, the search will include resources that declare the current profile in meta.profile
|
34
|
+
considerMetaProfile: true
|
35
|
+
|
36
|
+
# - If considerValidationResults, resources will be validated against each profile to determine which they should be checked against.
|
37
|
+
# The search will include resources that validate against the current profile
|
38
|
+
# (in other words, resources for which a validation request produces no errors).
|
39
|
+
considerValidationResults: false
|
40
|
+
|
41
|
+
# - If considerOnlyResourceType, the search will include resources of the same type as the profile target type (StructureDefintion.type)
|
42
|
+
considerOnlyResourceType: false
|
43
|
+
AllExtensionsUsed:
|
44
|
+
Description: 'All extensions specified in profiles are represented in Examples'
|
45
|
+
Enabled: true
|
46
|
+
DifferentialContentHasExamples:
|
47
|
+
Enabled: true
|
48
|
+
ValueSetsDemonstrate:
|
49
|
+
Descripton: 'Examples demonstrate reasonable coverage of valuesets defines in an IG. (Note this probably only makes sense for small valuesets such as status options, not something like disease codes from SNOMED)'
|
50
|
+
Enabled: true
|
51
|
+
IgnoreUnloadableValueset: false
|
52
|
+
Exclude:
|
53
|
+
URN: true # Exclude if system is provided as Uniform Resource Name "urn:"
|
54
|
+
Filter: true # Exclude filter
|
55
|
+
SystemOnly: true # Exclude if only system is provided (e.g. http://loing.org)
|
56
|
+
AllSearchParametersHaveExamples:
|
57
|
+
Description: 'Examples cover all search parameters defined in an IG'
|
58
|
+
Enabled: true
|
59
|
+
AllDefinedExtensionsHaveExamples:
|
60
|
+
Description: 'All defined extensions are represented in Examples'
|
61
|
+
Enabled: true
|
62
|
+
AllProfilesHaveExamples:
|
63
|
+
Description: 'All profiles defined in an IG have at least one example instance'
|
64
|
+
Enabled: true
|
65
|
+
ConformanceOptions:
|
66
|
+
considerMetaProfile: true
|
67
|
+
considerValidationResults: false
|
68
|
+
considerOnlyResourceType: false
|
@@ -24,13 +24,11 @@ module Inferno
|
|
24
24
|
def evaluate(data, config = Config.new)
|
25
25
|
context = EvaluationContext.new(@ig, data, config, validator)
|
26
26
|
|
27
|
-
active_rules = []
|
28
27
|
config.data['Rule'].each do |rulename, rule_details|
|
29
|
-
|
30
|
-
end
|
28
|
+
next unless rule_details['Enabled']
|
31
29
|
|
32
|
-
|
33
|
-
|
30
|
+
Rule.descendants.select { |rule| rule.name.demodulize == rulename }
|
31
|
+
.each { |rule| rule.new.check(context) }
|
34
32
|
end
|
35
33
|
|
36
34
|
context.results
|
@@ -25,10 +25,10 @@ module Inferno
|
|
25
25
|
end
|
26
26
|
|
27
27
|
if unused_extensions.any?
|
28
|
-
message = "Found
|
28
|
+
message = "Found defined extensions in the IG without examples: \n\t #{unused_extensions.join(', ')}"
|
29
29
|
result = EvaluationResult.new(message, rule: self)
|
30
30
|
else
|
31
|
-
message = 'All defined extensions
|
31
|
+
message = 'All defined extensions in the IG have examples.'
|
32
32
|
result = EvaluationResult.new(message, severity: 'success', rule: self)
|
33
33
|
end
|
34
34
|
|
@@ -12,7 +12,7 @@ module Inferno
|
|
12
12
|
message = get_fail_message(unused_extensions)
|
13
13
|
result = EvaluationResult.new(message, rule: self)
|
14
14
|
else
|
15
|
-
message = 'All extensions specified in profiles are
|
15
|
+
message = 'All extensions specified in profiles are used in examples.'
|
16
16
|
result = EvaluationResult.new(message, severity: 'success', rule: self)
|
17
17
|
end
|
18
18
|
|
@@ -63,7 +63,7 @@ module Inferno
|
|
63
63
|
end
|
64
64
|
|
65
65
|
def get_fail_message(extensions)
|
66
|
-
message = 'Found extensions specified in profiles, but
|
66
|
+
message = 'Found extensions specified in profiles, but NOT used in examples:'
|
67
67
|
extensions.each do |profile, extension|
|
68
68
|
message += "\n Profile: #{profile}, \n\tExtensions: #{extension.join(', ')}" unless extension.empty?
|
69
69
|
end
|
@@ -48,7 +48,7 @@ module Inferno
|
|
48
48
|
else
|
49
49
|
message = 'Found Profiles with not all MustSupports represented:'
|
50
50
|
missing_items_by_profile.each do |profile_url, missing_items|
|
51
|
-
message += "\n\t
|
51
|
+
message += "\n\t#{profile_url}: #{missing_items.join(', ')}"
|
52
52
|
end
|
53
53
|
result = EvaluationResult.new(message, rule: self)
|
54
54
|
end
|
@@ -29,7 +29,7 @@ module Inferno
|
|
29
29
|
message = "Found profiles without examples: \n\t #{unused_profile_urls.join(', ')}"
|
30
30
|
result = EvaluationResult.new(message, rule: self)
|
31
31
|
else
|
32
|
-
message = 'All profiles have
|
32
|
+
message = 'All profiles have examples.'
|
33
33
|
result = EvaluationResult.new(message, severity: 'success', rule: self)
|
34
34
|
end
|
35
35
|
|
@@ -29,7 +29,7 @@ module Inferno
|
|
29
29
|
message = gen_reference_fail_message(unresolved_references)
|
30
30
|
result = EvaluationResult.new(message, rule: self)
|
31
31
|
else
|
32
|
-
message = 'All references resolve'
|
32
|
+
message = 'All references in examples resolve.'
|
33
33
|
result = EvaluationResult.new(message, severity: 'success', rule: self)
|
34
34
|
end
|
35
35
|
|
@@ -44,7 +44,7 @@ module Inferno
|
|
44
44
|
"\n Resource (id): #{resource_id} #{reference_detail}"
|
45
45
|
end.join(',')
|
46
46
|
|
47
|
-
"Found unresolved references: #{result_message}"
|
47
|
+
"Found unresolved references in examples: #{result_message}"
|
48
48
|
end
|
49
49
|
end
|
50
50
|
end
|
@@ -27,11 +27,11 @@ module Inferno
|
|
27
27
|
island_resources.to_a.sort!
|
28
28
|
|
29
29
|
if island_resources.any?
|
30
|
-
message = "Found resources
|
30
|
+
message = "Found resources in examples have no resolved references and are not referenced: #{
|
31
31
|
island_resources.join(', ')}"
|
32
32
|
result = EvaluationResult.new(message, rule: self)
|
33
33
|
else
|
34
|
-
message = 'All resources are reachable'
|
34
|
+
message = 'All resources in examples are reachable.'
|
35
35
|
result = EvaluationResult.new(message, severity: 'success', rule: self)
|
36
36
|
end
|
37
37
|
|
@@ -23,13 +23,14 @@ module Inferno
|
|
23
23
|
end
|
24
24
|
|
25
25
|
if unused_resource_urls.any?
|
26
|
-
|
26
|
+
unused_resource_list = unused_resource_urls.join("\n\t")
|
27
|
+
message = "Found SearchParameters with no searchable data in examples: \n\t#{unused_resource_list}"
|
27
28
|
result = EvaluationResult.new(message, rule: self)
|
28
29
|
elsif !search_params.empty?
|
29
|
-
message = 'All SearchParameters have examples'
|
30
|
+
message = 'All SearchParameters have examples.'
|
30
31
|
result = EvaluationResult.new(message, severity: 'success', rule: self)
|
31
32
|
else
|
32
|
-
message = 'IG contains no SearchParameter'
|
33
|
+
message = 'IG contains no SearchParameter.'
|
33
34
|
result = EvaluationResult.new(message, severity: 'information', rule: self)
|
34
35
|
end
|
35
36
|
|
@@ -42,13 +43,13 @@ module Inferno
|
|
42
43
|
# but without it there's no other way to select a value
|
43
44
|
# Return warning if params don't include expression
|
44
45
|
unless param.expression
|
45
|
-
message = "Search parameter #{param.url} doesn't
|
46
|
+
message = "Search parameter #{param.url} doesn't include an expression."
|
46
47
|
result = EvaluationResult.new(message, severity: 'warning', rule: self)
|
47
48
|
context.add_result result
|
48
49
|
return false
|
49
50
|
end
|
50
51
|
|
51
|
-
|
52
|
+
param_used = false
|
52
53
|
|
53
54
|
context.data.each do |resource|
|
54
55
|
next unless param.base.include? resource.resourceType
|
@@ -56,21 +57,31 @@ module Inferno
|
|
56
57
|
begin
|
57
58
|
result = evaluate_fhirpath(resource: resource, path: param.expression)
|
58
59
|
rescue StandardError => e
|
59
|
-
|
60
|
-
|
61
|
-
|
60
|
+
if e.to_s.include? 'Unable to connect to FHIRPath service'
|
61
|
+
result = EvaluationResult.new(e.to_s, severity: 'error', rule: self)
|
62
|
+
else
|
63
|
+
message = "SearchParameter #{param.url} failed to evaluate due to an error. " \
|
64
|
+
"Expression: #{param.expression}. #{e}"
|
65
|
+
result = EvaluationResult.new(message, severity: 'warning', rule: self)
|
66
|
+
end
|
67
|
+
|
62
68
|
context.add_result result
|
63
69
|
|
64
|
-
|
70
|
+
param_used = true
|
65
71
|
break
|
66
72
|
end
|
67
73
|
|
68
74
|
if result.present?
|
69
|
-
|
75
|
+
param_used = true
|
70
76
|
break
|
71
77
|
end
|
72
78
|
end
|
73
|
-
|
79
|
+
param_used
|
80
|
+
end
|
81
|
+
|
82
|
+
def add_message(message_type, message)
|
83
|
+
# No implementation but to prevent error from evaluate_fhirpath().
|
84
|
+
# Without this, will throw "undefined method" error since it expects to be called from a Runnable.
|
74
85
|
end
|
75
86
|
end
|
76
87
|
end
|
@@ -15,7 +15,7 @@ module Inferno
|
|
15
15
|
message = gen_differential_fail_message(unused_differential)
|
16
16
|
result = EvaluationResult.new(message, rule: self)
|
17
17
|
else
|
18
|
-
message = 'All differential fields are
|
18
|
+
message = 'All differential fields are used in examples.'
|
19
19
|
result = EvaluationResult.new(message, severity: 'success', rule: self)
|
20
20
|
end
|
21
21
|
|
@@ -110,7 +110,7 @@ module Inferno
|
|
110
110
|
end
|
111
111
|
|
112
112
|
def gen_differential_fail_message(unused_differential)
|
113
|
-
"Found fields highlighted in the differential view, but not used in
|
113
|
+
"Found fields highlighted in the differential view, but not used in examples: #{
|
114
114
|
unused_differential.map do |url, field|
|
115
115
|
next if field.empty?
|
116
116
|
|
@@ -72,7 +72,7 @@ module Inferno
|
|
72
72
|
# rubocop:disable Metrics/CyclomaticComplexity
|
73
73
|
def create_result_message
|
74
74
|
if value_set_unused.none?
|
75
|
-
message = 'All
|
75
|
+
message = 'All ValueSets are used in examples:'
|
76
76
|
value_set_used.map { |value_set| message += "\n\t#{value_set}" }
|
77
77
|
|
78
78
|
if value_set_unevaluated.any?
|
@@ -82,14 +82,14 @@ module Inferno
|
|
82
82
|
|
83
83
|
EvaluationResult.new(message, severity: 'success', rule: self)
|
84
84
|
else
|
85
|
-
message = '
|
85
|
+
message = 'Found ValueSets with all codes used (at least once) in examples:'
|
86
86
|
value_set_used.map { |url| message += "\n\t#{url}" }
|
87
87
|
|
88
|
-
message += "\nFound unused
|
88
|
+
message += "\nFound unused ValueSets: "
|
89
89
|
value_set_unused.map { |url| message += "\n\t#{url}" }
|
90
90
|
|
91
91
|
if value_set_unevaluated.any?
|
92
|
-
message += "\nFound unevaluated
|
92
|
+
message += "\nFound unevaluated ValueSets: "
|
93
93
|
value_set_unevaluated.map { |url| message += "\n\t#{url}" }
|
94
94
|
end
|
95
95
|
|