inferno_core 0.4.29 → 0.4.31

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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/lib/inferno/apps/cli/new.rb +42 -18
  3. data/lib/inferno/apps/cli/templates/%library_name%.gemspec.tt +26 -0
  4. data/lib/inferno/apps/cli/templates/Dockerfile.tt +22 -0
  5. data/lib/inferno/apps/cli/templates/Gemfile.tt +9 -0
  6. data/lib/inferno/apps/cli/templates/LICENSE.tt +201 -0
  7. data/lib/inferno/apps/cli/templates/Procfile.tt +2 -0
  8. data/lib/inferno/apps/cli/templates/README.md.tt +41 -0
  9. data/lib/inferno/apps/cli/templates/Rakefile.tt +15 -0
  10. data/lib/inferno/apps/cli/templates/config/database.yml.tt +18 -0
  11. data/lib/inferno/apps/cli/templates/config/nginx.background.conf.tt +86 -0
  12. data/lib/inferno/apps/cli/templates/config/nginx.conf.tt +101 -0
  13. data/lib/inferno/apps/cli/templates/config/puma.rb.tt +2 -0
  14. data/lib/inferno/apps/cli/templates/config.ru.tt +11 -0
  15. data/lib/inferno/apps/cli/templates/docker-compose.background.yml.tt +30 -0
  16. data/lib/inferno/apps/cli/templates/docker-compose.yml.tt +35 -0
  17. data/lib/inferno/apps/cli/templates/lib/%library_name%/igs/put_ig_package_dot_tgz_here +0 -0
  18. data/lib/inferno/apps/cli/templates/lib/%library_name%/patient_group.rb.tt +44 -0
  19. data/lib/inferno/apps/cli/templates/lib/%library_name%.rb.tt +53 -0
  20. data/lib/inferno/apps/cli/templates/run.sh +3 -0
  21. data/lib/inferno/apps/cli/templates/setup.sh +4 -0
  22. data/lib/inferno/apps/cli/templates/spec/%library_name%/patient_group_spec.rb.tt +105 -0
  23. data/lib/inferno/apps/cli/templates/spec/spec_helper.rb.tt +141 -0
  24. data/lib/inferno/apps/cli/templates/worker.rb.tt +3 -0
  25. data/lib/inferno/db/migrations/010_add_validator_sessions.rb +14 -0
  26. data/lib/inferno/db/schema.rb +14 -0
  27. data/lib/inferno/dsl/fhir_client_builder.rb +1 -1
  28. data/lib/inferno/dsl/fhir_resource_validation.rb +21 -7
  29. data/lib/inferno/dsl/http_client_builder.rb +1 -1
  30. data/lib/inferno/entities/validator_session.rb +22 -0
  31. data/lib/inferno/entities.rb +1 -0
  32. data/lib/inferno/jobs/invoke_validator_session.rb +3 -3
  33. data/lib/inferno/public/175.bundle.js +1 -0
  34. data/lib/inferno/public/assets.json +1 -1
  35. data/lib/inferno/public/bundle.js +21 -21
  36. data/lib/inferno/public/bundle.js.LICENSE.txt +17 -5
  37. data/lib/inferno/repositories/validator_sessions.rb +58 -0
  38. data/lib/inferno/repositories.rb +1 -0
  39. data/lib/inferno/utils/ig_downloader.rb +57 -0
  40. data/lib/inferno/version.rb +1 -1
  41. metadata +29 -2
