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.
@@ -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 all_optional_results? &&
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 required_results
28
- @required_results ||= results.select(&:required?)
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
@@ -70,22 +70,7 @@ module Inferno
70
70
  suite_options: test_session.suite_options_hash
71
71
  )
72
72
 
73
- result = begin
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
- results = []
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 results.last.waiting?
136
+ group_instance.results << result
137
+ break if result.waiting?
152
138
  end
153
139
 
154
- results.flatten!
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(result: roll_up_result(results),
157
- input_json: JSON.generate(group_inputs_with_values)))
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
- required_children = children.select(&:required?)
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(result: new_result))
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)
@@ -1,4 +1,4 @@
1
1
  module Inferno
2
2
  # Standard patterns for gem versions: https://guides.rubygems.org/patterns/
3
- VERSION = '0.4.39'.freeze
3
+ VERSION = '0.4.40'.freeze
4
4
  end
@@ -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.39
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-06-25 00:00:00.000000000 Z
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