#!/bin/bash # ============================================================ # Script principal QA — SaaS Turf Prédictions IA # Sprint 8 — QA, Beta Fermee, Go/No-Go # Ticket: HRT-34 # # Usage : bash tests/run_qa.sh [APP_URL] # ============================================================ set -e APP_URL="${1:-http://localhost:8792}" REPORT_DIR="tests/reports" VENV="venv" TIMESTAMP=$(date +%Y%m%d_%H%M%S) mkdir -p "$REPORT_DIR" echo "============================================================" echo "QA SPRINT 8 — SaaS Turf Prédictions IA" echo "Target : $APP_URL" echo "Date : $(date)" echo "============================================================" # Vérifier l'environnement if [ ! -d "$VENV" ]; then echo "❌ Venv non trouvé. Créer l'environnement virtuel d'abord." exit 1 fi source "$VENV/bin/activate" # Installer les dépendances de test si nécessaire pip install pytest pytest-asyncio pytest-html playwright locust bandit safety 2>/dev/null | tail -5 # Installer les navigateurs Playwright python -m playwright install chromium firefox webkit 2>/dev/null || true PASS=0 FAIL=0 RESULTS=() # ============================================================ # 1. Tests E2E Playwright # ============================================================ echo "" echo "--- Tests E2E Playwright ---" if APP_URL="$APP_URL" python -m pytest tests/e2e/ \ -v --tb=short \ --html="$REPORT_DIR/e2e_report_${TIMESTAMP}.html" \ --self-contained-html \ -q 2>&1 | tee "$REPORT_DIR/e2e_output_${TIMESTAMP}.log"; then echo "✅ E2E : PASS" RESULTS+=("✅ Tests E2E Playwright : PASS") ((PASS++)) else echo "❌ E2E : FAIL" RESULTS+=("❌ Tests E2E Playwright : FAIL — voir $REPORT_DIR/e2e_report_${TIMESTAMP}.html") ((FAIL++)) fi # ============================================================ # 2. Tests de sécurité (injection SQL, JWT, autorisation) # ============================================================ echo "" echo "--- Tests Sécurité ---" if APP_URL="$APP_URL" python -m pytest tests/security/test_security.py \ -v --tb=short \ --html="$REPORT_DIR/security_report_${TIMESTAMP}.html" \ --self-contained-html \ -q 2>&1 | tee "$REPORT_DIR/security_output_${TIMESTAMP}.log"; then echo "✅ Sécurité : PASS" RESULTS+=("✅ Tests Sécurité (JWT, SQL injection, autorisation) : PASS") ((PASS++)) else echo "❌ Sécurité : FAIL" RESULTS+=("❌ Tests Sécurité : FAIL — voir $REPORT_DIR/security_report_${TIMESTAMP}.html") ((FAIL++)) fi # ============================================================ # 3. Scan Bandit (vulnérabilités code Python) # ============================================================ echo "" echo "--- Scan Bandit ---" if bandit -r . \ --exclude ./venv,./tests \ -ll \ -f html \ -o "$REPORT_DIR/bandit_report_${TIMESTAMP}.html" \ 2>&1 | tee "$REPORT_DIR/bandit_output_${TIMESTAMP}.log"; then echo "✅ Bandit : PASS" RESULTS+=("✅ Bandit (sécurité code) : PASS") ((PASS++)) else echo "⚠️ Bandit : vulnérabilités détectées" RESULTS+=("⚠️ Bandit : voir $REPORT_DIR/bandit_report_${TIMESTAMP}.html") fi # ============================================================ # 4. Tests de charge Locust (100 users, 3 min) # ============================================================ echo "" echo "--- Tests de charge Locust (100 users, 3 min) ---" if locust \ -f tests/load/locustfile.py \ --host "$APP_URL" \ --users 100 \ --spawn-rate 10 \ --run-time 3m \ --headless \ --csv "$REPORT_DIR/load_normal_${TIMESTAMP}" \ 2>&1 | tee "$REPORT_DIR/load_output_${TIMESTAMP}.log"; then echo "✅ Locust 100 users : PASS" RESULTS+=("✅ Tests de charge 100 users : PASS") ((PASS++)) else echo "❌ Locust 100 users : FAIL" RESULTS+=("❌ Tests de charge 100 users : FAIL — voir $REPORT_DIR/load_output_${TIMESTAMP}.log") ((FAIL++)) fi # ============================================================ # 5. Test spike (500 users, 2 min) — optionnel # ============================================================ echo "" echo "--- Test spike Locust (500 users, 2 min) ---" if locust \ -f tests/load/locustfile.py \ --host "$APP_URL" \ --users 500 \ --spawn-rate 250 \ --run-time 2m \ --headless \ --csv "$REPORT_DIR/load_spike_${TIMESTAMP}" \ 2>&1 | tee "$REPORT_DIR/spike_output_${TIMESTAMP}.log"; then echo "✅ Spike 500 users : PASS" RESULTS+=("✅ Test spike 500 users : PASS") ((PASS++)) else echo "❌ Spike 500 users : FAIL" RESULTS+=("❌ Test spike 500 users : FAIL") ((FAIL++)) fi # ============================================================ # 6. OWASP ZAP (si Docker disponible) # ============================================================ if command -v docker &>/dev/null; then echo "" echo "--- OWASP ZAP ---" if bash tests/security/run_owasp_zap.sh "$APP_URL" 2>&1 | tee "$REPORT_DIR/zap_main_${TIMESTAMP}.log"; then echo "✅ OWASP ZAP : PASS" RESULTS+=("✅ OWASP ZAP (zero vulnérabilité critique) : PASS") ((PASS++)) else echo "❌ OWASP ZAP : FAIL" RESULTS+=("❌ OWASP ZAP : vulnérabilités critiques détectées") ((FAIL++)) fi else RESULTS+=("⚠️ OWASP ZAP : skippé (Docker non disponible)") fi # ============================================================ # Rapport final # ============================================================ echo "" echo "============================================================" echo "RAPPORT QA FINAL — Sprint 8" echo "============================================================" for r in "${RESULTS[@]}"; do echo " $r" done echo "" echo "Passed : $PASS" echo "Failed : $FAIL" echo "" if [ "$FAIL" -eq 0 ]; then echo "✅ VERDICT : GO — Tous les tests passent" echo " Lancement public autorisé" exit 0 else echo "❌ VERDICT : NO-GO — $FAIL test(s) en échec" echo " Corriger avant lancement public" exit 1 fi