PayrollManagementSystem/backend/tests/unit/test_monitoring.py

72 lines
2.6 KiB
Python
Raw Normal View History

"""验证遥测口径、有界内存和请求关联,防止监控干扰业务及泄漏原始地址。"""
from datetime import datetime, timedelta
from fastapi import FastAPI
from fastapi.testclient import TestClient
from app.core.monitoring import REQUEST_ID, MonitorMiddleware, Recorder, merge_metrics
def test_合并直方图计算P95且四百不计系统错误():
recorder = Recorder()
at = datetime(2026, 11, 2, 10)
for status, elapsed in [(200, 10), (400, 100), (403, 200), (500, 750)]:
recorder.record("GET", "/items/{id}", status, elapsed, "r", at=at)
result = merge_metrics(recorder.metrics()[at].values())
assert (result["count"], result["errors_4xx"], result["errors_5xx"]) == (4, 2, 1)
assert result["error_rate"] == 25
assert result["p95_ms"] == 750
assert merge_metrics([])["p95_ms"] is None
def test_中间件生成编号使用模板排除自身且不读取正文():
app, recorder = FastAPI(), Recorder()
app.add_middleware(MonitorMiddleware, recorder=recorder)
@app.get("/items/{id}")
def item(id: str):
return {"request_id": REQUEST_ID.get()}
@app.get("/api/v1/system/monitor/overview")
def monitor():
return {}
client = TestClient(app)
response = client.get("/items/private-id?token=never-record")
assert response.headers["x-request-id"] == response.json()["request_id"]
client.get("/api/v1/system/monitor/overview")
client.get("/private-route")
values = next(iter(recorder.metrics().values()))
assert set(values) == {("GET", "/items/{id}"), ("GET", "/__unmatched__")}
assert "private" not in str(recorder.metrics())
assert REQUEST_ID.get() == "-"
def test_内存分钟路由和事件队列均有界():
recorder = Recorder()
at = datetime(2026, 11, 2, 10)
for i in range(2100):
recorder.record("GET", f"/route/{i}", 500, 1, str(i), at=at)
assert len(recorder.events) == 2000 and recorder.dropped_events == 100
assert len(recorder.metrics()[at]) == 201
for i in range(11):
recorder.record("GET", "/ok", 200, 1, "r", at=at + timedelta(minutes=i))
assert len(recorder.metrics()) == 10
def test_遥测内部失败不改变业务响应(monkeypatch):
app, recorder = FastAPI(), Recorder()
app.add_middleware(MonitorMiddleware, recorder=recorder)
@app.get("/ok")
def ok():
return {"ok": True}
def broken(*args, **kwargs):
raise RuntimeError("synthetic-recorder-failure")
monkeypatch.setattr(recorder, "record", broken)
response = TestClient(app).get("/ok")
assert response.status_code == 200 and response.json() == {"ok": True}