#!/usr/bin/env bash # The end-to-end test (Development Plan M1.6): the whole agent against real # services, driven by a scripted operator. CI runs it on every PR (with # --local); locally, run only the tests you're writing (-k) or diagnosing # (--lf). # # scripts/e2e.sh on the bring-up build VM (configured below) # scripts/e2e.sh --local on a throwaway local sshd instead # # Uses tests/integration/nisse-test.yaml and its secrets (.env at the repo # root), like the integration tests. Every role runs on a local model # (tests/integration/e2e_support.py; NISSE_E2E_MODEL overrides it), so tell # the operator before a full run: it keeps the RTX 4090 busy for a while. set -euo pipefail cd "$(dirname "$0")/.." if [ "${1:-}" = "--local" ]; then shift else export NISSE_E2E_BUILD_HOST=${NISSE_E2E_BUILD_HOST:-nisse-dev.garrett-hall.com} export NISSE_E2E_BUILD_KEY=${NISSE_E2E_BUILD_KEY:-/root/nisse-e2e/ssh/id_ed25519} fi # Each run's state store is kept here, for nisse_dev.dump after a failure. export NISSE_E2E_RUNS=${NISSE_E2E_RUNS:-/root/nisse-e2e/test-runs} # What the run spent on the test key, read from LiteLLM (spend only). The # end-to-end tests run on a local model, so anything above $0 means a call # went to a paid one: an override, or a proxy fallback. spend() { (set -a; [ -f .env ] && . ./.env; set +a uv run python -c ' import os, httpx r = httpx.get("https://litellm.dongar.net/key/info", timeout=30, headers={"Authorization": "Bearer " + os.environ["NISSE_LLM_TOKEN"]}) i = r.json()["info"] print(i["spend"], i.get("max_budget"))' 2>/dev/null) || echo "? ?" } read -r before budget < <(spend) status=0 uv run pytest -m e2e -rs tests/integration/test_end_to_end.py tests/integration/test_end_to_end_loop.py "$@" || status=$? read -r after _ < <(spend) python3 -c " b, a, cap = '$before', '$after', '$budget' try: print(f'e2e spend: \${float(a) - float(b):.4f} this run; \${float(a):.2f} of \${float(cap):.2f} today') except ValueError: print('e2e spend: unknown (could not read the key)')" exit "$status"