inferno_core 0.0.6 → 0.0.7

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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/bin/inferno +7 -0
  3. data/lib/inferno/apps/cli/console.rb +12 -0
  4. data/lib/inferno/apps/cli/main.rb +18 -0
  5. data/lib/inferno/apps/cli/migration.rb +14 -0
  6. data/lib/inferno/apps/cli.rb +8 -0
  7. data/lib/inferno/config/application.rb +3 -0
  8. data/lib/inferno/config/boot/db.rb +1 -9
  9. data/lib/inferno/config/boot/logging.rb +2 -0
  10. data/lib/inferno/dsl/assertions.rb +66 -1
  11. data/lib/inferno/dsl/configurable.rb +1 -1
  12. data/lib/inferno/dsl/fhir_client.rb +4 -4
  13. data/lib/inferno/dsl/fhir_client_builder.rb +3 -3
  14. data/lib/inferno/dsl/fhir_validation.rb +1 -1
  15. data/lib/inferno/dsl/http_client.rb +4 -4
  16. data/lib/inferno/dsl/http_client_builder.rb +3 -3
  17. data/lib/inferno/dsl/request_storage.rb +8 -8
  18. data/lib/inferno/dsl/results.rb +1 -1
  19. data/lib/inferno/dsl/resume_test_route.rb +9 -9
  20. data/lib/inferno/dsl/runnable.rb +36 -18
  21. data/lib/inferno/entities/header.rb +14 -7
  22. data/lib/inferno/entities/message.rb +16 -8
  23. data/lib/inferno/entities/request.rb +32 -19
  24. data/lib/inferno/entities/result.rb +36 -29
  25. data/lib/inferno/entities/session_data.rb +12 -6
  26. data/lib/inferno/entities/test.rb +13 -0
  27. data/lib/inferno/entities/test_run.rb +29 -6
  28. data/lib/inferno/entities/test_session.rb +16 -10
  29. data/lib/inferno/public/bundle.js +1 -1
  30. data/lib/inferno/repositories/in_memory_repository.rb +1 -1
  31. data/lib/inferno/repositories/results.rb +1 -1
  32. data/lib/inferno/spec_support.rb +1 -1
  33. data/lib/inferno/test_runner.rb +1 -1
  34. data/lib/inferno/utils/markdown_formatter.rb +1 -1
  35. data/lib/inferno/utils/middleware/request_logger.rb +1 -1
  36. data/lib/inferno/utils/migration.rb +17 -0
  37. data/lib/inferno/version.rb +1 -1
  38. data/lib/inferno.rb +0 -4
  39. metadata +37 -4
  40. data/bin/inferno-console +0 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 40769c54fd3854730eb080d1bb9e0755ff1551b00761968155d463dd3a6ce3e0
4
- data.tar.gz: 8bbf5aaa2b09d7d5ff54e56a3ed33ce4e1f4df29fc53e3737f18e9972dc34f1e
3
+ metadata.gz: 86c8b0374d22ea35f07944360943d2a1240f8ef7365b97d625b32facde4a2eaa
4
+ data.tar.gz: '0258752a8738b7e9c1da7d9112d0ee4f15bac0a8c7b2acac5f9973bb35d8146c'
5
5
  SHA512:
6
- metadata.gz: 35fe2518d3856f01b3358da68d862318784f05ab067b579d3ac62053dc1deed2be2895e3cfb5ff8efbc97e71d2495a11ebf66eadf23c5b8b4edb502707334838
7
- data.tar.gz: 04e37af9daf40c01f0d4182f055e4ddf187d72f0e9d8a43e8858af5c549a4a60900d71f034a8e027e20f53a56f6b5e835bce1fca3a0b98870b07e0681793a2d9
6
+ metadata.gz: 76cd8133722b109ed66f9b79eea46279c177fdac68cfe9abea4d0e9caaa76b861e533909923a94121d17e15483be5254f8e36e67cf6abb6121bc12f1e37f5fd7
7
+ data.tar.gz: 9be9f363e78e653b33818a8e8eee7fc74474ec2ca019b715054b7926d7e5675c46b290e138c0ee020e586d91eecef2759ead3272b6087461af89afeb8fdd7e94
data/bin/inferno ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pry'
4
+ require_relative '../lib/inferno/config/application'
5
+ require_relative '../lib/inferno/apps/cli'
6
+
7
+ Inferno::CLI::Main.start
@@ -0,0 +1,12 @@
1
+ module Inferno
2
+ module CLI
3
+ class Console
4
+ def run
5
+ require_relative '../../../inferno'
6
+
7
+ Inferno::Application.finalize!
8
+ Pry.start
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,18 @@
1
+ require_relative 'console'
2
+ require_relative 'migration'
3
+
4
+ module Inferno
5
+ module CLI
6
+ class Main < Thor
7
+ desc 'console', 'Start an interactive console session with Inferno'
8
+ def console
9
+ Console.new.run
10
+ end
11
+
12
+ desc 'migrate', 'Run database migrations'
13
+ def migrate
14
+ Migration.new.run
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ require_relative '../../utils/migration'
2
+
3
+ module Inferno
4
+ module CLI
5
+ class Migration
6
+ def run
7
+ Inferno::Application.start(:logging)
8
+ Inferno::Application['logger'].level = Logger::DEBUG
9
+
10
+ Utils::Migration.new.run
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,8 @@
1
+ require 'thor'
2
+
3
+ require_relative 'cli/main'
4
+
5
+ module Inferno
6
+ module CLI
7
+ end
8
+ end
@@ -1,4 +1,7 @@
1
+ require 'active_support/all'
2
+ require 'dotenv'
1
3
  require 'dry/system/container'
