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.
- checksums.yaml +4 -4
- data/bin/inferno +7 -0
- data/lib/inferno/apps/cli/console.rb +12 -0
- data/lib/inferno/apps/cli/main.rb +18 -0
- data/lib/inferno/apps/cli/migration.rb +14 -0
- data/lib/inferno/apps/cli.rb +8 -0
- data/lib/inferno/config/application.rb +3 -0
- data/lib/inferno/config/boot/db.rb +1 -9
- data/lib/inferno/config/boot/logging.rb +2 -0
- data/lib/inferno/dsl/assertions.rb +66 -1
- data/lib/inferno/dsl/configurable.rb +1 -1
- data/lib/inferno/dsl/fhir_client.rb +4 -4
- data/lib/inferno/dsl/fhir_client_builder.rb +3 -3
- data/lib/inferno/dsl/fhir_validation.rb +1 -1
- data/lib/inferno/dsl/http_client.rb +4 -4
- data/lib/inferno/dsl/http_client_builder.rb +3 -3
- data/lib/inferno/dsl/request_storage.rb +8 -8
- data/lib/inferno/dsl/results.rb +1 -1
- data/lib/inferno/dsl/resume_test_route.rb +9 -9
- data/lib/inferno/dsl/runnable.rb +36 -18
- data/lib/inferno/entities/header.rb +14 -7
- data/lib/inferno/entities/message.rb +16 -8
- data/lib/inferno/entities/request.rb +32 -19
- data/lib/inferno/entities/result.rb +36 -29
- data/lib/inferno/entities/session_data.rb +12 -6
- data/lib/inferno/entities/test.rb +13 -0
- data/lib/inferno/entities/test_run.rb +29 -6
- data/lib/inferno/entities/test_session.rb +16 -10
- data/lib/inferno/public/bundle.js +1 -1
- data/lib/inferno/repositories/in_memory_repository.rb +1 -1
- data/lib/inferno/repositories/results.rb +1 -1
- data/lib/inferno/spec_support.rb +1 -1
- data/lib/inferno/test_runner.rb +1 -1
- data/lib/inferno/utils/markdown_formatter.rb +1 -1
- data/lib/inferno/utils/middleware/request_logger.rb +1 -1
- data/lib/inferno/utils/migration.rb +17 -0
- data/lib/inferno/version.rb +1 -1
- data/lib/inferno.rb +0 -4
- metadata +37 -4
- data/bin/inferno-console +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 86c8b0374d22ea35f07944360943d2a1240f8ef7365b97d625b32facde4a2eaa
|
4
|
+
data.tar.gz: '0258752a8738b7e9c1da7d9112d0ee4f15bac0a8c7b2acac5f9973bb35d8146c'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 76cd8133722b109ed66f9b79eea46279c177fdac68cfe9abea4d0e9caaa76b861e533909923a94121d17e15483be5254f8e36e67cf6abb6121bc12f1e37f5fd7
|
7
|
+
data.tar.gz: 9be9f363e78e653b33818a8e8eee7fc74474ec2ca019b715054b7926d7e5675c46b290e138c0ee020e586d91eecef2759ead3272b6087461af89afeb8fdd7e94
|
data/bin/inferno
ADDED
@@ -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
|
@@ -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
|
@@ -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
|
|
@@ -35,7 +35,7 @@ module Inferno
|
|
35
35
|
# @see Inferno::FHIRClientBuilder Documentation for the client
|
36
36
|
# configuration DSL
|
37
37
|
module FHIRClient
|
38
|
-
# @
|
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
|
-
# @
|
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
|
-
# @
|
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
|
-
# @
|
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
|
-
# @
|
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
|
-
# @
|
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
|
-
# @
|
66
|
+
# @private
|
67
67
|
def respond_to_missing?(name)
|
68
68
|
runnable.respond_to?(name) || super
|
69
69
|
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
|
-
#
|
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
|
-
# @
|
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
|
-
# @
|
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
|
-
# @
|
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
|
-
# @
|
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
|
-
# @
|
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
|
-
# @
|
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
|
-
# @
|
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
|
-
# @
|
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
|
-
# @
|
77
|
+
# @private
|
78
78
|
def named_requests_made
|
79
79
|
@named_requests_made ||= []
|
80
80
|
end
|
81
81
|
|
82
|
-
# @
|
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
|
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
|
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
|
-
# @
|
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
|
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|
|
data/lib/inferno/dsl/results.rb
CHANGED
@@ -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
|
-
# @
|
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
|
-
# @
|
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
|
-
# @
|
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
|
-
# @
|
40
|
+
# @private
|
41
41
|
def update_result
|
42
42
|
results_repo.pass_waiting_result(waiting_result.id)
|
43
43
|
end
|
44
44
|
|
45
|
-
# @
|
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
|
-
# @
|
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
|
-
# @
|
61
|
+
# @private
|
62
62
|
def test
|
63
63
|
@test ||= tests_repo.find(waiting_result.test_id)
|
64
64
|
end
|
65
65
|
|
66
|
-
# @
|
66
|
+
# @private
|
67
67
|
def waiting_group_id
|
68
68
|
test.parent.id
|
69
69
|
end
|
70
70
|
|
71
|
-
# @
|
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}'.")
|