mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 17:30:23 +08:00
- 将 Antigravity 和 Codex 从独立模块迁移至 src/services/provider/adapters/ 插件体系 - 新增 provider_types 和 oauth_token 模块,移除 maintenance_scheduler 中的 OAuth 定时刷新 - 增强 admin API:扩展 keys 和 provider_query 端点,新增 dashboard 路由 - 大幅增强 ProviderDetailDrawer 组件,新增 AntigravityQuotaDialog - 改进 handler 基类(chat/cli)和错误分类器 - 优化 fetch_scheduler 和 upstream_fetcher - 前端 UI 组件清理和优化 - 更新测试以匹配新模块结构
62 lines
1.5 KiB
Python
62 lines
1.5 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from types import SimpleNamespace
|
|
from unittest.mock import AsyncMock
|
|
|
|
import pytest
|
|
|
|
from src.api.handlers.claude.adapter import ClaudeChatAdapter
|
|
|
|
|
|
@dataclass
|
|
class _DummyResp:
|
|
status_code: int
|
|
payload: object
|
|
text: str = ""
|
|
|
|
def json(self) -> object: # noqa: D401
|
|
"""Return mocked JSON payload."""
|
|
return self.payload
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_claude_fetch_models_paginates_until_has_more_false() -> None:
|
|
page1 = {
|
|
"data": [{"id": "m1"}, {"id": "m2"}],
|
|
"has_more": True,
|
|
"first_id": "m1",
|
|
"last_id": "m2",
|
|
}
|
|
page2 = {
|
|
"data": [{"id": "m3"}],
|
|
"has_more": False,
|
|
"first_id": "m3",
|
|
"last_id": "m3",
|
|
}
|
|
|
|
client = SimpleNamespace(
|
|
get=AsyncMock(
|
|
side_effect=[
|
|
_DummyResp(status_code=200, payload=page1),
|
|
_DummyResp(status_code=200, payload=page2),
|
|
]
|
|
)
|
|
)
|
|
|
|
models, err = await ClaudeChatAdapter.fetch_models(
|
|
client, # type: ignore[arg-type]
|
|
"https://api.anthropic.com",
|
|
"k",
|
|
None,
|
|
)
|
|
|
|
assert err is None
|
|
assert [m.get("id") for m in models] == ["m1", "m2", "m3"]
|
|
assert all(m.get("api_format") == "claude:chat" for m in models)
|
|
|
|
# Second page should pass after_id=last_id from page1.
|
|
assert client.get.call_count == 2
|
|
_, kwargs2 = client.get.call_args_list[1]
|
|
assert kwargs2.get("params", {}).get("after_id") == "m2"
|