fix: 修复监控链路 api_key 未解码致 401、瞬时 401 误禁、前端表单多处问题 - monitor: 调度链路对 base64 存储的 api_key 解码(此前直接发送编码串导致所有账号 401) - fetcher: 401/403 先按重试次数确认再判定禁用,避免瞬时 401 误杀;POST 自动补 Content-Type: application/json - ui: val/err 兼容 # 前缀(保存无反应的根因);平台编辑回填 headers 反转义;监控页补添加账号入口 - test: 新增 monitor 解码回归测试,共 51 个用例

This commit is contained in:
2026-08-05 00:21:31 +08:00
parent 17d2496a65
commit edf19e121b
7 changed files with 132 additions and 13 deletions
+15 -3
View File
@@ -105,7 +105,7 @@ class TestFetchBalance:
assert result.ok
assert captured["data"] == '{"api_key": "sk-2"}'
def test_401_is_auth_error_no_retry(self, monkeypatch):
def test_401_retries_then_auth_error(self, monkeypatch):
calls = []
def fake_get(url, headers=None, timeout=10):
@@ -113,9 +113,21 @@ class TestFetchBalance:
return FakeResponse(401, text="unauthorized")
monkeypatch.setattr("requests.get", fake_get)
result = fetch_balance(PLATFORM_GET, "bad", retry_count=3, timeout=10)
result = fetch_balance(PLATFORM_GET, "bad", retry_count=2, timeout=10)
assert not result.ok and result.auth_error
assert len(calls) == 1
assert len(calls) == 3 # 401 也按重试次数确认后再判定
def test_transient_401_then_success(self, monkeypatch):
calls = []
def fake_get(url, headers=None, timeout=10):
calls.append(1)
return FakeResponse(401) if len(calls) == 1 else FakeResponse(200, json_data={"data": {"balance": 6.6}})
monkeypatch.setattr("requests.get", fake_get)
result = fetch_balance(PLATFORM_GET, "k", retry_count=2, timeout=10)
assert result.ok and result.balance == 6.6
assert len(calls) == 2 # 瞬时 401 重试后成功,不误判禁用
def test_5xx_retries_then_success(self, monkeypatch):
calls = []
+41
View File
@@ -0,0 +1,41 @@
"""monitor 调度链路测试:api_key base64 解码等关键行为。"""
import base64
from app.monitor import _split
def _row(**overrides):
row = {
"id": 1, "platform_id": 2, "name": "a",
"api_key": base64.b64encode(b"sk-123").decode(),
"threshold": 0, "enabled": 1, "alert_armed": 1,
"last_balance": None, "last_status": "pending", "last_error": "",
"last_check_at": None, "note": "",
"platform_name": "P", "currency": "USD", "icon": "", "method": "GET",
"url": "http://x", "headers": "{}", "body": "", "balance_path": "b",
"interval_seconds": None, "retry_count": None, "timeout_seconds": None,
"platform_enabled": 1, "platform_note": "",
}
row.update(overrides)
return row
class TestSplit:
def test_api_key_decoded(self):
"""监控链路必须使用解码后的明文 key,否则请求永远 401。"""
account, platform = _split(_row())
assert account["api_key"] == "sk-123"
def test_platform_fields_mapped(self):
account, platform = _split(_row())
assert platform["name"] == "P"
assert platform["id"] == 2
assert platform["enabled"] == 1
assert platform["url"] == "http://x"
assert platform["balance_path"] == "b"
def test_plain_key_passthrough(self):
"""未编码的 key(历史数据)原样使用,不抛错。"""
account, _ = _split(_row(api_key="sk-plain"))
assert account["api_key"] == "sk-plain"