tcp-client 0.0.11 → 0.1.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/README.md +11 -5
- data/gems.rb +1 -1
- data/lib/tcp-client.rb +15 -8
- data/lib/tcp-client/address.rb +1 -1
- data/lib/tcp-client/configuration.rb +10 -3
- data/lib/tcp-client/default_configuration.rb +21 -0
- data/lib/tcp-client/mixin/io_timeout.rb +3 -3
- data/lib/tcp-client/tcp_socket.rb +5 -3
- data/lib/tcp-client/version.rb +1 -1
- data/sample/google.rb +15 -10
- data/sample/google_ssl.rb +9 -5
- data/test/tcp-client/address_test.rb +3 -1
- data/test/tcp-client/configuration_test.rb +44 -11
- data/test/tcp-client/default_configuration_test.rb +59 -0
- data/test/tcp-client/version_test.rb +3 -1
- data/test/tcp_client_test.rb +66 -62
- data/test/test_helper.rb +3 -3
- metadata +9 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bb5546419b47d6680b576f39d8c4b382c39d74f07ca43f6e782160122b6ba524
|
4
|
+
data.tar.gz: 3e563cd2db3efc765e491ece2fc37a784cb55ef05f6390eb23d1322a926be49e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 712f24a4dc3427cf37126681ba50d53f0aefc9f839920283f611ef22e923f65f53f09fc83ca66cb45930536ca3c13d630dc7b0c5a5f40c6fc6f91f82bf123c3c
|
7
|
+
data.tar.gz: e97e52fc2aa1ad3cc548d2f561df97678e00c0e7e617c08afdbb9c6537709fc2743a07f26679cc8007124348cb32f1e8481d6417b7d3e28d247b504fcc951805
|
data/README.md
CHANGED
@@ -8,20 +8,26 @@ This gem implements a TCP client with (optional) SSL support. The motivation of
|
|
8
8
|
## Sample
|
9
9
|
|
10
10
|
```ruby
|
11
|
-
|
11
|
+
require 'tcp-client'
|
12
|
+
|
13
|
+
TCPClient.configure do |cfg|
|
12
14
|
cfg.connect_timeout = 1 # second to connect the server
|
13
15
|
cfg.write_timeout = 0.25 # seconds to write a single data junk
|
14
16
|
cfg.read_timeout = 0.5 # seconds to read some bytes
|
15
|
-
cfg.ssl_params = {ssl_version: :TLSv1_2} # use TLS 1.2
|
17
|
+
cfg.ssl_params = { ssl_version: :TLSv1_2 } # use TLS 1.2
|
16
18
|
end
|
17
19
|
|
18
20
|
# the following request sequence is not allowed to last longer than 2 seconds:
|
19
21
|
# 1 second to connect (incl. SSL handshake etc.)
|
20
22
|
# + 0.25 seconds to write data
|
21
23
|
# + 0.5 seconds to read a response
|
22
|
-
|
23
|
-
|
24
|
-
|
24
|
+
|
25
|
+
TCPClient.open('www.google.com:443') do |client|
|
26
|
+
# simple HTTP get request
|
27
|
+
pp client.write("GET / HTTP/1.1\r\nHost: google.com\r\n\r\n")
|
28
|
+
|
29
|
+
# read "HTTP/1.1 " + 3 byte HTTP status code
|
30
|
+
pp client.read(12)
|
25
31
|
end
|
26
32
|
```
|
27
33
|
|
data/gems.rb
CHANGED
data/lib/tcp-client.rb
CHANGED
@@ -4,6 +4,7 @@ require_relative 'tcp-client/address'
|
|
4
4
|
require_relative 'tcp-client/tcp_socket'
|
5
5
|
require_relative 'tcp-client/ssl_socket'
|
6
6
|
require_relative 'tcp-client/configuration'
|
7
|
+
require_relative 'tcp-client/default_configuration'
|
7
8
|
require_relative 'tcp-client/version'
|
8
9
|
|
9
10
|
class TCPClient
|
@@ -19,9 +20,15 @@ class TCPClient
|
|
19
20
|
end
|
20
21
|
end
|
21
22
|
|
22
|
-
|
23
|
+
TimeoutError = Class.new(IOError)
|
24
|
+
ConnectTimeoutError = Class.new(TimeoutError)
|
25
|
+
ReadTimeoutError = Class.new(TimeoutError)
|
26
|
+
WriteTimeoutError = Class.new(TimeoutError)
|
23
27
|
|
24
|
-
|
28
|
+
Timeout = TimeoutError # backward compatibility
|
29
|
+
deprecate_constant(:Timeout)
|
30
|
+
|
31
|
+
def self.open(addr, configuration = Configuration.default)
|
25
32
|
addr = Address.new(addr)
|
26
33
|
client = new
|
27
34
|
client.connect(addr, configuration)
|
@@ -44,10 +51,10 @@ class TCPClient
|
|
44
51
|
close
|
45
52
|
NoOpenSSL.raise! if configuration.ssl? && !defined?(SSLSocket)
|
46
53
|
@address = Address.new(addr)
|
47
|
-
@socket = TCPSocket.new(@address, configuration,
|
48
|
-
configuration.ssl? &&
|
49
|
-
@socket
|
50
|
-
|
54
|
+
@socket = TCPSocket.new(@address, configuration, ConnectTimeoutError)
|
55
|
+
configuration.ssl? &&
|
56
|
+
@socket =
|
57
|
+
SSLSocket.new(@socket, @address, configuration, ConnectTimeoutError)
|
51
58
|
@write_timeout = configuration.write_timeout
|
52
59
|
@read_timeout = configuration.read_timeout
|
53
60
|
self
|
@@ -67,12 +74,12 @@ class TCPClient
|
|
67
74
|
|
68
75
|
def read(nbytes, timeout: @read_timeout)
|
69
76
|
NotConnected.raise!(self) if closed?
|
70
|
-
@socket.read(nbytes, timeout: timeout, exception:
|
77
|
+
@socket.read(nbytes, timeout: timeout, exception: ReadTimeoutError)
|
71
78
|
end
|
72
79
|
|
73
80
|
def write(*msg, timeout: @write_timeout)
|
74
81
|
NotConnected.raise!(self) if closed?
|
75
|
-
@socket.write(*msg, timeout: timeout, exception:
|
82
|
+
@socket.write(*msg, timeout: timeout, exception: WriteTimeoutError)
|
76
83
|
end
|
77
84
|
|
78
85
|
def flush
|
data/lib/tcp-client/address.rb
CHANGED
@@ -44,7 +44,7 @@ class TCPClient
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def from_string(str)
|
47
|
-
return
|
47
|
+
return nil, str.to_i unless idx = str.rindex(':')
|
48
48
|
name = str[0, idx]
|
49
49
|
name = name[1, name.size - 2] if name[0] == '[' && name[-1] == ']'
|
50
50
|
[name, str[idx + 1, str.size - idx].to_i]
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class TCPClient
|
2
2
|
class Configuration
|
3
|
-
def self.create
|
4
|
-
ret = new
|
3
|
+
def self.create(options = {})
|
4
|
+
ret = new(options)
|
5
5
|
yield(ret) if block_given?
|
6
6
|
ret
|
7
7
|
end
|
@@ -9,9 +9,10 @@ class TCPClient
|
|
9
9
|
attr_reader :buffered, :keep_alive, :reverse_lookup
|
10
10
|
attr_accessor :ssl_params
|
11
11
|
|
12
|
-
def initialize
|
12
|
+
def initialize(options = {})
|
13
13
|
@buffered = @keep_alive = @reverse_lookup = true
|
14
14
|
self.timeout = @ssl_params = nil
|
15
|
+
options.each_pair { |attribute, value| set(attribute, value) }
|
15
16
|
end
|
16
17
|
|
17
18
|
def ssl?
|
@@ -67,6 +68,12 @@ class TCPClient
|
|
67
68
|
|
68
69
|
private
|
69
70
|
|
71
|
+
def set(attribute, value)
|
72
|
+
public_send("#{attribute}=", value)
|
73
|
+
rescue NoMethodError
|
74
|
+
raise(ArgumentError, "unknown attribute - #{attribute}")
|
75
|
+
end
|
76
|
+
|
70
77
|
def seconds(value)
|
71
78
|
value&.positive? ? value : nil
|
72
79
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative 'configuration'
|
2
|
+
|
3
|
+
class TCPClient
|
4
|
+
@default_configuration = Configuration.new
|
5
|
+
|
6
|
+
class << self
|
7
|
+
attr_reader :default_configuration
|
8
|
+
|
9
|
+
def configure(options = {})
|
10
|
+
cfg = Configuration.new(options)
|
11
|
+
yield(cfg) if block_given?
|
12
|
+
@default_configuration = cfg
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Configuration
|
17
|
+
def self.default
|
18
|
+
TCPClient.default_configuration
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -12,7 +12,7 @@ module IOTimeoutMixin
|
|
12
12
|
|
13
13
|
def read(nbytes, timeout: nil, exception: IOTimeoutError)
|
14
14
|
timeout = timeout.to_f
|
15
|
-
return read_all(nbytes){ |junk_size| super(junk_size) } if timeout <= 0
|
15
|
+
return read_all(nbytes) { |junk_size| super(junk_size) } if timeout <= 0
|
16
16
|
deadline = Time.now + timeout
|
17
17
|
read_all(nbytes) do |junk_size|
|
18
18
|
with_deadline(deadline, exception) do
|
@@ -23,9 +23,9 @@ module IOTimeoutMixin
|
|
23
23
|
|
24
24
|
def write(*msgs, timeout: nil, exception: IOTimeoutError)
|
25
25
|
timeout = timeout.to_f
|
26
|
-
return write_all(msgs.join){ |junk| super(junk) } if timeout <= 0
|
26
|
+
return write_all(msgs.join.b) { |junk| super(junk) } if timeout <= 0
|
27
27
|
deadline = Time.now + timeout
|
28
|
-
write_all(msgs.join) do |junk|
|
28
|
+
write_all(msgs.join.b) do |junk|
|
29
29
|
with_deadline(deadline, exception) do
|
30
30
|
write_nonblock(junk, exception: false)
|
31
31
|
end
|
@@ -14,9 +14,11 @@ class TCPClient
|
|
14
14
|
private
|
15
15
|
|
16
16
|
def connect_to(address, timeout, exception)
|
17
|
-
addr =
|
18
|
-
|
19
|
-
|
17
|
+
addr =
|
18
|
+
::Socket.pack_sockaddr_in(
|
19
|
+
address.addrinfo.ip_port,
|
20
|
+
address.addrinfo.ip_address
|
21
|
+
)
|
20
22
|
return connect(addr) unless timeout
|
21
23
|
with_deadline(Time.now + timeout, exception) do
|
22
24
|
connect_nonblock(addr, exception: false)
|
data/lib/tcp-client/version.rb
CHANGED
data/sample/google.rb
CHANGED
@@ -1,16 +1,21 @@
|
|
1
1
|
require_relative '../lib/tcp-client'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
TCPClient.configure(
|
4
|
+
connect_timeout: 0.5, # seconds to connect the server
|
5
|
+
write_timeout: 0.25, # seconds to write a single data junk
|
6
|
+
read_timeout: 0.5 # seconds to read some bytes
|
7
|
+
)
|
8
8
|
|
9
|
-
# the following request sequence is not allowed
|
10
|
-
#
|
9
|
+
# the following request sequence is not allowed
|
10
|
+
# to last longer than 1.25 seconds:
|
11
|
+
# 0.5 seconds to connect
|
11
12
|
# + 0.25 seconds to write data
|
12
13
|
# + 0.5 seconds to read a response
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
|
15
|
+
TCPClient.open('www.google.com:80') do |client|
|
16
|
+
# simple HTTP get request
|
17
|
+
pp client.write("GET / HTTP/1.1\r\nHost: google.com\r\n\r\n")
|
18
|
+
|
19
|
+
# read "HTTP/1.1 " + 3 byte HTTP status code
|
20
|
+
pp client.read(12)
|
16
21
|
end
|
data/sample/google_ssl.rb
CHANGED
@@ -1,17 +1,21 @@
|
|
1
1
|
require_relative '../lib/tcp-client'
|
2
2
|
|
3
|
-
|
3
|
+
TCPClient.configure do |cfg|
|
4
4
|
cfg.connect_timeout = 1 # second to connect the server
|
5
5
|
cfg.write_timeout = 0.25 # seconds to write a single data junk
|
6
6
|
cfg.read_timeout = 0.5 # seconds to read some bytes
|
7
|
-
cfg.ssl_params = {ssl_version: :TLSv1_2} # use TLS 1.2
|
7
|
+
cfg.ssl_params = { ssl_version: :TLSv1_2 } # use TLS 1.2
|
8
8
|
end
|
9
9
|
|
10
10
|
# the following request sequence is not allowed to last longer than 2 seconds:
|
11
11
|
# 1 second to connect (incl. SSL handshake etc.)
|
12
12
|
# + 0.25 seconds to write data
|
13
13
|
# + 0.5 seconds to read a response
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
|
15
|
+
TCPClient.open('www.google.com:443') do |client|
|
16
|
+
# simple HTTP get request
|
17
|
+
pp client.write("GET / HTTP/1.1\r\nHost: google.com\r\n\r\n")
|
18
|
+
|
19
|
+
# read "HTTP/1.1 " + 3 byte HTTP status code
|
20
|
+
pp client.read(12)
|
17
21
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require_relative '../test_helper'
|
2
2
|
|
3
|
-
class ConfigurationTest < Test
|
3
|
+
class ConfigurationTest < MiniTest::Test
|
4
|
+
parallelize_me!
|
5
|
+
|
4
6
|
def test_defaults
|
5
7
|
subject = TCPClient::Configuration.new
|
6
8
|
assert(subject.buffered)
|
@@ -13,11 +15,12 @@ class ConfigurationTest < Test
|
|
13
15
|
end
|
14
16
|
|
15
17
|
def test_configure
|
16
|
-
subject =
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
subject =
|
19
|
+
TCPClient::Configuration.create do |cfg|
|
20
|
+
cfg.buffered = cfg.keep_alive = cfg.reverse_lookup = false
|
21
|
+
cfg.timeout = 42
|
22
|
+
cfg.ssl = true
|
23
|
+
end
|
21
24
|
refute(subject.buffered)
|
22
25
|
refute(subject.keep_alive)
|
23
26
|
refute(subject.reverse_lookup)
|
@@ -27,6 +30,35 @@ class ConfigurationTest < Test
|
|
27
30
|
assert(subject.ssl?)
|
28
31
|
end
|
29
32
|
|
33
|
+
def test_options
|
34
|
+
subject =
|
35
|
+
TCPClient::Configuration.new(
|
36
|
+
buffered: false,
|
37
|
+
keep_alive: false,
|
38
|
+
reverse_lookup: false,
|
39
|
+
connect_timeout: 1,
|
40
|
+
read_timeout: 2,
|
41
|
+
write_timeout: 3,
|
42
|
+
ssl: true
|
43
|
+
)
|
44
|
+
refute(subject.buffered)
|
45
|
+
refute(subject.keep_alive)
|
46
|
+
refute(subject.reverse_lookup)
|
47
|
+
assert_same(1, subject.connect_timeout)
|
48
|
+
assert_same(2, subject.read_timeout)
|
49
|
+
assert_same(3, subject.write_timeout)
|
50
|
+
assert(subject.ssl?)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_invalid_option
|
54
|
+
err =
|
55
|
+
assert_raises(ArgumentError) do
|
56
|
+
TCPClient::Configuration.new(unknown_attr: :argument)
|
57
|
+
end
|
58
|
+
assert_includes(err.message, 'attribute')
|
59
|
+
assert_includes(err.message, 'unknown_attr')
|
60
|
+
end
|
61
|
+
|
30
62
|
def test_ssl_params
|
31
63
|
subject = TCPClient::Configuration.new
|
32
64
|
refute(subject.ssl?)
|
@@ -40,11 +72,12 @@ class ConfigurationTest < Test
|
|
40
72
|
end
|
41
73
|
|
42
74
|
def test_timeout_overwrite
|
43
|
-
subject =
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
75
|
+
subject =
|
76
|
+
TCPClient::Configuration.create do |cfg|
|
77
|
+
cfg.connect_timeout = 1
|
78
|
+
cfg.read_timeout = 2
|
79
|
+
cfg.write_timeout = 3
|
80
|
+
end
|
48
81
|
assert_same(1, subject.connect_timeout)
|
49
82
|
assert_same(2, subject.read_timeout)
|
50
83
|
assert_same(3, subject.write_timeout)
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
class DefauktConfigurationTest < MiniTest::Test
|
4
|
+
def test_default
|
5
|
+
subject = TCPClient.configure # reset to defaults
|
6
|
+
|
7
|
+
assert_same(
|
8
|
+
TCPClient.default_configuration,
|
9
|
+
TCPClient::Configuration.default
|
10
|
+
)
|
11
|
+
assert(subject.buffered)
|
12
|
+
assert(subject.keep_alive)
|
13
|
+
assert(subject.reverse_lookup)
|
14
|
+
refute(subject.ssl?)
|
15
|
+
assert_nil(subject.connect_timeout)
|
16
|
+
assert_nil(subject.read_timeout)
|
17
|
+
assert_nil(subject.write_timeout)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_configure_options
|
21
|
+
TCPClient.configure(
|
22
|
+
buffered: false,
|
23
|
+
keep_alive: false,
|
24
|
+
reverse_lookup: false,
|
25
|
+
ssl: true,
|
26
|
+
connect_timeout: 1,
|
27
|
+
read_timeout: 2,
|
28
|
+
write_timeout: 3
|
29
|
+
)
|
30
|
+
subject = TCPClient.default_configuration
|
31
|
+
refute(subject.buffered)
|
32
|
+
refute(subject.keep_alive)
|
33
|
+
refute(subject.reverse_lookup)
|
34
|
+
assert(subject.ssl?)
|
35
|
+
assert_same(1, subject.connect_timeout)
|
36
|
+
assert_same(2, subject.read_timeout)
|
37
|
+
assert_same(3, subject.write_timeout)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_configure_block
|
41
|
+
TCPClient.configure do |cfg|
|
42
|
+
cfg.buffered = false
|
43
|
+
cfg.keep_alive = false
|
44
|
+
cfg.reverse_lookup = false
|
45
|
+
cfg.ssl = true
|
46
|
+
cfg.connect_timeout = 1
|
47
|
+
cfg.read_timeout = 2
|
48
|
+
cfg.write_timeout = 3
|
49
|
+
end
|
50
|
+
subject = TCPClient.default_configuration
|
51
|
+
refute(subject.buffered)
|
52
|
+
refute(subject.keep_alive)
|
53
|
+
refute(subject.reverse_lookup)
|
54
|
+
assert(subject.ssl?)
|
55
|
+
assert_same(1, subject.connect_timeout)
|
56
|
+
assert_same(2, subject.read_timeout)
|
57
|
+
assert_same(3, subject.write_timeout)
|
58
|
+
end
|
59
|
+
end
|
data/test/tcp_client_test.rb
CHANGED
@@ -1,23 +1,27 @@
|
|
1
1
|
require_relative 'test_helper'
|
2
2
|
|
3
|
-
class TCPClientTest < Test
|
3
|
+
class TCPClientTest < MiniTest::Test
|
4
|
+
parallelize_me!
|
5
|
+
|
6
|
+
attr_reader :config
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@config = TCPClient::Configuration.create(buffered: false)
|
10
|
+
end
|
11
|
+
|
4
12
|
def test_defaults
|
5
13
|
subject = TCPClient.new
|
6
14
|
assert(subject.closed?)
|
7
15
|
assert_equal('', subject.to_s)
|
8
16
|
assert_nil(subject.address)
|
9
17
|
subject.close
|
10
|
-
assert_raises(TCPClient::NotConnected)
|
11
|
-
|
12
|
-
end
|
13
|
-
assert_raises(TCPClient::NotConnected) do
|
14
|
-
subject.read(42)
|
15
|
-
end
|
18
|
+
assert_raises(TCPClient::NotConnected) { subject.write('hello world!') }
|
19
|
+
assert_raises(TCPClient::NotConnected) { subject.read(42) }
|
16
20
|
end
|
17
21
|
|
18
22
|
def create_nonconnected_client
|
19
23
|
client = TCPClient.new
|
20
|
-
client.connect('',
|
24
|
+
client.connect('', config)
|
21
25
|
rescue Errno::EADDRNOTAVAIL
|
22
26
|
ensure
|
23
27
|
return client
|
@@ -32,52 +36,32 @@ class TCPClientTest < Test
|
|
32
36
|
assert_equal('localhost', subject.address.hostname)
|
33
37
|
assert_instance_of(Addrinfo, subject.address.addrinfo)
|
34
38
|
assert_same(0, subject.address.addrinfo.ip_port)
|
35
|
-
assert_raises(TCPClient::NotConnected)
|
36
|
-
|
37
|
-
end
|
38
|
-
assert_raises(TCPClient::NotConnected) do
|
39
|
-
subject.read(42)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def with_dummy_server(port)
|
44
|
-
# this server will never receive or send any data
|
45
|
-
server = TCPServer.new('localhost', port)
|
46
|
-
yield
|
47
|
-
ensure
|
48
|
-
server&.close
|
39
|
+
assert_raises(TCPClient::NotConnected) { subject.write('hello world!') }
|
40
|
+
assert_raises(TCPClient::NotConnected) { subject.read(42) }
|
49
41
|
end
|
50
42
|
|
51
43
|
def test_connected_state
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
assert_same(address_when_opened, subject.address)
|
66
|
-
end
|
44
|
+
TCPClient.open('localhost:1234') do |subject|
|
45
|
+
refute(subject.closed?)
|
46
|
+
assert_equal('localhost:1234', subject.to_s)
|
47
|
+
refute_nil(subject.address)
|
48
|
+
address_when_opened = subject.address
|
49
|
+
assert_equal('localhost:1234', subject.address.to_s)
|
50
|
+
assert_equal('localhost', subject.address.hostname)
|
51
|
+
assert_instance_of(Addrinfo, subject.address.addrinfo)
|
52
|
+
assert_same(1234, subject.address.addrinfo.ip_port)
|
53
|
+
|
54
|
+
subject.close
|
55
|
+
assert(subject.closed?)
|
56
|
+
assert_same(address_when_opened, subject.address)
|
67
57
|
end
|
68
58
|
end
|
69
59
|
|
70
|
-
def
|
71
|
-
TCPClient.open(
|
60
|
+
def check_read_timeout(timeout)
|
61
|
+
TCPClient.open('localhost:1234', config) do |subject|
|
72
62
|
refute(subject.closed?)
|
73
63
|
start_time = nil
|
74
|
-
assert_raises(TCPClient::
|
75
|
-
start_time = Time.now
|
76
|
-
# send 1MB to avoid any TCP stack buffering
|
77
|
-
subject.write('?' * (1024 * 1024), timeout: timeout)
|
78
|
-
end
|
79
|
-
assert_in_delta(timeout, Time.now - start_time, 0.02)
|
80
|
-
assert_raises(TCPClient::Timeout) do
|
64
|
+
assert_raises(TCPClient::ReadTimeoutError) do
|
81
65
|
start_time = Time.now
|
82
66
|
subject.read(42, timeout: timeout)
|
83
67
|
end
|
@@ -85,31 +69,51 @@ class TCPClientTest < Test
|
|
85
69
|
end
|
86
70
|
end
|
87
71
|
|
88
|
-
def
|
89
|
-
|
90
|
-
|
91
|
-
|
72
|
+
def test_read_timeout
|
73
|
+
check_read_timeout(0.5)
|
74
|
+
check_read_timeout(1)
|
75
|
+
check_read_timeout(1.5)
|
76
|
+
end
|
77
|
+
|
78
|
+
def check_write_timeout(timeout)
|
79
|
+
TCPClient.open('localhost:1234', config) do |subject|
|
80
|
+
refute(subject.closed?)
|
81
|
+
start_time = nil
|
82
|
+
assert_raises(TCPClient::WriteTimeoutError) do
|
83
|
+
start_time = Time.now
|
84
|
+
|
85
|
+
# send 1MB to avoid any TCP stack buffering
|
86
|
+
args = Array.new(2024, '?' * 1024)
|
87
|
+
subject.write(*args, timeout: timeout)
|
92
88
|
end
|
89
|
+
assert_in_delta(timeout, Time.now - start_time, 0.02)
|
93
90
|
end
|
94
91
|
end
|
95
92
|
|
96
|
-
def
|
93
|
+
def test_write_timeout
|
94
|
+
check_write_timeout(0.1)
|
95
|
+
check_write_timeout(0.25)
|
96
|
+
end
|
97
|
+
|
98
|
+
def check_connect_timeout(ssl_config)
|
97
99
|
start_time = nil
|
98
|
-
assert_raises(TCPClient::
|
100
|
+
assert_raises(TCPClient::ConnectTimeoutError) do
|
99
101
|
start_time = Time.now
|
100
|
-
TCPClient.new.connect(
|
102
|
+
TCPClient.new.connect('localhost:1234', ssl_config)
|
101
103
|
end
|
102
|
-
assert_in_delta(
|
104
|
+
assert_in_delta(ssl_config.connect_timeout, Time.now - start_time, 0.02)
|
103
105
|
end
|
104
106
|
|
105
107
|
def test_connect_ssl_timeout
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
108
|
+
ssl_config = TCPClient::Configuration.new(ssl: true)
|
109
|
+
|
110
|
+
ssl_config.connect_timeout = 0.5
|
111
|
+
check_connect_timeout(ssl_config)
|
112
|
+
|
113
|
+
ssl_config.connect_timeout = 1
|
114
|
+
check_connect_timeout(ssl_config)
|
115
|
+
|
116
|
+
ssl_config.connect_timeout = 1.5
|
117
|
+
check_connect_timeout(ssl_config)
|
114
118
|
end
|
115
119
|
end
|
data/test/test_helper.rb
CHANGED
@@ -4,6 +4,6 @@ require_relative '../lib/tcp-client'
|
|
4
4
|
|
5
5
|
$stdout.sync = $stderr.sync = true
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
# this pseudo-server never reads or writes anything
|
8
|
+
DummyServer = TCPServer.new('localhost', 1234)
|
9
|
+
Minitest.after_run { DummyServer.close }
|
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.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Blumtritt
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -70,6 +70,7 @@ files:
|
|
70
70
|
- lib/tcp-client.rb
|
71
71
|
- lib/tcp-client/address.rb
|
72
72
|
- lib/tcp-client/configuration.rb
|
73
|
+
- lib/tcp-client/default_configuration.rb
|
73
74
|
- lib/tcp-client/mixin/io_timeout.rb
|
74
75
|
- lib/tcp-client/ssl_socket.rb
|
75
76
|
- lib/tcp-client/tcp_socket.rb
|
@@ -81,6 +82,7 @@ files:
|
|
81
82
|
- tcp-client.gemspec
|
82
83
|
- test/tcp-client/address_test.rb
|
83
84
|
- test/tcp-client/configuration_test.rb
|
85
|
+
- test/tcp-client/default_configuration_test.rb
|
84
86
|
- test/tcp-client/version_test.rb
|
85
87
|
- test/tcp_client_test.rb
|
86
88
|
- test/test_helper.rb
|
@@ -89,7 +91,7 @@ licenses: []
|
|
89
91
|
metadata:
|
90
92
|
source_code_uri: https://github.com/mblumtritt/tcp-client
|
91
93
|
bug_tracker_uri: https://github.com/mblumtritt/tcp-client/issues
|
92
|
-
post_install_message:
|
94
|
+
post_install_message:
|
93
95
|
rdoc_options: []
|
94
96
|
require_paths:
|
95
97
|
- lib
|
@@ -104,13 +106,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
104
106
|
- !ruby/object:Gem::Version
|
105
107
|
version: 1.3.6
|
106
108
|
requirements: []
|
107
|
-
rubygems_version: 3.
|
108
|
-
signing_key:
|
109
|
+
rubygems_version: 3.2.9
|
110
|
+
signing_key:
|
109
111
|
specification_version: 4
|
110
112
|
summary: A TCP client implementation with working timeout support.
|
111
113
|
test_files:
|
112
114
|
- test/tcp-client/address_test.rb
|
113
115
|
- test/tcp-client/configuration_test.rb
|
116
|
+
- test/tcp-client/default_configuration_test.rb
|
114
117
|
- test/tcp-client/version_test.rb
|
115
118
|
- test/tcp_client_test.rb
|
116
119
|
- test/test_helper.rb
|