From bafd43ed5fc184d8403584cdcbbe642065e771c8 Mon Sep 17 00:00:00 2001 From: Drew Newberry Date: Tue, 28 Jul 2026 17:46:17 -0700 Subject: [PATCH] refactor(e2e): simplify suite runner Signed-off-by: Drew Newberry --- e2e/run.sh | 155 +++++++++++++++++------------------------------------ 1 file changed, 50 insertions(+), 105 deletions(-) diff --git a/e2e/run.sh b/e2e/run.sh index 5ff531f48..6be85e50e 100755 --- a/e2e/run.sh +++ b/e2e/run.sh @@ -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}"