refactor(e2e): simplify suite runner

Signed-off-by: Drew Newberry <anewberry@nvidia.com>
This commit is contained in:
Drew Newberry
2026-07-28 17:46:17 -07:00
parent 5621f27673
commit bafd43ed5f
+50 -105
View File
@@ -90,22 +90,15 @@ catalog_has_entry() {
}
vm=
vm_set=0
gateway_config=
gateway_config_set=0
suite_name=
suite_set=0
with_configurations=()
while [ "$#" -gt 0 ]; do
case "$1" in
--vm)
require_value "$1" "$#" "${2:-}"
if [ "${vm_set}" -eq 1 ]; then
die "--vm may be supplied only once"
fi
vm=$2
vm_set=1
shift 2
;;
--with)
@@ -115,20 +108,12 @@ while [ "$#" -gt 0 ]; do
;;
--gateway-config)
require_value "$1" "$#" "${2:-}"
if [ "${gateway_config_set}" -eq 1 ]; then
die "--gateway-config may be supplied only once"
fi
gateway_config=$2
gateway_config_set=1
shift 2
;;
--suite)
require_value "$1" "$#" "${2:-}"
if [ "${suite_set}" -eq 1 ]; then
die "--suite may be supplied only once"
fi
suite_name=$2
suite_set=1
shift 2
;;
-h | --help)
@@ -141,10 +126,10 @@ while [ "$#" -gt 0 ]; do
esac
done
if [ "${gateway_config_set}" -ne 1 ]; then
if [ -z "${gateway_config}" ]; then
die "--gateway-config is required"
fi
if [ "${suite_set}" -ne 1 ]; then
if [ -z "${suite_name}" ]; then
die "--suite is required"
fi
if ! command -v python3 >/dev/null 2>&1; then
@@ -162,9 +147,9 @@ if [ ! -f "${suite_path}" ]; then
die "unknown suite: ${suite_name}"
fi
mode=host
if [ "${vm_set}" -eq 1 ] || [ "${#with_configurations[@]}" -gt 0 ]; then
if [ -n "${vm}" ] || [ "${#with_configurations[@]}" -gt 0 ]; then
mode=vm
if [ "${vm_set}" -eq 0 ]; then
if [ -z "${vm}" ]; then
vm=ubuntu
fi
fi
@@ -180,6 +165,9 @@ if [ "${mode}" = vm ]; then
if ! command -v nix >/dev/null 2>&1; then
die "Nix is required for VM mode"
fi
if ! command -v base64 >/dev/null 2>&1; then
die "base64 is required for VM mode"
fi
if ! vm_catalog="$(cd "${ROOT}" && nix run .#test-guest -- --list)"; then
die "failed to read the Nix test-guest catalog"
fi
@@ -226,10 +214,9 @@ if [ -n "${CARGO_BUILD_JOBS:-}" ]; then
fi
cd "${ROOT}"
target_dir="$(
mise x -- cargo metadata --format-version=1 --no-deps |
python3 -c 'import json, sys; print(json.load(sys.stdin)["target_directory"])'
)"
target_dir="$(e2e_cargo_target_dir "${ROOT}")"
ensure_build_nofile_limit
echo "==> Building native host openshell CLI"
mise x -- cargo build "${cargo_jobs[@]}" -p openshell-cli --bin openshell
@@ -237,7 +224,6 @@ host_cli_bin="${target_dir}/debug/openshell"
echo "==> Preparing ${linux_musl_target} build target"
mise x -- rustup target add "${linux_musl_target}" >/dev/null
ensure_build_nofile_limit
echo "==> Building Linux openshell-sandbox (${linux_musl_target})"
mise x -- cargo zigbuild "${cargo_jobs[@]}" \
@@ -248,7 +234,6 @@ mise x -- cargo zigbuild "${cargo_jobs[@]}" \
linux_sandbox_bin="${target_dir}/${linux_musl_target}/release/openshell-sandbox"
host_gateway_bin=
guest_cli_bin=
guest_gateway_bin=
if [ "${mode}" = host ]; then
echo "==> Building native host openshell-gateway"
@@ -258,17 +243,6 @@ if [ "${mode}" = host ]; then
--features bundled-z3
host_gateway_bin="${target_dir}/debug/openshell-gateway"
else
if ! command -v base64 >/dev/null 2>&1; then
die "base64 is required for VM mode"
fi
echo "==> Building Linux openshell CLI (${linux_musl_target})"
CXXSTDLIB=c++ mise x -- cargo zigbuild "${cargo_jobs[@]}" \
--release \
--target "${linux_musl_target}" \
-p openshell-cli \
--bin openshell
guest_cli_bin="${target_dir}/${linux_musl_target}/release/openshell"
echo "==> Preparing ${linux_gateway_rust_target} build target"
mise x -- rustup target add "${linux_gateway_rust_target}" >/dev/null
echo "==> Building Linux openshell-gateway (${linux_gateway_zig_target})"
@@ -289,32 +263,25 @@ else
guest_gateway_bin="${target_dir}/${linux_gateway_rust_target}/release/openshell-gateway"
fi
for binary in "${host_cli_bin}" "${linux_sandbox_bin}"; do
expected_binaries=("${host_cli_bin}" "${linux_sandbox_bin}")
if [ "${mode}" = host ]; then
expected_binaries+=("${host_gateway_bin}")
else
expected_binaries+=("${guest_gateway_bin}")
fi
for binary in "${expected_binaries[@]}"; do
if [ ! -x "${binary}" ]; then
echo "ERROR: expected built binary at ${binary}" >&2
exit 1
fi
done
if [ "${mode}" = host ] && [ ! -x "${host_gateway_bin}" ]; then
echo "ERROR: expected built gateway at ${host_gateway_bin}" >&2
exit 1
fi
if [ "${mode}" = vm ]; then
for binary in "${guest_cli_bin}" "${guest_gateway_bin}"; do
if [ ! -x "${binary}" ]; then
echo "ERROR: expected built guest binary at ${binary}" >&2
exit 1
fi
done
fi
run_parent="${ROOT}/.cache/openshell-e2e/runs"
mkdir -p "${run_parent}"
run_dir="$(mktemp -d "${run_parent%/}/run.XXXXXX")"
child_pid=
child_process_group=0
runtime_log=
portable_jwt_dir="${ROOT}/.cache/openshell-e2e/gateway-jwt"
portable_jwt_dir=
keep=0
if [ "${OPENSHELL_E2E_KEEP:-0}" = 1 ]; then
keep=1
@@ -324,15 +291,11 @@ fi
# shellcheck disable=SC2329
stop_child() {
local pid=$1
local process_group=$2
local signal_target=${pid}
local signal_target="-${pid}"
if [ -z "${pid}" ] || ! kill -0 "${pid}" 2>/dev/null; then
return
fi
if [ "${process_group}" -eq 1 ]; then
signal_target="-${pid}"
fi
kill -TERM -- "${signal_target}" 2>/dev/null || true
for _ in $(seq 1 30); do
if ! kill -0 "${pid}" 2>/dev/null; then
@@ -349,24 +312,25 @@ stop_child() {
# Invoked by EXIT, INT, and TERM traps.
# shellcheck disable=SC2329
cleanup() {
local incoming_status=$?
local status=${1:-${incoming_status}}
local status=$?
trap - EXIT INT TERM
stop_child "${child_pid}" "${child_process_group}"
stop_child "${child_pid}"
if [ "${status}" -ne 0 ] && [ -n "${runtime_log}" ] && [ -f "${runtime_log}" ]; then
echo "=== ${mode} gateway log ===" >&2
cat "${runtime_log}" >&2
echo "=== end ${mode} gateway log ===" >&2
fi
if [ "${keep}" -eq 1 ]; then
echo "Kept E2E wrapper state at ${run_dir}" >&2
echo "Kept E2E runner state at ${run_dir}" >&2
else
rm -f \
"${portable_jwt_dir}/signing.pem" \
"${portable_jwt_dir}/public.pem" \
"${portable_jwt_dir}/kid"
rmdir "${portable_jwt_dir}" 2>/dev/null || true
if [ -n "${portable_jwt_dir}" ]; then
rm -f \
"${portable_jwt_dir}/signing.pem" \
"${portable_jwt_dir}/public.pem" \
"${portable_jwt_dir}/kid"
rmdir "${portable_jwt_dir}" 2>/dev/null || true
fi
rm -rf "${run_dir}"
fi
exit "${status}"
@@ -378,12 +342,15 @@ trap 'exit 143' TERM
jwt_source_dir="${run_dir}/gateway-jwt"
e2e_generate_gateway_jwt "${jwt_source_dir}"
mkdir -p "${portable_jwt_dir}"
install -m 0600 "${jwt_source_dir}/signing.pem" "${portable_jwt_dir}/signing.pem"
install -m 0600 "${jwt_source_dir}/public.pem" "${portable_jwt_dir}/public.pem"
install -m 0600 "${jwt_source_dir}/kid" "${portable_jwt_dir}/kid"
if [ "${mode}" = host ]; then
portable_jwt_dir="${ROOT}/.cache/openshell-e2e/gateway-jwt"
mkdir -p "${portable_jwt_dir}"
install -m 0600 "${jwt_source_dir}/signing.pem" "${portable_jwt_dir}/signing.pem"
install -m 0600 "${jwt_source_dir}/public.pem" "${portable_jwt_dir}/public.pem"
install -m 0600 "${jwt_source_dir}/kid" "${portable_jwt_dir}/kid"
fi
host_port="$(python3 -c 'import socket; s=socket.socket(); s.bind(("127.0.0.1", 0)); print(s.getsockname()[1]); s.close()')"
host_port="$(e2e_pick_port)"
guest_port=
if [ "${mode}" = vm ]; then
guest_port=8080
@@ -396,45 +363,33 @@ mkdir -p "${XDG_CONFIG_HOME}" "${XDG_DATA_HOME}" "${XDG_STATE_HOME}"
gateway_name="openshell-e2e-${mode}-${host_port}"
gateway_endpoint="http://127.0.0.1:${host_port}"
e2e_register_plaintext_gateway \
"${XDG_CONFIG_HOME}" \
"${gateway_name}" \
"${gateway_endpoint}" \
"${host_port}"
with_contract="${with_configurations[*]}"
export OPENSHELL_GATEWAY_ENDPOINT="${gateway_endpoint}"
export OPENSHELL_GATEWAY="${gateway_name}"
export OPENSHELL_BIN="${host_cli_bin}"
export OPENSHELL_E2E_MODE="${mode}"
export OPENSHELL_E2E_VM="${vm}"
export OPENSHELL_E2E_WITH="${with_contract}"
export OPENSHELL_E2E_GATEWAY_CONFIG="${gateway_config}"
export OPENSHELL_E2E_HOST_PORT="${host_port}"
export OPENSHELL_E2E_GUEST_PORT="${guest_port}"
staged_supervisor="${ROOT}/.cache/openshell-e2e/bin/openshell-sandbox"
mkdir -p "$(dirname "${staged_supervisor}")"
ln -sfn "${linux_sandbox_bin}" "${staged_supervisor}"
if [ "${mode}" = host ]; then
e2e_align_docker_host_with_cli_context
staged_supervisor="${ROOT}/.cache/openshell-e2e/bin/openshell-sandbox"
mkdir -p "$(dirname "${staged_supervisor}")"
ln -sfn "${linux_sandbox_bin}" "${staged_supervisor}"
runtime_log="${run_dir}/gateway.log"
echo "==> Starting host gateway at ${gateway_endpoint}"
(
cd "${ROOT}"
exec "${host_gateway_bin}" \
exec python3 -c \
'import os, sys; os.setsid(); os.execvp(sys.argv[1], sys.argv[1:])' \
"${host_gateway_bin}" \
--config "${gateway_config}" \
--bind-address 127.0.0.1 \
--port "${host_port}" \
--disable-tls
) >"${runtime_log}" 2>&1 &
child_pid=$!
child_process_group=0
else
runtime_log="${run_dir}/vm.log"
guest_launcher="${run_dir}/launch-gateway.sh"
guest_launcher_path="/home/openshell/.cache/openshell-e2e/bin/launch-gateway"
guest_launcher_path=/home/openshell/.cache/openshell-e2e/bin/launch-gateway
config_payload="$(base64 <"${gateway_config}" | tr -d '\r\n')"
jwt_signing_payload="$(base64 <"${jwt_source_dir}/signing.pem" | tr -d '\r\n')"
jwt_public_payload="$(base64 <"${jwt_source_dir}/public.pem" | tr -d '\r\n')"
@@ -477,7 +432,6 @@ EOF
vm_args+=(--with "${configuration}")
done
vm_args+=(
--copy "${guest_cli_bin}:/usr/local/bin/openshell"
--copy "${guest_gateway_bin}:/usr/local/bin/openshell-gateway"
--copy "${linux_sandbox_bin}:/home/openshell/.cache/openshell-e2e/bin/openshell-sandbox"
--copy "${guest_launcher}:${guest_launcher_path}"
@@ -496,9 +450,7 @@ EOF
"${vm_args[@]}"
) >"${runtime_log}" 2>&1 &
child_pid=$!
child_process_group=1
fi
export OPENSHELL_E2E_RUNTIME_LOG="${runtime_log}"
probe_gateway() {
python3 - "${OPENSHELL_BIN}" "${1}" <<'PY'
@@ -535,8 +487,11 @@ wait_for_gateway() {
break
fi
if ! kill -0 "${child_pid}" 2>/dev/null; then
wait "${child_pid}"
process_status=$?
if wait "${child_pid}"; then
process_status=0
else
process_status=$?
fi
child_pid=
echo "ERROR: ${mode} gateway process exited before becoming ready" >&2
if [ "${process_status}" -eq 0 ]; then
@@ -561,22 +516,12 @@ wait_for_gateway() {
return 1
}
set +e
wait_for_gateway
readiness_status=$?
set -e
if [ "${readiness_status}" -ne 0 ]; then
cleanup "${readiness_status}"
fi
echo "==> Running E2E suite: ${suite_name}"
cd "${ROOT}"
set +e
cargo test \
--manifest-path e2e/rust/Cargo.toml \
--features e2e \
--test "${suite_name}" \
-- --nocapture
suite_status=$?
set -e
cleanup "${suite_status}"