tcp-client 0.7.0 → 0.8.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.
@@ -0,0 +1,596 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helper'
4
+
5
+ SOCKET_ERRORS = [
6
+ Errno::EADDRNOTAVAIL,
7
+ Errno::ECONNABORTED,
8
+ Errno::ECONNREFUSED,
9
+ Errno::ECONNRESET,
10
+ Errno::EHOSTUNREACH,
11
+ Errno::EINVAL,
12
+ Errno::ENETUNREACH,
13
+ Errno::EPIPE,
14
+ IOError,
15
+ SocketError,
16
+ ::OpenSSL::SSL::SSLError
17
+ ].freeze
18
+
19
+ RSpec.describe TCPClient do
20
+ subject(:client) { TCPClient.new.connect('localhost:1234', configuration) }
21
+ let(:configuration) do
22
+ TCPClient::Configuration.create(buffered: false, reverse_lookup: false)
23
+ end
24
+
25
+ describe 'a new instance' do
26
+ subject(:client) { TCPClient.new }
27
+
28
+ it 'is closed' do
29
+ expect(client.closed?).to be true
30
+ end
31
+
32
+ it 'has no address' do
33
+ expect(client.address).to be_nil
34
+ end
35
+
36
+ it 'returns no address string' do
37
+ expect(client.to_s).to eq ''
38
+ end
39
+
40
+ it 'has no configuration' do
41
+ expect(client.configuration).to be_nil
42
+ end
43
+
44
+ it 'failes when read is called' do
45
+ expect { client.read(42) }.to raise_error(TCPClient::NotConnectedError)
46
+ end
47
+
48
+ it 'failes when write is called' do
49
+ expect { client.write('?!') }.to raise_error(TCPClient::NotConnectedError)
50
+ end
51
+
52
+ it 'can be closed' do
53
+ expect_any_instance_of(::Socket).not_to receive(:close)
54
+ expect(client.close).to be client
55
+ end
56
+
57
+ it 'can be flushed' do
58
+ expect_any_instance_of(::Socket).not_to receive(:flush)
59
+ expect(client.flush).to be client
60
+ end
61
+ end
62
+
63
+ describe 'a connected instance' do
64
+ before { allow_any_instance_of(::Socket).to receive(:connect) }
65
+
66
+ it 'is not closed' do
67
+ expect(client.closed?).to be false
68
+ end
69
+
70
+ it 'has an address' do
71
+ expect(client.address).to be_a TCPClient::Address
72
+ end
73
+
74
+ it 'returns an address string' do
75
+ expect(client.to_s).to eq 'localhost:1234'
76
+ end
77
+
78
+ it 'uses the given configuration' do
79
+ expect(client.configuration).to be configuration
80
+ end
81
+
82
+ it 'allows to read data' do
83
+ result = '-' * 42
84
+ allow_any_instance_of(::Socket).to receive(:read)
85
+ .with(42)
86
+ .and_return(result)
87
+ expect(client.read(42)).to be result
88
+ end
89
+
90
+ it 'allows to write data' do
91
+ allow_any_instance_of(::Socket).to receive(:write)
92
+ .with('!' * 21)
93
+ .and_return(21)
94
+ expect(client.write('!' * 21)).to be 21
95
+ end
96
+
97
+ it 'can be closed' do
98
+ expect_any_instance_of(::Socket).to receive(:close)
99
+ expect(client.close).to be client
100
+ end
101
+
102
+ it 'can be flushed' do
103
+ expect_any_instance_of(::Socket).to receive(:flush)
104
+ expect(client.flush).to be client
105
+ end
106
+ end
107
+
108
+ describe 'an instance after #connect failed' do
109
+ subject(:client) do
110
+ TCPClient.new.tap do |instance|
111
+ instance.connect('', configuration)
112
+ rescue StandardError
113
+ Errno::EADDRNOTAVAIL
114
+ end
115
+ end
116
+
117
+ it 'is closed' do
118
+ expect(client.closed?).to be true
119
+ end
120
+
121
+ it 'has an address' do
122
+ expect(client.address).to be_a TCPClient::Address
123
+ end
124
+
125
+ it 'returns an address string' do
126
+ expect(client.to_s).to eq 'localhost:0'
127
+ end
128
+
129
+ it 'uses the given configuration' do
130
+ expect(client.configuration).to be configuration
131
+ end
132
+
133
+ it 'failes when read is called' do
134
+ expect { client.read(42) }.to raise_error(TCPClient::NotConnectedError)
135
+ end
136
+
137
+ it 'failes when write is called' do
138
+ expect { client.write('?!') }.to raise_error(TCPClient::NotConnectedError)
139
+ end
140
+
141
+ it 'can be closed' do
142
+ expect_any_instance_of(::Socket).not_to receive(:close)
143
+ expect(client.close).to be client
144
+ end
145
+
146
+ it 'can be flushed' do
147
+ expect_any_instance_of(::Socket).not_to receive(:flush)
148
+ expect(client.flush).to be client
149
+ end
150
+ end
151
+
152
+ xdescribe '.open' do
153
+ end
154
+
155
+ xdescribe '.with_deadline' do
156
+ end
157
+
158
+ context 'when not using SSL' do
159
+ describe '#connect' do
160
+ it 'configures the socket' do
161
+ expect_any_instance_of(::Socket).to receive(:sync=).once.with(true)
162
+ expect_any_instance_of(::Socket).to receive(:setsockopt)
163
+ .once
164
+ .with(:TCP, :NODELAY, 1)
165
+ expect_any_instance_of(::Socket).to receive(:setsockopt)
166
+ .once
167
+ .with(:SOCKET, :KEEPALIVE, 1)
168
+ expect_any_instance_of(::Socket).to receive(:do_not_reverse_lookup=)
169
+ .once
170
+ .with(false)
171
+ expect_any_instance_of(::Socket).to receive(:connect)
172
+ TCPClient.new.connect('localhost:1234', configuration)
173
+ end
174
+
175
+ context 'when a timeout is specified' do
176
+ it 'checks the time' do
177
+ expect_any_instance_of(::Socket).to receive(:connect_nonblock)
178
+ .once
179
+ .with(kind_of(String), exception: false)
180
+ TCPClient.new.connect('localhost:1234', configuration, timeout: 10)
181
+ end
182
+
183
+ context 'when the connection can not be established in time' do
184
+ before do
185
+ allow_any_instance_of(::Socket).to receive(:connect_nonblock)
186
+ .and_return(:wait_writable)
187
+ end
188
+
189
+ it 'raises an exception' do
190
+ expect do
191
+ TCPClient.new.connect(
192
+ 'localhost:1234',
193
+ configuration,
194
+ timeout: 0.25
195
+ )
196
+ end.to raise_error(TCPClient::ConnectTimeoutError)
197
+ end
198
+
199
+ it 'allows to raise a custom exception' do
200
+ exception = Class.new(StandardError)
201
+ expect do
202
+ TCPClient.new.connect(
203
+ 'localhost:1234',
204
+ configuration,
205
+ timeout: 0.25,
206
+ exception: exception
207
+ )
208
+ end.to raise_error(exception)
209
+ end
210
+ end
211
+ end
212
+
213
+ context 'when a SocketError appears' do
214
+ it 'does not handle it' do
215
+ allow_any_instance_of(::Socket).to receive(:connect) {
216
+ raise SocketError
217
+ }
218
+ expect do
219
+ TCPClient.new.connect('localhost:1234', configuration)
220
+ end.to raise_error(SocketError)
221
+ end
222
+
223
+ context 'when normalize_network_errors is configured' do
224
+ let(:configuration) do
225
+ TCPClient::Configuration.create(normalize_network_errors: true)
226
+ end
227
+
228
+ SOCKET_ERRORS.each do |error_class|
229
+ it "raises a TCPClient::NetworkError when a #{error_class} appeared" do
230
+ allow_any_instance_of(::Socket).to receive(:connect) {
231
+ raise error_class
232
+ }
233
+ expect do
234
+ TCPClient.new.connect('localhost:1234', configuration)
235
+ end.to raise_error(TCPClient::NetworkError)
236
+ end
237
+ end
238
+ end
239
+ end
240
+ end
241
+
242
+ describe '#read' do
243
+ let(:data) { 'some bytes' }
244
+ let(:data_size) { data.bytesize }
245
+
246
+ before { allow_any_instance_of(::Socket).to receive(:connect) }
247
+
248
+ it 'reads from socket' do
249
+ expect_any_instance_of(::Socket).to receive(:read)
250
+ .once
251
+ .with(nil)
252
+ .and_return(data)
253
+ expect(client.read).to be data
254
+ end
255
+
256
+ context 'when a number of bytes is specified' do
257
+ it 'reads the requested number of bytes' do
258
+ expect_any_instance_of(::Socket).to receive(:read)
259
+ .once
260
+ .with(data_size)
261
+ .and_return(data)
262
+ expect(client.read(data_size)).to be data
263
+ end
264
+ end
265
+
266
+ context 'when a timeout is specified' do
267
+ it 'checks the time' do
268
+ expect_any_instance_of(::Socket).to receive(:read_nonblock)
269
+ .and_return(data)
270
+ expect(client.read(timeout: 10)).to be data
271
+ end
272
+
273
+ context 'when data can not be fetched in a single chunk' do
274
+ it 'reads chunk by chunk' do
275
+ expect_any_instance_of(::Socket).to receive(:read_nonblock)
276
+ .once
277
+ .with(data_size * 2, exception: false)
278
+ .and_return(data)
279
+ expect_any_instance_of(::Socket).to receive(:read_nonblock)
280
+ .once
281
+ .with(data_size, exception: false)
282
+ .and_return(data)
283
+ expect(client.read(data_size * 2, timeout: 10)).to eq data * 2
284
+ end
285
+ end
286
+
287
+ context 'when the data can not be read in time' do
288
+ before do
289
+ allow_any_instance_of(::Socket).to receive(:read_nonblock)
290
+ .and_return(:wait_readable)
291
+ end
292
+ it 'raises an exception' do
293
+ expect { client.read(timeout: 0.25) }.to raise_error(
294
+ TCPClient::ReadTimeoutError
295
+ )
296
+ end
297
+
298
+ it 'allows to raise a custom exception' do
299
+ exception = Class.new(StandardError)
300
+ expect do
301
+ client.read(timeout: 0.25, exception: exception)
302
+ end.to raise_error(exception)
303
+ end
304
+ end
305
+ end
306
+
307
+ context 'when a SocketError appears' do
308
+ it 'does not handle it' do
309
+ allow_any_instance_of(::Socket).to receive(:read) {
310
+ raise SocketError
311
+ }
312
+ expect { client.read(10) }.to raise_error(SocketError)
313
+ end
314
+
315
+ context 'when normalize_network_errors is configured' do
316
+ let(:configuration) do
317
+ TCPClient::Configuration.create(normalize_network_errors: true)
318
+ end
319
+
320
+ SOCKET_ERRORS.each do |error_class|
321
+ it "raises a TCPClient::NetworkError when a #{error_class} appeared" do
322
+ allow_any_instance_of(::Socket).to receive(:read) {
323
+ raise error_class
324
+ }
325
+ expect { client.read(12) }.to raise_error(TCPClient::NetworkError)
326
+ end
327
+ end
328
+ end
329
+ end
330
+ end
331
+
332
+ describe '#write' do
333
+ let(:data) { 'some bytes' }
334
+ let(:data_size) { data.bytesize }
335
+
336
+ before { allow_any_instance_of(::Socket).to receive(:connect) }
337
+
338
+ it 'writes to the socket' do
339
+ expect_any_instance_of(::Socket).to receive(:write)
340
+ .once
341
+ .with(data)
342
+ .and_return(data_size)
343
+ expect(client.write(data)).to be data_size
344
+ end
345
+
346
+ context 'when multiple data chunks are given' do
347
+ it 'writes each chunk' do
348
+ expect_any_instance_of(::Socket).to receive(:write)
349
+ .once
350
+ .with(data, data)
351
+ .and_return(data_size * 2)
352
+ expect(client.write(data, data)).to be data_size * 2
353
+ end
354
+ end
355
+
356
+ context 'when a timeout is specified' do
357
+ it 'checks the time' do
358
+ expect_any_instance_of(::Socket).to receive(:write_nonblock)
359
+ .and_return(data_size)
360
+ expect(client.write(data, timeout: 10)).to be data_size
361
+ end
362
+
363
+ context 'when data can not be written in a single chunk' do
364
+ let(:chunk1) { '1234567890' }
365
+ let(:chunk2) { '12345' }
366
+ let(:data1) { chunk1 + chunk2 }
367
+ let(:chunk3) { 'abcdefghijklm' }
368
+ let(:chunk4) { 'ABCDE' }
369
+ let(:data2) { chunk3 + chunk4 }
370
+
371
+ it 'writes chunk by chunk and part by part' do
372
+ expect_any_instance_of(::Socket).to receive(:write_nonblock)
373
+ .once
374
+ .with(data1, exception: false)
375
+ .and_return(chunk1.bytesize)
376
+ expect_any_instance_of(::Socket).to receive(:write_nonblock)
377
+ .once
378
+ .with(chunk2, exception: false)
379
+ .and_return(chunk2.bytesize)
380
+ expect_any_instance_of(::Socket).to receive(:write_nonblock)
381
+ .once
382
+ .with(data2, exception: false)
383
+ .and_return(chunk3.bytesize)
384
+ expect_any_instance_of(::Socket).to receive(:write_nonblock)
385
+ .once
386
+ .with(chunk4, exception: false)
387
+ .and_return(chunk4.bytesize)
388
+
389
+ expect(client.write(data1, data2, timeout: 10)).to be(
390
+ data1.bytesize + data2.bytesize
391
+ )
392
+ end
393
+ end
394
+
395
+ context 'when the data can not be written in time' do
396
+ before do
397
+ allow_any_instance_of(::Socket).to receive(:write_nonblock)
398
+ .and_return(:wait_writable)
399
+ end
400
+ it 'raises an exception' do
401
+ expect { client.write(data, timeout: 0.25) }.to raise_error(
402
+ TCPClient::WriteTimeoutError
403
+ )
404
+ end
405
+
406
+ it 'allows to raise a custom exception' do
407
+ exception = Class.new(StandardError)
408
+ expect do
409
+ client.write(data, timeout: 0.25, exception: exception)
410
+ end.to raise_error(exception)
411
+ end
412
+ end
413
+ end
414
+
415
+ context 'when a SocketError appears' do
416
+ before { allow_any_instance_of(::Socket).to receive(:connect) }
417
+
418
+ it 'does not handle it' do
419
+ allow_any_instance_of(::Socket).to receive(:write) {
420
+ raise SocketError
421
+ }
422
+ expect { client.write('some data') }.to raise_error(SocketError)
423
+ end
424
+
425
+ context 'when normalize_network_errors is configured' do
426
+ let(:configuration) do
427
+ TCPClient::Configuration.create(normalize_network_errors: true)
428
+ end
429
+
430
+ SOCKET_ERRORS.each do |error_class|
431
+ it "raises a TCPClient::NetworkError when a #{error_class} appeared" do
432
+ allow_any_instance_of(::Socket).to receive(:write) {
433
+ raise error_class
434
+ }
435
+ expect { client.write('some data') }.to raise_error(
436
+ TCPClient::NetworkError
437
+ )
438
+ end
439
+ end
440
+ end
441
+ end
442
+ end
443
+
444
+ describe '#with_deadline' do
445
+ subject(:client) { TCPClient.new }
446
+ let(:configuration) { TCPClient::Configuration.create(timeout: 60) }
447
+
448
+ before do
449
+ allow_any_instance_of(::Socket).to receive(:connect_nonblock)
450
+ allow_any_instance_of(::Socket).to receive(:read_nonblock) do |_, size|
451
+ 'r' * size
452
+ end
453
+ allow_any_instance_of(::Socket).to receive(
454
+ :write_nonblock
455
+ ) do |_, data|
456
+ data.bytesize
457
+ end
458
+ end
459
+
460
+ it 'allows to use a timeout value for all actions in the given block' do
461
+ expect_any_instance_of(::Socket).to receive(:connect_nonblock)
462
+ .once
463
+ .with(kind_of(String), exception: false)
464
+ expect_any_instance_of(::Socket).to receive(:read_nonblock)
465
+ .once
466
+ .with(12, exception: false)
467
+ .and_return('123456789012')
468
+ expect_any_instance_of(::Socket).to receive(:write_nonblock)
469
+ .once
470
+ .with('123456', exception: false)
471
+ .and_return(6)
472
+ expect_any_instance_of(::Socket).to receive(:read_nonblock)
473
+ .once
474
+ .with(7, exception: false)
475
+ .and_return('abcdefg')
476
+ expect_any_instance_of(::Socket).to receive(:read_nonblock)
477
+ .once
478
+ .with(7, exception: false)
479
+ .and_return('ABCDEFG')
480
+ expect_any_instance_of(::Socket).to receive(:write_nonblock)
481
+ .once
482
+ .with('abc', exception: false)
483
+ .and_return(3)
484
+ expect_any_instance_of(::Socket).to receive(:write_nonblock)
485
+ .once
486
+ .with('ABC', exception: false)
487
+ .and_return(3)
488
+ expect_any_instance_of(::Socket).to receive(:write_nonblock)
489
+ .once
490
+ .with('ABCDEF', exception: false)
491
+ .and_return(6)
492
+
493
+ client.with_deadline(10) do
494
+ expect(client.connect('localhost:1234', configuration)).to be client
495
+ expect(client.read(12)).to eq '123456789012'
496
+ expect(client.write('123456')).to be 6
497
+ expect(client.read(7)).to eq 'abcdefg'
498
+ expect(client.read(7)).to eq 'ABCDEFG'
499
+ expect(client.write('abc')).to be 3
500
+ expect(client.write('ABC', 'ABCDEF')).to be 9
501
+ end
502
+ end
503
+
504
+ context 'when called without a block' do
505
+ it 'raises an exception' do
506
+ expect { client.with_deadline(0.25) }.to raise_error(ArgumentError)
507
+ end
508
+ end
509
+
510
+ context 'when #connect fails' do
511
+ it 'raises an exception' do
512
+ expect_any_instance_of(::Socket).to receive(:connect_nonblock)
513
+ .and_return(:wait_writable)
514
+ expect do
515
+ client.with_deadline(0.25) do
516
+ client.connect('localhost:1234', configuration)
517
+ client.read(12)
518
+ client.write('Hello World!')
519
+ end
520
+ end.to raise_error(TCPClient::ConnectTimeoutError)
521
+ end
522
+ end
523
+
524
+ context 'when #read fails' do
525
+ it 'raises an exception' do
526
+ expect_any_instance_of(::Socket).to receive(:read_nonblock)
527
+ .and_return(:wait_readable)
528
+ expect do
529
+ client.with_deadline(0.25) do
530
+ client.connect('localhost:1234', configuration)
531
+ client.write('Hello World!')
532
+ client.read(12)
533
+ end
534
+ end.to raise_error(TCPClient::ReadTimeoutError)
535
+ end
536
+ end
537
+
538
+ context 'when #write fails' do
539
+ it 'raises an exception' do
540
+ expect_any_instance_of(::Socket).to receive(:write_nonblock)
541
+ .and_return(:wait_writable)
542
+ expect do
543
+ client.with_deadline(0.25) do
544
+ client.connect('localhost:1234', configuration)
545
+ client.read(12)
546
+ client.write('Hello World!')
547
+ end
548
+ end.to raise_error(TCPClient::WriteTimeoutError)
549
+ end
550
+ end
551
+ end
552
+ end
553
+
554
+ context 'when using SSL' do
555
+ let(:configuration) do
556
+ TCPClient::Configuration.create(
557
+ buffered: false,
558
+ reverse_lookup: false,
559
+ ssl: {
560
+ min_version: :TLS1_2,
561
+ max_version: :TLS1_3
562
+ }
563
+ )
564
+ end
565
+
566
+ before do
567
+ allow_any_instance_of(::Socket).to receive(:connect)
568
+ allow_any_instance_of(::OpenSSL::SSL::SSLSocket).to receive(:connect)
569
+ end
570
+
571
+ describe '#connect' do
572
+ it 'configures the SSL socket' do
573
+ # this produces a mock warning :(
574
+ # expect_any_instance_of(::OpenSSL::SSL::SSLContext).to receive(
575
+ # :set_params
576
+ # )
577
+ # .once
578
+ # .with(ssl_version: :TLSv1_2)
579
+ # .and_call_original
580
+ expect_any_instance_of(::OpenSSL::SSL::SSLSocket).to receive(
581
+ :sync_close=
582
+ )
583
+ .once
584
+ .with(true)
585
+ .and_call_original
586
+ expect_any_instance_of(::OpenSSL::SSL::SSLSocket).to receive(
587
+ :post_connection_check
588
+ )
589
+ .once
590
+ .with('localhost')
591
+
592
+ TCPClient.new.connect('localhost:1234', configuration)
593
+ end
594
+ end
595
+ end
596
+ end
data/tcp-client.gemspec CHANGED
@@ -27,11 +27,11 @@ Gem::Specification.new do |spec|
27
27
  'https://github.com/mblumtritt/tcp-client/issues'
