66 lines
2.2 KiB
Python
66 lines
2.2 KiB
Python
"""多 Provider failover 单元测试(mock 数据,不依赖网络)。"""
|
|||
|
|
from types import SimpleNamespace
|
||
|
|
from unittest.mock import patch
|
||
|
|
|
||
|
|
from app.failover import (FAILOVER_KINDS, failover_candidates, failover_target,
|
||
|
|
should_failover)
|
||
|
|
|
||
|
|
|
||
|
|
def _provider(pid, name, models, default_model="", enabled=True):
|
||
|
|
return SimpleNamespace(id=pid, name=name, models=list(models),
|
||
|
|
default_model=default_model or (models[0] if models else ""),
|
||
|
|
enabled=enabled)
|
||
|
|
|
||
|
|
|
||
|
|
def _session(providers):
|
||
|
|
return SimpleNamespace(exec=lambda *a, **k: SimpleNamespace(all=lambda: providers))
|
||
|
|
|
||
|
|
|
||
|
|
def test_should_failover_kinds():
|
||
|
|
assert should_failover("auth")
|
||
|
|
assert should_failover("rate_limit")
|
||
|
|
assert should_failover("connection")
|
||
|
|
assert should_failover("model_not_found")
|
||
|
|
assert not should_failover("other")
|
||
|
|
assert not should_failover("rejected")
|
||
|
|
|
||
|
|
|
||
|
|
def test_candidates_excludes_current_and_disabled():
|
||
|
|
providers = [
|
||
|
|
_provider(1, "主", ["m1"]),
|
||
|
|
_provider(2, "备一", ["m1"]),
|
||
|
|
_provider(3, "备二", ["m2"], enabled=False),
|
||
|
|
]
|
||
|
|
session = _session(providers)
|
||
|
|
ids = [p.id for p in failover_candidates(session, 1)]
|
||
|
|
assert ids == [2]
|
||
|
|
|
||
|
|
|
||
|
|
def test_target_prefers_same_model():
|
||
|
|
providers = [
|
||
|
|
_provider(1, "主", ["deepseek-chat"]),
|
||
|
|
_provider(2, "备一", ["deepseek-chat", "mimo"], default_model="mimo"),
|
||
|
|
_provider(3, "备二", ["glm-4"], default_model="glm-4"),
|
||
|
|
]
|
||
|
|
session = _session(providers)
|
||
|
|
target = failover_target(session, 1, "deepseek-chat")
|
||
|
|
assert target is not None
|
||
|
|
assert target[0].id == 2 and target[1] == "deepseek-chat"
|
||
|
|
|
||
|
|
|
||
|
|
def test_target_falls_back_to_default_model():
|
||
|
|
providers = [
|
||
|
|
_provider(1, "主", ["deepseek-chat"]),
|
||
|
|
_provider(2, "备一", ["glm-4"], default_model="glm-4"),
|
||
|
|
]
|
||
|
|
session = _session(providers)
|
||
|
|
target = failover_target(session, 1, "deepseek-chat")
|
||
|
|
assert target is not None
|
||
|
|
assert target[0].id == 2 and target[1] == "glm-4"
|
||
|
|
|
||
|
|
|
||
|
|
def test_target_none_when_no_alternatives():
|
||
|
|
providers = [_provider(1, "主", ["deepseek-chat"])]
|
||
|
|
session = _session(providers)
|
||
|
|
assert failover_target(session, 1, "deepseek-chat") is None
|