From 6686fcdded540cfae130da1cd7f67a672815d517 Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Thu, 2 Jul 2026 22:35:23 +0000 Subject: [PATCH] =?UTF-8?q?fix(gamestream/tests):=20sender=5Fdelivers=5Fba?= =?UTF-8?q?tches=20flaked=20under=20CI=20load=20=E2=80=94=20burst=20overfl?= =?UTF-8?q?owed=20the=20default=20socket=20buffer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The test burst 3×100 1200 B datagrams into an undrained loopback socket: at ~2.5 KB kernel truesize each, the default ~212 KB rmem holds only ~80, so on a starved CI runner (parallel release builds) the kernel silently dropped the overflow and the recv loop could never reach 300 — surfacing as WouldBlock after the 3 s timeout. Size the burst (3×20) to fit the default buffer even with zero concurrent draining, and give recv a starvation-tolerant 10 s. Co-Authored-By: Claude Fable 5 --- crates/punktfunk-host/src/gamestream/stream.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/crates/punktfunk-host/src/gamestream/stream.rs b/crates/punktfunk-host/src/gamestream/stream.rs index a3a775e..63ecd0f 100644 --- a/crates/punktfunk-host/src/gamestream/stream.rs +++ b/crates/punktfunk-host/src/gamestream/stream.rs @@ -820,8 +820,10 @@ mod tests { #[test] fn sender_delivers_batches() { let rx_sock = UdpSocket::bind("127.0.0.1:0").unwrap(); + // Generous: on a CI host saturated by parallel release builds, this thread can be + // starved for whole seconds between recv() wakeups. rx_sock - .set_read_timeout(Some(Duration::from_secs(3))) + .set_read_timeout(Some(Duration::from_secs(10))) .unwrap(); let tx_sock = UdpSocket::bind("127.0.0.1:0").unwrap(); tx_sock.connect(rx_sock.local_addr().unwrap()).unwrap(); @@ -837,10 +839,15 @@ mod tests { ) .unwrap(); - // 3 frames of 100 packets, content-tagged for verification. + // 3 frames of 20 packets, content-tagged for verification. The TOTAL burst must fit + // the receive socket's DEFAULT buffer even if this thread never drains concurrently + // (a starved CI runner): a 1200 B datagram costs ~2.5 KB kernel truesize, and the + // default rmem (~212 KB) holds only ~80 — a bigger burst gets silently dropped by + // the kernel and the test can never complete (the old 3×100 flaked exactly there). + const PER_FRAME: usize = 20; let mut sent = Vec::new(); for f in 0..3u8 { - let batch: PacketBatch = (0..100u8) + let batch: PacketBatch = (0..PER_FRAME as u8) .map(|i| { let mut p = vec![0u8; 1200]; p[0] = f; @@ -859,10 +866,10 @@ mod tests { let n = rx_sock.recv(&mut buf).expect("packet within timeout"); assert_eq!(n, 1200); let (f, i) = (buf[0] as usize, buf[1] as usize); - assert_eq!(&buf[..n], &sent[f * 100 + i][..], "payload intact"); + assert_eq!(&buf[..n], &sent[f * PER_FRAME + i][..], "payload intact"); got += 1; } - assert_eq!(got, 300); + assert_eq!(got, 3 * PER_FRAME); assert!(running.load(Ordering::SeqCst), "no spurious client-gone"); } }