# apps/api/tests/test_golden_regression.py # 2026-04-28 ogt + Claude Sonnet 4.6 — P3.2.4 黃金回歸測試集 """ 30 個黃金測試案例,保護 classify_alert_early() 邏輯不退步。 涵蓋 10 類告警場景。 函數簽章: classify_alert_early(alertname, severity, labels=None, age_hours=0.0) -> tuple[str, str] # (alert_category, notification_type) """ from __future__ import annotations from src.services.incident_service import classify_alert_early class TestKubernetes: def test_pod_crash_looping(self): cat, ntype = classify_alert_early("PodCrashLooping", "critical") assert cat == "kubernetes" and ntype == "TYPE-3" def test_deploy_rollout_stuck(self): cat, ntype = classify_alert_early("DeployRolloutStuck", "warning") assert cat == "kubernetes" and ntype == "TYPE-3" def test_kube_node_not_ready(self): cat, ntype = classify_alert_early("KubeNodeNotReady", "critical") assert cat == "kubernetes" and ntype == "TYPE-3" def test_pod_oom_killed(self): cat, ntype = classify_alert_early("PodOOMKilled", "warning") assert cat == "kubernetes" and ntype == "TYPE-3" def test_node_memory_pressure(self): cat, ntype = classify_alert_early("NodeMemoryPressure", "warning") assert cat == "kubernetes" and ntype == "TYPE-3" class TestHostResource: def test_host_high_cpu_load(self): cat, ntype = classify_alert_early("HostHighCpuLoad", "critical") assert cat == "host_resource" and ntype == "TYPE-3" def test_host_high_memory(self): cat, ntype = classify_alert_early("HostHighMemory", "warning") assert cat == "host_resource" and ntype == "TYPE-3" def test_host_disk_space_full(self): cat, ntype = classify_alert_early("HostDiskSpaceFull", "critical") assert cat == "host_resource" and ntype == "TYPE-3" def test_systemd_runner_watchdog_is_not_heartbeat(self): cat, ntype = classify_alert_early("SystemdRunnerWatchdogEnabled", "warning") assert cat == "host_resource" and ntype == "TYPE-3" class TestHighCpuVariants: """HighCPU* prefix 規則覆蓋""" def test_high_cpu_prefix(self): cat, ntype = classify_alert_early("HighCPUUsage", "critical") assert cat == "host_resource" and ntype == "TYPE-3" def test_high_memory_prefix(self): cat, ntype = classify_alert_early("HighMemoryPressure", "warning") assert cat == "host_resource" and ntype == "TYPE-3" class TestBackup: def test_host_backup_failed_fresh(self): """< 24h 備份失敗 → TYPE-1(pure info)""" cat, ntype = classify_alert_early("HostBackupFailed", "warning", age_hours=10.0) assert cat == "backup" and ntype == "TYPE-1" def test_host_backup_failed_stale_upgrade(self): """> 24h 備份失敗 → 升級為 TYPE-3(P0 故障)""" cat, ntype = classify_alert_early("HostBackupFailed", "warning", age_hours=25.0) assert cat == "backup_failure" and ntype == "TYPE-3" def test_host_backup_stale_upgrade(self): cat, ntype = classify_alert_early("HostBackupStale", "warning", age_hours=30.0) assert cat == "backup_failure" and ntype == "TYPE-3" def test_backup_restore_test_not_upgraded(self): """BackupRestoreTestFailed 不受 age 升級影響""" cat, ntype = classify_alert_early("BackupRestoreTestFailed", "warning", age_hours=48.0) assert ntype == "TYPE-1" class TestDatabase: def test_postgres_connections_high(self): cat, ntype = classify_alert_early("PostgreSQLConnectionsHigh", "warning") assert cat == "database" and ntype == "TYPE-3" def test_postgres_disk_growth_rate(self): cat, ntype = classify_alert_early("PostgreSQLDiskGrowthRate", "warning") assert cat == "database" and ntype == "TYPE-3" def test_redis_memory_full(self): cat, ntype = classify_alert_early("RedisMemoryFull", "critical") assert cat == "database" and ntype == "TYPE-3" class TestInfoAndHeartbeat: def test_severity_info_is_type1(self): _, ntype = classify_alert_early("SomeAlert", "info") assert ntype == "TYPE-1" def test_severity_none_is_type1(self): _, ntype = classify_alert_early("SomeAlert", "none") assert ntype == "TYPE-1" def test_watchdog_heartbeat(self): cat, ntype = classify_alert_early("Watchdog", "warning") assert cat == "backup" and ntype == "TYPE-1" def test_deadmansswitch(self): cat, ntype = classify_alert_early("DeadMansSwitch", "critical") assert cat == "backup" and ntype == "TYPE-1" class TestConfigDrift: def test_configuration_drift(self): cat, ntype = classify_alert_early("ConfigurationDrift", "warning") assert cat == "config_drift" and ntype == "TYPE-4D" def test_kube_config_drift(self): cat, ntype = classify_alert_early("KubeConfigDrift", "critical") assert cat == "config_drift" and ntype == "TYPE-4D" class TestFlywheelHealth: def test_auto_repair_low_success(self): cat, ntype = classify_alert_early("AutoRepairLowSuccessRate", "critical") assert cat == "flywheel_health" and ntype == "TYPE-8M" def test_ollama_down(self): cat, ntype = classify_alert_early("OllamaDown", "critical") assert cat == "flywheel_health" and ntype == "TYPE-8M" class TestSecops: def test_unauthorized_ssh(self): cat, ntype = classify_alert_early("UnauthorizedSSH", "critical") assert cat == "secops" and ntype == "TYPE-5S" def test_pod_abnormal_activity(self): cat, ntype = classify_alert_early("PodAbnormalActivity", "critical") assert cat == "secops" and ntype == "TYPE-5S" class TestDevopsAndExternal: def test_gitea_down(self): cat, ntype = classify_alert_early("GiteaDown", "critical") assert cat == "devops_tool" and ntype == "TYPE-3" def test_mowoo_work_down(self): cat, ntype = classify_alert_early("MoWoooWorkDown", "critical") assert cat == "external_site" and ntype == "TYPE-3" def test_minio_down(self): cat, ntype = classify_alert_early("MinIODown", "critical") assert cat == "storage" and ntype == "TYPE-3" class TestAlertChainAndGeneral: def test_alert_chain_broken_alertmanager(self): cat, ntype = classify_alert_early("AlertChainBroken_Alertmanager", "critical") assert cat == "alertchain_health" and ntype == "TYPE-8M" def test_no_alerts_received(self): cat, ntype = classify_alert_early("NoAlertsReceived", "critical") assert cat == "alertchain_health" and ntype == "TYPE-8M" def test_unknown_alert_falls_to_general(self): cat, ntype = classify_alert_early("SomeBrandNewUnknownAlert2026", "warning") assert cat == "general" and ntype == "TYPE-3"