inferno_core 0.6.2 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7789d88730cda670cc051b8d0d56d1a9d3f8fba3133628eda872eddebd57abf9
4
- data.tar.gz: 7f617722c5dd12f6ed349dd474954b7af2fc499420815e4087a18af68dbe5024
3
+ metadata.gz: afdf870396c4f72a853bcbc56b7f134c827391a0b0b2e956b47e79aa36fccdf8
4
+ data.tar.gz: d77d91fc728001379862adb5d740039704d3dd81fe184b8e11d3b99a650e5218
5
5
  SHA512:
6
- metadata.gz: 47b1907c5b14d12b59466d131addf56ba5579e99c7ad96ed8d7e5a7de8e8b83825f4599e39f01aa9abecd263b2fb4945c8e53efc11d247fb7eb969771ede9a06
7
- data.tar.gz: 04d10803787c55903e58131832b8586a5592e27608f46b17831abf30ff4ce560fed2061e9db203965f967109e393641a3d5c17a048845df8ab1b3fba664adacc
6
+ metadata.gz: 03ff313b070ce6d09ae5ec35c0f677ed30c04010915189fdf9361ddb0e69b5df9ae0bdb7350a9e8db041a3352cc183d60173b0598fc729273ccfdf1386b03351
7
+ data.tar.gz: 37ea35ed4bad96e583f935763f22865244d01ae8daed58b43b0a82d9e2b74d5a39efcc6995bdc087c19fa620eddbc131f81a6365aa8ece6b12dcf8db319c9245
@@ -6,7 +6,6 @@ RUN mkdir -p $INSTALL_PATH
6
6
 
7
7
  WORKDIR $INSTALL_PATH
8
8
 
9
- ADD lib/<%= library_name %>/metadata.rb $INSTALL_PATH/lib/<%= library_name %>/metadata.rb
10
9
  ADD lib/<%= library_name %>/version.rb $INSTALL_PATH/lib/<%= library_name %>/version.rb
11
10
  ADD *.gemspec $INSTALL_PATH
12
11
  ADD Gemfile* $INSTALL_PATH
