188 lines
6.6 KiB
Python
188 lines
6.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Test Marathon — Runs all trace scripts and test scripts, combines results.
|
|
|
|
Usage: python3 scripts/test_suite/marathon.py
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent.parent
|
|
SUITE_DIR = Path(__file__).resolve().parent
|
|
|
|
# All trace scripts (static analysis — find verkabelungsfehler)
|
|
TRACE_SCRIPTS = [
|
|
("trace_api_contracts", "Frontend↔Backend API Contracts"),
|
|
("trace_hooks", "Hook Registrations vs Triggers"),
|
|
("trace_functions", "Dead Functions (defined but never called)"),
|
|
("trace_stores", "Unused Store Actions/State"),
|
|
("trace_contracts", "Contract Attribute Mismatches"),
|
|
("trace_plugins", "Plugin→Manifest→Frontend Verkabelung"),
|
|
("trace_imports", "Broken/Missing Imports"),
|
|
]
|
|
|
|
# All test scripts (runtime — find crashes and errors)
|
|
# These will be added as they are built
|
|
TEST_SCRIPTS = [
|
|
# ("test_all_endpoints", "All 224 API Endpoints"),
|
|
# ("test_all_routes", "All 62 Frontend Routes"),
|
|
# ("test_schema_vs_models", "DB Schema vs Models"),
|
|
# ("test_permission_matrix", "Permission Matrix"),
|
|
]
|
|
|
|
|
|
def run_script(name: str, description: str) -> dict:
|
|
"""Run a single script and capture results."""
|
|
script_path = SUITE_DIR / f"{name}.py"
|
|
if not script_path.exists():
|
|
return {"name": name, "description": description, "status": "SKIP", "reason": "Script not found", "issues": 0}
|
|
|
|
print(f"\n{'─' * 70}")
|
|
print(f"RUNNING: {name} — {description}")
|
|
print(f"{'─' * 70}")
|
|
|
|
start = time.time()
|
|
try:
|
|
result = subprocess.run(
|
|
[sys.executable, str(script_path)],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=300,
|
|
cwd=str(ROOT),
|
|
)
|
|
elapsed = time.time() - start
|
|
|
|
# Print stdout
|
|
if result.stdout:
|
|
print(result.stdout)
|
|
if result.stderr:
|
|
print(f"STDERR: {result.stderr[:500]}")
|
|
|
|
# Try to read results JSON
|
|
results_file = SUITE_DIR / f"results_{name}.json"
|
|
issues_count = 0
|
|
if results_file.exists():
|
|
try:
|
|
with open(results_file) as f:
|
|
data = json.load(f)
|
|
if "summary" in data:
|
|
issues_count = data["summary"].get("total_issues", 0)
|
|
elif "issues" in data:
|
|
issues_count = len(data["issues"])
|
|
elif "mismatches" in data:
|
|
issues_count = len(data["mismatches"])
|
|
elif "broken" in data:
|
|
issues_count = len(data["broken"])
|
|
elif "critical_dead" in data:
|
|
issues_count = len(data["critical_dead"])
|
|
elif "orphan_registrations" in data:
|
|
issues_count = len(data.get("orphan_registrations", [])) + len(data.get("orphan_triggers", []))
|
|
elif "unused" in data:
|
|
issues_count = sum(len(v) for v in data["unused"].values()) if isinstance(data["unused"], dict) else 0
|
|
except Exception:
|
|
pass
|
|
|
|
return {
|
|
"name": name,
|
|
"description": description,
|
|
"status": "PASS" if result.returncode == 0 else "FAIL",
|
|
"exit_code": result.returncode,
|
|
"elapsed": round(elapsed, 2),
|
|
"issues": issues_count,
|
|
}
|
|
except subprocess.TimeoutExpired:
|
|
elapsed = time.time() - start
|
|
return {"name": name, "description": description, "status": "TIMEOUT", "elapsed": round(elapsed, 2), "issues": 0}
|
|
except Exception as e:
|
|
elapsed = time.time() - start
|
|
return {"name": name, "description": description, "status": "ERROR", "error": str(e), "elapsed": round(elapsed, 2), "issues": 0}
|
|
|
|
|
|
def main():
|
|
print("╔" + "═" * 70 + "╗")
|
|
print("║" + " LEOCRM TEST MARATHON — Vollständige System-Audit".center(70) + "║")
|
|
print("║" + f" Started: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}".center(70) + "║")
|
|
print("╚" + "═" * 70 + "╝")
|
|
|
|
all_results = []
|
|
total_start = time.time()
|
|
|
|
# Phase 1: Trace Scripts (static analysis)
|
|
print("\n" + "=" * 70)
|
|
print("PHASE 1: TRACE SCRIPTS — Statische Verkabelungs-Analyse")
|
|
print("=" * 70)
|
|
|
|
for name, desc in TRACE_SCRIPTS:
|
|
result = run_script(name, desc)
|
|
all_results.append(result)
|
|
|
|
# Phase 2: Test Scripts (runtime)
|
|
if TEST_SCRIPTS:
|
|
print("\n" + "=" * 70)
|
|
print("PHASE 2: TEST SCRIPTS — Runtime Tests")
|
|
print("=" * 70)
|
|
|
|
for name, desc in TEST_SCRIPTS:
|
|
result = run_script(name, desc)
|
|
all_results.append(result)
|
|
|
|
# Summary
|
|
total_elapsed = time.time() - total_start
|
|
print("\n" + "╔" + "═" * 70 + "╗")
|
|
print("║" + " MARATHON SUMMARY".center(70) + "║")
|
|
print("╠" + "═" * 70 + "╣")
|
|
|
|
total_issues = 0
|
|
passed = 0
|
|
failed = 0
|
|
skipped = 0
|
|
|
|
for r in all_results:
|
|
status_icon = {"PASS": "✅", "FAIL": "❌", "SKIP": "⏭️", "TIMEOUT": "⏰", "ERROR": "💥"}.get(r["status"], "?")
|
|
issues = r.get("issues", 0)
|
|
total_issues += issues
|
|
if r["status"] == "PASS":
|
|
passed += 1
|
|
elif r["status"] in ("FAIL", "ERROR", "TIMEOUT"):
|
|
failed += 1
|
|
else:
|
|
skipped += 1
|
|
elapsed = r.get("elapsed", 0)
|
|
line = f" {status_icon} {r['name']:<30} {issues:>5} issues {elapsed:>6}s"
|
|
print("║" + line.ljust(70) + "║")
|
|
|
|
print("╠" + "═" * 70 + "╣")
|
|
summary_line = f" Total: {len(all_results)} scripts | ✅ {passed} passed | ❌ {failed} failed | ⏭️ {skipped} skipped"
|
|
print("║" + summary_line.ljust(70) + "║")
|
|
issues_line = f" Total issues found: {total_issues}"
|
|
print("║" + issues_line.ljust(70) + "║")
|
|
time_line = f" Total time: {round(total_elapsed, 2)}s"
|
|
print("║" + time_line.ljust(70) + "║")
|
|
print("╚" + "═" * 70 + "╝")
|
|
|
|
# Write combined results
|
|
combined_file = SUITE_DIR / "marathon_results.json"
|
|
with open(combined_file, "w") as f:
|
|
json.dump({
|
|
"timestamp": datetime.now().isoformat(),
|
|
"total_time": round(total_elapsed, 2),
|
|
"total_scripts": len(all_results),
|
|
"total_issues": total_issues,
|
|
"passed": passed,
|
|
"failed": failed,
|
|
"skipped": skipped,
|
|
"results": all_results,
|
|
}, f, indent=2)
|
|
print(f"\nCombined results: {combined_file}")
|
|
|
|
return total_issues
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|