From 7d1be82417e4a0a28288e1b94b7fc6fbc2ea2faa Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Thu, 5 Nov 2026 10:24:38 -0500 Subject: [PATCH] joule-moq-relay: the loop-of-relays test starts again on new ports when one it chose was taken The three relays of a_loop_of_relays each dial the next, so their ports are chosen before any of them listens, and another test can bind one in between: CI's linux-arm64 leg refused a start with "Address already in use" (#640). A start refused for a port in use is now tried again on three new ports, at most five times; any other refusal fails the test, and what the test holds of the loop is unchanged. Co-Authored-By: Claude Opus 5.5 --- .../crates/joule-moq-relay/tests/cascade.rs | 39 +++++++++++++------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/joule-code/joule-code-rs/crates/joule-moq-relay/tests/cascade.rs b/joule-code/joule-code-rs/crates/joule-moq-relay/tests/cascade.rs index 67cb910d9..0fa455f9e 100644 --- a/joule-code/joule-code-rs/crates/joule-moq-relay/tests/cascade.rs +++ b/joule-code/joule-code-rs/crates/joule-moq-relay/tests/cascade.rs @@ -439,20 +439,35 @@ async fn a_loop_of_relays() { async fn relay_loop() { // A dials B, B dials C, C dials A, each routing everything under live: a loop. - let ports = [free_port(), free_port(), free_port()]; - let ws = |i: usize| format!("ws://127.0.0.1:{}/moq", ports[i]); - let mk = |i: usize| { - let next = (i + 1) % 3; - let url = ws(next); - move |c: &mut RelayConfig| { - quick(c); - c.websocket_listen = Some(format!("127.0.0.1:{}", ports[i]).parse().unwrap()); - c.upstream = vec![upstream(url.clone(), UpstreamTransport::WebSocket, &[&["live"]])]; + // Each relay dials the next, so the three ports are chosen before any of them listens, and + // another test can bind one in between: a start refused for a port in use is tried again + // on three new ports, at most five times. Anything else a start refuses fails the test. + let (ra, rb, rc) = { + let mut attempt = 0; + 'start: loop { + attempt += 1; + let ports = [free_port(), free_port(), free_port()]; + let mut started = Vec::new(); + for i in 0..3 { + let mut c = RelayConfig::loopback(); + quick(&mut c); + c.websocket_listen = Some(format!("127.0.0.1:{}", ports[i]).parse().unwrap()); + c.upstream = vec![upstream(format!("ws://127.0.0.1:{}/moq", ports[(i + 1) % 3]), UpstreamTransport::WebSocket, &[&["live"]])]; + match RelayServer::start(c).await { + Ok(r) => started.push(r), + Err(e) if attempt < 5 && e.contains("Address already in use") => { + for r in started { + r.shutdown().await; + } + continue 'start; + } + Err(e) => panic!("the relay starts: {e}"), + } + } + let mut it = started.into_iter(); + break (it.next().unwrap(), it.next().unwrap(), it.next().unwrap()); } }; - let ra = relay(mk(0)).await; - let rb = relay(mk(1)).await; - let rc = relay(mk(2)).await; for r in [&ra, &rb, &rc] { linked(r, 1).await; } -- 2.54.0 (Apple Git-157)