inferno_core 0.4.39 → 0.4.40
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/router.rb +3 -0
- data/lib/inferno/config/application.rb +2 -0
- data/lib/inferno/dsl/auth_info.rb +142 -6
- data/lib/inferno/dsl/fhir_client.rb +2 -2
- data/lib/inferno/dsl/fhir_client_builder.rb +29 -0
- data/lib/inferno/dsl/fhir_resource_validation.rb +18 -14
- data/lib/inferno/dsl/fhir_validation.rb +14 -9
- data/lib/inferno/dsl/fhirpath_evaluation.rb +121 -0
- data/lib/inferno/dsl/jwks.rb +79 -0
- data/lib/inferno/dsl/messages.rb +71 -0
- data/lib/inferno/dsl/runnable.rb +12 -0
- data/lib/inferno/dsl.rb +5 -1
- data/lib/inferno/entities/test.rb +0 -76
- data/lib/inferno/entities/test_group.rb +13 -1
- data/lib/inferno/entities/test_suite.rb +15 -0
- data/lib/inferno/exceptions.rb +19 -0
- data/lib/inferno/ext/fhir_client.rb +3 -3
- data/lib/inferno/jobs/invoke_validator_session.rb +9 -10
- data/lib/inferno/public/bundle.js +18 -18
- data/lib/inferno/result_collection.rb +72 -0
- data/lib/inferno/result_summarizer.rb +9 -10
- data/lib/inferno/test_runner.rb +55 -27
- data/lib/inferno/version.rb +1 -1
- data/spec/fixtures/auth_info_constants.rb +71 -0
- metadata +7 -2
@@ -0,0 +1,72 @@
|
|
1
|
+
module Inferno
|
2
|
+
# The ResultCollection class is used to manage a collection of Inferno::Entities::Result objects.
|
3
|
+
# It provides methods to filter required and optional results, access results
|
4
|
+
# by index or by their runnable IDs, and iterate over the collection.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
#
|
8
|
+
# results = [
|
9
|
+
# Result.new(test_group_id: 'group_id1', result: 'pass'),
|
10
|
+
# Result.new(test_group_id: 'group_id2', result: 'fail'),
|
11
|
+
# Result.new(test_group_id: 'group_id3', result: 'pass')
|
12
|
+
# ]
|
13
|
+
#
|
14
|
+
# result_collection = Inferno::ResultCollection.new(results)
|
15
|
+
#
|
16
|
+
# # Access by index
|
17
|
+
# result = result_collection[0]
|
18
|
+
#
|
19
|
+
# # Access by runnable ID (partial)
|
20
|
+
# result = result_collection['group_id2']
|
21
|
+
#
|
22
|
+
# # Iterate over results
|
23
|
+
# result_collection.each do |result|
|
24
|
+
# puts result.result
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# # Get required results
|
28
|
+
# required_results = result_collection.required_results
|
29
|
+
#
|
30
|
+
# # Get optional results
|
31
|
+
# optional_results = result_collection.optional_results
|
32
|
+
# @private
|
33
|
+
class ResultCollection
|
34
|
+
include Enumerable
|
35
|
+
|
36
|
+
attr_reader :results
|
37
|
+
|
38
|
+
def initialize(results = [])
|
39
|
+
@results = results
|
40
|
+
end
|
41
|
+
|
42
|
+
def [](key)
|
43
|
+
key.is_a?(Integer) ? results[key] : lookup_by_runnable_id(key)
|
44
|
+
end
|
45
|
+
|
46
|
+
def <<(result)
|
47
|
+
(results << result).flatten!
|
48
|
+
self
|
49
|
+
end
|
50
|
+
|
51
|
+
def each(&)
|
52
|
+
return to_enum(:each) unless block_given?
|
53
|
+
|
54
|
+
results.each(&)
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
def required_results
|
59
|
+
results.select(&:required?)
|
60
|
+
end
|
61
|
+
|
62
|
+
def optional_results
|
63
|
+
results.select(&:optional?)
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def lookup_by_runnable_id(key)
|
69
|
+
results.find { |result| result.runnable&.id == key.to_s || result.runnable&.id&.end_with?("-#{key}") }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require_relative './result_collection'
|
1
2
|
module Inferno
|
2
3
|
# @private
|
3
4
|
# This class takes an array of results and determines the overall result. This
|
@@ -7,13 +8,11 @@ module Inferno
|
|
7
8
|
attr_reader :results
|
8
9
|
|
9
10
|
def initialize(results)
|
10
|
-
@results = results
|
11
|
+
@results = results.is_a?(ResultCollection) ? results : ResultCollection.new(results)
|
11
12
|
end
|
12
13
|
|
13
14
|
def summarize
|
14
|
-
return 'pass' if
|
15
|
-
unique_result_strings.any?('pass') &&
|
16
|
-
unique_result_strings.none? { |result| %w[wait running].include? result }
|
15
|
+
return 'pass' if optional_results_passing_criteria_met?
|
17
16
|
|
18
17
|
prioritized_result_strings.find { |result_string| unique_result_strings.include? result_string }
|
19
18
|
end
|
@@ -24,21 +23,21 @@ module Inferno
|
|
24
23
|
Entities::Result::RESULT_OPTIONS
|
25
24
|
end
|
26
25
|
|
27
|
-
def
|
28
|
-
|
26
|
+
def optional_results_passing_criteria_met?
|
27
|
+
all_optional_results? && unique_result_strings.any?('pass') &&
|
28
|
+
unique_result_strings.none? { |result| %w[wait running].include? result }
|
29
29
|
end
|
30
30
|
|
31
31
|
def all_optional_results?
|
32
|
-
required_results.blank?
|
32
|
+
results.required_results.blank?
|
33
33
|
end
|
34
34
|
|
35
35
|
def results_for_summary
|
36
|
-
all_optional_results? ? results : required_results
|
36
|
+
all_optional_results? ? results : results.required_results
|
37
37
|
end
|
38
38
|
|
39
39
|
def unique_result_strings
|
40
|
-
@unique_result_strings ||=
|
41
|
-
results_for_summary.map(&:result).uniq
|
40
|
+
@unique_result_strings ||= results_for_summary.map(&:result).uniq
|
42
41
|
end
|
43
42
|
end
|
44
43
|
end
|
data/lib/inferno/test_runner.rb
CHANGED
@@ -70,22 +70,7 @@ module Inferno
|
|
70
70
|
suite_options: test_session.suite_options_hash
|
71
71
|
)
|
72
72
|
|
73
|
-
result =
|
74
|
-
raise Exceptions::CancelException, 'Test cancelled by user' if test_run_is_cancelling
|
75
|
-
|
76
|
-
check_inputs(test, test_instance, inputs)
|
77
|
-
|
78
|
-
test_instance.load_named_requests
|
79
|
-
test_instance.instance_eval(&test.block)
|
80
|
-
'pass'
|
81
|
-
rescue Exceptions::TestResultException => e
|
82
|
-
test_instance.result_message = format_markdown(e.message)
|
83
|
-
e.result
|
84
|
-
rescue StandardError => e
|
85
|
-
Application['logger'].error(e.full_message)
|
86
|
-
test_instance.result_message = format_markdown("Error: #{e.message}\n\n#{e.backtrace.first}")
|
87
|
-
'error'
|
88
|
-
end
|
73
|
+
result = evaluate_runnable_result(test, test_instance, inputs)
|
89
74
|
|
90
75
|
outputs = save_outputs(test_instance)
|
91
76
|
output_json_string = JSON.generate(outputs)
|
@@ -144,17 +129,22 @@ module Inferno
|
|
144
129
|
return group_result
|
145
130
|
end
|
146
131
|
|
147
|
-
|
132
|
+
group_instance = group.new
|
133
|
+
|
148
134
|
group.children(test_session.suite_options).each do |child|
|
149
135
|
result = run(child, scratch)
|
150
|
-
results << result
|
151
|
-
break if
|
136
|
+
group_instance.results << result
|
137
|
+
break if result.waiting?
|
152
138
|
end
|
153
139
|
|
154
|
-
results
|
140
|
+
result = evaluate_runnable_result(group, group_instance) || roll_up_result(group_instance.results)
|
155
141
|
|
156
|
-
group_result = persist_result(group.reference_hash.merge(
|
157
|
-
|
142
|
+
group_result = persist_result(group.reference_hash.merge(
|
143
|
+
messages: group_instance.messages,
|
144
|
+
result:,
|
145
|
+
result_message: group_instance.result_message,
|
146
|
+
input_json: JSON.generate(group_inputs_with_values)
|
147
|
+
))
|
158
148
|
|
159
149
|
update_parent_result(group.parent)
|
160
150
|
|
@@ -166,15 +156,19 @@ module Inferno
|
|
166
156
|
|
167
157
|
children = parent.children(test_session.suite_options)
|
168
158
|
child_results = results_repo.current_results_for_test_session_and_runnables(test_session.id, children)
|
169
|
-
|
170
|
-
required_results = child_results.select(&:required?)
|
171
|
-
return if required_children.length != required_results.length
|
159
|
+
return unless need_to_update_parent_result?(children, child_results, &parent.block)
|
172
160
|
|
161
|
+
parent_instance = parent.new
|
162
|
+
parent_instance.results << child_results
|
173
163
|
old_result = results_repo.current_result_for_test_session(test_session.id, parent.reference_hash)&.result
|
174
|
-
new_result = roll_up_result(child_results)
|
164
|
+
new_result = evaluate_runnable_result(parent, parent_instance) || roll_up_result(child_results)
|
175
165
|
|
176
166
|
if new_result != old_result
|
177
|
-
persist_result(parent.reference_hash.merge(
|
167
|
+
persist_result(parent.reference_hash.merge(
|
168
|
+
result: new_result,
|
169
|
+
result_message: parent_instance.result_message,
|
170
|
+
messages: parent_instance.messages
|
171
|
+
))
|
178
172
|
|
179
173
|
update_parent_result(parent.parent)
|
180
174
|
end
|
@@ -182,6 +176,40 @@ module Inferno
|
|
182
176
|
new_result
|
183
177
|
end
|
184
178
|
|
179
|
+
def evaluate_runnable_result(runnable, runnable_instance, inputs = nil)
|
180
|
+
return if !(runnable < Entities::Test) && !runnable.block
|
181
|
+
|
182
|
+
if runnable < Entities::Test
|
183
|
+
raise Exceptions::CancelException, 'Test cancelled by user' if test_run_is_cancelling
|
184
|
+
|
185
|
+
check_inputs(runnable, runnable_instance, inputs)
|
186
|
+
|
187
|
+
runnable_instance.load_named_requests
|
188
|
+
end
|
189
|
+
runnable_instance.instance_eval(&runnable.block)
|
190
|
+
'pass'
|
191
|
+
rescue Exceptions::TestResultException => e
|
192
|
+
runnable_instance.result_message = format_markdown(e.message)
|
193
|
+
e.result
|
194
|
+
rescue StandardError => e
|
195
|
+
Application['logger'].error(e.full_message)
|
196
|
+
runnable_instance.result_message = format_markdown("Error: #{e.message}\n\n#{e.backtrace.first}")
|
197
|
+
'error'
|
198
|
+
end
|
199
|
+
|
200
|
+
# Determines if the parent result needs to be updated based on the results of its children.
|
201
|
+
#
|
202
|
+
# The parent result needs to be updated if:
|
203
|
+
# - No custom result block is provided and all required children have corresponding required results.
|
204
|
+
# - A custom result block is provided and all children have corresponding results.
|
205
|
+
def need_to_update_parent_result?(children, child_results, &)
|
206
|
+
required_children = children.select(&:required?)
|
207
|
+
required_results = child_results.select(&:required?)
|
208
|
+
|
209
|
+
(!block_given? && required_children.length == required_results.length) ||
|
210
|
+
(block_given? && children.length == child_results.length)
|
211
|
+
end
|
212
|
+
|
185
213
|
def load_inputs(runnable)
|
186
214
|
runnable.inputs.each_with_object({}) do |input_identifier, input_hash|
|
187
215
|
input_alias = runnable.config.input_name(input_identifier)
|
data/lib/inferno/version.rb
CHANGED
@@ -0,0 +1,71 @@
|
|
1
|
+
module AuthInfoConstants
|
2
|
+
AUTH_URL = 'http://example.com/authorization'.freeze
|
3
|
+
TOKEN_URL = 'http://example.com/token'.freeze
|
4
|
+
REQUESTED_SCOPES = 'launch/patient openid fhirUser patient/*.*'.freeze
|
5
|
+
ENCRYPTION_ALGORITHM = 'ES384'.freeze
|
6
|
+
KID = '4b49a739d1eb115b3225f4cf9beb6d1b'.freeze
|
7
|
+
JWKS = File.read(File.join('lib', 'inferno', 'dsl', 'jwks.json')).freeze
|
8
|
+
class << self
|
9
|
+
def token_info
|
10
|
+
{
|
11
|
+
access_token: 'SAMPLE_TOKEN',
|
12
|
+
refresh_token: 'SAMPLE_REFRESH_TOKEN',
|
13
|
+
expires_in: '3600',
|
14
|
+
issue_time: Time.now.iso8601
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
def public_access_default
|
19
|
+
{
|
20
|
+
auth_type: 'public',
|
21
|
+
token_url: TOKEN_URL,
|
22
|
+
client_id: 'SAMPLE_PUBLIC_CLIENT_ID',
|
23
|
+
requested_scopes: REQUESTED_SCOPES,
|
24
|
+
pkce_support: 'enabled',
|
25
|
+
pkce_code_challenge_method: 'S256',
|
26
|
+
auth_request_method: 'GET'
|
27
|
+
}.merge(token_info)
|
28
|
+
end
|
29
|
+
|
30
|
+
def symmetric_confidential_access_default
|
31
|
+
{
|
32
|
+
auth_type: 'symmetric',
|
33
|
+
token_url: TOKEN_URL,
|
34
|
+
client_id: 'SAMPLE_CONFIDENTIAL_CLIENT_ID',
|
35
|
+
client_secret: 'SAMPLE_CONFIDENTIAL_CLIENT_SECRET',
|
36
|
+
auth_url: AUTH_URL,
|
37
|
+
requested_scopes: REQUESTED_SCOPES,
|
38
|
+
pkce_support: 'enabled',
|
39
|
+
pkce_code_challenge_method: 'S256',
|
40
|
+
auth_request_method: 'post',
|
41
|
+
use_discovery: 'false'
|
42
|
+
}.merge(token_info)
|
43
|
+
end
|
44
|
+
|
45
|
+
def asymmetric_confidential_access_default
|
46
|
+
{
|
47
|
+
auth_type: 'asymmetric',
|
48
|
+
token_url: TOKEN_URL,
|
49
|
+
client_id: 'SAMPLE_CONFIDENTIAL_CLIENT_ID',
|
50
|
+
requested_scopes: REQUESTED_SCOPES,
|
51
|
+
pkce_support: 'disabled',
|
52
|
+
auth_request_method: 'post',
|
53
|
+
encryption_algorithm: ENCRYPTION_ALGORITHM,
|
54
|
+
jwks: JWKS,
|
55
|
+
kid: KID
|
56
|
+
}.merge(token_info)
|
57
|
+
end
|
58
|
+
|
59
|
+
def backend_services_access_default
|
60
|
+
{
|
61
|
+
auth_type: 'backend_services',
|
62
|
+
token_url: TOKEN_URL,
|
63
|
+
client_id: 'SAMPLE_CONFIDENTIAL_CLIENT_ID',
|
64
|
+
requested_scopes: REQUESTED_SCOPES,
|
65
|
+
encryption_algorithm: ENCRYPTION_ALGORITHM,
|
66
|
+
jwks: JWKS,
|
67
|
+
kid: KID
|
68
|
+
}.merge(token_info)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inferno_core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.40
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen MacVicar
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2024-
|
13
|
+
date: 2024-09-12 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
@@ -649,9 +649,12 @@ files:
|
|
649
649
|
- lib/inferno/dsl/fhir_client_builder.rb
|
650
650
|
- lib/inferno/dsl/fhir_resource_validation.rb
|
651
651
|
- lib/inferno/dsl/fhir_validation.rb
|
652
|
+
- lib/inferno/dsl/fhirpath_evaluation.rb
|
652
653
|
- lib/inferno/dsl/http_client.rb
|
653
654
|
- lib/inferno/dsl/http_client_builder.rb
|
654
655
|
- lib/inferno/dsl/input_output_handling.rb
|
656
|
+
- lib/inferno/dsl/jwks.rb
|
657
|
+
- lib/inferno/dsl/messages.rb
|
655
658
|
- lib/inferno/dsl/oauth_credentials.rb
|
656
659
|
- lib/inferno/dsl/request_storage.rb
|
657
660
|
- lib/inferno/dsl/results.rb
|
@@ -713,6 +716,7 @@ files:
|
|
713
716
|
- lib/inferno/repositories/tests.rb
|
714
717
|
- lib/inferno/repositories/validate_runnable_reference.rb
|
715
718
|
- lib/inferno/repositories/validator_sessions.rb
|
719
|
+
- lib/inferno/result_collection.rb
|
716
720
|
- lib/inferno/result_summarizer.rb
|
717
721
|
- lib/inferno/spec_support.rb
|
718
722
|
- lib/inferno/test_runner.rb
|
@@ -731,6 +735,7 @@ files:
|
|
731
735
|
- spec/factories/result.rb
|
732
736
|
- spec/factories/test_run.rb
|
733
737
|
- spec/factories/test_session.rb
|
738
|
+
- spec/fixtures/auth_info_constants.rb
|
734
739
|
- spec/fixtures/basic_test_group.rb
|
735
740
|
- spec/fixtures/basic_test_suite.rb
|
736
741
|
- spec/support/factory_bot.rb
|