From 9ee03e36f4e58fa883d5fdc8cb50d127c560e722 Mon Sep 17 00:00:00 2001 From: JJ Liebig Date: Wed, 14 Oct 2026 16:43:54 +0200 Subject: [PATCH] test: deflake federated remote restart on loaded CI (#5276) The client_mode::federated_client_starts_without_local_and_survives_its_restart integration test fails intermittently on the ubuntu (and macos) runners at two polling budgets: - "remote must be usable before Local exists" - "remote reconnect N must restore visible input and preserve the shell" Both budgets are shorter than the client's own connection and activation deadlines. Saved-SSH discovery probes are bounded by a 15s SSH command timeout, the remote handshake read timeout is 60s, and each endpoint activation phase has a 5s deadline that can retry. Under a loaded runner the client can still be legitimately connecting, or holding pane input closed through an activation retry, when the test gives up. Give the remote-readiness and remote-input waits budgets that exceed those deadlines. The waits still return as soon as the observed condition holds, so only the failure path gets slower. The intentionally tight waits that prove Local does not wait for a stalled remote stay at 3s. --- tests/client_mode.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tests/client_mode.rs b/tests/client_mode.rs index 9d6e9ecab..5b994bb39 100644 --- a/tests/client_mode.rs +++ b/tests/client_mode.rs @@ -984,6 +984,13 @@ fn federated_launch_opens_local_directly_while_saved_ssh_is_unavailable() { } } +/// CI runners are heavily loaded, and a saved remote can need several connection +/// attempts plus activation retries (each activation phase has its own deadline) +/// before it is usable. These budgets only slow the failure path: every +/// `wait_until` below returns as soon as its condition holds. +const REMOTE_READY_TIMEOUT: Duration = Duration::from_secs(30); +const REMOTE_INPUT_TIMEOUT: Duration = Duration::from_secs(20); + #[test] fn federated_client_starts_without_local_and_survives_its_restart() { use std::os::unix::fs::PermissionsExt; @@ -1067,7 +1074,7 @@ fn federated_client_starts_without_local_and_survives_its_restart() { terminal_screen::text(&bytes, 80, 24) }; assert!( - wait_until(Duration::from_secs(12), Duration::from_millis(20), || { + wait_until(REMOTE_READY_TIMEOUT, Duration::from_millis(20), || { screen_text().contains("REMOTE_INITIAL_FRAME") }), "remote must be usable before Local exists: {}", @@ -1098,7 +1105,7 @@ fn federated_client_starts_without_local_and_survives_its_restart() { "remote reconnect {cycle} must restore the visible screen without switching machines" ); assert!( - wait_until(Duration::from_secs(8), Duration::from_millis(100), || { + wait_until(REMOTE_INPUT_TIMEOUT, Duration::from_millis(100), || { if screen_text().contains(&format!("REMOTE_ALIVE_INPUT_{cycle}")) { return true; } @@ -1134,7 +1141,7 @@ fn federated_client_starts_without_local_and_survives_its_restart() { local.close_master(); drop(local); assert!( - wait_until(Duration::from_secs(8), Duration::from_millis(20), || { + wait_until(REMOTE_INPUT_TIMEOUT, Duration::from_millis(20), || { if screen_text().contains("REMOTE_SURVIVED") { return true; } @@ -1260,7 +1267,7 @@ fn federated_client_starts_without_local_and_survives_its_restart() { ); // A coherent frame precedes the final host-effects fence; input stays gated until then. assert!( - wait_until(Duration::from_secs(8), Duration::from_millis(100), || { + wait_until(REMOTE_INPUT_TIMEOUT, Duration::from_millis(100), || { if screen_text().contains("LOCAL_INPUT_RECOVERED") { return true; }