nonnative 3.1.0 → 3.2.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: 3e20a9fa436249c182c4fc90bfaaeeaed91035899d31340eba35d1f4208a31ab
4
- data.tar.gz: c68e618e0a2a48cf9958210a8200a96c2aff7c0406eeec332bea01cf9290e860
3
+ metadata.gz: 3015cc7b1f784a45dbb77184fd73e67e6cf33ff9d7bb97d09ebd01f1359d85b9
4
+ data.tar.gz: 9bf8f2fc9bb72f8de89e76f44912d62e8a7cd19ccb533c7930600fbc70411b28
5
5
  SHA512:
6
- metadata.gz: c228d28fa41f6e9d526c107feedb4aebfed673aca7b47d7262913db7ceb04468772a1ca068fd4cf696a46a50fc52f01f3dfb9934547945c6ef78b03298cd6cc4
7
- data.tar.gz: 60ebed64503ac1505ccd4398330290627600f14519d40389ba96a5e02189762e7d54b314ee98fdd31220f9aba560fc6e09ad7340ffc3925b3f3359747bcf0c0f
6
+ metadata.gz: 73147dafad8a271673d070f033a1a3f92270994b0593bb7f391d0ae126ed0e34005cfd22af9e01052846bd757b866fba9db4d36a3468219be54208e8121a5f80
7
+ data.tar.gz: ad58bc0015ccdf3f91f9ffbb5ca12de3bd9650d540ef33ec982df353abd6892c496328815f60991e340721971e1bfbf86a663292337a755280d1157c2ff9d5be
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- nonnative (3.1.0)
4
+ nonnative (3.2.0)
5
5
  concurrent-ruby (>= 1, < 2)
6
6
  config (>= 5, < 6)
7
7
  cucumber (>= 7, < 12)
data/README.md CHANGED
@@ -10,7 +10,7 @@ Nonnative is a Ruby-first harness for end-to-end testing of systems implemented
10
10
  It helps you:
11
11
  - start **OS processes** (e.g. your Go/Java/Rust service binary),
12
12
  - start **in-process Ruby servers** (e.g. small HTTP/TCP/gRPC fakes for dependencies),
13
- - optionally start **proxies** in front of processes/servers/services for fault-injection,
13
+ - optionally start **service proxies** for fault-injection in front of externally managed dependencies,
14
14
  - wait for readiness/shutdown using **TCP port checks**.
15
15
 
16
16
  Once started, you can test however you like (TCP, HTTP, gRPC, etc).
@@ -54,25 +54,20 @@ High-level configuration fields:
54
54
  - `log`: path for the Nonnative logger output.
55
55
  - `processes`: child processes to `spawn`.
56
56
  - `servers`: in-process Ruby servers started in threads.
57
- - `services`: external dependencies (proxy-only; no process/thread started by Nonnative).
57
+ - `services`: external dependencies (no process/thread started by Nonnative).
58
58
 
59
59
  Common runner fields:
60
60
  - `name`: runner name used for lookup.
61
61
  - `host`: client-facing host. Defaults to `127.0.0.1`.
62
62
 
63
63
  Process/server fields:
64
- - `ports`: client-facing ports. These are also used for readiness/shutdown port checks. When a `fault_injection` proxy is enabled, clients should hit the first configured port.
64
+ - `ports`: client-facing ports. These are also used for readiness/shutdown port checks.
65
65
  - `timeout`: max time (seconds) for readiness/shutdown port checks.
66
66
  - `wait`: small sleep (seconds) between lifecycle steps.
67
67
  - `log`: per-runner log file used by process output redirection or server implementations.
68
68
 
69
69
  Service fields:
70
- - `port`: client-facing proxy port. Services do not get TCP readiness/shutdown checks from Nonnative.
71
-
72
- 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`.
73
-
74
- > [!IMPORTANT]
75
- > When a proxy is enabled, tests and clients connect to the runner `host` and client-facing endpoint (`ports` first entry for processes/servers, `port` for services); the nested `proxy.host`/`proxy.port` is the upstream target behind the proxy.
70
+ - `port`: client-facing service port. Services do not get TCP readiness/shutdown checks from Nonnative.
76
71
 
77
72
  Nonnative readiness and shutdown checks are TCP-only. Configure process/server ports that are dedicated to the test run; if another process is already listening on the same endpoint, results are undefined.
78
73
 
@@ -252,7 +247,7 @@ module Nonnative
252
247
  def initialize(service)
253
248
  super
254
249
 
255
- @socket_server = ::TCPServer.new(proxy.host, proxy.port)
250
+ @socket_server = ::TCPServer.new(service.host, service.port)
256
251
  end
257
252
 
258
253
  def perform_start
@@ -409,9 +404,9 @@ Nonnative.configure do |config|
409
404
  end
410
405
  ```
