mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-03 01:40:21 +08:00
将 admin keys 接口的创建、更新、查询、删除、导出与配额刷新逻辑迁移到 provider_keys 服务层 新增 auth_type 归一化、重复校验、响应构建与 quota_refresh(codex/kiro/antigravity)模块,并补充对应单元测试
156 lines
5.1 KiB
Python
156 lines
5.1 KiB
Python
from __future__ import annotations
|
|
|
|
from types import SimpleNamespace
|
|
from typing import Any, cast
|
|
|
|
import pytest
|
|
|
|
from src.core.exceptions import NotFoundException
|
|
from src.services.provider_keys import key_query_service as query_service_module
|
|
from src.services.provider_keys.key_query_service import (
|
|
get_keys_grouped_by_format,
|
|
list_provider_keys_responses,
|
|
)
|
|
|
|
|
|
class _FakeQuery:
|
|
def __init__(
|
|
self,
|
|
*,
|
|
first_result: Any = None,
|
|
all_result: list[Any] | None = None,
|
|
) -> None:
|
|
self._first_result = first_result
|
|
self._all_result = all_result or []
|
|
|
|
def join(self, *args: Any, **kwargs: Any) -> _FakeQuery:
|
|
return self
|
|
|
|
def filter(self, *args: Any, **kwargs: Any) -> _FakeQuery:
|
|
return self
|
|
|
|
def order_by(self, *args: Any, **kwargs: Any) -> _FakeQuery:
|
|
return self
|
|
|
|
def offset(self, *args: Any, **kwargs: Any) -> _FakeQuery:
|
|
return self
|
|
|
|
def limit(self, *args: Any, **kwargs: Any) -> _FakeQuery:
|
|
return self
|
|
|
|
def first(self) -> Any:
|
|
return self._first_result
|
|
|
|
def all(self) -> list[Any]:
|
|
return self._all_result
|
|
|
|
|
|
class _FakeGroupedDB:
|
|
def __init__(
|
|
self,
|
|
*,
|
|
key_provider_rows: list[tuple[Any, Any]],
|
|
endpoint_rows: list[tuple[str, str, str]],
|
|
) -> None:
|
|
self._key_provider_rows = key_provider_rows
|
|
self._endpoint_rows = endpoint_rows
|
|
|
|
def query(self, *models: Any) -> _FakeQuery:
|
|
if len(models) == 2:
|
|
return _FakeQuery(all_result=self._key_provider_rows)
|
|
if len(models) == 3:
|
|
return _FakeQuery(all_result=self._endpoint_rows)
|
|
raise AssertionError(f"unexpected query models: {models}")
|
|
|
|
|
|
class _FakeListDB:
|
|
def __init__(self, *, provider: Any, keys: list[SimpleNamespace]) -> None:
|
|
self._provider = provider
|
|
self._keys = keys
|
|
|
|
def query(self, model: Any) -> _FakeQuery:
|
|
model_name = getattr(model, "__name__", "")
|
|
if model_name == "Provider":
|
|
return _FakeQuery(first_result=self._provider)
|
|
if model_name == "ProviderAPIKey":
|
|
return _FakeQuery(all_result=self._keys)
|
|
raise AssertionError(f"unexpected query model: {model}")
|
|
|
|
|
|
def test_get_keys_grouped_by_format_builds_expected_shape(
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
provider = SimpleNamespace(id="p1", is_active=True, name="Provider-1")
|
|
key = SimpleNamespace(
|
|
id="k1",
|
|
name="Key-1",
|
|
api_formats=["openai:chat", "openai:cli"],
|
|
auth_type="api_key",
|
|
api_key="enc-key",
|
|
internal_priority=3,
|
|
global_priority_by_format={"openai:chat": 8},
|
|
rate_multipliers={"openai:chat": 1.1},
|
|
is_active=True,
|
|
capabilities={"cache_1h": True, "ctx_1m": False},
|
|
success_count=8,
|
|
request_count=10,
|
|
total_response_time_ms=800,
|
|
health_by_format={"openai:chat": {"health_score": 0.7}},
|
|
circuit_breaker_by_format={"openai:chat": {"open": True}},
|
|
)
|
|
db = _FakeGroupedDB(
|
|
key_provider_rows=[(key, provider)],
|
|
endpoint_rows=[
|
|
("p1", "openai:chat", "https://chat.example"),
|
|
("p1", "openai:cli", "https://cli.example"),
|
|
],
|
|
)
|
|
|
|
monkeypatch.setattr(
|
|
query_service_module.crypto_service, "decrypt", lambda _v: "sk-1234567890abcd"
|
|
)
|
|
monkeypatch.setattr(
|
|
query_service_module,
|
|
"get_capability",
|
|
lambda name: SimpleNamespace(short_name="缓存1h") if name == "cache_1h" else None,
|
|
)
|
|
|
|
result = get_keys_grouped_by_format(cast(Any, db))
|
|
|
|
assert set(result.keys()) == {"openai:chat", "openai:cli"}
|
|
chat_item = result["openai:chat"][0]
|
|
assert chat_item["id"] == "k1"
|
|
assert chat_item["provider_name"] == "Provider-1"
|
|
assert chat_item["endpoint_base_url"] == "https://chat.example"
|
|
assert chat_item["format_priority"] == 8
|
|
assert chat_item["circuit_breaker_open"] is True
|
|
assert chat_item["health_score"] == 0.7
|
|
assert chat_item["capabilities"] == ["缓存1h"]
|
|
assert chat_item["api_key_masked"].startswith("sk-12345")
|
|
assert chat_item["api_key_masked"].endswith("abcd")
|
|
|
|
cli_item = result["openai:cli"][0]
|
|
assert cli_item["endpoint_base_url"] == "https://cli.example"
|
|
assert cli_item["format_priority"] is None
|
|
assert cli_item["circuit_breaker_open"] is False
|
|
assert cli_item["health_score"] == 1.0
|
|
|
|
|
|
def test_list_provider_keys_responses_provider_not_found_raises() -> None:
|
|
db = _FakeListDB(provider=None, keys=[])
|
|
with pytest.raises(NotFoundException, match="Provider p1 不存在"):
|
|
list_provider_keys_responses(cast(Any, db), provider_id="p1", skip=0, limit=10)
|
|
|
|
|
|
def test_list_provider_keys_responses_uses_response_builder(
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
provider = SimpleNamespace(id="p1")
|
|
keys = [SimpleNamespace(id="k1"), SimpleNamespace(id="k2")]
|
|
db = _FakeListDB(provider=provider, keys=keys)
|
|
|
|
monkeypatch.setattr(query_service_module, "build_key_response", lambda key: {"id": key.id})
|
|
|
|
result = list_provider_keys_responses(cast(Any, db), provider_id="p1", skip=0, limit=10)
|
|
assert result == [{"id": "k1"}, {"id": "k2"}]
|