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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/lib/inferno/apps/cli/evaluate/database.yml +15 -0
  3. data/lib/inferno/apps/cli/evaluate/docker-compose.evaluate.yml +16 -0
  4. data/lib/inferno/apps/cli/evaluate.rb +52 -4
  5. data/lib/inferno/apps/cli/execute.rb +17 -21
  6. data/lib/inferno/apps/cli/main.rb +5 -1
  7. data/lib/inferno/apps/cli/requirements.rb +28 -0
  8. data/lib/inferno/apps/cli/requirements_exporter.rb +194 -0
  9. data/lib/inferno/apps/cli/suite.rb +21 -0
  10. data/lib/inferno/apps/cli/templates/lib/%library_name%/example_suite/patient_group.rb.tt +141 -0
  11. data/lib/inferno/apps/cli/templates/lib/%library_name%/example_suite.rb.tt +128 -0
  12. data/lib/inferno/apps/cli/templates/lib/%library_name%/metadata.rb.tt +65 -3
  13. data/lib/inferno/apps/cli/templates/lib/%library_name%/version.rb.tt +1 -0
  14. data/lib/inferno/apps/cli/templates/lib/%library_name%.rb.tt +1 -1
  15. data/lib/inferno/apps/web/router.rb +10 -5
  16. data/lib/inferno/apps/web/serializers/input.rb +1 -0
  17. data/lib/inferno/apps/web/serializers/serializer.rb +7 -0
  18. data/lib/inferno/apps/web/serializers/test.rb +1 -0
  19. data/lib/inferno/apps/web/serializers/test_group.rb +1 -0
  20. data/lib/inferno/apps/web/serializers/test_suite.rb +2 -1
  21. data/lib/inferno/config/boot/suites.rb +3 -0
  22. data/lib/inferno/dsl/fhir_evaluation/default.yml +68 -0
  23. data/lib/inferno/dsl/fhir_evaluation/evaluator.rb +3 -5
  24. data/lib/inferno/dsl/fhir_evaluation/rules/all_defined_extensions_have_examples.rb +2 -2
  25. data/lib/inferno/dsl/fhir_evaluation/rules/all_extensions_used.rb +2 -2
  26. data/lib/inferno/dsl/fhir_evaluation/rules/all_must_supports_present.rb +1 -1
  27. data/lib/inferno/dsl/fhir_evaluation/rules/all_profiles_have_examples.rb +1 -1
  28. data/lib/inferno/dsl/fhir_evaluation/rules/all_references_resolve.rb +2 -2
  29. data/lib/inferno/dsl/fhir_evaluation/rules/all_resources_reachable.rb +2 -2
  30. data/lib/inferno/dsl/fhir_evaluation/rules/all_search_parameters_have_examples.rb +22 -11
  31. data/lib/inferno/dsl/fhir_evaluation/rules/differential_content_has_examples.rb +2 -2
  32. data/lib/inferno/dsl/fhir_evaluation/rules/value_sets_demonstrate.rb +4 -4
  33. data/lib/inferno/dsl/fhir_resource_validation.rb +25 -3
  34. data/lib/inferno/dsl/fhirpath_evaluation.rb +25 -1
  35. data/lib/inferno/dsl/input_output_handling.rb +1 -0
  36. data/lib/inferno/dsl/runnable.rb +5 -0
  37. data/lib/inferno/dsl/short_id_manager.rb +55 -0
  38. data/lib/inferno/entities/input.rb +14 -5
  39. data/lib/inferno/entities/requirement.rb +15 -3
  40. data/lib/inferno/entities/test.rb +3 -1
  41. data/lib/inferno/entities/test_group.rb +3 -1
  42. data/lib/inferno/entities/test_suite.rb +2 -0
  43. data/lib/inferno/exceptions.rb +6 -0
  44. data/lib/inferno/feature.rb +9 -0
  45. data/lib/inferno/public/237.bundle.js +1 -1
  46. data/lib/inferno/public/bundle.js +54 -54
  47. data/lib/inferno/public/bundle.js.LICENSE.txt +3 -36
  48. data/lib/inferno/repositories/requirements.rb +6 -2
  49. data/lib/inferno/version.rb +1 -1
  50. data/spec/shared/test_kit_examples.rb +32 -0
  51. metadata +25 -4
  52. data/lib/inferno/apps/cli/templates/lib/%library_name%/patient_group.rb.tt +0 -44
  53. 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
- This is a big markdown description of the test kit.
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
- # tags ['SMART App Launch', 'US Core']
12
- # last_updated '2024-03-07'
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,3 +1,4 @@
1
1
  module <%= module_name %>
2
2
  VERSION = '0.0.0'.freeze
3
+ LAST_UPDATED = '<%= Date.today.strftime("%Y-%m-%d") %>'.freeze # TODO: update next release
3
4
  end
@@ -1 +1 @@
1
- require_relative '<%= library_name %>/suite'
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
- get ':id/requirements',
51
- to: Inferno::Web::Controllers::TestSuites::Requirements::Index,
52
- as: :requirements
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
- scope 'requirements' do
56
- get '/:id', to: Inferno::Web::Controllers::Requirements::Show, as: :show
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
@@ -14,6 +14,7 @@ module Inferno
14
14
  field :optional, if: :field_present?
15
15
  field :options, if: :field_present?
16
16
  field :locked, if: :field_present?
17
+ field :hidden, if: :field_present?
17
18
  field :value, if: :field_present?
18
19
  end
19
20
  end
@@ -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
@@ -20,6 +20,7 @@ module Inferno
20
20
  field :input_instructions
21
21
  field :user_runnable?, name: :user_runnable
22
22
  field :optional?, name: :optional
23
+ field :verifies_requirements, if: :field_present_and_requirements_enabled?
23
24
  end
24
25
  end
25
26
  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: :field_present? do |suite, options|
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
- active_rules << rulename if rule_details['Enabled']
30
- end
28
+ next unless rule_details['Enabled']
31
29
 
32
- Rule.descendants.each do |rule|
33
- rule.new.check(context) if active_rules.include?(rule.name.demodulize)
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 unused extensions defined in the IG: \n\t #{unused_extensions.join(', ')}"
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 are represented in examples'
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 represented in instances.'
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 not used in instances:'
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\t#{profile_url}: #{missing_items.join(', ')}"
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 example instances.'
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 that have no resolved references and are not referenced: #{
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
- message = "Found SearchParameters with no searchable data: \n\t#{unused_resource_urls.join(' ,')}"
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 have an expression."
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
- used = false
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
- message = "SearchParameter #{param.url} failed to evaluate due to an error. " \
60
- "Expression: #{param.expression}. #{e}"
61
- result = EvaluationResult.new(message)
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
- used = true
70
+ param_used = true
65
71
  break
66
72
  end
67
73
 
68
74
  if result.present?
69
- used = true
75
+ param_used = true
70
76
  break
71
77
  end
72
78
  end
73
- used
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 represented in instances'
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 instances: #{
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 Value sets are used in Examples:'
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 = 'Value sets with all codes used at least once in Examples:'
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 Value Sets: "
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 Value Sets: "
92
+ message += "\nFound unevaluated ValueSets: "
93
93
  value_set_unevaluated.map { |url| message += "\n\t#{url}" }
94
94
  end
95
95