411
406
 
412
- ##### 🔀 Proxy
407
+ ##### 🔀 HTTP Forward Proxy
413
408
 
414
- The system allows you to define an HTTP proxy for external systems, e.g. `api.github.com`.
409
+ The system allows you to define an in-process HTTP forward proxy server for external systems, e.g. `api.github.com`. This is a server implementation, not a fault-injection service proxy.
415
410
 
416
411
  Define your server:
417
412
 
@@ -547,9 +542,9 @@ end
547
542
 
548
543
  ### 🧩 Services
549
544
 
550
- 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).
545
+ A service is an external dependency to your system that you **do not** want Nonnative to start (no OS process, no Ruby thread).
551
546
 
552
- 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.
547
+ Services do not get process lifecycle management or TCP readiness/shutdown checks from Nonnative. They provide a named endpoint for a dependency that another tool already manages.
553
548
 
554
549
  Set it up programmatically:
555
550
 
@@ -620,153 +615,38 @@ Custom proxy kinds can be registered through `Nonnative.proxies`:
620
615
  Nonnative.proxies['custom'] = CustomProxy
621
616
  ```
622
617
 
623
- 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.
624
-
625
- ##### ⚙️ Process Proxies
626
-
627
- Add this to an existing process configuration:
628
-
629
- ```ruby
630
- require 'nonnative'
631
-
632
- Nonnative.configure do |config|
633
- config.version = '1.0'
634
- config.name = 'test'
635
- config.url = 'http://localhost:4567'
636
- config.log = 'nonnative.log'
637
-
638
- config.process do |p|
639
- p.host = '127.0.0.1'
640
- p.ports = [20_000]
641
-
642
- p.proxy = {
643
- kind: 'fault_injection',
644
- host: '127.0.0.1',
645
- port: 12_321,
646
- log: 'proxy_server.log',
647
- wait: 1,
648
- options: {
649
- delay: 5
650
- }
651
- }
652
- end
653
- end
654
- ```
655
-
656
- YAML fragment:
618
+ Only services support proxies. For `fault_injection`, keep the service `host`/`port` as the client-facing proxy endpoint and use nested `proxy.host`/`proxy.port` for the upstream target behind the proxy.
657
619
 
658
- ```yaml
659
- version: "1.0"
660
- name: test
661
- url: http://localhost:4567
662
- log: nonnative.log
663
- processes:
664
- -
665
- host: 127.0.0.1
666
- ports:
667
- - 20000
668
- proxy:
669
- kind: fault_injection
670
- host: 127.0.0.1
671
- port: 12321
672
- log: proxy_server.log
673
- wait: 1
674
- options:
675
- delay: 5
676
- ```
620
+ ##### 🧩 Service Proxies
677
621
 
678
- ##### 🖥️ Server Proxies
622
+ ###### Programmatic Configuration
679
623
 
680
- Add this to an existing server configuration:
624
+ Add a proxy to a service configuration:
681
625
 
682
626
  ```ruby
