tcp-client 0.9.1 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +5 -0
- data/README.md +11 -10
- data/gems.rb +2 -1
- data/lib/tcp-client/address.rb +31 -15
- data/lib/tcp-client/configuration.rb +132 -99
- data/lib/tcp-client/deadline.rb +1 -3
- data/lib/tcp-client/default_configuration.rb +20 -8
- data/lib/tcp-client/errors.rb +34 -14
- data/lib/tcp-client/mixin/io_with_deadline.rb +46 -16
- data/lib/tcp-client/version.rb +2 -4
- data/lib/tcp-client.rb +169 -100
- data/rakefile.rb +6 -1
- data/sample/google_ssl.rb +8 -5
- data/spec/tcp-client/address_spec.rb +15 -28
- data/spec/tcp-client/configuration_spec.rb +7 -6
- data/spec/tcp_client_spec.rb +227 -23
- data/tcp-client.gemspec +9 -11
- metadata +5 -4
@@ -9,8 +9,8 @@ RSpec.describe TCPClient::Address do
|
|
9
9
|
|
10
10
|
it 'points to the given port on localhost' do
|
11
11
|
expect(address.hostname).to eq 'localhost'
|
12
|
+
expect(address.port).to be 42
|
12
13
|
expect(address.to_s).to eq 'localhost:42'
|
13
|
-
expect(address.addrinfo.ip_port).to be 42
|
14
14
|
end
|
15
15
|
|
16
16
|
it 'uses IPv6' do
|
@@ -29,8 +29,9 @@ RSpec.describe TCPClient::Address do
|
|
29
29
|
end
|
30
30
|
|
31
31
|
it 'points to the given host and port' do
|
32
|
-
expect(address.hostname).to eq
|
33
|
-
expect(address.
|
32
|
+
expect(address.hostname).to eq 'localhost'
|
33
|
+
expect(address.port).to be 42
|
34
|
+
expect(address.to_s).to eq 'localhost:42'
|
34
35
|
end
|
35
36
|
|
36
37
|
it 'uses IPv6' do
|
@@ -46,30 +47,21 @@ RSpec.describe TCPClient::Address do
|
|
46
47
|
|
47
48
|
it 'points to the given host and port' do
|
48
49
|
expect(address.hostname).to eq 'localhost'
|
50
|
+
expect(address.port).to be 42
|
49
51
|
expect(address.to_s).to eq 'localhost:42'
|
50
|
-
expect(address.addrinfo.ip_port).to be 42
|
51
|
-
end
|
52
|
-
|
53
|
-
it 'uses IPv6' do
|
54
52
|
expect(address.addrinfo.ip?).to be true
|
55
|
-
expect(address.addrinfo.ipv6?).to be true
|
56
|
-
expect(address.addrinfo.ipv4?).to be false
|
57
53
|
end
|
54
|
+
|
58
55
|
end
|
59
56
|
|
60
57
|
context 'when only a port is provided' do
|
61
|
-
subject(:address) { TCPClient::Address.new(':
|
58
|
+
subject(:address) { TCPClient::Address.new(':42') }
|
62
59
|
|
63
60
|
it 'points to the given port on localhost' do
|
64
|
-
expect(address.hostname).to eq ''
|
65
|
-
expect(address.
|
66
|
-
expect(address.
|
67
|
-
end
|
68
|
-
|
69
|
-
it 'uses IPv4' do
|
61
|
+
expect(address.hostname).to eq 'localhost'
|
62
|
+
expect(address.port).to be 42
|
63
|
+
expect(address.to_s).to eq 'localhost:42'
|
70
64
|
expect(address.addrinfo.ip?).to be true
|
71
|
-
expect(address.addrinfo.ipv6?).to be false
|
72
|
-
expect(address.addrinfo.ipv4?).to be true
|
73
65
|
end
|
74
66
|
end
|
75
67
|
|
@@ -78,14 +70,9 @@ RSpec.describe TCPClient::Address do
|
|
78
70
|
|
79
71
|
it 'points to the given port on localhost' do
|
80
72
|
expect(address.hostname).to eq '::1'
|
73
|
+
expect(address.port).to be 42
|
81
74
|
expect(address.to_s).to eq '[::1]:42'
|
82
|
-
expect(address.addrinfo.ip_port).to be 42
|
83
|
-
end
|
84
|
-
|
85
|
-
it 'uses IPv6' do
|
86
75
|
expect(address.addrinfo.ip?).to be true
|
87
|
-
expect(address.addrinfo.ipv6?).to be true
|
88
|
-
expect(address.addrinfo.ipv4?).to be false
|
89
76
|
end
|
90
77
|
end
|
91
78
|
end
|
@@ -108,13 +95,13 @@ RSpec.describe TCPClient::Address do
|
|
108
95
|
expect(address_a).to eq address_b
|
109
96
|
end
|
110
97
|
|
111
|
-
context 'using the ==
|
98
|
+
context 'using the == operator' do
|
112
99
|
it 'compares to equal' do
|
113
100
|
expect(address_a == address_b).to be true
|
114
101
|
end
|
115
102
|
end
|
116
103
|
|
117
|
-
context 'using the ===
|
104
|
+
context 'using the === operator' do
|
118
105
|
it 'compares to equal' do
|
119
106
|
expect(address_a === address_b).to be true
|
120
107
|
end
|
@@ -129,13 +116,13 @@ RSpec.describe TCPClient::Address do
|
|
129
116
|
expect(address_a).not_to eq address_b
|
130
117
|
end
|
131
118
|
|
132
|
-
context 'using the ==
|
119
|
+
context 'using the == operator' do
|
133
120
|
it 'compares not to equal' do
|
134
121
|
expect(address_a == address_b).to be false
|
135
122
|
end
|
136
123
|
end
|
137
124
|
|
138
|
-
context 'using the ===
|
125
|
+
context 'using the === operator' do
|
139
126
|
it 'compares not to equal' do
|
140
127
|
expect(address_a === address_b).to be false
|
141
128
|
end
|
@@ -82,7 +82,7 @@ RSpec.describe TCPClient::Configuration do
|
|
82
82
|
expect(configuration.keep_alive).to be false
|
83
83
|
end
|
84
84
|
|
85
|
-
it 'allows to configure reverse address
|
85
|
+
it 'allows to configure reverse address lookup' do
|
86
86
|
expect(configuration.reverse_lookup).to be false
|
87
87
|
end
|
88
88
|
|
@@ -148,7 +148,7 @@ RSpec.describe TCPClient::Configuration do
|
|
148
148
|
end
|
149
149
|
end
|
150
150
|
|
151
|
-
context 'with invalid
|
151
|
+
context 'with invalid attribute' do
|
152
152
|
it 'raises an error' do
|
153
153
|
expect { TCPClient::Configuration.new(invalid: :value) }.to raise_error(
|
154
154
|
TCPClient::UnknownAttributeError
|
@@ -182,6 +182,7 @@ RSpec.describe TCPClient::Configuration do
|
|
182
182
|
read_timeout_error: TCPClient::ReadTimeoutError,
|
183
183
|
write_timeout: 3,
|
184
184
|
write_timeout_error: TCPClient::WriteTimeoutError,
|
185
|
+
normalize_network_errors: false,
|
185
186
|
ssl_params: {
|
186
187
|
min_version: :TLS1_2,
|
187
188
|
max_version: :TLS1_3
|
@@ -232,13 +233,13 @@ RSpec.describe TCPClient::Configuration do
|
|
232
233
|
expect(config_a).to eq config_b
|
233
234
|
end
|
234
235
|
|
235
|
-
context 'using the ==
|
236
|
+
context 'using the == operator' do
|
236
237
|
it 'compares to equal' do
|
237
238
|
expect(config_a == config_b).to be true
|
238
239
|
end
|
239
240
|
end
|
240
241
|
|
241
|
-
context 'using the ===
|
242
|
+
context 'using the === operator' do
|
242
243
|
it 'compares to equal' do
|
243
244
|
expect(config_a === config_b).to be true
|
244
245
|
end
|
@@ -253,13 +254,13 @@ RSpec.describe TCPClient::Configuration do
|
|
253
254
|
expect(config_a).not_to eq config_b
|
254
255
|
end
|
255
256
|
|
256
|
-
context 'using the ==
|
257
|
+
context 'using the == operator' do
|
257
258
|
it 'compares not to equal' do
|
258
259
|
expect(config_a == config_b).to be false
|
259
260
|
end
|
260
261
|
end
|
261
262
|
|
262
|
-
context 'using the ===
|
263
|
+
context 'using the === operator' do
|
263
264
|
it 'compares not to equal' do
|
264
265
|
expect(config_a === config_b).to be false
|
265
266
|
end
|
data/spec/tcp_client_spec.rb
CHANGED
@@ -26,7 +26,7 @@ RSpec.describe TCPClient do
|
|
26
26
|
subject(:client) { TCPClient.new }
|
27
27
|
|
28
28
|
it 'is closed' do
|
29
|
-
expect(client
|
29
|
+
expect(client).to be_closed
|
30
30
|
end
|
31
31
|
|
32
32
|
it 'has no address' do
|
@@ -64,7 +64,7 @@ RSpec.describe TCPClient do
|
|
64
64
|
before { allow_any_instance_of(::Socket).to receive(:connect) }
|
65
65
|
|
66
66
|
it 'is not closed' do
|
67
|
-
expect(client
|
67
|
+
expect(client).not_to be_closed
|
68
68
|
end
|
69
69
|
|
70
70
|
it 'has an address' do
|
@@ -115,7 +115,7 @@ RSpec.describe TCPClient do
|
|
115
115
|
end
|
116
116
|
|
117
117
|
it 'is closed' do
|
118
|
-
expect(client
|
118
|
+
expect(client).to be_closed
|
119
119
|
end
|
120
120
|
|
121
121
|
it 'has an address' do
|
@@ -157,6 +157,8 @@ RSpec.describe TCPClient do
|
|
157
157
|
|
158
158
|
context 'when not using SSL' do
|
159
159
|
describe '#connect' do
|
160
|
+
subject(:client) { TCPClient.new }
|
161
|
+
|
160
162
|
it 'configures the socket' do
|
161
163
|
expect_any_instance_of(::Socket).to receive(:sync=).once.with(true)
|
162
164
|
expect_any_instance_of(::Socket).to receive(:setsockopt)
|
@@ -169,7 +171,7 @@ RSpec.describe TCPClient do
|
|
169
171
|
.once
|
170
172
|
.with(false)
|
171
173
|
expect_any_instance_of(::Socket).to receive(:connect)
|
172
|
-
|
174
|
+
client.connect('localhost:1234', configuration)
|
173
175
|
end
|
174
176
|
|
175
177
|
context 'when a timeout is specified' do
|
@@ -177,7 +179,26 @@ RSpec.describe TCPClient do
|
|
177
179
|
expect_any_instance_of(::Socket).to receive(:connect_nonblock)
|
178
180
|
.once
|
179
181
|
.with(kind_of(String), exception: false)
|
180
|
-
|
182
|
+
client.connect('localhost:1234', configuration, timeout: 10)
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'is returns itself' do
|
186
|
+
allow_any_instance_of(::Socket).to receive(:connect_nonblock).with(
|
187
|
+
kind_of(String),
|
188
|
+
exception: false
|
189
|
+
)
|
190
|
+
result = client.connect('localhost:1234', configuration, timeout: 10)
|
191
|
+
|
192
|
+
expect(client).to be client
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'is not closed' do
|
196
|
+
allow_any_instance_of(::Socket).to receive(:connect_nonblock).with(
|
197
|
+
kind_of(String),
|
198
|
+
exception: false
|
199
|
+
)
|
200
|
+
client.connect('localhost:1234', configuration, timeout: 10)
|
201
|
+
expect(client).not_to be_closed
|
181
202
|
end
|
182
203
|
|
183
204
|
context 'when the connection can not be established in time' do
|
@@ -188,25 +209,29 @@ RSpec.describe TCPClient do
|
|
188
209
|
|
189
210
|
it 'raises an exception' do
|
190
211
|
expect do
|
191
|
-
|
192
|
-
'localhost:1234',
|
193
|
-
configuration,
|
194
|
-
timeout: 0.25
|
195
|
-
)
|
212
|
+
client.connect('localhost:1234', configuration, timeout: 0.1)
|
196
213
|
end.to raise_error(TCPClient::ConnectTimeoutError)
|
197
214
|
end
|
198
215
|
|
199
216
|
it 'allows to raise a custom exception' do
|
200
217
|
exception = Class.new(StandardError)
|
201
218
|
expect do
|
202
|
-
|
219
|
+
client.connect(
|
203
220
|
'localhost:1234',
|
204
221
|
configuration,
|
205
|
-
timeout: 0.
|
222
|
+
timeout: 0.1,
|
206
223
|
exception: exception
|
207
224
|
)
|
208
225
|
end.to raise_error(exception)
|
209
226
|
end
|
227
|
+
|
228
|
+
it 'is still closed' do
|
229
|
+
begin
|
230
|
+
client.connect('localhost:1234', configuration, timeout: 0.1)
|
231
|
+
rescue TCPClient::ConnectTimeoutError
|
232
|
+
end
|
233
|
+
expect(client).to be_closed
|
234
|
+
end
|
210
235
|
end
|
211
236
|
end
|
212
237
|
|
@@ -226,7 +251,7 @@ RSpec.describe TCPClient do
|
|
226
251
|
end
|
227
252
|
|
228
253
|
SOCKET_ERRORS.each do |error_class|
|
229
|
-
it "raises
|
254
|
+
it "raises TCPClient::NetworkError when a #{error_class} appeared" do
|
230
255
|
allow_any_instance_of(::Socket).to receive(:connect) {
|
231
256
|
raise error_class
|
232
257
|
}
|
@@ -270,18 +295,61 @@ RSpec.describe TCPClient do
|
|
270
295
|
expect(client.read(timeout: 10)).to be data
|
271
296
|
end
|
272
297
|
|
298
|
+
context 'when socket closed before any data can be read' do
|
299
|
+
it 'returns empty buffer' do
|
300
|
+
expect_any_instance_of(::Socket).to receive(:read_nonblock)
|
301
|
+
.and_return(nil)
|
302
|
+
expect(client.read(timeout: 10)).to be_empty
|
303
|
+
end
|
304
|
+
|
305
|
+
it 'is closed' do
|
306
|
+
expect_any_instance_of(::Socket).to receive(:read_nonblock)
|
307
|
+
.and_return(nil)
|
308
|
+
|
309
|
+
client.read(timeout: 10)
|
310
|
+
expect(client).to be_closed
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
273
314
|
context 'when data can not be fetched in a single chunk' do
|
274
315
|
it 'reads chunk by chunk' do
|
275
316
|
expect_any_instance_of(::Socket).to receive(:read_nonblock)
|
276
317
|
.once
|
277
|
-
.with(
|
318
|
+
.with(instance_of(Integer), exception: false)
|
278
319
|
.and_return(data)
|
279
320
|
expect_any_instance_of(::Socket).to receive(:read_nonblock)
|
280
321
|
.once
|
281
|
-
.with(
|
322
|
+
.with(instance_of(Integer), exception: false)
|
282
323
|
.and_return(data)
|
283
324
|
expect(client.read(data_size * 2, timeout: 10)).to eq data * 2
|
284
325
|
end
|
326
|
+
|
327
|
+
context 'when socket closed before enough data is avail' do
|
328
|
+
it 'returns available data only' do
|
329
|
+
expect_any_instance_of(::Socket).to receive(:read_nonblock)
|
330
|
+
.once
|
331
|
+
.with(instance_of(Integer), exception: false)
|
332
|
+
.and_return(data)
|
333
|
+
expect_any_instance_of(::Socket).to receive(:read_nonblock)
|
334
|
+
.once
|
335
|
+
.with(instance_of(Integer), exception: false)
|
336
|
+
.and_return(nil)
|
337
|
+
expect(client.read(data_size * 2, timeout: 10)).to eq data
|
338
|
+
end
|
339
|
+
|
340
|
+
it 'is closed' do
|
341
|
+
expect_any_instance_of(::Socket).to receive(:read_nonblock)
|
342
|
+
.once
|
343
|
+
.with(instance_of(Integer), exception: false)
|
344
|
+
.and_return(data)
|
345
|
+
expect_any_instance_of(::Socket).to receive(:read_nonblock)
|
346
|
+
.once
|
347
|
+
.with(instance_of(Integer), exception: false)
|
348
|
+
.and_return(nil)
|
349
|
+
client.read(data_size * 2, timeout: 10)
|
350
|
+
expect(client).to be_closed
|
351
|
+
end
|
352
|
+
end
|
285
353
|
end
|
286
354
|
|
287
355
|
context 'when the data can not be read in time' do
|
@@ -329,6 +397,146 @@ RSpec.describe TCPClient do
|
|
329
397
|
end
|
330
398
|
end
|
331
399
|
|
400
|
+
describe '#readline' do
|
401
|
+
before { allow_any_instance_of(::Socket).to receive(:connect) }
|
402
|
+
|
403
|
+
it 'reads from socket' do
|
404
|
+
expect_any_instance_of(::Socket).to receive(:readline)
|
405
|
+
.once
|
406
|
+
.with($/, chomp: false)
|
407
|
+
.and_return("Hello World\n")
|
408
|
+
expect(client.readline).to eq "Hello World\n"
|
409
|
+
end
|
410
|
+
|
411
|
+
context 'when a separator is specified' do
|
412
|
+
it 'forwards the separator' do
|
413
|
+
expect_any_instance_of(::Socket).to receive(:readline)
|
414
|
+
.once
|
415
|
+
.with('/', chomp: false)
|
416
|
+
.and_return('Hello/')
|
417
|
+
expect(client.readline('/')).to eq 'Hello/'
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
context 'when chomp is true' do
|
422
|
+
it 'forwards the flag' do
|
423
|
+
expect_any_instance_of(::Socket).to receive(:readline)
|
424
|
+
.once
|
425
|
+
.with($/, chomp: true)
|
426
|
+
.and_return('Hello World')
|
427
|
+
expect(client.readline(chomp: true)).to eq 'Hello World'
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
context 'when a timeout is specified' do
|
432
|
+
it 'checks the time' do
|
433
|
+
expect_any_instance_of(::Socket).to receive(:read_nonblock)
|
434
|
+
.and_return("Hello World\nHello World\n")
|
435
|
+
expect(client.readline(timeout: 10)).to eq "Hello World\n"
|
436
|
+
end
|
437
|
+
|
438
|
+
it 'optional chomps the line' do
|
439
|
+
expect_any_instance_of(::Socket).to receive(:read_nonblock)
|
440
|
+
.and_return("Hello World\nHello World\n")
|
441
|
+
expect(client.readline(chomp: true, timeout: 10)).to eq 'Hello World'
|
442
|
+
end
|
443
|
+
|
444
|
+
it 'uses the given separator' do
|
445
|
+
expect_any_instance_of(::Socket).to receive(:read_nonblock)
|
446
|
+
.and_return("Hello/World\n")
|
447
|
+
expect(client.readline('/', timeout: 10)).to eq 'Hello/'
|
448
|
+
end
|
449
|
+
|
450
|
+
context 'when data can not be fetched in a single chunk' do
|
451
|
+
it 'reads chunk by chunk' do
|
452
|
+
expect_any_instance_of(::Socket).to receive(:read_nonblock)
|
453
|
+
.once
|
454
|
+
.with(instance_of(Integer), exception: false)
|
455
|
+
.and_return('Hello ')
|
456
|
+
expect_any_instance_of(::Socket).to receive(:read_nonblock)
|
457
|
+
.once
|
458
|
+
.with(instance_of(Integer), exception: false)
|
459
|
+
.and_return('World')
|
460
|
+
expect_any_instance_of(::Socket).to receive(:read_nonblock)
|
461
|
+
.once
|
462
|
+
.with(instance_of(Integer), exception: false)
|
463
|
+
.and_return("\nAnd so...")
|
464
|
+
expect(client.readline(timeout: 10)).to eq "Hello World\n"
|
465
|
+
end
|
466
|
+
|
467
|
+
context 'when socket closed before enough data is avail' do
|
468
|
+
it 'returns available data only' do
|
469
|
+
expect_any_instance_of(::Socket).to receive(:read_nonblock)
|
470
|
+
.once
|
471
|
+
.with(instance_of(Integer), exception: false)
|
472
|
+
.and_return('Hello ')
|
473
|
+
expect_any_instance_of(::Socket).to receive(:read_nonblock)
|
474
|
+
.once
|
475
|
+
.with(instance_of(Integer), exception: false)
|
476
|
+
.and_return(nil)
|
477
|
+
expect(client.readline(timeout: 10)).to eq "Hello "
|
478
|
+
end
|
479
|
+
|
480
|
+
it 'is closed' do
|
481
|
+
expect_any_instance_of(::Socket).to receive(:read_nonblock)
|
482
|
+
.once
|
483
|
+
.with(instance_of(Integer), exception: false)
|
484
|
+
.and_return('Hello ')
|
485
|
+
expect_any_instance_of(::Socket).to receive(:read_nonblock)
|
486
|
+
.once
|
487
|
+
.with(instance_of(Integer), exception: false)
|
488
|
+
.and_return(nil)
|
489
|
+
client.readline(timeout: 10)
|
490
|
+
expect(client).to be_closed
|
491
|
+
end
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
context 'when the data can not be read in time' do
|
496
|
+
before do
|
497
|
+
allow_any_instance_of(::Socket).to receive(:read_nonblock)
|
498
|
+
.and_return(:wait_readable)
|
499
|
+
end
|
500
|
+
it 'raises an exception' do
|
501
|
+
expect { client.readline(timeout: 0.25) }.to raise_error(
|
502
|
+
TCPClient::ReadTimeoutError
|
503
|
+
)
|
504
|
+
end
|
505
|
+
|
506
|
+
it 'allows to raise a custom exception' do
|
507
|
+
exception = Class.new(StandardError)
|
508
|
+
expect do
|
509
|
+
client.read(timeout: 0.25, exception: exception)
|
510
|
+
end.to raise_error(exception)
|
511
|
+
end
|
512
|
+
end
|
513
|
+
end
|
514
|
+
|
515
|
+
context 'when a SocketError appears' do
|
516
|
+
it 'does not handle it' do
|
517
|
+
allow_any_instance_of(::Socket).to receive(:read) {
|
518
|
+
raise SocketError
|
519
|
+
}
|
520
|
+
expect { client.read(10) }.to raise_error(SocketError)
|
521
|
+
end
|
522
|
+
|
523
|
+
context 'when normalize_network_errors is configured' do
|
524
|
+
let(:configuration) do
|
525
|
+
TCPClient::Configuration.create(normalize_network_errors: true)
|
526
|
+
end
|
527
|
+
|
528
|
+
SOCKET_ERRORS.each do |error_class|
|
529
|
+
it "raises a TCPClient::NetworkError when a #{error_class} appeared" do
|
530
|
+
allow_any_instance_of(::Socket).to receive(:read) {
|
531
|
+
raise error_class
|
532
|
+
}
|
533
|
+
expect { client.read(12) }.to raise_error(TCPClient::NetworkError)
|
534
|
+
end
|
535
|
+
end
|
536
|
+
end
|
537
|
+
end
|
538
|
+
end
|
539
|
+
|
332
540
|
describe '#write' do
|
333
541
|
let(:data) { 'some bytes' }
|
334
542
|
let(:data_size) { data.bytesize }
|
@@ -463,20 +671,16 @@ RSpec.describe TCPClient do
|
|
463
671
|
.with(kind_of(String), exception: false)
|
464
672
|
expect_any_instance_of(::Socket).to receive(:read_nonblock)
|
465
673
|
.once
|
466
|
-
.with(
|
467
|
-
.and_return('
|
674
|
+
.with(instance_of(Integer), exception: false)
|
675
|
+
.and_return('123456789012abcdefgAB')
|
468
676
|
expect_any_instance_of(::Socket).to receive(:write_nonblock)
|
469
677
|
.once
|
470
678
|
.with('123456', exception: false)
|
471
679
|
.and_return(6)
|
472
680
|
expect_any_instance_of(::Socket).to receive(:read_nonblock)
|
473
681
|
.once
|
474
|
-
.with(
|
475
|
-
.and_return('
|
476
|
-
expect_any_instance_of(::Socket).to receive(:read_nonblock)
|
477
|
-
.once
|
478
|
-
.with(7, exception: false)
|
479
|
-
.and_return('ABCDEFG')
|
682
|
+
.with(instance_of(Integer), exception: false)
|
683
|
+
.and_return('CDEFG')
|
480
684
|
expect_any_instance_of(::Socket).to receive(:write_nonblock)
|
481
685
|
.once
|
482
686
|
.with('abc', exception: false)
|
data/tcp-client.gemspec
CHANGED
@@ -5,12 +5,11 @@ require_relative './lib/tcp-client/version'
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = 'tcp-client'
|
7
7
|
spec.version = TCPClient::VERSION
|
8
|
-
spec.author = 'Mike Blumtritt'
|
9
|
-
|
10
8
|
spec.required_ruby_version = '>= 2.7.0'
|
11
9
|
|
10
|
+
spec.author = 'Mike Blumtritt'
|
12
11
|
spec.summary = 'A TCP client implementation with working timeout support.'
|
13
|
-
spec.description = <<~
|
12
|
+
spec.description = <<~description
|
14
13
|
This Gem implements a TCP client with (optional) SSL support.
|
15
14
|
It is an easy to use, versatile configurable client that can correctly
|
16
15
|
handle time limits.
|
@@ -18,15 +17,15 @@ Gem::Specification.new do |spec|
|
|
18
17
|
predefined/configurable time limits for each method
|
19
18
|
(`connect`, `read`, `write`). Deadlines for a sequence of read/write
|
20
19
|
actions can also be monitored.
|
21
|
-
|
20
|
+
description
|
21
|
+
|
22
22
|
spec.homepage = 'https://github.com/mblumtritt/tcp-client'
|
23
23
|
spec.license = 'BSD-3-Clause'
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
'https://rubydoc.info/github/mblumtritt/tcp-client'
|
28
|
-
|
29
|
-
'https://github.com/mblumtritt/tcp-client/issues'
|
24
|
+
spec.metadata.merge!(
|
25
|
+
'source_code_uri' => 'https://github.com/mblumtritt/tcp-client',
|
26
|
+
'bug_tracker_uri' => 'https://github.com/mblumtritt/tcp-client/issues',
|
27
|
+
'documentation_uri' => 'https://rubydoc.info/github/mblumtritt/tcp-client'
|
28
|
+
)
|
30
29
|
|
31
30
|
spec.add_development_dependency 'bundler'
|
32
31
|
spec.add_development_dependency 'rake'
|
@@ -36,6 +35,5 @@ Gem::Specification.new do |spec|
|
|
36
35
|
all_files = Dir.chdir(__dir__) { `git ls-files -z`.split(0.chr) }
|
37
36
|
spec.test_files = all_files.grep(%r{^spec/})
|
38
37
|
spec.files = all_files - spec.test_files
|
39
|
-
|
40
38
|
spec.extra_rdoc_files = %w[README.md LICENSE]
|
41
39
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tcp-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Blumtritt
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-01-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -82,6 +82,7 @@ extra_rdoc_files:
|
|
82
82
|
- LICENSE
|
83
83
|
files:
|
84
84
|
- ".gitignore"
|
85
|
+
- ".yardopts"
|
85
86
|
- LICENSE
|
86
87
|
- README.md
|
87
88
|
- gems.rb
|
@@ -111,8 +112,8 @@ licenses:
|
|
111
112
|
- BSD-3-Clause
|
112
113
|
metadata:
|
113
114
|
source_code_uri: https://github.com/mblumtritt/tcp-client
|
114
|
-
documentation_uri: https://rubydoc.info/github/mblumtritt/tcp-client
|
115
115
|
bug_tracker_uri: https://github.com/mblumtritt/tcp-client/issues
|
116
|
+
documentation_uri: https://rubydoc.info/github/mblumtritt/tcp-client
|
116
117
|
post_install_message:
|
117
118
|
rdoc_options: []
|
118
119
|
require_paths:
|
@@ -128,7 +129,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
128
129
|
- !ruby/object:Gem::Version
|
129
130
|
version: '0'
|
130
131
|
requirements: []
|
131
|
-
rubygems_version: 3.
|
132
|
+
rubygems_version: 3.3.3
|
132
133
|
signing_key:
|
133
134
|
specification_version: 4
|
134
135
|
summary: A TCP client implementation with working timeout support.
|