nonnative 3.13.0 → 3.14.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 +1 -1
- data/AGENTS.md +26 -0
- data/Gemfile.lock +1 -1
- data/README.md +3 -0
- data/lib/nonnative/configuration_proxy.rb +2 -2
- data/lib/nonnative/cucumber.rb +1 -0
- data/lib/nonnative/fault_injection_proxy.rb +12 -0
- data/lib/nonnative/socket_pair.rb +1 -0
- data/lib/nonnative/socket_pair_factory.rb +5 -1
- data/lib/nonnative/timeout_socket_pair.rb +30 -0
- data/lib/nonnative/version.rb +1 -1
- data/lib/nonnative.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 802f0ee020ba8e7c6cef867895d30c6491ace313fec8103aa6b99726c8402666
|
|
4
|
+
data.tar.gz: 70d522685a3c9cfbc872ee36549d9ba8274be60138a79db68e64c83115fd7cb5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a0b3e8502437cfd6d3a556a8a6f10901a2a89d85a4689fbad3c68d6819e03b4cccf5a51de3cfd66b86827d66f768891f68ee41c91b3ea504345c7f25d22178c8
|
|
7
|
+
data.tar.gz: b16ef6cfe6099e9a62be954178c71a743fb297ece661be2651239c8501707af30e1609e58abfe99bc58d007777a45c99505eb374484c0ba9788e886d0b876e42
|
data/.circleci/config.yml
CHANGED
data/AGENTS.md
CHANGED
|
@@ -79,6 +79,32 @@ of dependencies.
|
|
|
79
79
|
thread. Do not flag the listener `join` as an unbounded reliability gap unless
|
|
80
80
|
the task is explicitly about proxy shutdown behavior or there is a normal-use
|
|
81
81
|
reproducer, failing CI evidence, or platform-specific hang evidence.
|
|
82
|
+
- Service readiness is intentionally TCP-only for externally managed
|
|
83
|
+
dependencies. Do not flag missing HTTP/gRPC service readiness as a feature gap
|
|
84
|
+
unless the task is explicitly about changing the `Nonnative::Service`
|
|
85
|
+
readiness model. HTTP/gRPC readiness belongs to managed processes, where the
|
|
86
|
+
user explicitly models the application health endpoints.
|
|
87
|
+
- Process runners intentionally inherit the parent working directory. Nonnative
|
|
88
|
+
is normally run from the test folder that owns `test/nonnative.yml`, relative
|
|
89
|
+
config paths, logs, and reports. Do not flag missing process cwd/chdir support
|
|
90
|
+
as a feature gap unless the task is explicitly about changing process working
|
|
91
|
+
directory behavior.
|
|
92
|
+
- Message-specific start/stop assertions and attempted-stop success assertions
|
|
93
|
+
in `features/step_definitions/lifecycle_steps.rb` are repository-local
|
|
94
|
+
Cucumber helpers. Do not flag their absence from `lib/nonnative/cucumber.rb`
|
|
95
|
+
as a feature gap unless downstream usage evidence exists or the task is
|
|
96
|
+
explicitly about expanding public lifecycle assertion steps.
|
|
97
|
+
- Liveness, readiness, and metrics endpoint assertion steps in
|
|
98
|
+
`features/step_definitions/servers_steps.rb` are repository-local Cucumber
|
|
99
|
+
helpers for testing nonnative's own framework assumptions. Do not flag their
|
|
100
|
+
absence from `lib/nonnative/cucumber.rb` as a feature gap unless downstream
|
|
101
|
+
usage evidence exists or the task is explicitly about expanding public
|
|
102
|
+
observability assertion steps.
|
|
103
|
+
- `Nonnative::Configuration` intentionally exposes `process_by_name` without
|
|
104
|
+
matching `server_by_name` or `service_by_name` helpers. Do not flag missing
|
|
105
|
+
server/service configuration lookup helpers as a feature gap unless downstream
|
|
106
|
+
usage evidence exists or the task is explicitly about changing the
|
|
107
|
+
pre-start configuration lookup API.
|
|
82
108
|
|
|
83
109
|
## Runtime Model
|
|
84
110
|
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -758,6 +758,7 @@ Clients connect to the service `host`/`port`, while the proxy forwards traffic t
|
|
|
758
758
|
|
|
759
759
|
- `close_all` - Closes the socket as soon as it connects.
|
|
760
760
|
- `delay` - Delays traffic on the connection. Defaults to 2 seconds and can be configured through options.
|
|
761
|
+
- `timeout` - Accepts the connection and stalls traffic until reset or stop closes the connection, so clients exercise their own read timeout behavior.
|
|
761
762
|
- `invalid_data` - Forwards client requests unchanged, then corrupts upstream responses before they reach the client.
|
|
762
763
|
|
|
763
764
|
###### 🧩 Fault Injection Services
|
|
@@ -769,6 +770,7 @@ name = 'name of service in configuration'
|
|
|
769
770
|
service = Nonnative.pool.service_by_name(name)
|
|
770
771
|
|
|
771
772
|
service.proxy.close_all # To use close_all.
|
|
773
|
+
service.proxy.timeout # To stall traffic until reset or stop.
|
|
772
774
|
service.proxy.reset # To reset it back to a good state.
|
|
773
775
|
```
|
|
774
776
|
|
|
@@ -776,6 +778,7 @@ Use the Cucumber proxy steps:
|
|
|
776
778
|
|
|
777
779
|
```cucumber
|
|
778
780
|
Given I set the proxy for service 'service_1' to 'close_all'
|
|
781
|
+
Given I set the proxy for service 'service_1' to 'timeout'
|
|
779
782
|
Then I should reset the proxy for service 'service_1'
|
|
780
783
|
```
|
|
781
784
|
|
|
@@ -4,8 +4,8 @@ module Nonnative
|
|
|
4
4
|
# Proxy configuration attached to a service configuration.
|
|
5
5
|
#
|
|
6
6
|
# A proxy allows you to interpose behavior between a client and a real service. For example,
|
|
7
|
-
# the built-in `"fault_injection"` proxy can close connections, introduce delays,
|
|
8
|
-
# for resilience testing.
|
|
7
|
+
# the built-in `"fault_injection"` proxy can close connections, introduce delays, stall traffic,
|
|
8
|
+
# or corrupt data for resilience testing.
|
|
9
9
|
#
|
|
10
10
|
# This object is created automatically for each service via {Nonnative::ConfigurationService}.
|
|
11
11
|
# When `kind` is set to `"none"`, no proxy is started and the service will use its configured
|
data/lib/nonnative/cucumber.rb
CHANGED
|
@@ -11,6 +11,7 @@ module Nonnative
|
|
|
11
11
|
#
|
|
12
12
|
# - {#close_all}: close connections immediately on accept
|
|
13
13
|
# - {#delay}: delay reads by a configured duration (default: 2 seconds)
|
|
14
|
+
# - {#timeout}: accept connections and keep them silent until clients time out
|
|
14
15
|
# - {#invalid_data}: forward requests unchanged and mutate upstream responses before they reach clients
|
|
15
16
|
# - {#reset}: return to healthy pass-through behavior
|
|
16
17
|
#
|
|
@@ -107,6 +108,17 @@ module Nonnative
|
|
|
107
108
|
apply_state :delay
|
|
108
109
|
end
|
|
109
110
|
|
|
111
|
+
# Accepts connections and stalls without forwarding bytes.
|
|
112
|
+
#
|
|
113
|
+
# This simulates a dependency that accepts a TCP connection but leaves clients waiting until
|
|
114
|
+
# their own read timeout fires. The proxy keeps the connection silent until reset or stop closes
|
|
115
|
+
# active connections.
|
|
116
|
+
#
|
|
117
|
+
# @return [void]
|
|
118
|
+
def timeout
|
|
119
|
+
apply_state :timeout
|
|
120
|
+
end
|
|
121
|
+
|
|
110
122
|
# Mutates upstream responses while forwarding client requests unchanged.
|
|
111
123
|
#
|
|
112
124
|
# @return [void]
|
|
@@ -16,6 +16,7 @@ module Nonnative
|
|
|
16
16
|
# @see Nonnative::SocketPairFactory
|
|
17
17
|
# @see Nonnative::CloseAllSocketPair
|
|
18
18
|
# @see Nonnative::DelaySocketPair
|
|
19
|
+
# @see Nonnative::TimeoutSocketPair
|
|
19
20
|
# @see Nonnative::InvalidDataSocketPair
|
|
20
21
|
class SocketPair
|
|
21
22
|
# @param proxy [#host, #port, #options] proxy configuration used to connect upstream
|
|
@@ -10,18 +10,20 @@ module Nonnative
|
|
|
10
10
|
# - `:none` (or any unknown value) -> {Nonnative::SocketPair} (pass-through)
|
|
11
11
|
# - `:close_all` -> {Nonnative::CloseAllSocketPair}
|
|
12
12
|
# - `:delay` -> {Nonnative::DelaySocketPair}
|
|
13
|
+
# - `:timeout` -> {Nonnative::TimeoutSocketPair}
|
|
13
14
|
# - `:invalid_data` -> {Nonnative::InvalidDataSocketPair}
|
|
14
15
|
#
|
|
15
16
|
# @see Nonnative::FaultInjectionProxy
|
|
16
17
|
# @see Nonnative::SocketPair
|
|
17
18
|
# @see Nonnative::CloseAllSocketPair
|
|
18
19
|
# @see Nonnative::DelaySocketPair
|
|
20
|
+
# @see Nonnative::TimeoutSocketPair
|
|
19
21
|
# @see Nonnative::InvalidDataSocketPair
|
|
20
22
|
class SocketPairFactory
|
|
21
23
|
class << self
|
|
22
24
|
# Creates a socket-pair instance for the given proxy state.
|
|
23
25
|
#
|
|
24
|
-
# @param kind [Symbol] proxy state (e.g. `:none`, `:close_all`, `:delay`, `:invalid_data`)
|
|
26
|
+
# @param kind [Symbol] proxy state (e.g. `:none`, `:close_all`, `:delay`, `:timeout`, `:invalid_data`)
|
|
25
27
|
# @param proxy [Nonnative::ConfigurationProxy] proxy configuration (host/port/options)
|
|
26
28
|
# @return [Nonnative::SocketPair] a socket-pair implementation instance
|
|
27
29
|
def create(kind, proxy)
|
|
@@ -30,6 +32,8 @@ module Nonnative
|
|
|
30
32
|
CloseAllSocketPair
|
|
31
33
|
when :delay
|
|
32
34
|
DelaySocketPair
|
|
35
|
+
when :timeout
|
|
36
|
+
TimeoutSocketPair
|
|
33
37
|
when :invalid_data
|
|
34
38
|
InvalidDataSocketPair
|
|
35
39
|
else
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Nonnative
|
|
4
|
+
# Socket-pair variant used by the fault-injection proxy to simulate read timeouts.
|
|
5
|
+
#
|
|
6
|
+
# When active, the proxy accepts the client connection and keeps it open without forwarding bytes.
|
|
7
|
+
# Clients with read deadlines should observe their own timeout behavior.
|
|
8
|
+
#
|
|
9
|
+
# This behavior is enabled by calling {Nonnative::FaultInjectionProxy#timeout}.
|
|
10
|
+
#
|
|
11
|
+
# @see Nonnative::FaultInjectionProxy
|
|
12
|
+
# @see Nonnative::SocketPairFactory
|
|
13
|
+
# @see Nonnative::SocketPair
|
|
14
|
+
class TimeoutSocketPair < SocketPair
|
|
15
|
+
# Keeps the accepted socket silent until reset or stop closes active proxy connections.
|
|
16
|
+
#
|
|
17
|
+
# @param local_socket [TCPSocket] the accepted client socket
|
|
18
|
+
# @return [void]
|
|
19
|
+
def connect(local_socket)
|
|
20
|
+
@local_socket = local_socket
|
|
21
|
+
|
|
22
|
+
Nonnative.logger.info "stalling socket '#{local_socket.inspect}' for 'timeout' pair"
|
|
23
|
+
|
|
24
|
+
# Do not call super: the base implementation opens the upstream socket and forwards traffic.
|
|
25
|
+
sleep 0.1 until local_socket.closed?
|
|
26
|
+
ensure
|
|
27
|
+
close
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
data/lib/nonnative/version.rb
CHANGED
data/lib/nonnative.rb
CHANGED
|
@@ -102,6 +102,7 @@ require 'nonnative/fault_injection_proxy'
|
|
|
102
102
|
require 'nonnative/socket_pair'
|
|
103
103
|
require 'nonnative/close_all_socket_pair'
|
|
104
104
|
require 'nonnative/delay_socket_pair'
|
|
105
|
+
require 'nonnative/timeout_socket_pair'
|
|
105
106
|
require 'nonnative/invalid_data_socket_pair'
|
|
106
107
|
require 'nonnative/socket_pair_factory'
|
|
107
108
|
require 'nonnative/go_executable'
|
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: 3.
|
|
4
|
+
version: 3.14.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alejandro Falkowski
|
|
@@ -330,6 +330,7 @@ files:
|
|
|
330
330
|
- lib/nonnative/stop_error.rb
|
|
331
331
|
- lib/nonnative/tcp_probe.rb
|
|
332
332
|
- lib/nonnative/timeout.rb
|
|
333
|
+
- lib/nonnative/timeout_socket_pair.rb
|
|
333
334
|
- lib/nonnative/version.rb
|
|
334
335
|
- nonnative.gemspec
|
|
335
336
|
homepage: https://github.com/alexfalkowski/nonnative
|