Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/openshell-driver-podman/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,69 +1,43 @@
// 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_<name>` 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;

/// 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()
}

/// 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 `<workspace>/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
}

/// Run `openshell-driver-podman` pointed at a Podman socket that does not
/// exist, and wait for it to exit.
///
/// The driver retries a handful of times before giving up (to tolerate the
/// 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");
// 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(driver_podman_bin());
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());

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");
Expand Down Expand Up @@ -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()
);
}
5 changes: 0 additions & 5 deletions e2e/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 0 additions & 4 deletions tests/artifacts.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading