From debe7dabe33f45d8e64ed716fa7d0deaed4ede3c Mon Sep 17 00:00:00 2001 From: xfy Date: Thu, 16 Jul 2026 13:22:49 +0800 Subject: [PATCH] =?UTF-8?q?fix(test):=20Docker=20=E9=9B=86=E6=88=90?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E5=9C=A8=E6=97=A0=20daemon=20=E7=8E=AF?= =?UTF-8?q?=E5=A2=83=E4=BC=98=E9=9B=85=E8=B7=B3=E8=BF=87=E8=80=8C=E9=9D=9E?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit docker.rs 的 4 个 test_run_in_container_* 此前直接 unwrap Docker 客户端, 在没有 Docker daemon 的环境(如 CI、纯服务端交叉编译检查)会 panic 失败, 拖累整套 cargo test 的退出码——即便这些测试本就无法在那里运行。 加 require_docker() 守卫:socket 缺失(DOCKER_CLIENT == None)或 daemon 无响应(轻量 version() 探测)时返回 None,测试 eprintln + 提前 return。 选动态探测而非 #[ignore]:#[ignore] 会在所有环境一律跳过、需 cargo test --ignored 显式触发;探测守卫让测试在有 Docker 时自动运行, 在无 Docker 的 CI 上静默放行,且在 --nocapture 下可见跳过原因。 验证:cargo test --bin yggdrasil 从 535 passed / 4 failed → 539 passed / 0 failed。 --- src/infra/docker.rs | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/infra/docker.rs b/src/infra/docker.rs index a2f5b3e..ad76470 100644 --- a/src/infra/docker.rs +++ b/src/infra/docker.rs @@ -696,9 +696,27 @@ mod tests { assert_eq!(host_config.memory_swap, Some(512 * 1024 * 1024)); } + /// 探测 Docker daemon 是否可用:socket 缺失(`DOCKER_CLIENT == None`)或 + /// daemon 无响应时返回 `None`。集成测试用它做动态守卫——daemon 在则跑, + /// 不在则显式跳过(eprintln + 提前 return),而非 panic 失败。 + /// + /// 这比 `#[ignore]` 更合适:`#[ignore]` 会在所有环境(含有 Docker 的开发机) + /// 一律跳过、且需 `cargo test --ignored` 显式触发;探测守卫让这些测试在 + /// 有 Docker 时自动运行、在无 Docker 的 CI 上静默放行。 + async fn require_docker() -> Option<&'static Docker> { + let docker = DOCKER_CLIENT.as_ref()?; + // socket 在但 daemon 挂了的情况靠这一步轻量只读调用兜住。 + docker.version().await.ok()?; + Some(docker) + } + #[tokio::test] #[serial_test::serial] async fn test_run_in_container_success() { + if require_docker().await.is_none() { + eprintln!("skip: Docker daemon 不可用(未安装或未运行)"); + return; + } let limits = ResourceLimits { cpu_cores: 1.0, memory_mb: 128, @@ -725,6 +743,10 @@ mod tests { #[tokio::test] #[serial_test::serial] async fn test_run_in_container_output_truncation() { + if require_docker().await.is_none() { + eprintln!("skip: Docker daemon 不可用(未安装或未运行)"); + return; + } let limits = ResourceLimits { cpu_cores: 1.0, memory_mb: 128, @@ -751,6 +773,10 @@ mod tests { #[tokio::test] #[serial_test::serial] async fn test_run_in_container_timeout() { + if require_docker().await.is_none() { + eprintln!("skip: Docker daemon 不可用(未安装或未运行)"); + return; + } let limits = ResourceLimits { cpu_cores: 1.0, memory_mb: 128, @@ -774,7 +800,13 @@ mod tests { #[serial_test::serial] async fn test_run_in_container_cancellation() { use bollard::query_parameters::ListContainersOptions; - let docker = get_docker().expect("test requires a running Docker daemon"); + let docker = match require_docker().await { + Some(d) => d, + None => { + eprintln!("skip: Docker daemon 不可用(未安装或未运行)"); + return; + } + }; let before = docker .list_containers(Some(ListContainersOptions {