nonnative 2.1.0 → 2.8.0
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/.circleci/config.yml +5 -4
- data/AGENTS.md +86 -202
- data/Gemfile.lock +21 -20
- data/README.md +21 -12
- data/lib/nonnative/configuration.rb +11 -10
- data/lib/nonnative/configuration_proxy.rb +13 -1
- data/lib/nonnative/cucumber.rb +199 -103
- data/lib/nonnative/http_proxy_server.rb +36 -9
- data/lib/nonnative/pool.rb +114 -23
- data/lib/nonnative/process.rb +2 -1
- data/lib/nonnative/version.rb +1 -1
- data/lib/nonnative.rb +59 -15
- metadata +1 -1
|
@@ -20,7 +20,8 @@ module Nonnative
|
|
|
20
20
|
# @return [String, nil] path to proxy log file (implementation-dependent)
|
|
21
21
|
# @return [Numeric] wait interval (seconds) after proxy state changes (defaults to `0.1`)
|
|
22
22
|
# @return [Hash] proxy implementation options (implementation-dependent)
|
|
23
|
-
attr_accessor :kind, :host, :port, :log, :wait
|
|
23
|
+
attr_accessor :kind, :host, :port, :log, :wait
|
|
24
|
+
attr_reader :options
|
|
24
25
|
|
|
25
26
|
# Creates a proxy configuration with defaults.
|
|
26
27
|
#
|
|
@@ -39,5 +40,16 @@ module Nonnative
|
|
|
39
40
|
self.wait = 0.1
|
|
40
41
|
self.options = {}
|
|
41
42
|
end
|
|
43
|
+
|
|
44
|
+
# Stores proxy implementation options.
|
|
45
|
+
#
|
|
46
|
+
# Nil is normalized to an empty hash so callers loading partial configuration do not erase the
|
|
47
|
+
# default options container.
|
|
48
|
+
#
|
|
49
|
+
# @param value [Hash, nil]
|
|
50
|
+
# @return [void]
|
|
51
|
+
def options=(value)
|
|
52
|
+
@options = value || {}
|
|
53
|
+
end
|
|
42
54
|
end
|
|
43
55
|
end
|
data/lib/nonnative/cucumber.rb
CHANGED
|
@@ -1,105 +1,201 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
Given('I
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
3
|
+
require 'cucumber'
|
|
4
|
+
|
|
5
|
+
module Nonnative
|
|
6
|
+
# Lazily installs the Cucumber integration once the Cucumber Ruby DSL is ready.
|
|
7
|
+
#
|
|
8
|
+
# Requiring `nonnative` outside a running Cucumber environment should not fail, but when Cucumber
|
|
9
|
+
# does finish booting its support-code registry this installer still needs to register the hooks
|
|
10
|
+
# and step definitions defined here.
|
|
11
|
+
module Cucumber
|
|
12
|
+
module LanguageHook
|
|
13
|
+
def rb_language=(value)
|
|
14
|
+
super.tap { ::Nonnative::Cucumber.install! }
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
module WorldHooks
|
|
19
|
+
def install_world
|
|
20
|
+
World(::RSpec::Benchmark::Matchers)
|
|
21
|
+
World(::RSpec::Matchers)
|
|
22
|
+
World(::RSpec::Wait)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def install_hooks
|
|
26
|
+
Before('@startup') { Nonnative.start }
|
|
27
|
+
After('@startup') { Nonnative.stop }
|
|
28
|
+
After('@manual') { Nonnative.stop }
|
|
29
|
+
Before('@clear') { Nonnative.clear }
|
|
30
|
+
After('@reset') { Nonnative.reset }
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
module ProxySteps
|
|
35
|
+
def install_proxy_steps
|
|
36
|
+
install_proxy_mutation_steps
|
|
37
|
+
install_proxy_reset_steps
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def install_proxy_mutation_steps
|
|
41
|
+
Given('I set the proxy for process {string} to {string}') do |name, operation|
|
|
42
|
+
process = Nonnative.pool.process_by_name(name)
|
|
43
|
+
process.proxy.send(operation)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
Given('I set the proxy for server {string} to {string}') do |name, operation|
|
|
47
|
+
server = Nonnative.pool.server_by_name(name)
|
|
48
|
+
server.proxy.send(operation)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
Given('I set the proxy for service {string} to {string}') do |name, operation|
|
|
52
|
+
service = Nonnative.pool.service_by_name(name)
|
|
53
|
+
service.proxy.send(operation)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def install_proxy_reset_steps
|
|
58
|
+
Then('I should reset the proxy for process {string}') do |name|
|
|
59
|
+
process = Nonnative.pool.process_by_name(name)
|
|
60
|
+
process.proxy.reset
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
Then('I should reset the proxy for server {string}') do |name|
|
|
64
|
+
server = Nonnative.pool.server_by_name(name)
|
|
65
|
+
server.proxy.reset
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
Then('I should reset the proxy for service {string}') do |name|
|
|
69
|
+
service = Nonnative.pool.service_by_name(name)
|
|
70
|
+
service.proxy.reset
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
module LifecycleSteps
|
|
76
|
+
def install_state_steps
|
|
77
|
+
install_start_step
|
|
78
|
+
install_unhealthy_step
|
|
79
|
+
install_healthy_step
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def install_start_step
|
|
83
|
+
Given('I start the system') do
|
|
84
|
+
Nonnative.start
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def install_unhealthy_step
|
|
89
|
+
opts = observability_options
|
|
90
|
+
|
|
91
|
+
Given('I should see {string} as unhealthy') do |service|
|
|
92
|
+
wait_for { Nonnative.observability.health(opts).code }.to eq(503)
|
|
93
|
+
wait_for { Nonnative.observability.health(opts).body }.to include(service)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def install_healthy_step
|
|
98
|
+
opts = observability_options
|
|
99
|
+
|
|
100
|
+
Then('I should see {string} as healthy') do |service|
|
|
101
|
+
wait_for { Nonnative.observability.health(opts).code }.to eq(200)
|
|
102
|
+
wait_for { Nonnative.observability.health(opts).body }.to_not include(service)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def observability_options
|
|
107
|
+
{
|
|
108
|
+
headers: { content_type: :json, accept: :json },
|
|
109
|
+
read_timeout: 10,
|
|
110
|
+
open_timeout: 10
|
|
111
|
+
}
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
module Assertions
|
|
116
|
+
def install_assertion_steps
|
|
117
|
+
install_memory_assertion_step
|
|
118
|
+
install_error_assertion_steps
|
|
119
|
+
install_log_assertion_steps
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def install_memory_assertion_step
|
|
123
|
+
Then('the process {string} should consume less than {string} of memory') do |name, mem|
|
|
124
|
+
process = Nonnative.pool.process_by_name(name)
|
|
125
|
+
_, size, type = mem.split(/(\d+)/)
|
|
126
|
+
actual = process.memory.send(type)
|
|
127
|
+
size = size.to_i
|
|
128
|
+
|
|
129
|
+
expect(actual).to be < size
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def install_error_assertion_steps
|
|
134
|
+
Then('starting the system should raise an error') do
|
|
135
|
+
expect { Nonnative.start }.to raise_error(Nonnative::StartError)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
Then('stopping the system should raise an error') do
|
|
139
|
+
expect { Nonnative.stop }.to raise_error(Nonnative::StopError)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def install_log_assertion_steps
|
|
144
|
+
Then('I should see a log entry of {string} for process {string}') do |message, process|
|
|
145
|
+
process = Nonnative.configuration.process_by_name(process)
|
|
146
|
+
expect(Nonnative.log_lines(process.log, ->(l) { l.include?(message) }).first).to include(message)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
Then('I should see a log entry of {string} in the file {string}') do |message, path|
|
|
150
|
+
expect(Nonnative.log_lines(path, ->(l) { l.include?(message) }).first).to include(message)
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
module Registration
|
|
156
|
+
extend ::Cucumber::Glue::Dsl
|
|
157
|
+
extend WorldHooks
|
|
158
|
+
extend ProxySteps
|
|
159
|
+
extend LifecycleSteps
|
|
160
|
+
extend Assertions
|
|
161
|
+
|
|
162
|
+
class << self
|
|
163
|
+
def install!
|
|
164
|
+
install_world
|
|
165
|
+
install_hooks
|
|
166
|
+
install_proxy_steps
|
|
167
|
+
install_state_steps
|
|
168
|
+
install_assertion_steps
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
class << self
|
|
174
|
+
def bootstrap!
|
|
175
|
+
return if @bootstrapped
|
|
176
|
+
|
|
177
|
+
dsl_singleton = ::Cucumber::Glue::Dsl.singleton_class
|
|
178
|
+
dsl_singleton.prepend(LanguageHook) unless dsl_singleton.ancestors.include?(LanguageHook)
|
|
179
|
+
|
|
180
|
+
@bootstrapped = true
|
|
181
|
+
install!
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def install!
|
|
185
|
+
return if @installed
|
|
186
|
+
return unless ready?
|
|
187
|
+
|
|
188
|
+
Registration.install!
|
|
189
|
+
@installed = true
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
private
|
|
193
|
+
|
|
194
|
+
def ready?
|
|
195
|
+
!::Cucumber::Glue::Dsl.instance_variable_get(:@rb_language).nil?
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
Nonnative::Cucumber.bootstrap!
|
|
@@ -30,10 +30,11 @@ module Nonnative
|
|
|
30
30
|
# @param request [Sinatra::Request] the incoming request
|
|
31
31
|
# @return [Hash{String=>String}] headers to forward to the upstream
|
|
32
32
|
def retrieve_headers(request)
|
|
33
|
-
headers = request.env.
|
|
34
|
-
|
|
33
|
+
headers = request.env.each_with_object({}) do |(header, value), result|
|
|
34
|
+
next unless forward_header?(header)
|
|
35
|
+
|
|
36
|
+
result[normalized_header_name(header)] = value
|
|
35
37
|
end
|
|
36
|
-
headers = headers.compact.to_h
|
|
37
38
|
|
|
38
39
|
headers.except('Host', 'Accept-Encoding', 'Version')
|
|
39
40
|
end
|
|
@@ -53,19 +54,45 @@ module Nonnative
|
|
|
53
54
|
# @param uri [String] upstream URI
|
|
54
55
|
# @param opts [Hash] RestClient options (e.g. headers)
|
|
55
56
|
# @return [RestClient::Response] response for error statuses, otherwise RestClient return value
|
|
56
|
-
def api_response(
|
|
57
|
-
|
|
57
|
+
def api_response(method:, url:, headers:, payload: nil)
|
|
58
|
+
options = { method:, url:, headers: }
|
|
59
|
+
options[:payload] = payload unless payload.nil?
|
|
58
60
|
|
|
59
|
-
|
|
61
|
+
RestClient::Request.execute(options)
|
|
60
62
|
rescue RestClient::Exception => e
|
|
61
63
|
e.response
|
|
62
64
|
end
|
|
63
65
|
|
|
66
|
+
# Extracts the request payload for verbs that can carry a body.
|
|
67
|
+
#
|
|
68
|
+
# @param request [Sinatra::Request] the incoming request
|
|
69
|
+
# @param verb [String] HTTP verb name (e.g. `"post"`)
|
|
70
|
+
# @return [String, nil] request payload for body-carrying verbs
|
|
71
|
+
def retrieve_payload(request, verb)
|
|
72
|
+
return unless %w[post put patch delete].include?(verb)
|
|
73
|
+
|
|
74
|
+
payload = request.body.read
|
|
75
|
+
payload unless payload.empty?
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
private
|
|
79
|
+
|
|
80
|
+
def forward_header?(header)
|
|
81
|
+
header.start_with?('HTTP_') || %w[CONTENT_TYPE CONTENT_LENGTH].include?(header)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def normalized_header_name(header)
|
|
85
|
+
header.delete_prefix('HTTP_').split('_').map(&:capitalize).join('-')
|
|
86
|
+
end
|
|
87
|
+
|
|
64
88
|
%w[get post put patch delete].each do |verb|
|
|
65
89
|
send(verb, /.*/) do
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
90
|
+
res = api_response(
|
|
91
|
+
method: verb.to_sym,
|
|
92
|
+
url: build_url(request, settings),
|
|
93
|
+
headers: retrieve_headers(request),
|
|
94
|
+
payload: retrieve_payload(request, verb)
|
|
95
|
+
)
|
|
69
96
|
|
|
70
97
|
status res.code
|
|
71
98
|
res.body
|
data/lib/nonnative/pool.rb
CHANGED
|
@@ -18,6 +18,9 @@ module Nonnative
|
|
|
18
18
|
# @param configuration [Nonnative::Configuration] the configuration to run
|
|
19
19
|
def initialize(configuration)
|
|
20
20
|
@configuration = configuration
|
|
21
|
+
@services = nil
|
|
22
|
+
@servers = nil
|
|
23
|
+
@processes = nil
|
|
21
24
|
end
|
|
22
25
|
|
|
23
26
|
# Starts all configured runners and yields results for each process/server.
|
|
@@ -27,10 +30,14 @@ module Nonnative
|
|
|
27
30
|
# @yieldparam name [String, nil] runner name
|
|
28
31
|
# @yieldparam values [Object] runner-specific return value from `start` (e.g. `[pid, running]` for processes)
|
|
29
32
|
# @yieldparam result [Boolean] result of the port readiness check (`true` if ready in time)
|
|
30
|
-
# @return [
|
|
33
|
+
# @return [Array<String>] lifecycle and readiness-check errors collected while starting
|
|
31
34
|
def start(&)
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
errors = []
|
|
36
|
+
|
|
37
|
+
errors.concat(service_lifecycle(services, :start, :start))
|
|
38
|
+
[servers, processes].each { |t| errors.concat(process(t, :start, :open?, :start, &)) }
|
|
39
|
+
|
|
40
|
+
errors
|
|
34
41
|
end
|
|
35
42
|
|
|
36
43
|
# Stops all configured runners and yields results for each process/server.
|
|
@@ -40,10 +47,32 @@ module Nonnative
|
|
|
40
47
|
# @yieldparam name [String, nil] runner name
|
|
41
48
|
# @yieldparam id [Object] runner-specific identifier returned by `stop` (e.g. pid or object_id)
|
|
42
49
|
# @yieldparam result [Boolean] result of the port shutdown check (`true` if closed in time)
|
|
43
|
-
# @return [
|
|
50
|
+
# @return [Array<String>] lifecycle and shutdown-check errors collected while stopping
|
|
44
51
|
def stop(&)
|
|
45
|
-
[
|
|
46
|
-
|
|
52
|
+
errors = []
|
|
53
|
+
|
|
54
|
+
[processes, servers].each { |t| errors.concat(process(t, :stop, :closed?, :stop, &)) }
|
|
55
|
+
errors.concat(service_lifecycle(services, :stop, :stop))
|
|
56
|
+
|
|
57
|
+
errors
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Stops only runners that have already been instantiated in this pool.
|
|
61
|
+
#
|
|
62
|
+
# This is used to rollback partial startup after a failed {#start} without constructing new runner
|
|
63
|
+
# wrappers as a side effect.
|
|
64
|
+
#
|
|
65
|
+
# @yieldparam name [String, nil] runner name
|
|
66
|
+
# @yieldparam id [Object] runner-specific identifier returned by `stop`
|
|
67
|
+
# @yieldparam result [Boolean] result of the port shutdown check (`true` if closed in time)
|
|
68
|
+
# @return [Array<String>] lifecycle and shutdown-check errors collected while rolling back
|
|
69
|
+
def rollback(&)
|
|
70
|
+
errors = []
|
|
71
|
+
|
|
72
|
+
[existing_processes, existing_servers].each { |t| errors.concat(process(t, :stop, :closed?, :stop, &)) }
|
|
73
|
+
errors.concat(service_lifecycle(existing_services, :stop, :stop))
|
|
74
|
+
|
|
75
|
+
errors
|
|
47
76
|
end
|
|
48
77
|
|
|
49
78
|
# Finds a running process runner by configured name.
|
|
@@ -96,41 +125,103 @@ module Nonnative
|
|
|
96
125
|
end
|
|
97
126
|
|
|
98
127
|
def processes
|
|
99
|
-
@processes
|
|
100
|
-
|
|
128
|
+
return @processes unless @processes.nil?
|
|
129
|
+
|
|
130
|
+
@processes = []
|
|
131
|
+
configuration.processes.each do |p|
|
|
132
|
+
@processes << [Nonnative::Process.new(p), Nonnative::Port.new(p)]
|
|
101
133
|
end
|
|
134
|
+
|
|
135
|
+
@processes
|
|
102
136
|
end
|
|
103
137
|
|
|
104
138
|
def servers
|
|
105
|
-
@servers
|
|
106
|
-
|
|
139
|
+
return @servers unless @servers.nil?
|
|
140
|
+
|
|
141
|
+
@servers = []
|
|
142
|
+
configuration.servers.each do |s|
|
|
143
|
+
@servers << [s.klass.new(s), Nonnative::Port.new(s)]
|
|
107
144
|
end
|
|
145
|
+
|
|
146
|
+
@servers
|
|
108
147
|
end
|
|
109
148
|
|
|
110
149
|
def services
|
|
111
|
-
@services
|
|
150
|
+
return @services unless @services.nil?
|
|
151
|
+
|
|
152
|
+
@services = []
|
|
153
|
+
configuration.services.each do |s|
|
|
154
|
+
@services << Nonnative::Service.new(s)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
@services
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def existing_processes
|
|
161
|
+
@processes || []
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def existing_servers
|
|
165
|
+
@servers || []
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def existing_services
|
|
169
|
+
@services || []
|
|
112
170
|
end
|
|
113
171
|
|
|
114
|
-
def
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
172
|
+
def service_lifecycle(all, type_method, action)
|
|
173
|
+
all.each_with_object([]) do |service, errors|
|
|
174
|
+
service.send(type_method)
|
|
175
|
+
rescue StandardError => e
|
|
176
|
+
errors << lifecycle_error(action, service, e)
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def process(all, type_method, port_method, action, &)
|
|
181
|
+
checks = []
|
|
182
|
+
errors = []
|
|
118
183
|
|
|
119
184
|
all.each do |type, port|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
185
|
+
values = type.send(type_method)
|
|
186
|
+
checks << [type, values, Thread.new { check_port(port, port_method) }]
|
|
187
|
+
rescue StandardError => e
|
|
188
|
+
errors << lifecycle_error(action, type, e)
|
|
123
189
|
end
|
|
124
190
|
|
|
125
|
-
|
|
191
|
+
errors.concat(yield_results(checks, action, &))
|
|
192
|
+
end
|
|
126
193
|
|
|
127
|
-
|
|
194
|
+
def check_port(port, port_method)
|
|
195
|
+
{ result: port.send(port_method) }
|
|
196
|
+
rescue StandardError => e
|
|
197
|
+
{ error: e }
|
|
128
198
|
end
|
|
129
199
|
|
|
130
|
-
def yield_results(
|
|
131
|
-
|
|
132
|
-
|
|
200
|
+
def yield_results(checks, action, &)
|
|
201
|
+
checks.each_with_object([]) do |(type, values, thread), errors|
|
|
202
|
+
result = thread.value
|
|
203
|
+
if result[:error]
|
|
204
|
+
errors << port_error(action, type, result[:error])
|
|
205
|
+
elsif block_given?
|
|
206
|
+
yield type.name, values, result[:result]
|
|
207
|
+
end
|
|
133
208
|
end
|
|
134
209
|
end
|
|
210
|
+
|
|
211
|
+
def lifecycle_error(action, type, error)
|
|
212
|
+
"#{action.to_s.capitalize} failed for #{runner_name(type)}: #{error.class} - #{error.message}"
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def port_error(action, type, error)
|
|
216
|
+
check = action == :start ? 'readiness' : 'shutdown'
|
|
217
|
+
"#{check.capitalize} check failed for #{runner_name(type)}: #{error.class} - #{error.message}"
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def runner_name(type)
|
|
221
|
+
name = type.name
|
|
222
|
+
return "runner '#{name}'" if name
|
|
223
|
+
|
|
224
|
+
type.class.to_s
|
|
225
|
+
end
|
|
135
226
|
end
|
|
136
227
|
end
|
data/lib/nonnative/process.rb
CHANGED
data/lib/nonnative/version.rb
CHANGED