diff --git a/crates/oxide_cli/src/main.rs b/crates/oxide_cli/src/main.rs index ca846285..e2daef49 100644 --- a/crates/oxide_cli/src/main.rs +++ b/crates/oxide_cli/src/main.rs @@ -9,7 +9,6 @@ use std::time::{Duration, Instant}; use ansi_term::Colour::Red; use clap::{Parser, Subcommand}; use oxide_cli::format_js_value; -use oxide_net::Endpoint; use oxide_cli::server::cleanup::{well_known_cleanup, CleanupOutcome}; use oxide_cli::server::client::send_control_request; use oxide_cli::server::log as server_log; @@ -26,6 +25,7 @@ use oxide_kernel::shape_forge::ShapeForge; use oxide_kernel::string_forge::PermInterner; use oxide_kernel::{kernel_error, kernel_info}; use oxide_log::{Level, SUBSYSTEM_COUNT}; +use oxide_net::Endpoint; use oxide_vm::vm::Vm; use oxide_vm::vm_error; use oxide_vm::JsValue; diff --git a/crates/oxide_cli/src/server/liveness.rs b/crates/oxide_cli/src/server/liveness.rs index 262edb80..8a65dfb9 100644 --- a/crates/oxide_cli/src/server/liveness.rs +++ b/crates/oxide_cli/src/server/liveness.rs @@ -354,7 +354,12 @@ mod tests { let sidecar_scan = sidecar.clone(); let socket_scan = socket.clone(); let scan_handle = std::thread::spawn(move || { - liveness_scan_with_waits(&sidecar_scan, &Endpoint::Unix(socket_scan), Duration::from_secs(5), Duration::from_secs(1)) + liveness_scan_with_waits( + &sidecar_scan, + &Endpoint::Unix(socket_scan), + Duration::from_secs(5), + Duration::from_secs(1), + ) }); // 主线程在窗口内删 sidecar(模拟旧 server 退出序列),扫描应判无操作。 std::thread::sleep(Duration::from_millis(200)); @@ -381,7 +386,12 @@ mod tests { sidecar::write_exclusive(&id, &sidecar).expect("写 sidecar 应成功"); // 注入短僵尸退出窗口(500 毫秒)加短杀进程等待(3 秒):子进程存活, // sidecar 不消失,扫描等窗口后杀进程。 - let outcome = liveness_scan_with_waits(&sidecar, &Endpoint::Unix(socket.clone()), Duration::from_millis(500), Duration::from_secs(3)); + let outcome = liveness_scan_with_waits( + &sidecar, + &Endpoint::Unix(socket.clone()), + Duration::from_millis(500), + Duration::from_secs(3), + ); assert_eq!(outcome, LivenessOutcome::Cleaned, "刻度匹配的存活进程应被杀且文件被删"); // 有界等待回收线程:子进程被杀后收尸即退出,不无限阻塞。 let deadline = Instant::now() + Duration::from_secs(5); @@ -410,8 +420,12 @@ mod tests { sidecar::write_exclusive(&id, &sidecar).expect("写 sidecar 应成功"); // 注入短僵尸退出窗口(500 毫秒)加短杀进程等待(300 毫秒):子进程忽略 // SIGTERM,扫描判杀进程失败,文件原样。 - let outcome = - liveness_scan_with_waits(&sidecar, &Endpoint::Unix(socket.clone()), Duration::from_millis(500), Duration::from_millis(300)); + let outcome = liveness_scan_with_waits( + &sidecar, + &Endpoint::Unix(socket.clone()), + Duration::from_millis(500), + Duration::from_millis(300), + ); assert_eq!(outcome, LivenessOutcome::KillFailed, "忽略 SIGTERM 应判杀进程失败"); assert!(sidecar.exists(), "sidecar 应原样"); assert!(!socket.exists(), "socket 文件应保持不存在"); diff --git a/crates/oxide_cli/src/server/server.rs b/crates/oxide_cli/src/server/server.rs index 28782160..dd65970f 100644 --- a/crates/oxide_cli/src/server/server.rs +++ b/crates/oxide_cli/src/server/server.rs @@ -212,9 +212,7 @@ pub fn run_server(config: &ServerConfig) -> Result<(), ServerError> { // 清理命令。两臂通用:TCP server 也写 sidecar,同端口裁决交给绑定失败。 match liveness::liveness_scan(&config.sidecar_path, &config.endpoint) { liveness::LivenessOutcome::Noop | liveness::LivenessOutcome::Cleaned => {} - liveness::LivenessOutcome::KillFailed => { - return Err(ServerError::ClaimRefused(ClaimResult::RefusedAmbiguous)) - } + liveness::LivenessOutcome::KillFailed => return Err(ServerError::ClaimRefused(ClaimResult::RefusedAmbiguous)), } // 认领 sidecar(启动顺序契约:先写 sidecar 再绑定监听器):同版本 @@ -1292,11 +1290,8 @@ mod tests { // sidecar(PID 存活且启动时刻刻度匹配,版本不匹配,认领判 // VersionMismatch)。 let listener = UnixListener::bind(unix_path(&config.endpoint)).expect("绑定模拟旧 server 应成功"); - sidecar::write_exclusive( - &sidecar::ServerIdentity::new(&config.endpoint, "0.0.0"), - &config.sidecar_path, - ) - .expect("写模拟 sidecar 应成功"); + sidecar::write_exclusive(&sidecar::ServerIdentity::new(&config.endpoint, "0.0.0"), &config.sidecar_path) + .expect("写模拟 sidecar 应成功"); // 模拟连接处理:接受循环,逐连接读一帧后回 Error 帧。须保持监听 // (真实 server 是 accept 循环):启动时 liveness 扫描与认领探活各 @@ -1325,11 +1320,8 @@ mod tests { let config = unique_paths("yield_hang"); let listener = UnixListener::bind(unix_path(&config.endpoint)).expect("绑定模拟旧 server 应成功"); - sidecar::write_exclusive( - &sidecar::ServerIdentity::new(&config.endpoint, "0.0.0"), - &config.sidecar_path, - ) - .expect("写模拟 sidecar 应成功"); + sidecar::write_exclusive(&sidecar::ServerIdentity::new(&config.endpoint, "0.0.0"), &config.sidecar_path) + .expect("写模拟 sidecar 应成功"); // 模拟连接处理:接受连接后挂住不回应(模拟挂起的旧 server)。 std::thread::spawn(move || { diff --git a/crates/oxide_cli/src/server/sidecar.rs b/crates/oxide_cli/src/server/sidecar.rs index 9cc63ee6..4b6d1db7 100644 --- a/crates/oxide_cli/src/server/sidecar.rs +++ b/crates/oxide_cli/src/server/sidecar.rs @@ -437,7 +437,11 @@ mod tests { #[test] fn parse_endpoint_two_forms() { let tcp = parse_endpoint("127.0.0.1:4242"); - assert_eq!(tcp, Endpoint::Tcp(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 4242)), "host:port 应得 TCP 臂"); + assert_eq!( + tcp, + Endpoint::Tcp(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 4242)), + "host:port 应得 TCP 臂" + ); let unix = parse_endpoint("/tmp/oxide-test.sock"); assert_eq!(unix, Endpoint::Unix(PathBuf::from("/tmp/oxide-test.sock")), "路径形态应得 Unix 臂"); } @@ -463,8 +467,12 @@ mod tests { let socket = dir.path("server.sock"); // 存活 server 必有 sidecar(启动顺序契约:先写 sidecar 再 bind endpoint)。 let listener = UnixListener::bind(&socket).expect("绑定监听者应成功"); - write_exclusive(&ServerIdentity::new(&Endpoint::Unix(socket.clone()), "0.0.0"), &sidecar).expect("写 sidecar 应成功"); - assert_eq!(claim_sidecar(&sidecar, &Endpoint::Unix(socket.clone()), "0.0.0"), ClaimResult::AlreadyRunning); + write_exclusive(&ServerIdentity::new(&Endpoint::Unix(socket.clone()), "0.0.0"), &sidecar) + .expect("写 sidecar 应成功"); + assert_eq!( + claim_sidecar(&sidecar, &Endpoint::Unix(socket.clone()), "0.0.0"), + ClaimResult::AlreadyRunning + ); drop(listener); } @@ -477,8 +485,12 @@ mod tests { let socket = dir.path("server.sock"); let listener = UnixListener::bind(&socket).expect("绑定监听者应成功"); // 旧 sidecar 版本与本进程版本不同:比对判不匹配。 - write_exclusive(&ServerIdentity::new(&Endpoint::Unix(socket.clone()), "0.0.0"), &sidecar).expect("写 sidecar 应成功"); - assert_eq!(claim_sidecar(&sidecar, &Endpoint::Unix(socket.clone()), "0.0.1"), ClaimResult::VersionMismatch); + write_exclusive(&ServerIdentity::new(&Endpoint::Unix(socket.clone()), "0.0.0"), &sidecar) + .expect("写 sidecar 应成功"); + assert_eq!( + claim_sidecar(&sidecar, &Endpoint::Unix(socket.clone()), "0.0.1"), + ClaimResult::VersionMismatch + ); drop(listener); } @@ -514,7 +526,10 @@ mod tests { // PID 与启动时刻刻度都是本进程的:进程活且刻度匹配。 let id = ServerIdentity::new(&Endpoint::Unix(socket.clone()), "0.0.0"); write_exclusive(&id, &sidecar).expect("写 sidecar 应成功"); - assert_eq!(claim_sidecar(&sidecar, &Endpoint::Unix(socket.clone()), "0.0.0"), ClaimResult::RefusedAmbiguous); + assert_eq!( + claim_sidecar(&sidecar, &Endpoint::Unix(socket.clone()), "0.0.0"), + ClaimResult::RefusedAmbiguous + ); } /// 认领分支:损坏文件加死 socket 判陈旧,sidecar 重建。 @@ -555,7 +570,10 @@ mod tests { let socket = dir.path("server.sock"); let listener = UnixListener::bind(&socket).expect("绑定监听者应成功"); fs::write(&sidecar, "not json at all").expect("写损坏文件应成功"); - assert_eq!(claim_sidecar(&sidecar, &Endpoint::Unix(socket.clone()), "0.0.0"), ClaimResult::VersionMismatch); + assert_eq!( + claim_sidecar(&sidecar, &Endpoint::Unix(socket.clone()), "0.0.0"), + ClaimResult::VersionMismatch + ); drop(listener); }