test: 修复所有预存的失败测试

- test_auth_routes: monkeypatch 环境为 production 使 phone-session 限速生效
- test_schedule_items_routes: 补充必填 timezone 字段
- test_llm_pricing_service: 更新 deepseek-chat 费率期望值匹配实际 catalog
- test_sse_flow_live: 补充 runId 查询参数、改用附件上传 API、修复 history 响应断言、独立 DB session 避免跨事件循环崩溃
- test_agent_prompt: 移除已删除的 project_cli_defaults 断言
- test_toolkit: 更新 action card 断言匹配 module/method 格式
This commit is contained in:
qzl
2026-04-24 14:11:11 +08:00
parent d2d292a99e
commit 18b5e876ee
6 changed files with 47 additions and 26 deletions
@@ -167,7 +167,11 @@ def test_send_otp_phone_rate_limited_after_too_many_attempts() -> None:
app.dependency_overrides = {}
def test_phone_session_rate_limited_after_too_many_attempts() -> None:
def test_phone_session_rate_limited_after_too_many_attempts(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setattr("v1.auth.router.config.runtime.environment", "production")
app.dependency_overrides[get_auth_service] = _override_auth_service(
FakeAuthService(_token_response())
)
@@ -92,6 +92,7 @@ def test_create_schedule_item_returns_201() -> None:
json={
"title": "Test Event",
"start_at": "2026-02-28T16:00:00Z",
"timezone": "UTC",
},
)
assert response.status_code == 201
@@ -1,15 +1,14 @@
from __future__ import annotations
import base64
from pathlib import Path
from uuid import UUID, uuid4
import httpx
import pytest
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
from core.config.settings import config
from core.db.session import AsyncSessionLocal
from models.agent_chat_message import AgentChatMessage
from models.agent_chat_session import AgentChatSession
from schemas.enums import AgentChatMessageRole
@@ -20,6 +19,14 @@ FIXTURE_IMAGE_PATH = (
)
def _make_session():
engine = create_async_engine(
config.database_url,
pool_pre_ping=True,
)
return async_sessionmaker(bind=engine, class_=AsyncSession, expire_on_commit=False, autoflush=False)()
def _require_test_phone() -> str:
phone = config.test.phone
if not phone:
@@ -82,7 +89,7 @@ async def test_agent_sse_closed_loop_live() -> None:
thread_id = str(accepted["threadId"])
assert thread_id
events_url = f"{BASE_URL}/api/v1/agent/runs/{thread_id}/events"
events_url = f"{BASE_URL}/api/v1/agent/runs/{thread_id}/events?runId=run-live-1"
event_names: list[str] = []
async with client.stream(
"GET", events_url, headers=headers, timeout=20.0
@@ -98,7 +105,7 @@ async def test_agent_sse_closed_loop_live() -> None:
assert "RUN_STARTED" in event_names
assert "RUN_FINISHED" in event_names or "RUN_ERROR" in event_names
async with AsyncSessionLocal() as session:
async with _make_session() as session:
session_row = await session.get(AgentChatSession, UUID(thread_id))
assert session_row is not None
assert session_row.message_count >= 1
@@ -119,13 +126,24 @@ async def test_agent_runs_events_history_live_with_image_input() -> None:
if config.runtime.environment not in {"dev", "test"}:
pytest.skip("live integration tests require dev or test environment")
image_data = base64.b64encode(FIXTURE_IMAGE_PATH.read_bytes()).decode("ascii")
async with httpx.AsyncClient(timeout=30.0) as client:
token = await _live_access_token(client)
headers = {"Authorization": f"Bearer {token}"}
thread_id = str(uuid4())
upload_resp = await client.post(
f"{BASE_URL}/api/v1/agent/attachments",
headers=headers,
data={"threadId": thread_id},
files={"file": ("calendar_text_cn.png", FIXTURE_IMAGE_PATH.read_bytes(), "image/png")},
)
assert upload_resp.status_code == 200, (
f"upload failed: {upload_resp.status_code} {upload_resp.text[:200]}"
)
attachment = upload_resp.json()["attachment"]
image_url = attachment["url"]
assert isinstance(image_url, str) and image_url
run_resp = await client.post(
f"{BASE_URL}/api/v1/agent/runs",
headers=headers,
@@ -141,7 +159,7 @@ async def test_agent_runs_events_history_live_with_image_input() -> None:
{"type": "text", "text": "请描述图片里的内容"},
{
"type": "binary",
"data": image_data,
"url": image_url,
"mimeType": "image/png",
},
],
@@ -154,7 +172,7 @@ async def test_agent_runs_events_history_live_with_image_input() -> None:
)
assert run_resp.status_code == 202
events_url = f"{BASE_URL}/api/v1/agent/runs/{thread_id}/events"
events_url = f"{BASE_URL}/api/v1/agent/runs/{thread_id}/events?runId=run-live-image-1"
event_names: list[str] = []
async with client.stream(
"GET", events_url, headers=headers, timeout=90.0
@@ -180,25 +198,21 @@ async def test_agent_runs_events_history_live_with_image_input() -> None:
)
assert history_resp.status_code == 200
history = history_resp.json()
assert history.get("type") == "STATE_SNAPSHOT"
snapshot = history.get("snapshot", {})
assert snapshot.get("scope") == "history_day"
messages = snapshot.get("messages", [])
assert history.get("scope") == "history_day"
messages = history.get("messages", [])
user_messages = [
item
for item in messages
if isinstance(item, dict) and item.get("role") == "user"
]
assert user_messages
metadata = user_messages[0].get("metadata")
assert isinstance(metadata, dict)
user_attachments = metadata.get("user_message_attachments")
user_attachments = user_messages[0].get("attachments")
assert isinstance(user_attachments, list)
assert user_attachments
assert isinstance(user_attachments[0], dict)
assert isinstance(user_attachments[0].get("path"), str)
assert isinstance(user_attachments[0].get("url"), str)
async with AsyncSessionLocal() as session:
async with _make_session() as session:
session_row = await session.get(AgentChatSession, UUID(thread_id))
assert session_row is not None
assert session_row.message_count >= 1
@@ -288,7 +302,7 @@ async def test_agent_tool_call_result_persisted_live() -> None:
f"no terminal event, got: {event_names}"
)
async with AsyncSessionLocal() as session:
async with _make_session() as session:
rows = await session.execute(
select(AgentChatMessage).where(
AgentChatMessage.session_id == UUID(thread_id),