nonnative 2.1.0 → 2.10.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 +7 -5
- data/AGENTS.md +97 -198
- data/Gemfile.lock +21 -20
- data/README.md +32 -12
- data/lib/nonnative/configuration.rb +11 -10
- data/lib/nonnative/configuration_proxy.rb +13 -1
- data/lib/nonnative/cucumber.rb +219 -103
- data/lib/nonnative/http_proxy_server.rb +36 -9
- data/lib/nonnative/invalid_data_socket_pair.rb +17 -5
- 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
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
data/lib/nonnative.rb
CHANGED
|
@@ -53,7 +53,6 @@ require 'rest-client'
|
|
|
53
53
|
require 'retriable'
|
|
54
54
|
require 'concurrent'
|
|
55
55
|
require 'config'
|
|
56
|
-
require 'cucumber'
|
|
57
56
|
require 'get_process_mem'
|
|
58
57
|
require 'rspec-benchmark'
|
|
59
58
|
require 'rspec/expectations'
|
|
@@ -109,10 +108,10 @@ require 'nonnative/header'
|
|
|
109
108
|
# @see Nonnative::Pool for lifecycle orchestration once started
|
|
110
109
|
module Nonnative
|
|
111
110
|
class << self
|
|
112
|
-
# Returns the current runner pool (created on {Nonnative.start}).
|
|
111
|
+
# Returns or overrides the current runner pool (created on {Nonnative.start}).
|
|
113
112
|
#
|
|
114
113
|
# @return [Nonnative::Pool, nil] the pool instance, or `nil` if not started yet
|
|
115
|
-
|
|
114
|
+
attr_accessor :pool
|
|
116
115
|
|
|
117
116
|
# Loads one or more configuration files using the `config` gem.
|
|
118
117
|
#
|
|
@@ -210,13 +209,19 @@ module Nonnative
|
|
|
210
209
|
def start
|
|
211
210
|
@pool ||= Nonnative::Pool.new(configuration)
|
|
212
211
|
errors = []
|
|
213
|
-
|
|
214
|
-
@pool.start do |name, values, result|
|
|
212
|
+
errors.concat(@pool.start do |name, values, result|
|
|
215
213
|
id, started = values
|
|
216
|
-
errors << "Started #{name} with id #{id}, though did respond in time" if !started || !result
|
|
217
|
-
end
|
|
214
|
+
errors << "Started #{name} with id #{id}, though did not respond in time" if !started || !result
|
|
215
|
+
end)
|
|
216
|
+
nil
|
|
217
|
+
rescue StandardError => e
|
|
218
|
+
errors << unexpected_lifecycle_error(:start, e)
|
|
219
|
+
ensure
|
|
220
|
+
if errors.any?
|
|
221
|
+
errors.concat(rollback_start)
|
|
218
222
|
|
|
219
|
-
|
|
223
|
+
raise Nonnative::StartError, errors.join("\n")
|
|
224
|
+
end
|
|
220
225
|
end
|
|
221
226
|
|
|
222
227
|
# Stops all configured processes and servers, then services, and waits for shutdown.
|
|
@@ -224,14 +229,16 @@ module Nonnative
|
|
|
224
229
|
# @return [void]
|
|
225
230
|
# @raise [Nonnative::StopError] if one or more runners fail to stop in time
|
|
226
231
|
def stop
|
|
227
|
-
return if @pool.nil?
|
|
228
|
-
|
|
229
232
|
errors = []
|
|
233
|
+
return if @pool.nil?
|
|
230
234
|
|
|
231
|
-
@pool.stop do |name, id, result|
|
|
232
|
-
errors << "Stopped #{name} with id #{id}, though did respond in time" unless result
|
|
233
|
-
end
|
|
234
|
-
|
|
235
|
+
errors.concat(@pool.stop do |name, id, result|
|
|
236
|
+
errors << "Stopped #{name} with id #{id}, though did not respond in time" unless result
|
|
237
|
+
end)
|
|
238
|
+
nil
|
|
239
|
+
rescue StandardError => e
|
|
240
|
+
errors << unexpected_lifecycle_error(:stop, e)
|
|
241
|
+
ensure
|
|
235
242
|
raise Nonnative::StopError, errors.join("\n") unless errors.empty?
|
|
236
243
|
end
|
|
237
244
|
|
|
@@ -242,6 +249,22 @@ module Nonnative
|
|
|
242
249
|
@configuration = nil
|
|
243
250
|
end
|
|
244
251
|
|
|
252
|
+
# Closes and clears the memoized logger instance.
|
|
253
|
+
#
|
|
254
|
+
# @return [void]
|
|
255
|
+
def clear_logger
|
|
256
|
+
@logger&.close
|
|
257
|
+
ensure
|
|
258
|
+
@logger = nil
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# Clears the memoized observability client.
|
|
262
|
+
#
|
|
263
|
+
# @return [void]
|
|
264
|
+
def clear_observability
|
|
265
|
+
@observability = nil
|
|
266
|
+
end
|
|
267
|
+
|
|
245
268
|
# Clears the memoized pool instance.
|
|
246
269
|
#
|
|
247
270
|
# @return [void]
|
|
@@ -249,10 +272,12 @@ module Nonnative
|
|
|
249
272
|
@pool = nil
|
|
250
273
|
end
|
|
251
274
|
|
|
252
|
-
# Clears memoized configuration and pool.
|
|
275
|
+
# Clears memoized configuration, logger, observability client, and pool.
|
|
253
276
|
#
|
|
254
277
|
# @return [void]
|
|
255
278
|
def clear
|
|
279
|
+
clear_logger
|
|
280
|
+
clear_observability
|
|
256
281
|
clear_configuration
|
|
257
282
|
clear_pool
|
|
258
283
|
end
|
|
@@ -264,5 +289,24 @@ module Nonnative
|
|
|
264
289
|
def reset
|
|
265
290
|
Nonnative.pool.reset
|
|
266
291
|
end
|
|
292
|
+
|
|
293
|
+
private
|
|
294
|
+
|
|
295
|
+
def rollback_start
|
|
296
|
+
errors = []
|
|
297
|
+
return errors if @pool.nil?
|
|
298
|
+
|
|
299
|
+
errors.concat(@pool.rollback do |name, id, result|
|
|
300
|
+
errors << "Rollback failed for #{name} with id #{id}, because it did not stop in time" unless result
|
|
301
|
+
end)
|
|
302
|
+
rescue StandardError => e
|
|
303
|
+
errors << unexpected_lifecycle_error(:rollback, e)
|
|
304
|
+
ensure
|
|
305
|
+
clear_pool if errors.empty?
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def unexpected_lifecycle_error(action, error)
|
|
309
|
+
"#{action.to_s.capitalize} failed with #{error.class}: #{error.message}"
|
|
310
|
+
end
|
|
267
311
|
end
|
|
268
312
|
end
|