683
- require 'nonnative'
684
-
685
- Nonnative.configure do |config|
686
- config.version = '1.0'
687
- config.name = 'test'
688
- config.url = 'http://localhost:4567'
689
- config.log = 'nonnative.log'
690
-
691
- config.server do |s|
692
- s.host = '127.0.0.1'
693
- s.ports = [20_000]
694
-
695
- s.proxy = {
696
- kind: 'fault_injection',
697
- host: '127.0.0.1',
698
- port: 12_321,
699
- log: 'proxy_server.log',
700
- wait: 1,
701
- options: {
702
- delay: 5
703
- }
627
+ config.service do |s|
628
+ s.name = 'redis'
629
+ s.host = '127.0.0.1'
630
+ s.port = 16_379
631
+
632
+ s.proxy = {
633
+ kind: 'fault_injection',
634
+ host: '127.0.0.1',
635
+ port: 6379,
636
+ log: 'proxy_server.log',
637
+ wait: 1,
638
+ options: {
639
+ delay: 5
704
640
  }
705
- end
641
+ }
706
642
  end
707
643
  ```
708
644
 
709
- YAML fragment:
710
-
711
- ```yaml
712
- version: "1.0"
713
- name: test
714
- url: http://localhost:4567
715
- log: nonnative.log
716
- servers:
717
- -
718
- host: 127.0.0.1
719
- ports:
720
- - 20000
721
- proxy:
722
- kind: fault_injection
723
- host: 127.0.0.1
724
- port: 12321
725
- log: proxy_server.log
726
- wait: 1
727
- options:
728
- delay: 5
729
- ```
730
-
731
- ##### 🧩 Service Proxies
732
-
733
- Add this to an existing service configuration:
734
-
735
- ```ruby
736
- require 'nonnative'
645
+ ###### YAML Configuration
737
646
 
738
- Nonnative.configure do |config|
739
- config.version = '1.0'
740
- config.name = 'test'
741
- config.url = 'http://localhost:4567'
742
- config.log = 'nonnative.log'
743
-
744
- config.service do |s|
745
- s.name = 'redis'
746
- s.host = '127.0.0.1'
747
- s.port = 16_379
748
-
749
- s.proxy = {
750
- kind: 'fault_injection',
751
- host: '127.0.0.1',
752
- port: 6379,
753
- log: 'proxy_server.log',
754
- wait: 1,
755
- options: {
756
- delay: 5
757
- }
758
- }
759
- end
760
- end
761
- ```
762
-
763
- YAML fragment:
647
+ Add a proxy to a service YAML entry:
764
648
 
765
649
  ```yaml
766
- version: "1.0"
767
- name: test
768
- url: http://localhost:4567
769
- log: nonnative.log
770
650
  services:
771
651
  -
772
652
  name: redis
@@ -786,53 +666,15 @@ services:
786
666
 
787
667
  The `fault_injection` proxy allows you to simulate failures by injecting them. We currently support the following:
788
668
 
789
- Clients connect to the runner `host` and client-facing endpoint, while the proxy forwards traffic to nested `proxy.host`/`proxy.port`.
669
+ Clients connect to the service `host`/`port`, while the proxy forwards traffic to nested `proxy.host`/`proxy.port`.
790
670
 
791
671
  - `close_all` - Closes the socket as soon as it connects.
792
672
  - `delay` - Delays traffic on the connection. Defaults to 2 seconds and can be configured through options.
793
673
  - `invalid_data` - Forwards client requests unchanged, then corrupts upstream responses before they reach the client.
794
674
 
795
- ###### ⚙️ Fault Injection Processes
796
-
797
- Set it up programmatically:
798
-
799
- ```ruby
800
- name = 'name of process in configuration'
801
- server = Nonnative.pool.process_by_name(name)
802
-
803
- server.proxy.close_all # To use close_all.
804
- server.proxy.reset # To reset it back to a good state.
805
- ```
806
-
807
- With cucumber:
808
-
809
- ```cucumber
810
- Given I set the proxy for process 'process_1' to 'close_all'
811
- Then I should reset the proxy for process 'process_1'
812
- ```
813
-
814
- ###### 🖥️ Fault Injection Servers
815
-
816
- Set it up programmatically:
817
-
818
- ```ruby
819
- name = 'name of server in configuration'
820
- server = Nonnative.pool.server_by_name(name)
821
-
822
- server.proxy.close_all # To use close_all.
823
- server.proxy.reset # To reset it back to a good state.
824
- ```
825
-
826
- With cucumber:
827
-
828
- ```cucumber
829
- Given I set the proxy for server 'server_1' to 'close_all'
830
- Then I should reset the proxy for server 'server_1'
831
- ```
832
-
833
675
  ###### 🧩 Fault Injection Services
834
676
 
835
- Set it up programmatically:
677
+ Set the proxy state programmatically:
836
678
 
837
679
  ```ruby
838
680
  name = 'name of service in configuration'
@@ -842,7 +684,7 @@ service.proxy.close_all # To use close_all.
842
684
  service.proxy.reset # To reset it back to a good state.
843
685
  ```
844
686
 
845
- With cucumber:
687
+ Use the Cucumber proxy steps:
846
688
 
847
689
  ```cucumber
848
690
  Given I set the proxy for service 'service_1' to 'close_all'
@@ -124,13 +124,13 @@ module Nonnative
124
124
  def add_processes(cfg)
125
125
  processes = cfg.processes || []
126
126
  processes.each do |loaded_process|
127
+ reject_proxy(loaded_process, 'processes')
128
+
127
129
  process do |process_config|
128
130
  process_config.command = command(loaded_process)
129
131
  process_config.signal = loaded_process.signal
130
132
  process_config.environment = loaded_process.environment
131
133
  runner_attributes(process_config, loaded_process)
132
-
133
- assign_proxy(process_config, loaded_process.proxy)
134
134
  end
135
135
  end
136
136
  end
@@ -150,11 +150,11 @@ module Nonnative
150
150
  def add_servers(cfg)
151
151
  servers = cfg.servers || []
152
152
  servers.each do |loaded_server|
153
+ reject_proxy(loaded_server, 'servers')
154
+
153
155
  server do |server_config|
154
156
  server_config.klass = Object.const_get(server_class_name(loaded_server))
155
157
  runner_attributes(server_config, loaded_server)
156
-
157
- assign_proxy(server_config, loaded_server.proxy)
158
158
  end
159
159
  end
160
160
  end
@@ -200,7 +200,14 @@ module Nonnative
200
200
  service.port = loaded.port if loaded.port
201
201
  end
202
202
 
203
- def assign_proxy(runner, loaded_proxy)
203
+ def reject_proxy(loaded, kind)
204
+ values = loaded.to_h
205
+ return unless values.key?(:proxy) || values.key?('proxy')
206
+
207
+ raise ArgumentError, "Use 'services' for proxy configuration; #{kind} do not support 'proxy'"
208
+ end
209
+
210
+ def assign_proxy(service, loaded_proxy)
204
211
  return unless loaded_proxy
205
212
 
206
213
  proxy_attributes = {
@@ -213,7 +220,7 @@ module Nonnative
213
220
  proxy_attributes[:host] = loaded_proxy.host if loaded_proxy.host
214
221
  proxy_attributes[:wait] = loaded_proxy.wait if loaded_proxy.wait
215
222
 
216
- runner.proxy = proxy_attributes
223
+ service.proxy = proxy_attributes
217
224
  end
218
225
  end
219
226
  end
@@ -1,17 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Nonnative
4
- # Proxy configuration attached to a runner configuration.
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
7
  # the built-in `"fault_injection"` proxy can close connections, introduce delays, or corrupt data
8
8
  # for resilience testing.
9
9
  #
10
- # This object is created automatically for each runner via {Nonnative::ConfigurationRunner}.
11
- # When `kind` is set to `"none"`, no proxy is started and the runner will use its configured
10
+ # This object is created automatically for each service via {Nonnative::ConfigurationService}.
11
+ # When `kind` is set to `"none"`, no proxy is started and the service will use its configured
12
12
  # `host`/`port` directly.
13
13
  #
14
- # @see Nonnative::ConfigurationRunner#proxy
14
+ # @see Nonnative::ConfigurationService#proxy
15
15
  # @see Nonnative.proxies
16
16
  class ConfigurationProxy
17
17
  # @return [String] proxy kind name (for example `"none"` or `"fault_injection"`)
@@ -3,8 +3,7 @@
3
3
  module Nonnative
4
4
  # Base configuration for a runnable unit managed by Nonnative.
5
5
  #
6
- # This class holds connection and timing attributes common to processes, servers and services,
7
- # as well as a nested {Nonnative::ConfigurationProxy} describing how/if a proxy should be started.
6
+ # This class holds connection and timing attributes common to processes, servers and services.
8
7
  #
9
8
  # Instances of this type are typically created via {Nonnative::Configuration#process},
10
9
  # {Nonnative::Configuration#server}, or {Nonnative::Configuration#service}.
@@ -22,29 +21,18 @@ module Nonnative
22
21
  # @return [Array<Integer>] client-facing ports used for readiness/shutdown checks
23
22
  attr_reader :ports
24
23
 
25
- # Proxy configuration for this runner.
26
- #
27
- # Note that this returns a configuration object even if no proxy is enabled; by default
28
- # the proxy kind is `"none"`.
29
- #
30
- # @return [Nonnative::ConfigurationProxy]
31
- attr_reader :proxy
32
-
33
24
  # Creates a runner configuration with defaults.
34
25
  #
35
26
  # Defaults:
36
27
  # - `host`: `"127.0.0.1"`
37
28
  # - `ports`: `[0]`
38
29
  # - `wait`: `0.1`
39
- # - `proxy`: a new {Nonnative::ConfigurationProxy} with its own defaults
40
30
  #
41
31
  # @return [void]
42
32
  def initialize
43
33
  self.host = '127.0.0.1'
44
34
  @ports = [0]
45
35
  self.wait = 0.1
46
-
47
- @proxy = Nonnative::ConfigurationProxy.new
48
36
  end
49
37
 
50
38
  # Sets the client-facing ports for this runner.
@@ -57,34 +45,11 @@ module Nonnative
57
45
 
58
46
  # Returns the primary client-facing port.
59
47
  #
60
- # This preserves a single endpoint for proxy binding and client helpers while the public
61
- # configuration contract uses {#ports}.
48
+ # This preserves a single endpoint for client helpers while the public configuration contract uses {#ports}.
62
49
  #
63
50
  # @return [Integer]
64
51
  def port
65
52
  ports.first
66
53
  end
67
-
68
- # Sets proxy configuration using a hash-like value.
69
- #
70
- # This is primarily used when loading YAML configuration files, where proxy attributes are
71
- # represented as scalar values.
72
- #
73
- # @param value [Hash] proxy attributes
74
- # @option value [String] :kind proxy kind name (for example `"fault_injection"`)
75
- # @option value [String] :host upstream host behind the proxy (optional)
76
- # @option value [Integer] :port upstream port behind the proxy
77
- # @option value [String] :log proxy log file path
78
- # @option value [Numeric] :wait wait interval (seconds) after state changes (optional)
79
- # @option value [Hash] :options proxy implementation specific options
80
- # @return [void]
81
- def proxy=(value)
82
- proxy.kind = value[:kind]
83
- proxy.host = value[:host] if value[:host]
84
- proxy.port = value[:port]
85
- proxy.log = value[:log]
86
- proxy.wait = value[:wait] if value[:wait]
87
- proxy.options = value[:options]
88
- end
89
54
  end
90
55
  end
@@ -14,6 +14,11 @@ module Nonnative
14
14
  # @return [Integer] client-facing port used by the service proxy
15
15
  attr_accessor :port
16
16
 
17
+ # Proxy configuration for this service.
18
+ #
19
+ # @return [Nonnative::ConfigurationProxy]
20
+ attr_reader :proxy
21
+
17
22
  # Creates a service configuration with defaults.
18
23
  #
19
24
  # @return [void]
@@ -21,6 +26,29 @@ module Nonnative
21
26
  super
22
27
 
23
28
  self.port = 0
29
+ @proxy = Nonnative::ConfigurationProxy.new
30
+ end
31
+
32
+ # Sets proxy configuration using a hash-like value.
33
+ #
34
+ # This is primarily used when loading YAML configuration files, where proxy attributes are
35
+ # represented as scalar values.
36
+ #
37
+ # @param value [Hash] proxy attributes
38
+ # @option value [String] :kind proxy kind name (for example `"fault_injection"`)
39
+ # @option value [String] :host upstream host behind the proxy (optional)
40
+ # @option value [Integer] :port upstream port behind the proxy
41
+ # @option value [String] :log proxy log file path
42
+ # @option value [Numeric] :wait wait interval (seconds) after state changes (optional)
43
+ # @option value [Hash] :options proxy implementation specific options
44
+ # @return [void]
45
+ def proxy=(value)
46
+ proxy.kind = value[:kind]
47
+ proxy.host = value[:host] if value[:host]
48
+ proxy.port = value[:port]
49
+ proxy.log = value[:log]
50
+ proxy.wait = value[:wait] if value[:wait]
51
+ proxy.options = value[:options]
24
52
  end
25
53
 
26
54
  # Services expose a single proxy listener, so plural runner ports are not supported.
@@ -45,16 +45,6 @@ module Nonnative
45
45
  end
46
46
 
47
47
  def install_proxy_mutation_steps
48
- Given('I set the proxy for process {string} to {string}') do |name, operation|
49
- process = Nonnative.pool.process_by_name(name)
50
- Nonnative::Cucumber::Registration.apply_proxy_operation(process.proxy, operation)
51
- end
52
-
53
- Given('I set the proxy for server {string} to {string}') do |name, operation|
54
- server = Nonnative.pool.server_by_name(name)
55
- Nonnative::Cucumber::Registration.apply_proxy_operation(server.proxy, operation)
56
- end
57
-
58
48
  Given('I set the proxy for service {string} to {string}') do |name, operation|
59
49
  service = Nonnative.pool.service_by_name(name)
60
50
  Nonnative::Cucumber::Registration.apply_proxy_operation(service.proxy, operation)
@@ -62,16 +52,6 @@ module Nonnative
62
52
  end
63
53
 
64
54
  def install_proxy_reset_steps
65
- Then('I should reset the proxy for process {string}') do |name|
66
- process = Nonnative.pool.process_by_name(name)
67
- process.proxy.reset
68
- end
69
-
70
- Then('I should reset the proxy for server {string}') do |name|
71
- server = Nonnative.pool.server_by_name(name)
72
- server.proxy.reset
73
- end
74
-
75
55
  Then('I should reset the proxy for service {string}') do |name|
76
56
  service = Nonnative.pool.service_by_name(name)
77
57
  service.proxy.reset
@@ -18,12 +18,12 @@ module Nonnative
18
18
  #
19
19
  # ## Wiring
20
20
  #
21
- # When enabled, your test/client should connect to the runner `host` and primary port (the proxy
21
+ # When enabled, your test/client should connect to the service `host` and `port` (the proxy
22
22
  # endpoint), and the proxy will forward traffic to the upstream target exposed by {#host}:{#port}.
23
23
  #
24
24
  # ## Configuration
25
25
  #
26
- # The proxy is configured via the runner’s `proxy` hash:
26
+ # The proxy is configured via the service's `proxy` hash:
27
27
  #
28
28
  # - `kind`: `"fault_injection"`
29
29
  # - `host` / `port`: upstream target behind the proxy (exposed via {#host}/{#port})
@@ -50,7 +50,7 @@ module Nonnative
50
50
  end
51
51
  end
52
52
 
53
- # @param service [Nonnative::ConfigurationRunner] runner configuration with proxy settings
53
+ # @param service [Nonnative::ConfigurationService] service configuration with proxy settings
54
54
  def initialize(service)
55
55
  @connections = Concurrent::Hash.new
56
56
  @logger = Logger.new(service.proxy.log)
@@ -62,8 +62,8 @@ 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` and primary port.
66
- # Clients connect to that runner endpoint, while upstream traffic is forwarded to {#host}:{#port}.
65
+ # This binds a TCP server on the service `host` and `port`.
66
+ # Clients connect to that service endpoint, while upstream traffic is forwarded to {#host}:{#port}.
67
67
  #
68
68
  # @return [void]
69
69
  def start
@@ -4,8 +4,7 @@ module Nonnative
4
4
  # gRPC server runner implemented using {GRPC::RpcServer}.
5
5
  #
6
6
  # This is a convenience server implementation for running a gRPC service in-process under
7
- # Nonnative's server lifecycle. It binds to the configured proxy `host`/`port` and is started/stopped
8
- # by {Nonnative::Server} via {#perform_start} / {#perform_stop}.
7
+ # Nonnative's server lifecycle. It binds to the configured server `host` and first `ports` entry.
9
8
  #
10
9
  # Important note about logging: the `grpc` gem uses a global logger. This implementation sets
11
10
  # `GRPC.logger` to write to the configured `service.log`, and whichever gRPC server is initialized
@@ -33,12 +32,11 @@ module Nonnative
33
32
 
34
33
  # Binds the gRPC server and begins serving requests.
35
34
  #
36
- # The server binds to the upstream proxy host/port so the fault-injection proxy can expose the
37
- # runner host and first configured port as the client-facing endpoint used by readiness checks.
35
+ # The server binds to the configured server host and first configured port.
38
36
  #
39
37
  # @return [void]
40
38
  def perform_start
41
- server.add_http2_port("#{proxy.host}:#{proxy.port}", :this_port_is_insecure)
39
+ server.add_http2_port("#{service.host}:#{service.port}", :this_port_is_insecure)
42
40
  server.run
43
41
  end
44
42
 
@@ -4,8 +4,7 @@ module Nonnative
4
4
  # Puma-based HTTP server runner.
5
5
  #
6
6
  # This is a convenience server implementation for running a Rack/Sinatra application in-process
7
- # under Nonnative's server lifecycle. It binds to the configured proxy `host`/`port` (so it works
8
- # consistently with proxy configuration) and uses Puma for HTTP serving.
7
+ # under Nonnative's server lifecycle. It binds to the configured server `host` and first `ports` entry.
9
8
  #
10
9
  # The server is started and stopped by {Nonnative::Server} via {#perform_start} / {#perform_stop}.
11
10
  #
@@ -48,12 +47,11 @@ module Nonnative
48
47
 
49
48
  # Binds the Puma server and begins serving.
50
49
  #
51
- # The listener binds to the upstream proxy host/port so the fault-injection proxy can expose the
52
- # runner host and first configured port as the client-facing endpoint used by readiness checks.
50
+ # The listener binds to the configured server host and first configured port.
53
51
  #
54
52
  # @return [void]
55
53
  def perform_start
56
- server.add_tcp_listener proxy.host, proxy.port
54
+ server.add_tcp_listener service.host, service.port
57
55
  server.run false
58
56
  end
59
57
 
@@ -7,7 +7,7 @@ module Nonnative
7
7
  # It does not bind/listen or alter traffic; it simply exposes the underlying runner's configured
8
8
  # `host` and primary `port`.
9
9
  #
10
- # Runners can always call `start`, `stop`, and `reset` safely on this proxy.
10
+ # Services can always call `start`, `stop`, and `reset` safely on this proxy.
11
11
  #
12
12
  # @see Nonnative.proxy
13
13
  # @see Nonnative::Proxy
@@ -104,15 +104,13 @@ module Nonnative
104
104
  services[runner_index(configuration.services, name)]
105
105
  end
106
106
 
107
- # Resets proxies for all runners in this pool.
107
+ # Resets service proxies in this pool.
108
108
  #
109
109
  # This is used by the Cucumber `@reset` hook and is safe to call any time after the pool is created.
110
110
  #
111
111
  # @return [void]
112
112
  def reset
113
113
  services.each { |s| s.proxy.reset }
114
- servers.each { |s| s.first.proxy.reset }
115
- processes.each { |p| p.first.proxy.reset }
116
114
  end
117
115
 
118
116
  private
@@ -4,7 +4,6 @@ module Nonnative
4
4
  # Runtime runner that manages an OS-level child process.
5
5
  #
6
6
  # A process runner:
7
- # - starts the configured proxy (if any),
8
7
  # - spawns a child process using the configured command and environment,
9
8
  # - waits briefly (via the runner `wait`), and
10
9
  # - participates in readiness/shutdown via TCP port checks orchestrated by {Nonnative::Pool}.
@@ -21,7 +20,7 @@ module Nonnative
21
20
  @timeout = Nonnative::Timeout.new(service.timeout)
22
21
  end
23
22
 
24
- # Starts the proxy (if any) and spawns the configured process if it is not already running.
23
+ # Spawns the configured process if it is not already running.
25
24
  #
26
25
  # @return [Array<(Integer, Boolean)>]
27
26
  # a tuple of:
@@ -29,7 +28,6 @@ module Nonnative
29
28
  # - whether the process appears to still be running (non-blocking wait result)
30
29
  def start
31
30
  unless process_exists?
32
- proxy.start
33
31
  @pid = process_spawn
34
32
  wait_start
35
33
  end
@@ -37,7 +35,7 @@ module Nonnative
37
35
  [pid, ::Process.waitpid2(pid, ::Process::WNOHANG).nil?]
38
36
  end
39
37
 
40
- # Stops the process (if running) and stops the proxy (if any).
38
+ # Stops the process if it is running.
41
39
  #
42
40
  # The process is signalled using the configured signal (defaults to `INT` when not set).
43
41
  #
@@ -54,8 +52,6 @@ module Nonnative
54
52
  end
55
53
 
56
54
  [pid, stopped]
57
- ensure
58
- proxy.stop
59
55
  end
60
56
 
61
57
  # Returns a memoized memory reader for the spawned process.
@@ -4,8 +4,7 @@ module Nonnative
4
4
  # Base class for proxy implementations.
5
5
  #
6
6
  # A proxy is responsible for interposing behavior between a client and a target service.
7
- # Runners ({Nonnative::Process}, {Nonnative::Server}, and {Nonnative::Service}) create a proxy
8
- # instance via {Nonnative::ProxyFactory} based on `service.proxy.kind`.
7
+ # Runtime services create a proxy instance via {Nonnative::ProxyFactory} based on `service.proxy.kind`.
9
8
  #
10
9
  # Concrete proxies typically implement these public methods:
11
10
  # - `start`: begin proxying (bind/listen, start threads, etc)
@@ -17,7 +16,7 @@ module Nonnative
17
16
  # @see Nonnative::NoProxy
18
17
  # @see Nonnative::FaultInjectionProxy
19
18
  class Proxy
20
- # @param service [Nonnative::ConfigurationRunner] runner configuration with an attached proxy configuration
19
+ # @param service [Nonnative::ConfigurationService] service configuration with an attached proxy configuration
21
20
  def initialize(service)
22
21
  @service = service
23
22
  end
@@ -1,11 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Nonnative
4
- # Factory for creating proxy instances for runners.
4
+ # Factory for creating proxy instances for services.
5
5
  #
6
- # Each runtime runner ({Nonnative::Process}, {Nonnative::Server}, {Nonnative::Service}) constructs
7
- # a proxy via this factory. The proxy implementation is selected by `service.proxy.kind` and resolved
8
- # using {Nonnative.proxy}.
6
+ # A runtime service constructs a proxy via this factory. The proxy implementation is selected by
7
+ # `service.proxy.kind` and resolved using {Nonnative.proxy}.
9
8
  #
10
9
  # If the kind is unknown (or `"none"`), {Nonnative.proxy} returns {Nonnative::NoProxy}.
11
10
  #
@@ -15,9 +14,9 @@ module Nonnative
15
14
  # @see Nonnative::NoProxy
16
15
  class ProxyFactory
17
16
  class << self
18
- # Creates a proxy instance for the given runner configuration.
17
+ # Creates a proxy instance for the given service configuration.
19
18
  #
20
- # @param service [Nonnative::ConfigurationRunner] runner configuration with an attached proxy configuration
19
+ # @param service [Nonnative::ConfigurationService] service configuration with an attached proxy configuration
21
20
  # @return [Nonnative::Proxy] proxy instance (may be a {Nonnative::NoProxy})
22
21
  def create(service)
23
22
  proxy = Nonnative.proxy(service.proxy.kind)
@@ -10,21 +10,13 @@ module Nonnative
10
10
  # - {Nonnative::Server} for in-process Ruby servers (threads)
11
11
  # - {Nonnative::Service} for proxy-only external dependencies
12
12
  #
13
- # Each runner has an associated proxy instance created via {Nonnative::ProxyFactory}.
14
- #
15
13
  # @see Nonnative::Process
16
14
  # @see Nonnative::Server
17
15
  # @see Nonnative::Service
18
16
  class Runner
19
- # Returns the proxy instance for this runner.
20
- #
21
- # @return [Nonnative::Proxy]
22
- attr_reader :proxy
23
-
24
17
  # @param service [Nonnative::ConfigurationRunner] runner configuration
25
18
  def initialize(service)
26
19
  @service = service
27
- @proxy = Nonnative::ProxyFactory.create(service)
28
20
  end
29
21
 
30
22
  # Returns the configured runner name.
@@ -4,7 +4,6 @@ module Nonnative
4
4
  # Runtime runner that manages an in-process Ruby server.
5
5
  #
6
6
  # A server runner:
7
- # - starts the configured proxy (if any),
8
7
  # - starts a Ruby thread that runs {#perform_start},
9
8
  # - waits briefly (via the runner `wait`), and
10
9
  # - participates in readiness/shutdown via TCP port checks orchestrated by {Nonnative::Pool}.
@@ -25,7 +24,7 @@ module Nonnative
25
24
  @timeout = Nonnative::Timeout.new(service.timeout)
26
25
  end
27
26
 
28
- # Starts the proxy (if any) and starts the server thread if not already started.
27
+ # Starts the server thread if it is not already started.
29
28
  #
30
29
  # @return [Array<(Integer, TrueClass)>]
31
30
  # a tuple of:
@@ -33,7 +32,6 @@ module Nonnative
33
32
  # - `true` (thread creation itself is considered started; readiness is checked separately)
34
33
  def start
35
34
  unless thread
36
- proxy.start
37
35
  @thread = Thread.new { perform_start }
38
36
 
39
37
  wait_start
@@ -46,14 +44,13 @@ module Nonnative
46
44
 
47
45
  # Stops the server if it is running.
48
46
  #
49
- # Calls {#perform_stop}, terminates the server thread, stops the proxy (if any), and waits briefly.
47
+ # Calls {#perform_stop}, terminates the server thread, and waits briefly.
50
48
  #
51
49
  # @return [Integer] the server identifier (`object_id`)
52
50
  def stop
53
51
  if thread
54
52
  perform_stop
55
53
  thread.terminate
56
- proxy.stop
57
54
 
58
55
  @thread = nil
59
56
  wait_stop
@@ -12,6 +12,18 @@ module Nonnative
12
12
  # @see Nonnative::ConfigurationService
13
13
  # @see Nonnative::Proxy
14
14
  class Service < Runner
15
+ # Returns the proxy instance for this service.
16
+ #
17
+ # @return [Nonnative::Proxy]
18
+ attr_reader :proxy
19
+
20
+ # @param service [Nonnative::ConfigurationService] service configuration
21
+ def initialize(service)
22
+ super
23
+
24
+ @proxy = Nonnative::ProxyFactory.create(service)
25
+ end
26
+
15
27
  # Starts the configured proxy (if any).
16
28
  #
17
29
  # @return [void]
@@ -4,5 +4,5 @@ module Nonnative
4
4
  # The current gem version.
5
5
  #
6
6
  # @return [String]
7
- VERSION = '3.1.0'
7
+ VERSION = '3.2.0'
8
8
  end
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.1.0
4
+ version: 3.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alejandro Falkowski