nonnative 3.19.0 → 3.26.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.
@@ -26,6 +26,15 @@ module Nonnative
26
26
  service.name
27
27
  end
28
28
 
29
+ # Describes how the runner terminated before becoming ready, for lifecycle diagnostics.
30
+ #
31
+ # Base runners report nothing; {Nonnative::Process} overrides this to describe an early exit.
32
+ #
33
+ # @return [String, nil]
34
+ def termination
35
+ nil
36
+ end
37
+
29
38
  protected
30
39
 
31
40
  # Returns the underlying configuration object.
@@ -13,6 +13,7 @@ module Nonnative
13
13
  # - `:delay` -> {Nonnative::DelaySocketPair}
14
14
  # - `:timeout` -> {Nonnative::TimeoutSocketPair}
15
15
  # - `:invalid_data` -> {Nonnative::InvalidDataSocketPair}
16
+ # - `:bandwidth` -> {Nonnative::BandwidthSocketPair}
16
17
  #
17
18
  # @see Nonnative::FaultInjectionProxy
18
19
  # @see Nonnative::SocketPair
@@ -21,11 +22,12 @@ module Nonnative
21
22
  # @see Nonnative::DelaySocketPair
22
23
  # @see Nonnative::TimeoutSocketPair
23
24
  # @see Nonnative::InvalidDataSocketPair
25
+ # @see Nonnative::BandwidthSocketPair
24
26
  class SocketPairFactory
25
27
  class << self
26
28
  # Creates a socket-pair instance for the given proxy state.
27
29
  #
28
- # @param kind [Symbol] proxy state (e.g. `:none`, `:close_all`, `:reset_peer`, `:delay`, `:timeout`, `:invalid_data`)
30
+ # @param kind [Symbol] proxy state (e.g. `:none`, `:close_all`, `:reset_peer`, `:delay`, `:timeout`, `:invalid_data`, `:bandwidth`)
29
31
  # @param proxy [Nonnative::ConfigurationProxy] proxy configuration (host/port/options)
30
32
  # @return [Nonnative::SocketPair] a socket-pair implementation instance
31
33
  def create(kind, proxy)
@@ -40,6 +42,8 @@ module Nonnative
40
42
  TimeoutSocketPair
41
43
  when :invalid_data
42
44
  InvalidDataSocketPair
45
+ when :bandwidth
46
+ BandwidthSocketPair
43
47
  else
44
48
  SocketPair
45
49
  end
@@ -30,18 +30,25 @@ module Nonnative
30
30
 
31
31
  # Generates a signed SSH token.
32
32
  #
33
+ # SSH tokens carry only `iat`/`exp` (in Unix nanoseconds); there is no `nbf` claim, so
34
+ # `not_before` is rejected.
35
+ #
33
36
  # @param aud [String] the `aud` claim (for example `"GET /v1/things"` or a gRPC full method)
37
+ # @param issued_at [Time, nil] overrides the `iat` claim (default: now)
38
+ # @param expires_at [Time, nil] overrides the `exp` claim (default: `issued_at` plus `expiration`)
39
+ # @raise [ArgumentError] if `not_before` is given (SSH tokens have no `nbf` claim)
34
40
  # @return [String] the token, `"<base64(claims)>.<base64(signature)>"`
35
- def generate(aud:, **)
36
- now = Time.now
37
- issued_at = (now.to_i * 1_000_000_000) + now.nsec
41
+ def generate(aud:, issued_at: nil, expires_at: nil, not_before: nil, **)
42
+ raise ArgumentError, "ssh tokens do not support 'not_before' (no nbf claim)" unless not_before.nil?
43
+
44
+ iat = nanoseconds(issued_at || Time.now)
38
45
  claims = {
39
46
  ver: TOKEN_VERSION,
40
47
  kid: @key,
41
48
  sub: @key,
42
49
  aud: aud,
43
- iat: issued_at,
44
- exp: issued_at + (@expiration * 1_000_000_000)
50
+ iat: iat,
51
+ exp: expires_at ? nanoseconds(expires_at) : iat + (@expiration * 1_000_000_000)
45
52
  }.to_json
