nonnative 2.23.0 → 3.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 53ded0979e2825948ce16066839a784ef26ee94385d78ba2f557da5ce9e4424a
4
- data.tar.gz: 5dbceda50fe7dc82c109a3fec1c4af041a27026a438bb7c51eee52344be13ab1
3
+ metadata.gz: 786062cd10bbaba4298dd41abc683bc7a5fd769ea7c41a05e39a9f41bc2c5d96
4
+ data.tar.gz: 1d0e8303858861f849aacbcb54ba2bac1f5a8336fdb74c44d09cb48881658c9f
5
5
  SHA512:
6
- metadata.gz: d2952d70183482b382509e0088fc5e2c8e4b53a320ddb00d57e9237961355f39bc48828c26779568318bad54552ad373bd341349d2cbb77cedd5dbc0fa84f6c0
7
- data.tar.gz: fb7c6404f30ec98145e168c919ad4de609eb4a11436bf0c5f8d8a7832e93bc9fad55c8cd4b820242bdfc9f928640dcd3577b83cf54dd98520c08046d12bd71f2
6
+ metadata.gz: 729e1141493b2b21c5c9014216a73aade7f7ec1ab03686ab581cbcb1b1c28d2d469a4fd5e416bcd391c2f8056725433a0befe40c283357166b0743f3f4f2d834
7
+ data.tar.gz: e17dfe6bd69bbf4d0faf76d0b37502a32abf1ca0943d24f261c4c32301be86fff18e302f65dc9af32ac499ca73d5fe4a08ede17422d2de715a15b4c986ea64c7
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:3.12
6
+ - image: alexfalkowski/ruby:3.14
7
7
  working_directory: ~/nonnative
8
8
  steps:
9
9
  - checkout:
@@ -35,7 +35,7 @@ jobs:
35
35
  resource_class: arm.large
36
36
  sync:
37
37
  docker:
38
- - image: alexfalkowski/release:8.11
38
+ - image: alexfalkowski/release:8.14
39
39
  working_directory: ~/nonnative
40
40
  steps:
41
41
  - checkout:
@@ -46,7 +46,7 @@ jobs:
46
46
  resource_class: arm.large
47
47
  version:
48
48
  docker:
49
- - image: alexfalkowski/release:8.11
49
+ - image: alexfalkowski/release:8.14
50
50
  working_directory: ~/nonnative
51
51
  steps:
52
52
  - checkout:
@@ -58,7 +58,7 @@ jobs:
58
58
  resource_class: arm.large
59
59
  wait-all:
60
60
  docker:
61
- - image: alexfalkowski/ruby:3.12
61
+ - image: alexfalkowski/ruby:3.14
62
62
  steps:
63
63
  - run: echo "all applicable jobs finished"
64
64
  resource_class: arm.large
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- nonnative (2.23.0)
4
+ nonnative (3.0.0)
5
5
  concurrent-ruby (>= 1, < 2)
6
6
  config (>= 5, < 6)
7
7
  cucumber (>= 7, < 12)
@@ -30,7 +30,7 @@ GEM
30
30
  config (5.6.1)
31
31
  deep_merge (~> 1.2, >= 1.2.1)
32
32
  ostruct
33
- cucumber (11.0.0)
33
+ cucumber (11.1.0)
34
34
  base64 (~> 0.2)
35
35
  builder (~> 3.2)
36
36
  cucumber-ci-environment (> 9, < 12)
@@ -64,24 +64,24 @@ GEM
64
64
  get_process_mem (1.0.0)
65
65
  bigdecimal (>= 2.0)
66
66
  ffi (~> 1.0)
67
- google-protobuf (4.34.1-x86_64-darwin)
67
+ google-protobuf (4.35.0-x86_64-darwin)
68
68
  bigdecimal
69
69
  rake (~> 13.3)
70
- google-protobuf (4.34.1-x86_64-linux-gnu)
70
+ google-protobuf (4.35.0-x86_64-linux-gnu)
71
71
  bigdecimal
72
72
  rake (~> 13.3)
73
- googleapis-common-protos-types (1.22.0)
73
+ googleapis-common-protos-types (1.23.0)
74
74
  google-protobuf (~> 4.26)
75
- grpc (1.80.0-x86_64-darwin)
75
+ grpc (1.81.0-x86_64-darwin)
76
76
  google-protobuf (>= 3.25, < 5.0)
77
77
  googleapis-common-protos-types (~> 1.0)