4
+ require 'sequel'
2
5
  require_relative 'boot'
3
6
 
4
7
  module Inferno
@@ -12,6 +12,7 @@ Inferno::Application.boot(:db) do
12
12
  config = YAML.load_file(config_path)[ENV['APP_ENV']]
13
13
  .merge(logger: Inferno::Application['logger'])
14
14
  connection = Sequel.connect(config)
15
+ connection.sql_log_level = :debug
15
16
 
16
17
  register('db.config', config)
17
18
  register('db.connection', connection)
@@ -19,14 +20,5 @@ Inferno::Application.boot(:db) do
19
20
 
20
21
  start do
21
22
  Sequel.extension :migration
22
- db = Inferno::Application['db.connection']
23
- migration_path = File.join(Inferno::Application.root, 'lib', 'inferno', 'db', 'migrations')
24
- Sequel::Migrator.run(db, migration_path)
25
-
26
- if ENV['APP_ENV'] == 'development'
27
- schema_path = File.join(Inferno::Application.root, 'lib', 'inferno', 'db', 'schema.rb')
28
- db.extension :schema_dumper
29
- File.open(schema_path, 'w') { |f| f.print(db.dump_schema_migration) }
30
- end
31
23
  end
32
24
  end
@@ -11,6 +11,8 @@ Inferno::Application.boot(:logging) do
11
11
  Logger.new($stdout)
12
12
  end
13
13
 
14
+ logger.level = Logger::INFO
15
+
14
16
  register('logger', logger)
15
17
  end
16
18
  end
@@ -3,22 +3,43 @@ require_relative '../exceptions'
3
3
  module Inferno
4
4
  module DSL
5
5
  module Assertions
6
+ # Make an assertion
7
+ #
8
+ # @param test a value whose truthiness will determine whether the
9
+ # assertion passes or fails
10
+ # @param message [String] failure message
6
11
  def assert(test, message = '')
7
12
  raise Exceptions::AssertionException, message unless test
8
13
  end
9
14
 
15
+ # @private
10
16
  def bad_response_status_message(expected, received)
11
17
  "Bad response status: expected #{Array.wrap(expected).join(', ')}, but received #{received}"
12
18
  end
13
19
 
20
+ # Check an response's status
21
+ #
22
+ # @param status [Integer, Array<Integer>] a single integer or an array of
23
+ # integer status codes
24
+ # @param response [Hash]
14
25
  def assert_response_status(status, response: self.response)
15
26
  assert Array.wrap(status).include?(response[:status]), bad_response_status_message(status, response[:status])
16
27
  end
17
28
 
29
+ # @private
18
30
  def bad_resource_type_message(expected, received)
19
31
  "Bad resource type received: expected #{expected}, but received #{received}"
20
32
  end
21
33
 
34
+ # Check a FHIR resource's type
35
+ #
36
+ # @param resource_type [String, Symbol, Class]
37
+ # @param resource [FHIR::Model]
38
+ # @example
39
+ # # The resource type can be a symbol, String, or FHIR::Model class
40
+ # assert_resource_type(:capability_statement)
41
+ # assert_resource_type('CapabilityStatement')
42
+ # assert_resource_type(FHIR::CapabilityStatement)
22
43
  def assert_resource_type(resource_type, resource: self.resource)
23
44
  resource_type_name = normalize_resource_type(resource_type)
