fix(alerts): surface legacy hitl backlog
Some checks failed
CD Pipeline / tests (push) Successful in 1m21s
Code Review / ai-code-review (push) Successful in 13s
Type Sync Check / check-type-sync (push) Failing after 40s
CD Pipeline / build-and-deploy (push) Successful in 5m22s
CD Pipeline / post-deploy-checks (push) Successful in 2m19s
Some checks failed
CD Pipeline / tests (push) Successful in 1m21s
Code Review / ai-code-review (push) Successful in 13s
Type Sync Check / check-type-sync (push) Failing after 40s
CD Pipeline / build-and-deploy (push) Successful in 5m22s
CD Pipeline / post-deploy-checks (push) Successful in 2m19s
This commit is contained in:
122
apps/api/tests/test_approval_pending_visibility.py
Normal file
122
apps/api/tests/test_approval_pending_visibility.py
Normal file
@@ -0,0 +1,122 @@
|
||||
from datetime import UTC, datetime, timedelta
|
||||
from types import SimpleNamespace
|
||||
from uuid import UUID
|
||||
|
||||
from src.models.approval import (
|
||||
ApprovalRequest,
|
||||
ApprovalRequestResponse,
|
||||
ApprovalStatus,
|
||||
RiskLevel,
|
||||
)
|
||||
from src.services.approval_db import approval_record_to_request
|
||||
from src.services.heartbeat_report_service import (
|
||||
AlertPipelineStats,
|
||||
DbRedisStats,
|
||||
FlywheelStats,
|
||||
HeartbeatReport,
|
||||
HeartbeatReportService,
|
||||
)
|
||||
|
||||
|
||||
def test_approval_response_exposes_incident_delivery_and_playbook_fields():
|
||||
approval = ApprovalRequest(
|
||||
id=UUID("11111111-1111-1111-1111-111111111111"),
|
||||
action="kubectl rollout restart deployment/awoooi-api",
|
||||
description="manual gate",
|
||||
risk_level=RiskLevel.MEDIUM,
|
||||
requested_by="OpenClaw",
|
||||
required_signatures=1,
|
||||
incident_id="INC-20260531-VISIBLE",
|
||||
matched_playbook_id="PB-20260531-VISIBLE",
|
||||
telegram_message_id=98765,
|
||||
telegram_chat_id=-1001234567890,
|
||||
)
|
||||
|
||||
response = ApprovalRequestResponse.from_approval(approval)
|
||||
|
||||
assert response.incident_id == "INC-20260531-VISIBLE"
|
||||
assert response.matched_playbook_id == "PB-20260531-VISIBLE"
|
||||
assert response.telegram_message_id == 98765
|
||||
assert response.telegram_chat_id == -1001234567890
|
||||
|
||||
|
||||
def test_approval_db_converter_preserves_incident_and_telegram_fields():
|
||||
now = datetime.now(UTC)
|
||||
record = SimpleNamespace(
|
||||
id="22222222-2222-2222-2222-222222222222",
|
||||
action="OBSERVE",
|
||||
description="[LLM Failed] observe only",
|
||||
status=ApprovalStatus.PENDING,
|
||||
risk_level=RiskLevel.MEDIUM,
|
||||
blast_radius={
|
||||
"affected_pods": 0,
|
||||
"estimated_downtime": "0",
|
||||
"related_services": [],
|
||||
"data_impact": "none",
|
||||
},
|
||||
dry_run_checks=[],
|
||||
required_signatures=1,
|
||||
current_signatures=0,
|
||||
signatures=[],
|
||||
requested_by="OpenClaw (fallback)",
|
||||
created_at=now,
|
||||
expires_at=now + timedelta(hours=1),
|
||||
resolved_at=None,
|
||||
rejection_reason=None,
|
||||
extra_metadata={"source": "fallback"},
|
||||
fingerprint="abc123",
|
||||
hit_count=2,
|
||||
last_seen_at=now,
|
||||
incident_id="INC-20260531-LEGACY",
|
||||
matched_playbook_id="PB-20260531-LEGACY",
|
||||
telegram_message_id=45678,
|
||||
telegram_chat_id=-1001234567890,
|
||||
)
|
||||
|
||||
approval = approval_record_to_request(record)
|
||||
|
||||
assert approval.incident_id == "INC-20260531-LEGACY"
|
||||
assert approval.matched_playbook_id == "PB-20260531-LEGACY"
|
||||
assert approval.telegram_message_id == 45678
|
||||
assert approval.telegram_chat_id == -1001234567890
|
||||
|
||||
|
||||
def _report_with_pipeline(stats: AlertPipelineStats) -> HeartbeatReport:
|
||||
return HeartbeatReport(
|
||||
timestamp=datetime.now(UTC),
|
||||
flywheel=FlywheelStats(playbook_count=1),
|
||||
db_redis=DbRedisStats(db_ok=True, db_status="ok", redis_ok=True, redis_status="ok"),
|
||||
alert_pipeline=stats,
|
||||
)
|
||||
|
||||
|
||||
def test_heartbeat_does_not_warn_when_pending_backlog_is_observe_only():
|
||||
report = _report_with_pipeline(
|
||||
AlertPipelineStats(
|
||||
total_24h=25,
|
||||
pending_approval=21,
|
||||
pending_actionable=1,
|
||||
pending_observe_only=20,
|
||||
)
|
||||
)
|
||||
|
||||
warnings = HeartbeatReportService()._build_warnings(report)
|
||||
|
||||
assert not any("待人工審核" in warning for warning in warnings)
|
||||
assert not any("PENDING 積壓" in warning for warning in warnings)
|
||||
|
||||
|
||||
def test_heartbeat_warns_with_frontend_route_for_actionable_backlog():
|
||||
report = _report_with_pipeline(
|
||||
AlertPipelineStats(
|
||||
total_24h=25,
|
||||
pending_approval=21,
|
||||
pending_actionable=11,
|
||||
pending_observe_only=10,
|
||||
)
|
||||
)
|
||||
|
||||
warnings = HeartbeatReportService()._build_warnings(report)
|
||||
|
||||
assert any("/awooop/approvals" in warning for warning in warnings)
|
||||
assert any("觀察類 10" in warning for warning in warnings)
|
||||
Reference in New Issue
Block a user