inferno_core 1.4.6 → 1.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/web/serializers/test.rb +1 -0
- data/lib/inferno/apps/web/serializers/test_group.rb +1 -0
- data/lib/inferno/apps/web/templates/test_kit.html.erb +10 -6
- data/lib/inferno/dsl/fhir_resource_navigation.rb +10 -5
- data/lib/inferno/dsl/must_support_assessment.rb +10 -20
- data/lib/inferno/dsl/must_support_strings.rb +62 -0
- data/lib/inferno/dsl/profile_metadata.rb +9 -18
- data/lib/inferno/dsl/resume_test_route.rb +12 -4
- data/lib/inferno/dsl/runnable.rb +25 -4
- data/lib/inferno/dsl/suite_endpoint.rb +19 -6
- data/lib/inferno/dsl/value_extractor.rb +22 -4
- data/lib/inferno/entities/test_kit.rb +2 -1
- data/lib/inferno/public/bundle.js +34 -34
- data/lib/inferno/repositories/results.rb +14 -9
- data/lib/inferno/version.rb +1 -1
- data/spec/shared/test_kit_examples.rb +2 -2
- metadata +5 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ebcc6f348889f26a45097656da0a40a89b233bc7a216f06c8d538092362419a1
|
|
4
|
+
data.tar.gz: dfddeba814ef81eaddbc3b54635903cc01b9a7016a00a06eb6c723a01af2adf7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b97797a253c6d9419ce3a715e56a97464a4ce04f0e48944067c9fbe72b1c645c907d11c33cca7cbe5bfa2771f25908dfdd7ead1f59d63ef5f0850755d2733ce4
|
|
7
|
+
data.tar.gz: '0184d977bbb3e25ef6ef3d9b02ec69e7f17f90cec4f00b54b19e3eab87a5621bec611d3fd2b9a20079503e873ec1141999c1df357d4cb0937da48c36d5a05814'
|
|
@@ -23,6 +23,7 @@ module Inferno
|
|
|
23
23
|
field :optional?, name: :optional
|
|
24
24
|
field :simulation_verification?, name: :is_simulation_verification
|
|
25
25
|
field :attestation?, name: :is_attestation
|
|
26
|
+
field :tester_initiated_exchange?, name: :is_tester_initiated_exchange
|
|
26
27
|
field :verifies_requirements, if: :field_present?, extractor: RequirementsFilteringExtractor
|
|
27
28
|
end
|
|
28
29
|
end
|
|
@@ -18,6 +18,7 @@ module Inferno
|
|
|
18
18
|
field :user_runnable?, name: :user_runnable
|
|
19
19
|
field :optional?, name: :optional
|
|
20
20
|
field :simulation_verification?, name: :is_simulation_verification
|
|
21
|
+
field :tester_initiated_exchange?, name: :is_tester_initiated_exchange
|
|
21
22
|
|
|
22
23
|
field :test_count do |group, options|
|
|
23
24
|
group.test_count(options[:suite_options])
|
|
@@ -145,11 +145,15 @@
|
|
|
145
145
|
</div>
|
|
146
146
|
<div class="modal-body">
|
|
147
147
|
<p>
|
|
148
|
-
Test Kits are broadly grouped into
|
|
149
|
-
<strong>
|
|
150
|
-
<strong>Low</strong>. This is intended
|
|
151
|
-
on the level of confidence they should
|
|
152
|
-
completeness of these tests.
|
|
148
|
+
Test Kits are broadly grouped into four levels of maturity:
|
|
149
|
+
<strong>Certification</strong>, <strong>High</strong>,
|
|
150
|
+
<strong>Medium</strong>, and <strong>Low</strong>. This is intended
|
|
151
|
+
to provide guidance to users on the level of confidence they should
|
|
152
|
+
place in the accuracy and completeness of these tests.
|
|
153
|
+
</p>
|
|
154
|
+
<p>
|
|
155
|
+
<strong>Certification</strong> maturity Test Kits are used as part
|
|
156
|
+
of a formal certification program.
|
|
153
157
|
</p>
|
|
154
158
|
<p>
|
|
155
159
|
<strong>High</strong> maturity Test Kits typically have been
|
|
@@ -157,7 +161,7 @@
|
|
|
157
161
|
that has limited ambiguity.
|
|
158
162
|
</p>
|
|
159
163
|
<p>
|
|
160
|
-
<strong>
|
|
164
|
+
<strong>Medium</strong> and <strong>Low</strong> maturity Test Kits typically have
|
|
161
165
|
not had widespread usage and/or are targeting less mature
|
|
162
166
|
specifications that contain ambiguous or conflicting information.
|
|
163
167
|
These Test Kits are still of value to implementers, but they should be
|
|
@@ -252,16 +252,18 @@ module Inferno
|
|
|
252
252
|
|
|
253
253
|
# @private
|
|
254
254
|
def matching_pattern_codeable_concept_slice?(slice, discriminator)
|
|
255
|
-
|
|
256
|
-
|
|
255
|
+
codings = resolve_path(slice, discriminator[:path])
|
|
256
|
+
.flat_map { |codeable_concept| Array.wrap(codeable_concept.coding) }
|
|
257
|
+
codings.any? do |coding|
|
|
257
258
|
coding.code == discriminator[:code] && coding.system == discriminator[:system]
|
|
258
259
|
end
|
|
259
260
|
end
|
|
260
261
|
|
|
261
262
|
# @private
|
|
262
263
|
def matching_pattern_coding_slice?(slice, discriminator)
|
|
263
|
-
|
|
264
|
-
|
|
264
|
+
resolve_path(slice, discriminator[:path]).any? do |coding|
|
|
265
|
+
coding.code == discriminator[:code] && coding.system == discriminator[:system]
|
|
266
|
+
end
|
|
265
267
|
end
|
|
266
268
|
|
|
267
269
|
# @private
|
|
@@ -323,7 +325,10 @@ module Inferno
|
|
|
323
325
|
when String
|
|
324
326
|
value == coding.code
|
|
325
327
|
when Hash
|
|
326
|
-
|
|
328
|
+
next false unless value[:system] == coding.system
|
|
329
|
+
|
|
330
|
+
# A value without a code stands for every code in its system
|
|
331
|
+
value[:code].nil? ? coding.code.present? : value[:code] == coding.code
|
|
327
332
|
end
|
|
328
333
|
end
|
|
329
334
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require_relative 'must_support_strings'
|
|
2
|
+
|
|
1
3
|
module Inferno
|
|
2
4
|
module DSL
|
|
3
5
|
# The MustSupportAssessment module contains the logic for tests
|
|
@@ -23,7 +25,7 @@ module Inferno
|
|
|
23
25
|
# test kits can subclass to build these objects, eg from generated YAML, instead of hand-rolling one.
|
|
24
26
|
# @param requirement_extension [String] Extension URL that implies "required" as an alternative to the MS flag
|
|
25
27
|
# @yield [MustSupportMetadataExtractor] Customize the metadata before running the test
|
|
26
|
-
# @return [Array<String>] List of missing elements
|
|
28
|
+
# @return [Array<String>] List of missing elements, sorted alphabetically
|
|
27
29
|
def missing_must_support_elements(resources, profile_url, validator_name: :default, metadata: nil,
|
|
28
30
|
requirement_extension: nil, &)
|
|
29
31
|
debug_metadata = config.options[:debug_must_support_metadata]
|
|
@@ -195,18 +197,17 @@ module Inferno
|
|
|
195
197
|
end
|
|
196
198
|
end
|
|
197
199
|
|
|
200
|
+
# See {MustSupportStrings} for how each missing item is represented. Sorted to match
|
|
201
|
+
# {ProfileMetadata#must_support_strings}.
|
|
198
202
|
def missing_must_support_strings
|
|
199
|
-
missing_elements.map { |element_definition| missing_element_string(element_definition) } +
|
|
200
|
-
missing_slices.map { |slice_definition| slice_definition
|
|
201
|
-
missing_extensions.map { |extension_definition| extension_definition
|
|
203
|
+
(missing_elements.map { |element_definition| missing_element_string(element_definition) } +
|
|
204
|
+
missing_slices.map { |slice_definition| MustSupportStrings.slice_string(slice_definition) } +
|
|
205
|
+
missing_extensions.map { |extension_definition| MustSupportStrings.extension_string(extension_definition) })
|
|
206
|
+
.sort
|
|
202
207
|
end
|
|
203
208
|
|
|
204
209
|
def missing_element_string(element_definition)
|
|
205
|
-
|
|
206
|
-
"#{element_definition[:path]}:#{element_definition[:fixed_value]}"
|
|
207
|
-
else
|
|
208
|
-
element_definition[:path]
|
|
209
|
-
end
|
|
210
|
+
MustSupportStrings.element_string(element_definition)
|
|
210
211
|
end
|
|
211
212
|
|
|
212
213
|
def must_support_extensions
|
|
@@ -452,17 +453,6 @@ module Inferno
|
|
|
452
453
|
def find_slice_by_values(element, value_definitions)
|
|
453
454
|
Array.wrap(element).find { |el| verify_slice_by_values(el, value_definitions) }
|
|
454
455
|
end
|
|
455
|
-
|
|
456
|
-
def required_binding_value_match?(coding, values)
|
|
457
|
-
values.any? do |value|
|
|
458
|
-
case value
|
|
459
|
-
when String
|
|
460
|
-
value == coding.code
|
|
461
|
-
when Hash
|
|
462
|
-
value[:system] == coding.system && value[:code] == coding.code
|
|
463
|
-
end
|
|
464
|
-
end
|
|
465
|
-
end
|
|
466
456
|
end
|
|
467
457
|
end
|
|
468
458
|
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
module Inferno
|
|
2
|
+
module DSL
|
|
3
|
+
# Builds the strings used to identify Must Support elements, slices, and extensions from their
|
|
4
|
+
# metadata, so that lists of what is expected to be supported (eg {ProfileMetadata#must_support_strings})
|
|
5
|
+
# and lists of what is missing (eg {MustSupportAssessment#missing_must_support_elements}) agree.
|
|
6
|
+
#
|
|
7
|
+
# Each item is represented by its ElementDefinition id (which includes the names of any parent
|
|
8
|
+
# slices) without the leading resource type, eg 'category:us-core' rather than
|
|
9
|
+
# 'Condition.category:us-core'. Elements with a fixed value have it appended, eg 'name.use = old'.
|
|
10
|
+
# @private
|
|
11
|
+
module MustSupportStrings
|
|
12
|
+
module_function
|
|
13
|
+
|
|
14
|
+
# @param element_definition [Hash] Must Support element metadata
|
|
15
|
+
# @return [String]
|
|
16
|
+
def element_string(element_definition)
|
|
17
|
+
path = element_display_path(element_definition)
|
|
18
|
+
|
|
19
|
+
fixed_value = element_definition[:fixed_value]
|
|
20
|
+
if fixed_value.present? || fixed_value == false
|
|
21
|
+
"#{path} = #{fixed_value}"
|
|
22
|
+
else
|
|
23
|
+
path
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# @param slice_definition [Hash] Must Support slice metadata
|
|
28
|
+
# @return [String]
|
|
29
|
+
def slice_string(slice_definition)
|
|
30
|
+
id_string(slice_definition, :slice_id)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @param extension_definition [Hash] Must Support extension metadata
|
|
34
|
+
# @return [String]
|
|
35
|
+
def extension_string(extension_definition)
|
|
36
|
+
id_string(extension_definition, :id)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Elements under a choice type slice (eg value[x]:valueQuantity.value) have their navigation
|
|
40
|
+
# path rewritten so the slice name is mangled (eg valueQuantity:valueQuantity.value), so report
|
|
41
|
+
# the original path instead. Elements where only some types of a choice are Must Support
|
|
42
|
+
# (eg original path effective[x], path effectiveDateTime) keep their path since it names the type.
|
|
43
|
+
def element_display_path(element_definition)
|
|
44
|
+
original_path = element_definition[:original_path]
|
|
45
|
+
original_path&.include?('[x]:') ? original_path : element_definition[:path]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def id_string(definition, id_key)
|
|
49
|
+
id = definition[id_key]
|
|
50
|
+
raise ArgumentError, "Must Support metadata is missing #{id_key.inspect}: #{definition.inspect}" if id.blank?
|
|
51
|
+
|
|
52
|
+
without_resource_type(id)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Resource types are PascalCase while element names are camelCase, so a leading
|
|
56
|
+
# capitalized segment is the resource type prefix of an ElementDefinition id.
|
|
57
|
+
def without_resource_type(id)
|
|
58
|
+
id&.sub(/\A[A-Z][A-Za-z0-9]*\./, '')
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require_relative 'must_support_strings'
|
|
2
|
+
|
|
1
3
|
module Inferno
|
|
2
4
|
module DSL
|
|
3
5
|
# A ProfileMetadata object is a small, inheritable data holder for generated metadata about a
|
|
@@ -85,29 +87,18 @@ module Inferno
|
|
|
85
87
|
# check, this includes everything that's expected to be supported, not just what's absent
|
|
86
88
|
# from a particular set of resources.
|
|
87
89
|
#
|
|
88
|
-
#
|
|
89
|
-
#
|
|
90
|
-
#
|
|
91
|
-
# (eg `"
|
|
90
|
+
# Each item is represented the same way as in the list returned by a missing-elements check:
|
|
91
|
+
# by its ElementDefinition id (including the names of any parent slices) without the leading
|
|
92
|
+
# resource type (eg `"category:us-core"`, `"extension:us-core-race"`), with any matched
|
|
93
|
+
# `fixed_value` appended to elements (eg `"code.coding.code = 45473-6"`). See {MustSupportStrings}.
|
|
92
94
|
# @return [Array<String>]
|
|
93
95
|
def must_support_strings
|
|
94
|
-
element_strings =
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
end
|
|
98
|
-
slice_strings =
|
|
99
|
-
Array.wrap(must_supports[:slices]).map { |slice| must_support_string(slice[:path], slice[:slice_name]) }
|
|
100
|
-
extension_strings =
|
|
101
|
-
Array.wrap(must_supports[:extensions]).map { |ext| must_support_string(ext[:path], ext[:slice_name]) }
|
|
96
|
+
element_strings = Array.wrap(must_supports[:elements]).map { |el| MustSupportStrings.element_string(el) }
|
|
97
|
+
slice_strings = Array.wrap(must_supports[:slices]).map { |slice| MustSupportStrings.slice_string(slice) }
|
|
98
|
+
extension_strings = Array.wrap(must_supports[:extensions]).map { |ex| MustSupportStrings.extension_string(ex) }
|
|
102
99
|
|
|
103
100
|
(element_strings + slice_strings + extension_strings).sort
|
|
104
101
|
end
|
|
105
|
-
|
|
106
|
-
private
|
|
107
|
-
|
|
108
|
-
def must_support_string(path, suffix)
|
|
109
|
-
suffix.present? ? "#{path}:#{suffix}" : path
|
|
110
|
-
end
|
|
111
102
|
end
|
|
112
103
|
end
|
|
113
104
|
end
|
|
@@ -75,6 +75,17 @@ module Inferno
|
|
|
75
75
|
test_run.test_suite_id || test_run.test_group_id || test.parent&.id || test.id
|
|
76
76
|
end
|
|
77
77
|
|
|
78
|
+
# @private
|
|
79
|
+
def no_test_run_message(test_run_identifier, url)
|
|
80
|
+
base_message = "Inferno could not find an active test run for this request to '#{url}'"
|
|
81
|
+
|
|
82
|
+
if test_run_identifier.blank?
|
|
83
|
+
"#{base_message}: no identifier found."
|
|
84
|
+
else
|
|
85
|
+
"#{base_message}: identifier '#{test_run_identifier}' is not associated with a waiting session."
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
78
89
|
# @private
|
|
79
90
|
def handle(req, res)
|
|
80
91
|
request = Inferno::Entities::Request.from_hanami_request(req)
|
|
@@ -84,10 +95,7 @@ module Inferno
|
|
|
84
95
|
|
|
85
96
|
test_run = find_test_run(test_run_identifier)
|
|
86
97
|
|
|
87
|
-
if test_run.nil?
|
|
88
|
-
halt 500, "Unable to find test run with identifier '#{test_run_identifier}' " \
|
|
89
|
-
"on request to '#{request.url}'."
|
|
90
|
-
end
|
|
98
|
+
halt 500, no_test_run_message(test_run_identifier, request.url) if test_run.nil?
|
|
91
99
|
|
|
92
100
|
test_runs_repo.mark_as_no_longer_waiting(test_run.id)
|
|
93
101
|
|
data/lib/inferno/dsl/runnable.rb
CHANGED
|
@@ -309,14 +309,17 @@ module Inferno
|
|
|
309
309
|
!optional?
|
|
310
310
|
end
|
|
311
311
|
|
|
312
|
-
#
|
|
312
|
+
# Flag as simulation verification. Tests are not simulation verification by default.
|
|
313
313
|
#
|
|
314
314
|
# @param simulation_verification [Boolean]
|
|
315
315
|
# @return [void]
|
|
316
|
-
def
|
|
316
|
+
def flag_as_simulation_verification(simulation_verification = true) # rubocop:disable Style/OptionalBooleanParameter
|
|
317
317
|
@is_simulation_verification = simulation_verification
|
|
318
318
|
end
|
|
319
319
|
|
|
320
|
+
# Alias for {#flag_as_simulation_verification}
|
|
321
|
+
alias simulation_verification flag_as_simulation_verification
|
|
322
|
+
|
|
320
323
|
# The test is simulation verification if true
|
|
321
324
|
#
|
|
322
325
|
# @return [Boolean]
|
|
@@ -324,14 +327,17 @@ module Inferno
|
|
|
324
327
|
!!@is_simulation_verification
|
|
325
328
|
end
|
|
326
329
|
|
|
327
|
-
#
|
|
330
|
+
# Flag as attestation. Tests are not attestation by default.
|
|
328
331
|
#
|
|
329
332
|
# @param attestation [Boolean]
|
|
330
333
|
# @return [void]
|
|
331
|
-
def
|
|
334
|
+
def flag_as_attestation(attestation = true) # rubocop:disable Style/OptionalBooleanParameter
|
|
332
335
|
@is_attestation = attestation
|
|
333
336
|
end
|
|
334
337
|
|
|
338
|
+
# Alias for {#flag_as_attestation}
|
|
339
|
+
alias attestation flag_as_attestation
|
|
340
|
+
|
|
335
341
|
# The test is attestation if true
|
|
336
342
|
#
|
|
337
343
|
# @return [Boolean]
|
|
@@ -339,6 +345,21 @@ module Inferno
|
|
|
339
345
|
!!@is_attestation
|
|
340
346
|
end
|
|
341
347
|
|
|
348
|
+
# Flag as tester-initiated exchange. Tests are not tester-initiated exchanges by default.
|
|
349
|
+
#
|
|
350
|
+
# @param tester_initiated_exchange [Boolean]
|
|
351
|
+
# @return [void]
|
|
352
|
+
def flag_as_tester_initiated_exchange(tester_initiated_exchange = true) # rubocop:disable Style/OptionalBooleanParameter
|
|
353
|
+
@is_tester_initiated_exchange = tester_initiated_exchange
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
# The test is a tester-initiated exchange if true
|
|
357
|
+
#
|
|
358
|
+
# @return [Boolean]
|
|
359
|
+
def tester_initiated_exchange?
|
|
360
|
+
!!@is_tester_initiated_exchange
|
|
361
|
+
end
|
|
362
|
+
|
|
342
363
|
# @private
|
|
343
364
|
def default_id
|
|
344
365
|
to_s
|
|
@@ -97,7 +97,9 @@ module Inferno
|
|
|
97
97
|
|
|
98
98
|
# @private
|
|
99
99
|
def error_response_format_value
|
|
100
|
-
@error_response_format_value
|
|
100
|
+
return @error_response_format_value if @error_response_format_value.present?
|
|
101
|
+
|
|
102
|
+
superclass.respond_to?(:error_response_format_value) ? superclass.error_response_format_value : :text
|
|
101
103
|
end
|
|
102
104
|
end
|
|
103
105
|
|
|
@@ -308,7 +310,8 @@ module Inferno
|
|
|
308
310
|
log_error(e)
|
|
309
311
|
render_error_and_halt do
|
|
310
312
|
error_response(
|
|
311
|
-
|
|
313
|
+
"Inferno could not find an active test run for this request to '#{request.url}': " \
|
|
314
|
+
'error encountered while determining the test run identifier.',
|
|
312
315
|
code: 'exception',
|
|
313
316
|
diagnostics: e.full_message
|
|
314
317
|
)
|
|
@@ -317,7 +320,7 @@ module Inferno
|
|
|
317
320
|
|
|
318
321
|
# @private
|
|
319
322
|
def no_session_message
|
|
320
|
-
base_message = "
|
|
323
|
+
base_message = "Inferno could not find an active test run for this request to '#{request.url}'"
|
|
321
324
|
location = test_run_identifier_location_description
|
|
322
325
|
identifier = find_test_run_identifier
|
|
323
326
|
|
|
@@ -369,10 +372,11 @@ module Inferno
|
|
|
369
372
|
details: FHIR::CodeableConcept.new(text: message)
|
|
370
373
|
)
|
|
371
374
|
issue.diagnostics = diagnostics if diagnostics
|
|
375
|
+
meta = FHIR::Meta.new(source: Application['base_url'])
|
|
372
376
|
|
|
373
377
|
response.status = 500
|
|
374
378
|
response.content_type = 'application/fhir+json'
|
|
375
|
-
response.body = FHIR::OperationOutcome.new(issue: [issue]).to_json
|
|
379
|
+
response.body = FHIR::OperationOutcome.new(meta:, issue: [issue]).to_json
|
|
376
380
|
end
|
|
377
381
|
|
|
378
382
|
# @private
|
|
@@ -427,7 +431,7 @@ module Inferno
|
|
|
427
431
|
log_error(e)
|
|
428
432
|
render_error_and_halt do
|
|
429
433
|
error_response(
|
|
430
|
-
|
|
434
|
+
"Inferno encountered an error while processing this request to '#{request.url}'.",
|
|
431
435
|
code: 'exception',
|
|
432
436
|
diagnostics: e.full_message
|
|
433
437
|
)
|
|
@@ -459,7 +463,7 @@ module Inferno
|
|
|
459
463
|
|
|
460
464
|
response_headers = response_headers.map { |name, value| { name:, value: } }
|
|
461
465
|
|
|
462
|
-
repo.create(
|
|
466
|
+
persisted_request = repo.create(
|
|
463
467
|
verb:,
|
|
464
468
|
url:,
|
|
465
469
|
direction: 'incoming',
|
|
@@ -474,6 +478,15 @@ module Inferno
|
|
|
474
478
|
tags: env['inferno.tags']
|
|
475
479
|
)
|
|
476
480
|
|
|
481
|
+
# Display the request with the waiting test's result. Failures are
|
|
482
|
+
# logged rather than raised so that they cannot prevent the test run
|
|
483
|
+
# from resuming.
|
|
484
|
+
begin
|
|
485
|
+
results_repo.add_request(env['inferno.result_id'], persisted_request.id)
|
|
486
|
+
rescue StandardError => e
|
|
487
|
+
log_error(e, url:)
|
|
488
|
+
end
|
|
489
|
+
|
|
477
490
|
if env['inferno.resume_test_run']
|
|
478
491
|
test_run_id = env['inferno.test_run_id']
|
|
479
492
|
Inferno::Repositories::TestRuns.new.mark_as_no_longer_waiting(test_run_id)
|
|
@@ -60,9 +60,8 @@ module Inferno
|
|
|
60
60
|
def bound_systems_from_valueset_include_element(include_element)
|
|
61
61
|
if include_element.concept.present?
|
|
62
62
|
include_element
|
|
63
|
-
elsif
|
|
64
|
-
|
|
65
|
-
ig_resources.code_system_by_url(include_element.system)
|
|
63
|
+
elsif whole_code_system_include?(include_element)
|
|
64
|
+
whole_code_system(include_element)
|
|
66
65
|
elsif include_element.valueSet.present?
|
|
67
66
|
include_element.valueSet.map do |vs|
|
|
68
67
|
a_value_set = ig_resources.value_set_by_url(vs)
|
|
@@ -71,6 +70,18 @@ module Inferno
|
|
|
71
70
|
end
|
|
72
71
|
end
|
|
73
72
|
|
|
73
|
+
def whole_code_system_include?(include_element)
|
|
74
|
+
include_element.system.present? && include_element.concept.blank? &&
|
|
75
|
+
include_element.filter&.empty? && include_element.valueSet.blank?
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# An include of a whole code system lists no codes. Use the code system's concepts when the IG
|
|
79
|
+
# has them, otherwise keep the include so that any code from its system is accepted.
|
|
80
|
+
def whole_code_system(include_element)
|
|
81
|
+
code_system = ig_resources.code_system_by_url(include_element.system)
|
|
82
|
+
code_system&.concept.present? ? code_system : include_element
|
|
83
|
+
end
|
|
84
|
+
|
|
74
85
|
def codes_from_value_set_binding(the_element)
|
|
75
86
|
codes_from_system_code_pair(codings_from_value_set_binding(the_element))
|
|
76
87
|
end
|
|
@@ -99,7 +110,7 @@ module Inferno
|
|
|
99
110
|
bound_systems.flat_map do |bound_system|
|
|
100
111
|
case bound_system
|
|
101
112
|
when FHIR::ValueSet::Compose::Include
|
|
102
|
-
bound_system
|
|
113
|
+
codings_from_include(bound_system)
|
|
103
114
|
when FHIR::CodeSystem
|
|
104
115
|
bound_system.concept.map { |concept| { system: bound_system.url, code: concept.code } }
|
|
105
116
|
else
|
|
@@ -108,6 +119,13 @@ module Inferno
|
|
|
108
119
|
end.uniq
|
|
109
120
|
end
|
|
110
121
|
|
|
122
|
+
# A whole code system include becomes a system-only value
|
|
123
|
+
def codings_from_include(include_element)
|
|
124
|
+
return [{ system: include_element.system }] if include_element.concept.blank?
|
|
125
|
+
|
|
126
|
+
include_element.concept.map { |concept| { system: include_element.system, code: concept.code } }
|
|
127
|
+
end
|
|
128
|
+
|
|
111
129
|
def value_set_expansion_contains(element)
|
|
112
130
|
value_set(element)&.expansion&.contains
|
|
113
131
|
end
|
|
@@ -92,7 +92,8 @@ module Inferno
|
|
|
92
92
|
|
|
93
93
|
# Set/get the maturity level for the test kit
|
|
94
94
|
#
|
|
95
|
-
# @param new_maturity [String]
|
|
95
|
+
# @param new_maturity [String] one of 'Low', 'Medium', 'High', or
|
|
96
|
+
# 'Certification'
|
|
96
97
|
# @return [String]
|
|
97
98
|
def maturity(new_maturity = nil)
|
|
98
99
|
return @maturity if new_maturity.nil?
|