@@ -0,0 +1,30 @@
1
+ version: '3'
2
+ services:
3
+ validator_service:
4
+ image: infernocommunity/fhir-validator-service
5
+ # Update this path to match your directory structure
6
+ volumes:
7
+ - ./<%= ig_path %>:/home/igs
8
+ fhir_validator_app:
9
+ image: infernocommunity/fhir-validator-app
10
+ depends_on:
11
+ - validator_service
12
+ environment:
13
+ EXTERNAL_VALIDATOR_URL: http://localhost/validatorapi
14
+ VALIDATOR_BASE_PATH: /validator
15
+ nginx:
16
+ image: nginx
17
+ volumes:
18
+ - ./config/nginx.background.conf:/etc/nginx/nginx.conf
19
+ ports:
20
+ - "80:80"
21
+ command: [nginx, '-g', 'daemon off;']
22
+ depends_on:
23
+ - fhir_validator_app
24
+ redis:
25
+ image: redis
26
+ ports:
27
+ - "6379:6379"
28
+ volumes:
29
+ - ./data/redis:/data
30
+ command: redis-server --appendonly yes
@@ -0,0 +1,35 @@
1
+ version: '3'
2
+ services:
3
+ inferno:
4
+ build:
5
+ context: ./
6
+ volumes:
7
+ - ./data:/opt/inferno/data
8
+ depends_on:
9
+ - validator_service
10
+ worker:
11
+ build:
12
+ context: ./
13
+ volumes:
14
+ - ./data:/opt/inferno/data
15
+ command: bundle exec sidekiq -r ./worker.rb
16
+ depends_on:
17
+ - redis
18
+ validator_service:
19
+ extends:
20
+ file: docker-compose.background.yml
21
+ service: validator_service
22
+ fhir_validator_app:
23
+ extends:
24
+ file: docker-compose.background.yml
25
+ service: fhir_validator_app
26
+ nginx:
27
+ extends:
28
+ file: docker-compose.background.yml
29
+ service: nginx
30
+ volumes:
31
+ - ./config/nginx.conf:/etc/nginx/nginx.conf
32
+ redis:
33
+ extends:
34
+ file: docker-compose.background.yml
35
+ service: redis
@@ -0,0 +1,44 @@
1
+ module <%= module_name %>
2
+ class PatientGroup < Inferno::TestGroup
3
+ title 'Patient Tests'
4
+ description 'Verify that the server makes Patient resources available'
5
+ id :patient_group
6
+
7
+ test do
8
+ title 'Server returns requested Patient resource from the Patient read interaction'
9
+ description %(
10
+ Verify that Patient resources can be read from the server.
11
+ )
12
+
13
+ input :patient_id,
14
+ title: 'Patient ID'
15
+
16
+ # Named requests can be used by other tests
17
+ makes_request :patient
18
+
19
+ run do
20
+ fhir_read(:patient, patient_id, name: :patient)
21
+
22
+ assert_response_status(200)
23
+ assert_resource_type(:patient)
24
+ assert resource.id == patient_id,
25
+ "Requested resource with id #{patient_id}, received resource with id #{resource.id}"
26
+ end
27
+ end
28
+
29
+ test do
30
+ title 'Patient resource is valid'
31
+ description %(
32
+ Verify that the Patient resource returned from the server is a valid FHIR resource.
33
+ )
34
+ # This test will use the response from the :patient request in the
35
+ # previous test
36
+ uses_request :patient
37
+
38
+ run do
39
+ assert_resource_type(:patient)
40
+ assert_valid_resource
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,53 @@
1
+ require_relative '<%= library_name %>/patient_group'
2
+
3
+ module <%= module_name %>
4
+ class Suite < Inferno::TestSuite
5
+ id :<%= test_suite_id %>
6
+ title '<%= title_name %> Test Suite'
7
+ description 'Inferno <%= human_name.downcase %> test suite for FHIR'
8
+
9
+ # These inputs will be available to all tests in this suite
10
+ input :url,
11
+ title: 'FHIR Server Base Url'
12
+
13
+ input :credentials,
14
+ title: 'OAuth Credentials',
15
+ type: :oauth_credentials,
16
+ optional: true
17
+
18
+ # All FHIR requests in this suite will use this FHIR client
19
+ fhir_client do
20
+ url :url
21
+ oauth_credentials :credentials
22
+ end
23
+
24
+ # All FHIR validation requsets will use this FHIR validator
25
+ validator do
26
+ url ENV.fetch('VALIDATOR_URL')
27
+ end
28
+
29
+ # Tests and TestGroups can be defined inline
30
+ group do
31
+ id :capability_statement
32
+ title 'Capability Statement'
33
+ description 'Verify that the server has a CapabilityStatement'
34
+
35
+ test do
36
+ id :capability_statement_read
37
+ title 'Read CapabilityStatement'
38
+ description 'Read CapabilityStatement from /metadata endpoint'
39
+
40
+ run do
41
+ fhir_get_capability_statement
42
+
43
+ assert_response_status(200)
44
+ assert_resource_type(:capability_statement)
45
+ end
46
+ end
47
+ end
48
+
49
+ # Tests and TestGroups can be written in separate files and then included
50
+ # using their id
51
+ group from: :patient_group
52
+ end
53
+ end
@@ -0,0 +1,3 @@
1
+ #!/bin/sh
2
+ docker compose build
3
+ docker compose up
@@ -0,0 +1,4 @@
1
+ #!/bin/sh
2
+ docker compose pull
3
+ docker compose build
4
+ docker compose run inferno bundle exec inferno migrate
@@ -0,0 +1,105 @@
1
+ RSpec.describe <%= module_name %>::PatientGroup do
2
+ let(:suite) { Inferno::Repositories::TestSuites.new.find('<%= test_suite_id %>') }
3
+ let(:group) { suite.groups[1] }
4
+ let(:session_data_repo) { Inferno::Repositories::SessionData.new }
5
+ let(:test_session) { repo_create(:test_session, test_suite_id: '<%= test_suite_id %>') }
6
+ let(:url) { 'http://example.com/fhir' }
7
+ let(:error_outcome) { FHIR::OperationOutcome.new(issue: [{ severity: 'error' }]) }
8
+
9
+ def run(runnable, inputs = {})
10
+ test_run_params = { test_session_id: test_session.id }.merge(runnable.reference_hash)
11
+ test_run = Inferno::Repositories::TestRuns.new.create(test_run_params)
12
+ inputs.each do |name, value|
13
+ session_data_repo.save(test_session_id: test_session.id, name: name, value: value, type: 'text')
14
+ end
15
+ Inferno::TestRunner.new(test_session: test_session, test_run: test_run).run(runnable)
16
+ end
17
+
18
+ describe 'read test' do
19
+ let(:test) { group.tests.first }
20
+ let(:patient_id) { 'abc123' }
21
+
22
+ it 'passes if a Patient was received' do
23
+ resource = FHIR::Patient.new(id: patient_id)
24
+ stub_request(:get, "#{url}/Patient/#{patient_id}")
25
+ .to_return(status: 200, body: resource.to_json)
26
+
27
+ result = run(test, url: url, patient_id: patient_id)
28
+
29
+ expect(result.result).to eq('pass')
30
+ end
31
+
32
+ it 'fails if a 200 is not received' do
33
+ resource = FHIR::Patient.new(id: patient_id)
34
+ stub_request(:get, "#{url}/Patient/#{patient_id}")
35
+ .to_return(status: 201, body: resource.to_json)
36
+
37
+ result = run(test, url: url, patient_id: patient_id)
38
+
39
+ expect(result.result).to eq('fail')
40
+ expect(result.result_message).to match(/200/)
41
+ end
42
+
43
+ it 'fails if a Patient is not received' do
44
+ resource = FHIR::Condition.new(id: patient_id)
45
+ stub_request(:get, "#{url}/Patient/#{patient_id}")
46
+ .to_return(status: 200, body: resource.to_json)
47
+
48
+ result = run(test, url: url, patient_id: patient_id)
49
+
50
+ expect(result.result).to eq('fail')
51
+ expect(result.result_message).to match(/Patient/)
52
+ end
53
+
54
+ it 'fails if the id received does not match the one requested' do
55
+ resource = FHIR::Patient.new(id: '456')
56
+ stub_request(:get, "#{url}/Patient/#{patient_id}")
57
+ .to_return(status: 200, body: resource.to_json)
58
+
59
+ result = run(test, url: url, patient_id: patient_id)
60
+
61
+ expect(result.result).to eq('fail')
62
+ expect(result.result_message).to match(/resource with id/)
63
+ end
64
+ end
65
+
66
+ describe 'validation test' do
67
+ let(:test) { group.tests.last }
68
+
69
+ it 'passes if the resource is valid' do
70
+ stub_request(:post, "#{ENV.fetch('VALIDATOR_URL')}/validate")
71
+ .with(query: hash_including({}))
72
+ .to_return(status: 200, body: FHIR::OperationOutcome.new.to_json)
73
+
74
+ resource = FHIR::Patient.new
75
+ repo_create(
76
+ :request,
77
+ name: :patient,
78
+ test_session_id: test_session.id,
79
+ response_body: resource.to_json
80
+ )
81
+
82
+ result = run(test)
83
+
84
+ expect(result.result).to eq('pass')
85
+ end
86
+
87
+ it 'fails if the resource is not valid' do
88
+ stub_request(:post, "#{ENV.fetch('VALIDATOR_URL')}/validate")
89
+ .with(query: hash_including({}))
90
+ .to_return(status: 200, body: error_outcome.to_json)
91
+
92
+ resource = FHIR::Patient.new
93
+ repo_create(
94
+ :request,
95
+ name: :patient,
96
+ test_session_id: test_session.id,
97
+ response_body: resource.to_json
98
+ )
99
+
100
+ result = run(test)
101
+
102
+ expect(result.result).to eq('fail')
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,141 @@
1
+ # Hide deprecation warnings
2
+ $VERBOSE = nil
3
+
4
+ ENV['APP_ENV'] ||= 'test'
5
+
6
+ require 'database_cleaner/sequel'
7
+ require 'pry'
8
+ require 'pry-byebug'
9
+
10
+ require 'webmock/rspec'
11
+ WebMock.disable_net_connect!
12
+
13
+ require 'factory_bot'
14
+
15
+ # This file was generated by the `rspec --init` command. Conventionally, all
16
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
17
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
18
+ # this file to always be loaded, without a need to explicitly require it in any
19
+ # files.
20
+ #
21
+ # Given that it is always loaded, you are encouraged to keep this file as
22
+ # light-weight as possible. Requiring heavyweight dependencies from this file
23
+ # will add to the boot time of your test suite on EVERY test run, even for an
24
+ # individual file that may not need all of that loaded. Instead, consider making
25
+ # a separate helper file that requires the additional dependencies and performs
26
+ # the additional setup, and require it from the spec files that actually need
27
+ # it.
28
+ #
29
+ # The `.rspec` file also contains a few flags that are not defaults but that
30
+ # users commonly want.
31
+ #
32
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
33
+ RSpec.configure do |config|
34
+ # rspec-expectations config goes here. You can use an alternate
35
+ # assertion/expectation library such as wrong or the stdlib/minitest
36
+ # assertions if you prefer.
37
+ config.expect_with :rspec do |expectations|
38
+ # This option will default to `true` in RSpec 4. It makes the `description`
39
+ # and `failure_message` of custom matchers include text for helper methods
40
+ # defined using `chain`, e.g.:
41
+ # be_bigger_than(2).and_smaller_than(4).description
42
+ # # => "be bigger than 2 and smaller than 4"
43
+ # ...rather than:
44
+ # # => "be bigger than 2"
45
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
46
+ end
47
+
48
+ # rspec-mocks config goes here. You can use an alternate test double
49
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
50
+ config.mock_with :rspec do |mocks|
51
+ # Prevents you from mocking or stubbing a method that does not exist on
52
+ # a real object. This is generally recommended, and will default to
53
+ # `true` in RSpec 4.
54
+ mocks.verify_partial_doubles = true
55
+ end
56
+
57
+ # Allows RSpec to persist some state between runs in order to support
58
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
59
+ # you configure your source control system to ignore this file.
60
+ config.example_status_persistence_file_path = 'spec/examples.txt'
61
+
62
+ # Limits the available syntax to the non-monkey patched syntax that is
63
+ # recommended. For more details, see:
64
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
65
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
66
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
67
+ config.disable_monkey_patching!
68
+
69
+ # Many RSpec users commonly either run the entire suite or an individual
70
+ # file, and it's useful to allow more verbose output when running an
71
+ # individual spec file.
72
+ if config.files_to_run.one?
73
+ # Use the documentation formatter for detailed output,
74
+ # unless a formatter has already been configured
75
+ # (e.g. via a command-line flag).
76
+ config.default_formatter = 'doc'
77
+ end
78
+
79
+ # Run specs in random order to surface order dependencies. If you find an
80
+ # order dependency and want to debug it, you can fix the order by providing
81
+ # the seed, which is printed after each run.
82
+ # --seed 1234
83
+ config.order = :random
84
+
85
+ # Seed global randomization in this process using the `--seed` CLI option.
86
+ # Setting this allows you to use `--seed` to deterministically reproduce
87
+ # test failures related to randomization by passing the same `--seed` value
88
+ # as the one that triggered the failure.
89
+ Kernel.srand config.seed
90
+
91
+ # These two settings work together to allow you to limit a spec run
92
+ # to individual examples or groups you care about by tagging them with
93
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
94
+ # get run.
95
+ config.filter_run :focus
96
+ config.run_all_when_everything_filtered = true
97
+
98
+ # This setting enables warnings. It's recommended, but in many cases may
99
+ # be too noisy due to issues in dependencies.
100
+ # config.warnings = false
101
+
102
+ # Print the 10 slowest examples and example groups at the
103
+ # end of the spec run, to help surface which specs are running
104
+ # particularly slow.
105
+ # config.profile_examples = 10
106
+
107
+ config.before(:suite) do
108
+ DatabaseCleaner.strategy = :transaction
109
+ DatabaseCleaner.clean_with(:truncation)
110
+ end
111
+
112
+ config.around do |example|
113
+ DatabaseCleaner.cleaning { example.run }
114
+ end
115
+
116
+ config.include FactoryBot::Syntax::Methods
117
+
118
+ config.before(:suite) do
119
+ FactoryBot.find_definitions
120
+ end
121
+ end
122
+
123
+ require 'inferno/config/application'
124
+ require 'inferno/utils/migration'
125
+ Inferno::Utils::Migration.new.run
126
+
127
+ require 'inferno'
128
+ Inferno::Application.finalize!
129
+
130
+ require Inferno::SpecSupport::FACTORY_BOT_SUPPORT_PATH
131
+
132
+ FactoryBot.definition_file_paths = [
133
+ Inferno::SpecSupport::FACTORY_PATH
134
+ ]
135
+
136
+ RSpec::Matchers.define_negated_matcher :exclude, :include
137
+
138
+ FHIR.logger = Inferno::Application['logger']
139
+
140
+ DatabaseCleaner[:sequel].strategy = :truncation
141
+ DatabaseCleaner[:sequel].db = Inferno::Application['db.connection']
@@ -0,0 +1,3 @@
1
+ require 'inferno'
2
+
3
+ Inferno::Application.finalize!
@@ -0,0 +1,14 @@
1
+ Sequel.migration do
2
+ change do
3
+ create_table :validator_sessions do
4
+ column :id, String, primary_key: true, null: false, size: 36
5
+ column :validator_session_id, String, null: false, size: 255
6
+ column :test_suite_id, String, null: false, size: 255
7
+ column :validator_name, String, null: false, size: 255
8
+ column :suite_options, String, text: true
9
+ column :last_accessed, DateTime, null: false
10
+ index [:validator_session_id], unique: true
11
+ index [:test_suite_id, :validator_name, :suite_options], unique: true
12
+ end
13
+ end
14
+ end
@@ -23,6 +23,20 @@ Sequel.migration do
23
23
  primary_key [:id]