46
53
 
47
54
  signature = Ed25519::SigningKey.new(seed).sign(claims)
@@ -51,6 +58,10 @@ module Nonnative
51
58
 
52
59
  private
53
60
 
61
+ def nanoseconds(time)
62
+ (time.to_i * 1_000_000_000) + time.nsec
63
+ end
64
+
54
65
  def seed
55
66
  SSHData::PrivateKey.parse_openssh(File.read(@private_key)).first.sk[0, 32]
56
67
  end
@@ -54,11 +54,20 @@ module Nonnative
54
54
 
55
55
  # Generates a signed token.
56
56
  #
57
+ # The optional time claims default to the current time (and the constructor `expiration`), so
58
+ # omitting them reproduces the token's normal claims. Supply them to mint tokens with specific
59
+ # time claims for negative auth tests, such as a not-yet-valid (future `not_before`) or
60
+ # clock-skewed token. Times are absolute; the `ssh` kind has no `nbf` claim and rejects
61
+ # `not_before`.
62
+ #
57
63
  # @param aud [String] the `aud` claim
58
64
  # @param sub [String] the `sub` claim
65
+ # @param issued_at [Time, nil] overrides the `iat` claim (default: now)
66
+ # @param not_before [Time, nil] overrides the `nbf` claim (default: `issued_at`); unsupported by `ssh`
67
+ # @param expires_at [Time, nil] overrides the `exp` claim (default: `issued_at` plus `expiration`)
59
68
  # @return [String] the signed token
60
- def generate(aud:, sub:)
61
- @token.generate(aud: aud, sub: sub)
69
+ def generate(aud:, sub:, issued_at: nil, not_before: nil, expires_at: nil)
70
+ @token.generate(aud: aud, sub: sub, issued_at: issued_at, not_before: not_before, expires_at: expires_at)
62
71
  end
63
72
  end
64
73
  end
@@ -4,5 +4,5 @@ module Nonnative
4
4
  # The current gem version.
5
5
  #
6
6
  # @return [String]
7
- VERSION = '3.19.0'
7
+ VERSION = '3.26.0'
8
8
  end
data/lib/nonnative.rb CHANGED
@@ -115,6 +115,7 @@ require 'nonnative/reset_peer_socket_pair'
115
115
  require 'nonnative/delay_socket_pair'
116
116
  require 'nonnative/timeout_socket_pair'
117
117
  require 'nonnative/invalid_data_socket_pair'
118
+ require 'nonnative/bandwidth_socket_pair'
118
119
  require 'nonnative/socket_pair_factory'
119
120
  require 'nonnative/go_executable'
120
121
  require 'nonnative/cucumber'
@@ -270,10 +271,7 @@ module Nonnative
270
271
  def start
271
272
  @pool ||= Nonnative::Pool.new(configuration)
272
273
  errors = []
273
- errors.concat(@pool.start do |name, values, result, ports|
274
- id, started = values
275
- errors << "Started #{name} with id #{id}, though did not respond in time for #{ports.description}" if !started || !result
276
- end)
274
+ errors.concat(@pool.start)
277
275
  nil
278
276
  rescue StandardError => e
279
277
  errors << unexpected_lifecycle_error(:start, e)
@@ -293,11 +291,7 @@ module Nonnative
293
291
  errors = []
294
292
  return if @pool.nil?
295
293
 
296
- errors.concat(@pool.stop do |name, values, result, ports|
297
- id, stopped = Array(values).then { |v| [v.first, v.fetch(1, true)] }
298
- errors << "Stopped #{name} with id #{id}, though did not respond in time for #{ports.description}" unless result
299
- errors << "Stopped #{name} with id #{id}, though the process did not exit in time" unless stopped
300
- end)
294
+ errors.concat(@pool.stop)
301
295
  nil
302
296
  rescue StandardError => e
303
297
  errors << unexpected_lifecycle_error(:stop, e)
