inferno_core 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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}'.")
|