Files
OpenShell/tests/artifacts.nix
Evan Lezar b10ab39f9a refactor(e2e): align suite layout with testing strategy
Move behavioral suites under e2e/suites and extract shared Rust tooling into e2e/support/rust. Organize conformance tests into one Cargo target per area with story modules containing the tests and assertions. Remove the separate scenario crate and registry, and split lifecycle coverage into independent stop/start and stopped-deletion stories.

Reuse shared helpers from the existing Rust harness, preserve artifact packaging and focused test selection, and include tooling and pure assertion tests in test:rust and branch checks. Update authoring guidance for required behavior and retained failures with explicit waivers.

Closes #4119

Signed-off-by: Evan Lezar <elezar@nvidia.com>
2026-10-06 16:56:51 +02:00

379 lines
12 KiB
Nix

# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
{
pkgs,
rustToolchain,
toolchains,
}:
let
isAarch64 = pkgs.stdenv.hostPlatform.isAarch64;
gnuToolchain = toolchains.${if isAarch64 then "aarch64-gnu" else "x86_64-gnu"};
muslToolchain = toolchains.${if isAarch64 then "aarch64-musl" else "x86_64-musl"};
dockerArch = if isAarch64 then "arm64" else "amd64";
toolchainEnv = pkgs.lib.foldl' (env: toolchain: env // toolchain.env) { } (
builtins.attrValues toolchains
);
mkTestArchive =
{
name,
workspacePath,
manifestPath,
package,
target,
output,
features ? null,
filter ? "kind(test)",
}:
pkgs.writeShellApplication {
name = "build-${name}-test-archive";
runtimeInputs = [
pkgs.cargo-nextest
pkgs.coreutils
pkgs.findutils
pkgs.git
pkgs.gnutar
rustToolchain
];
runtimeEnv = toolchainEnv;
text = ''
root=$(git rev-parse --show-toplevel)
manifest_path="$root/${manifestPath}"
workspace_root="$root/${workspacePath}"
output="$root/${output}"
bundle_dir=$(mktemp -d -p /tmp openshell-test-bundle.XXXXXX)
cleanup() {
status=$?
trap - EXIT
rm -rf -- "$bundle_dir"
exit "$status"
}
trap cleanup EXIT
mkdir -p "$(dirname "$output")"
cd "$root"
cargo nextest archive \
--manifest-path "$manifest_path" \
--target ${target} \
-p ${package} \
${pkgs.lib.optionalString (features != null) "--features ${pkgs.lib.escapeShellArg features}"} \
-E ${pkgs.lib.escapeShellArg filter} \
--archive-file "$bundle_dir/tests.tar.zst"
cd "$workspace_root"
bundle_files=()
while IFS= read -r -d "" manifest; do
relative_path="''${manifest#./}"
install -D -m 0644 "$relative_path" "$bundle_dir/$relative_path"
bundle_files+=("$relative_path")
done < <(
find . \
\( -path ./.git -o -path ./.worktrees -o -path ./target \) -prune -o \
-type f -name Cargo.toml -print0
)
tar -C "$bundle_dir" -cf "$output" "''${bundle_files[@]}" tests.tar.zst
echo "Created nextest test bundle: $output"
'';
};
conformanceTestArchive = mkTestArchive {
name = "openshell-conformance";
workspacePath = "e2e/suites/conformance";
manifestPath = "e2e/suites/conformance/Cargo.toml";
package = "openshell-test-conformance-cli";
target = muslToolchain.target;
output = "artifacts/test-archives/${muslToolchain.target}/openshell-conformance-tests.tar";
};
providerRefreshKeycloakArchive = mkTestArchive {
name = "provider-refresh-keycloak";
workspacePath = "e2e/suites/features";
manifestPath = "e2e/suites/features/Cargo.toml";
package = "openshell-test-feature-provider-refresh-keycloak";
target = muslToolchain.target;
output = "artifacts/test-archives/${muslToolchain.target}/provider-refresh-keycloak-tests.tar";
};
# Follow-up: migrate these wrapper-coupled tests once tmachine provides their
# managed-gateway controls, SPIFFE fixtures, caller driver-config setting,
# guest tools, and matching workload-image identity behavior. The corporate
# proxy and gateway-start binaries currently self-skip without wrapper-owned
# gateway metadata, so exclude them rather than report false passes.
podmanE2eFollowUpBinaries = [
"credential_gating"
"driver_config_volume"
"forward_proxy_graphql_l7"
"forward_proxy_jsonrpc_l7"
"forward_proxy_l7_bypass"
"host_gateway_alias"
"landlock"
"local_driver_token_restart"
# Standalone tmachine runs can time out while opening the localhost relay.
# Follow up on making the relay setup deterministic before restoring it.
"no_proxy"
"podman_corporate_proxy"
"podman_gateway_start"
"podman_oci_identity"
"provider_auto_create"
# The provider-refresh feature suite covers revoked Keycloak grants. This
# binary instead covers stable workload handles across repeated rotations
# and explicit refresh reconfiguration in a long-running sandbox.
"provider_refresh_handles"
"provider_token_exchange"
"proxy_egress_pipeline"
# Conformance covers stop/start workspace preservation and deletion while
# stopped. The remaining canonical-main, TTY, attachment replay, and
# no-keep cases still need migration. Nextest archive filters cannot select
# individual tests, so keep the complete binary in the follow-up bucket.
"sandbox_lifecycle"
# Needs a prebuilt musl DNS probe in guest artifact mode; tracked in #3009.
"transparent_tcp"
"websocket_conformance"
"workspace_lifecycle"
];
podmanE2eArchiveFilter =
let
excludedBinaries = map (binary: "binary(=${binary})") podmanE2eFollowUpBinaries;
in
"kind(test) and not (${pkgs.lib.concatStringsSep " or " excludedBinaries})";
podmanE2eCiTests = pkgs.writeShellApplication {
name = "generate-podman-e2e-ci-tests";
runtimeInputs = [
pkgs.cargo-nextest
pkgs.git
pkgs.jq
rustToolchain
];
runtimeEnv = toolchainEnv;
text = ''
root=$(git rev-parse --show-toplevel)
cd "$root"
cargo nextest list \
--manifest-path e2e/rust/Cargo.toml \
--target ${muslToolchain.target} \
-p openshell-e2e \
--features e2e-podman \
--list-type binaries-only \
--message-format json \
| jq -r --argjson excluded ${pkgs.lib.escapeShellArg (builtins.toJSON podmanE2eFollowUpBinaries)} '
[
.["rust-binaries"]
| to_entries[]
| select(.value.kind == "test")
| .value["binary-name"]
| select(. as $name | $excluded | index($name) | not)
]
| sort
| "PODMAN_CI_TESTS=(\n"
+ (map(" " + @sh) | join("\n"))
+ "\n)"
'
'';
};
podmanDriverArchive = mkTestArchive {
name = "podman-driver";
workspacePath = "e2e/suites/drivers";
manifestPath = "e2e/suites/drivers/Cargo.toml";
package = "openshell-test-suite-podman";
target = muslToolchain.target;
output = "artifacts/test-archives/${muslToolchain.target}/openshell-podman-tests.tar";
};
podmanE2eArchive = mkTestArchive {
name = "podman-e2e";
workspacePath = "e2e/rust";
manifestPath = "e2e/rust/Cargo.toml";
package = "openshell-e2e";
target = muslToolchain.target;
output = "artifacts/test-archives/${muslToolchain.target}/openshell-podman-e2e-tests.tar";
features = "e2e-podman";
filter = podmanE2eArchiveFilter;
};
in
rec {
inherit
conformanceTestArchive
providerRefreshKeycloakArchive
podmanDriverArchive
podmanE2eArchive
podmanE2eCiTests
;
binaries = pkgs.writeShellApplication {
name = "build-artifacts-binaries";
runtimeInputs = [
pkgs.coreutils
pkgs.git
rustToolchain
];
runtimeEnv = toolchainEnv;
text = ''
root=$(git rev-parse --show-toplevel)
cd "$root"
cargo build --target ${muslToolchain.target} \
-p openshell-cli \
-p openshell-sandbox
cargo build --target ${gnuToolchain.target} \
-p openshell-gateway \
-p openshell-supervisor
install -D -m 0755 \
target/${muslToolchain.target}/debug/openshell \
artifacts/binaries/${muslToolchain.target}/openshell
install -D -m 0755 \
target/${muslToolchain.target}/debug/openshell-sandbox \
artifacts/binaries/${muslToolchain.target}/openshell-sandbox
install -D -m 0755 \
target/${gnuToolchain.target}/debug/openshell-gateway \
artifacts/binaries/${gnuToolchain.target}/openshell-gateway
install -D -m 0755 \
target/${gnuToolchain.target}/debug/openshell-supervisor \
artifacts/binaries/${gnuToolchain.target}/openshell-supervisor
'';
};
testArchives = pkgs.writeShellApplication {
name = "build-artifacts-test-archives";
runtimeInputs = [
conformanceTestArchive
providerRefreshKeycloakArchive
podmanDriverArchive
podmanE2eArchive
];
text = ''
build-openshell-conformance-test-archive
build-provider-refresh-keycloak-test-archive
build-podman-driver-test-archive
build-podman-e2e-test-archive
'';
};
testImages = pkgs.writeShellApplication {
name = "build-artifacts-test-images";
runtimeInputs = [
pkgs.coreutils
pkgs.docker-client
pkgs.git
];
text = ''
root=$(git rev-parse --show-toplevel)
cd "$root"
docker build \
--platform linux/${dockerArch} \
--file e2e/python/Dockerfile.workload \
--build-arg "PYTHON_VERSION=$(cat .python-version)" \
--tag openshell/e2e-python:dev \
e2e/python
mkdir -p artifacts/images
docker save \
--output artifacts/images/openshell-e2e-python-dev.tar \
openshell/e2e-python:dev
'';
};
images = pkgs.writeShellApplication {
name = "build-artifacts-images";
runtimeInputs = [
pkgs.coreutils
pkgs.docker-client
pkgs.git
testImages
];
text = ''
root=$(git rev-parse --show-toplevel)
cd "$root"
install -D -m 0755 \
artifacts/binaries/${gnuToolchain.target}/openshell-gateway \
deploy/docker/.build/prebuilt-binaries/${dockerArch}/openshell-gateway
install -D -m 0755 \
artifacts/binaries/${gnuToolchain.target}/openshell-supervisor \
deploy/docker/.build/prebuilt-binaries/${dockerArch}/openshell-supervisor
install -D -m 0755 \
artifacts/binaries/${muslToolchain.target}/openshell-sandbox \
deploy/docker/.build/prebuilt-binaries/${dockerArch}/openshell-sandbox
docker build \
--platform linux/${dockerArch} \
--file deploy/docker/Dockerfile.gateway \
--target gateway \
--tag openshell/gateway:tmachine \
.
docker build \
--platform linux/${dockerArch} \
--file deploy/docker/Dockerfile.supervisor \
--target supervisor \
--tag openshell/supervisor:tmachine \
.
docker build \
--platform linux/${dockerArch} \
--file deploy/docker/Dockerfile.sandbox \
--target sandbox \
--tag openshell/sandbox:tmachine \
.
mkdir -p artifacts/images
docker save \
--output artifacts/images/openshell-gateway-tmachine.tar \
openshell/gateway:tmachine
docker save \
--output artifacts/images/openshell-supervisor-tmachine.tar \
openshell/supervisor:tmachine
docker save \
--output artifacts/images/openshell-sandbox-tmachine.tar \
openshell/sandbox:tmachine
build-artifacts-test-images
'';
};
helm = pkgs.writeShellApplication {
name = "build-artifacts-helm";
runtimeInputs = [
pkgs.git
pkgs.kubernetes-helm
];
text = ''
root=$(git rev-parse --show-toplevel)
cd "$root"
mkdir -p artifacts/helm
helm package deploy/helm/openshell --destination artifacts/helm
'';
};
all = pkgs.writeShellApplication {
name = "build-artifacts";
runtimeInputs = [
binaries
testArchives
images
helm
];
text = ''
build-artifacts-binaries
build-artifacts-test-archives
build-artifacts-images
build-artifacts-helm
'';
};
}