fix: Restore all files lost during destructive rebase
A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.
This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).
Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
277
backend/api/tests/models.py
Normal file
277
backend/api/tests/models.py
Normal file
@@ -0,0 +1,277 @@
|
||||
"""
|
||||
Test Registry Data Models
|
||||
|
||||
Definiert die Datenstrukturen fuer das zentrale Test-Dashboard.
|
||||
"""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from typing import Optional, List, Dict, Any
|
||||
|
||||
|
||||
class TestFramework(str, Enum):
|
||||
GO_TEST = "go_test"
|
||||
PYTEST = "pytest"
|
||||
JEST = "jest"
|
||||
PLAYWRIGHT = "playwright"
|
||||
BQAS_GOLDEN = "bqas_golden"
|
||||
BQAS_RAG = "bqas_rag"
|
||||
BQAS_SYNTHETIC = "bqas_synthetic"
|
||||
|
||||
|
||||
class TestCategory(str, Enum):
|
||||
UNIT = "unit"
|
||||
INTEGRATION = "integration"
|
||||
E2E = "e2e"
|
||||
BQAS = "bqas"
|
||||
SECURITY = "security"
|
||||
PERFORMANCE = "performance"
|
||||
|
||||
|
||||
class TestStatus(str, Enum):
|
||||
PENDING = "pending"
|
||||
RUNNING = "running"
|
||||
PASSED = "passed"
|
||||
FAILED = "failed"
|
||||
SKIPPED = "skipped"
|
||||
ERROR = "error"
|
||||
|
||||
|
||||
class RunStatus(str, Enum):
|
||||
QUEUED = "queued"
|
||||
RUNNING = "running"
|
||||
COMPLETED = "completed"
|
||||
FAILED = "failed"
|
||||
CANCELLED = "cancelled"
|
||||
|
||||
|
||||
@dataclass
|
||||
class TestCase:
|
||||
"""Einzelner Testfall"""
|
||||
id: str
|
||||
name: str
|
||||
file_path: str
|
||||
line_number: Optional[int] = None
|
||||
framework: TestFramework = TestFramework.GO_TEST
|
||||
category: TestCategory = TestCategory.UNIT
|
||||
duration_ms: Optional[float] = None
|
||||
status: TestStatus = TestStatus.PENDING
|
||||
error_message: Optional[str] = None
|
||||
output: Optional[str] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class TestSuite:
|
||||
"""Test-Suite eines Services"""
|
||||
id: str
|
||||
service: str
|
||||
name: str
|
||||
framework: TestFramework
|
||||
category: TestCategory
|
||||
base_path: str
|
||||
pattern: str # z.B. "*_test.go" oder "test_*.py"
|
||||
tests: List[TestCase] = field(default_factory=list)
|
||||
total_tests: int = 0
|
||||
passed_tests: int = 0
|
||||
failed_tests: int = 0
|
||||
skipped_tests: int = 0
|
||||
duration_ms: float = 0.0
|
||||
coverage_percent: Optional[float] = None
|
||||
last_run: Optional[datetime] = None
|
||||
status: TestStatus = TestStatus.PENDING
|
||||
|
||||
|
||||
@dataclass
|
||||
class TestRun:
|
||||
"""Ein Test-Durchlauf"""
|
||||
id: str
|
||||
suite_id: str
|
||||
service: str
|
||||
started_at: datetime
|
||||
completed_at: Optional[datetime] = None
|
||||
status: RunStatus = RunStatus.QUEUED
|
||||
total_tests: int = 0
|
||||
passed_tests: int = 0
|
||||
failed_tests: int = 0
|
||||
skipped_tests: int = 0
|
||||
duration_seconds: float = 0.0
|
||||
git_commit: Optional[str] = None
|
||||
git_branch: Optional[str] = None
|
||||
coverage_percent: Optional[float] = None
|
||||
triggered_by: str = "manual"
|
||||
output: Optional[str] = None
|
||||
failed_test_ids: List[str] = field(default_factory=list)
|
||||
|
||||
|
||||
@dataclass
|
||||
class CoverageReport:
|
||||
"""Coverage-Bericht fuer einen Service"""
|
||||
service: str
|
||||
framework: TestFramework
|
||||
line_coverage: float
|
||||
branch_coverage: Optional[float] = None
|
||||
function_coverage: Optional[float] = None
|
||||
statement_coverage: Optional[float] = None
|
||||
uncovered_files: List[str] = field(default_factory=list)
|
||||
timestamp: datetime = field(default_factory=datetime.now)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ServiceTestInfo:
|
||||
"""Aggregierte Test-Informationen fuer einen Service"""
|
||||
service: str
|
||||
display_name: str
|
||||
port: Optional[int] = None
|
||||
language: str = "unknown"
|
||||
total_tests: int = 0
|
||||
passed_tests: int = 0
|
||||
failed_tests: int = 0
|
||||
skipped_tests: int = 0
|
||||
pass_rate: float = 0.0
|
||||
coverage_percent: Optional[float] = None
|
||||
last_run: Optional[datetime] = None
|
||||
status: TestStatus = TestStatus.PENDING
|
||||
suites: List[TestSuite] = field(default_factory=list)
|
||||
|
||||
|
||||
@dataclass
|
||||
class TestRegistryStats:
|
||||
"""Gesamtstatistik des Test-Registrys"""
|
||||
total_tests: int = 0
|
||||
total_passed: int = 0
|
||||
total_failed: int = 0
|
||||
total_skipped: int = 0
|
||||
overall_pass_rate: float = 0.0
|
||||
average_coverage: Optional[float] = None
|
||||
services_count: int = 0
|
||||
last_full_run: Optional[datetime] = None
|
||||
by_category: Dict[str, int] = field(default_factory=dict)
|
||||
by_framework: Dict[str, int] = field(default_factory=dict)
|
||||
|
||||
|
||||
# Service-Definitionen mit Test-Informationen
|
||||
SERVICE_DEFINITIONS = [
|
||||
{
|
||||
"service": "consent-service",
|
||||
"display_name": "Consent Service",
|
||||
"port": 8081,
|
||||
"language": "go",
|
||||
"base_path": "/consent-service",
|
||||
"test_pattern": "*_test.go",
|
||||
"framework": TestFramework.GO_TEST,
|
||||
},
|
||||
{
|
||||
"service": "backend",
|
||||
"display_name": "Python Backend",
|
||||
"port": 8000,
|
||||
"language": "python",
|
||||
"base_path": "/backend/tests",
|
||||
"test_pattern": "test_*.py",
|
||||
"framework": TestFramework.PYTEST,
|
||||
},
|
||||
{
|
||||
"service": "voice-service",
|
||||
"display_name": "Voice Service",
|
||||
"port": 8091,
|
||||
"language": "python",
|
||||
"base_path": "/app/tests",
|
||||
"test_pattern": "test_*.py",
|
||||
"framework": TestFramework.PYTEST,
|
||||
"container_name": "breakpilot-pwa-voice-service",
|
||||
"run_in_container": True,
|
||||
"pytest_args": "--ignore=/app/tests/bqas", # Exclude BQAS tests - run separately
|
||||
},
|
||||
{
|
||||
"service": "klausur-service",
|
||||
"display_name": "Klausur Service",
|
||||
"port": 8086,
|
||||
"language": "python",
|
||||
"base_path": "/app/tests",
|
||||
"test_pattern": "test_*.py",
|
||||
"framework": TestFramework.PYTEST,
|
||||
"container_name": "breakpilot-pwa-klausur-service",
|
||||
"run_in_container": True,
|
||||
},
|
||||
{
|
||||
"service": "billing-service",
|
||||
"display_name": "Billing Service",
|
||||
"port": 8082,
|
||||
"language": "go",
|
||||
"base_path": "/billing-service",
|
||||
"test_pattern": "*_test.go",
|
||||
"framework": TestFramework.GO_TEST,
|
||||
},
|
||||
{
|
||||
"service": "school-service",
|
||||
"display_name": "School Service",
|
||||
"port": 8084,
|
||||
"language": "go",
|
||||
"base_path": "/school-service",
|
||||
"test_pattern": "*_test.go",
|
||||
"framework": TestFramework.GO_TEST,
|
||||
},
|
||||
{
|
||||
"service": "edu-search-service",
|
||||
"display_name": "Edu Search Service",
|
||||
"port": 8088,
|
||||
"language": "go",
|
||||
"base_path": "/edu-search-service",
|
||||
"test_pattern": "*_test.go",
|
||||
"framework": TestFramework.GO_TEST,
|
||||
},
|
||||
{
|
||||
"service": "ai-compliance-sdk",
|
||||
"display_name": "AI Compliance SDK",
|
||||
"port": None,
|
||||
"language": "go",
|
||||
"base_path": "/ai-compliance-sdk",
|
||||
"test_pattern": "*_test.go",
|
||||
"framework": TestFramework.GO_TEST,
|
||||
},
|
||||
{
|
||||
"service": "geo-service",
|
||||
"display_name": "Geo Service",
|
||||
"port": 8089,
|
||||
"language": "mixed",
|
||||
"base_path": "/geo-service",
|
||||
"test_pattern": "*_test.go",
|
||||
"framework": TestFramework.GO_TEST,
|
||||
"disabled": True, # Keine Tests vorhanden - Verzeichnis ist leer
|
||||
"disabled_reason": "Keine Test-Dateien vorhanden",
|
||||
},
|
||||
{
|
||||
"service": "website",
|
||||
"display_name": "Website (Jest)",
|
||||
"port": 3000,
|
||||
"language": "typescript",
|
||||
"base_path": "/website",
|
||||
"test_pattern": "*.test.{ts,tsx}",
|
||||
"framework": TestFramework.JEST,
|
||||
"requires_setup": True, # Erfordert npm install im Website-Verzeichnis
|
||||
"setup_note": "Fuehren Sie 'npm install' im website-Verzeichnis aus, um Tests lokal auszufuehren",
|
||||
},
|
||||
# Website E2E entfernt - keine Playwright-Tests vorhanden
|
||||
{
|
||||
"service": "bqas-golden",
|
||||
"display_name": "BQAS Golden Suite",
|
||||
"port": 8091,
|
||||
"language": "python",
|
||||
"base_path": "/app/tests/bqas/test_golden.py",
|
||||
"test_pattern": "test_*.py",
|
||||
"framework": TestFramework.PYTEST,
|
||||
"container_name": "breakpilot-pwa-voice-service",
|
||||
"run_in_container": True,
|
||||
},
|
||||
{
|
||||
"service": "bqas-rag",
|
||||
"display_name": "BQAS RAG Tests",
|
||||
"port": 8091,
|
||||
"language": "python",
|
||||
"base_path": "/app/tests/bqas/test_rag.py",
|
||||
"test_pattern": "test_*.py",
|
||||
"framework": TestFramework.PYTEST,
|
||||
"container_name": "breakpilot-pwa-voice-service",
|
||||
"run_in_container": True,
|
||||
},
|
||||
]
|
||||
Reference in New Issue
Block a user