#!/bin/bash # BQAS Local Runner - Lokale Alternative zu GitHub Actions # Fuehrt BQAS Tests aus und benachrichtigt bei Fehlern set -e # Konfiguration VOICE_SERVICE_DIR="/Users/benjaminadmin/Projekte/breakpilot-pwa/voice-service" VOICE_SERVICE_URL="${BQAS_SERVICE_URL:-http://localhost:8091}" LOG_DIR="/var/log/bqas" LOG_FILE="${LOG_DIR}/bqas.log" REGRESSION_THRESHOLD="${BQAS_REGRESSION_THRESHOLD:-0.1}" # Farben fuer Output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Argumente QUICK_MODE=false GOLDEN_ONLY=false RAG_ONLY=false SILENT=false usage() { echo "Usage: $0 [OPTIONS]" echo "" echo "Options:" echo " --quick Nur schnelle Golden Tests (fuer Git Hooks)" echo " --golden Nur Golden Suite" echo " --rag Nur RAG Suite" echo " --silent Keine Desktop-Benachrichtigungen" echo " --help Diese Hilfe anzeigen" echo "" echo "Umgebungsvariablen:" echo " BQAS_SERVICE_URL Voice Service URL (default: http://localhost:8091)" echo " BQAS_REGRESSION_THRESHOLD Regression Schwelle (default: 0.1)" } while [[ $# -gt 0 ]]; do case $1 in --quick) QUICK_MODE=true shift ;; --golden) GOLDEN_ONLY=true shift ;; --rag) RAG_ONLY=true shift ;; --silent) SILENT=true shift ;; --help) usage exit 0 ;; *) echo "Unbekannte Option: $1" usage exit 1 ;; esac done # Logging-Funktion log() { local level=$1 local message=$2 local timestamp=$(date '+%Y-%m-%d %H:%M:%S') # Log-Verzeichnis erstellen falls nicht vorhanden if [ -d "$LOG_DIR" ]; then echo "${timestamp} [${level}] ${message}" >> "$LOG_FILE" fi # Console Output case $level in INFO) echo -e "${BLUE}[INFO]${NC} ${message}" ;; SUCCESS) echo -e "${GREEN}[SUCCESS]${NC} ${message}" ;; WARNING) echo -e "${YELLOW}[WARNING]${NC} ${message}" ;; ERROR) echo -e "${RED}[ERROR]${NC} ${message}" ;; esac } # Benachrichtigung senden notify() { local title=$1 local message=$2 local is_error=${3:-false} if [ "$SILENT" = true ]; then return fi # macOS Desktop-Benachrichtigung if [ "$is_error" = true ]; then osascript -e "display notification \"${message}\" with title \"${title}\" sound name \"Basso\"" 2>/dev/null || true else osascript -e "display notification \"${message}\" with title \"${title}\"" 2>/dev/null || true fi } # Python-Notifier aufrufen (falls vorhanden) notify_python() { local status=$1 local message=$2 local details=$3 if [ -f "${VOICE_SERVICE_DIR}/bqas/notifier.py" ]; then python3 "${VOICE_SERVICE_DIR}/bqas/notifier.py" \ --status "$status" \ --message "$message" \ --details "$details" 2>/dev/null || true fi } # Pruefen ob Service laeuft check_service() { log "INFO" "Pruefe Voice Service Verfuegbarkeit..." local health_url="${VOICE_SERVICE_URL}/health" local response response=$(curl -s -o /dev/null -w "%{http_code}" "$health_url" 2>/dev/null) || response="000" if [ "$response" = "200" ]; then log "SUCCESS" "Voice Service erreichbar" return 0 else log "WARNING" "Voice Service nicht erreichbar (HTTP $response)" return 1 fi } # Regression Check durchfuehren check_regression() { log "INFO" "Pruefe auf Score-Regression..." local regression_url="${VOICE_SERVICE_URL}/api/v1/bqas/regression-check?threshold=${REGRESSION_THRESHOLD}" local response response=$(curl -s "$regression_url" 2>/dev/null) || { log "WARNING" "Regression-Check fehlgeschlagen" return 1 } local is_regression is_regression=$(echo "$response" | python3 -c "import sys,json; print(json.load(sys.stdin).get('is_regression', False))" 2>/dev/null) || is_regression="False" if [ "$is_regression" = "True" ]; then local delta delta=$(echo "$response" | python3 -c "import sys,json; print(json.load(sys.stdin).get('delta', 0))" 2>/dev/null) || delta="unknown" log "ERROR" "Regression erkannt! Score-Abfall: ${delta}" return 1 else log "SUCCESS" "Keine Regression erkannt" return 0 fi } # Tests ausfuehren run_tests() { local test_type=$1 local test_path=$2 local exit_code=0 log "INFO" "Starte ${test_type} Tests..." cd "$VOICE_SERVICE_DIR" # Aktiviere venv falls vorhanden if [ -f "venv/bin/activate" ]; then source venv/bin/activate fi # pytest ausfuehren if python3 -m pytest "$test_path" -v --tb=short 2>&1 | tee -a "$LOG_FILE"; then log "SUCCESS" "${test_type} Tests bestanden" exit_code=0 else log "ERROR" "${test_type} Tests fehlgeschlagen" exit_code=1 fi return $exit_code } # Hauptlogik main() { local start_time=$(date +%s) local golden_exit=0 local rag_exit=0 local regression_exit=0 local service_available=false log "INFO" "==========================================" log "INFO" "BQAS Local Runner gestartet" log "INFO" "==========================================" # Service-Check (optional, Tests koennen auch offline laufen) if check_service; then service_available=true fi # Quick Mode: Nur schnelle Tests if [ "$QUICK_MODE" = true ]; then log "INFO" "Quick Mode - nur schnelle Golden Tests" run_tests "Golden (Quick)" "tests/bqas/test_golden.py -k 'not slow'" || golden_exit=1 else # Vollstaendige Test-Ausfuehrung if [ "$RAG_ONLY" = false ]; then run_tests "Golden" "tests/bqas/test_golden.py" || golden_exit=1 fi if [ "$GOLDEN_ONLY" = false ]; then run_tests "RAG" "tests/bqas/test_rag.py" || rag_exit=1 fi # Regression-Check nur wenn Service verfuegbar if [ "$service_available" = true ]; then check_regression || regression_exit=1 fi fi # Zusammenfassung local end_time=$(date +%s) local duration=$((end_time - start_time)) log "INFO" "==========================================" log "INFO" "BQAS Run abgeschlossen (${duration}s)" log "INFO" "==========================================" # Ergebnis ermitteln local total_failures=$((golden_exit + rag_exit + regression_exit)) if [ $total_failures -eq 0 ]; then log "SUCCESS" "Alle Tests bestanden!" notify "BQAS" "Alle Tests bestanden" false notify_python "success" "Alle Tests bestanden" "Dauer: ${duration}s" return 0 else local failure_details="" [ $golden_exit -ne 0 ] && failure_details="${failure_details}Golden Tests fehlgeschlagen. " [ $rag_exit -ne 0 ] && failure_details="${failure_details}RAG Tests fehlgeschlagen. " [ $regression_exit -ne 0 ] && failure_details="${failure_details}Regression erkannt. " log "ERROR" "Tests fehlgeschlagen: ${failure_details}" notify "BQAS Alert" "$failure_details" true notify_python "failure" "Tests fehlgeschlagen" "$failure_details" return 1 fi } # Script ausfuehren main