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.
- checksums.yaml +4 -4
- data/lib/inferno/apps/cli/new.rb +42 -18
- data/lib/inferno/apps/cli/templates/%library_name%.gemspec.tt +26 -0
- data/lib/inferno/apps/cli/templates/Dockerfile.tt +22 -0
- data/lib/inferno/apps/cli/templates/Gemfile.tt +9 -0
- data/lib/inferno/apps/cli/templates/LICENSE.tt +201 -0
- data/lib/inferno/apps/cli/templates/Procfile.tt +2 -0
- data/lib/inferno/apps/cli/templates/README.md.tt +41 -0
- data/lib/inferno/apps/cli/templates/Rakefile.tt +15 -0
- data/lib/inferno/apps/cli/templates/config/database.yml.tt +18 -0
- data/lib/inferno/apps/cli/templates/config/nginx.background.conf.tt +86 -0
- data/lib/inferno/apps/cli/templates/config/nginx.conf.tt +101 -0
- data/lib/inferno/apps/cli/templates/config/puma.rb.tt +2 -0
- data/lib/inferno/apps/cli/templates/config.ru.tt +11 -0
- data/lib/inferno/apps/cli/templates/docker-compose.background.yml.tt +30 -0
- data/lib/inferno/apps/cli/templates/docker-compose.yml.tt +35 -0
- data/lib/inferno/apps/cli/templates/lib/%library_name%/igs/put_ig_package_dot_tgz_here +0 -0
- data/lib/inferno/apps/cli/templates/lib/%library_name%/patient_group.rb.tt +44 -0
- data/lib/inferno/apps/cli/templates/lib/%library_name%.rb.tt +53 -0
- data/lib/inferno/apps/cli/templates/run.sh +3 -0
- data/lib/inferno/apps/cli/templates/setup.sh +4 -0
- data/lib/inferno/apps/cli/templates/spec/%library_name%/patient_group_spec.rb.tt +105 -0
- data/lib/inferno/apps/cli/templates/spec/spec_helper.rb.tt +141 -0
- data/lib/inferno/apps/cli/templates/worker.rb.tt +3 -0
- data/lib/inferno/db/migrations/010_add_validator_sessions.rb +14 -0
- data/lib/inferno/db/schema.rb +14 -0
- data/lib/inferno/dsl/fhir_client_builder.rb +1 -1
- data/lib/inferno/dsl/fhir_resource_validation.rb +21 -7
- data/lib/inferno/dsl/http_client_builder.rb +1 -1
- data/lib/inferno/entities/validator_session.rb +22 -0
- data/lib/inferno/entities.rb +1 -0
- data/lib/inferno/jobs/invoke_validator_session.rb +3 -3
- data/lib/inferno/public/175.bundle.js +1 -0
- data/lib/inferno/public/assets.json +1 -1
- data/lib/inferno/public/bundle.js +21 -21
- data/lib/inferno/public/bundle.js.LICENSE.txt +17 -5
- data/lib/inferno/repositories/validator_sessions.rb +58 -0
- data/lib/inferno/repositories.rb +1 -0
- data/lib/inferno/utils/ig_downloader.rb +57 -0
- data/lib/inferno/version.rb +1 -1
- 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
|
File without changes
|
@@ -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,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,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
|
data/lib/inferno/db/schema.rb
CHANGED
@@ -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]
|
@@ -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
|
-
|
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
|
@@ -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
|
data/lib/inferno/entities.rb
CHANGED
@@ -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
|
-
|
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)}}}]);
|