fix(desktop): isolate relay admission tests (#5221)

## Summary

- serialize the relay error-message test with all other tests mutating
the process-wide admission gate
- clear its 300-second rate-limit expiry after the assertion
- prevent the paused-time waiter test from observing another test's
state

## Root cause

`relay::tests::oversized_hint_is_capped_in_relay_error_message_string`
arms the process-wide gate for 300 seconds without taking `TEST_SERIAL`
or resetting it. In a parallel test run,
`relay_admission::tests::concurrent_429_extends_the_window_for_parked_waiters`
can observe that expiry, producing the reported `300.001s` instead of
`5s`.

## Validation

- focused admission suite + relay error test repeated 10 times
- pre-push `desktop-tauri-checks` passed, including the full Rust
workspace suite
- `branch-skew` passed

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
This commit is contained in:
Wes
2026-08-07 16:09:07 -06:00
committed by GitHub
parent dcc1231d6d
commit 74b913cff8
2 changed files with 10 additions and 3 deletions

View File

@@ -652,9 +652,12 @@ mod tests {
#[tokio::test]
async fn oversized_hint_is_capped_in_relay_error_message_string() {
use crate::relay_admission::MAX_HINT_SECONDS;
use crate::relay_admission::{reset_rate_limit_gate, MAX_HINT_SECONDS, TEST_SERIAL};
use std::io::{Read as _, Write as _};
let _serial = TEST_SERIAL.lock().await;
reset_rate_limit_gate();
// Use a std::net listener on a std::thread — the same pattern as the
// relay_admission loopback tests. This avoids two races that cause CI
// failures with tokio::net + into_std():
@@ -702,6 +705,7 @@ mod tests {
!msg.contains(&oversized.to_string()),
"raw oversized hint must not appear in the message string"
);
reset_rate_limit_gate();
}
// ── effective_agent_relay_url: legacy pin ignored ─────────────────────────

View File

@@ -42,6 +42,10 @@ pub const MAX_HINT_SECONDS: u64 = 300;
static GATE_EXPIRY: Mutex<Option<Instant>> = Mutex::new(None);
// The gate is process-wide, so every test that can arm it must serialize.
#[cfg(test)]
pub(crate) static TEST_SERIAL: tokio::sync::Mutex<()> = tokio::sync::Mutex::const_new(());
/// Arm (or extend) the admission gate from a relay 429.
///
/// `retry_in_seconds` is the parsed `retry in Ns` hint, if the relay provided
@@ -105,9 +109,8 @@ mod tests {
use super::*;
// The gate is a process-wide static shared by every test in this binary,
// so all gate tests serialize on one async lock to keep armed expiries
// so all tests that arm it serialize on one async lock to keep expiries
// from bleeding between parallel test threads.
pub(crate) static TEST_SERIAL: tokio::sync::Mutex<()> = tokio::sync::Mutex::const_new(());
#[tokio::test(start_paused = true)]
async fn wait_returns_immediately_when_gate_is_inactive() {