24
45
 
@@ -26,15 +47,48 @@ module Inferno
26
47
  bad_resource_type_message(resource_type_name, resource&.resourceType)
27
48
  end
28
49
 
50
+ # @private
29
51
  def invalid_resource_message(profile_url)
30
52
  "Resource does not conform to the profile: #{profile_url}"
31
53
  end
32
54
 
55
+ # Validate a FHIR resource
56
+ #
57
+ # @param resource [FHIR::Model]
58
+ # @param profile_url [String] url of the profile to validate against,
59
+ # defaults to validating against the base FHIR resource
33
60
  def assert_valid_resource(resource: self.resource, profile_url: nil)
34
61
  assert resource_is_valid?(resource: resource, profile_url: profile_url),
35
62
  invalid_resource_message(profile_url)
36
63
  end
37
64
 
65
+ # Validate each entry of a Bundle
66
+ #
67
+ # @param bundle [FHIR::Bundle]
68
+ # @param resource_types
69
+ # [String,Symbol,FHIR::Model,Array<String,Symbol,FHIR::Model>,Hash] If a
70
+ # string, symbol, or FHIR::Model is provided, only that resource type
71
+ # will be validated. If an array of strings is provided, only those
72
+ # resource types will be validated. If a hash is provided with resource
73
+ # types as keys and profile urls (or nil) as values, only those resource
74
+ # types will be validated against the provided profile url or the base
75
+ # resource if nil.
76
+ # @example
77
+ # # Only validate Patient bundle entries
78
+ # assert_valid_bundle_entries(resource_types: 'Patient')
79
+ #
80
+ # # Only valiadte Patient and Condition bundle entries
81
+ # assert_valid_bundle_entries(resource_types: ['Patient', 'Condition'])
82
+ #
83
+ # # Only validate Patient and Condition bundle entries. Validate Patient
84
+ # # resources against the given profile, and Codition resources against the
85
+ # # base FHIR Condition resource.
86
+ # assert_valid_bundle_entries(
87
+ # resource_types: {
88
+ # 'Patient': 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient',
89
+ # 'Condition': nil
90
+ # }
91
+ # )
38
92
  def assert_valid_bundle_entries(bundle: resource, resource_types: {})
39
93
  assert_resource_type('Bundle', resource: bundle)
40
94
 
@@ -56,6 +110,7 @@ module Inferno
56
110
  assert invalid_resources.empty?, invalid_bundle_entries_message(invalid_resources)
57
111
  end
58
112
 
113
+ # @private
59
114
  def invalid_bundle_entries_message(invalid_resources)
60
115
  identifier_strings =
61
116
  invalid_resources
@@ -64,6 +119,7 @@ module Inferno
64
119
  "The following bundle entries are invalid: #{identifier_strings}"
65
120
  end
66
121
 
122
+ # @private
67
123
  def normalize_resource_type(resource_type)
68
124
  if resource_type.is_a? Class
69
125
  resource_type.name.demodulize
@@ -72,6 +128,7 @@ module Inferno
72
128
  end
73
129
  end
74
130
 
131
+ # @private
75
132
  def normalize_types_to_check(resource_types)
76
133
  case resource_types
77
134
  when Hash
@@ -83,14 +140,22 @@ module Inferno
83
140
  end
84
141
  end
85
142
 
143
+ # Check for valid JSON
144
+ #
145
+ # @param maybe_json_string [String]
146
+ # @param message [String] extra failure message
86
147
  def assert_valid_json(maybe_json_string, message = '')
87
148
  assert JSON.parse(maybe_json_string)
88
149
  rescue JSON::ParserError
89
150
  assert false, "Invalid JSON. #{message}"
90
151
  end
91
152
 
153
+ # Check for a valid http/https uri
154
+ #
155
+ # @param uri [String]
156
+ # @param message [String] custom failure message
92
157
  def assert_valid_http_uri(uri, message = '')
93
- error_message = message || "\"#{uri}\" is not a valid URI"
158
+ error_message = message.presence || "\"#{uri}\" is not a valid URI"
94
159
  assert uri =~ /\A#{URI::DEFAULT_PARSER.make_regexp(['http', 'https'])}\z/, error_message
95
160
  end
96
161
 
@@ -15,7 +15,7 @@ module Inferno
15
15
  @config.apply(new_configuration)
16
16
  end
17
17
 
18
- # @api private
18
+ # @private
19
19
  class Configuration
20
20
  attr_accessor :configuration
21
21
 
