Files
Aether/tests/services/test_pool_quota_probe_scheduler.py
fawney19 25d38ae632 feat(oauth): 账号封禁前置 OAuth 验证、抽取 provider_context、完善账号状态分类
- 新增 verify_oauth_before_account_block:在标记账号封禁前先尝试刷新 token,
  区分 OAuth 过期与真正的账号级封禁,避免误标
- 抽取 provider_context.py 统一解析 provider_type,解决 ORM detached 访问问题
- account_state 新增 workspace_deactivated 分类和 auto-removable 状态集合,
  补充中文验证关键词匹配
- OAuth refresh 成功后仅清除可恢复的 token 错误,不再自动清除账号级 block
- deploy.sh 依赖指纹改用纯 shell 实现,移除对 Python tomllib 的依赖
- 前端 Pool 管理页面新增筛选和批量操作优化
- 补充对应测试用例
2026-03-20 16:50:59 +08:00

89 lines
2.7 KiB
Python

from __future__ import annotations
from datetime import datetime, timedelta, timezone
from types import SimpleNamespace
from src.services.provider_keys.pool_quota_probe_scheduler import _select_probe_key_ids
def _key(
key_id: str,
*,
last_used_at: datetime | None = None,
upstream_metadata: dict | None = None,
) -> SimpleNamespace:
return SimpleNamespace(
id=key_id,
last_used_at=last_used_at,
upstream_metadata=upstream_metadata or {},
)
def test_select_probe_key_ids_selects_silent_keys_only() -> None:
now = datetime(2026, 3, 5, 12, 0, 0, tzinfo=timezone.utc)
now_ts = int(now.timestamp())
keys = [
_key("k1"), # never used, should be probed
_key("k2", last_used_at=now - timedelta(minutes=2)), # recently used,仍可定期探测
_key(
"k3",
upstream_metadata={"codex": {"updated_at": now_ts - (20 * 60)}},
), # long-time no refresh, should be probed
]
selected = _select_probe_key_ids(
keys=keys, # type: ignore[arg-type]
provider_type="codex",
now_ts=now_ts,
interval_seconds=10 * 60,
last_probe_timestamps={},
limit=0,
)
assert selected == ["k1", "k2", "k3"]
def test_select_probe_key_ids_keeps_periodic_probe_even_after_recent_usage() -> None:
now = datetime(2026, 3, 5, 12, 0, 0, tzinfo=timezone.utc)
now_ts = int(now.timestamp())
keys = [
_key(
"k1",
last_used_at=now - timedelta(seconds=30),
upstream_metadata={"codex": {"updated_at": now_ts - (40 * 60)}},
)
]
# 即使 key 刚刚被真实流量使用,只要上次额度刷新/主动探测已过窗口,仍应继续定期探测
selected = _select_probe_key_ids(
keys=keys, # type: ignore[arg-type]
provider_type="codex",
now_ts=now_ts,
interval_seconds=10 * 60,
last_probe_timestamps={"k1": now_ts - (25 * 60)},
limit=0,
)
assert selected == ["k1"]
def test_select_probe_key_ids_applies_limit_by_oldest_anchor_first() -> None:
now = datetime(2026, 3, 5, 12, 0, 0, tzinfo=timezone.utc)
now_ts = int(now.timestamp())
keys = [
_key("k1", upstream_metadata={"codex": {"updated_at": now_ts - (60 * 60)}}),
_key("k2", upstream_metadata={"codex": {"updated_at": now_ts - (50 * 60)}}),
_key("k3", upstream_metadata={"codex": {"updated_at": now_ts - (40 * 60)}}),
]
selected = _select_probe_key_ids(
keys=keys, # type: ignore[arg-type]
provider_type="codex",
now_ts=now_ts,
interval_seconds=10 * 60,
last_probe_timestamps={},
limit=2,
)
assert selected == ["k1", "k2"]