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
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8220ca25997b624a13ebf5f3f6a046af6bf05ee7428b21b96454d7c23ad42bef
|
|
4
|
+
data.tar.gz: 5a1884b26d92f57b54631ef22a4c2d6b3f16690c81364353ecb3e2d941b39638
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d026441a2ed85facab82a48a8967e246d6c717c00c5c0039fb434feb585fe35fb23fbfa06732f85ec5491d0febcdda056d1cf4264a014efe432b87dfc705275f
|
|
7
|
+
data.tar.gz: 2cc84560c80a27144d3176b3e019a6ab9c86e32c2215e774d97d5a58927c34dda006a3da8f3b5b356b19bc7e2e96fb863b2bc168c9f4ac3e7a91f7181f08c57d
|
data/.circleci/config.yml
CHANGED
|
@@ -3,7 +3,7 @@ version: 2.1
|
|
|
3
3
|
jobs:
|
|
4
4
|
build:
|
|
5
5
|
docker:
|
|
6
|
-
- image: alexfalkowski/ruby:2.
|
|
6
|
+
- image: alexfalkowski/ruby:2.4
|
|
7
7
|
working_directory: ~/nonnative
|
|
8
8
|
steps:
|
|
9
9
|
- checkout:
|
|
@@ -24,7 +24,9 @@ jobs:
|
|
|
24
24
|
paths:
|
|
25
25
|
- vendor
|
|
26
26
|
- run: make lint
|
|
27
|
-
- run: make
|
|
27
|
+
- run: make sec
|
|
28
|
+
- run: COVERAGE_NAME="Cucumber Features" make features
|
|
29
|
+
- run: COVERAGE_NAME="Cucumber Benchmarks" make benchmarks
|
|
28
30
|
- store_test_results:
|
|
29
31
|
path: test/reports
|
|
30
32
|
- store_artifacts:
|
|
@@ -33,7 +35,7 @@ jobs:
|
|
|
33
35
|
resource_class: arm.large
|
|
34
36
|
sync:
|
|
35
37
|
docker:
|
|
36
|
-
- image: alexfalkowski/release:7.
|
|
38
|
+
- image: alexfalkowski/release:7.5
|
|
37
39
|
working_directory: ~/nonnative
|
|
38
40
|
steps:
|
|
39
41
|
- checkout:
|
|
@@ -44,7 +46,7 @@ jobs:
|
|
|
44
46
|
resource_class: arm.large
|
|
45
47
|
version:
|
|
46
48
|
docker:
|
|
47
|
-
- image: alexfalkowski/release:7.
|
|
49
|
+
- image: alexfalkowski/release:7.5
|
|
48
50
|
working_directory: ~/nonnative
|
|
49
51
|
steps:
|
|
50
52
|
- checkout:
|
|
@@ -56,7 +58,7 @@ jobs:
|
|
|
56
58
|
resource_class: arm.large
|
|
57
59
|
wait-all:
|
|
58
60
|
docker:
|
|
59
|
-
- image: alexfalkowski/ruby:2.
|
|
61
|
+
- image: alexfalkowski/ruby:2.4
|
|
60
62
|
steps:
|
|
61
63
|
- run: echo "all applicable jobs finished"
|
|
62
64
|
resource_class: arm.large
|
data/AGENTS.md
CHANGED
|
@@ -1,248 +1,147 @@
|
|
|
1
1
|
# AGENTS.md
|
|
2
2
|
|
|
3
|
-
This
|
|
3
|
+
This repo is the `nonnative` Ruby gem: a Ruby-first harness for end-to-end testing of systems implemented in other languages by starting processes/servers/services, waiting on TCP port readiness, and optionally putting fault-injection proxies in front of them.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Quick map
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- Library code: `lib/nonnative/**/*.rb`
|
|
8
|
+
- Acceptance tests: `features/**/*.feature`, `features/support/**/*.rb`, `features/step_definitions/**/*.rb`
|
|
9
|
+
- Generated gRPC Ruby stubs for tests: `test/grpc/**/*`
|
|
10
|
+
- Test proto files: `test/nonnative/v1/*.proto`
|
|
11
|
+
- Build wiring: root `Makefile` includes `bin/build/make/*.mak`
|
|
8
12
|
|
|
9
|
-
|
|
10
|
-
- Added/expanded RDoc for the module entry point (`Nonnative`) and core configuration/error types.
|
|
11
|
-
- Goal: document *public APIs only* (gem consumers), not internal/private helpers.
|
|
12
|
-
- **README accuracy pass started**:
|
|
13
|
-
- Fixed incorrect examples around **services**:
|
|
14
|
-
- Programmatic example incorrectly used `p.port` inside a `config.service do |s| ... end` block; corrected to `s.host`/`s.port`.
|
|
15
|
-
- YAML example incorrectly used `processes:` for services; corrected to `services:`.
|
|
16
|
-
- Removed/avoided implying non-existent config fields (e.g. there is no top-level `config.wait`; `wait` is per-runner).
|
|
13
|
+
## Key repo dependency
|
|
17
14
|
|
|
18
|
-
|
|
15
|
+
This repo depends on the `bin/` git submodule.
|
|
19
16
|
|
|
20
|
-
|
|
17
|
+
- `.gitmodules` points to `git@github.com:alexfalkowski/bin.git`
|
|
18
|
+
- CI runs `git submodule sync && git submodule update --init`
|
|
19
|
+
- If `bin/` is missing or you do not have SSH access, `make` targets will fail
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
- **Acceptance tests**: `features/**/*.feature` + `features/support/**/*.rb` + `features/step_definitions/**/*.rb` (Cucumber)
|
|
24
|
-
- **Generated gRPC Ruby stubs for tests**: `test/grpc/**/*` (excluded from RuboCop)
|
|
25
|
-
- **Proto definitions for test fixtures**: `test/nonnative/v1/*.proto`
|
|
26
|
-
- **Build system**: `Makefile` includes make fragments from the `bin/` submodule (`bin/build/make/*.mak`).
|
|
21
|
+
## Core commands
|
|
27
22
|
|
|
28
|
-
|
|
23
|
+
- Install deps: `make dep`
|
|
24
|
+
- Lint: `make lint`
|
|
25
|
+
- Run features: `make features`
|
|
26
|
+
- Run benchmarks only: `make benchmarks`
|
|
27
|
+
- Clean deps: `make clean-dep`
|
|
28
|
+
- Clean reports: `make clean-reports`
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
## Runtime model
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
- CI runs `git submodule sync && git submodule update --init` before running `make` targets (`.circleci/config.yml`).
|
|
32
|
+
Public entry point is `lib/nonnative.rb`.
|
|
34
33
|
|
|
35
|
-
|
|
34
|
+
Main module API:
|
|
36
35
|
|
|
37
|
-
|
|
36
|
+
- `configure`
|
|
37
|
+
- `start`
|
|
38
|
+
- `stop`
|
|
39
|
+
- `clear`
|
|
40
|
+
- `reset`
|
|
41
|
+
- `pool`
|
|
38
42
|
|
|
39
|
-
|
|
40
|
-
git submodule sync
|
|
41
|
-
git submodule update --init
|
|
42
|
-
```
|
|
43
|
+
Configuration lives in `Nonnative::Configuration` and is built either:
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
- programmatically with `config.process`, `config.server`, `config.service`
|
|
46
|
+
- from YAML with `config.load_file(...)`
|
|
45
47
|
|
|
46
|
-
|
|
48
|
+
Runtime runners:
|
|
47
49
|
|
|
48
|
-
- `
|
|
50
|
+
- `Nonnative::Process`: manages an OS process
|
|
51
|
+
- `Nonnative::Server`: manages an in-process Ruby server thread
|
|
52
|
+
- `Nonnative::Service`: manages only proxy lifecycle for an externally managed dependency
|
|
49
53
|
|
|
50
|
-
|
|
54
|
+
`Nonnative::Pool` starts services first, then servers/processes, and stops in the reverse direction.
|
|
51
55
|
|
|
52
|
-
|
|
56
|
+
Readiness and shutdown checks are TCP-only via `Nonnative::Port#open?` and `#closed?`.
|
|
53
57
|
|
|
54
|
-
|
|
55
|
-
make dep
|
|
56
|
-
```
|
|
58
|
+
## Cucumber integration
|
|
57
59
|
|
|
58
|
-
|
|
60
|
+
Cucumber integration lives in `lib/nonnative/cucumber.rb`.
|
|
59
61
|
|
|
60
|
-
|
|
62
|
+
Treat `lib/nonnative/cucumber.rb` as a public compatibility surface for library consumers.
|
|
63
|
+
Existing hooks and step text should not be removed or renamed unless the user explicitly wants a breaking change.
|
|
61
64
|
|
|
62
|
-
|
|
63
|
-
make lint
|
|
64
|
-
```
|
|
65
|
+
Supported tags:
|
|
65
66
|
|
|
66
|
-
|
|
67
|
+
- `@startup`: start before scenario, stop after scenario
|
|
68
|
+
- `@manual`: scenario starts manually, stop after scenario
|
|
69
|
+
- `@clear`: call `Nonnative.clear` before scenario
|
|
70
|
+
- `@reset`: reset proxies after scenario
|
|
67
71
|
|
|
68
|
-
-
|
|
69
|
-
- Config: `.rubocop.yml` (TargetRubyVersion 3.4; max line length 150)
|
|
72
|
+
Repo-owned feature files also use suite taxonomy tags:
|
|
70
73
|
|
|
71
|
-
|
|
74
|
+
- `@acceptance`: end-to-end runner and client flows
|
|
75
|
+
- `@contract`: lower-level lifecycle / command coverage
|
|
76
|
+
- `@proxy`: proxy-specific coverage
|
|
77
|
+
- `@config`: scenarios or example sets that load YAML/configuration
|
|
78
|
+
- `@service`: coverage centered on external services
|
|
79
|
+
- `@benchmark`: benchmark-only scenarios
|
|
80
|
+
- `@slow`: slower-running scenarios, currently benchmarks
|
|
72
81
|
|
|
73
|
-
|
|
74
|
-
make fix-lint
|
|
75
|
-
# or
|
|
76
|
-
make format
|
|
77
|
-
```
|
|
82
|
+
`make features` excludes `@benchmark`; `make benchmarks` runs only `@benchmark`.
|
|
78
83
|
|
|
79
|
-
|
|
84
|
+
`Nonnative.clear` now clears:
|
|
80
85
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
86
|
+
- configuration
|
|
87
|
+
- logger
|
|
88
|
+
- observability client
|
|
89
|
+
- pool
|
|
84
90
|
|
|
85
|
-
|
|
91
|
+
`require 'nonnative'` still loads the Cucumber integration, but hook/step registration is lazy, so plain `require 'nonnative'` is safe outside a booted Cucumber runtime.
|
|
86
92
|
|
|
87
|
-
|
|
88
|
-
- Cucumber profile `report` is defined in `.config/cucumber.yml` and writes:
|
|
89
|
-
- JUnit XML to `test/reports`
|
|
90
|
-
- HTML report to `test/reports/index.html`
|
|
93
|
+
For “start once per test run”, use `require 'nonnative/startup'`.
|
|
91
94
|
|
|
92
|
-
|
|
95
|
+
## Proxy wiring
|
|
93
96
|
|
|
94
|
-
|
|
95
|
-
make benchmarks
|
|
96
|
-
```
|
|
97
|
+
This is the easiest thing to get wrong.
|
|
97
98
|
|
|
98
|
-
|
|
99
|
+
- Runner `host` / `port` are the client-facing endpoint and the values used by readiness/shutdown checks
|
|
100
|
+
- For `fault_injection`, nested `proxy.host` / `proxy.port` are the upstream target behind the proxy
|
|
101
|
+
- Clients should connect to the runner `host` / `port` when a proxy is enabled
|
|
99
102
|
|
|
100
|
-
|
|
103
|
+
Available proxy kinds:
|
|
101
104
|
|
|
102
|
-
|
|
105
|
+
- `none`
|
|
106
|
+
- `fault_injection`
|
|
103
107
|
|
|
104
|
-
|
|
108
|
+
Fault injection states:
|
|
105
109
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
110
|
+
- `none`
|
|
111
|
+
- `close_all`
|
|
112
|
+
- `delay`
|
|
113
|
+
- `invalid_data`
|
|
109
114
|
|
|
110
|
-
|
|
115
|
+
## Config gotchas
|
|
111
116
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
117
|
+
- Services must be declared under `services:` in YAML, not `processes:`
|
|
118
|
+
- There is no top-level `config.wait`; `wait` is per runner
|
|
119
|
+
- Service configs use `config.service do |s| ... end`, so use `s.host` / `s.port`
|
|
120
|
+
- Proxy examples need both sides of the split:
|
|
121
|
+
- runner `host` / `port` = proxy endpoint
|
|
122
|
+
- nested `proxy.host` / `proxy.port` = upstream target
|
|
116
123
|
|
|
117
|
-
##
|
|
124
|
+
## Test fixtures worth knowing
|
|
118
125
|
|
|
119
|
-
|
|
126
|
+
- Local process fixture: `features/support/bin/start`
|
|
127
|
+
- HTTP fixtures: `features/support/http_server.rb`, `features/support/http_proxy_server.rb`
|
|
128
|
+
- TCP fixture: `features/support/tcp_server.rb`
|
|
129
|
+
- gRPC fixtures: `features/support/grpc_server.rb`, plus generated stubs under `test/grpc/`
|
|
120
130
|
|
|
121
|
-
|
|
131
|
+
## Important limitations / gotchas
|
|
122
132
|
|
|
123
|
-
-
|
|
124
|
-
-
|
|
125
|
-
-
|
|
126
|
-
-
|
|
133
|
+
- Ruby version is constrained by `nonnative.gemspec` to `>= 4.0.0` and `< 5.0.0`
|
|
134
|
+
- The `grpc` Ruby library uses a global logger; per-server gRPC loggers are not really supported
|
|
135
|
+
- `make` depends on the `bin/` submodule being present
|
|
136
|
+
- Local Ruby/Bundler mismatches can break native extensions on macOS
|
|
137
|
+
- Coverage output and Cucumber reports are written under `test/reports`
|
|
138
|
+
- Port checks can be flaky if tests reuse ports unexpectedly
|
|
127
139
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
- `lib/nonnative/startup.rb` calls `Nonnative.start` and registers an `at_exit` stop.
|
|
131
|
-
|
|
132
|
-
### README gotchas that matter in practice
|
|
133
|
-
|
|
134
|
-
- **Service vs process YAML keys**:
|
|
135
|
-
- Services must be declared under `services:` in YAML (not `processes:`). Code reads `cfg.services` and maps them to `Nonnative::ConfigurationService`.
|
|
136
|
-
- **No top-level `wait`**:
|
|
137
|
-
- `wait` is defined on runner configurations (`ConfigurationRunner#wait`) and is per process/server/service.
|
|
138
|
-
- **Proxy wiring is easy to misunderstand**:
|
|
139
|
-
- When a proxy kind like `fault_injection` is enabled, the proxy binds to `service.proxy.host`/`service.proxy.port`.
|
|
140
|
-
- Readiness checks and traffic should typically target the **proxy host/port**, not the underlying service host/port.
|
|
141
|
-
|
|
142
|
-
### Feature support code
|
|
143
|
-
|
|
144
|
-
`features/support/` contains small servers/clients used by cucumber scenarios (HTTP/TCP/gRPC). Example:
|
|
145
|
-
|
|
146
|
-
- `features/support/http_server.rb` defines a Sinatra app for `/hello` and health endpoints.
|
|
147
|
-
|
|
148
|
-
### Process fixture
|
|
149
|
-
|
|
150
|
-
Scenarios start a local process via `features/support/bin/start` (referenced in step definitions and YAML configs like `features/configs/processes.yml`).
|
|
151
|
-
|
|
152
|
-
## Library architecture (high level)
|
|
153
|
-
|
|
154
|
-
### Entry point and global state
|
|
155
|
-
|
|
156
|
-
- `lib/nonnative.rb` defines the `Nonnative` module singleton API:
|
|
157
|
-
- `configure { |config| ... }`
|
|
158
|
-
- `start` / `stop`
|
|
159
|
-
- `clear`, `reset`
|
|
160
|
-
- `pool` is created on `start` (`Nonnative::Pool.new(configuration)`).
|
|
161
|
-
|
|
162
|
-
### Configuration objects
|
|
163
|
-
|
|
164
|
-
- `Nonnative::Configuration` (`lib/nonnative/configuration.rb`) holds arrays of:
|
|
165
|
-
- `processes` (`Nonnative::ConfigurationProcess`)
|
|
166
|
-
- `servers` (`Nonnative::ConfigurationServer`)
|
|
167
|
-
- `services` (`Nonnative::ConfigurationService`)
|
|
168
|
-
|
|
169
|
-
It can be populated either:
|
|
170
|
-
|
|
171
|
-
- programmatically via `config.process { ... }`, `config.server { ... }`, `config.service { ... }`
|
|
172
|
-
- via YAML using `config.load_file(path)` which calls `Config.load_files(...)` (the `config` gem)
|
|
173
|
-
|
|
174
|
-
Proxies are configured via `ConfigurationProxy` (`lib/nonnative/configuration_proxy.rb`) and attached to runners as a hash.
|
|
175
|
-
|
|
176
|
-
### Runners and lifecycle
|
|
177
|
-
|
|
178
|
-
There are three runtime “runner” types, all subclassing `Runner` (`lib/nonnative/runner.rb`):
|
|
179
|
-
|
|
180
|
-
- `Nonnative::Process` (`lib/nonnative/process.rb`): `spawn(...)` + `Process.kill` / `waitpid2`.
|
|
181
|
-
- `Nonnative::Server` (`lib/nonnative/server.rb`): `Thread.new { perform_start }` + `perform_stop`.
|
|
182
|
-
- `Nonnative::Service` (`lib/nonnative/service.rb`): no process management; proxy only.
|
|
183
|
-
|
|
184
|
-
`Nonnative::Pool` (`lib/nonnative/pool.rb`) owns collections of runners and orchestrates start/stop:
|
|
185
|
-
|
|
186
|
-
- starts **services first**, then servers/processes
|
|
187
|
-
- stops **processes/servers first**, then services
|
|
188
|
-
- readiness is determined via `Nonnative::Port#open?` / `#closed?` (`lib/nonnative/port.rb`) which repeatedly tries `TCPSocket.new(host, port)` inside a timeout.
|
|
189
|
-
|
|
190
|
-
### Proxies
|
|
191
|
-
|
|
192
|
-
Proxy selection is keyed by `kind`:
|
|
193
|
-
|
|
194
|
-
- mapping: `Nonnative.proxies` in `lib/nonnative.rb`
|
|
195
|
-
- default proxy config values: `ConfigurationProxy#initialize` sets kind `none`, host `0.0.0.0`, wait `0.1`, etc.
|
|
196
|
-
|
|
197
|
-
Implemented proxies:
|
|
198
|
-
|
|
199
|
-
- `Nonnative::NoProxy` (`lib/nonnative/no_proxy.rb`)
|
|
200
|
-
- `Nonnative::FaultInjectionProxy` (`lib/nonnative/fault_injection_proxy.rb`)
|
|
201
|
-
- states: `:none`, `:close_all`, `:delay`, `:invalid_data`
|
|
202
|
-
- delegates behavior to socket-pair classes via `SocketPairFactory` (`lib/nonnative/socket_pair_factory.rb`).
|
|
203
|
-
|
|
204
|
-
### Go executable helper
|
|
205
|
-
|
|
206
|
-
There is a helper for building a Go *test binary* command line with optional profiling/trace/coverage flags:
|
|
207
|
-
|
|
208
|
-
- `Nonnative.go_executable` in `lib/nonnative.rb`
|
|
209
|
-
- `Nonnative::GoCommand` in `lib/nonnative/go_command.rb`
|
|
210
|
-
|
|
211
|
-
This is used when YAML process config has a `go:` section (see `Configuration#command` in `lib/nonnative/configuration.rb`).
|
|
212
|
-
|
|
213
|
-
## Style and conventions
|
|
214
|
-
|
|
215
|
-
- Ruby style is enforced by RuboCop (`.rubocop.yml`):
|
|
216
|
-
- Target Ruby 3.4
|
|
217
|
-
- Line length 150
|
|
218
|
-
- `Style/Documentation` disabled
|
|
219
|
-
- `.editorconfig`:
|
|
220
|
-
- `indent_size = 2` for most files
|
|
221
|
-
- **Makefiles use tabs**
|
|
222
|
-
- Many Ruby files use `# frozen_string_literal: true`.
|
|
223
|
-
|
|
224
|
-
## CI notes
|
|
225
|
-
|
|
226
|
-
CircleCI runs (see `.circleci/config.yml`):
|
|
227
|
-
|
|
228
|
-
- `make source-key` (defined in `bin/build/make/git.mak`) to generate `.source-key` used for caching
|
|
229
|
-
- `make dep`, `make clean-dep`
|
|
230
|
-
- `make lint`, `make features`
|
|
231
|
-
- uploads `test/reports` artifacts
|
|
232
|
-
|
|
233
|
-
## Common gotchas
|
|
234
|
-
|
|
235
|
-
- **Submodule required**: root `Makefile` only includes `bin/...` make fragments; without `bin/` present/updated, `make` won’t work.
|
|
236
|
-
- **SSH-only submodule URL**: `.gitmodules` uses `git@github.com:...`; CI or local environments without SSH keys will fail to init the submodule.
|
|
237
|
-
- **Local Ruby/Bundler mismatch can break native extensions**: on macOS, `make lint`/`bundle exec ...` may fail if the Ruby used to install gems differs from the Ruby used to run them (example error seen: `prism.bundle` missing `libruby.3.4.dylib`).
|
|
238
|
-
- **Requiring `nonnative` loads Cucumber DSL**: `lib/nonnative.rb` requires `lib/nonnative/cucumber.rb`, which calls `World(...)`. Outside a Cucumber runtime this can raise (example error seen: `Cucumber::Glue::Dsl.build_rb_world_factory`).
|
|
239
|
-
- **Reports directory**: Cucumber report profile writes into `test/reports/` and the repo keeps a `test/reports/.keep` file.
|
|
240
|
-
- **Port checks can be flaky if ports are reused**: readiness is purely `TCPSocket`-based (`lib/nonnative/port.rb`), so ensure test fixtures bind expected ports.
|
|
241
|
-
|
|
242
|
-
## Where to look first when changing behavior
|
|
140
|
+
## Where to look first
|
|
243
141
|
|
|
244
142
|
- Lifecycle orchestration: `lib/nonnative.rb`, `lib/nonnative/pool.rb`
|
|
245
143
|
- Readiness / timeouts: `lib/nonnative/port.rb`, `lib/nonnative/timeout.rb`
|
|
246
|
-
- Process
|
|
144
|
+
- Process lifecycle: `lib/nonnative/process.rb`
|
|
247
145
|
- Proxies / fault injection: `lib/nonnative/fault_injection_proxy.rb`, `lib/nonnative/socket_pair_factory.rb`
|
|
248
146
|
- Cucumber integration: `lib/nonnative/cucumber.rb`, `lib/nonnative/startup.rb`, `features/support/env.rb`
|
|
147
|
+
- Config loading: `lib/nonnative/configuration.rb`, `lib/nonnative/configuration_runner.rb`, `lib/nonnative/configuration_proxy.rb`
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
nonnative (2.
|
|
4
|
+
nonnative (2.10.0)
|
|
5
5
|
concurrent-ruby (>= 1, < 2)
|
|
6
6
|
config (>= 5, < 6)
|
|
7
7
|
cucumber (>= 7, < 11)
|
|
@@ -24,7 +24,7 @@ GEM
|
|
|
24
24
|
benchmark-malloc (0.2.0)
|
|
25
25
|
benchmark-perf (0.6.0)
|
|
26
26
|
benchmark-trend (0.4.0)
|
|
27
|
-
bigdecimal (4.
|
|
27
|
+
bigdecimal (4.1.1)
|
|
28
28
|
builder (3.3.0)
|
|
29
29
|
concurrent-ruby (1.3.6)
|
|
30
30
|
config (5.6.1)
|
|
@@ -47,7 +47,7 @@ GEM
|
|
|
47
47
|
cucumber-gherkin (> 36, < 40)
|
|
48
48
|
cucumber-messages (> 31, < 33)
|
|
49
49
|
cucumber-tag-expressions (> 6, < 9)
|
|
50
|
-
cucumber-cucumber-expressions (18.0
|
|
50
|
+
cucumber-cucumber-expressions (18.1.0)
|
|
51
51
|
bigdecimal
|
|
52
52
|
cucumber-gherkin (39.0.0)
|
|
53
53
|
cucumber-messages (>= 31, < 33)
|
|
@@ -59,29 +59,29 @@ GEM
|
|
|
59
59
|
diff-lcs (1.6.2)
|
|
60
60
|
docile (1.4.1)
|
|
61
61
|
domain_name (0.6.20240107)
|
|
62
|
-
ffi (1.17.
|
|
63
|
-
ffi (1.17.
|
|
62
|
+
ffi (1.17.4-x86_64-darwin)
|
|
63
|
+
ffi (1.17.4-x86_64-linux-gnu)
|
|
64
64
|
get_process_mem (1.0.0)
|
|
65
65
|
bigdecimal (>= 2.0)
|
|
66
66
|
ffi (~> 1.0)
|
|
67
|
-
google-protobuf (4.34.
|
|
67
|
+
google-protobuf (4.34.1-x86_64-darwin)
|
|
68
68
|
bigdecimal
|
|
69
69
|
rake (~> 13.3)
|
|
70
|
-
google-protobuf (4.34.
|
|
70
|
+
google-protobuf (4.34.1-x86_64-linux-gnu)
|
|
71
71
|
bigdecimal
|
|
72
72
|
rake (~> 13.3)
|
|
73
73
|
googleapis-common-protos-types (1.22.0)
|
|
74
74
|
google-protobuf (~> 4.26)
|
|
75
|
-
grpc (1.
|
|
75
|
+
grpc (1.80.0-x86_64-darwin)
|
|
76
76
|
google-protobuf (>= 3.25, < 5.0)
|
|
77
77
|
googleapis-common-protos-types (~> 1.0)
|
|
78
|
-
grpc (1.
|
|
78
|
+
grpc (1.80.0-x86_64-linux-gnu)
|
|
79
79
|
google-protobuf (>= 3.25, < 5.0)
|
|
80
80
|
googleapis-common-protos-types (~> 1.0)
|
|
81
81
|
http-accept (1.7.0)
|
|
82
|
-
http-cookie (1.1.
|
|
82
|
+
http-cookie (1.1.4)
|
|
83
83
|
domain_name (~> 0.5)
|
|
84
|
-
json (2.19.
|
|
84
|
+
json (2.19.3)
|
|
85
85
|
language_server-protocol (3.17.0.5)
|
|
86
86
|
lint_roller (1.1.0)
|
|
87
87
|
logger (1.7.0)
|
|
@@ -89,7 +89,7 @@ GEM
|
|
|
89
89
|
mime-types (3.7.0)
|
|
90
90
|
logger
|
|
91
91
|
mime-types-data (~> 3.2025, >= 3.2025.0507)
|
|
92
|
-
mime-types-data (3.2026.
|
|
92
|
+
mime-types-data (3.2026.0407)
|
|
93
93
|
mini_mime (1.1.5)
|
|
94
94
|
multi_test (1.1.0)
|
|
95
95
|
mustermann (3.0.4)
|
|
@@ -97,28 +97,29 @@ GEM
|
|
|
97
97
|
netrc (0.11.0)
|
|
98
98
|
nio4r (2.7.5)
|
|
99
99
|
ostruct (0.6.3)
|
|
100
|
-
parallel (1.
|
|
101
|
-
parser (3.3.
|
|
100
|
+
parallel (1.28.0)
|
|
101
|
+
parser (3.3.11.1)
|
|
102
102
|
ast (~> 2.4.1)
|
|
103
103
|
racc
|
|
104
104
|
prism (1.9.0)
|
|
105
105
|
puma (7.2.0)
|
|
106
106
|
nio4r (~> 2.0)
|
|
107
107
|
racc (1.8.1)
|
|
108
|
-
rack (3.2.
|
|
108
|
+
rack (3.2.6)
|
|
109
109
|
rack-protection (4.2.1)
|
|
110
110
|
base64 (>= 0.1.0)
|
|
111
111
|
logger (>= 1.6.0)
|
|
112
112
|
rack (>= 3.0.0, < 4)
|
|
113
|
-
rack-session (2.1.
|
|
113
|
+
rack-session (2.1.2)
|
|
114
114
|
base64 (>= 0.1.0)
|
|
115
115
|
rack (>= 3.0.0)
|
|
116
116
|
rainbow (3.1.1)
|
|
117
117
|
rake (13.3.1)
|
|
118
|
-
rbs (
|
|
118
|
+
rbs (4.0.2)
|
|
119
119
|
logger
|
|
120
|
+
prism (>= 1.6.0)
|
|
120
121
|
tsort
|
|
121
|
-
regexp_parser (2.
|
|
122
|
+
regexp_parser (2.12.0)
|
|
122
123
|
rest-client (2.1.0)
|
|
123
124
|
http-accept (>= 1.7.0, < 2.0)
|
|
124
125
|
http-cookie (>= 1.0.2, < 2.0)
|
|
@@ -160,7 +161,7 @@ GEM
|
|
|
160
161
|
rubocop-ast (1.49.1)
|
|
161
162
|
parser (>= 3.3.7.2)
|
|
162
163
|
prism (~> 1.7)
|
|
163
|
-
ruby-lsp (0.26.
|
|
164
|
+
ruby-lsp (0.26.9)
|
|
164
165
|
language_server-protocol (~> 3.17.0)
|
|
165
166
|
prism (>= 1.2, < 2.0)
|
|
166
167
|
rbs (>= 3, < 5)
|
|
@@ -182,7 +183,7 @@ GEM
|
|
|
182
183
|
rack-protection (= 4.2.1)
|
|
183
184
|
rack-session (>= 2.0.0, < 3)
|
|
184
185
|
tilt (~> 2.0)
|
|
185
|
-
sys-uname (1.5.
|
|
186
|
+
sys-uname (1.5.1)
|
|
186
187
|
ffi (~> 1.1)
|
|
187
188
|
memoist3 (~> 1.0.0)
|
|
188
189
|
tilt (2.7.0)
|
data/README.md
CHANGED
|
@@ -51,17 +51,32 @@ High-level configuration fields:
|
|
|
51
51
|
Runner fields (process/server/service):
|
|
52
52
|
- `timeout`: max time (seconds) for readiness/shutdown port checks.
|
|
53
53
|
- `wait`: small sleep (seconds) between lifecycle steps.
|
|
54
|
-
- `host`/`port`: address used for port checks
|
|
54
|
+
- `host`/`port`: client-facing address used for readiness/shutdown port checks. When a `fault_injection` proxy is enabled, this is the endpoint your tests/clients should hit.
|
|
55
55
|
- `log`: per-runner log file (used by process output redirection or server implementations).
|
|
56
56
|
|
|
57
|
+
For `fault_injection`, the nested `proxy.host`/`proxy.port` describe the upstream target behind the proxy. In-process server implementations typically bind there via `proxy.host` / `proxy.port`.
|
|
58
|
+
|
|
57
59
|
### Lifecycle strategies (Cucumber integration)
|
|
58
60
|
|
|
59
61
|
Nonnative ships Cucumber hooks (when loaded) that support these tags/strategies:
|
|
60
62
|
- `@startup`: start before scenario; stop after scenario
|
|
61
63
|
- `@manual`: stop after scenario (start is expected to be triggered manually in steps)
|
|
62
|
-
- `@clear`: clears memoized configuration and pool before scenario
|
|
64
|
+
- `@clear`: clears memoized configuration, logger, observability client, and pool before scenario
|
|
63
65
|
- `@reset`: resets proxies after scenario
|
|
64
66
|
|
|
67
|
+
The repo’s own Cucumber suite also uses taxonomy tags to classify coverage:
|
|
68
|
+
- `@acceptance`: end-to-end behavior across configured runners and clients
|
|
69
|
+
- `@contract`: lower-level contract and lifecycle behavior
|
|
70
|
+
- `@proxy`: proxy-specific behavior and failure injection
|
|
71
|
+
- `@config`: coverage that exercises YAML/config loading
|
|
72
|
+
- `@service`: scenarios centered on externally managed dependencies
|
|
73
|
+
- `@benchmark`: benchmark-only scenarios run by `make benchmarks`
|
|
74
|
+
- `@slow`: slower scenarios, currently used by benchmark coverage
|
|
75
|
+
|
|
76
|
+
`make features` excludes `@benchmark`, while `make benchmarks` runs only `@benchmark`.
|
|
77
|
+
|
|
78
|
+
Requiring `nonnative` is enough; the Cucumber hooks and step definitions are installed lazily once Cucumber’s Ruby DSL is ready.
|
|
79
|
+
|
|
65
80
|
If you want “start once per test run”, require:
|
|
66
81
|
|
|
67
82
|
```ruby
|
|
@@ -516,9 +531,11 @@ We allow different proxies to be configured. These proxies can be used to simula
|
|
|
516
531
|
- `none` (this is the default)
|
|
517
532
|
- `fault_injection`
|
|
518
533
|
|
|
534
|
+
For `fault_injection`, keep the runner `host`/`port` as the client-facing endpoint and use nested `proxy.host`/`proxy.port` for the upstream target behind the proxy.
|
|
535
|
+
|
|
519
536
|
##### Proxies Processes
|
|
520
537
|
|
|
521
|
-
|
|
538
|
+
Add this to an existing process configuration:
|
|
522
539
|
|
|
523
540
|
```ruby
|
|
524
541
|
require 'nonnative'
|
|
@@ -543,7 +560,7 @@ Nonnative.configure do |config|
|
|
|
543
560
|
end
|
|
544
561
|
```
|
|
545
562
|
|
|
546
|
-
|
|
563
|
+
YAML fragment:
|
|
547
564
|
|
|
548
565
|
```yaml
|
|
549
566
|
version: "1.0"
|
|
@@ -563,7 +580,7 @@ processes:
|
|
|
563
580
|
|
|
564
581
|
##### Proxies Servers
|
|
565
582
|
|
|
566
|
-
|
|
583
|
+
Add this to an existing server configuration:
|
|
567
584
|
|
|
568
585
|
```ruby
|
|
569
586
|
require 'nonnative'
|
|
@@ -588,7 +605,7 @@ Nonnative.configure do |config|
|
|
|
588
605
|
end
|
|
589
606
|
```
|
|
590
607
|
|
|
591
|
-
|
|
608
|
+
YAML fragment:
|
|
592
609
|
|
|
593
610
|
```yaml
|
|
594
611
|
version: "1.0"
|
|
@@ -608,7 +625,7 @@ servers:
|
|
|
608
625
|
|
|
609
626
|
##### Proxies Services
|
|
610
627
|
|
|
611
|
-
|
|
628
|
+
Add this to an existing service configuration:
|
|
612
629
|
|
|
613
630
|
```ruby
|
|
614
631
|
require 'nonnative'
|
|
@@ -622,12 +639,12 @@ Nonnative.configure do |config|
|
|
|
622
639
|
config.service do |s|
|
|
623
640
|
s.name = 'redis'
|
|
624
641
|
s.host = '127.0.0.1'
|
|
625
|
-
s.port =
|
|
642
|
+
s.port = 16_379
|
|
626
643
|
|
|
627
644
|
s.proxy = {
|
|
628
645
|
kind: 'fault_injection',
|
|
629
646
|
host: '127.0.0.1',
|
|
630
|
-
port:
|
|
647
|
+
port: 6379,
|
|
631
648
|
log: 'proxy_server.log',
|
|
632
649
|
wait: 1,
|
|
633
650
|
options: {
|
|
@@ -638,19 +655,22 @@ Nonnative.configure do |config|
|
|
|
638
655
|
end
|
|
639
656
|
```
|
|
640
657
|
|
|
641
|
-
|
|
658
|
+
YAML fragment:
|
|
642
659
|
|
|
643
660
|
```yaml
|
|
644
661
|
version: "1.0"
|
|
645
662
|
name: test
|
|
646
663
|
url: http://localhost:4567
|
|
647
664
|
log: nonnative.log
|
|
648
|
-
wait: 1
|
|
649
665
|
services:
|
|
650
666
|
-
|
|
667
|
+
name: redis
|
|
668
|
+
host: 127.0.0.1
|
|
669
|
+
port: 16379
|
|
651
670
|
proxy:
|
|
652
671
|
kind: fault_injection
|
|
653
|
-
|
|
672
|
+
host: 127.0.0.1
|
|
673
|
+
port: 6379
|
|
654
674
|
log: proxy_server.log
|
|
655
675
|
wait: 1
|
|
656
676
|
options:
|