inferno_core 0.4.37 → 0.4.38

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: 5fad068333ba8fce867afba323937728da89231ded560129675318866059975a
4
- data.tar.gz: d231cf80975b781b0584c5bb2b4677e1493eaba2fa6469ffca490e113d46ba08
3
+ metadata.gz: e2af0569e09addd1d815e42110f9813a875037b66a67871af0441a149b38c818
4
+ data.tar.gz: 4b526226bac3009548c7e70b75b59dc77e9c800700eed13e13846d30cbc79161
5
5
  SHA512:
6
- metadata.gz: 34c983546c7ea05443d9edde97e59d9c9dab2e1848271eefb4f888ff58cafc1219541de91634250ae4831162689cdd9e1e8f043735bc0fe6e495c86eb3a1bf41
7
- data.tar.gz: 2208622633268affb624426a91f4d6b7feed45cd7eac97dbad7c750c22169d7c08c5297fa96f8be86d13785faccf9966ad328b700528bcce0d2b8c6ba9cf97d1
6
+ metadata.gz: c0ab492c234d9a19ee06cca497a1e9714238bd1b7b0a2765b3647a49e0f3125a7a3b3f73e025e9741ec71b67c695d78258480d22aaf8974f8002b0354a0c0bdc
7
+ data.tar.gz: 241271ec1ef24731b06446dd442485fb8053f43504e3948a29077e26358b6b515102f41671336577c54b6705cb3858b7c59e0ac53819eadde5243ea98c16f8b2
@@ -4,6 +4,9 @@ module Inferno
4
4
  def run
5
5
  require_relative '../../../inferno'
6
6
 
7
+ ENV['ASYNC_JOBS'] = 'false'
8
+ ENV['INITIALIZE_VALIDATOR_SESSIONS'] = 'false'
9
+
7
10
  Inferno::Application.finalize!
8
11
  Pry.start
9
12
  end
@@ -11,6 +11,7 @@ module Inferno
11
11
  class Main < Thor
12
12
  desc 'console', 'Start an interactive console session with Inferno'
13
13
  def console
14
+ Migration.new.run(Logger::INFO)
14
15
  Console.new.run
15
16
  end
16
17
 
@@ -25,6 +26,7 @@ module Inferno
25
26
  type: :boolean,
26
27
  desc: 'Automatically restart Inferno when a file is changed.'
27
28
  def start
29
+ Migration.new.run(Logger::INFO)
28
30
  command = 'foreman start --env=/dev/null'
29
31
  if `gem list -i foreman`.chomp == 'false'
30
32
  puts "You must install foreman with 'gem install foreman' prior to running Inferno."
@@ -3,9 +3,9 @@ require_relative '../../utils/migration'
3
3
  module Inferno
4
4
  module CLI
5
5
  class Migration
6
- def run
6
+ def run(log_level = Logger::DEBUG)
7
7
  Inferno::Application.start(:logging)
8
- Inferno::Application['logger'].level = Logger::DEBUG
8
+ Inferno::Application['logger'].level = log_level
9
9
 
10
10
  Utils::Migration.new.run
11
11
  end
@@ -1,2 +1,2 @@
1
- VALIDATOR_URL=http://localhost/validatorapi
1
+ FHIR_RESOURCE_VALIDATOR_URL=http://localhost/hl7validatorapi
2
2
  REDIS_URL=redis://localhost:6379/0
@@ -1,2 +1,2 @@
1
1
  REDIS_URL=redis://redis:6379/0
2
- VALIDATOR_URL=http://validator_service:4567
2
+ FHIR_RESOURCE_VALIDATOR_URL=http://hl7_validator_service:3500
@@ -1,2 +1,2 @@
1
- VALIDATOR_URL=https://example.com/validatorapi
1
+ FHIR_RESOURCE_VALIDATOR_URL=https://example.com/validatorapi
2
2
  ASYNC_JOBS=false
@@ -82,5 +82,21 @@ http {
82
82
 
83
83
  proxy_pass http://validator_service:4567/;
84
84
  }
85
+
86
+ location /hl7validatorapi/ {
87
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
88
+ proxy_set_header Host $http_host;
89
+ proxy_set_header X-Forwarded-Proto $scheme;
90
+ proxy_set_header X-Forwarded-Port $server_port;
91
+ proxy_redirect off;
92
+ proxy_set_header Connection '';
93
+ proxy_http_version 1.1;
94
+ chunked_transfer_encoding off;
95
+ proxy_buffering off;
96
+ proxy_cache off;
97
+ proxy_read_timeout 600s;
98
+
99
+ proxy_pass http://hl7_validator_service:3500/;
100
+ }
85
101
  }
