inferno_core 0.0.3 → 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/apps/web/controllers/test_runs/create.rb +30 -10
- data/lib/inferno/apps/web/controllers/test_runs/show.rb +10 -0
- data/lib/inferno/apps/web/controllers/test_sessions/create.rb +1 -0
- data/lib/inferno/apps/web/controllers/test_sessions/last_test_run.rb +22 -0
- data/lib/inferno/apps/web/controllers/test_sessions/results/index.rb +6 -1
- data/lib/inferno/apps/web/controllers/test_sessions/session_data/index.rb +21 -0
- data/lib/inferno/apps/web/router.rb +15 -0
- data/lib/inferno/apps/web/serializers/hash_value_extractor.rb +11 -0
- data/lib/inferno/apps/web/serializers/request.rb +1 -0
- data/lib/inferno/apps/web/serializers/result.rb +8 -0
- data/lib/inferno/apps/web/serializers/session_data.rb +10 -0
- data/lib/inferno/apps/web/serializers/test.rb +3 -6
- data/lib/inferno/apps/web/serializers/test_group.rb +5 -8
- data/lib/inferno/apps/web/serializers/test_run.rb +1 -0
- data/lib/inferno/apps/web/serializers/test_session.rb +1 -1
- data/lib/inferno/apps/web/serializers/test_suite.rb +1 -0
- data/lib/inferno/config/application.rb +8 -2
- data/lib/inferno/config/boot/db.rb +3 -2
- data/lib/inferno/config/boot/logging.rb +2 -0
- data/lib/inferno/config/boot/sidekiq.rb +11 -0
- data/lib/inferno/config/boot/suites.rb +4 -6
- data/lib/inferno/config/boot.rb +2 -0
- data/lib/inferno/db/migrations/001_create_initial_structure.rb +0 -21
- data/lib/inferno/db/migrations/002_add_wait_support.rb +7 -0
- data/lib/inferno/db/migrations/003_update_session_data.rb +18 -0
- data/lib/inferno/db/migrations/004_add_request_results_table.rb +9 -0
- data/lib/inferno/db/migrations/005_add_updated_at_index_to_results.rb +5 -0
- data/lib/inferno/db/schema.rb +154 -0
- data/lib/inferno/dsl/assertions.rb +85 -0
- data/lib/inferno/dsl/configurable.rb +126 -0
- data/lib/inferno/dsl/fhir_client.rb +8 -6
- data/lib/inferno/dsl/fhir_client_builder.rb +19 -3
- data/lib/inferno/dsl/fhir_validation.rb +1 -1
- data/lib/inferno/dsl/http_client.rb +14 -12
- data/lib/inferno/dsl/http_client_builder.rb +3 -3
- data/lib/inferno/dsl/request_storage.rb +34 -13
- data/lib/inferno/dsl/results.rb +49 -0
- data/lib/inferno/dsl/resume_test_route.rb +89 -0
- data/lib/inferno/dsl/runnable.rb +183 -28
- data/lib/inferno/dsl.rb +1 -3
- data/lib/inferno/entities/header.rb +14 -7
- data/lib/inferno/entities/message.rb +16 -6
- data/lib/inferno/entities/request.rb +59 -20
- data/lib/inferno/entities/result.rb +45 -22
- data/lib/inferno/entities/session_data.rb +39 -0
- data/lib/inferno/entities/test.rb +48 -8
- data/lib/inferno/entities/test_group.rb +8 -0
- data/lib/inferno/entities/test_run.rb +36 -6
- data/lib/inferno/entities/test_session.rb +17 -11
- data/lib/inferno/entities.rb +1 -1
- data/lib/inferno/exceptions.rb +24 -0
- data/lib/inferno/jobs/execute_test_run.rb +14 -0
- data/lib/inferno/jobs/resume_test_run.rb +14 -0
- data/lib/inferno/jobs.rb +16 -0
- data/lib/inferno/public/bundle.js +1 -1
- data/lib/inferno/repositories/in_memory_repository.rb +1 -1
- data/lib/inferno/repositories/repository.rb +13 -0
- data/lib/inferno/repositories/requests.rb +5 -4
- data/lib/inferno/repositories/results.rb +151 -3
- data/lib/inferno/repositories/session_data.rb +47 -0
- data/lib/inferno/repositories/test_runs.rb +81 -0
- data/lib/inferno/spec_support.rb +1 -1
- data/lib/inferno/test_runner.rb +126 -32
- data/lib/inferno/utils/markdown_formatter.rb +15 -0
- data/lib/inferno/utils/middleware/request_logger.rb +17 -4
- data/lib/inferno/utils/migration.rb +17 -0
- data/lib/inferno/version.rb +1 -1
- data/lib/inferno.rb +4 -4
- data/spec/factories/request.rb +14 -7
- data/spec/factories/result.rb +8 -0
- data/spec/factories/test_run.rb +2 -0
- metadata +84 -7
- data/bin/inferno-console +0 -8
- data/lib/inferno/dsl/fhir_manipulation.rb +0 -25
- data/lib/inferno/entities/test_input.rb +0 -20
@@ -38,13 +38,14 @@ module Inferno
|
|
38
38
|
|
39
39
|
# TODO: do a check in the test runner
|
40
40
|
def named_request(name)
|
41
|
-
requests.find { |request| request.name == name.to_sym }
|
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
|
|
48
|
+
name = self.class.config.request_name(name)
|
48
49
|
request =
|
49
50
|
if response.is_a? FHIR::ClientReply
|
50
51
|
Entities::Request.from_fhir_client_reply(
|
@@ -60,40 +61,60 @@ module Inferno
|
|
60
61
|
request
|
61
62
|
end
|
62
63
|
|
63
|
-
# @
|
64
|
+
# @private
|
64
65
|
def load_named_requests
|
65
66
|
requests_repo = Inferno::Repositories::Requests.new
|
66
67
|
self.class.named_requests_used.map do |request_name|
|
67
|
-
|
68
|
-
|
68
|
+
request_alias = self.class.config.request_name(request_name)
|
69
|
+
request = requests_repo.find_named_request(test_session_id, request_alias)
|
70
|
+
raise StandardError, "Unable to find '#{request_alias}' request" if request.nil?
|
69
71
|
|
70
72
|
requests << request
|
71
73
|
end
|
72
74
|
end
|
73
75
|
|
74
76
|
module ClassMethods
|
75
|
-
# @
|
77
|
+
# @private
|
76
78
|
def named_requests_made
|
77
79
|
@named_requests_made ||= []
|
78
80
|
end
|
79
81
|
|
80
|
-
# @
|
82
|
+
# @private
|
81
83
|
def named_requests_used
|
82
84
|
@named_requests_used ||= []
|
83
85
|
end
|
84
86
|
|
85
87
|
# Specify the named requests made by a test
|
86
88
|
#
|
87
|
-
# @param
|
88
|
-
def makes_request(*
|
89
|
-
named_requests_made.concat(
|
89
|
+
# @param identifiers [Symbol] one or more request identifiers
|
90
|
+
def makes_request(*identifiers)
|
91
|
+
named_requests_made.concat(identifiers).uniq!
|
92
|
+
identifiers.each do |identifier|
|
93
|
+
config.add_request(identifier)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Specify the name for a request received by a test
|
98
|
+
#
|
99
|
+
# @param identifier [Symbol]
|
100
|
+
def receives_request(identifier)
|
101
|
+
config.add_request(identifier)
|
102
|
+
@incoming_request_name = identifier
|
103
|
+
end
|
104
|
+
|
105
|
+
# @private
|
106
|
+
def incoming_request_name
|
107
|
+
@incoming_request_name
|
90
108
|
end
|
91
109
|
|
92
110
|
# Specify the named requests used by a test
|
93
111
|
#
|
94
|
-
# @param
|
95
|
-
def uses_request(*
|
96
|
-
named_requests_used.concat(
|
112
|
+
# @param identifiers [Symbol] one or more request identifiers
|
113
|
+
def uses_request(*identifiers)
|
114
|
+
named_requests_used.concat(identifiers).uniq!
|
115
|
+
identifiers.each do |identifier|
|
116
|
+
config.add_request(identifier)
|
117
|
+
end
|
97
118
|
end
|
98
119
|
end
|
99
120
|
end
|
data/lib/inferno/dsl/results.rb
CHANGED
@@ -49,6 +49,55 @@ module Inferno
|
|
49
49
|
def omit_if(test, message = '')
|
50
50
|
raise Exceptions::OmitException, message if test
|
51
51
|
end
|
52
|
+
|
53
|
+
# Halt execution of the current test and wait for execution to resume.
|
54
|
+
#
|
55
|
+
# @see Inferno::DSL::Runnable#resume_test_route
|
56
|
+
# @example
|
57
|
+
# resume_test_route :get, '/launch' do
|
58
|
+
# request.query_parameters['iss']
|
59
|
+
# end
|
60
|
+
#
|
61
|
+
# test do
|
62
|
+
# input :issuer
|
63
|
+
# receives_request :launch
|
64
|
+
#
|
65
|
+
# run do
|
66
|
+
# wait(
|
67
|
+
# identifier: issuer,
|
68
|
+
# message: "Wating to receive a request with an issuer of #{issuer}"
|
69
|
+
# )
|
70
|
+
# end
|
71
|
+
# end
|
72
|
+
# @param identifier [String] An identifier which can uniquely identify
|
73
|
+
# this test run based on an incoming request. This is necessary so that
|
74
|
+
# the correct test run can be resumed.
|
75
|
+
# @param message [String]
|
76
|
+
# @param timeout [Integer] Number of seconds to wait for an incoming
|
77
|
+
# request
|
78
|
+
def wait(identifier:, message: '', timeout: 300)
|
79
|
+
identifier(identifier)
|
80
|
+
wait_timeout(timeout)
|
81
|
+
|
82
|
+
raise Exceptions::WaitException, message
|
83
|
+
end
|
84
|
+
|
85
|
+
def identifier(identifier = nil)
|
86
|
+
@identifier ||= identifier
|
87
|
+
end
|
88
|
+
|
89
|
+
def wait_timeout(timeout = nil)
|
90
|
+
@wait_timeout ||= timeout
|
91
|
+
end
|
92
|
+
|
93
|
+
# Halt execution of the current test. This provided for testing purposes
|
94
|
+
# and should not be used in real tests.
|
95
|
+
#
|
96
|
+
# @param message [String]
|
97
|
+
# @private
|
98
|
+
def cancel(message = '')
|
99
|
+
raise Exceptions::CancelException, message
|
100
|
+
end
|
52
101
|
end
|
53
102
|
end
|
54
103
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'hanami-controller'
|
2
|
+
|
3
|
+
module Inferno
|
4
|
+
module DSL
|
5
|
+
# A base class for creating routes to resume test execution upon receiving
|
6
|
+
# an incoming request.
|
7
|
+
# @private
|
8
|
+
# @see Inferno::DSL::Runnable#resume_test_route
|
9
|
+
class ResumeTestRoute
|
10
|
+
include Hanami::Action
|
11
|
+
include Import[
|
12
|
+
requests_repo: 'repositories.requests',
|
13
|
+
results_repo: 'repositories.results',
|
14
|
+
test_runs_repo: 'repositories.test_runs',
|
15
|
+
tests_repo: 'repositories.tests'
|
16
|
+
]
|
17
|
+
|
18
|
+
def self.call(params)
|
19
|
+
new.call(params)
|
20
|
+
end
|
21
|
+
|
22
|
+
# The incoming request
|
23
|
+
#
|
24
|
+
# @return [Inferno::Entities::Request]
|
25
|
+
def request
|
26
|
+
@request ||= Inferno::Entities::Request.from_rack_env(@params.env)
|
27
|
+
end
|
28
|
+
|
29
|
+
# @private
|
30
|
+
def test_run
|
31
|
+
@test_run ||=
|
32
|
+
test_runs_repo.find_latest_waiting_by_identifier(test_run_identifier)
|
33
|
+
end
|
34
|
+
|
35
|
+
# @private
|
36
|
+
def waiting_result
|
37
|
+
@waiting_result ||= results_repo.find_waiting_result(test_run_id: test_run.id)
|
38
|
+
end
|
39
|
+
|
40
|
+
# @private
|
41
|
+
def update_result
|
42
|
+
results_repo.pass_waiting_result(waiting_result.id)
|
43
|
+
end
|
44
|
+
|
45
|
+
# @private
|
46
|
+
def persist_request
|
47
|
+
requests_repo.create(
|
48
|
+
request.to_hash.merge(
|
49
|
+
test_session_id: test_run.test_session_id,
|
50
|
+
result_id: waiting_result.id,
|
51
|
+
name: test.config.request_name(test.incoming_request_name)
|
52
|
+
)
|
53
|
+
)
|
54
|
+
end
|
55
|
+
|
56
|
+
# @private
|
57
|
+
def redirect_route
|
58
|
+
"/test_sessions/#{test_run.test_session_id}##{waiting_group_id}"
|
59
|
+
end
|
60
|
+
|
61
|
+
# @private
|
62
|
+
def test
|
63
|
+
@test ||= tests_repo.find(waiting_result.test_id)
|
64
|
+
end
|
65
|
+
|
66
|
+
# @private
|
67
|
+
def waiting_group_id
|
68
|
+
test.parent.id
|
69
|
+
end
|
70
|
+
|
71
|
+
# @private
|
72
|
+
def call(_params)
|
73
|
+
if test_run.nil?
|
74
|
+
status(500, "Unable to find test run with identifier '#{test_run_identifier}'.")
|
75
|
+
return
|
76
|
+
end
|
77
|
+
|
78
|
+
test_runs_repo.mark_as_no_longer_waiting(test_run.id)
|
79
|
+
|
80
|
+
update_result
|
81
|
+
persist_request
|
82
|
+
|
83
|
+
Jobs.perform(Jobs::ResumeTestRun, test_run.id)
|
84
|
+
|
85
|
+
redirect_to redirect_route
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/lib/inferno/dsl/runnable.rb
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
require_relative 'configurable'
|
2
|
+
require_relative 'resume_test_route'
|
3
|
+
require_relative '../utils/markdown_formatter'
|
4
|
+
|
1
5
|
module Inferno
|
2
6
|
module DSL
|
3
7
|
# This module contains the DSL for defining child entities in the test
|
@@ -5,14 +9,17 @@ module Inferno
|
|
5
9
|
module Runnable
|
6
10
|
attr_accessor :parent
|
7
11
|
|
12
|
+
include Inferno::Utils::MarkdownFormatter
|
13
|
+
|
8
14
|
# When a class (e.g. TestSuite/TestGroup) uses this module, set it up
|
9
15
|
# so that subclassing it works correctly.
|
10
16
|
# - add the subclass to the relevant repository when it is created
|
11
17
|
# - copy the class instance variables from the superclass
|
12
18
|
# - add a hook to the subclass so that its subclasses do the same
|
13
|
-
# @
|
19
|
+
# @private
|
14
20
|
def self.extended(extending_class)
|
15
21
|
super
|
22
|
+
extending_class.extend Configurable
|
16
23
|
|
17
24
|
extending_class.define_singleton_method(:inherited) do |subclass|
|
18
25
|
copy_instance_variables(subclass)
|
@@ -34,14 +41,16 @@ module Inferno
|
|
34
41
|
# classes. When inheriting from a Runnable class, these class instance
|
35
42
|
# variables need to be copied. Any child Runnable classes will themselves
|
36
43
|
# need to be subclassed so that their parent can be updated.
|
37
|
-
# @
|
44
|
+
# @private
|
38
45
|
def copy_instance_variables(subclass)
|
39
46
|
instance_variables.each do |variable|
|
40
|
-
next if [:@id, :@groups, :@tests, :@parent, :@children].include?(variable)
|
47
|
+
next if [:@id, :@groups, :@tests, :@parent, :@children, :@test_count, :@config].include?(variable)
|
41
48
|
|
42
49
|
subclass.instance_variable_set(variable, instance_variable_get(variable).dup)
|
43
50
|
end
|
44
51
|
|
52
|
+
subclass.config(config)
|
53
|
+
|
45
54
|
child_types.each do |child_type|
|
46
55
|
new_children = send(child_type).map do |child|
|
47
56
|
Class.new(child).tap do |subclass_child|
|
@@ -54,12 +63,13 @@ module Inferno
|
|
54
63
|
end
|
55
64
|
end
|
56
65
|
|
57
|
-
# @
|
66
|
+
# @private
|
58
67
|
def add_self_to_repository
|
59
68
|
repository.insert(self)
|
60
69
|
end
|
61
70
|
|
62
71
|
# An instance of the repository for the class using this module
|
72
|
+
# @private
|
63
73
|
def repository
|
64
74
|
nil
|
65
75
|
end
|
@@ -67,7 +77,7 @@ module Inferno
|
|
67
77
|
# This method defines a child entity. Classes using this module should
|
68
78
|
# alias the method name they wish to use to define child entities to this
|
69
79
|
# method.
|
70
|
-
# @
|
80
|
+
# @private
|
71
81
|
def define_child(*args, &block)
|
72
82
|
hash_args = process_args(args)
|
73
83
|
|
@@ -87,7 +97,7 @@ module Inferno
|
|
87
97
|
klass
|
88
98
|
end
|
89
99
|
|
90
|
-
# @
|
100
|
+
# @private
|
91
101
|
def process_args(args)
|
92
102
|
hash_args =
|
93
103
|
if args[0].is_a? Hash
|
@@ -103,13 +113,13 @@ module Inferno
|
|
103
113
|
hash_args
|
104
114
|
end
|
105
115
|
|
106
|
-
# @
|
116
|
+
# @private
|
107
117
|
def child_metadata(metadata = nil)
|
108
118
|
@child_metadata = metadata if metadata
|
109
119
|
@child_metadata
|
110
120
|
end
|
111
121
|
|
112
|
-
# @
|
122
|
+
# @private
|
113
123
|
def create_child_class(hash_args)
|
114
124
|
superclass_id = hash_args.delete :from
|
115
125
|
|
@@ -122,18 +132,18 @@ module Inferno
|
|
122
132
|
Class.new(superclass)
|
123
133
|
end
|
124
134
|
|
125
|
-
# @
|
135
|
+
# @private
|
126
136
|
def configure_child_class(klass, hash_args) # rubocop:disable Metrics/CyclomaticComplexity
|
127
|
-
inputs.each do |
|
128
|
-
next if klass.inputs.
|
137
|
+
inputs.each do |name|
|
138
|
+
next if klass.inputs.any? { |klass_input_name| klass_input_name == name }
|
129
139
|
|
130
|
-
klass.input
|
140
|
+
klass.input name
|
131
141
|
end
|
132
142
|
|
133
|
-
outputs.each do |
|
134
|
-
next if klass.outputs.include?
|
143
|
+
outputs.each do |output_name|
|
144
|
+
next if klass.outputs.include? output_name
|
135
145
|
|
136
|
-
klass.output
|
146
|
+
klass.output output_name
|
137
147
|
end
|
138
148
|
|
139
149
|
new_fhir_client_definitions = klass.instance_variable_get(:@fhir_client_definitions) || {}
|
@@ -152,8 +162,14 @@ module Inferno
|
|
152
162
|
end
|
153
163
|
klass.instance_variable_set(:@http_client_definitions, new_http_client_definitions)
|
154
164
|
|
165
|
+
klass.config(config)
|
166
|
+
|
155
167
|
hash_args.each do |key, value|
|
156
|
-
|
168
|
+
if value.is_a? Array
|
169
|
+
klass.send(key, *value)
|
170
|
+
else
|
171
|
+
klass.send(key, value)
|
172
|
+
end
|
157
173
|
end
|
158
174
|
|
159
175
|
klass.children.each do |child_class|
|
@@ -162,11 +178,15 @@ module Inferno
|
|
162
178
|
end
|
163
179
|
end
|
164
180
|
|
165
|
-
# @
|
181
|
+
# @private
|
166
182
|
def handle_child_definition_block(klass, &block)
|
167
183
|
klass.class_eval(&block) if block_given?
|
168
184
|
end
|
169
185
|
|
186
|
+
# Set/Get a runnable's id
|
187
|
+
#
|
188
|
+
# @param new_id [String,Symbol]
|
189
|
+
# @return [String,Symbol] the id
|
170
190
|
def id(new_id = nil)
|
171
191
|
return @id if new_id.nil? && @id.present?
|
172
192
|
|
@@ -182,53 +202,93 @@ module Inferno
|
|
182
202
|
@id = "#{prefix}#{@base_id}"
|
183
203
|
end
|
184
204
|
|
205
|
+
# Set/Get a runnable's title
|
206
|
+
#
|
207
|
+
# @param new_title [String]
|
208
|
+
# @return [String] the title
|
185
209
|
def title(new_title = nil)
|
186
210
|
return @title if new_title.nil?
|
187
211
|
|
188
212
|
@title = new_title
|
189
213
|
end
|
190
214
|
|
215
|
+
# Set/Get a runnable's description
|
216
|
+
#
|
217
|
+
# @param new_description [String]
|
218
|
+
# @return [String] the description
|
191
219
|
def description(new_description = nil)
|
192
220
|
return @description if new_description.nil?
|
193
221
|
|
194
|
-
@description = new_description
|
222
|
+
@description = format_markdown(new_description)
|
195
223
|
end
|
196
224
|
|
197
225
|
# Define inputs
|
198
226
|
#
|
199
|
-
# @param
|
227
|
+
# @param identifier [Symbol] identifier for the input
|
228
|
+
# @param other_identifiers [Symbol] array of symbols if specifying multiple inputs
|
229
|
+
# @param input_definition [Hash] options for input such as type, description, or title
|
230
|
+
# @option input_definition [String] :title Human readable title for input
|
231
|
+
# @option input_definition [String] :description Description for the input
|
232
|
+
# @option input_definition [String] :type text | textarea
|
233
|
+
# @option input_definition [String] :default The default value for the input
|
234
|
+
# @option input_definition [Boolean] :optional Set to true to not require input for test execution
|
200
235
|
# @return [void]
|
201
236
|
# @example
|
202
|
-
# input :
|
203
|
-
|
204
|
-
|
237
|
+
# input :patientid, title: 'Patient ID', description: 'The ID of the patient being searched for',
|
238
|
+
# default: 'default_patient_id'
|
239
|
+
# @example
|
240
|
+
# input :textarea, title: 'Textarea Input Example', type: 'textarea', optional: true
|
241
|
+
def input(identifier, *other_identifiers, **input_definition)
|
242
|
+
if other_identifiers.present?
|
243
|
+
[identifier, *other_identifiers].compact.each do |input_identifier|
|
244
|
+
inputs << input_identifier
|
245
|
+
config.add_input(input_identifier)
|
246
|
+
end
|
247
|
+
else
|
248
|
+
inputs << identifier
|
249
|
+
config.add_input(identifier, input_definition)
|
250
|
+
end
|
205
251
|
end
|
206
252
|
|
207
253
|
# Define outputs
|
208
254
|
#
|
209
|
-
# @param
|
255
|
+
# @param output_list [Symbol]
|
210
256
|
# @return [void]
|
211
257
|
# @example
|
212
258
|
# output :patient_id, :bearer_token
|
213
|
-
def output(*
|
214
|
-
|
259
|
+
def output(*output_list)
|
260
|
+
output_list.each do |output_identifier|
|
261
|
+
outputs << output_identifier
|
262
|
+
config.add_output(output_identifier)
|
263
|
+
end
|
215
264
|
end
|
216
265
|
|
217
|
-
# @
|
266
|
+
# @private
|
218
267
|
def default_id
|
219
268
|
to_s
|
220
269
|
end
|
221
270
|
|
222
|
-
# @
|
271
|
+
# @private
|
223
272
|
def inputs
|
224
273
|
@inputs ||= []
|
225
274
|
end
|
226
275
|
|
227
|
-
# @
|
276
|
+
# @private
|
277
|
+
def input_definitions
|
278
|
+
config.inputs.slice(*inputs)
|
279
|
+
end
|
280
|
+
|
281
|
+
# @private
|
282
|
+
def output_definitions
|
283
|
+
config.outputs.slice(*outputs)
|
284
|
+
end
|
285
|
+
|
286
|
+
# @private
|
228
287
|
def outputs
|
229
288
|
@outputs ||= []
|
230
289
|
end
|
231
290
|
|
291
|
+
# @private
|
232
292
|
def child_types
|
233
293
|
return [] if ancestors.include? Inferno::Entities::Test
|
234
294
|
return [:groups] if ancestors.include? Inferno::Entities::TestSuite
|
@@ -236,6 +296,7 @@ module Inferno
|
|
236
296
|
[:groups, :tests]
|
237
297
|
end
|
238
298
|
|
299
|
+
# @private
|
239
300
|
def children
|
240
301
|
@children ||= []
|
241
302
|
end
|
@@ -245,6 +306,100 @@ module Inferno
|
|
245
306
|
|
246
307
|
@validator_url = url
|
247
308
|
end
|
309
|
+
|
310
|
+
# @private
|
311
|
+
def suite
|
312
|
+
return self if ancestors.include? Inferno::Entities::TestSuite
|
313
|
+
|
314
|
+
parent.suite
|
315
|
+
end
|
316
|
+
|
317
|
+
# Create a route which will resume a test run when a request is received
|
318
|
+
#
|
319
|
+
# @see Inferno::DSL::Results#wait
|
320
|
+
# @example
|
321
|
+
# resume_test_route :get, '/launch' do
|
322
|
+
# request.query_parameters['iss']
|
323
|
+
# end
|
324
|
+
#
|
325
|
+
# test do
|
326
|
+
# input :issuer
|
327
|
+
# receives_request :launch
|
328
|
+
#
|
329
|
+
# run do
|
330
|
+
# wait(
|
331
|
+
# identifier: issuer,
|
332
|
+
# message: "Wating to receive a request with an issuer of #{issuer}"
|
333
|
+
# )
|
334
|
+
# end
|
335
|
+
# end
|
336
|
+
#
|
337
|
+
# @param method [Symbol] the HTTP request type (:get, :post, etc.) for the
|
338
|
+
# incoming request
|
339
|
+
# @param path [String] the path for this request. The route will be served
|
340
|
+
# with a prefix of `/custom/TEST_SUITE_ID` to prevent path conflicts.
|
341
|
+
# [Any of the path options available in Hanami
|
342
|
+
# Router](https://github.com/hanami/router/tree/f41001d4c3ee9e2d2c7bb142f74b43f8e1d3a265#a-beautiful-dsl)
|
343
|
+
# can be used here.
|
344
|
+
# @yield This method takes a block which must return the identifier
|
345
|
+
# defined when a test was set to wait for the test run that hit this
|
346
|
+
# route. The block has access to the `request` method which returns a
|
347
|
+
# {Inferno::Entities::Request} object with the information for the
|
348
|
+
# incoming request.
|
349
|
+
def resume_test_route(method, path, &block)
|
350
|
+
route_class = Class.new(ResumeTestRoute) do
|
351
|
+
define_method(:test_run_identifier, &block)
|
352
|
+
define_method(:request_name, -> { options[:name] })
|
353
|
+
end
|
354
|
+
|
355
|
+
route(method, path, route_class)
|
356
|
+
end
|
357
|
+
|
358
|
+
# Create a route to handle a request
|
359
|
+
#
|
360
|
+
# @param method [Symbol] the HTTP request type (:get, :post, etc.) for the
|
361
|
+
# incoming request. `:all` will accept all HTTP request types.
|
362
|
+
# @param path [String] the path for this request. The route will be served
|
363
|
+
# with a prefix of `/custom/TEST_SUITE_ID` to prevent path conflicts.
|
364
|
+
# [Any of the path options available in Hanami
|
365
|
+
# Router](https://github.com/hanami/router/tree/f41001d4c3ee9e2d2c7bb142f74b43f8e1d3a265#a-beautiful-dsl)
|
366
|
+
# can be used here.
|
367
|
+
# @param handler [#call] the route handler. This can be any Rack
|
368
|
+
# compatible object (e.g. a `Proc` object, a [Sinatra
|
369
|
+
# app](http://sinatrarb.com/)) as described in the [Hanami Router
|
370
|
+
# documentation.](https://github.com/hanami/router/tree/f41001d4c3ee9e2d2c7bb142f74b43f8e1d3a265#mount-rack-applications)
|
371
|
+
def route(method, path, handler)
|
372
|
+
Inferno.routes << { method: method, path: path, handler: handler, suite: suite }
|
373
|
+
end
|
374
|
+
|
375
|
+
# @private
|
376
|
+
def test_count
|
377
|
+
@test_count ||= children&.reduce(0) { |sum, child| sum + child.test_count } || 0
|
378
|
+
end
|
379
|
+
|
380
|
+
# @private
|
381
|
+
def required_inputs(prior_outputs = [])
|
382
|
+
required_inputs = inputs.select do |input|
|
383
|
+
!input_definitions[input][:optional] && !prior_outputs.include?(input)
|
384
|
+
end
|
385
|
+
required_inputs.map! { |input_identifier| input_definitions[input_identifier][:name] }
|
386
|
+
children_required_inputs = children.flat_map { |child| child.required_inputs(prior_outputs) }
|
387
|
+
prior_outputs.concat(outputs)
|
388
|
+
(required_inputs + children_required_inputs).flatten.uniq
|
389
|
+
end
|
390
|
+
|
391
|
+
# @private
|
392
|
+
def missing_inputs(submitted_inputs)
|
393
|
+
submitted_inputs = [] if submitted_inputs.nil?
|
394
|
+
|
395
|
+
required_inputs.map(&:to_s) - submitted_inputs.map { |input| input[:name] }
|
396
|
+
end
|
397
|
+
|
398
|
+
def user_runnable?
|
399
|
+
@user_runnable ||= parent.nil? ||
|
400
|
+
!parent.respond_to?(:run_as_group?) ||
|
401
|
+
(parent.user_runnable? && !parent.run_as_group?)
|
402
|
+
end
|
248
403
|
end
|
249
404
|
end
|
250
405
|
end
|
data/lib/inferno/dsl.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require_relative 'dsl/assertions'
|
2
2
|
require_relative 'dsl/fhir_client'
|
3
|
-
require_relative 'dsl/fhir_manipulation'
|
4
3
|
require_relative 'dsl/fhir_validation'
|
5
4
|
require_relative 'dsl/http_client'
|
6
5
|
require_relative 'dsl/results'
|
@@ -14,8 +13,7 @@ module Inferno
|
|
14
13
|
FHIRClient,
|
15
14
|
HTTPClient,
|
16
15
|
Results,
|
17
|
-
FHIRValidation
|
18
|
-
FHIRManipulation
|
16
|
+
FHIRValidation
|
19
17
|
].freeze
|
20
18
|
|
21
19
|
EXTENDABLE_DSL_MODULES = [
|
@@ -2,13 +2,20 @@ module Inferno
|
|
2
2
|
module Entities
|
3
3
|
# A `Header` represents an HTTP request/response header
|
4
4
|
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
5
|
+
# @!attribute id
|
6
|
+
# @return [String] id of the header
|
7
|
+
# @!attribute request_id
|
8
|
+
# @return [String] index of the HTTP request
|
9
|
+
# @!attribute name
|
10
|
+
# @return [String] header name
|
11
|
+
# @!attribute value
|
12
|
+
# @return [String] header value
|
13
|
+
# @!attribute type
|
14
|
+
# @return [String] request/response
|
15
|
+
# @!attribute created_at
|
16
|
+
# @return [Time]
|
17
|
+
# @!attribute updated_at
|
18
|
+
# @return [Time]
|
12
19
|
class Header < Entity
|
13
20
|
ATTRIBUTES = [:id, :request_id, :name, :type, :value, :created_at, :updated_at].freeze
|
14
21
|
|
@@ -2,12 +2,22 @@ module Inferno
|
|
2
2
|
module Entities
|
3
3
|
# A `Message` represents a message generated during a test.
|
4
4
|
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
5
|
+
# @!attribute id
|
6
|
+
# @return [String] id of the message
|
7
|
+
# @!attribute index
|
8
|
+
# @return [String] index of the message. Used for ordering.
|
9
|
+
# @!attribute result_id
|
10
|
+
# @return [String]
|
11
|
+
# @!attribute result
|
12
|
+
# @return [Inferno::Entities::Result]
|
13
|
+
# @!attribute type
|
14
|
+
# @return [String]
|
15
|
+
# @!attribute message
|
16
|
+
# @return [String]
|
17
|
+
# @!attribute created_at
|
18
|
+
# @return [Time]
|
19
|
+
# @!attribute updated_at
|
20
|
+
# @return [Time]
|
11
21
|
class Message < Entity
|
12
22
|
ATTRIBUTES = [:id, :index, :message, :result_id, :result, :type, :created_at, :updated_at].freeze
|
13
23
|
TYPES = ['error', 'warning', 'info'].freeze
|