Files
OxideJS-New/crates/oxide_cli/tests/server_signal_term.rs
T

69 lines
3.0 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! 信号处理集成测试(SIGTERM):真实信号路径触发优雅退出。
//!
//! 独立进程、进程内唯一 server 与唯一信号处理器:`ctrlc` 的处理器注册是
//! 进程级一次性的,信号投递无歧义,测试确定。SIGINT 路径见
//! `server_signal_int.rs`(同型,独立进程)。
use std::process::Command;
use std::thread::JoinHandle;
use std::time::{Duration, Instant};
use oxide_cli::server::server::{run_server, ServerConfig, ServerError};
/// 唯一临时路径(进程号加测试名):单进程内唯一,进程间以进程号隔离。
/// worker 数取小值 2:与既有单测同口径,大值徒增预热成本。
fn unique_paths(test_name: &str) -> ServerConfig {
let dir = std::env::temp_dir().join(format!("oxide_server_signal_term_{}_{}", std::process::id(), test_name));
std::fs::create_dir_all(&dir).expect("测试目录创建应成功");
ServerConfig {
socket_path: dir.join("server.sock"),
sidecar_path: dir.join("sidecar.json"),
worker_count: 2,
version: env!("CARGO_PKG_VERSION").to_string(),
}
}
/// 后台线程起真实 run_server,等 socket 文件出现(bind 成功即就绪,
/// 且蕴含信号处理器已注册——注册在绑定之前)。
fn start_server(config: ServerConfig) -> JoinHandle<Result<(), ServerError>> {
let server_config = config.clone();
let handle = std::thread::spawn(move || run_server(&server_config));
let deadline = Instant::now() + Duration::from_secs(10);
while !config.socket_path.exists() {
assert!(Instant::now() < deadline, "socket 文件未出现");
std::thread::sleep(Duration::from_millis(10));
}
handle
}
/// 给本测试进程发 SIGTERM(`kill` 二进制与 sidecar 的 `pid_alive` 同一口径)。
fn send_sigterm() {
let status = Command::new("kill")
.args(["-TERM", &std::process::id().to_string()])
.status()
.expect("kill 应可执行");
assert!(status.success(), "kill -TERM 应成功:{status:?}");
}
/// 等 server 线程退出,断言正常退出与 sidecar、socket 文件均被删除。
fn wait_shutdown(config: &ServerConfig, handle: JoinHandle<Result<(), ServerError>>) {
let deadline = Instant::now() + Duration::from_secs(30);
while !handle.is_finished() {
assert!(Instant::now() < deadline, "server 线程应在有界时间内退出");
std::thread::sleep(Duration::from_millis(10));
}
let result = handle.join().expect("server 线程应正常退出");
assert!(result.is_ok(), "server 应正常退出:{result:?}");
assert!(!config.sidecar_path.exists(), "sidecar 文件应被删除");
assert!(!config.socket_path.exists(), "socket 文件应被删除");
}
/// SIGTERM 触发优雅退出:在途归零、删 sidecar 与 socket 文件。
#[test]
fn sigterm_graceful_shutdown() {
let config = unique_paths("sigterm");
let handle = start_server(config.clone());
send_sigterm();
wait_shutdown(&config, handle);
}