Skip to content

Commit

Permalink
Fix port collisions in adapter_lint
Browse files Browse the repository at this point in the history
In order to 'reserve' a free TCP Server port, we create a TCPServer,
take a note of its port number, and then immediately close it.
We'd then ask our adapter to use the port we just finished with via
that adapter's configuration.

While this isn't a particularly safe way of 'reserving' a port,
it's the best we can do with heterogeneous adapters that have a one-way
config method.

However, this would cause intermittent test failures when our 'canary'
socket did not get out of the way in time for an adapter to bind its
server. Socket#close does not actually block until the socket is
closed at OS level, it just frees the Ruby handle to it.

Actually waiting for the socket to become free or garbage-collecting
it to force the issue is counterproductive – we'd need to poll the port
or run a full GC, which would take more time than a
simple sleep. Additionally, the sleep needs to be tuned so that tests
 are not unduly slowed by it – too quick and we'll see failures, too
 slow and our builds will reflect it.
  • Loading branch information
rgarner committed Apr 6, 2016
1 parent 07f02c2 commit 0899628
Showing 1 changed file with 13 additions and 1 deletion.
14 changes: 13 additions & 1 deletion lib/webmachine/spec/adapter_lint.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,19 @@
attr_accessor :client

let(:address) { "127.0.0.1" }
let(:port) { s = TCPServer.new(address, 0); p = s.addr[1]; s.close; p }
let(:port) do
s = TCPServer.new(address, 0)
p = s.addr[1]
s.close # This does not close the socket at OS level, just frees from Ruby.
# The socket will be in TIME_WAIT http://www.ssfnet.org/Exchange/tcp/tcpTutorialNotes.html
# "The main thing to recognize about connection teardown is that a connection in
# the TIME_WAIT state cannot move to the CLOSED state until it has waited for two times
# the maximum amount of time an IP datagram might live in the Inter net."

sleep(0.005) # This is just about the best we can do. Any more slows the tests,
# any less and we get intermittent silent port collisions
p
end

let(:application) do
application = Webmachine::Application.new
Expand Down

0 comments on commit 0899628

Please sign in to comment.