24
24
  end
25
25
 
26
+ create_table(:validator_sessions, :ignore_index_errors=>true) do
27
+ String :id, :size=>36, :null=>false
28
+ String :validator_session_id, :size=>255, :null=>false
29
+ String :test_suite_id, :size=>255, :null=>false
30
+ String :validator_name, :size=>255, :null=>false
31
+ String :suite_options, :text=>true
32
+ DateTime :last_accessed, :null=>false
33
+
34
+ primary_key [:id]
35
+
36
+ index [:test_suite_id, :validator_name, :suite_options], :unique=>true
37
+ index [:validator_session_id], :unique=>true
38
+ end
39
+
26
40
  create_table(:session_data, :ignore_index_errors=>true) do
27
41
  String :id, :size=>255, :null=>false
28
42
  foreign_key :test_session_id, :test_sessions, :type=>String, :size=>36, :null=>false, :key=>[:id]
@@ -90,7 +90,7 @@ module Inferno
90
90
 
91
91
  # @private
92
92
  def method_missing(name, *args, &)
93
- return runnable.call(name, *args, &) if runnable.respond_to? name
93
+ return runnable.send(name, *args, &) if runnable.respond_to? name
94
94
 
95
95
  super
96
96
  end
@@ -27,10 +27,12 @@ module Inferno
27
27
 
