test(daemon): serialize heavy socket/PTY integration tests
Process-wide serial lock around the socket-binding and PTY-spawning integration tests in spaceshd. Running several at once on a many-core box starved each other's async tasks and tripped timing assumptions, causing ~1/10 flakes under cargo test --workspace. Unit tests stay parallel. 0/20 spaceshd + 0/5 workspace runs after the change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,24 @@ mod surface;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
/// Test-only support shared across the crate's test modules.
|
||||
#[cfg(test)]
|
||||
pub(crate) mod test_support {
|
||||
use std::sync::{Mutex, MutexGuard};
|
||||
|
||||
/// Process-wide serialization lock for the heavy socket/PTY integration tests.
|
||||
/// These bind sockets and spawn real PTYs/processes; running several at once on a
|
||||
/// many-core box starves each other's tasks and trips timing assumptions. Unit
|
||||
/// tests stay parallel; only guarded integration tests serialize on this lock.
|
||||
static SERIAL: Mutex<()> = Mutex::new(());
|
||||
|
||||
/// Acquire the serial lock for the duration of a test. Poison-tolerant so one
|
||||
/// panicking test does not cascade-fail the rest.
|
||||
pub(crate) fn serial() -> MutexGuard<'static, ()> {
|
||||
SERIAL.lock().unwrap_or_else(|e| e.into_inner())
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let arg = std::env::args().nth(1);
|
||||
|
||||
@@ -323,6 +323,7 @@ mod tests {
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn open_new_surface_attach_streams_output() {
|
||||
let _serial = crate::test_support::serial();
|
||||
let dir = tempdir_path();
|
||||
let sock = dir.join("sock");
|
||||
let sock_for_task = sock.clone();
|
||||
@@ -360,6 +361,7 @@ mod tests {
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn unknown_surface_returns_not_found() {
|
||||
let _serial = crate::test_support::serial();
|
||||
let dir = tempdir_path();
|
||||
let sock = dir.join("sock");
|
||||
let sock_for_task = sock.clone();
|
||||
@@ -401,6 +403,7 @@ mod tests {
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn reattach_returns_snapshot_with_prior_output() {
|
||||
let _serial = crate::test_support::serial();
|
||||
let dir = tempdir_path();
|
||||
let sock = dir.join("sock");
|
||||
let sock_for_task = sock.clone();
|
||||
|
||||
@@ -132,6 +132,7 @@ mod tests {
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn attach_receives_output() {
|
||||
let _serial = crate::test_support::serial();
|
||||
let pty = PtyHandle::spawn(spec("printf HELLO; sleep 0.3")).unwrap();
|
||||
let (exit_tx, _exit_rx) = mpsc::unbounded_channel();
|
||||
let handle = spawn_surface(SurfaceId("s_1".into()), WorkspaceId("w_1".into()), pty, 80, 24, exit_tx);
|
||||
@@ -155,6 +156,7 @@ mod tests {
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn exit_is_reported() {
|
||||
let _serial = crate::test_support::serial();
|
||||
let pty = PtyHandle::spawn(spec("exit 7")).unwrap();
|
||||
let (exit_tx, mut exit_rx) = mpsc::unbounded_channel();
|
||||
let _handle = spawn_surface(SurfaceId("s_2".into()), WorkspaceId("w_1".into()), pty, 80, 24, exit_tx);
|
||||
@@ -166,6 +168,7 @@ mod tests {
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn attach_snapshot_reflects_prior_output() {
|
||||
let _serial = crate::test_support::serial();
|
||||
let pty = PtyHandle::spawn(spec("printf SNAPME; sleep 0.5")).unwrap();
|
||||
let (exit_tx, _exit_rx) = mpsc::unbounded_channel();
|
||||
let handle = spawn_surface(SurfaceId("s_s".into()), WorkspaceId("w_1".into()), pty, 80, 24, exit_tx);
|
||||
|
||||
Reference in New Issue
Block a user