nonnative 1.106.0 → 1.108.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 +16 -11
- data/.rubocop.yml +3 -0
- data/AGENTS.md +248 -0
- data/CHANGELOG.md +155 -0
- data/Gemfile.lock +65 -63
- data/README.md +51 -32
- data/lib/nonnative/close_all_socket_pair.rb +14 -0
- data/lib/nonnative/configuration.rb +67 -0
- data/lib/nonnative/configuration_process.rb +14 -0
- data/lib/nonnative/configuration_proxy.rb +28 -0
- data/lib/nonnative/configuration_runner.rb +44 -0
- data/lib/nonnative/configuration_server.rb +12 -0
- data/lib/nonnative/configuration_service.rb +9 -0
- data/lib/nonnative/delay_socket_pair.rb +15 -0
- data/lib/nonnative/error.rb +7 -0
- data/lib/nonnative/fault_injection_proxy.rb +63 -0
- data/lib/nonnative/go_command.rb +34 -0
- data/lib/nonnative/grpc_server.rb +30 -0
- data/lib/nonnative/header.rb +44 -0
- data/lib/nonnative/http_client.rb +45 -0
- data/lib/nonnative/http_proxy_server.rb +62 -1
- data/lib/nonnative/http_server.rb +40 -0
- data/lib/nonnative/invalid_data_socket_pair.rb +15 -0
- data/lib/nonnative/no_proxy.rb +35 -0
- data/lib/nonnative/not_found_error.rb +7 -0
- data/lib/nonnative/observability.rb +44 -0
- data/lib/nonnative/pool.rb +50 -0
- data/lib/nonnative/port.rb +26 -0
- data/lib/nonnative/process.rb +29 -0
- data/lib/nonnative/proxy.rb +24 -0
- data/lib/nonnative/proxy_factory.rb +16 -0
- data/lib/nonnative/runner.rb +30 -0
- data/lib/nonnative/server.rb +28 -0
- data/lib/nonnative/service.rb +16 -0
- data/lib/nonnative/socket_pair.rb +46 -0
- data/lib/nonnative/socket_pair_factory.rb +21 -0
- data/lib/nonnative/start_error.rb +5 -0
- data/lib/nonnative/stop_error.rb +5 -0
- data/lib/nonnative/timeout.rb +20 -0
- data/lib/nonnative/version.rb +4 -1
- data/lib/nonnative.rb +128 -0
- data/nonnative.gemspec +1 -1
- metadata +7 -6
data/lib/nonnative.rb
CHANGED
|
@@ -1,5 +1,46 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# = Nonnative
|
|
4
|
+
#
|
|
5
|
+
# Nonnative is a Ruby-first harness for end-to-end testing of services implemented in other languages.
|
|
6
|
+
# It can:
|
|
7
|
+
#
|
|
8
|
+
# - start external processes and in-process servers
|
|
9
|
+
# - wait for readiness via port checks
|
|
10
|
+
# - optionally run fault-injection proxies in front of services
|
|
11
|
+
#
|
|
12
|
+
# The public entry points are exposed as module-level methods on {Nonnative}.
|
|
13
|
+
#
|
|
14
|
+
# == Basic usage
|
|
15
|
+
#
|
|
16
|
+
# Configure the system under test:
|
|
17
|
+
#
|
|
18
|
+
# Nonnative.configure do |config|
|
|
19
|
+
# config.name = 'example'
|
|
20
|
+
# config.url = 'http://127.0.0.1:8080'
|
|
21
|
+
# config.log = 'test.log'
|
|
22
|
+
#
|
|
23
|
+
# config.process do |p|
|
|
24
|
+
# p.name = 'api'
|
|
25
|
+
# p.command = -> { './bin/api' }
|
|
26
|
+
# p.host = '127.0.0.1'
|
|
27
|
+
# p.port = 8080
|
|
28
|
+
# p.timeout = 10
|
|
29
|
+
# p.log = 'api.log'
|
|
30
|
+
# end
|
|
31
|
+
# end
|
|
32
|
+
#
|
|
33
|
+
# Start and stop around your test suite:
|
|
34
|
+
#
|
|
35
|
+
# Nonnative.start
|
|
36
|
+
# # run tests...
|
|
37
|
+
# Nonnative.stop
|
|
38
|
+
#
|
|
39
|
+
# == Notes
|
|
40
|
+
#
|
|
41
|
+
# This file also requires integration helpers used by acceptance tests. If you require `nonnative` outside a
|
|
42
|
+
# Cucumber runtime, loading `nonnative/cucumber` may not be desirable for your environment.
|
|
43
|
+
#
|
|
3
44
|
require 'socket'
|
|
4
45
|
require 'timeout'
|
|
5
46
|
require 'yaml'
|
|
@@ -56,46 +97,116 @@ require 'nonnative/go_command'
|
|
|
56
97
|
require 'nonnative/cucumber'
|
|
57
98
|
require 'nonnative/header'
|
|
58
99
|
|
|
100
|
+
# The main namespace for the gem.
|
|
101
|
+
#
|
|
102
|
+
# Most consumers will interact with module-level methods:
|
|
103
|
+
#
|
|
104
|
+
# - {Nonnative.configure} / {Nonnative.configuration}
|
|
105
|
+
# - {Nonnative.start} / {Nonnative.stop}
|
|
106
|
+
# - {Nonnative.clear} / {Nonnative.reset}
|
|
107
|
+
#
|
|
108
|
+
# @see Nonnative::Configuration for the configuration DSL
|
|
109
|
+
# @see Nonnative::Pool for lifecycle orchestration once started
|
|
59
110
|
module Nonnative
|
|
60
111
|
class << self
|
|
112
|
+
# Returns the current runner pool (created on {Nonnative.start}).
|
|
113
|
+
#
|
|
114
|
+
# @return [Nonnative::Pool, nil] the pool instance, or `nil` if not started yet
|
|
61
115
|
attr_reader :pool
|
|
62
116
|
|
|
117
|
+
# Loads one or more configuration files using the `config` gem.
|
|
118
|
+
#
|
|
119
|
+
# This is primarily used by {Nonnative::Configuration#load_file}, but is public for advanced cases.
|
|
120
|
+
#
|
|
121
|
+
# @param files [Array<String>] paths to configuration files
|
|
122
|
+
# @return [Config::Options] the loaded configuration object
|
|
63
123
|
def configurations(*files)
|
|
64
124
|
Config.load_files(files)
|
|
65
125
|
end
|
|
66
126
|
|
|
127
|
+
# Returns the current configuration (memoized).
|
|
128
|
+
#
|
|
129
|
+
# @return [Nonnative::Configuration]
|
|
67
130
|
def configuration
|
|
68
131
|
@configuration ||= Nonnative::Configuration.new
|
|
69
132
|
end
|
|
70
133
|
|
|
134
|
+
# Yields the configuration to a block for programmatic setup.
|
|
135
|
+
#
|
|
136
|
+
# @yieldparam config [Nonnative::Configuration]
|
|
137
|
+
# @return [void]
|
|
138
|
+
#
|
|
139
|
+
# @example
|
|
140
|
+
# Nonnative.configure do |config|
|
|
141
|
+
# config.name = 'my-service'
|
|
142
|
+
# # ...
|
|
143
|
+
# end
|
|
71
144
|
def configure
|
|
72
145
|
yield configuration
|
|
73
146
|
end
|
|
74
147
|
|
|
148
|
+
# Returns the gem logger (memoized).
|
|
149
|
+
#
|
|
150
|
+
# The logger writes to the path configured at {Nonnative::Configuration#log}.
|
|
151
|
+
#
|
|
152
|
+
# @return [Logger]
|
|
75
153
|
def logger
|
|
76
154
|
@logger ||= Logger.new(configuration.log)
|
|
77
155
|
end
|
|
78
156
|
|
|
157
|
+
# Reads a file and returns only lines matching the given predicate.
|
|
158
|
+
#
|
|
159
|
+
# @param path [String] file path to read
|
|
160
|
+
# @param predicate [#call] callable that receives a line and returns truthy/falsey
|
|
161
|
+
# @return [Array<String>] matching lines
|
|
79
162
|
def log_lines(path, predicate)
|
|
80
163
|
File.readlines(path).select { |l| predicate.call(l) }
|
|
81
164
|
end
|
|
82
165
|
|
|
166
|
+
# Builds a Go test executable command line with optional profiling/trace/coverage flags.
|
|
167
|
+
#
|
|
168
|
+
# This is used when process configuration specifies a `go` section.
|
|
169
|
+
#
|
|
170
|
+
# @param tools [Array<String>] enabled tool names (e.g. `["prof", "trace", "cover"]`)
|
|
171
|
+
# @param output [String] directory where outputs should be written
|
|
172
|
+
# @param exec [String] the test binary (or wrapper) to execute
|
|
173
|
+
# @param cmd [String] the command argument passed to the test binary
|
|
174
|
+
# @param params [Array<String>] extra parameters for the command
|
|
175
|
+
# @return [String] executable command string
|
|
83
176
|
def go_executable(tools, output, exec, cmd, *params)
|
|
84
177
|
Nonnative::GoCommand.new(tools, exec, output).executable(cmd, params)
|
|
85
178
|
end
|
|
86
179
|
|
|
180
|
+
# Returns an HTTP client for common health/readiness endpoints.
|
|
181
|
+
#
|
|
182
|
+
# @return [Nonnative::Observability]
|
|
87
183
|
def observability
|
|
88
184
|
@observability ||= Nonnative::Observability.new(configuration.url)
|
|
89
185
|
end
|
|
90
186
|
|
|
187
|
+
# Returns the configured proxy kinds mapped to proxy classes.
|
|
188
|
+
#
|
|
189
|
+
# Consumers can extend this map to add custom proxy implementations.
|
|
190
|
+
#
|
|
191
|
+
# @return [Hash{String=>Class}]
|
|
91
192
|
def proxies
|
|
92
193
|
@proxies ||= { 'fault_injection' => Nonnative::FaultInjectionProxy }.freeze
|
|
93
194
|
end
|
|
94
195
|
|
|
196
|
+
# Resolves a proxy implementation for a configured kind.
|
|
197
|
+
#
|
|
198
|
+
# @param kind [String] proxy kind name (for example `"fault_injection"`)
|
|
199
|
+
# @return [Class] a subclass of {Nonnative::Proxy}
|
|
95
200
|
def proxy(kind)
|
|
96
201
|
Nonnative.proxies[kind] || Nonnative::NoProxy
|
|
97
202
|
end
|
|
98
203
|
|
|
204
|
+
# Starts all configured services, servers, and processes, and waits for readiness.
|
|
205
|
+
#
|
|
206
|
+
# Readiness is determined by attempting to connect to each runner's configured host/port.
|
|
207
|
+
#
|
|
208
|
+
# @return [void]
|
|
209
|
+
# @raise [Nonnative::StartError] if one or more runners fail to start or become ready in time
|
|
99
210
|
def start
|
|
100
211
|
@pool ||= Nonnative::Pool.new(configuration)
|
|
101
212
|
errors = []
|
|
@@ -108,6 +219,10 @@ module Nonnative
|
|
|
108
219
|
raise Nonnative::StartError, errors.join("\n") unless errors.empty?
|
|
109
220
|
end
|
|
110
221
|
|
|
222
|
+
# Stops all configured processes and servers, then services, and waits for shutdown.
|
|
223
|
+
#
|
|
224
|
+
# @return [void]
|
|
225
|
+
# @raise [Nonnative::StopError] if one or more runners fail to stop in time
|
|
111
226
|
def stop
|
|
112
227
|
return if @pool.nil?
|
|
113
228
|
|
|
@@ -120,19 +235,32 @@ module Nonnative
|
|
|
120
235
|
raise Nonnative::StopError, errors.join("\n") unless errors.empty?
|
|
121
236
|
end
|
|
122
237
|
|
|
238
|
+
# Clears the memoized configuration instance.
|
|
239
|
+
#
|
|
240
|
+
# @return [void]
|
|
123
241
|
def clear_configuration
|
|
124
242
|
@configuration = nil
|
|
125
243
|
end
|
|
126
244
|
|
|
245
|
+
# Clears the memoized pool instance.
|
|
246
|
+
#
|
|
247
|
+
# @return [void]
|
|
127
248
|
def clear_pool
|
|
128
249
|
@pool = nil
|
|
129
250
|
end
|
|
130
251
|
|
|
252
|
+
# Clears memoized configuration and pool.
|
|
253
|
+
#
|
|
254
|
+
# @return [void]
|
|
131
255
|
def clear
|
|
132
256
|
clear_configuration
|
|
133
257
|
clear_pool
|
|
134
258
|
end
|
|
135
259
|
|
|
260
|
+
# Resets proxies for all currently started runners.
|
|
261
|
+
#
|
|
262
|
+
# @return [void]
|
|
263
|
+
# @raise [NoMethodError] if called before {Nonnative.start} (because {Nonnative.pool} is nil)
|
|
136
264
|
def reset
|
|
137
265
|
Nonnative.pool.reset
|
|
138
266
|
end
|
data/nonnative.gemspec
CHANGED
|
@@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
|
|
|
29
29
|
spec.add_dependency 'cucumber', '>= 7', '< 11'
|
|
30
30
|
spec.add_dependency 'get_process_mem', '>= 1', '< 2'
|
|
31
31
|
spec.add_dependency 'grpc', '>= 1', '< 2'
|
|
32
|
-
spec.add_dependency 'puma', '>=
|
|
32
|
+
spec.add_dependency 'puma', '>= 7', '< 8'
|
|
33
33
|
spec.add_dependency 'rest-client', '>= 2', '< 3'
|
|
34
34
|
spec.add_dependency 'retriable', '>= 3', '< 4'
|
|
35
35
|
spec.add_dependency 'rspec-benchmark', '>= 0', '< 1'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: nonnative
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.108.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alejandro Falkowski
|
|
@@ -115,20 +115,20 @@ dependencies:
|
|
|
115
115
|
requirements:
|
|
116
116
|
- - ">="
|
|
117
117
|
- !ruby/object:Gem::Version
|
|
118
|
-
version: '
|
|
118
|
+
version: '7'
|
|
119
119
|
- - "<"
|
|
120
120
|
- !ruby/object:Gem::Version
|
|
121
|
-
version: '
|
|
121
|
+
version: '8'
|
|
122
122
|
type: :runtime
|
|
123
123
|
prerelease: false
|
|
124
124
|
version_requirements: !ruby/object:Gem::Requirement
|
|
125
125
|
requirements:
|
|
126
126
|
- - ">="
|
|
127
127
|
- !ruby/object:Gem::Version
|
|
128
|
-
version: '
|
|
128
|
+
version: '7'
|
|
129
129
|
- - "<"
|
|
130
130
|
- !ruby/object:Gem::Version
|
|
131
|
-
version: '
|
|
131
|
+
version: '8'
|
|
132
132
|
- !ruby/object:Gem::Dependency
|
|
133
133
|
name: rest-client
|
|
134
134
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -264,6 +264,7 @@ files:
|
|
|
264
264
|
- ".gitignore"
|
|
265
265
|
- ".gitmodules"
|
|
266
266
|
- ".rubocop.yml"
|
|
267
|
+
- AGENTS.md
|
|
267
268
|
- CHANGELOG.md
|
|
268
269
|
- Gemfile
|
|
269
270
|
- Gemfile.lock
|
|
@@ -330,7 +331,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
330
331
|
- !ruby/object:Gem::Version
|
|
331
332
|
version: '0'
|
|
332
333
|
requirements: []
|
|
333
|
-
rubygems_version:
|
|
334
|
+
rubygems_version: 4.0.3
|
|
334
335
|
specification_version: 4
|
|
335
336
|
summary: Allows you to keep using the power of ruby to test other systems
|
|
336
337
|
test_files: []
|