From d44269b12643b5f9905a284a898c07ece9971c23 Mon Sep 17 00:00:00 2001 From: politerealism Date: Mon, 28 Sep 2026 13:50:13 -0400 Subject: [PATCH 1/2] test(podman): move podman_preflight into driver-podman integration tests podman_preflight verifies that openshell-driver-podman fails fast when its Podman socket is unreachable. It only needs the standalone driver binary, not a gateway, so it never fit the gateway-backed e2e-podman harness it lived under and never ran anywhere in CI. Move it into crates/openshell-driver-podman/tests/ as a plain Cargo integration test. It now runs via the existing required workspace test job with no special mise task, workflow step, or coverage exception. Signed-off-by: politerealism --- Cargo.lock | 1 + crates/openshell-driver-podman/Cargo.toml | 1 + .../tests/podman_preflight.rs | 70 +++++++++---------- e2e/rust/Cargo.toml | 5 -- tests/artifacts.nix | 4 -- 5 files changed, 37 insertions(+), 44 deletions(-) rename {e2e/rust => crates/openshell-driver-podman}/tests/podman_preflight.rs (64%) diff --git a/Cargo.lock b/Cargo.lock index c6330b8897..0854d0bf41 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4264,6 +4264,7 @@ dependencies = [ "serde_json", "tar", "temp-env", + "tempfile", "thiserror 2.0.20", "tokio", "tokio-stream", diff --git a/crates/openshell-driver-podman/Cargo.toml b/crates/openshell-driver-podman/Cargo.toml index c49c309f65..18b1928c33 100644 --- a/crates/openshell-driver-podman/Cargo.toml +++ b/crates/openshell-driver-podman/Cargo.toml @@ -51,6 +51,7 @@ openshell-otel-test-support = { path = "../openshell-otel-test-support" } opentelemetry_sdk = { workspace = true, features = ["testing"] } prost-types = { workspace = true } temp-env = "0.3" +tempfile = "3" tokio = { workspace = true, features = ["test-util"] } [lints] diff --git a/e2e/rust/tests/podman_preflight.rs b/crates/openshell-driver-podman/tests/podman_preflight.rs similarity index 64% rename from e2e/rust/tests/podman_preflight.rs rename to crates/openshell-driver-podman/tests/podman_preflight.rs index afb3bc1c38..37ea37dfdc 100644 --- a/e2e/rust/tests/podman_preflight.rs +++ b/crates/openshell-driver-podman/tests/podman_preflight.rs @@ -1,49 +1,47 @@ // SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -#![cfg(feature = "e2e-podman")] - -//! Podman driver daemon-unavailable e2e tests. +//! Podman driver daemon-unavailable integration tests. //! //! These tests verify that `openshell-driver-podman` fails fast with an //! actionable error when it cannot reach a Podman API socket, instead of //! hanging or silently serving gRPC against a dead connection. //! -//! The tests do NOT require a running Podman daemon or gateway — they point +//! They do NOT require a running Podman daemon or gateway — they point //! `--podman-socket` at a path that is guaranteed not to exist to simulate -//! the daemon being unavailable. +//! the daemon being unavailable. As a plain Cargo integration test in this +//! crate, this runs via the normal `cargo test -p openshell-driver-podman` +//! lane with no special CI wiring: Cargo provides `CARGO_BIN_EXE_` for +//! this crate's own `[[bin]]` target automatically. -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::time::{Duration, Instant}; -use openshell_e2e::harness::output::strip_ansi; +/// Strip ANSI escape codes (e.g. colors) from a string, for readable failure +/// messages. Not required for the assertions below to pass — the driver's +/// own tracing output carries ANSI codes even when captured non-interactively, +/// but they never fragment the substrings these tests check for — this is +/// purely so a failed assertion's `{clean}` output is readable. +fn strip_ansi(s: &str) -> String { + let mut out = String::with_capacity(s.len()); + let mut chars = s.chars().peekable(); -/// Locate the workspace root by walking up from this crate's manifest directory. -fn workspace_root() -> PathBuf { - Path::new(env!("CARGO_MANIFEST_DIR")) - .ancestors() - .nth(2) - .expect("failed to resolve workspace root from CARGO_MANIFEST_DIR") - .to_path_buf() -} + while let Some(c) = chars.next() { + if c == '\x1b' { + if chars.peek() == Some(&'[') { + chars.next(); + for c in chars.by_ref() { + if c.is_ascii_alphabetic() { + break; + } + } + } + } else { + out.push(c); + } + } -/// Return the path to the `openshell-driver-podman` binary. -/// -/// Uses `OPENSHELL_EXTERNAL_DRIVER_BIN` when set (the same env var the shell -/// e2e harness uses for prebuilt standalone driver artifacts), otherwise -/// expects the binary at `/target/debug/openshell-driver-podman`. -fn driver_podman_bin() -> PathBuf { - let bin = std::env::var_os("OPENSHELL_EXTERNAL_DRIVER_BIN").map_or_else( - || workspace_root().join("target/debug/openshell-driver-podman"), - PathBuf::from, - ); - assert!( - bin.is_file(), - "openshell-driver-podman binary not found at {} — set OPENSHELL_EXTERNAL_DRIVER_BIN \ - or run `cargo build -p openshell-driver-podman` first", - bin.display() - ); - bin + out } /// Run `openshell-driver-podman` pointed at a Podman socket that does not @@ -53,17 +51,19 @@ fn driver_podman_bin() -> PathBuf { /// socket briefly re-activating), so this can take several seconds. async fn run_with_unreachable_podman_socket() -> (String, i32, Duration, PathBuf) { let tmpdir = tempfile::tempdir().expect("create isolated socket dir"); - let missing_socket = tmpdir.path().join("openshell-e2e-nonexistent-podman.sock"); + let missing_socket = tmpdir + .path() + .join("openshell-driver-podman-nonexistent.sock"); let start = Instant::now(); - let mut cmd = tokio::process::Command::new(driver_podman_bin()); + let mut cmd = tokio::process::Command::new(env!("CARGO_BIN_EXE_openshell-driver-podman")); cmd.arg("--podman-socket") .arg(&missing_socket) .kill_on_drop(true) .stdout(std::process::Stdio::piped()) .stderr(std::process::Stdio::piped()); - let output = tokio::time::timeout(Duration::from_secs(60), cmd.output()) + let output = tokio::time::timeout(Duration::from_mins(1), cmd.output()) .await .expect("openshell-driver-podman should exit instead of hanging") .expect("spawn openshell-driver-podman"); diff --git a/e2e/rust/Cargo.toml b/e2e/rust/Cargo.toml index b492c8ac86..6868193431 100644 --- a/e2e/rust/Cargo.toml +++ b/e2e/rust/Cargo.toml @@ -93,11 +93,6 @@ name = "podman_host_gateway" path = "tests/podman_host_gateway.rs" required-features = ["e2e-podman"] -[[test]] -name = "podman_preflight" -path = "tests/podman_preflight.rs" -required-features = ["e2e-podman"] - [[test]] name = "podman_corporate_proxy" path = "tests/podman_corporate_proxy.rs" diff --git a/tests/artifacts.nix b/tests/artifacts.nix index c3017a5da5..c86d8f6d30 100644 --- a/tests/artifacts.nix +++ b/tests/artifacts.nix @@ -116,10 +116,6 @@ let "podman_corporate_proxy" "podman_gateway_start" "podman_oci_identity" - # This validates the standalone driver binary's daemon-unavailable path and - # belongs in the Podman driver crate's integration tests. The E2E archive - # does not contain `openshell-driver-podman`. - "podman_preflight" "provider_auto_create" # The provider-refresh feature suite covers revoked Keycloak grants. This # binary instead covers stable workload handles across repeated rotations From b9c4f2cf742f74a9f940be7562e8ff9d053e52ac Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Mon, 28 Sep 2026 21:15:30 +0200 Subject: [PATCH 2/2] test(podman): make preflight diagnostics portable Signed-off-by: Evan Lezar --- .../tests/podman_preflight.rs | 43 ++++--------------- 1 file changed, 8 insertions(+), 35 deletions(-) diff --git a/crates/openshell-driver-podman/tests/podman_preflight.rs b/crates/openshell-driver-podman/tests/podman_preflight.rs index 37ea37dfdc..439cb95d98 100644 --- a/crates/openshell-driver-podman/tests/podman_preflight.rs +++ b/crates/openshell-driver-podman/tests/podman_preflight.rs @@ -17,33 +17,6 @@ use std::path::PathBuf; use std::time::{Duration, Instant}; -/// Strip ANSI escape codes (e.g. colors) from a string, for readable failure -/// messages. Not required for the assertions below to pass — the driver's -/// own tracing output carries ANSI codes even when captured non-interactively, -/// but they never fragment the substrings these tests check for — this is -/// purely so a failed assertion's `{clean}` output is readable. -fn strip_ansi(s: &str) -> String { - let mut out = String::with_capacity(s.len()); - let mut chars = s.chars().peekable(); - - while let Some(c) = chars.next() { - if c == '\x1b' { - if chars.peek() == Some(&'[') { - chars.next(); - for c in chars.by_ref() { - if c.is_ascii_alphabetic() { - break; - } - } - } - } else { - out.push(c); - } - } - - out -} - /// Run `openshell-driver-podman` pointed at a Podman socket that does not /// exist, and wait for it to exit. /// @@ -51,14 +24,15 @@ fn strip_ansi(s: &str) -> String { /// socket briefly re-activating), so this can take several seconds. async fn run_with_unreachable_podman_socket() -> (String, i32, Duration, PathBuf) { let tmpdir = tempfile::tempdir().expect("create isolated socket dir"); - let missing_socket = tmpdir - .path() - .join("openshell-driver-podman-nonexistent.sock"); + // Use a short relative path so miette cannot insert a line-wrap gutter + // inside it on platforms with long temporary-directory paths. + let missing_socket = PathBuf::from("missing-podman.sock"); let start = Instant::now(); let mut cmd = tokio::process::Command::new(env!("CARGO_BIN_EXE_openshell-driver-podman")); cmd.arg("--podman-socket") .arg(&missing_socket) + .current_dir(tmpdir.path()) .kill_on_drop(true) .stdout(std::process::Stdio::piped()) .stderr(std::process::Stdio::piped()); @@ -102,15 +76,14 @@ async fn driver_error_names_unreachable_socket() { let (output, code, _, missing_socket) = run_with_unreachable_podman_socket().await; assert_ne!(code, 0); - let clean = strip_ansi(&output); assert!( - clean.contains("connection error"), - "driver error should describe a connection failure:\n{clean}" + output.contains("connection error"), + "driver error should describe a connection failure:\n{output}" ); assert!( - clean.contains(missing_socket.to_str().expect("socket path is utf-8")), - "driver error should name the unreachable socket path {}:\n{clean}", + output.contains(missing_socket.to_str().expect("socket path is utf-8")), + "driver error should name the unreachable socket path {}:\n{output}", missing_socket.display() ); }