""" Test Runner Orchestrates test execution and persists results. """ from datetime import datetime from typing import Dict from ...models import TestRun, RunStatus, TestFramework from ..config import ( PROJECT_ROOT, get_test_runs, get_current_runs, get_persisted_results, save_persisted_results, is_postgres_available, ) from .go_executor import run_go_tests from .python_executor import run_python_tests from .bqas_executor import run_bqas_tests from .jest_executor import run_jest_tests from .playwright_executor import run_playwright_tests from .container_executor import run_tests_in_container async def execute_test_run(run_id: str, service_def: Dict): """Fuehrt einen Test-Run im Hintergrund aus""" test_runs = get_test_runs() current_runs = get_current_runs() persisted_results = get_persisted_results() framework = service_def["framework"] service_id = service_def["service"] base_path = PROJECT_ROOT / service_def["base_path"].lstrip("/") # Pruefe ob Service deaktiviert ist if service_def.get("disabled", False): reason = service_def.get("disabled_reason", "Service deaktiviert") run = TestRun( id=run_id, suite_id=service_id, service=service_id, started_at=datetime.now(), completed_at=datetime.now(), status=RunStatus.COMPLETED, output=f"Service deaktiviert: {reason}", ) current_runs[run_id] = run test_runs.append({ "id": run.id, "suite_id": run.suite_id, "service": run.service, "started_at": run.started_at.isoformat(), "completed_at": run.completed_at.isoformat(), "status": run.status.value, "total_tests": 0, "passed_tests": 0, "failed_tests": 0, "failed_test_ids": [], "duration_seconds": 0, }) return # Pruefe ob Tests in einem anderen Container laufen sollen run_in_container = service_def.get("run_in_container", False) container_name = service_def.get("container_name", "") run = TestRun( id=run_id, suite_id=service_id, service=service_id, started_at=datetime.now(), status=RunStatus.RUNNING, ) current_runs[run_id] = run try: # Echte Test-Ausführung basierend auf Framework if run_in_container and container_name: # Tests im externen Container ausfuehren framework_str = "pytest" if framework == TestFramework.PYTEST else "go" container_base_path = service_def.get("base_path", "/app/tests") pytest_args = service_def.get("pytest_args", "") result = await run_tests_in_container(container_name, framework_str, container_base_path, service_id, pytest_args) elif framework == TestFramework.GO_TEST: result = await run_go_tests(base_path, service_id=service_id) elif framework == TestFramework.PYTEST: result = await run_python_tests(base_path, service_id=service_id) elif framework in [TestFramework.BQAS_GOLDEN, TestFramework.BQAS_RAG]: result = await run_bqas_tests(service_def) elif framework == TestFramework.JEST: result = await run_jest_tests(base_path, service_id=service_id) elif framework == TestFramework.PLAYWRIGHT: result = await run_playwright_tests(base_path, service_id=service_id) else: result = {"passed": 0, "failed": 0, "total": 0, "output": "Framework nicht unterstuetzt"} run.completed_at = datetime.now() run.status = RunStatus.COMPLETED if result.get("failed", 0) == 0 else RunStatus.FAILED run.total_tests = result.get("total", 0) run.passed_tests = result.get("passed", 0) run.failed_tests = result.get("failed", 0) run.failed_test_ids = result.get("failed_test_ids", []) run.duration_seconds = (run.completed_at - run.started_at).total_seconds() run.output = result.get("output", "") except Exception as e: run.completed_at = datetime.now() run.status = RunStatus.FAILED run.output = str(e) # In Historie speichern (In-Memory) test_runs.append({ "id": run.id, "suite_id": run.suite_id, "service": run.service, "started_at": run.started_at.isoformat(), "completed_at": run.completed_at.isoformat() if run.completed_at else None, "status": run.status.value, "total_tests": run.total_tests, "passed_tests": run.passed_tests, "failed_tests": run.failed_tests, "failed_test_ids": run.failed_test_ids, "duration_seconds": run.duration_seconds, }) # Persistiere Ergebnisse (Legacy In-Memory Dict) persisted_results[service_id] = { "total": run.total_tests, "passed": run.passed_tests, "failed": run.failed_tests, "failed_test_ids": run.failed_test_ids, "last_run": run.completed_at.isoformat() if run.completed_at else datetime.now().isoformat(), "status": run.status.value, } save_persisted_results() # PostgreSQL-Persistierung if is_postgres_available(): try: from ...database import get_db_session from ...repository import TestRepository with get_db_session() as db: repo = TestRepository(db) # Run erstellen falls noch nicht vorhanden db_run = repo.get_run(run.id) if not db_run: db_run = repo.create_run( run_id=run.id, service=service_id, framework=framework.value, triggered_by="manual" ) # Run abschliessen repo.complete_run( run_id=run.id, status=run.status.value, total_tests=run.total_tests, passed_tests=run.passed_tests, failed_tests=run.failed_tests, skipped_tests=0, duration_seconds=run.duration_seconds, output=run.output ) # Einzelne Test-Ergebnisse speichern (fehlgeschlagene Tests) if run.failed_test_ids: results_to_add = [] for failed in run.failed_test_ids: if isinstance(failed, dict): results_to_add.append({ "name": failed.get("name") or failed.get("id", "unknown"), "file_path": failed.get("file_path"), "status": "failed", "error_message": failed.get("error_message"), "error_type": failed.get("error_type"), "suggestion": failed.get("suggestion") }) elif isinstance(failed, str): results_to_add.append({ "name": failed, "status": "failed" }) if results_to_add: repo.add_results(run.id, results_to_add) except Exception as e: print(f"Fehler beim PostgreSQL-Speichern: {e}")