28
28
 
29
29
  spec.add_development_dependency 'bundler'
30
- spec.add_development_dependency 'minitest'
31
30
  spec.add_development_dependency 'rake'
31
+ spec.add_development_dependency 'rspec'
32
32
 
33
33
  all_files = Dir.chdir(__dir__) { `git ls-files -z`.split(0.chr) }
34
- spec.test_files = all_files.grep(%r{^test/})
34
+ spec.test_files = all_files.grep(%r{^spec/})
35
35
  spec.files = all_files - spec.test_files
36
36
 
37
37
  spec.extra_rdoc_files = %w[README.md LICENSE]
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.7.0
4
+ version: 0.8.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: 2021-11-06 00:00:00.000000000 Z
11
+ date: 2021-11-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -25,7 +25,7 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: minitest
28
+ name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rake
42
+ name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -85,14 +85,13 @@ files:
85
85
  - rakefile.rb
86
86
  - sample/google.rb
87
87
  - sample/google_ssl.rb
88
+ - spec/helper.rb
89
+ - spec/tcp-client/address_spec.rb
90
+ - spec/tcp-client/configuration_spec.rb
91
+ - spec/tcp-client/default_configuration_spec.rb
92
+ - spec/tcp-client/version_spec.rb
93
+ - spec/tcp_client_spec.rb
88
94
  - tcp-client.gemspec
