Swi-prolog 9.2.2 fails http:proxy test on armv7

Hi, swi-prolog 9.2.2 has 1 test failure, with armv7, on Alpine Linux:

45/82 Test #52: http:proxy .......................***Failed    1.39 sec
% [10/13] proxy:Request URL..ections go via HTTP .. **FAILED (0.031 sec)
ERROR: /builds/brebs/aports/testing/swi-prolog/src/swipl-9.2.2/packages/http/test_proxy.pl:586:
ERROR:     test proxy:'Request URL when all connections go via HTTP': received error: Unknown error term: proxy_error(tried([error(proxy(localhost,40817),error(socket_error(econnrefused,'Connection refused'),_15396))-[]]))
% Started server at http://localhost:33337/
% Started server at https://localhost:33543/
Warning: Unknown message: stop(http_proxy_server,error(socket_error(econnrefused,'Connection refused'),_16882))

Full output:

Only armv7 has this problem (can be seen by clicking on the red cross, and seeing the successful builds in the drop-down list that appears):

The tests passed in swi-prolog 9.2.1

Hopefully there’s an easy fix?

A rerun succeeded, so I’m unsure if the test is unstable on armv7, or perhaps the Alpine build server itself was unstable.

That is still an open issue. The same happens on MacOS/M1 incidentally. I think the issue is about reusing TCP/IP ports the wrong way while the various HTTP tests run concurrently, picking free ports to do the test. One of the tests gets 4 ports, then closes them and reuses them with explicit port numbers. Concurrent tests may pick these ports as free ports.

I’m not 100% sure though as these are two incidents on arm chips while I’m not aware of the issue on amd64/Linux. I expected the difference to be due to timing and port lingering on MacOS vs Linux, but this adds another data point to it.

So, I fear it needs to be resolved :frowning:

Yes - the code is free_ports

free_ports should not exist - it should be e.g. start_http_proxy which instantiates the Port variable, and runs assertz(port(socks, Port)).

That would then prevent the race condition.

Just wanted to mention this nice code:

?- tcp_socket(Socket), tcp_bind(Socket, localhost:Port).
Socket = <socket>(0x55b76f16c260),
Port = 55917.

That is probably roughly what needs to happen. I don’t recall the exact history. I think the original code was written with hard-wired ports, which of course causes other conflicts. The test surely needs to be fixed. Whether or not that fixes the issue gets a little less certain after the problem also emerges on arm on Linux. Now the common factor is the arm chip rather than the OS.

If you can figure it out how to fix the test, please make a PR.

PR raised: Don't reuse original test port for HTTP proxy by brebs-gh · Pull Request #165 · SWI-Prolog/packages-http · GitHub

It makes the port for the HTTP proxy dynamic, leaving 4 static ports remaining.

It’s reliable on Linux amd64… are you able to test whether it improves reliability on Mac M1, @jan ?

Hopefully it’s a quick win - completely preventing static port reuse seems to be a bigger task of redesigning all the tests in test_proxy.pl

1 Like

Unless I was just very lucky, it seems to do the trick on the M1 as well :slight_smile: Thanks!

The whole thing remains a bit complicated of course. Notably test the failure to connect to an unused port is probably hard to do reliably in an unknown environment :frowning:

Yes - I don’t think there’s a properly-safe way to do that, especially as a non-root user.

I suppose we’re also testing the limits of SO_REUSEADDR :grinning: