Skip to content

Commit 3537a70

Browse files
committed
Add test coverage for socket changes
1 parent bb1e2f0 commit 3537a70

File tree

1 file changed

+92
-1
lines changed

1 file changed

+92
-1
lines changed

test/test_socket.rb

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,27 @@
33

44
class MockSocket
55
include Dalli::Socket::InstanceMethods
6-
attr_accessor :options, :read_results
6+
attr_accessor :options, :read_results, :write_results
77

88
def initialize(options = {})
99
@options = options
1010
@read_results = []
11+
@write_results = []
1112
@read_index = 0
13+
@write_index = 0
1214
end
1315

1416
def read_nonblock(_count, exception: true)
1517
result = @read_results[@read_index]
1618
@read_index += 1
1719
result
1820
end
21+
22+
def write_nonblock(_bytes, exception: true)
23+
result = @write_results[@write_index]
24+
@write_index += 1
25+
result
26+
end
1927
end
2028

2129
describe 'Dalli::Socket::InstanceMethods' do
@@ -81,6 +89,70 @@ def read_nonblock(_count, exception: true)
8189
end
8290
end
8391

92+
describe '#writefull' do
93+
it 'writes all bytes in a single call' do
94+
sock.write_results = [5]
95+
assert_equal 5, sock.writefull("hello")
96+
end
97+
98+
it 'handles partial writes across multiple calls' do
99+
sock.write_results = [2, 3]
100+
assert_equal 5, sock.writefull("hello")
101+
end
102+
103+
it 'retries on :wait_writable when IO.select succeeds' do
104+
sock.write_results = [:wait_writable, 5]
105+
IO.stubs(:select).with(nil, [sock], nil, 1).returns([nil, [sock]])
106+
assert_equal 5, sock.writefull("hello")
107+
end
108+
109+
it 'retries on :wait_readable when IO.select succeeds' do
110+
sock.write_results = [:wait_readable, 5]
111+
IO.stubs(:select).with([sock], nil, nil, 1).returns([[sock]])
112+
assert_equal 5, sock.writefull("hello")
113+
end
114+
115+
it 'raises Timeout::Error on :wait_writable when IO.select times out' do
116+
sock.write_results = [:wait_writable]
117+
IO.stubs(:select).with(nil, [sock], nil, 1).returns(nil)
118+
assert_raises(Timeout::Error) { sock.writefull("hello") }
119+
end
120+
121+
it 'raises Timeout::Error on :wait_readable when IO.select times out' do
122+
sock.write_results = [:wait_readable]
123+
IO.stubs(:select).with([sock], nil, nil, 1).returns(nil)
124+
assert_raises(Timeout::Error) { sock.writefull("hello") }
125+
end
126+
127+
it 'delivers all bytes through a real socket pair' do
128+
s1, s2 = Socket.pair(:UNIX, :STREAM, 0)
129+
s1.extend(Dalli::Socket::InstanceMethods)
130+
def s1.options; { socket_timeout: 5 }; end
131+
132+
data = "hello world"
133+
result = s1.writefull(data)
134+
s1.close
135+
136+
assert_equal data.bytesize, result
137+
assert_equal data, s2.read
138+
ensure
139+
s1&.close rescue nil
140+
s2&.close rescue nil
141+
end
142+
143+
describe 'with credentials' do
144+
let(:sock) { MockSocket.new(socket_timeout: 1, username: 'admin', password: 'secret') }
145+
146+
it 'excludes credentials from Timeout::Error message' do
147+
sock.write_results = [:wait_writable]
148+
IO.stubs(:select).with(nil, [sock], nil, 1).returns(nil)
149+
error = assert_raises(Timeout::Error) { sock.writefull("hello") }
150+
refute_match(/admin/, error.message)
151+
refute_match(/secret/, error.message)
152+
end
153+
end
154+
end
155+
84156
describe '#read_available' do
85157
it 'reads all available data until :wait_readable' do
86158
sock.read_results = ["he", "llo", :wait_readable]
@@ -179,6 +251,19 @@ def read_nonblock(_count, exception: true)
179251
@sock = Dalli::Socket::TCP.open('127.0.0.1', @port, 'my_server', socket_timeout: 5)
180252
assert_equal 'my_server', @sock.server
181253
end
254+
255+
it 'raises SocketError for unresolvable hostname' do
256+
assert_raises(SocketError) do
257+
Dalli::Socket::TCP.open('this-host-does-not-exist.invalid', 11211, 'srv', socket_timeout: 1)
258+
end
259+
end
260+
261+
it 'includes hostname in SocketError message for unresolvable host' do
262+
error = assert_raises(SocketError) do
263+
Dalli::Socket::TCP.open('this-host-does-not-exist.invalid', 11211, 'srv', socket_timeout: 1)
264+
end
265+
assert_match(/this-host-does-not-exist\.invalid/, error.message)
266+
end
182267
end
183268

184269
describe 'Dalli::Socket::UNIX' do
@@ -212,4 +297,10 @@ def read_nonblock(_count, exception: true)
212297
@sock = Dalli::Socket::UNIX.open(@path, 'my_server', socket_timeout: 5)
213298
assert_equal 'my_server', @sock.server
214299
end
300+
301+
it 'raises Errno::ENOENT for non-existent socket path' do
302+
assert_raises(Errno::ENOENT) do
303+
Dalli::Socket::UNIX.open('/tmp/nonexistent_dalli_test_socket', 'srv', socket_timeout: 1)
304+
end
305+
end
215306
end

0 commit comments

Comments
 (0)