86
102
  }
@@ -97,5 +97,21 @@ http {
97
97
 
98
98
  proxy_pass http://validator_service:4567/;
99
99
  }
100
+
101
+ location /hl7validatorapi/ {
102
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
103
+ proxy_set_header Host $http_host;
104
+ proxy_set_header X-Forwarded-Proto $scheme;
105
+ proxy_set_header X-Forwarded-Port $server_port;
106
+ proxy_redirect off;
107
+ proxy_set_header Connection '';
108
+ proxy_http_version 1.1;
109
+ chunked_transfer_encoding off;
110
+ proxy_buffering off;
111
+ proxy_cache off;
112
+ proxy_read_timeout 600s;
113
+
114
+ proxy_pass http://hl7_validator_service:3500/;
115
+ }
100
116
  }
101
117
  }
@@ -1,5 +1,16 @@
1
1
  version: '3'
2
2
  services:
3
+ hl7_validator_service:
4
+ image: infernocommunity/inferno-resource-validator
5
+ environment:
6
+ # Defines how long validator sessions last if unused, in minutes:
7
+ # Negative values mean sessions never expire, 0 means sessions immediately expire
8
+ SESSION_CACHE_DURATION: -1
9
+ volumes:
10
+ - ./<%= ig_path %>:/app/igs
11
+ # To let the service share your local FHIR package cache,
12
+ # uncomment the below line
13
+ # - ~/.fhir:/home/ktor/.fhir
3
14
  validator_service:
4
15
  image: infernocommunity/fhir-validator-service
5
16
  # Update this path to match your directory structure
@@ -15,6 +15,10 @@ services:
15
15
  command: bundle exec sidekiq -r ./worker.rb
16
16
  depends_on:
17
17
  - redis
18
+ hl7_validator_service:
19
+ extends:
20
+ file: docker-compose.background.yml
21
+ service: hl7_validator_service
18
22
  validator_service:
19
23
  extends:
20
24
  file: docker-compose.background.yml
@@ -0,0 +1,21 @@
1
+ # Note on this IGs folder
2
+
3
+ There are three reasons why it would be necessary to put an IG package.tgz in this folder. If none of these apply, you do not need to put any files here, or can consider removing any existing files to make it clear they are unused.
4
+
5
+ ## 1. Generated Test Suites
6
+ Some test kits use a "generator" to automatically generate the contents of a test suite for an IG. The IG files are required every time the test suites need to be regenerated. Examples of test kits that use this approach are the US Core Test Kit and CARIN IG for Blue Button® Test Kit.
7
+
8
+
9
+ ## 2. Non-published IG
10
+ If your IG, or the specific version of the IG you want to test against, is not published, then the validator service needs to load the IG from file in order to be able to validate resources with it. The IG must be referenced in the `fhir_resource_validator` block in the test suite definition by filename, ie:
11
+
12
+ ```ruby
13
+ fhir_resource_validator do
14
+ igs 'igs/filename.tgz'
15
+
16
+ ...
17
+ end
18
+ ```
19
+
20
+ ## 3. Inferno Validator UI
21
+ The Inferno Validator UI is configured to auto-load any IGs present in the igs folder and include them in all validations. In general, the Inferno team is currently leaving IGs in this folder even if not otherwise necessary to make it easy to re-enable the validator UI.
@@ -22,8 +22,13 @@ module <%= module_name %>
22
22
  end
23
23
 
24
24
  # All FHIR validation requsets will use this FHIR validator
25
- validator do
26
- url ENV.fetch('VALIDATOR_URL')
25
+ fhir_resource_validator do
26
+ # igs 'identifier#version' # Use this method for published IGs/versions
27
+ # igs 'igs/filename.tgz' # Use this otherwise
28
+
29
+ exclude_message do |message|
30
+ message.message.match?(/\A\S+: \S+: URL value '.*' does not resolve/)
31
+ end
27
32
  end
28
33
 
29
34
  # Tests and TestGroups can be defined inline
@@ -4,7 +4,26 @@ RSpec.describe <%= module_name %>::PatientGroup do
4
4
  let(:session_data_repo) { Inferno::Repositories::SessionData.new }
5
5
  let(:test_session) { repo_create(:test_session, test_suite_id: '<%= test_suite_id %>') }
6
6
  let(:url) { 'http://example.com/fhir' }
7
- let(:error_outcome) { FHIR::OperationOutcome.new(issue: [{ severity: 'error' }]) }
7
+ let(:success_outcome) do
8
+ {
9
+ outcomes: [{
10
+ issues: []
11
+ }],
12
+ sessionId: ''
13
+ }
14
+ end
15
+ let(:error_outcome) do
16
+ {
17
+ outcomes: [{
18
+ issues: [{
19
+ location: 'Patient.identifier[0]',
20
+ message: 'Identifier.system must be an absolute reference, not a local reference',
21
+ level: 'ERROR'
22
+ }]
23
+ }],
24
+ sessionId: ''
25
+ }
26
+ end
8
27
 
9
28
  def run(runnable, inputs = {})
10
29
  test_run_params = { test_session_id: test_session.id }.merge(runnable.reference_hash)
@@ -67,9 +86,9 @@ RSpec.describe <%= module_name %>::PatientGroup do
67
86
  let(:test) { group.tests.last }
68
87
 
69
88
  it 'passes if the resource is valid' do
70
- stub_request(:post, "#{ENV.fetch('VALIDATOR_URL')}/validate")
89
+ stub_request(:post, "#{ENV.fetch('FHIR_RESOURCE_VALIDATOR_URL')}/validate")
71
90
  .with(query: hash_including({}))
72
- .to_return(status: 200, body: FHIR::OperationOutcome.new.to_json)
91
+ .to_return(status: 200, body: success_outcome.to_json)
73
92
 
74
93
  resource = FHIR::Patient.new
75
94
  repo_create(
@@ -79,13 +98,13 @@ RSpec.describe <%= module_name %>::PatientGroup do
79
98
  response_body: resource.to_json
80
99
  )
81
100
 
82
- result = run(test)
101
+ result = run(test, url: url)
83
102
 
84
103
  expect(result.result).to eq('pass')
85
104
  end
86
105
 
87
106
  it 'fails if the resource is not valid' do
88
- stub_request(:post, "#{ENV.fetch('VALIDATOR_URL')}/validate")
107
+ stub_request(:post, "#{ENV.fetch('FHIR_RESOURCE_VALIDATOR_URL')}/validate")
89
108
  .with(query: hash_including({}))
90
109
  .to_return(status: 200, body: error_outcome.to_json)
91
110
 
@@ -97,7 +116,7 @@ RSpec.describe <%= module_name %>::PatientGroup do
97
116
  response_body: resource.to_json
98
117
  )
99
118
 
100
- result = run(test)
119
+ result = run(test, url: url)
101
120
 
102
121
  expect(result.result).to eq('fail')
103
122
  end
@@ -5,6 +5,11 @@ Inferno::Application.register_provider(:sidekiq) do
5
5
  if Inferno::Application['async_jobs']
6
6
  Sidekiq.configure_server do |config|
7
7
  config.redis = { url: ENV.fetch('REDIS_URL', 'redis://127.0.0.1:6379/0') }
8
+
9
+ config.capsule('validator_sessions') do |cap|
10
+ cap.concurrency = ENV.fetch('VALIDATOR_SESSIONS_CONCURRENCY', '1').to_i
11
+ cap.queues = ['validator_sessions']
12
+ end
8
13
  end
9
14
  end
10
15
  end
@@ -8,6 +8,8 @@ Inferno::Application.register_provider(:validator) do
8
8
 
9
9
  next if ENV['APP_ENV'] == 'test'
10
10
 
11
+ next if ENV.fetch('INITIALIZE_VALIDATOR_SESSIONS', 'true').casecmp?('false')
12
+
11
13
  Inferno::Repositories::TestSuites.new.all.each do |suite|
12
14
  suite.fhir_validators.each do |name, validators|
13
15
  validators.each_with_index do |validator, index|
@@ -1,4 +1,4 @@
1
- require_relative 'suite_endpoint'
1
+ require 'hanami/controller'
2
2
 
3
3
  module Inferno
4
4
  module DSL
@@ -6,47 +6,58 @@ module Inferno
6
6
  # an incoming request.
7
7
  # @private
8
8
  # @see Inferno::DSL::Runnable#resume_test_route
9
- class ResumeTestRoute < SuiteEndpoint
10
- # The incoming request
11
- #
12
- # @return [Inferno::Entities::Request]
13
- def request
14
- @request ||= Inferno::Entities::Request.from_hanami_request(req)
9
+ class ResumeTestRoute < Hanami::Action
10
+ include Import[
11
+ requests_repo: 'inferno.repositories.requests',
12
+ results_repo: 'inferno.repositories.results',
13
+ test_runs_repo: 'inferno.repositories.test_runs',
14
+ tests_repo: 'inferno.repositories.tests'
15
+ ]
16
+
17
+ def self.call(...)
18
+ new.call(...)
15
19
  end
16
20
 
17
21
  # @private
