#!/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 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-qwen3-tts \ mike-ai-tts-gateway \ mike-ai-llama-dashboard \ mike-ai-mcp-athena-operator \ mike-ai-backup; do healthy "$name" || fail "$name fehlt oder ist nicht gesund" done pass "Athena-Kerndienste sind gesund" for name in mike-ai-llama-dashboard mike-ai-portainer; do network_mode=$(docker inspect -f '{{.HostConfig.NetworkMode}}' "$name" 2>/dev/null || true) [[ $network_mode != container:* ]] || \ fail "$name teilt noch einen fluechtigen Container-Netzwerk-Namespace" done pass "Dashboard und Portainer besitzen stabile Netzwerk-Namespaces" active_llama=$(docker ps --format '{{.Names}}' | \ grep -Ec '^mike-ai-llama-(fast|medium|beta1|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 \ mike-ai-mcp-arr \ mike-ai-mcp-deemix \ mike-ai-mcp-github \ mike-ai-mcp-homeassistant \ mike-ai-mcp-navidrome; do [[ -z $(docker inspect -f '{{.Name}}' "$legacy" 2>/dev/null || true) ]] || \ fail "Altlast existiert noch: $legacy" done pass "OpenWebUI, alte Hermes-Dienste und migrierte MCPs sind entfernt" 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" ./restore.sh --check "$latest" >/dev/null || fail "Athena-Backup ist nicht wiederherstellbar" pass "Automatisches Athena-Backup ist vorhanden und strukturell wiederherstellbar" printf '\nATHENA_E2E_OK\n'