I have integration test that starts several binaries, each of which is a web API that takes port number it should bind to via command-line arguments
So my test will first gather available ports like this
let mut free_ports = {
let mut ports = vec![];
let mut sockets = vec![]; // just to make sure we won't pick the same port twice
for _ in 0..(cfg.file_workers.len() + 2) {
let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap();
let port = socket.local_addr().unwrap().port();
sockets.push(socket);
ports.push(port);
}
ports
};
Where cfg.file_workers.len() + 2 is indeed the amount of ports that I need in total during the test.
But I have a problem: Sometimes, one of the components will panic and say that the port is already in use!
Firstly, I wonder if this is a TOCTOU problem (time of check to time of use) problem where there's actually another application grabbing the port in that tiny window of time? I kinda doubt it because it happens quite often, I mean what is the chance that some application grabs that exact (random) port in the timespan of a few milliseconds?
The next thing I tried was to start on port 40000 and for every component spawned, increment it.
Note that there are several tests and they all run in parallel. The port number variable is global across all tests, and the incrementing and reading of the port number variable is atomic, so surely each component has a separate port number.
It still fails sometimes. Interestingly, when running while true; do cargo test; done it has long sequences of success and then maybe a minute where for example port 40002 is taken.
I don't understand why some 400xx port is taken though.
syncthing 543 ploppz 17u IPv6 28481 0t0 TCP *:22000 (LISTE )
syncthing 543 ploppz 18u IPv4 28484 0t0 TCP 127.0.0.1:8384 (LISTEN)
spotify 4207 ploppz 86u IPv4 1059487 0t0 TCP *:37147 (LISTE )
spotify 4207 ploppz 98u IPv4 77338 0t0 TCP *:57621 (LISTE )
container 14113 root 8u IPv4 98588 0t0 TCP 127.0.0.1:44009 (LISTEN)
docker-pr 68920 root 4u IPv6 213909 0t0 TCP *:9000 (LISTEN)
docker-pr 175427 root 4u IPv6 740622 0t0 TCP *:5432 (LISTEN)
Does anyone here have experience with the problem of selecting free ports for external applications?