18
- def test_run_identifier
19
- @test_run_identifier ||= instance_exec(request, &test_run_identifier_block)
22
+ def test_run_identifier_block
23
+ self.class.singleton_class.instance_variable_get(:@test_run_identifier_block)
20
24
  end
21
25
 
22
26
  # @private
23
27
  def tags
24
- self.class.singleton_class.instance_variable_get(:@tags) || []
28
+ self.class.singleton_class.instance_variable_get(:@tags)
25
29
  end
26
30
 
27
31
  # @private
28
- def update_result
29
- results_repo.update_result(result.id, new_result)
32
+ def result
33
+ self.class.singleton_class.instance_variable_get(:@result)
30
34
  end
31
35
 
32
36
  # @private
33
- def make_response
34
- res.redirect_to redirect_route(test_run, test)
37
+ def find_test_run(test_run_identifier)
38
+ test_runs_repo.find_latest_waiting_by_identifier(test_run_identifier)
35
39
  end
36
40
 
37
41
  # @private
38
- def name
39
- test.config.request_name(test.incoming_request_name)
42
+ def find_waiting_result(test_run)
43
+ results_repo.find_waiting_result(test_run_id: test_run.id)
40
44
  end
41
45
 
42
46
  # @private
43
- def test_run_identifier_block
44
- self.class.singleton_class.instance_variable_get(:@test_run_identifier_block)
47
+ def update_result(waiting_result)
48
+ results_repo.update_result(waiting_result.id, result)
45
49
  end
46
50
 
47
51
  # @private
48
- def new_result
49
- self.class.singleton_class.instance_variable_get(:@new_result)
52
+ def persist_request(request, test_run, waiting_result, test)
53
+ requests_repo.create(
54
+ request.to_hash.merge(
55
+ test_session_id: test_run.test_session_id,
56
+ result_id: waiting_result.id,
57
+ name: test.config.request_name(test.incoming_request_name),
58
+ tags:
59
+ )
60
+ )
50
61
  end
51
62
 
52
63
  # @private
@@ -54,10 +65,38 @@ module Inferno
54
65
  "#{Application['base_url']}/test_sessions/#{test_run.test_session_id}##{resume_ui_at_id(test_run, test)}"
55
66
  end
56
67
 
68
+ # @private
69
+ def find_test(waiting_result)
70
+ tests_repo.find(waiting_result.test_id)
71
+ end
72
+
57
73
  # @private
58
74
  def resume_ui_at_id(test_run, test)
59
75
  test_run.test_suite_id || test_run.test_group_id || test.parent.id
60
76
  end
77
+
78
+ # @private
79
+ def handle(req, res)
80
+ request = Inferno::Entities::Request.from_hanami_request(req)
81
+
82
+ test_run_identifier = instance_exec(request, &test_run_identifier_block)
83
+
84
+ test_run = find_test_run(test_run_identifier)
85
+
86
+ halt 500, "Unable to find test run with identifier '#{test_run_identifier}'." if test_run.nil?
87
+
88
+ test_runs_repo.mark_as_no_longer_waiting(test_run.id)
89
+
90
+ waiting_result = find_waiting_result(test_run)
91
+ test = find_test(waiting_result)
92
+
93
+ update_result(waiting_result)
94
+ persist_request(request, test_run, waiting_result, test)
95
+
96
+ Jobs.perform(Jobs::ResumeTestRun, test_run.id)
97
+
98
+ res.redirect_to redirect_route(test_run, test)
99
+ end
61
100
  end
62
101
  end
63
102
  end
@@ -343,7 +343,7 @@ module Inferno
343
343
  route_class = Class.new(ResumeTestRoute) do |klass|
344
344
  klass.singleton_class.instance_variable_set(:@test_run_identifier_block, block)
345
345
  klass.singleton_class.instance_variable_set(:@tags, tags)
346
- klass.singleton_class.instance_variable_set(:@new_result, result)
346
+ klass.singleton_class.instance_variable_set(:@result, result)
347
347
  end
348
348
 
349
349
  route(method, path, route_class)
@@ -244,7 +244,7 @@ module Inferno
244
244
 
245
245
  # @private
246
246
  def resume_test_run?
247
- find_result&.result != 'waiting'
247
+ find_result&.result != 'wait'
248
248
  end
249
249
 
250
250
  # @private
@@ -2,6 +2,7 @@ module Inferno
2
2
  module Jobs
3
3
  class InvokeValidatorSession
4
4
  include Sidekiq::Worker
5
+ sidekiq_options queue: 'validator_sessions'
5
6
 
6
7
  def perform(suite_id, validator_name, validator_index)
7
8
  suite = Inferno::Repositories::TestSuites.new.find suite_id