89
- - test/helper.rb
90
- - test/tcp-client/address_test.rb
91
- - test/tcp-client/configuration_test.rb
92
- - test/tcp-client/deadline_test.rb
93
- - test/tcp-client/default_configuration_test.rb
94
- - test/tcp-client/version_test.rb
95
- - test/tcp_client_test.rb
96
95
  homepage: https://github.com/mblumtritt/tcp-client
97
96
  licenses:
98
97
  - BSD-3-Clause
@@ -119,10 +118,9 @@ signing_key:
119
118
  specification_version: 4
120
119
  summary: A TCP client implementation with working timeout support.
121
120
  test_files:
122
- - test/helper.rb
123
- - test/tcp-client/address_test.rb
124
- - test/tcp-client/configuration_test.rb
125
- - test/tcp-client/deadline_test.rb
126
- - test/tcp-client/default_configuration_test.rb
127
- - test/tcp-client/version_test.rb
128
- - test/tcp_client_test.rb
121
+ - spec/helper.rb
122
+ - spec/tcp-client/address_spec.rb
123
+ - spec/tcp-client/configuration_spec.rb
124
+ - spec/tcp-client/default_configuration_spec.rb
125
+ - spec/tcp-client/version_spec.rb
126
+ - spec/tcp_client_spec.rb