inferno_core 0.4.39 → 0.4.40
Sign up to get free protection for your applications and to get access to all the features.
- 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
|