inferno_core 0.4.29 → 0.4.31

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