Files
Aether/tests/services/test_claude_fetch_models_pagination.py
fawney19 b88fb6273b refactor: Antigravity/Codex 服务重构为插件化适配器架构
- 将 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 组件清理和优化
- 更新测试以匹配新模块结构
2026-02-06 16:37:06 +08:00

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"