78
- grpc (1.80.0-x86_64-linux-gnu)
78
+ grpc (1.81.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
82
  http-cookie (1.1.6)
83
83
  domain_name (~> 0.5)
84
- json (2.19.5)
84
+ json (2.19.8)
85
85
  language_server-protocol (3.17.0.5)
86
86
  lint_roller (1.1.0)
87
87
  logger (1.7.0)
@@ -101,7 +101,7 @@ GEM
101
101
  ast (~> 2.4.1)
102
102
  racc
103
103
  prism (1.9.0)
104
- puma (7.2.0)
104
+ puma (7.2.1)
105
105
  nio4r (~> 2.0)
106
106
  racc (1.8.1)
107
107
  rack (3.2.6)
@@ -124,7 +124,7 @@ GEM
124
124
  http-cookie (>= 1.0.2, < 2.0)
125
125
  mime-types (>= 1.16, < 4.0)
126
126
  netrc (~> 0.8)
127
- retriable (3.4.1)
127
+ retriable (3.8.0)
128
128
  rexml (3.4.4)
129
129
  rspec (3.13.2)
130
130
  rspec-core (~> 3.13.0)
@@ -146,7 +146,7 @@ GEM
146
146
  rspec-support (3.13.7)
147
147
  rspec-wait (1.0.2)
148
148
  rspec (>= 3.4)
149
- rubocop (1.86.2)
149
+ rubocop (1.87.0)
150
150
  json (~> 2.3)
151
151
  language_server-protocol (~> 3.17.0.2)
152
152
  lint_roller (~> 1.1.0)
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![Gem Version](https://badge.fury.io/rb/nonnative.svg)](https://badge.fury.io/rb/nonnative)
4
4
  [![Stability: Active](https://masterminds.github.io/stability/active.svg)](https://masterminds.github.io/stability/active.html)
5
5
 
6
- # Nonnative
6
+ # 🧪 Nonnative
7
7
 
8
8
  Nonnative is a Ruby-first harness for end-to-end testing of systems implemented in other languages.
9
9
 
@@ -15,7 +15,10 @@ It helps you:
15
15
 
16
16
  Once started, you can test however you like (TCP, HTTP, gRPC, etc).
17
17
 
18
- ## Installation
18
+ ## 📦 Installation
19
+
20
+ > [!IMPORTANT]
21
+ > Nonnative currently supports Ruby `>= 4.0.0` and `< 5.0.0`.
19
22
 
20
23
  Add this line to your application's Gemfile:
21
24
 
@@ -35,12 +38,15 @@ Or install it yourself as:
35
38
  gem install nonnative
36
39
  ```
37
40
 
38
- ## Usage
41
+ ## 🚀 Usage
39
42
 
40
43
  Nonnative is configured via `Nonnative.configure` (programmatic) or `config.load_file(...)` (YAML).
41
44
  YAML configuration is loaded as data only: ERB is not evaluated and arbitrary Ruby objects are not
42
45
  deserialized.
43
46
 
47
+ > [!CAUTION]
48
+ > Treat YAML configuration as plain data. ERB is not evaluated and arbitrary Ruby object tags are rejected.
49
+
44
50
  High-level configuration fields:
45
51
  - `version`: configuration version (example: `"1.0"`).
46
52
  - `name`: logical system name (used by `Nonnative.observability` for `/<name>/healthz`, etc).
@@ -52,7 +58,7 @@ High-level configuration fields:
52
58
 
53
59
  Common runner fields:
54
60
  - `name`: runner name used for lookup.
55
- - `host`/`port`: client-facing address. `host` defaults to `127.0.0.1`. For processes and servers, this address is also used for readiness/shutdown port checks. When a `fault_injection` proxy is enabled, this is the endpoint your tests/clients should hit.
61
+ - `host`/`ports`: client-facing address. `host` defaults to `127.0.0.1`. For processes and servers, this address is also used for readiness/shutdown port checks. When a `fault_injection` proxy is enabled, clients should hit the first configured port.
56
62
 
57
63
  Process/server fields:
58
64
  - `timeout`: max time (seconds) for readiness/shutdown port checks.
@@ -61,9 +67,55 @@ Process/server fields:
61
67
 
62
68
  For `fault_injection`, the nested `proxy.host`/`proxy.port` describe the upstream target behind the proxy. Nested `proxy.host` also defaults to `127.0.0.1`. In-process server implementations typically bind there via `proxy.host` / `proxy.port`.
63
69
 
64
- Nonnative readiness and shutdown checks are TCP-only. Configure ports that are dedicated to the test run; if another process is already listening on the same `host`/`port`, results are undefined.
70
+ > [!IMPORTANT]
71
+ > When a proxy is enabled, tests and clients connect to the runner `host` and first configured `ports` entry; the nested `proxy.host`/`proxy.port` is the upstream target behind the proxy.
72
+
73
+ Nonnative readiness and shutdown checks are TCP-only. Configure ports that are dedicated to the test run; if another process is already listening on the same `host`/`ports` endpoint, results are undefined.
74
+
75
+ > [!WARNING]
76
+ > Readiness and shutdown checks only prove that a TCP port opened or closed. They do not verify HTTP status, gRPC health, schema readiness, migrations, or application-specific health.
77
+
78
+ Start and stop Nonnative around the test scope that should own the configured runners:
79
+
80
+ ```ruby
81
+ require 'nonnative'
82
+
83
+ Nonnative.configure do |config|
84
+ config.load_file('configuration.yml')
85
+ end
86
+
87
+ Nonnative.start
88
+ # run tests...
89
+ Nonnative.stop
90
+ ```
91
+
92
+ `Nonnative.start` starts services first, then servers and processes. `Nonnative.stop` stops processes and servers first, then services. If startup fails, Nonnative rolls back runners that already started and raises `Nonnative::StartError`; shutdown failures raise `Nonnative::StopError`.
93
+
94
+ > [!NOTE]
95
+ > `Nonnative.clear` clears memoized configuration, logger, observability client, and pool. Use it before reconfiguring Nonnative in the same Ruby process.
65
96
 
66
- ### Lifecycle strategies (Cucumber integration)
97
+ ### 📈 Observability
98
+
99
+ `Nonnative.observability` is an HTTP client for common service endpoints under the configured `name` and `url`:
100
+
101
+ - `health(...)`: calls `/<name>/healthz`.
102
+ - `liveness(...)`: calls `/<name>/livez`.
103
+ - `readiness(...)`: calls `/<name>/readyz`.
104
+ - `metrics(...)`: calls `/<name>/metrics`.
105
+
106
+ Each method accepts RestClient options such as `headers`, `open_timeout`, and `read_timeout`.
107
+
108
+ ```ruby
109
+ response = Nonnative.observability.health(
110
+ headers: { content_type: :json, accept: :json },
111
+ open_timeout: 2,
112
+ read_timeout: 2
113
+ )
114
+
115
+ expect(response.code).to eq(200)
116
+ ```
117
+
118
+ ### 🔁 Lifecycle strategies (Cucumber integration)
67
119
 
68
120
  Nonnative ships Cucumber hooks (when loaded) that support these tags/strategies:
69
121
  - `@startup`: start before scenario; stop after scenario
@@ -84,7 +136,7 @@ The repo’s own Cucumber suite also uses taxonomy tags to classify coverage:
84
136
 
85
137
  Requiring `nonnative` is enough; the Cucumber hooks and step definitions are installed lazily once Cucumber’s Ruby DSL is ready.
86
138
 
87
- If you want start once per test run”, require:
139
+ If you want "start once per test run", require:
88
140
 
89
141
  ```ruby
90
142
  require 'nonnative/startup'
@@ -92,11 +144,13 @@ require 'nonnative/startup'
92
144
 
93
145
  This calls `Nonnative.start` immediately and registers an `at_exit` stop.
94
146
 
95
- ### Processes
147
+ ### ⚙️ Processes
96
148
 
97
149
  A process is some sort of command that you would run locally.
98
- Commands can be strings or argv arrays. String commands preserve legacy shell semantics, while argv arrays
99
- avoid shell interpretation and are preferred for new configuration.
150
+ Programmatic `p.command` values must be callables that return a shell string or an argv array. YAML `command` values can be scalars or lists and are wrapped internally. String commands preserve legacy shell semantics, while argv arrays avoid shell interpretation and are preferred for new configuration.
151
+
152
+ > [!TIP]
153
+ > Prefer argv arrays for new process commands. Use shell strings only when you intentionally need shell parsing, expansion, or redirection.
100
154
 
101
155
  Set it up programmatically:
102
156
 
@@ -114,7 +168,7 @@ Nonnative.configure do |config|
114
168
  p.command = -> { ['features/support/bin/start', '12_321'] }
115
169
  p.timeout = 5
116
170
  p.wait = 0.1
117
- p.port = 12_321
171
+ p.ports = [12_321]
118
172
  p.log = '12_321.log'
119
173
  p.signal = 'INT' # Possible values are described in Signal.list.keys.
120
174
  p.environment = { # Pass environment variables to process.
@@ -127,7 +181,7 @@ Nonnative.configure do |config|
127
181
  p.command = -> { ['features/support/bin/start', '12_322'] }
128
182
  p.timeout = 0.5
129
183
  p.wait = 0.1
130
- p.port = 12_322
184
+ p.ports = [12_322]
131
185
  p.log = '12_322.log'
132
186
  end
133
187
  end
@@ -148,7 +202,8 @@ processes:
148
202
  - "12_321"
149
203
  timeout: 5
150
204
  wait: 1
151
- port: 12321
205
+ ports:
206
+ - 12321
152
207
  log: 12_321.log
153
208
  signal: INT # Possible values are described in Signal.list.keys.
154
209
  environment: # Pass environment variables to process.
@@ -160,7 +215,8 @@ processes:
160
215
  - "12_322"
161
216
  timeout: 5
162
217
  wait: 1
163
- port: 12322
218
+ ports:
219
+ - 12322
164
220
  log: 12_322.log
165
221
  ```
166
222
 
@@ -180,9 +236,9 @@ With cucumber you can also verify how much memory is used by the process:
180
236
  Then the process 'start_1' should consume less than '25mb' of memory
181
237
  ```
182
238
 
183
- ### Servers
239
+ ### 🖥️ Servers
184
240
 
185
- A server is a dependency to some external API.
241
+ A server is an in-process Ruby fake or helper server that Nonnative starts in a thread. Use servers for dependencies that are easiest to model inside the test process, such as small TCP, HTTP, or gRPC fakes.
186
242
 
187
243
  Define your server:
188
244
 
@@ -231,7 +287,7 @@ Nonnative.configure do |config|
231
287
  s.name = 'server_1'
232
288
  s.klass = Nonnative::TCPServer
233
289
  s.timeout = 1
234
- s.port = 12_323
290
+ s.ports = [12_323]
235
291
  s.log = 'server_1.log'
236
292
  end
237
293
 
@@ -239,7 +295,7 @@ Nonnative.configure do |config|
239
295
  s.name = 'server_2'
240
296
  s.klass = Nonnative::TCPServer
241
297
  s.timeout = 1
242
- s.port = 12_324
298
+ s.ports = [12_324]
243
299
  s.log = 'server_2.log'
244
300
  end
245
301
  end
@@ -257,13 +313,15 @@ servers:
257
313
  name: server_1
258
314
  class: Nonnative::TCPServer
259
315
  timeout: 1
260
- port: 12323
316
+ ports:
317
+ - 12323
261
318
  log: server_1.log
262
319
  -
263
320
  name: server_2
264
321
  class: Nonnative::TCPServer
265
322
  timeout: 1
266
- port: 12324
323
+ ports:
324
+ - 12324
267
325
  log: server_2.log
268
326
  ```
269
327
 
@@ -277,7 +335,7 @@ Nonnative.configure do |config|
277
335
  end
278
336
  ```
279
337
 
280
- #### HTTP
338
+ #### 🌐 HTTP
281
339
 
282
340
  Define your server:
283
341
 
@@ -314,7 +372,7 @@ Nonnative.configure do |config|
314
372
  s.name = 'http_server_1'
315
373
  s.klass = Nonnative::Features::HTTPServer
316
374
  s.timeout = 1
317
- s.port = 4567
375
+ s.ports = [4567]
318
376
  s.log = 'http_server_1.log'
319
377
  end
320
378
  end
@@ -332,7 +390,8 @@ servers:
332
390
  name: http_server_1
333
391
  class: Nonnative::Features::HTTPServer
334
392
  timeout: 1
335
- port: 4567
393
+ ports:
394
+ - 4567
336
395
  log: http_server_1.log
337
396
  ```
338
397
 
@@ -346,9 +405,9 @@ Nonnative.configure do |config|
346
405
  end
347
406
  ```
348
407
 
349
- ##### Proxy
408
+ ##### 🔀 Proxy
350
409
 
351
- The system allows you to define a http proxy for external systems, e.g api.github.com
410
+ The system allows you to define an HTTP proxy for external systems, e.g. `api.github.com`.
352
411
 
353
412
  Define your server:
354
413
 
@@ -379,7 +438,7 @@ Nonnative.configure do |config|
379
438
  s.name = 'http_server_proxy'
380
439
  s.klass = Nonnative::Features::HTTPProxyServer
381
440
  s.timeout = 1
382
- s.port = 4567
441
+ s.ports = [4567]
383
442
  s.log = 'http_server_proxy.log'
384
443
  end
385
444
  end
@@ -397,7 +456,8 @@ servers:
397
456
  name: http_server_proxy
398
457
  class: Nonnative::Features::HTTPProxyServer
399
458
  timeout: 1
400
- port: 4567
459
+ ports:
460
+ - 4567
401
461
  log: http_server_proxy.log
402
462
  ```
403
463
 
@@ -411,7 +471,7 @@ Nonnative.configure do |config|
411
471
  end
412
472
  ```
413
473
 
414
- #### gRPC
474
+ #### 📡 gRPC
415
475
 
416
476
  Define your server:
417
477
 
@@ -448,7 +508,7 @@ Nonnative.configure do |config|
448
508
  s.name = 'grpc_server_1'
449
509
  s.klass = Nonnative::Features::GRPCServer
450
510
  s.timeout = 1
451
- s.port = 9002
511
+ s.ports = [9002]
452
512
  s.log = 'grpc_server_1.log'
453
513
  end
454
514
  end
@@ -466,7 +526,8 @@ servers:
466
526
  name: grpc_server_1
467
527
  class: Nonnative::Features::GRPCServer
468
528
  timeout: 1
469
- port: 9002
529
+ ports:
530
+ - 9002
470
531
  log: grpc_server_1.log
471
532
  ```
472
533
 
@@ -480,10 +541,12 @@ Nonnative.configure do |config|
480
541
  end
481
542
  ```
482
543
 
483
- ### Services
544
+ ### 🧩 Services
484
545
 
485
546
  A service is an external dependency to your system that you **do not** want Nonnative to start (no OS process, no Ruby thread). Services are primarily useful when paired with proxies, because they let you inject failures into dependencies that are managed elsewhere (e.g. a DB running in Docker).
486
547
 
548
+ Services do not get process lifecycle management or TCP readiness/shutdown checks from Nonnative. They only provide a named runner and optional proxy lifecycle for a dependency that another tool already manages.
549
+
487
550
  Set it up programmatically:
488
551
 
489
552
  ```ruby
@@ -498,13 +561,13 @@ Nonnative.configure do |config|
498
561
  config.service do |s|
499
562
  s.name = 'postgres'
500
563
  s.host = '127.0.0.1'
501
- s.port = 5432
564
+ s.ports = [5432]
502
565
  end
503
566
 
504
567
  config.service do |s|
505
568
  s.name = 'redis'
506
569
  s.host = '127.0.0.1'
507
- s.port = 6379
570
+ s.ports = [6379]
508
571
  end
509
572
  end
510
573
  ```
@@ -520,11 +583,13 @@ services:
520
583
  -
521
584
  name: postgres
522
585
  host: 127.0.0.1
523
- port: 5432
586
+ ports:
587
+ - 5432
524
588
  -
525
589
  name: redis
526
590
  host: 127.0.0.1
527
- port: 6379
591
+ ports:
592
+ - 6379
528
593
  ```
529
594
 
530
595
  Then load the file with:
@@ -537,16 +602,25 @@ Nonnative.configure do |config|
537
602
  end
538
603
  ```
539
604
 
540
- #### Proxies
605
+ #### 🕸️ Proxies
541
606
 
542
- We allow different proxies to be configured. These proxies can be used to simulate all kind of situations. The proxies that can be configured are:
607
+ These proxies can simulate different situations. Available proxy kinds are:
543
608
 
544
609
  - `none` (this is the default)
545
610
  - `fault_injection`
546
611
 
547
- 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.
612
+ > [!WARNING]
613
+ > Unknown proxy kinds fall back to `none`. If fault injection is not taking effect, check the `kind` spelling or register the custom kind before loading the configuration.
614
+
615
+ Custom proxy kinds can be registered through `Nonnative.proxies`:
616
+
617
+ ```ruby
618
+ Nonnative.proxies['custom'] = CustomProxy
619
+ ```
548
620
 
549
- ##### Proxies Processes
621
+ For `fault_injection`, keep the runner `host` and first `ports` entry as the client-facing endpoint and use nested `proxy.host`/`proxy.port` for the upstream target behind the proxy.
622
+
623
+ ##### ⚙️ Process Proxies
550
624
 
551
625
  Add this to an existing process configuration:
552
626
 
@@ -561,7 +635,7 @@ Nonnative.configure do |config|
561
635
 
562
636
  config.process do |p|
563
637
  p.host = '127.0.0.1'
564
- p.port = 20_000
638
+ p.ports = [20_000]
565
639
 
566
640
  p.proxy = {
567
641
  kind: 'fault_injection',
@@ -587,7 +661,8 @@ log: nonnative.log
587
661
  processes:
588
662
  -
589
663
  host: 127.0.0.1
590
- port: 20000
664
+ ports:
665
+ - 20000
591
666
  proxy:
592
667
  kind: fault_injection
593
668
  host: 127.0.0.1
@@ -598,7 +673,7 @@ processes:
598
673
  delay: 5
599
674
  ```
600
675
 
601
- ##### Proxies Servers
676
+ ##### 🖥️ Server Proxies
602
677
 
603
678
  Add this to an existing server configuration:
604
679
 
@@ -613,7 +688,7 @@ Nonnative.configure do |config|
613
688
 
614
689
  config.server do |s|
615
690
  s.host = '127.0.0.1'
616
- s.port = 20_000
691
+ s.ports = [20_000]
617
692
 
618
693
  s.proxy = {
619
694
  kind: 'fault_injection',
@@ -639,7 +714,8 @@ log: nonnative.log
639
714
  servers:
640
715
  -
641
716
  host: 127.0.0.1
642
- port: 20000
717
+ ports:
718
+ - 20000
643
719
  proxy:
644
720
  kind: fault_injection
645
721
  host: 127.0.0.1
@@ -650,7 +726,7 @@ servers:
650
726
  delay: 5
651
727
  ```
652
728
 
653
- ##### Proxies Services
729
+ ##### 🧩 Service Proxies
654
730
 
655
731
  Add this to an existing service configuration:
656
732
 
@@ -666,7 +742,7 @@ Nonnative.configure do |config|
666
742
  config.service do |s|
667
743
  s.name = 'redis'
668
744
  s.host = '127.0.0.1'
669
- s.port = 16_379
745
+ s.ports = [16_379]
670
746
 
671
747
  s.proxy = {
672
748
  kind: 'fault_injection',
@@ -693,7 +769,8 @@ services:
693
769
  -
694
770
  name: redis
695
771
  host: 127.0.0.1
696
- port: 16379
772
+ ports:
773
+ - 16379
697
774
  proxy:
698
775
  kind: fault_injection
699
776
  host: 127.0.0.1
@@ -704,17 +781,17 @@ services:
704
781
  delay: 5
705
782
  ```
706
783
 
707
- ##### Fault Injection
784
+ ##### 🧪 Fault Injection
708
785
 
709
786
  The `fault_injection` proxy allows you to simulate failures by injecting them. We currently support the following:
710
787
 
711
- Clients connect to the runner `host`/`port`, while the proxy forwards traffic to nested `proxy.host`/`proxy.port`.
788
+ Clients connect to the runner `host` and first configured `ports` entry, while the proxy forwards traffic to nested `proxy.host`/`proxy.port`.
712
789
 
713
790
  - `close_all` - Closes the socket as soon as it connects.
714
- - `delay` - This delays the communication between the connection. Default is 2 secs can be configured through options.
715
- - `invalid_data` - This takes the input and rearranges it to produce invalid data.
791
+ - `delay` - Delays traffic on the connection. Defaults to 2 seconds and can be configured through options.
792
+ - `invalid_data` - Forwards client requests unchanged, then corrupts upstream responses before they reach the client.
716
793
 
717
- ###### Fault Injection Processes
794
+ ###### ⚙️ Fault Injection Processes
718
795
 
719
796
  Set it up programmatically:
720
797
 
@@ -733,7 +810,7 @@ Given I set the proxy for process 'process_1' to 'close_all'
733
810
  Then I should reset the proxy for process 'process_1'
734
811
  ```
735
812
 
736
- ###### Fault Injection Servers
813
+ ###### 🖥️ Fault Injection Servers
737
814
 
738
815
  Set it up programmatically:
739
816
 
@@ -752,7 +829,7 @@ Given I set the proxy for server 'server_1' to 'close_all'
752
829
  Then I should reset the proxy for server 'server_1'
753
830
  ```
754
831
 
755
- ###### Fault Injection Services
832
+ ###### 🧩 Fault Injection Services
756
833
 
757
834
  Set it up programmatically:
758
835
 
@@ -771,7 +848,7 @@ Given I set the proxy for service 'service_1' to 'close_all'
771
848
  Then I should reset the proxy for service 'service_1'
772
849
  ```
773
850
 
774
- ### Go
851
+ ### 🐹 Go
775
852
 
776
853
  As we love using Go as a language for services we have added support to start binaries with defined parameters.
777
854
 
@@ -782,7 +859,7 @@ Nonnative.configure do |config|
782
859
  config.process do |p|
783
860
  p.name = 'go'
784
861
  p.command = -> { Nonnative.go_argv(%w[cover], 'reports', 'your_binary', 'sub_command', '-i file:.config/server.yml') }
785
- p.port = 12_345
862
+ p.ports = [12_345]
786
863
  end
787
864
  end
788
865
  ```
@@ -791,6 +868,9 @@ Use `Nonnative.go_argv(...)` when a process should execute without shell interpr
791
868
 
792
869
  YAML `go:` configuration is for Go test binaries compiled with `go test -c`. It builds argv entries in this order: executable, optional `-test.*` profiling/trace/coverage flags, command, then parameters. Parameter strings are parsed into argv words with shell-style quoting, but the argv entries are executed without shell interpretation.
793
870
 
871
+ > [!IMPORTANT]
872
+ > If `tools` is omitted or empty, Nonnative enables all Go tools: `prof`, `trace`, and `cover`. Provide a subset, such as `tools: [cover]`, to limit the generated `-test.*` flags.
873
+
794
874
  To get this to work you will need to create a `main_test.go` file with these contents:
795
875
 
796
876
  ```go
@@ -830,6 +910,7 @@ processes:
830
910
  parameters:
831
911
  - "-i file:.config/server.yml"
832
912
  timeout: 5
833
- port: 8000
913
+ ports:
914
+ - 8000
834
915
  log: go.log
835
916
  ```
@@ -19,7 +19,7 @@ module Nonnative
19
19
  # p.name = 'api'
20
20
  # p.command = -> { './bin/api' }
21
21
  # p.host = '127.0.0.1'
22
- # p.port = 8080
22
+ # p.ports = [8080, 9090]
23
23
  # p.timeout = 10
24
24
  # p.log = 'api.log'
25
25
  # end
@@ -123,14 +123,14 @@ module Nonnative
123
123
 
124
124
  def add_processes(cfg)
125
125
  processes = cfg.processes || []
126
- processes.each do |fd|
127
- process do |d|
128
- d.command = command(fd)
129
- d.signal = fd.signal
130
- d.environment = fd.environment
131
- runner_attributes(d, fd)
132
-
133
- proxy d, fd.proxy
126
+ processes.each do |loaded_process|
127
+ process do |process_config|
128
+ process_config.command = command(loaded_process)
129
+ process_config.signal = loaded_process.signal
130
+ process_config.environment = loaded_process.environment
131
+ runner_attributes(process_config, loaded_process)
132
+
133
+ assign_proxy(process_config, loaded_process.proxy)
134
134
  end
135
135
  end
136
136
  end
@@ -149,25 +149,25 @@ module Nonnative
149
149
 
150
150
  def add_servers(cfg)
151
151
  servers = cfg.servers || []
152
- servers.each do |fd|
153
- server do |s|
154
- s.klass = Object.const_get(server_class_name(fd))
155
- runner_attributes(s, fd)
152
+ servers.each do |loaded_server|
153
+ server do |server_config|
154
+ server_config.klass = Object.const_get(server_class_name(loaded_server))
155
+ runner_attributes(server_config, loaded_server)
156
156
 
157
- proxy s, fd.proxy
157
+ assign_proxy(server_config, loaded_server.proxy)
158
158
  end
159
159
  end
160
160
  end
161
161
 
162
162
  def add_services(cfg)
163
163
  services = cfg.services || []
164
- services.each do |fd|
165
- service do |s|
166
- s.name = fd.name
167
- s.host = fd.host if fd.host
168
- s.port = fd.port
164
+ services.each do |loaded_service|
165
+ service do |service_config|
166
+ service_config.name = loaded_service.name
167
+ service_config.host = loaded_service.host if loaded_service.host
168
+ assign_ports(service_config, loaded_service)
169
169
 
170
- proxy s, fd.proxy
170
+ assign_proxy(service_config, loaded_service.proxy)
171
171
  end
172
172
  end
173
173
  end
@@ -182,24 +182,31 @@ module Nonnative
182
182
  runner.timeout = loaded.timeout
183
183
  runner.wait = loaded.wait if loaded.wait
184
184
  runner.host = loaded.host if loaded.host
185
- runner.port = loaded.port
185
+ assign_ports(runner, loaded)
186
186
  runner.log = loaded.log if loaded.respond_to?(:log)
187
187
  end
188
188
 
189
- def proxy(runner, proxy)
190
- return unless proxy
189
+ def assign_ports(runner, loaded)
190
+ values = loaded.to_h
191
+ raise ArgumentError, "Use 'ports' instead of 'port' for runner '#{loaded.name}'" if values.key?(:port) || values.key?('port')
191
192
 
192
- p = {
193
- kind: proxy.kind,
194
- port: proxy.port,
195
- log: proxy.log,
196
- options: proxy.options
193
+ runner.ports = loaded.ports if loaded.ports
194
+ end
195
+
196
+ def assign_proxy(runner, loaded_proxy)
197
+ return unless loaded_proxy
198
+
199
+ proxy_attributes = {
200
+ kind: loaded_proxy.kind,
201
+ port: loaded_proxy.port,
202
+ log: loaded_proxy.log,
203
+ options: loaded_proxy.options
197
204
  }
198
205
 
199
- p[:host] = proxy.host if proxy.host
200
- p[:wait] = proxy.wait if proxy.wait
206
+ proxy_attributes[:host] = loaded_proxy.host if loaded_proxy.host
207
+ proxy_attributes[:wait] = loaded_proxy.wait if loaded_proxy.wait
201
208
 
202
- runner.proxy = p
209
+ runner.proxy = proxy_attributes
203
210
  end
204
211
  end
205
212
  end
@@ -19,7 +19,7 @@ module Nonnative
19
19
  # @return [String, nil] signal name to use for stopping (defaults to `"INT"` when not set)
20
20
  attr_accessor :signal
21
21
 
22
- # @return [Numeric] readiness timeout (seconds) used when waiting for the port to open/close
22
+ # @return [Numeric] readiness timeout (seconds) used when waiting for ports to open/close
23
23
  attr_accessor :timeout
24
24
 
25
25
  # @return [String] log file path to append process stdout/stderr to
@@ -15,9 +15,12 @@ module Nonnative
15
15
  class ConfigurationRunner
16
16
  # @return [String, nil] runner name used for lookup (for example via `pool.process_by_name`)
17
17
  # @return [String] host to bind/connect to (defaults to `"127.0.0.1"`)
18
- # @return [Integer] port to bind/connect to
18
+ # @return [Array<Integer>] ports to bind/connect to
19
19
  # @return [Numeric] wait interval (seconds) used by runners between lifecycle steps
20
- attr_accessor :name, :host, :port, :wait
20
+ attr_accessor :name, :host, :wait
21
+
22
+ # @return [Array<Integer>] client-facing ports used for readiness/shutdown checks
23
+ attr_reader :ports
21
24
 
22
25
  # Proxy configuration for this runner.
23
26
  #
@@ -31,19 +34,37 @@ module Nonnative
31
34
  #
32
35
  # Defaults:
33
36
  # - `host`: `"127.0.0.1"`
34
- # - `port`: `0`
37
+ # - `ports`: `[0]`
35
38
  # - `wait`: `0.1`
36
39
  # - `proxy`: a new {Nonnative::ConfigurationProxy} with its own defaults
37
40
  #
38
41
  # @return [void]
39
42
  def initialize
40
43
  self.host = '127.0.0.1'
41
- self.port = 0
44
+ self.ports = [0]
42
45
  self.wait = 0.1
43
46
 
44
47
  @proxy = Nonnative::ConfigurationProxy.new
45
48
  end
46
49
 
50
+ # Sets the client-facing ports for this runner.
51
+ #
52
+ # @param value [Array<Integer>] ports to check for readiness/shutdown
53
+ # @return [void]
54
+ def ports=(value)
55
+ @ports = Array(value)
56
+ end
57
+
58
+ # Returns the primary client-facing port.
59
+ #
60
+ # This preserves a single endpoint for proxy binding and client helpers while the public
61
+ # configuration contract uses {#ports}.
62
+ #
63
+ # @return [Integer]
64
+ def port
65
+ ports.first
66
+ end
67
+
47
68
  # Sets proxy configuration using a hash-like value.
48
69
  #
49
70
  # This is primarily used when loading YAML configuration files, where proxy attributes are
@@ -12,7 +12,7 @@ module Nonnative
12
12
  # @see Nonnative::Server
13
13
  class ConfigurationServer < ConfigurationRunner
14
14
  # @return [Class] a class that implements `#initialize(service)`, and lifecycle hooks expected by {Nonnative::Server}
15
- # @return [Numeric] readiness timeout (seconds) used when waiting for the port to open/close
15
+ # @return [Numeric] readiness timeout (seconds) used when waiting for ports to open/close
16
16
  # @return [String] log file path used by server implementations (for example Puma/gRPC log files)
17
17
  attr_accessor :klass, :timeout, :log
18
18
  end
@@ -18,8 +18,8 @@ module Nonnative
18
18
  #
19
19
  # ## Wiring
20
20
  #
21
- # When enabled, your test/client should connect to the runner `host` / `port` (the proxy endpoint),
22
- # and the proxy will forward traffic to the upstream target exposed by {#host}:{#port}.
21
+ # When enabled, your test/client should connect to the runner `host` and first configured port (the
22
+ # proxy endpoint), and the proxy will forward traffic to the upstream target exposed by {#host}:{#port}.
23
23
  #
24
24
  # ## Configuration
25
25
  #
@@ -62,7 +62,7 @@ module Nonnative
62
62
 
63
63
  # Starts the proxy accept loop in a background thread.
64
64
  #
65
- # This binds a TCP server on the underlying runner’s `service.host` / `service.port`.
65
+ # This binds a TCP server on the underlying runner’s `service.host` and first configured port.
66
66
  # Clients connect to that runner endpoint, while upstream traffic is forwarded to {#host}:{#port}.
67
67
  #
68
68
  # @return [void]
@@ -34,7 +34,7 @@ module Nonnative
34
34
  # Binds the gRPC server and begins serving requests.
35
35
  #
36
36
  # The server binds to the upstream proxy host/port so the fault-injection proxy can expose the
37
- # runner host/port as the client-facing endpoint used by readiness checks.
37
+ # runner host and first configured port as the client-facing endpoint used by readiness checks.
38
38
  #
39
39
  # @return [void]
40
40
  def perform_start
@@ -50,9 +50,10 @@ module Nonnative
50
50
 
51
51
  # Executes the upstream request and returns the response.
52
52
  #
53
- # @param verb [String] HTTP verb name (e.g. `"get"`)
54
- # @param uri [String] upstream URI
55
- # @param opts [Hash] RestClient options (e.g. headers)
53
+ # @param method [Symbol] HTTP verb name (e.g. `:get`)
54
+ # @param url [String] upstream URL
55
+ # @param headers [Hash] request headers
56
+ # @param payload [String, nil] request payload
56
57
  # @return [RestClient::Response] response for error statuses, otherwise RestClient return value
57
58
  def api_response(method:, url:, headers:, payload: nil)
58
59
  options = { method:, url:, headers: }
@@ -109,7 +110,7 @@ module Nonnative
109
110
  # s.klass = Nonnative::Features::HTTPProxyServer
110
111
  # s.timeout = 2
111
112
  # s.host = '127.0.0.1'
112
- # s.port = 4567
113
+ # s.ports = [4567]
113
114
  # s.log = 'proxy.log'
114
115
  # end
115
116
  # end
@@ -20,7 +20,7 @@ module Nonnative
20
20
  # s.klass = ->(service) { Nonnative::HTTPServer.new(app, service) }
21
21
  # s.timeout = 2
22
22
  # s.host = '127.0.0.1'
23
- # s.port = 4567
23
+ # s.ports = [4567]
24
24
  # s.log = 'http.log'
25
25
  # end
26
26
  # end
@@ -49,7 +49,7 @@ module Nonnative
49
49
  # Binds the Puma server and begins serving.
50
50
  #
51
51
  # The listener binds to the upstream proxy host/port so the fault-injection proxy can expose the
52
- # runner host/port as the client-facing endpoint used by readiness checks.
52
+ # runner host and first configured port as the client-facing endpoint used by readiness checks.
53
53
  #
54
54
  # @return [void]
55
55
  def perform_start
@@ -66,6 +66,6 @@ module Nonnative
66
66
 
67
67
  private
68
68
 
69
- attr_reader :queue, :server
69
+ attr_reader :server
70
70
  end
71
71
  end
@@ -5,7 +5,7 @@ module Nonnative
5
5
  #
6
6
  # This is the default proxy when `service.proxy.kind` is `"none"` (or an unknown kind is provided).
7
7
  # It does not bind/listen or alter traffic; it simply exposes the underlying runner's configured
8
- # `host` and `port`.
8
+ # `host` and primary `port`.
9
9
  #
10
10
  # Runners can always call `start`, `stop`, and `reset` safely on this proxy.
11
11
  #
@@ -50,7 +50,7 @@ module Nonnative
50
50
 
51
51
  # Returns the port clients should connect to.
52
52
  #
53
- # For {NoProxy}, this is the underlying runner configuration port.
53
+ # For {NoProxy}, this is the first underlying runner configuration port.
54
54
  #
55
55
  # @return [Integer]
56
56
  def port
@@ -9,7 +9,7 @@ module Nonnative
9
9
  # - On start: services first, then servers/processes (in parallel port-check threads)
10
10
  # - On stop: processes/servers first, then services
11
11
  #
12
- # Readiness and shutdown are determined via TCP port checks ({Nonnative::Port#open?} / {Nonnative::Port#closed?}).
12
+ # Readiness and shutdown are determined via TCP port checks ({Nonnative::Ports#open?} / {Nonnative::Ports#closed?}).
13
13
  #
14
14
  # @see Nonnative.start
15
15
  # @see Nonnative.stop
@@ -35,7 +35,7 @@ module Nonnative
35
35
  errors = []
36
36
 
37
37
  errors.concat(service_lifecycle(services, :start, :start))
38
- [servers, processes].each { |t| errors.concat(process(t, :start, :open?, :start, &)) }
38
+ [servers, processes].each { |runners| errors.concat(run_lifecycle_checks(runners, :start, :open?, :start, &)) }
39
39
 
40
40
  errors
41
41
  end
@@ -51,7 +51,7 @@ module Nonnative
51
51
  def stop(&)
52
52
  errors = []
53
53
 
54
- [processes, servers].each { |t| errors.concat(process(t, :stop, :closed?, :stop, &)) }
54
+ [processes, servers].each { |runners| errors.concat(run_lifecycle_checks(runners, :stop, :closed?, :stop, &)) }
55
55
  errors.concat(service_lifecycle(services, :stop, :stop))
56
56
 
57
57
  errors
@@ -69,7 +69,9 @@ module Nonnative
69
69
  def rollback(&)
70
70
  errors = []
71
71
 
72
- [existing_processes, existing_servers].each { |t| errors.concat(process(t, :stop, :closed?, :stop, &)) }
72
+ [existing_processes, existing_servers].each do |runners|
73
+ errors.concat(run_lifecycle_checks(runners, :stop, :closed?, :stop, &))
74
+ end
73
75
  errors.concat(service_lifecycle(existing_services, :stop, :stop))
74
76
 
75
77
  errors
@@ -129,7 +131,7 @@ module Nonnative
129
131
 
130
132
  @processes = []
131
133
  configuration.processes.each do |p|
132
- @processes << [Nonnative::Process.new(p), Nonnative::Port.new(p)]
134
+ @processes << [Nonnative::Process.new(p), Nonnative::Ports.new(p)]
133
135
  end
134
136
 
135
137
  @processes
@@ -140,7 +142,7 @@ module Nonnative
140
142
 
141
143
  @servers = []
142
144
  configuration.servers.each do |s|
143
- @servers << [s.klass.new(s), Nonnative::Port.new(s)]
145
+ @servers << [s.klass.new(s), Nonnative::Ports.new(s)]
144
146
  end
145
147
 
146
148
  @servers
@@ -177,15 +179,15 @@ module Nonnative
177
179
  end
178
180
  end
179
181
 
180
- def process(all, type_method, port_method, action, &)
182
+ def run_lifecycle_checks(runners, lifecycle_method, port_method, action, &)
181
183
  checks = []
182
184
  errors = []
183
185
 
184
- all.each do |type, port|
185
- values = type.send(type_method)
186
- checks << [type, values, Thread.new { check_port(port, port_method) }]
186
+ runners.each do |runner, port|
187
+ values = runner.send(lifecycle_method)
188
+ checks << [runner, values, Thread.new { check_port(port, port_method) }]
187
189
  rescue StandardError => e
188
- errors << lifecycle_error(action, type, e)
190
+ errors << lifecycle_error(action, runner, e)
189
191
  end
190
192
 
191
193
  errors.concat(yield_results(checks, action, &))
@@ -3,21 +3,23 @@
3
3
  module Nonnative
4
4
  # Performs TCP port readiness/shutdown checks for a configured runner.
5
5
  #
6
- # Nonnative uses this to decide whether a process/server is ready after start, and whether it has
7
- # shut down after stop. The checks repeatedly attempt to open a TCP connection to `process.host`
8
- # and `process.port` until either:
6
+ # Nonnative uses this to decide whether a process/server port is ready after start, and whether it
7
+ # has shut down after stop. The checks repeatedly attempt to open a TCP connection to `process.host`
8
+ # and the configured `port` until either:
9
9
  #
10
10
  # - the expected condition is met, or
11
11
  # - the configured timeout elapses (in which case the method returns `false`)
12
12
  #
13
13
  # The `process` argument is a runner configuration object (e.g. {Nonnative::ConfigurationProcess}
14
- # or {Nonnative::ConfigurationServer}) that responds to `host`, `port`, and `timeout`.
14
+ # or {Nonnative::ConfigurationServer}) that responds to `host` and `timeout`.
15
15
  #
16
16
  # @see Nonnative::Pool for how these checks are orchestrated during start/stop
17
17
  class Port
18
- # @param process [#host, #port, #timeout] runner configuration providing connection details
19
- def initialize(process)
18
+ # @param process [#host, #timeout] runner configuration providing connection details
19
+ # @param port [Integer] port to check
20
+ def initialize(process, port = process.port)
20
21
  @process = process
22
+ @port = port
21
23
  @timeout = Nonnative::Timeout.new(process.timeout)
22
24
  end
23
25
 
@@ -28,7 +30,7 @@ module Nonnative
28
30
  #
29
31
  # @return [Boolean] `true` if the port opened in time; otherwise `false`
30
32
  def open?
31
- Nonnative.logger.info "checking if port '#{process.port}' is open on host '#{process.host}'"
33
+ Nonnative.logger.info "checking if port '#{port}' is open on host '#{process.host}'"
32
34
 
33
35
  timeout.perform do
34
36
  open_socket
@@ -46,7 +48,7 @@ module Nonnative
46
48
  #
47
49
  # @return [Boolean] `true` if the port closed in time; otherwise `false`
48
50
  def closed?
49
- Nonnative.logger.info "checking if port '#{process.port}' is closed on host '#{process.host}'"
51
+ Nonnative.logger.info "checking if port '#{port}' is closed on host '#{process.host}'"
50
52
 
51
53
  timeout.perform do
52
54
  open_socket
@@ -61,10 +63,10 @@ module Nonnative
61
63
 
62
64
  private
63
65
 
64
- attr_reader :process, :timeout
66
+ attr_reader :process, :port, :timeout
65
67
 
66
68
  def open_socket
67
- TCPSocket.new(process.host, process.port).close
69
+ TCPSocket.new(process.host, port).close
68
70
  end
69
71
 
70
72
  def sleep_interval
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nonnative
4
+ # Performs aggregate TCP readiness/shutdown checks for all configured runner ports.
5
+ #
6
+ # A runner is considered ready only when every configured port is open, and stopped only when every
7
+ # configured port is closed.
8
+ #
9
+ # @see Nonnative::Port
10
+ class Ports
11
+ # @param runner [#host, #ports, #timeout] runner configuration providing connection details
12
+ def initialize(runner)
13
+ @ports = runner.ports.map { |port| Nonnative::Port.new(runner, port) }
14
+ end
15
+
16
+ # Returns whether all configured ports become connectable before their timeouts elapse.
17
+ #
18
+ # @return [Boolean]
19
+ def open?
20
+ ports.all?(&:open?)
21
+ end
22
+
23
+ # Returns whether all configured ports become non-connectable before their timeouts elapse.
24
+ #
25
+ # @return [Boolean]
26
+ def closed?
27
+ ports.all?(&:closed?)
28
+ end
29
+
30
+ private
31
+
32
+ attr_reader :ports
33
+ end
34
+ end
@@ -65,18 +65,18 @@ module Nonnative
65
65
  ::TCPSocket.new(proxy.host, proxy.port)
66
66
  end
67
67
 
68
- # Pipes data from `socket1` to `socket2` if `socket1` is readable.
68
+ # Pipes data from `source_socket` to `destination_socket` when the source is readable.
69
69
  #
70
70
  # @param ready [Array<Array<IO>>] the result from `select`
71
- # @param socket1 [IO] readable side
72
- # @param socket2 [IO] writable side
71
+ # @param source_socket [IO] readable side
72
+ # @param destination_socket [IO] writable side
73
73
  # @return [Boolean] whether the piping loop should terminate
74
- def pipe?(ready, socket1, socket2)
75
- if ready[0].include?(socket1)
76
- data = read(socket1)
74
+ def pipe?(ready, source_socket, destination_socket)
75
+ if ready[0].include?(source_socket)
76
+ data = read(source_socket)
77
77
  return true if data.empty?
78
78
 
79
- write socket2, data
79
+ write destination_socket, data
80
80
  end
81
81
 
82
82
  false
@@ -4,5 +4,5 @@ module Nonnative
4
4
  # The current gem version.
5
5
  #
6
6
  # @return [String]
7
- VERSION = '2.23.0'
7
+ VERSION = '3.0.0'
8
8
  end
data/lib/nonnative.rb CHANGED
@@ -24,7 +24,7 @@
24
24
  # p.name = 'api'
25
25
  # p.command = -> { './bin/api' }
26
26
  # p.host = '127.0.0.1'
27
- # p.port = 8080
27
+ # p.ports = [8080, 9090]
28
28
  # p.timeout = 10
29
29
  # p.log = 'api.log'
30
30
  # end
@@ -68,6 +68,7 @@ require 'nonnative/stop_error'
68
68
  require 'nonnative/not_found_error'
69
69
  require 'nonnative/timeout'
70
70
  require 'nonnative/port'
71
+ require 'nonnative/ports'
71
72
  require 'nonnative/configuration_file'
72
73
  require 'nonnative/configuration'
73
74
  require 'nonnative/configuration_runner'
@@ -208,7 +209,7 @@ module Nonnative
208
209
 
209
210
  # Starts all configured services, servers, and processes, and waits for readiness.
210
211
  #
211
- # Readiness is determined by attempting to connect to each runner's configured host/port.
212
+ # Readiness is determined by attempting to connect to each runner's configured host/ports.
212
213
  #
213
214
  # @return [void]
214
215
  # @raise [Nonnative::StartError] if one or more runners fail to start or become ready in time
data/nonnative.gemspec CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
11
11
  spec.authors = ['Alejandro Falkowski']
12
12
  spec.email = ['alexrfalkowski@gmail.com']
13
13
 
14
- spec.summary = 'Allows you to keep using the power of ruby to test other systems'
14
+ spec.summary = 'Allows you to keep using the power of Ruby to test other systems'
15
15
  spec.description = spec.summary
16
16
  spec.homepage = 'https://github.com/alexfalkowski/nonnative'
17
17
  spec.license = 'MIT'
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: 2.23.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alejandro Falkowski
@@ -263,7 +263,7 @@ dependencies:
263
263
  - - "<"
264
264
  - !ruby/object:Gem::Version
265
265
  version: '5'
266
- description: Allows you to keep using the power of ruby to test other systems
266
+ description: Allows you to keep using the power of Ruby to test other systems
267
267
  email:
268
268
  - alexrfalkowski@gmail.com
269
269
  executables: []
@@ -310,6 +310,7 @@ files:
310
310
  - lib/nonnative/observability.rb
311
311
  - lib/nonnative/pool.rb
312
312
  - lib/nonnative/port.rb
313
+ - lib/nonnative/ports.rb
313
314
  - lib/nonnative/process.rb
314
315
  - lib/nonnative/proxy.rb
315
316
  - lib/nonnative/proxy_factory.rb
@@ -348,5 +349,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
348
349
  requirements: []
349
350
  rubygems_version: 4.0.11
350
351
  specification_version: 4
351
- summary: Allows you to keep using the power of ruby to test other systems
352
+ summary: Allows you to keep using the power of Ruby to test other systems
352
353
  test_files: []