@@ -3,6 +3,16 @@
3
3
  <%= human_name %> [Inferno](https://github.com/inferno-community/inferno-core) Test Kit
4
4
  for FHIR testing.
5
5
 
6
+ ## Getting Started
7
+
8
+ The quickest way to run this test kit locally is with [Docker](https://www.docker.com/).
9
+
10
+ - Install Docker
11
+ - Clone this repository, or download an [official release](/releases) if available.
12
+ - Run `./setup.sh` within the test kit directory to download necessary dependencies
13
+ - Run `./run.sh` within the test kit directory to start the application
14
+ - Navigate to `http://localhost`
15
+
6
16
  ## Instructions for Developing Your Test Kit
7
17
 
8
18
  Refer to the Inferno documentation for information about [setting up
@@ -0,0 +1,7 @@
1
+ This file was generated from the Inferno template to demonstrate providing
2
+ documentation across multiple files, and has not yet customized for this test
3
+ kit.
4
+
5
+ For examples of test kit documentation, refer to the [US Core Test
6
+ Kit](/inferno-framework/us-core-test-kit/wiki) and the [ONC Certification
7
+ (g)(10) Test Kit](/inferno-framework/onc-certification-g10-test-kit/wiki).
@@ -0,0 +1,10 @@
1
+ <%= human_name %> documentation. This file has been generated from the Inferno
2
+ test kit template and has not yet been customized for this test kit.
3
+
4
+ *Note to developer: After customizing this documentation, initialize a GitHub
5
+ wiki within this repository to enable automatic publishing to the wiki via the
6
+ included Publish Docs Wiki action.*
7
+
8
+ ## Using this Test Kit (example)
9
+ * [Getting Started](../?tab=readme-ov-file#getting-started): Installation instructions for this test kit.
10
+ * [Test Kit Overview](Overview.md): An overview of the test kit and its tests.
@@ -0,0 +1,5 @@
1
+ _Test kit documentation is stored within the [./docs](../tree/main/docs) folder of
2
+ this repository and is automatically synchronized to this wiki with each update
3
+ to the `main` branch using the [Publish Docs Wiki
4
+ workflow](../actions/workflows/publish-docs-wiki.yml). Do not change content
5
+ within this wiki directly as changes will be overwritten._
@@ -0,0 +1,5 @@
1
+ **[Documentation Home](Home)**
2
+
3
+ **Using this Test Kit**
4
+ - [Getting Started](../?tab=readme-ov-file#getting-started)
5
+ - [Test Kit Overview](Overview.md)
@@ -307,9 +307,95 @@ module Inferno
307
307
  self.expires_in = expires_in
308
308
  self.issue_time = DateTime.now
309
309
 
310
- add_to_client(client)
310
+ add_to_client(client) if client
311
311
  self
312
312
  end
313
+
314
+ # Returns the default configuration for the "auth_type" component
315
+ # @return [Hash]
316
+ def self.default_auth_type_component
317
+ {
318
+ name: :auth_type,
319
+ options: {
320
+ list_options: [
321
+ { label: 'Public', value: 'public' },
322
+ { label: 'Confidential Symmetric', value: 'symmetric' },
323
+ { label: 'Confidential Asymmetric', value: 'asymmetric' },
324
+ { label: 'Backend Services', value: 'backend_services' }
325
+ ]
326
+ }
327
+ }
328
+ end
329
+
330
+ # Returns the default configuration for the "auth_type" component without
331
+ # the option for backend services auth
332
+ # @return [Hash]
333
+ def self.default_auth_type_component_without_backend_services
334
+ {
335
+ name: :auth_type,
336
+ options: {
337
+ list_options: [
338
+ { label: 'Public', value: 'public' },
339
+ { label: 'Confidential Symmetric', value: 'symmetric' },
340
+ { label: 'Confidential Asymmetric', value: 'asymmetric' }
341
+ ]
342
+ }
343
+ }
344
+ end
345
+
346
+ # Returns true when using public auth
347
+ # @return [Boolean]
348
+ def public_auth?
349
+ auth_type&.casecmp? 'public'
350
+ end
351
+
352
+ # Returns true when using confidential symmetric auth
353
+ # @return [Boolean]
354
+ def symmetric_auth?
355
+ auth_type&.casecmp? 'symmetric'
356
+ end
357
+
358
+ # Returns true when using confidential asymmetric auth
359
+ # @return [Boolean]
360
+ def asymmetric_auth?
361
+ auth_type&.casecmp? 'asymmetric'
362
+ end
363
+
364
+ # Returns true when using backend services auth
365
+ # @return [Boolean]
366
+ def backend_services_auth?
367
+ auth_type&.casecmp? 'backend_services'
368
+ end
369
+
370
+ # Returns true when using GET as the authorization request method
371
+ # @return [Boolean]
372
+ def get_auth_request?
373
+ auth_request_method&.casecmp? 'get'
374
+ end
375
+
376
+ # Returns true when using POST as the authorization request method
377
+ # @return [Boolean]
378
+ def post_auth_request?
379
+ auth_request_method&.casecmp? 'post'
380
+ end
381
+
382
+ # Returns true when pkce is enabled
383
+ # @return [Boolean]
384
+ def pkce_enabled?
385
+ pkce_support&.casecmp? 'enabled'
386
+ end
387
+
388
+ # Returns true when using the S256 pkce code challenge method
389
+ # @return [Boolean]
390
+ def s256_code_challenge_method?
391
+ pkce_code_challenge_method&.casecmp? 'S256'
392
+ end
393
+
394
+ # Returns true when using the palin pkce code challenge method
395
+ # @return [Boolean]
396
+ def plain_code_challenge_method?
397
+ pkce_code_challenge_method&.casecmp? 'plain'
398
+ end
313
399
  end
314
400
  end
315
401
  end
@@ -138,6 +138,19 @@ module Inferno
138
138
  configuration[:inputs] ||= {}
139
139
  end
140
140
 
141
+ # @private
142
+ # Recursively duplicate arrays/hashes to prevent them from being shared
143
+ # across different runnables
144
+ def deep_dup(value)
145
+ if value.is_a? Array
146
+ value.map { |element| deep_dup(element) }
147
+ elsif value.is_a? Hash
148
+ value.transform_values { |element| deep_dup(element) }
149
+ else
150
+ value.dup
151
+ end
152
+ end
153
+
141
154
  # @private
142
155
  def add_input(identifier, new_config = {})
143
156
  existing_config = input(identifier)
@@ -148,7 +161,7 @@ module Inferno
148
161
 
149
162
  inputs[identifier] =
150
163
  Entities::Input
151
- .new(**existing_config.to_hash)
164
+ .new(**deep_dup(existing_config.to_hash))
152
165
  .merge(Entities::Input.new(**new_config))
153
166
  end
154
167
 
@@ -194,6 +194,7 @@ module Inferno
194
194
  end
195
195
 
196
196
  available_inputs = children_available_inputs(selected_suite_options).merge(available_inputs)
197
+
197
198
  order_available_inputs(available_inputs)
198
199
  end
199
200
  end
@@ -47,11 +47,23 @@ module Inferno
47
47
  :@children_available_inputs # Needs to be recalculated
48
48
  ].freeze
49
49
 
50
+ # Recursively duplicate arrays/hashes to prevent them from being shared
51
+ # across different runnables
52
+ def deep_dup(value)
53
+ if value.is_a? Array
54
+ value.map { |element| deep_dup(element) }
55
+ elsif value.is_a? Hash
56
+ value.transform_values { |element| deep_dup(element) }
57
+ else
58
+ value.dup
59
+ end
60
+ end
61
+
50
62
  # @private
51
63
  def copy_instance_variables(subclass)
52
64
  instance_variables
53
65
  .reject { |variable| VARIABLES_NOT_TO_COPY.include? variable }
54
- .each { |variable| subclass.instance_variable_set(variable, instance_variable_get(variable).dup) }
66
+ .each { |variable| subclass.instance_variable_set(variable, deep_dup(instance_variable_get(variable))) }
55
67
 
56
68
  subclass.config(config)
57
69
 
data/lib/inferno/dsl.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require_relative 'dsl/assertions'
2
+ require_relative 'dsl/auth_info'
2
3
  require_relative 'dsl/fhir_client'
3
4
  require_relative 'dsl/fhir_validation'
4
5
  require_relative 'dsl/fhir_evaluation/evaluator'
@@ -43,7 +43,7 @@ module Inferno
43
43
 
44
44
  # These are the attributes that can be directly copied when merging a
45
45
  # runnable's input with an input configuration.
46
- MERGEABLE_ATTRIBUTES = (ATTRIBUTES - [:type]).freeze
46
+ MERGEABLE_ATTRIBUTES = (ATTRIBUTES - [:type, :options]).freeze
47
47
 
48
48
  def initialize(**params)
49
49
  bad_params = params.keys - ATTRIBUTES
@@ -69,21 +69,27 @@ module Inferno
69
69
 
70
70
  self.type = child_input.type if child_input.present? && child_input.type != 'text'
71
71
 
72
+ merge_options(primary_source: self, secondary_source: child_input)
73
+
72
74
  self
73
75
  end
74
76
 
75
77
  # @private
76
78
  # Merge this input with an input from a configuration. Fields defined in
77
79
  # the configuration take precedence over those defined on this input.
78
- def merge(other_input)
80
+ def merge(other_input, merge_all: false)
79
81
  return self if other_input.nil?
80
82
 
81
- MERGEABLE_ATTRIBUTES.each do |attribute|
83
+ attributes_to_merge = merge_all ? ATTRIBUTES : MERGEABLE_ATTRIBUTES
84
+
85
+ attributes_to_merge.each do |attribute|
82
86
  merge_attribute(attribute, primary_source: other_input, secondary_source: self)
83
87
  end
84
88
 
85
89
  self.type = other_input.type if other_input.type.present? && other_input.type != 'text'
86
90
 
91
+ merge_options(primary_source: other_input, secondary_source: self)
92
+
87
93
  self
88
94
  end
89
95
 
@@ -103,6 +109,60 @@ module Inferno
103
109
  send("#{attribute}=", value)
104
110
  end
105
111
 
112
+ # @private
113
+ # Merge input options. This performs a normal merge for all options except
114
+ # for the "components" field, the members of which are individually merged
115
+ # by `merge_components`
116
+ # @param primary_source [Input]
117
+ # @param secondary_source [Input]
118
+ def merge_options(primary_source:, secondary_source:)
119
+ primary_options = primary_source.options.dup || {}
120
+ secondary_options = secondary_source.options.dup || {}
121
+
122
+ return if primary_options.blank? && secondary_options.blank?
123
+
124
+ primary_components = primary_options.delete(:components) || []
125
+ secondary_components = secondary_options.delete(:components) || []
126
+
127
+ send('options=', secondary_options.merge(primary_options))
128
+
129
+ merge_components(primary_components:, secondary_components:)
130
+ end
131
+
132
+ # @private
133
+ # Merge component hashes.
134
+ # @param primary_source [Input]
135
+ # @param secondary_source [Input]
136
+ def merge_components(primary_components:, secondary_components:) # rubocop:disable Metrics/CyclomaticComplexity
137
+ primary_components
138
+ .each { |component| component[:name] = component[:name].to_sym }
139
+ secondary_components
140
+ .each { |component| component[:name] = component[:name].to_sym }
141
+
142
+ return if primary_components.blank? && secondary_components.blank?
143
+
144
+ component_keys =
145
+ (primary_components + secondary_components)
146
+ .map { |component| component[:name] }
147
+ .uniq
148
+
149
+ merged_components = component_keys.map do |key|
150
+ primary_component = primary_components.find { |component| component[:name] == key }
151
+ secondary_component = secondary_components.find { |component| component[:name] == key }
152
+
153
+ next secondary_component if primary_component.blank?
154
+
155
+ next primary_component if secondary_component.blank?
156
+
157
+ Input.new(**secondary_component).merge(Input.new(**primary_component), merge_all: true).to_hash
158
+ end
159
+
160
+ merged_components.each { |component| component[:name] = component[:name].to_sym }
161
+
162
+ self.options ||= {}
163
+ self.options[:components] = merged_components
164
+ end
165
+
106
166
  def to_hash
107
167
  ATTRIBUTES.each_with_object({}) do |attribute, hash|
108
168
  value = send(attribute)
@@ -112,6 +112,8 @@ module Inferno
112
112
  auth =
113
113
  if params[:value].is_a? String
114
114
  DSL::AuthInfo.new(JSON.parse(params[:value]))
115
+ elsif params[:value].is_a? Hash
116
+ DSL::AuthInfo.new(params[:value])
115
117
  elsif !params[:value].is_a? DSL::AuthInfo
116
118
  raise Exceptions::BadSessionDataType.new(
117
119
  params[:name],
@@ -1,4 +1,4 @@
1
1
  module Inferno
2
2
  # Standard patterns for gem versions: https://guides.rubygems.org/patterns/
3
- VERSION = '0.6.2'.freeze
3
+ VERSION = '0.6.3'.freeze
4
4
  end
@@ -5,24 +5,27 @@ RSpec.shared_context('when testing a runnable') do
5
5
  let(:test_session) { repo_create(:test_session, test_suite_id: suite_id) }
6
6
 
7
7
  before do
8
- allow(described_class).to receive(:suite).and_return(suite) if described_class.parent.nil?
8
+ if described_class.respond_to?(:parent) && described_class.parent.nil?
9
+ allow(described_class).to receive(:suite).and_return(suite)
10
+ end
9
11
  rescue NameError
10
12
  raise StandardError, "No suite id defined. Add `let(:suite_id) { 'your_suite_id' }` to the spec"
11
13
  end
12
14
 
13
- def run(runnable, inputs = {})
15
+ def run(runnable, inputs = {}, scratch = {})
14
16
  test_run_params = { test_session_id: test_session.id }.merge(runnable.reference_hash)
15
17
  test_run = Inferno::Repositories::TestRuns.new.create(test_run_params)
16
- inputs.each do |name, value|
18
+ inputs.each do |original_name, value|
19
+ name = runnable.config.input_name(original_name).presence || original_name
17
20
  session_data_repo.save(
18
21
  test_session_id: test_session.id,
19
22
  name:,
20
23
  value:,
21
- type: runnable.config.input_type(name)
24
+ type: runnable.available_inputs[name.to_sym]&.type
22
25
  )
23
26
  end
24
27
 
25
- Inferno::TestRunner.new(test_session:, test_run:).run(runnable)
28
+ Inferno::TestRunner.new(test_session:, test_run:).run(runnable, scratch)
26
29
  end
27
30
 
28
31
  # depth-first search looking for a runnable with a runtime id
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.6.2
4
+ version: 0.6.3
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: 2025-02-06 00:00:00.000000000 Z
13
+ date: 2025-02-13 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
@@ -444,6 +444,10 @@ files:
444
444
  - lib/inferno/apps/cli/templates/data/redis/.keep
445
445
  - lib/inferno/apps/cli/templates/docker-compose.background.yml.tt
446
446
  - lib/inferno/apps/cli/templates/docker-compose.yml.tt
447
+ - lib/inferno/apps/cli/templates/docs/Overview.md
448
+ - lib/inferno/apps/cli/templates/docs/README.md.tt
449
+ - lib/inferno/apps/cli/templates/docs/_Footer.md
450
+ - lib/inferno/apps/cli/templates/docs/_Sidebar.md
447
451
  - lib/inferno/apps/cli/templates/lib/%library_name%.rb.tt
448
452
  - lib/inferno/apps/cli/templates/lib/%library_name%/igs/.keep
449
453
  - lib/inferno/apps/cli/templates/lib/%library_name%/igs/README.md