@@ -362,11 +356,7 @@ module Nonnative
362
356
  errors = []
363
357
  return errors if @pool.nil?
364
358
 
365
- errors.concat(@pool.rollback do |name, values, result, ports|
366
- id, stopped = Array(values).then { |v| [v.first, v.fetch(1, true)] }
367
- errors << "Rollback failed for #{name} with id #{id}, because it did not stop in time for #{ports.description}" unless result
368
- errors << "Rollback failed for #{name} with id #{id}, because the process did not exit in time" unless stopped
369
- end)
359
+ errors.concat(@pool.rollback)
370
360
  rescue StandardError => e
371
361
  errors << unexpected_lifecycle_error(:rollback, e)
372
362
  ensure
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.19.0
4
+ version: 3.26.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alejandro Falkowski
@@ -391,24 +391,10 @@ executables: []
391
391
  extensions: []
392
392
  extra_rdoc_files: []
393
393
  files:
394
- - ".circleci/config.yml"
395
- - ".claude/skills"
396
- - ".codecov.yml"
397
- - ".config/cucumber.yml"
398
- - ".editorconfig"
399
- - ".github/dependabot.yml"
400
- - ".gitignore"
401
- - ".gitmodules"
402
- - ".goreleaser.yml"
403
- - ".rubocop.yml"
404
- - AGENTS.md
405
- - CLAUDE.md
406
- - Gemfile
407
- - Gemfile.lock
408
394
  - LICENSE
409
- - Makefile
410
395
  - README.md
411
396
  - lib/nonnative.rb
397
+ - lib/nonnative/bandwidth_socket_pair.rb
412
398
  - lib/nonnative/close_all_socket_pair.rb
413
399
  - lib/nonnative/configuration.rb
414
400
  - lib/nonnative/configuration_file.rb
@@ -461,7 +447,6 @@ files:
461
447
  - lib/nonnative/timeout_socket_pair.rb
462
448
  - lib/nonnative/token.rb
463
449
  - lib/nonnative/version.rb
464
- - nonnative.gemspec
465
450
  homepage: https://github.com/alexfalkowski/nonnative
466
451
  licenses:
467
452
  - MIT
