Files
BrowserSkill/crates/bsk-cli/tests/foreground_smoke.rs
2026-06-22 17:36:26 +08:00

68 lines
1.9 KiB
Rust

//! Smoke-test the foreground daemon: spawn the bin, wait for the heartbeat,
//! send SIGTERM (Unix) / CTRL_BREAK (Windows), and verify a clean exit.
#![cfg(unix)]
use std::process::{Command, Stdio};
use std::time::{Duration, Instant};
use tempfile::TempDir;
fn bsk_bin() -> std::path::PathBuf {
let bin = env!("CARGO_BIN_EXE_bsk");
std::path::PathBuf::from(bin)
}
#[test]
fn foreground_daemon_starts_and_stops() {
let tmp = TempDir::new().unwrap();
let home = tmp.path().join("bsk");
std::fs::create_dir_all(&home).unwrap();
let mut child = Command::new(bsk_bin())
.args([
"daemon",
"start",
"--foreground",
"--port",
"0",
"--daemon-idle",
"60s",
])
.env("BSK_HOME", &home)
.env("RUST_LOG", "info")
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
.expect("spawn bsk daemon start --foreground");
// Give the process a generous moment to come up and install signal
// handlers (cargo test on cold caches can stagger spawn significantly).
std::thread::sleep(Duration::from_millis(1500));
assert!(
child.try_wait().expect("try_wait").is_none(),
"daemon should still be running"
);
let pid = child.id() as i32;
// SAFETY: sending SIGTERM to our own child.
unsafe {
let _ = libc::kill(pid, libc::SIGTERM);
}
let started = Instant::now();
let status = loop {
if let Some(status) = child.try_wait().expect("try_wait after SIGTERM") {
break status;
}
if started.elapsed() > Duration::from_secs(5) {
let _ = child.kill();
panic!("daemon did not exit within 5s of SIGTERM");
}
std::thread::sleep(Duration::from_millis(50));
};
assert!(
status.success() || status.code() == Some(0),
"daemon exited with non-success status: {status:?}"
);
}