Files
shell-rs/src/testing.rs
T
XuzandClaude Opus 5.5 2576b46e43 Docker:右侧栏的 Docker 工具,管理容器、卷、镜像和网络
- 容器按 compose 项目分组,可启停、重启,查看详情和日志;卷、镜像、网络可查看详情和删除
- 工具图标换成 Docker 的鲸鱼;单元测试起子进程时加锁,修好外部 CLI 测试的偶发失败

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 18:18:27 +08:00

43 lines
1.5 KiB
Rust

//! What the unit tests share: starting processes without upsetting the
//! tests that need a closed socket to stay closed.
use std::process::{Command, Output};
use std::sync::{Mutex, MutexGuard};
static FORKS: Mutex<()> = Mutex::new(());
/// Hold while starting a process, or while making a socket that must refuse
/// connections once it is closed.
///
/// macOS makes a socket and marks it not to be handed to started programs
/// in two steps. A process another test starts in between, on its own
/// thread, gets a copy of the socket and keeps it open as long as it runs:
/// a listener the test has closed still takes connections. A process gets
/// its copies only as it starts, so holding this around starting one and
/// around making the socket keeps the two apart.
pub fn no_forks() -> MutexGuard<'static, ()> {
FORKS
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner())
}
/// Run `script` with this machine's `sh`, with `PATH` set to `path` when
/// given.
pub fn sh(script: &str, path: Option<&str>) -> Output {
let mut command = Command::new("sh");
command.args(["-c", script]);
if let Some(path) = path {
command.env("PATH", path);
}
let _forks = no_forks();
command.output().expect("sh runs")
}
/// Whether this machine's `sh` reads `script` without a syntax error.
pub fn sh_accepts(script: &str) -> bool {
let mut command = Command::new("sh");
command.args(["-n", "-c", script]);
let _forks = no_forks();
command.status().expect("sh runs").success()
}