data/.circleci/config.yml DELETED
@@ -1,97 +0,0 @@
1
- version: 2.1
2
-
3
- commands:
4
- sync-submodules:
5
- steps:
6
- - run: git submodule sync
7
- - run: git submodule update --init
8
- checkout-submodules:
9
- steps:
10
- - checkout:
11
- method: blobless
12
- - sync-submodules
13
-
14
- executors:
15
- ruby:
16
- docker:
17
- - image: alexfalkowski/ruby:3.20
18
- release:
19
- docker:
20
- - image: alexfalkowski/release:8.22
21
- alpine:
22
- docker:
23
- - image: alpine:latest
24
-
25
- jobs:
26
- build:
27
- executor: ruby
28
- working_directory: ~/nonnative
29
- steps:
30
- - checkout-submodules
31
- - run: make source-key
32
- - restore_cache:
33
- name: restore deps
34
- keys:
35
- - nonnative-ruby-cache-{{ checksum "Gemfile.lock" }}-{{ checksum "~/.ruby-version" }}
36
- - nonnative-ruby-cache-
37
- - run: make dep
38
- - run: make clean-dep
39
- - save_cache:
40
- name: save deps
41
- key: nonnative-ruby-cache-{{ checksum "Gemfile.lock" }}-{{ checksum "~/.ruby-version" }}
42
- paths:
43
- - vendor
44
- - run: make lint
45
- - run: make sec
46
- - run: make features
47
- - run: make benchmarks
48
- - store_test_results:
49
- path: test/reports
50
- - store_artifacts:
51
- path: test/reports
52
- - run: make codecov-upload
53
- resource_class: arm.large
54
- sync:
55
- executor: release
56
- working_directory: ~/nonnative
57
- steps:
58
- - checkout-submodules
59
- - run: make sync push
60
- resource_class: arm.large
61
- version:
62
- executor: release
63
- working_directory: ~/nonnative
64
- steps:
65
- - checkout-submodules
66
- - run: version
67
- - run: package
68
- resource_class: arm.large
69
- wait-all:
70
- executor: alpine
71
- resource_class: small
72
- steps:
73
- - run: echo "all applicable jobs finished"
74
-
75
- workflows:
76
- nonnative:
77
- jobs:
78
- - build
79
- - sync:
80
- requires:
81
- - build
82
- filters:
83
- branches:
84
- ignore: master
85
- - version:
86
- context: gh
87
- serial-group: << pipeline.project.slug >>/version
88
- requires:
89
- - build
90
- filters:
91
- branches:
92
- only: master
93
- - wait-all:
94
- requires:
95
- - build
96
- - sync
97
- - version
data/.claude/skills DELETED
@@ -1 +0,0 @@
1
- ../bin/skills
data/.codecov.yml DELETED
@@ -1,6 +0,0 @@
1
- coverage:
2
- precision: 2
3
- round: down
4
- range: "80...100"
5
- status:
6
- patch: false
data/.config/cucumber.yml DELETED
@@ -1 +0,0 @@
1
- report: --format junit --out test/reports --format html --out test/reports/index.html --format pretty --publish-quiet
data/.editorconfig DELETED
@@ -1,13 +0,0 @@
1
- root = true
2
-
3
- [*]
4
- charset = utf-8
5
- end_of_line = lf
6
- indent_style = space
7
- indent_size = 2
8
- insert_final_newline = true
9
- trim_trailing_whitespace = true
10
-
11
- [Makefile]
12
- indent_style = tab
13
- indent_size = 8
@@ -1,20 +0,0 @@
1
- version: 2
2
- updates:
3
- - package-ecosystem: "bundler"
4
- directory: "/"
5
- schedule:
6
- interval: "daily"
7
- commit-message:
8
- prefix: "test"
9
- prefix-development: "build"
10
- include: "scope"
11
- - package-ecosystem: "gitsubmodule"
12
- directory: "/"
13
- schedule:
14
- interval: "daily"
15
- commit-message:
16
- prefix: "build"
17
- prefix-development: "build"
18
- include: "scope"
19
- allow:
20
- - dependency-name: "bin"
data/.gitignore DELETED
@@ -1,18 +0,0 @@
1
- /.bundle/
2
- .crush/
3
- .ruby-lsp/
4
- .source-key
5
- /.yardoc
6
- /_yardoc/
7
- /doc/
8
- /pkg/
9
- ISSUES.md
10
- TESTS.md
11
- DOCS.md
12
- FEATURES.md
13
- PROJECTS.md
14
- RELIABILITY.md
15
- test/reports/*
16
- !test/reports/.keep
17
- /tmp/
18
- vendor/
data/.gitmodules DELETED
@@ -1,3 +0,0 @@
1
- [submodule "bin"]
2
- path = bin
3
- url = git@github.com:alexfalkowski/bin.git
data/.goreleaser.yml DELETED
@@ -1,17 +0,0 @@
1
- version: 2
2
-
3
- builds:
4
- - skip: true
5
-
6
- changelog:
7
- sort: asc
8
- filters:
9
- exclude:
10
- - "^chore"
11
-
12
- release:
13
- footer: >-
14
-
15
- ---
16
-
17
- Released by [GoReleaser](https://github.com/goreleaser/goreleaser).
data/.rubocop.yml DELETED
@@ -1,35 +0,0 @@
1
- AllCops:
2
- TargetRubyVersion: 4.0
3
- DisplayCopNames: true
4
- NewCops: enable
5
- Exclude:
6
- - "bin/**/*"
7
- - "vendor/**/*"
8
- - "test/grpc/**/*"
9
-
10
- Layout/LineLength:
11
- Max: 150
12
-
13
- Lint/HashCompareByIdentity:
14
- Enabled: false
15
-
16
- Metrics/MethodLength:
17
- Max: 20
18
-
19
- Metrics/BlockLength:
20
- Max: 90
21
-
22
- Metrics/AbcSize:
23
- Max: 25
24
-
25
- Metrics/ClassLength:
26
- Max: 150
27
-
28
- Style/Documentation:
29
- Enabled: false
30
-
31
- Style/NumericPredicate:
32
- Enabled: false
33
-
34
- Style/FileOpen:
35
- Enabled: false
data/AGENTS.md DELETED
@@ -1,208 +0,0 @@
1
- # AGENTS.md
2
-
3
- ## Shared guidance
4
-
5
- Use `bin/AGENTS.md` for shared skills and cross-repository defaults.
6
-
7
- `nonnative` is a Ruby gem for end-to-end testing systems implemented in other
8
- languages. It starts processes, in-process servers, and proxy-only services,
9
- waits on TCP readiness/shutdown, and can place fault-injection proxies in front
10
- of dependencies.
11
-
12
- ## Map And Commands
13
-
14
- - Library: `lib/nonnative/**/*.rb`
15
- - Cucumber features/support: `features/**/*.feature`, `features/support/**/*.rb`, `features/step_definitions/**/*.rb`
16
- - Generated gRPC test stubs: `test/grpc/**/*`
17
- - Test protos: `test/nonnative/v1/*.proto`
18
- - Build wiring: root `Makefile` includes `bin/build/make/*.mak`
19
- - Required submodule: `bin/`; missing submodule setup breaks `make`
20
- - Install deps: `make dep`
21
- - Lint: `make lint`
22
- - Security checks: `make sec`
23
- - Features: `make features`
24
- - Benchmarks only: `make benchmarks`
25
- - Cleanup: `make clean-dep`, `make clean-reports`
26
-
27
- ## Intentional Design Choices
28
-
29
- - The configured HTTP proxy feature intentionally uses the external
30
- `www.afalkowski.com` host through `features/support/http_proxy_server.rb`.
31
- Do not flag this external dependency as a code issue unless the task is
32
- explicitly about making HTTP proxy fixtures fully hermetic.
33
- - `test/Makefile` intentionally consumes the shared Buf make fragment as-is.
34
- Do not flag its inherited `breaking` target's `subdir=api` comparison as a
35
- code issue unless the task is explicitly about changing test proto breaking
36
- checks.
37
- - `nonnative` is a test-support gem used across many downstream projects.
38
- Do not flag the absence of an isolated gem build/install smoke test as a
39
- test gap unless the task is explicitly about release packaging or gem
40
- publication validation.
41
- - The Cucumber `@startup` lifecycle tag is exercised by downstream projects
42
- that use this gem. Do not flag missing in-repository `@startup` acceptance
43
- coverage as a test gap unless the task is explicitly about changing
44
- Cucumber startup hook behavior.
45
- - `Nonnative.go_argv` and `Nonnative.go_command` flag combinations are checked
46
- by external/downstream usage. Do not flag missing in-repository exhaustive
47
- `-test.*` flag or tool-filtering assertions as a test gap unless the task is
48
- explicitly about changing Go command generation.
49
- - Generated gRPC test stubs under `test/grpc/` are updated on demand when the
50
- test proto changes. Do not flag the absence of an automatic generated-stub
51
- freshness check as a test gap unless the task is explicitly about changing
52
- test proto generation or generated-file validation.
53
- - Generated gRPC test stubs may carry manual require-path adjustments after
54
- generation. Do not treat `make -C test stale` as a required validation target
55
- unless the task is explicitly about changing test proto generation; verify
56
- the generated Ruby loads before accepting generator-only rewrites.
57
- - Buf linting for the test-only proto module is intentionally not part of the
58
- required local validation surface. Do not flag missing root-level validation
59
- for `test/buf.yaml` as a test gap unless the task is explicitly about test
60
- proto linting or Buf validation.
61
- - The public proxy reset Cucumber steps and `@reset` hook are tested by
62
- external/downstream suites. Do not flag missing in-repository direct proxy
63
- reset step coverage as a test gap unless the task is explicitly about
64
- changing proxy reset behavior.
65
- - `Nonnative.clear` configuration and pool reset behavior is covered by
66
- external/downstream suites. Do not flag missing in-repository assertions for
67
- configuration or pool clearing as a test gap unless the task is explicitly
68
- about changing clear/reset lifecycle behavior.
69
- - Full repository validation is expected to run both regular features and
70
- benchmark-tagged lifecycle scenarios. Do not flag rollback/timeout lifecycle
71
- coverage living under `features/benchmark.feature` as a test gap unless the
72
- task is explicitly about changing validation target composition.
73
- - Service proxy round-trip behavior is validated by downstream projects that
74
- use `nonnative` against real dependencies. Do not flag the in-repository
75
- service proxy success scenario's connection-only assertion as a test gap
76
- unless the task is explicitly about changing service proxy forwarding.
77
- - `Nonnative::FaultInjectionProxy` owns its listener thread and stops it by
78
- closing the owned `TCPServer`, which wakes the accept loop before joining the
79
- thread. Do not flag the listener `join` as an unbounded reliability gap unless
80
- the task is explicitly about proxy shutdown behavior or there is a normal-use
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.
108
-
109
- ## Runtime Model
110
-
111
- Public entry point: `lib/nonnative.rb`.
112
-
113
- Main API: `configure`, `start`, `stop`, `clear`, `reset`, `pool`,
114
- `go_argv`, `go_command`, `token`.
115
-
116
- Configuration is `Nonnative::Configuration`, built with
117
- `config.process`, `config.server`, `config.service`, or
118
- `config.load_file(...)`.
119
-
120
- Runners:
121
-
122
- - `Nonnative::Process`: OS process
123
- - `Nonnative::Server`: in-process Ruby server thread
124
- - `Nonnative::Service`: proxy lifecycle for an externally managed dependency
125
-
126
- `Nonnative::Pool` starts services first, then servers/processes, and stops in
127
- reverse. Readiness and shutdown checks are TCP-only via
128
- `Nonnative::Port#open?` and `#closed?`.
129
-
130
- Token generation: `Nonnative.token(kind:, issuer:, key:, private_key:, expiration:)`
131
- returns a `Nonnative::Token` whose `generate(aud:, sub:)` produces a signed token for
132
- authenticating against services under test; it feeds `Nonnative::Header.auth_bearer`.
133
- Kinds are `jwt` (EdDSA, `kid` header), `paseto` (v4.public, `kid` footer), and `ssh`
134
- (go-service style raw-Ed25519 `base64(claims).base64(signature)`). All Ed25519 and
135
- generation-only. `jwt`/`paseto` take a PKCS#8 PEM key; `ssh` takes an OpenSSH-format
136
- key. PASETO needs system libsodium (via `rbnacl`), required lazily so `require
137
- 'nonnative'` works without it until a PASETO token is generated.
138
- `Nonnative::Token.http_audience` / `grpc_audience` build the endpoint-scoped `aud`.
139
-
140
- ## Cucumber Surface
141
-
142
- `lib/nonnative/cucumber.rb` is public compatibility surface. Do not remove or
143
- rename hooks/step text unless the user explicitly requests a breaking change.
144
-
145
- Lifecycle tags:
146
-
147
- - `@startup`: start before scenario, stop after scenario
148
- - `@manual`: scenario starts manually, stop after scenario
149
- - `@clear`: call `Nonnative.clear` before scenario
150
- - `@reset`: reset proxies after scenario
151
-
152
- Suite taxonomy tags: `@acceptance`, `@contract`, `@proxy`, `@config`,
153
- `@service`, `@benchmark`, `@slow`. `make features` excludes `@benchmark`;
154
- `make benchmarks` runs only `@benchmark`.
155
-
156
- `Nonnative.clear` clears configuration, logger, observability client, and pool.
157
- `require 'nonnative'` loads Cucumber integration lazily and is safe outside a
158
- booted Cucumber runtime. For start-once-per-test-run, use
159
- `require 'nonnative/startup'`.
160
-
161
- ## Proxy And Config Gotchas
162
-
163
- Proxy wiring is the easiest mistake:
164
-
165
- - Runner `host` / `port` are client-facing and used for readiness/shutdown
166
- - For `fault_injection`, nested `proxy.host` / `proxy.port` are the upstream target
167
- - Clients connect to runner `host` / `port` when a proxy is enabled
168
-
169
- Proxy kinds: `none`, `fault_injection`.
170
- Fault-injection states: `none`, `close_all`, `delay`, `invalid_data`.
171
-
172
- Config rules:
173
-
174
- - YAML config is loaded as data only via `Nonnative::ConfigurationFile`; ERB is not evaluated and arbitrary Ruby object tags are rejected
175
- - Runner `host` and nested `proxy.host` default to `127.0.0.1`; use explicit `0.0.0.0` only when external access is intended
176
- - Process `command` can be a legacy shell string or an argv array; prefer argv arrays for new config, and `go:` config builds argv internally with `Nonnative.go_argv`
177
- - Use `Nonnative.go_argv` for no-shell Go executable argv entries and `Nonnative.go_command` only when a caller needs Ruby shell-style command string spawning
178
- - YAML services belong under `services:`, not `processes:`
179
- - There is no top-level `config.wait`; `wait` is per runner
180
- - Programmatic service config uses `config.service do |s| ... end`, so use `s.host` / `s.port`
181
- - Proxy examples need both endpoint sides: runner `host` / `port` for the proxy, nested `proxy.host` / `proxy.port` for upstream
182
-
183
- ## Fixtures And Limitations
184
-
185
- Useful fixtures:
186
-
187
- - Process: `features/support/bin/start`
188
- - HTTP: `features/support/http_server.rb`, `features/support/http_proxy_server.rb`
189
- - TCP: `features/support/tcp_server.rb`
190
- - gRPC: `features/support/grpc_server.rb`, generated stubs in `test/grpc/`
191
-
192
- Limitations:
193
-
194
- - The `grpc` Ruby library uses a global logger; per-server gRPC loggers are not really supported
195
- - Local Ruby/Bundler mismatches can break native extensions on macOS
196
- - Coverage and Cucumber reports go under `test/reports`
197
- - Port checks can be flaky if tests reuse ports unexpectedly
198
-
199
- ## Look First
200
-
201
- - Lifecycle: `lib/nonnative.rb`, `lib/nonnative/pool.rb`
202
- - Readiness/timeouts: `lib/nonnative/port.rb`, `lib/nonnative/timeout.rb`
203
- - Process lifecycle: `lib/nonnative/process.rb`
204
- - Go executable command/argv building: `lib/nonnative/go_executable.rb`
205
- - Token generation: `lib/nonnative/token.rb`, `lib/nonnative/jwt_token.rb`, `lib/nonnative/paseto_token.rb`, `lib/nonnative/ssh_token.rb`, `lib/nonnative/ed25519_key.rb`
206
- - Proxies: `lib/nonnative/fault_injection_proxy.rb`, `lib/nonnative/socket_pair_factory.rb`
207
- - Cucumber: `lib/nonnative/cucumber.rb`, `lib/nonnative/startup.rb`, `features/support/env.rb`
208
- - Config loading: `lib/nonnative/configuration.rb`, `lib/nonnative/configuration_file.rb`, `lib/nonnative/configuration_runner.rb`, `lib/nonnative/configuration_proxy.rb`
data/CLAUDE.md DELETED
@@ -1,4 +0,0 @@
1
- <!-- BEGIN bin claude-init -->
2
- @AGENTS.md
3
- @bin/AGENTS.md
4
- <!-- END bin claude-init -->
data/Gemfile DELETED
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- source 'https://rubygems.org'
4
-
5
- git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
-
7
- # Specify your gem's dependencies in nonnative.gemspec
8
- gemspec
9
-
10
- gem 'bundler'
11
- gem 'rubocop'
12
- gem 'ruby-lsp'
13
- gem 'simplecov'
14
- gem 'simplecov-cobertura'