@@ -35,7 +35,7 @@ module Inferno
35
35
  # @see Inferno::FHIRClientBuilder Documentation for the client
36
36
  # configuration DSL
37
37
  module FHIRClient
38
- # @api private
38
+ # @private
39
39
  def self.included(klass)
40
40
  klass.extend ClassMethods
41
41
  klass.extend Forwardable
@@ -54,7 +54,7 @@ module Inferno
54
54
  FHIRClientBuilder.new.build(self, self.class.fhir_client_definitions[client])
55
55
  end
56
56
 
57
- # @api private
57
+ # @private
58
58
  def fhir_clients
59
59
  @fhir_clients ||= {}
60
60
  end
@@ -128,13 +128,13 @@ module Inferno
128
128
 
129
129
  # @todo Make this a FHIR class method? Something like
130
130
  # FHIR.class_for(resource_type)
131
- # @api private
131
+ # @private
132
132
  def fhir_class_from_resource_type(resource_type)
133
133
  FHIR.const_get(resource_type.to_s.camelize)
134
134
  end
135
135
 
136
136
  module ClassMethods
137
- # @api private
137
+ # @private
138
138
  def fhir_client_definitions
139
139
  @fhir_client_definitions ||= {}
140
140
  end
@@ -6,7 +6,7 @@ module Inferno
6
6
  class FHIRClientBuilder
7
7
  attr_accessor :runnable
8
8
 
9
- # @api private
9
+ # @private
10
10
  def build(runnable, block)
11
11
  self.runnable = runnable
12
12
  instance_exec(self, &block)
@@ -56,14 +56,14 @@ module Inferno
56
56
  @headers ||= headers
57
57
  end
58
58
 
59
- # @api private
59
+ # @private
60
60
  def method_missing(name, *args, &block)
61
61
  return runnable.call(name, *args, &block) if runnable.respond_to? name
62
62
 
63
63
  super
64
64
  end
65
65
 
66
- # @api private
66
+ # @private
67
67
  def respond_to_missing?(name)
68
68
  runnable.respond_to?(name) || super
69
69
  end
@@ -89,7 +89,7 @@ module Inferno
89
89
  end
90
90
 
91
91
  module ClassMethods
92
- # @api private
92
+ # @private
93
93
  def fhir_validators
94
94
  @fhir_validators ||= {}
95
95
  end
@@ -16,7 +16,7 @@ module Inferno
16
16
  # # performs a GET to https://example.com
17
17
  # get
18
18
  # # performs a GET to https://example.com/abc
19
- # get('abc')
19
+ # get('abc')
20
20
  #
21
21
  # request # the most recent request
22
22
  # response # the most recent response
@@ -27,7 +27,7 @@ module Inferno
27
27
  # @see Inferno::FHIRClientBuilder Documentation for the client
28
28
  # configuration DSL
29
29
  module HTTPClient
30
- # @api private
30
+ # @private
31
31
  def self.included(klass)
32
32
  klass.extend ClassMethods
33
33
  klass.include RequestStorage
@@ -47,7 +47,7 @@ module Inferno
47
47
  http_clients[client] = HTTPClientBuilder.new.build(self, definition)
48
48
  end
49
49
 
50
- # @api private
50
+ # @private
51
51
  def http_clients
52
52
  @http_clients ||= {}
53
53
  end
@@ -104,7 +104,7 @@ module Inferno
104
104
  end
105
105
 
106
106
  module ClassMethods
107
- # @api private
107
+ # @private
108
108
  def http_client_definitions
109
109
  @http_client_definitions ||= {}
110
110
  end
@@ -4,7 +4,7 @@ module Inferno
4
4
  class HTTPClientBuilder
5
5
  attr_accessor :runnable
6
6
 
7
- # @api private
7
+ # @private
8
8
  def build(runnable, block)
9
9
  self.runnable = runnable
10
10
  instance_exec(self, &block)
@@ -38,14 +38,14 @@ module Inferno
38
38
  @headers ||= headers
39
39
  end
40
40
 
41
- # @api private
41
+ # @private
42
42
  def method_missing(name, *args, &block)
43
43
  return runnable.call(name, *args, &block) if runnable.respond_to? name
44
44
 
45
45
  super
46
46
  end
47
47
 
48
- # @api private
48
+ # @private
49
49
  def respond_to_missing?(name)
50
50
  runnable.respond_to?(name) || super
51
51
  end
@@ -41,7 +41,7 @@ module Inferno
41
41
  requests.find { |request| request.name == self.class.config.request_name(name.to_sym) }
