#!/usr/bin/env bash # Short, read-only end-to-end test for every Athena release. set -Eeuo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ENV_FILE=${STACK_ENV:-/etc/mike-ai/stack.env} pass() { printf 'PASS %s\n' "$*"; } fail() { printf 'FAIL %s\n' "$*" >&2; exit 1; } [[ $EUID -eq 0 ]] || fail "Bitte als root ausfuehren." command -v docker >/dev/null || fail "Docker fehlt." [[ -s $ENV_FILE ]] || fail "Stack-Konfiguration fehlt: $ENV_FILE" cd "$ROOT_DIR" ./manage.sh validate >/dev/null pass "Profilmatrix, MCP-Liste und Compose-Konfiguration stimmen" healthy() { local name=$1 state health state=$(docker inspect -f '{{.State.Status}}' "$name" 2>/dev/null || true) health=$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{end}}' "$name" 2>/dev/null || true) [[ $state == running && ( -z $health || $health == healthy ) ]] } for name in \ mike-ai-wireguard-gateway \ mike-ai-profile-controller \ mike-ai-router \ mike-ai-piper \ mike-ai-xtts \ mike-ai-tts-gateway \ mike-ai-mcp-athena-operator \ mike-ai-backup; do healthy "$name" || fail "$name fehlt oder ist nicht gesund" done pass "Athena-Kerndienste sind gesund" active_llama=$(docker ps --format '{{.Names}}' | \ grep -Ec '^mike-ai-llama-(fast|medium|large|ultra|uncensored)$' || true) [[ $active_llama -eq 1 ]] || fail "$active_llama aktive llama-Profile (erwartet: 1)" pass "Genau ein llama.cpp-Profil ist aktiv" for legacy in \ mike-ai-open-webui \ mike-ai-hermes \ mike-ai-hermes-webui \ mike-ai-hermes-webui-vpn-proxy \ mike-ai-mcp-web \ mike-ai-tools-searxng \ mike-ai-tools-tinysearch \ mike-ai-mcp-platform-context; do [[ $(docker inspect -f '{{.State.Running}}' "$legacy" 2>/dev/null || true) != true ]] || \ fail "Altlast laeuft noch: $legacy" done pass "OpenWebUI, alte Hermes-Dienste und migrierte MCPs sind aus" docker exec mike-ai-router python - <<'PY' >/dev/null import json import os import urllib.request key = os.environ["ROUTER_API_KEY"] for path in ("/health", "/v1/models"): request = urllib.request.Request( "http://127.0.0.1:8081" + path, headers={"Authorization": "Bearer " + key}, ) with urllib.request.urlopen(request, timeout=10) as response: body = response.read() if response.status != 200: raise SystemExit(f"{path}: HTTP {response.status}") if path.endswith("models") and not json.loads(body).get("data"): raise SystemExit("Router meldet keine Modelle") PY pass "Router-Liveness und OpenAI-Modellliste funktionieren" latest=/data/docker-backups/athena-latest.tar.gz [[ -s $latest ]] || fail "Kein gueltiges Athena-Backup: $latest" pass "Automatisches Athena-Backup ist vorhanden" printf '\nATHENA_E2E_OK\n'