Files
awoooi/apps/api/tests/test_aider_event_service.py

94 lines
3.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Test aider_event_service | 2026-04-20 @ Asia/Taipei
import pytest
from datetime import datetime, timezone, timedelta
from src.services.aider_event_service import (
classify_severity, should_create_incident, build_signal_data,
)
from src.models.aider import AiderEventIn
TAIPEI = timezone(timedelta(hours=8))
def _ev(t, p=None, sid="s1"):
return AiderEventIn(
ts=datetime.now(TAIPEI), session_id=sid,
host="ogt-mac", type=t, payload=p or {},
)
def test_classify_error_is_warning():
# aider "error" event → signal severity "warning" → Severity.P2
assert classify_severity(_ev("error")) == "warning"
def test_classify_silent_timeout_is_info():
# silent_timeout → "info" → P3
assert classify_severity(_ev("silent_timeout")) == "info"
def test_classify_session_end_nonzero_exit_is_warning():
assert classify_severity(_ev("session_end", {"exit_code": 1})) == "warning"
def test_classify_session_end_multi_error_is_high():
# 3+ errors + nonzero exit → "high" → P1
assert classify_severity(_ev("session_end", {"exit_code": 1, "error_count": 5})) == "high"
def test_classify_session_end_clean_is_none():
ev = _ev("session_end", {"exit_code": 0, "error_count": 0})
assert classify_severity(ev) is None
assert should_create_incident(ev) is False
def test_classify_session_start_is_none():
assert should_create_incident(_ev("session_start")) is False
def test_classify_error_triggers_incident():
assert should_create_incident(_ev("error")) is True
def test_build_signal_data_fingerprint_per_session_type():
# 同 session + 同 type → 同 fingerprint讓既有 3min debounce 生效)
sd1 = build_signal_data(_ev("error", {"cwd": "/a", "model": "m"}, sid="sx"))
sd2 = build_signal_data(_ev("error", {"cwd": "/a", "model": "m"}, sid="sx"))
assert sd1["fingerprint"] == sd2["fingerprint"]
assert sd1["fingerprint"].startswith("aider:sx:error")
def test_build_signal_data_different_sessions_different_fp():
sd_a = build_signal_data(_ev("error", sid="sA"))
sd_b = build_signal_data(_ev("error", sid="sB"))
assert sd_a["fingerprint"] != sd_b["fingerprint"]
def test_build_signal_data_shape():
ev = _ev("error", {"cwd": "/Users/ogt/awoooi", "model": "elephant-alpha",
"message": "api timeout", "kind": "api_rate_limit"})
sd = build_signal_data(ev)
# 必要 keys
for k in ("alert_name", "severity", "source", "fingerprint", "target",
"labels", "annotations"):
assert k in sd, f"missing {k}"
assert sd["source"] == "manual"
assert sd["target"] == "awoooi" # 從 cwd basename
assert sd["labels"]["session_id"] == "s1"
assert sd["labels"]["model"] == "elephant-alpha"
def test_build_signal_data_redacts_secrets_in_annotations():
"""secret 不可進 annotations/labels"""
ev = _ev("error", {"cwd": "/r", "model": "m",
"message": "key sk-or-v1-abcdef0123456789ABCDEFghijklmnopqrstuv fail"})
sd = build_signal_data(ev)
# annotations 可能含 message — 需已遮罩
annot_str = str(sd["annotations"])
assert "sk-or-v1-abcdef" not in annot_str
assert "<redacted:" in annot_str
def test_build_signal_data_returns_none_for_non_incident_types():
# session_start 不該建 signal
assert build_signal_data(_ev("session_start")) is None