添加监控接口
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
"""外部监控接口:有在线 worker 才算服务正常;故障模拟只改探活响应。"""
|
||||
|
||||
import asyncio
|
||||
|
||||
import pytest
|
||||
|
||||
from gateway import app as gateway_app
|
||||
from gateway.app import monitor, monitor_fault, monitor_payload
|
||||
|
||||
|
||||
class _Req:
|
||||
def __init__(self, body=None, token="secret", raw=None):
|
||||
self._body = body
|
||||
self._raw = raw
|
||||
self.headers = {"X-Internal-Token": token} if token is not None else {}
|
||||
|
||||
async def json(self):
|
||||
if self._raw is not None:
|
||||
raise self._raw
|
||||
return self._body
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _reset_monitor_drill():
|
||||
gateway_app._monitor_drill["enabled"] = False
|
||||
yield
|
||||
gateway_app._monitor_drill["enabled"] = False
|
||||
|
||||
|
||||
def test_monitor_ok_when_any_worker_online():
|
||||
body = monitor_payload({
|
||||
"total": 5, "healthy": 1, "primary_total": 3, "primary_healthy": 0,
|
||||
})
|
||||
assert body["status"] == "ok"
|
||||
assert body["workers_healthy"] == 1
|
||||
assert "message" not in body
|
||||
|
||||
|
||||
def test_monitor_unhealthy_when_none_online():
|
||||
body = monitor_payload({
|
||||
"total": 5, "healthy": 0, "primary_total": 3, "primary_healthy": 0,
|
||||
})
|
||||
assert body["status"] == "unhealthy"
|
||||
assert body["message"] == "没有可用的 worker"
|
||||
assert body["workers_total"] == 5
|
||||
|
||||
|
||||
def test_monitor_unhealthy_when_pool_empty():
|
||||
body = monitor_payload({"total": 0, "healthy": 0})
|
||||
assert body["status"] == "unhealthy"
|
||||
|
||||
|
||||
def test_monitor_http_503_when_no_worker(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
"gateway.app._get_pool_status_safe",
|
||||
lambda: {"total": 2, "healthy": 0, "primary_total": 2, "primary_healthy": 0},
|
||||
)
|
||||
resp = asyncio.run(monitor())
|
||||
assert resp.status_code == 503
|
||||
assert resp.body
|
||||
assert b'"status":"unhealthy"' in resp.body or b'"status": "unhealthy"' in resp.body
|
||||
|
||||
|
||||
def test_monitor_http_200_when_worker_online(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
"gateway.app._get_pool_status_safe",
|
||||
lambda: {"total": 2, "healthy": 2, "primary_total": 2, "primary_healthy": 1},
|
||||
)
|
||||
body = asyncio.run(monitor())
|
||||
assert body["status"] == "ok"
|
||||
assert body["workers_healthy"] == 2
|
||||
|
||||
|
||||
def test_monitor_payload_simulated_and_really_down():
|
||||
body = monitor_payload(
|
||||
{"total": 5, "healthy": 0, "primary_total": 3, "primary_healthy": 0},
|
||||
simulated=True,
|
||||
)
|
||||
assert body["status"] == "unhealthy"
|
||||
assert body["simulated"] is True
|
||||
assert body["workers_healthy"] == 0
|
||||
assert "没有可用的 worker" in body["message"]
|
||||
|
||||
|
||||
def test_monitor_payload_simulated_keeps_real_counts():
|
||||
body = monitor_payload(
|
||||
{"total": 5, "healthy": 3, "primary_total": 3, "primary_healthy": 3},
|
||||
simulated=True,
|
||||
)
|
||||
assert body["status"] == "unhealthy"
|
||||
assert body["simulated"] is True
|
||||
assert body["workers_healthy"] == 3
|
||||
assert "模拟故障" in body["message"]
|
||||
|
||||
|
||||
def _patch_token(monkeypatch, password="secret"):
|
||||
monkeypatch.setattr(
|
||||
"gateway.config.get_config",
|
||||
lambda: {"shared_password": password},
|
||||
)
|
||||
|
||||
|
||||
def test_fault_requires_token(monkeypatch):
|
||||
_patch_token(monkeypatch)
|
||||
resp = asyncio.run(monitor_fault(_Req(body={"enabled": True}, token="nope")))
|
||||
assert resp.status_code == 401
|
||||
assert gateway_app._monitor_drill["enabled"] is False
|
||||
|
||||
|
||||
def test_fault_rejects_non_bool(monkeypatch):
|
||||
_patch_token(monkeypatch)
|
||||
resp = asyncio.run(monitor_fault(_Req(body={"enabled": "true"})))
|
||||
assert resp.status_code == 400
|
||||
assert gateway_app._monitor_drill["enabled"] is False
|
||||
|
||||
|
||||
def test_fault_on_makes_monitor_503_then_off_restores(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
"gateway.app._get_pool_status_safe",
|
||||
lambda: {"total": 5, "healthy": 3, "primary_total": 3, "primary_healthy": 3},
|
||||
)
|
||||
_patch_token(monkeypatch)
|
||||
|
||||
opened = asyncio.run(monitor_fault(_Req(body={"enabled": True})))
|
||||
assert opened["simulated"] is True
|
||||
failed = asyncio.run(monitor())
|
||||
assert failed.status_code == 503
|
||||
assert b'"simulated":true' in failed.body or b'"simulated": true' in failed.body
|
||||
assert b'"workers_healthy":3' in failed.body or b'"workers_healthy": 3' in failed.body
|
||||
|
||||
closed = asyncio.run(monitor_fault(_Req(body={"enabled": False})))
|
||||
assert closed["simulated"] is False
|
||||
ok = asyncio.run(monitor())
|
||||
assert ok["status"] == "ok"
|
||||
assert "simulated" not in ok
|
||||
Reference in New Issue
Block a user