Skip to content

Commit 080d66b

Browse files
authored
Avoid flaky test failures by retrying on local port conflicts (ruby#15818)
This test obtains an available port number by calling `TCPServer.new`, then closes it and passes the same port number as `local_port` to `TCPSocket.new`. However, `TCPSocket.new` could occasionally fail with `Errno::EADDRINUSE` at the bind(2) step. I believe this happens when tests are run in parallel and another process on the same host happens to bind the same port in the short window between closing the `TCPServer` and calling `TCPSocket.new`. To address this race condition, the test now retries with a newly selected available port when such a conflict occurs.
1 parent 950ffa9 commit 080d66b

File tree

1 file changed

+15
-6
lines changed
  • spec/ruby/library/socket/tcpsocket/shared

1 file changed

+15
-6
lines changed

spec/ruby/library/socket/tcpsocket/shared/new.rb

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,23 @@
5353
end
5454

5555
it "connects to a server when passed local_host and local_port arguments" do
56-
server = TCPServer.new(SocketSpecs.hostname, 0)
56+
retries = 0
57+
max_retries = 3
58+
5759
begin
58-
available_port = server.addr[1]
59-
ensure
60-
server.close
60+
retries += 1
61+
server = TCPServer.new(SocketSpecs.hostname, 0)
62+
begin
63+
available_port = server.addr[1]
64+
ensure
65+
server.close
66+
end
67+
@socket = TCPSocket.send(@method, @hostname, @server.port,
68+
@hostname, available_port)
69+
rescue Errno::EADDRINUSE
70+
raise if retries >= max_retries
71+
retry
6172
end
62-
@socket = TCPSocket.send(@method, @hostname, @server.port,
63-
@hostname, available_port)
6473
@socket.should be_an_instance_of(TCPSocket)
6574
end
6675

0 commit comments

Comments
 (0)