136 lines
4.3 KiB
Python
136 lines
4.3 KiB
Python
"""外部监控接口:有在线 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
|