28
28
  class Validator
29
29
  attr_reader :requirements
30
- attr_accessor :session_id
30
+ attr_accessor :session_id, :name, :test_suite_id
31
31
 
32
32
  # @private
33
- def initialize(requirements = nil, &)
33
+ def initialize(name = nil, test_suite_id = nil, requirements = nil, &)
34
+ @name = name
35
+ @test_suite_id = test_suite_id
34
36
  instance_eval(&)
35
37
  @requirements = requirements
36
38
  end
@@ -40,6 +42,10 @@ module Inferno
40
42
  ENV.fetch('FHIR_RESOURCE_VALIDATOR_URL')
41
43
  end
42
44
 
45
+ def validator_session_repo
46
+ @validator_session_repo ||= Inferno::Repositories::ValidatorSessions.new
47
+ end
48
+
43
49
  # Set the url of the validator service
44
50
  #
45
51
  # @param validator_url [String]
@@ -231,6 +237,10 @@ module Inferno
231
237
 
232
238
  # @private
233
239
  def wrap_resource_for_hl7_wrapper(resource, profile_url)
240
+ validator_session_id =
241
+ validator_session_repo.find_validator_session_id(test_suite_id,
242
+ name.to_s, requirements)
243
+ @session_id = validator_session_id if validator_session_id
234
244
  wrapped_resource = {
235
245
  cliContext: {
236
246
  **cli_context.definition,
@@ -269,8 +279,11 @@ module Inferno
269
279
  # @private
270
280
  def operation_outcome_from_hl7_wrapped_response(response)
271
281
  res = JSON.parse(response)
272
-
273
- @session_id = res['sessionId']
282
+ if res['sessionId'] != @session_id
283
+ validator_session_repo.save(test_suite_id:, validator_session_id: res['sessionId'],
284
+ validator_name: name.to_s, suite_options: requirements)
285
+ @session_id = res['sessionId']
286
+ end
274
287
 
275
288
  # assume for now that one resource -> one request
276
289
  issues = res['outcomes'][0]['issues']&.map do |i|
@@ -287,7 +300,7 @@ module Inferno
287
300
  else
288
301
  runnable.add_message('error', "Validator Response: HTTP #{response.status}\n#{response.body}")
289
302
  raise Inferno::Exceptions::ErrorInValidatorException,
290
- 'Validator response was an unexpected format. '\
303
+ 'Validator response was an unexpected format. ' \
291
304
  'Review Messages tab or validator service logs for more information.'
292
305
  end
293
306
  end
@@ -300,7 +313,8 @@ module Inferno
300
313
  CLICONTEXT_DEFAULTS = {
301
314
  sv: '4.0.1',
302
315
  doNative: false,
303
- extensions: ['any']
316
+ extensions: ['any'],
317
+ disableDefaultResourceFetcher: true
304
318
  }.freeze
305
319
 
306
320
  # @private
@@ -353,7 +367,7 @@ module Inferno
353
367
  def fhir_resource_validator(name = :default, required_suite_options: nil, &block)
354
368
  current_validators = fhir_validators[name] || []
355
369
 
356
- new_validator = Inferno::DSL::FHIRResourceValidation::Validator.new(required_suite_options, &block)
370
+ new_validator = Inferno::DSL::FHIRResourceValidation::Validator.new(name, id, required_suite_options, &block)
357
371
 
358
372
  current_validators.reject! { |validator| validator.requirements == required_suite_options }
359
373
  current_validators << new_validator
@@ -45,7 +45,7 @@ module Inferno
45
45
 
46
46
  # @private
47
47
  def method_missing(name, *args, &)
48
- return runnable.call(name, *args, &) if runnable.respond_to? name
48
+ return runnable.send(name, *args, &) if runnable.respond_to? name
49
49
 
50
50
  super
51
51
  end
@@ -0,0 +1,22 @@
1
+ module Inferno
2
+ module Entities
3
+ class ValidatorSession < Entity
4
+ ATTRIBUTES = [
5
+ :id,
6
+ :created_at,
7
+ :updated_at,
8
+ :validator_session_id,
9
+ :test_suite_id,
10
+ :validator_name,
11
+ :suite_options,
12
+ :validator_index
13
+ ].freeze
14
+
15
+ include Inferno::Entities::Attributes
16
+
17
+ def initialize(params)
18
+ super(params, ATTRIBUTES)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -11,6 +11,7 @@ require_relative 'entities/test_group'
11
11
  require_relative 'entities/test_run'
12
12
  require_relative 'entities/test_session'
13
13
  require_relative 'entities/test_suite'
14
+ require_relative 'entities/validator_session'
14
15
 
15
16
  module Inferno
16
17
  # Entities are domain objects whose identity is based on an `id`. Entities
@@ -6,13 +6,13 @@ module Inferno
6
6
  def perform(suite_id, validator_name, validator_index)
7
7
  suite = Inferno::Repositories::TestSuites.new.find suite_id
8
8
  validator = suite.fhir_validators[validator_name.to_sym][validator_index]
9
-
10
9
  response_body = validator.validate(FHIR::Patient.new, 'http://hl7.org/fhir/StructureDefinition/Patient')
11
-
12
10
  if response_body.start_with? '{'
13
11
  res = JSON.parse(response_body)
14
12
  session_id = res['sessionId']
15
- # TODO: (FI-2311) store this session ID so it can be referenced as needed
13
+ session_repo = Inferno::Repositories::ValidatorSessions.new
14
+ session_repo.save(test_suite_id: suite_id, validator_session_id: session_id,
15
+ validator_name:, suite_options: validator.requirements)
16
16
  validator.session_id = session_id
17
17
  else
18
18
  Inferno::Application['logger'].error("InvokeValidatorSession - error from validator: #{response_body}")
@@ -0,0 +1 @@
1
+ "use strict";(self.webpackChunkinferno_web_app=self.webpackChunkinferno_web_app||[]).push([[175],{9175:(t,e,n)=>{n.r(e),n.d(e,{getCLS:()=>d,getFCP:()=>m,getFID:()=>v,getLCP:()=>h,getTTFB:()=>S});var i,a,r=function(t){return{name:t,value:arguments.length>1&&void 0!==arguments[1]?arguments[1]:-1,delta:0,entries:[],id:"".concat(Date.now(),"-").concat(Math.floor(8999999999999*Math.random())+1e12),isFinal:!1}},o=function(t,e){try{if(PerformanceObserver.supportedEntryTypes.includes(t)){var n=new PerformanceObserver((function(t){return t.getEntries().map(e)}));return n.observe({type:t,buffered:!0}),n}}catch(t){}},s=!1,u=!1,c=function(t){s=!t.persisted},p=function(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1];u||(addEventListener("pagehide",c),addEventListener("beforeunload",(function(){})),u=!0),addEventListener("visibilitychange",(function(e){var n=e.timeStamp;"hidden"===document.visibilityState&&t({timeStamp:n,isUnloading:s})}),{capture:!0,once:e})},l=function(t,e,n,i){var a;return function(){n&&e.isFinal&&n.disconnect(),e.value>=0&&(i||e.isFinal||"hidden"===document.visibilityState)&&(e.delta=e.value-(a||0),(e.delta||e.isFinal||void 0===a)&&(t(e),a=e.value))}},d=function(t){var e,n=arguments.length>1&&void 0!==arguments[1]&&arguments[1],i=r("CLS",0),a=function(t){t.hadRecentInput||(i.value+=t.value,i.entries.push(t),e())},s=o("layout-shift",a);s&&(e=l(t,i,s,n),p((function(t){var n=t.isUnloading;s.takeRecords().map(a),n&&(i.isFinal=!0),e()})))},f=function(){return void 0===i&&(i="hidden"===document.visibilityState?0:1/0,p((function(t){var e=t.timeStamp;return i=e}),!0)),{get timeStamp(){return i}}},m=function(t){var e,n=r("FCP"),i=f(),a=o("paint",(function(t){"first-contentful-paint"===t.name&&t.startTime<i.timeStamp&&(n.value=t.startTime,n.isFinal=!0,n.entries.push(t),e())}));a&&(e=l(t,n,a))},v=function(t){var e=r("FID"),n=f(),i=function(t){t.startTime<n.timeStamp&&(e.value=t.processingStart-t.startTime,e.entries.push(t),e.isFinal=!0,s())},a=o("first-input",i),s=l(t,e,a);a?p((function(){a.takeRecords().map(i),a.disconnect()}),!0):window.perfMetrics&&window.perfMetrics.onFirstInputDelay&&window.perfMetrics.onFirstInputDelay((function(t,i){i.timeStamp<n.timeStamp&&(e.value=t,e.isFinal=!0,e.entries=[{entryType:"first-input",name:i.type,target:i.target,cancelable:i.cancelable,startTime:i.timeStamp,processingStart:i.timeStamp+t}],s())}))},g=function(){return a||(a=new Promise((function(t){return["scroll","keydown","pointerdown"].map((function(e){addEventListener(e,t,{once:!0,passive:!0,capture:!0})}))}))),a},h=function(t){var e,n=arguments.length>1&&void 0!==arguments[1]&&arguments[1],i=r("LCP"),a=f(),s=function(t){var n=t.startTime;n<a.timeStamp?(i.value=n,i.entries.push(t)):i.isFinal=!0,e()},u=o("largest-contentful-paint",s);if(u){e=l(t,i,u,n);var c=function(){i.isFinal||(u.takeRecords().map(s),i.isFinal=!0,e())};g().then(c),p(c,!0)}},S=function(t){var e,n=r("TTFB");e=function(){try{var e=performance.getEntriesByType("navigation")[0]||function(){var t=performance.timing,e={entryType:"navigation",startTime:0};for(var n in t)"navigationStart"!==n&&"toJSON"!==n&&(e[n]=Math.max(t[n]-t.navigationStart,0));return e}();n.value=n.delta=e.responseStart,n.entries=[e],n.isFinal=!0,t(n)}catch(t){}},"complete"===document.readyState?setTimeout(e,0):addEventListener("pageshow",e)}}}]);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "main.js": "/public/bundle.js",
3
- "217.bundle.js": "/public/217.bundle.js",
3
+ "175.bundle.js": "/public/175.bundle.js",
4
4
  "inferno_logo.png": "/public/0e0b993fd6ff351f435ff1c2938daf2d.png",
5
5
  "inferno_icon.png": "/public/a5cd39450ab0336db73c5e57228b649d.png"
6
6
  }