nonnative 1.21.0 → 1.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/Gemfile.lock +54 -51
- data/Makefile +0 -1
- data/README.md +66 -30
- data/lib/nonnative.rb +6 -1
- data/lib/nonnative/close_all_socket_pair.rb +9 -0
- data/lib/nonnative/command.rb +1 -1
- data/lib/nonnative/configuration.rb +5 -2
- data/lib/nonnative/configuration_process.rb +1 -1
- data/lib/nonnative/configuration_proxy.rb +2 -1
- data/lib/nonnative/configuration_server.rb +3 -2
- data/lib/nonnative/delay_socket_pair.rb +12 -0
- data/lib/nonnative/fault_injection_proxy.rb +78 -0
- data/lib/nonnative/grpc_server.rb +5 -0
- data/lib/nonnative/http_client.rb +12 -8
- data/lib/nonnative/http_server.rb +3 -1
- data/lib/nonnative/invalid_data_socket_pair.rb +11 -0
- data/lib/nonnative/proxy.rb +1 -2
- data/lib/nonnative/proxy_factory.rb +8 -7
- data/lib/nonnative/socket_pair.rb +53 -0
- data/lib/nonnative/socket_pair_factory.rb +22 -0
- data/lib/nonnative/version.rb +1 -1
- data/nonnative.gemspec +1 -2
- metadata +20 -35
- data/lib/nonnative/chaos_proxy.rb +0 -94
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 12206912ca29ab82602d7d07fdc15f5b42124e890572d463ad1c4358c7de9f08
|
|
4
|
+
data.tar.gz: ee0393650b33d8a3c5b1d31019f717a3fb680f8872171c7fea1ac4892e186ad5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9bbd95d62ddf01d04fd7f6bc4a783276e65dcc7775fbc1844316ee5f12ce150cf06cb3536c77e98f2b600fa5126fd2ed6e2946466559a53a4444ea4e1448b62f
|
|
7
|
+
data.tar.gz: 4417fe28fb3f291a7ac81bab44cbf398fc897acbf815397bd58aba7a72548c0320faba7aeab15778f7037c05b9fb84e2429cbd0a19ec6daba2d0c4f9f646318e
|
data/.rubocop.yml
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
nonnative (1.
|
|
4
|
+
nonnative (1.26.0)
|
|
5
5
|
concurrent-ruby (~> 1.0, >= 1.0.5)
|
|
6
|
-
cucumber (
|
|
6
|
+
cucumber (>= 4, < 5)
|
|
7
7
|
grpc (>= 1, < 2)
|
|
8
8
|
puma (~> 4.3, >= 4.3.3)
|
|
9
9
|
rest-client (~> 2.1)
|
|
@@ -14,47 +14,57 @@ PATH
|
|
|
14
14
|
GEM
|
|
15
15
|
remote: https://rubygems.org/
|
|
16
16
|
specs:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
activesupport (6.0.3.2)
|
|
18
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
19
|
+
i18n (>= 0.7, < 2)
|
|
20
|
+
minitest (~> 5.1)
|
|
21
|
+
tzinfo (~> 1.1)
|
|
22
|
+
zeitwerk (~> 2.2, >= 2.2.2)
|
|
20
23
|
ast (2.4.1)
|
|
21
24
|
backport (1.1.2)
|
|
22
|
-
backports (3.18.1)
|
|
23
25
|
benchmark (0.1.0)
|
|
24
26
|
benchmark-malloc (0.2.0)
|
|
25
27
|
benchmark-perf (0.6.0)
|
|
26
28
|
benchmark-trend (0.4.0)
|
|
27
29
|
builder (3.2.4)
|
|
28
|
-
chutney (2.0.3.1)
|
|
29
|
-
amatch (~> 0.4.0)
|
|
30
|
-
gherkin (~> 5.1.0)
|
|
31
|
-
i18n (~> 1.8.2)
|
|
32
|
-
pastel (~> 0.7)
|
|
33
|
-
tty-pie (~> 0.3)
|
|
34
30
|
concurrent-ruby (1.1.6)
|
|
35
|
-
cucumber (
|
|
36
|
-
builder (>= 2.
|
|
37
|
-
cucumber-core (~>
|
|
38
|
-
cucumber-
|
|
39
|
-
cucumber-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
31
|
+
cucumber (4.1.0)
|
|
32
|
+
builder (~> 3.2, >= 3.2.3)
|
|
33
|
+
cucumber-core (~> 7.1, >= 7.1.0)
|
|
34
|
+
cucumber-create-meta (~> 1.0.0, >= 1.0.0)
|
|
35
|
+
cucumber-cucumber-expressions (~> 10.1, >= 10.1.0)
|
|
36
|
+
cucumber-gherkin (~> 14.0, >= 14.0.1)
|
|
37
|
+
cucumber-html-formatter (~> 7.0, >= 7.0.0)
|
|
38
|
+
cucumber-messages (~> 12.2, >= 12.2.0)
|
|
39
|
+
cucumber-wire (~> 3.1, >= 3.1.0)
|
|
40
|
+
diff-lcs (~> 1.3, >= 1.3, < 1.4)
|
|
41
|
+
multi_test (~> 0.1, >= 0.1.2)
|
|
42
|
+
sys-uname (~> 1.0, >= 1.0.2)
|
|
43
|
+
cucumber-core (7.1.0)
|
|
44
|
+
cucumber-gherkin (~> 14.0, >= 14.0.1)
|
|
45
|
+
cucumber-messages (~> 12.2, >= 12.2.0)
|
|
46
|
+
cucumber-tag-expressions (~> 2.0, >= 2.0.4)
|
|
47
|
+
cucumber-create-meta (1.0.0)
|
|
48
|
+
cucumber-messages (~> 12.2, >= 12.2.0)
|
|
49
|
+
sys-uname (~> 1.2, >= 1.2.1)
|
|
50
|
+
cucumber-cucumber-expressions (10.2.1)
|
|
51
|
+
cucumber-gherkin (14.0.1)
|
|
52
|
+
cucumber-messages (~> 12.2, >= 12.2.0)
|
|
53
|
+
cucumber-html-formatter (7.0.0)
|
|
54
|
+
cucumber-messages (~> 12.2, >= 12.2.0)
|
|
55
|
+
cucumber-messages (12.2.0)
|
|
56
|
+
protobuf-cucumber (~> 3.10, >= 3.10.8)
|
|
57
|
+
cucumber-tag-expressions (2.0.4)
|
|
58
|
+
cucumber-wire (3.1.0)
|
|
59
|
+
cucumber-core (~> 7.1, >= 7.1.0)
|
|
60
|
+
cucumber-cucumber-expressions (~> 10.1, >= 10.1.0)
|
|
61
|
+
cucumber-messages (~> 12.2, >= 12.2.0)
|
|
62
|
+
diff-lcs (1.3)
|
|
52
63
|
docile (1.3.2)
|
|
53
64
|
domain_name (0.5.20190701)
|
|
54
65
|
unf (>= 0.0.5, < 1.0.0)
|
|
55
66
|
e2mmap (0.1.0)
|
|
56
|
-
|
|
57
|
-
gherkin (5.1.0)
|
|
67
|
+
ffi (1.13.1)
|
|
58
68
|
google-protobuf (3.12.2)
|
|
59
69
|
googleapis-common-protos-types (1.0.5)
|
|
60
70
|
google-protobuf (~> 3.11)
|
|
@@ -70,13 +80,12 @@ GEM
|
|
|
70
80
|
jaro_winkler (1.5.4)
|
|
71
81
|
json (2.3.0)
|
|
72
82
|
maruku (0.7.3)
|
|
83
|
+
middleware (0.1.0)
|
|
73
84
|
mime-types (3.3.1)
|
|
74
85
|
mime-types-data (~> 3.2015)
|
|
75
86
|
mime-types-data (3.2020.0512)
|
|
76
87
|
mini_portile2 (2.4.0)
|
|
77
|
-
|
|
78
|
-
protocol (~> 2.0)
|
|
79
|
-
multi_json (1.14.1)
|
|
88
|
+
minitest (5.14.1)
|
|
80
89
|
multi_test (0.1.2)
|
|
81
90
|
mustermann (1.1.1)
|
|
82
91
|
ruby2_keywords (~> 0.0.1)
|
|
@@ -87,11 +96,11 @@ GEM
|
|
|
87
96
|
parallel (1.19.2)
|
|
88
97
|
parser (2.7.1.4)
|
|
89
98
|
ast (~> 2.4.1)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
99
|
+
protobuf-cucumber (3.10.8)
|
|
100
|
+
activesupport (>= 3.2)
|
|
101
|
+
middleware
|
|
102
|
+
thor
|
|
103
|
+
thread_safe
|
|
95
104
|
puma (4.3.5)
|
|
96
105
|
nio4r (~> 2.0)
|
|
97
106
|
rack (2.2.3)
|
|
@@ -139,9 +148,6 @@ GEM
|
|
|
139
148
|
parser (>= 2.7.0.1)
|
|
140
149
|
ruby-progressbar (1.10.1)
|
|
141
150
|
ruby2_keywords (0.0.2)
|
|
142
|
-
ruby_parser (3.14.2)
|
|
143
|
-
sexp_processor (~> 4.9)
|
|
144
|
-
sexp_processor (4.15.0)
|
|
145
151
|
simplecov (0.17.1)
|
|
146
152
|
docile (~> 1.1)
|
|
147
153
|
json (>= 1.8, < 3)
|
|
@@ -166,28 +172,25 @@ GEM
|
|
|
166
172
|
thor (~> 1.0)
|
|
167
173
|
tilt (~> 2.0)
|
|
168
174
|
yard (~> 0.9, >= 0.9.24)
|
|
169
|
-
|
|
175
|
+
sys-uname (1.2.1)
|
|
176
|
+
ffi (>= 1.0.0)
|
|
170
177
|
thor (1.0.1)
|
|
178
|
+
thread_safe (0.3.6)
|
|
171
179
|
tilt (2.0.10)
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
tty-color (0.5.1)
|
|
175
|
-
tty-cursor (0.7.1)
|
|
176
|
-
tty-pie (0.3.0)
|
|
177
|
-
pastel (~> 0.7.3)
|
|
178
|
-
tty-cursor (~> 0.7)
|
|
180
|
+
tzinfo (1.2.7)
|
|
181
|
+
thread_safe (~> 0.1)
|
|
179
182
|
unf (0.1.4)
|
|
180
183
|
unf_ext
|
|
181
184
|
unf_ext (0.0.7.7)
|
|
182
185
|
unicode-display_width (1.7.0)
|
|
183
186
|
yard (0.9.25)
|
|
187
|
+
zeitwerk (2.3.1)
|
|
184
188
|
|
|
185
189
|
PLATFORMS
|
|
186
190
|
ruby
|
|
187
191
|
|
|
188
192
|
DEPENDENCIES
|
|
189
193
|
bundler (~> 2.1, >= 2.1.4)
|
|
190
|
-
chutney (~> 2.0, >= 2.0.3.1)
|
|
191
194
|
grpc-tools (>= 1, < 2)
|
|
192
195
|
nonnative!
|
|
193
196
|
rake (~> 13.0, >= 13.0.1)
|
data/Makefile
CHANGED
data/README.md
CHANGED
|
@@ -57,7 +57,7 @@ Nonnative.configure do |config|
|
|
|
57
57
|
d.command = 'features/support/bin/start 12_321'
|
|
58
58
|
d.timeout = 0.5
|
|
59
59
|
d.port = 12_321
|
|
60
|
-
d.
|
|
60
|
+
d.log = 'features/logs/12_321.log'
|
|
61
61
|
d.signal = 'INT' # Possible values are described in Signal.list.keys
|
|
62
62
|
end
|
|
63
63
|
|
|
@@ -66,7 +66,7 @@ Nonnative.configure do |config|
|
|
|
66
66
|
d.command = 'features/support/bin/start 12_322'
|
|
67
67
|
d.timeout = 0.5
|
|
68
68
|
d.port = 12_322
|
|
69
|
-
d.
|
|
69
|
+
d.log = 'features/logs/12_322.log'
|
|
70
70
|
end
|
|
71
71
|
end
|
|
72
72
|
```
|
|
@@ -82,14 +82,14 @@ processes:
|
|
|
82
82
|
command: features/support/bin/start 12_321
|
|
83
83
|
timeout: 5
|
|
84
84
|
port: 12321
|
|
85
|
-
|
|
85
|
+
log: features/logs/12_321.log
|
|
86
86
|
signal: INT # Possible values are described in Signal.list.keys
|
|
87
87
|
-
|
|
88
88
|
name: start_2
|
|
89
89
|
command: features/support/bin/start 12_322
|
|
90
90
|
timeout: 5
|
|
91
91
|
port: 12322
|
|
92
|
-
|
|
92
|
+
log: features/logs/12_322.log
|
|
93
93
|
```
|
|
94
94
|
|
|
95
95
|
Then load the file with
|
|
@@ -133,18 +133,20 @@ require 'nonnative'
|
|
|
133
133
|
Nonnative.configure do |config|
|
|
134
134
|
config.strategy = :manual
|
|
135
135
|
|
|
136
|
-
config.server do |
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
136
|
+
config.server do |s|
|
|
137
|
+
s.name = 'server_1'
|
|
138
|
+
s.klass = Nonnative::EchoServer
|
|
139
|
+
s.timeout = 1
|
|
140
|
+
s.port = 12_323
|
|
141
|
+
s.log = 'features/logs/server_1.log'
|
|
141
142
|
end
|
|
142
143
|
|
|
143
|
-
config.server do |
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
144
|
+
config.server do |s|
|
|
145
|
+
s.name = 'server_2'
|
|
146
|
+
s.klass = Nonnative::EchoServer
|
|
147
|
+
s.timeout = 1
|
|
148
|
+
s.port = 12_324
|
|
149
|
+
s.log = 'features/logs/server_2.log'
|
|
148
150
|
end
|
|
149
151
|
end
|
|
150
152
|
```
|
|
@@ -160,11 +162,13 @@ servers:
|
|
|
160
162
|
klass: Nonnative::EchoServer
|
|
161
163
|
timeout: 1
|
|
162
164
|
port: 12323
|
|
165
|
+
log: features/logs/server_1.log
|
|
163
166
|
-
|
|
164
167
|
name: server_2
|
|
165
168
|
klass: Nonnative::EchoServer
|
|
166
169
|
timeout: 1
|
|
167
170
|
port: 12324
|
|
171
|
+
log: features/logs/server_2.log
|
|
168
172
|
```
|
|
169
173
|
|
|
170
174
|
Then load the file with:
|
|
@@ -182,7 +186,11 @@ Define your server:
|
|
|
182
186
|
```ruby
|
|
183
187
|
module Nonnative
|
|
184
188
|
module Features
|
|
185
|
-
class Application < Sinatra::
|
|
189
|
+
class Application < Sinatra::Application
|
|
190
|
+
configure do
|
|
191
|
+
set :server_settings, log_requests: true
|
|
192
|
+
end
|
|
193
|
+
|
|
186
194
|
get '/hello' do
|
|
187
195
|
'Hello World!'
|
|
188
196
|
end
|
|
@@ -205,11 +213,12 @@ require 'nonnative'
|
|
|
205
213
|
Nonnative.configure do |config|
|
|
206
214
|
config.strategy = :manual
|
|
207
215
|
|
|
208
|
-
config.server do |
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
216
|
+
config.server do |s|
|
|
217
|
+
s.name = 'http_server_1'
|
|
218
|
+
s.klass = Nonnative::Features::HTTPServer
|
|
219
|
+
s.timeout = 1
|
|
220
|
+
s.port = 4567
|
|
221
|
+
s.log = 'features/logs/http_server_1.log'
|
|
213
222
|
end
|
|
214
223
|
end
|
|
215
224
|
```
|
|
@@ -225,6 +234,7 @@ servers:
|
|
|
225
234
|
klass: Nonnative::Features::HTTPServer
|
|
226
235
|
timeout: 1
|
|
227
236
|
port: 4567
|
|
237
|
+
log: features/logs/http_server_1.log
|
|
228
238
|
```
|
|
229
239
|
|
|
230
240
|
Then load the file with:
|
|
@@ -265,11 +275,12 @@ require 'nonnative'
|
|
|
265
275
|
Nonnative.configure do |config|
|
|
266
276
|
config.strategy = :manual
|
|
267
277
|
|
|
268
|
-
config.server do |
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
278
|
+
config.server do |s|
|
|
279
|
+
s.name = 'grpc_server_1'
|
|
280
|
+
s.klass = Nonnative::Features::GRPCServer
|
|
281
|
+
s.timeout = 1
|
|
282
|
+
s.port = 9002
|
|
283
|
+
s.log = 'features/logs/grpc_server_1.log'
|
|
273
284
|
end
|
|
274
285
|
end
|
|
275
286
|
```
|
|
@@ -285,6 +296,7 @@ servers:
|
|
|
285
296
|
klass: Nonnative::Features::GRPCServer
|
|
286
297
|
timeout: 1
|
|
287
298
|
port: 9002
|
|
299
|
+
log: features/logs/grpc_server_1.log
|
|
288
300
|
```
|
|
289
301
|
|
|
290
302
|
Then load the file with:
|
|
@@ -297,8 +309,8 @@ Nonnative.load_configuration('configuration.yml')
|
|
|
297
309
|
#### Proxies
|
|
298
310
|
|
|
299
311
|
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:
|
|
300
|
-
- none (this is the default)
|
|
301
|
-
-
|
|
312
|
+
- `none` (this is the default)
|
|
313
|
+
- `fault_injection`
|
|
302
314
|
|
|
303
315
|
Setup it up programmatically:
|
|
304
316
|
|
|
@@ -310,8 +322,12 @@ Nonnative.configure do |config|
|
|
|
310
322
|
|
|
311
323
|
config.server do |d|
|
|
312
324
|
d.proxy = {
|
|
313
|
-
type: '
|
|
314
|
-
port: 20_000
|
|
325
|
+
type: 'fault_injection',
|
|
326
|
+
port: 20_000,
|
|
327
|
+
log: 'features/logs/proxy_server.log',
|
|
328
|
+
options: {
|
|
329
|
+
delay: 5
|
|
330
|
+
}
|
|
315
331
|
}
|
|
316
332
|
end
|
|
317
333
|
end
|
|
@@ -325,6 +341,26 @@ strategy: manual
|
|
|
325
341
|
servers:
|
|
326
342
|
-
|
|
327
343
|
proxy:
|
|
328
|
-
type:
|
|
344
|
+
type: fault_injection
|
|
329
345
|
port: 20000
|
|
346
|
+
log: features/logs/proxy_server.log
|
|
347
|
+
options:
|
|
348
|
+
delay: 5
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
##### Fault Injection
|
|
352
|
+
|
|
353
|
+
The `fault_injection` proxy allows you to simulate failures by injecting them. We currently support the following:
|
|
354
|
+
- `close_all` - Closes the socket as soon as it connects.
|
|
355
|
+
- `delay` - This delays the communication between the connection. Default is 2 secs can be configured through options.
|
|
356
|
+
- `invalid_data` - This takes the input and rearranges it to produce invalid data.
|
|
357
|
+
|
|
358
|
+
Setup it up programmatically:
|
|
359
|
+
|
|
360
|
+
```ruby
|
|
361
|
+
name = 'name of server in configuration'
|
|
362
|
+
server = Nonnative.pool.server_by_name(name)
|
|
363
|
+
|
|
364
|
+
server.proxy.close_all # To use close_all.
|
|
365
|
+
server.proxy.reset # To reset it back to a good state.
|
|
330
366
|
```
|
data/lib/nonnative.rb
CHANGED
|
@@ -34,7 +34,12 @@ require 'nonnative/observability'
|
|
|
34
34
|
require 'nonnative/proxy_factory'
|
|
35
35
|
require 'nonnative/proxy'
|
|
36
36
|
require 'nonnative/no_proxy'
|
|
37
|
-
require 'nonnative/
|
|
37
|
+
require 'nonnative/fault_injection_proxy'
|
|
38
|
+
require 'nonnative/socket_pair'
|
|
39
|
+
require 'nonnative/close_all_socket_pair'
|
|
40
|
+
require 'nonnative/delay_socket_pair'
|
|
41
|
+
require 'nonnative/invalid_data_socket_pair'
|
|
42
|
+
require 'nonnative/socket_pair_factory'
|
|
38
43
|
|
|
39
44
|
module Nonnative
|
|
40
45
|
class << self
|
data/lib/nonnative/command.rb
CHANGED
|
@@ -24,7 +24,7 @@ module Nonnative
|
|
|
24
24
|
d.command = fd['command']
|
|
25
25
|
d.timeout = fd['timeout']
|
|
26
26
|
d.port = fd['port']
|
|
27
|
-
d.
|
|
27
|
+
d.log = fd['log']
|
|
28
28
|
d.signal = fd['signal']
|
|
29
29
|
end
|
|
30
30
|
end
|
|
@@ -38,13 +38,16 @@ module Nonnative
|
|
|
38
38
|
s.klass = Object.const_get(fd['klass'])
|
|
39
39
|
s.timeout = fd['timeout']
|
|
40
40
|
s.port = fd['port']
|
|
41
|
+
s.log = fd['log']
|
|
41
42
|
|
|
42
43
|
proxy = fd['proxy']
|
|
43
44
|
|
|
44
45
|
if proxy
|
|
45
46
|
s.proxy = {
|
|
46
47
|
type: proxy['type'],
|
|
47
|
-
port: proxy['port']
|
|
48
|
+
port: proxy['port'],
|
|
49
|
+
log: proxy['log'],
|
|
50
|
+
options: proxy['options']
|
|
48
51
|
}
|
|
49
52
|
end
|
|
50
53
|
end
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Nonnative
|
|
4
4
|
class ConfigurationServer
|
|
5
|
-
attr_accessor :name, :klass, :timeout, :port
|
|
6
|
-
|
|
5
|
+
attr_accessor :name, :klass, :timeout, :port, :log
|
|
7
6
|
attr_reader :proxy
|
|
8
7
|
|
|
9
8
|
def initialize
|
|
@@ -13,6 +12,8 @@ module Nonnative
|
|
|
13
12
|
def proxy=(value)
|
|
14
13
|
proxy.type = value[:type]
|
|
15
14
|
proxy.port = value[:port]
|
|
15
|
+
proxy.log = value[:log]
|
|
16
|
+
proxy.options = value[:options]
|
|
16
17
|
end
|
|
17
18
|
end
|
|
18
19
|
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Nonnative
|
|
4
|
+
class FaultInjectionProxy < Nonnative::Proxy
|
|
5
|
+
def initialize(service)
|
|
6
|
+
@connections = Concurrent::Hash.new
|
|
7
|
+
@logger = Logger.new(service.proxy.log)
|
|
8
|
+
@mutex = Mutex.new
|
|
9
|
+
@state = :none
|
|
10
|
+
|
|
11
|
+
super service
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def start
|
|
15
|
+
@tcp_server = ::TCPServer.new('0.0.0.0', service.port)
|
|
16
|
+
@thread = Thread.new { perform_start }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def stop
|
|
20
|
+
thread.terminate
|
|
21
|
+
tcp_server.close
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def close_all
|
|
25
|
+
apply_state :close_all
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def delay
|
|
29
|
+
apply_state :delay
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def invalid_data
|
|
33
|
+
apply_state :invalid_data
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def reset
|
|
37
|
+
apply_state :none
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def port
|
|
41
|
+
service.proxy.port
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
attr_reader :tcp_server, :thread, :connections, :mutex, :state, :logger
|
|
47
|
+
|
|
48
|
+
def perform_start
|
|
49
|
+
loop do
|
|
50
|
+
thread = Thread.start(tcp_server.accept) do |local_socket|
|
|
51
|
+
id = Thread.current.object_id
|
|
52
|
+
|
|
53
|
+
logger.info "started connection for #{id} with socket #{local_socket.inspect}"
|
|
54
|
+
|
|
55
|
+
connect local_socket
|
|
56
|
+
connections.delete(id)
|
|
57
|
+
|
|
58
|
+
logger.info "finished connection for #{id} with socket #{local_socket.inspect}"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
thread.report_on_exception = false
|
|
62
|
+
connections[thread.object_id] = thread
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def connect(local_socket)
|
|
67
|
+
SocketPairFactory.create(read_state, service.proxy, logger).connect(local_socket)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def apply_state(state)
|
|
71
|
+
mutex.synchronize { @state = state }
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def read_state
|
|
75
|
+
mutex.synchronize { state }
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -6,6 +6,11 @@ module Nonnative
|
|
|
6
6
|
@server = GRPC::RpcServer.new
|
|
7
7
|
server.handle(svc)
|
|
8
8
|
|
|
9
|
+
# Unfortunately gRPC has only one logger so the first server wins.
|
|
10
|
+
GRPC.define_singleton_method(:logger) do
|
|
11
|
+
@logger ||= Logger.new(service.log)
|
|
12
|
+
end
|
|
13
|
+
|
|
9
14
|
super service
|
|
10
15
|
end
|
|
11
16
|
|
|
@@ -8,31 +8,33 @@ module Nonnative
|
|
|
8
8
|
|
|
9
9
|
protected
|
|
10
10
|
|
|
11
|
-
def get(pathname, headers = {})
|
|
11
|
+
def get(pathname, headers = {}, timeout = 60)
|
|
12
12
|
with_exception do
|
|
13
13
|
uri = URI.join(host, pathname)
|
|
14
|
-
RestClient.get
|
|
14
|
+
RestClient::Request.execute(method: :get, url: uri.to_s, headers: headers, timeout: timeout)
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
def post(pathname, payload, headers = {})
|
|
18
|
+
def post(pathname, payload, headers = {}, timeout = 60)
|
|
19
19
|
with_exception do
|
|
20
20
|
uri = URI.join(host, pathname)
|
|
21
|
-
RestClient.post
|
|
21
|
+
RestClient::Request.execute(method: :post, url: uri.to_s, payload: payload.to_json, headers: headers,
|
|
22
|
+
timeout: timeout)
|
|
22
23
|
end
|
|
23
24
|
end
|
|
24
25
|
|
|
25
|
-
def delete(pathname, headers = {})
|
|
26
|
+
def delete(pathname, headers = {}, timeout = 60)
|
|
26
27
|
with_exception do
|
|
27
28
|
uri = URI.join(host, pathname)
|
|
28
|
-
RestClient.delete
|
|
29
|
+
RestClient::Request.execute(method: :delete, url: uri.to_s, headers: headers, timeout: timeout)
|
|
29
30
|
end
|
|
30
31
|
end
|
|
31
32
|
|
|
32
|
-
def put(pathname, payload, headers = {})
|
|
33
|
+
def put(pathname, payload, headers = {}, timeout = 60)
|
|
33
34
|
with_exception do
|
|
34
35
|
uri = URI.join(host, pathname)
|
|
35
|
-
RestClient.put
|
|
36
|
+
RestClient::Request.execute(method: :put, url: uri.to_s, payload: payload.to_json, headers: headers,
|
|
37
|
+
timeout: timeout)
|
|
36
38
|
end
|
|
37
39
|
end
|
|
38
40
|
|
|
@@ -42,6 +44,8 @@ module Nonnative
|
|
|
42
44
|
|
|
43
45
|
def with_exception
|
|
44
46
|
yield
|
|
47
|
+
rescue RestClient::Exceptions::ReadTimeout => e
|
|
48
|
+
raise e
|
|
45
49
|
rescue RestClient::ExceptionWithResponse => e
|
|
46
50
|
e.response
|
|
47
51
|
end
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
module Nonnative
|
|
4
4
|
class HTTPServer < Nonnative::Server
|
|
5
5
|
def initialize(service)
|
|
6
|
-
|
|
6
|
+
log = File.open(service.log, 'a')
|
|
7
|
+
events = Puma::Events.new(log, log)
|
|
8
|
+
@server = Puma::Server.new(app, events)
|
|
7
9
|
|
|
8
10
|
super service
|
|
9
11
|
end
|
data/lib/nonnative/proxy.rb
CHANGED
|
@@ -4,13 +4,14 @@ module Nonnative
|
|
|
4
4
|
class ProxyFactory
|
|
5
5
|
class << self
|
|
6
6
|
def create(service)
|
|
7
|
-
case service.proxy.type
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
proxy = case service.proxy.type
|
|
8
|
+
when 'fault_injection'
|
|
9
|
+
FaultInjectionProxy
|
|
10
|
+
else
|
|
11
|
+
NoProxy
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
proxy.new(service)
|
|
14
15
|
end
|
|
15
16
|
end
|
|
16
17
|
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Nonnative
|
|
4
|
+
class SocketPair
|
|
5
|
+
def initialize(proxy, logger)
|
|
6
|
+
@proxy = proxy
|
|
7
|
+
@logger = logger
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def connect(local_socket)
|
|
11
|
+
remote_socket = create_remote_socket
|
|
12
|
+
|
|
13
|
+
loop do
|
|
14
|
+
ready = select([local_socket, remote_socket], nil, nil)
|
|
15
|
+
|
|
16
|
+
break if pipe(ready, local_socket, remote_socket)
|
|
17
|
+
break if pipe(ready, remote_socket, local_socket)
|
|
18
|
+
end
|
|
19
|
+
rescue StandardError => e
|
|
20
|
+
logger.error e
|
|
21
|
+
ensure
|
|
22
|
+
local_socket.close
|
|
23
|
+
remote_socket&.close
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
protected
|
|
27
|
+
|
|
28
|
+
attr_reader :proxy, :logger
|
|
29
|
+
|
|
30
|
+
def create_remote_socket
|
|
31
|
+
::TCPSocket.new('0.0.0.0', proxy.port)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def pipe(ready, socket1, socket2)
|
|
35
|
+
if ready[0].include?(socket1)
|
|
36
|
+
data = read(socket1)
|
|
37
|
+
return true if data.empty?
|
|
38
|
+
|
|
39
|
+
write socket2, data
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
false
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def read(socket)
|
|
46
|
+
socket.recv(1024)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def write(socket, data)
|
|
50
|
+
socket.write(data)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Nonnative
|
|
4
|
+
class SocketPairFactory
|
|
5
|
+
class << self
|
|
6
|
+
def create(type, proxy, logger)
|
|
7
|
+
pair = case type
|
|
8
|
+
when :close_all
|
|
9
|
+
CloseAllSocketPair
|
|
10
|
+
when :delay
|
|
11
|
+
DelaySocketPair
|
|
12
|
+
when :invalid_data
|
|
13
|
+
InvalidDataSocketPair
|
|
14
|
+
else
|
|
15
|
+
SocketPair
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
pair.new(proxy, logger)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
data/lib/nonnative/version.rb
CHANGED
data/nonnative.gemspec
CHANGED
|
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
|
|
|
25
25
|
spec.require_paths = ['lib']
|
|
26
26
|
|
|
27
27
|
spec.add_dependency 'concurrent-ruby', '~> 1.0', '>= 1.0.5'
|
|
28
|
-
spec.add_dependency 'cucumber', '
|
|
28
|
+
spec.add_dependency 'cucumber', ['>= 4', '< 5']
|
|
29
29
|
spec.add_dependency 'grpc', ['>= 1', '< 2']
|
|
30
30
|
spec.add_dependency 'puma', '~> 4.3', '>= 4.3.3'
|
|
31
31
|
spec.add_dependency 'rest-client', '~> 2.1'
|
|
@@ -34,7 +34,6 @@ Gem::Specification.new do |spec|
|
|
|
34
34
|
spec.add_dependency 'sinatra', '~> 2.0', '>= 2.0.8.1'
|
|
35
35
|
|
|
36
36
|
spec.add_development_dependency 'bundler', '~> 2.1', '>= 2.1.4'
|
|
37
|
-
spec.add_development_dependency 'chutney', '~> 2.0', '>= 2.0.3.1'
|
|
38
37
|
spec.add_development_dependency 'grpc-tools', ['>= 1', '< 2']
|
|
39
38
|
spec.add_development_dependency 'rake', '~> 13.0', '>= 13.0.1'
|
|
40
39
|
spec.add_development_dependency 'rubocop', '~> 0.87.1'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: nonnative
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.26.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alex Falkowski
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2020-07-
|
|
11
|
+
date: 2020-07-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: concurrent-ruby
|
|
@@ -34,22 +34,22 @@ dependencies:
|
|
|
34
34
|
name: cucumber
|
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
|
-
- - "~>"
|
|
38
|
-
- !ruby/object:Gem::Version
|
|
39
|
-
version: '3.1'
|
|
40
37
|
- - ">="
|
|
41
38
|
- !ruby/object:Gem::Version
|
|
42
|
-
version:
|
|
39
|
+
version: '4'
|
|
40
|
+
- - "<"
|
|
41
|
+
- !ruby/object:Gem::Version
|
|
42
|
+
version: '5'
|
|
43
43
|
type: :runtime
|
|
44
44
|
prerelease: false
|
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
|
46
46
|
requirements:
|
|
47
|
-
- - "~>"
|
|
48
|
-
- !ruby/object:Gem::Version
|
|
49
|
-
version: '3.1'
|
|
50
47
|
- - ">="
|
|
51
48
|
- !ruby/object:Gem::Version
|
|
52
|
-
version:
|
|
49
|
+
version: '4'
|
|
50
|
+
- - "<"
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: '5'
|
|
53
53
|
- !ruby/object:Gem::Dependency
|
|
54
54
|
name: grpc
|
|
55
55
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -178,26 +178,6 @@ dependencies:
|
|
|
178
178
|
- - ">="
|
|
179
179
|
- !ruby/object:Gem::Version
|
|
180
180
|
version: 2.1.4
|
|
181
|
-
- !ruby/object:Gem::Dependency
|
|
182
|
-
name: chutney
|
|
183
|
-
requirement: !ruby/object:Gem::Requirement
|
|
184
|
-
requirements:
|
|
185
|
-
- - "~>"
|
|
186
|
-
- !ruby/object:Gem::Version
|
|
187
|
-
version: '2.0'
|
|
188
|
-
- - ">="
|
|
189
|
-
- !ruby/object:Gem::Version
|
|
190
|
-
version: 2.0.3.1
|
|
191
|
-
type: :development
|
|
192
|
-
prerelease: false
|
|
193
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
194
|
-
requirements:
|
|
195
|
-
- - "~>"
|
|
196
|
-
- !ruby/object:Gem::Version
|
|
197
|
-
version: '2.0'
|
|
198
|
-
- - ">="
|
|
199
|
-
- !ruby/object:Gem::Version
|
|
200
|
-
version: 2.0.3.1
|
|
201
181
|
- !ruby/object:Gem::Dependency
|
|
202
182
|
name: grpc-tools
|
|
203
183
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -303,16 +283,19 @@ files:
|
|
|
303
283
|
- bin/setup
|
|
304
284
|
- lib/nonnative.rb
|
|
305
285
|
- lib/nonnative/before.rb
|
|
306
|
-
- lib/nonnative/
|
|
286
|
+
- lib/nonnative/close_all_socket_pair.rb
|
|
307
287
|
- lib/nonnative/command.rb
|
|
308
288
|
- lib/nonnative/configuration.rb
|
|
309
289
|
- lib/nonnative/configuration_process.rb
|
|
310
290
|
- lib/nonnative/configuration_proxy.rb
|
|
311
291
|
- lib/nonnative/configuration_server.rb
|
|
292
|
+
- lib/nonnative/delay_socket_pair.rb
|
|
312
293
|
- lib/nonnative/error.rb
|
|
294
|
+
- lib/nonnative/fault_injection_proxy.rb
|
|
313
295
|
- lib/nonnative/grpc_server.rb
|
|
314
296
|
- lib/nonnative/http_client.rb
|
|
315
297
|
- lib/nonnative/http_server.rb
|
|
298
|
+
- lib/nonnative/invalid_data_socket_pair.rb
|
|
316
299
|
- lib/nonnative/manual.rb
|
|
317
300
|
- lib/nonnative/no_proxy.rb
|
|
318
301
|
- lib/nonnative/observability.rb
|
|
@@ -322,6 +305,8 @@ files:
|
|
|
322
305
|
- lib/nonnative/proxy_factory.rb
|
|
323
306
|
- lib/nonnative/server.rb
|
|
324
307
|
- lib/nonnative/service.rb
|
|
308
|
+
- lib/nonnative/socket_pair.rb
|
|
309
|
+
- lib/nonnative/socket_pair_factory.rb
|
|
325
310
|
- lib/nonnative/start_error.rb
|
|
326
311
|
- lib/nonnative/startup.rb
|
|
327
312
|
- lib/nonnative/stop_error.rb
|
|
@@ -333,7 +318,7 @@ homepage: https://github.com/alexfalkowski/nonnative
|
|
|
333
318
|
licenses:
|
|
334
319
|
- Unlicense
|
|
335
320
|
metadata: {}
|
|
336
|
-
post_install_message:
|
|
321
|
+
post_install_message:
|
|
337
322
|
rdoc_options: []
|
|
338
323
|
require_paths:
|
|
339
324
|
- lib
|
|
@@ -348,8 +333,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
348
333
|
- !ruby/object:Gem::Version
|
|
349
334
|
version: '0'
|
|
350
335
|
requirements: []
|
|
351
|
-
rubygems_version: 3.0.
|
|
352
|
-
signing_key:
|
|
336
|
+
rubygems_version: 3.0.8
|
|
337
|
+
signing_key:
|
|
353
338
|
specification_version: 4
|
|
354
339
|
summary: Allows you to keep using the power of ruby to test other systems
|
|
355
340
|
test_files: []
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Nonnative
|
|
4
|
-
class ChaosProxy < Nonnative::Proxy
|
|
5
|
-
def initialize(service)
|
|
6
|
-
@connections = Concurrent::Hash.new
|
|
7
|
-
@mutex = Mutex.new
|
|
8
|
-
@state = :none
|
|
9
|
-
|
|
10
|
-
super service
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def start
|
|
14
|
-
@tcp_server = ::TCPServer.new('0.0.0.0', service.port)
|
|
15
|
-
@thread = Thread.new { perform_start }
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def stop
|
|
19
|
-
thread.terminate
|
|
20
|
-
tcp_server.close
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def close_all
|
|
24
|
-
apply_state :close_all
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def reset
|
|
28
|
-
apply_state :none
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def port
|
|
32
|
-
service.proxy.port
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
private
|
|
36
|
-
|
|
37
|
-
attr_reader :tcp_server, :thread, :connections, :mutex, :state
|
|
38
|
-
|
|
39
|
-
def perform_start
|
|
40
|
-
loop do
|
|
41
|
-
thread = Thread.start(tcp_server.accept) { |local_socket| connect(local_socket) }
|
|
42
|
-
connections[thread.object_id] = thread
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def connect(local_socket)
|
|
47
|
-
return local_socket.close if state?(:close_all)
|
|
48
|
-
|
|
49
|
-
remote_socket = create_remote_socket
|
|
50
|
-
return unless remote_socket
|
|
51
|
-
|
|
52
|
-
loop do
|
|
53
|
-
ready = select([local_socket, remote_socket], nil, nil)
|
|
54
|
-
|
|
55
|
-
break if write(ready, local_socket, remote_socket)
|
|
56
|
-
break if write(ready, remote_socket, local_socket)
|
|
57
|
-
end
|
|
58
|
-
rescue Errno::ECONNRESET
|
|
59
|
-
# Just ignore it.
|
|
60
|
-
ensure
|
|
61
|
-
local_socket.close
|
|
62
|
-
remote_socket&.close
|
|
63
|
-
connections.delete(Thread.current.object_id)
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def create_remote_socket
|
|
67
|
-
timeout.perform do
|
|
68
|
-
::TCPSocket.new('0.0.0.0', port)
|
|
69
|
-
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
|
|
70
|
-
sleep 0.01
|
|
71
|
-
retry
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def write(ready, socket1, socket2)
|
|
76
|
-
if ready[0].include?(socket1)
|
|
77
|
-
data = socket1.recv(1024)
|
|
78
|
-
return true if data.empty?
|
|
79
|
-
|
|
80
|
-
socket2.write(data)
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
false
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def apply_state(state)
|
|
87
|
-
mutex.synchronize { @state = state }
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def state?(state)
|
|
91
|
-
mutex.synchronize { @state == state }
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
end
|