[squeak-dev] Port numbers in network tests

Chris Muller ma.chris.m at gmail.com
Sat Apr 6 18:32:32 UTC 2013


(Oops, I did mean for my note to go to the list).

For unit-test the "assume" approach has been more than practical
enough for me over the years.  For the random port numbers I chose,
the only time it ever didn't work is when I had forgotten to shutdown
the server image from a previously-failed test.

But wait!  Now I remember something!  There was some sort of "port
discovery" package available  for Squeak in years past -- can't
remember the name of it does anyone else?

On Fri, Apr 5, 2013 at 11:48 AM, Frank Shearar <frank.shearar at gmail.com> wrote:
> (Not sure if you meant to drop off-list, but OK.)
>
> Sure. But that's well beyond my implicit assumption of a unit test.
> You then still have a problem, with the cross-image test: either you
> assume that your listenOn: really did start listening on that port, or
> you check the port and communicate the actual real port in a side
> channel (for instance by passing in the port during the client image
> spawn directly, or via an environment variable. But I'd probably just
> fail the test, in your situation: the server starts up, and #assert:s
> that the proper port's being used.
>
> frank
>
> On 5 April 2013 17:36, Chris Muller <ma.chris.m at gmail.com> wrote:
>> That means server and client must run in the same image, yes?  My
>> network tests actually run in separate images (launched by OSProcess),
>> so if a port number was taken and the server got assigned a random
>> port (instead of its hard coded port), the client in a separate image
>> has no way to know about that.
>>
>> On Fri, Apr 5, 2013 at 11:25 AM, Frank Shearar <frank.shearar at gmail.com> wrote:
>>> On 5 April 2013 17:09, Chris Muller <asqueaker at gmail.com> wrote:
>>>> Of course, the other half are the connecting clients.  Not sure how
>>>> your code works but in my network tests I've been bitten by ports in
>>>> use because the clients didn't know about the random port having been
>>>> selected.
>>>
>>> Yes, but that's why Levente suggests asking the server for its port,
>>> instead of relying on a common magic number.
>>>
>>> frank
>>>
>>>> On Fri, Apr 5, 2013 at 6:54 AM, Frank Shearar <frank.shearar at gmail.com> wrote:
>>>>> 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