42
42
  end
43
43
 
44
- # @api private
44
+ # @private
45
45
  def store_request(direction, name = nil, &block)
46
46
  response = block.call
47
47
 
@@ -61,7 +61,7 @@ module Inferno
61
61
  request
62
62
  end
63
63
 
64
- # @api private
64
+ # @private
65
65
  def load_named_requests
66
66
  requests_repo = Inferno::Repositories::Requests.new
67
67
  self.class.named_requests_used.map do |request_name|
@@ -74,19 +74,19 @@ module Inferno
74
74
  end
75
75
 
76
76
  module ClassMethods
77
- # @api private
77
+ # @private
78
78
  def named_requests_made
79
79
  @named_requests_made ||= []
80
80
  end
81
81
 
82
- # @api private
82
+ # @private
83
83
  def named_requests_used
84
84
  @named_requests_used ||= []
85
85
  end
86
86
 
87
87
  # Specify the named requests made by a test
88
88
  #
89
- # @param *identifiers [Symbol] one or more Symbols
89
+ # @param identifiers [Symbol] one or more request identifiers
90
90
  def makes_request(*identifiers)
91
91
  named_requests_made.concat(identifiers).uniq!
92
92
  identifiers.each do |identifier|
@@ -96,20 +96,20 @@ module Inferno
96
96
 
97
97
  # Specify the name for a request received by a test
98
98
  #
99
- # @param *identifiers [Symbol] one or more Symbols
99
+ # @param identifier [Symbol]
100
100
  def receives_request(identifier)
101
101
  config.add_request(identifier)
102
102
  @incoming_request_name = identifier
103
103
  end
104
104
 
105
- # @api private
105
+ # @private
106
106
  def incoming_request_name
107
107
  @incoming_request_name
108
108
  end
109
109
 
110
110
  # Specify the named requests used by a test
111
111
  #
112
- # @param *identifiers [Symbol] one or more Symbols
112
+ # @param identifiers [Symbol] one or more request identifiers
113
113
  def uses_request(*identifiers)
114
114
  named_requests_used.concat(identifiers).uniq!
115
115
  identifiers.each do |identifier|
@@ -94,7 +94,7 @@ module Inferno
94
94
  # and should not be used in real tests.
95
95
  #
96
96
  # @param message [String]
97
- # @api private
97
+ # @private
98
98
  def cancel(message = '')
99
99
  raise Exceptions::CancelException, message
100
100
  end
@@ -4,7 +4,7 @@ module Inferno
4
4
  module DSL
5
5
  # A base class for creating routes to resume test execution upon receiving
6
6
  # an incoming request.
7
- # @api private
7
+ # @private
8
8
  # @see Inferno::DSL::Runnable#resume_test_route
9
9
  class ResumeTestRoute
10
10
  include Hanami::Action
@@ -26,23 +26,23 @@ module Inferno
26
26
  @request ||= Inferno::Entities::Request.from_rack_env(@params.env)
27
27
  end
28
28
 
29
- # @api private
29
+ # @private
30
30
  def test_run
31
31
  @test_run ||=
32
32
  test_runs_repo.find_latest_waiting_by_identifier(test_run_identifier)
33
33
  end
34
34
 
35
- # @api private
35
+ # @private
36
36
  def waiting_result
37
37
  @waiting_result ||= results_repo.find_waiting_result(test_run_id: test_run.id)
38
38
  end
39
39
 
40
- # @api private
40
+ # @private
41
41
  def update_result
42
42
  results_repo.pass_waiting_result(waiting_result.id)
43
43
  end
44
44
 
45
- # @api private
45
+ # @private
46
46
  def persist_request
47
47
  requests_repo.create(
48
48
  request.to_hash.merge(
@@ -53,22 +53,22 @@ module Inferno
53
53
  )
54
54
  end
55
55
 
56
- # @api private
56
+ # @private
57
57
  def redirect_route
58
58
  "/test_sessions/#{test_run.test_session_id}##{waiting_group_id}"
59
59
  end
60
60
 
61
- # @api private
61
+ # @private
62
62
  def test
63
63
  @test ||= tests_repo.find(waiting_result.test_id)
64
64
  end
65
65
 
66
- # @api private
66
+ # @private
67
67
  def waiting_group_id
68
68
  test.parent.id
69
69
  end
70
70
 
71
- # @api private
71
+ # @private
72
72
  def call(_params)
73
73
  if test_run.nil?
74
74
  status(500, "Unable to find test run with identifier '#{test_run_identifier}'.")