[squeak-dev] Port numbers in network tests

Frank Shearar frank.shearar at gmail.com
Fri Apr 5 11:54:44 UTC 2013


On 5 April 2013 10:04, Frank Shearar <frank.shearar at gmail.com> wrote:
> On 5 April 2013 04:16, Levente Uzonyi <leves at elte.hu> wrote:
>> On Thu, 4 Apr 2013, Frank Shearar wrote:
>>
>>> So this isn't exactly a common use case, except on build.squeak.org:
>>>
>>> You have a bunch of network tests, so in your #setUp you start up a
>>> server on some port and in #tearDown you shut down the server. What
>>> port do you use? Well, it doesn't really matter too much, as long as
>>> the port's available. So you choose some probably-not-used port, like
>>> 7799. (WebClient's test suite uses this.) All is almost always well,
>>> because tests only fail when something's using 7799, which is almost
>>> never.
>>>
>>> build.squeak.org has two executors, which means it can run two builds
>>> concurrently. Suddenly, if you build SqueakTrunk, you'll trigger
>>> ExternalPackages, ExternalPackages-Squeak4.3 and External-Squeak4.4.
>>> Which means you will often execute the same test suite in different
>>> images at the same time. Suddenly those tests using a hard-coded port
>>> all fail, causing noise. (Xtreams' test suite is also vulnerable to
>>> this problem: look at the  XTSocketReadingWritingTest failures in
>>> http://build.squeak.org/job/ExternalPackages/43/testReport/)
>>>
>>> So what do we do?
>>>
>>> One approach that I can think of is, like WebClient's test suite, to
>>> use a method #port returning the port to use in a test. However, #port
>>> should not return a constant but rather attempt to open a port within
>>> some range, and return _some_ open port. The problem here is a
>>> time-of-check-time-of-use race.
>>>
>>> Now that might nearly always work. Can anyone think of a better method?
>>
>>
>> The current socket implementation does exactly what you need. If a port is
>> being used, the socket will listen on a random free port. So the solution is
>> to ask the created Socket instance for which port it's listening on.
>>
>> Code showing the behavior:
>>
>> s := Socket newTCP.
>> s listenOn: 1234 backlogSize: 10.
>> s port.
>> s2 := Socket newTCP.
>> s2 listenOn: 1234 backlogSize: 10.
>> { s port. s2 port } "==> #(1234 50542)"
>
> That's.... surprising. Is that something the SocketPlugin does? No EADDRINUSE?
>
> OK, so leaving aside that I think that's crazy behaviour,

Upon reflection, it's not as crazy as I thought. listen() then
actually means "try open this specific port. If you can't, open on
some random port, and let me know I only got a listening socket on
some random port, not the particular port I asked for, by returning
EADDRINUSE."

That's handy for protocols that dynamically instantiate servers (FTP, say).

That _also_ means I've just been on a wild goose chase, thinking that
concurrent builds on separate executors were interfering. Only those
tests that expected a certain port number (and in WebClient that's
just one test) would fail if another job had opened that port.

frank


More information about the Squeak-dev mailing list