ForcePilot/backend/test/unit/server/utils/test_lifespan.py
Kris bab30f2715
Some checks failed
Deploy VitePress site to Pages / build (push) Has been cancelled
Ruff Format Check / Ruff Format & Lint (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
feat:0715
2026-07-15 12:30:58 +08:00

102 lines
3.9 KiB
Python

from __future__ import annotations
from unittest.mock import AsyncMock, MagicMock
import pytest
from fastapi import FastAPI
@pytest.fixture
def app():
return FastAPI()
@pytest.fixture
def lifespan_mocks(monkeypatch):
"""为 lifespan 测试准备最小 mock 集,使其能进入/退出上下文。"""
mocks = {
"channel_bootstrap": AsyncMock(),
}
# 渠道启动器
channel_class_mock = MagicMock(return_value=mocks["channel_bootstrap"])
monkeypatch.setattr("server.utils.lifespan.ChannelGatewayBootstrap", channel_class_mock)
# 数据库与基础服务
mock_pg_manager = MagicMock()
mock_pg_manager.initialize = MagicMock()
mock_pg_manager.create_tables = AsyncMock()
mock_pg_manager.ensure_business_schema = AsyncMock()
mock_pg_manager.ensure_knowledge_schema = AsyncMock()
mock_pg_manager.close = AsyncMock()
mock_pg_manager.langgraph_pool = MagicMock()
mock_pg_manager.get_async_session_context = MagicMock()
monkeypatch.setattr("server.utils.lifespan.pg_manager", mock_pg_manager)
monkeypatch.setattr("server.utils.lifespan.ensure_builtin_mcp_servers_in_db", AsyncMock())
monkeypatch.setattr("server.utils.lifespan.ensure_builtin_model_providers_in_db", AsyncMock())
monkeypatch.setattr("server.utils.lifespan.get_redis_client", AsyncMock())
monkeypatch.setattr("server.utils.lifespan.close_queue_clients", AsyncMock())
monkeypatch.setattr("server.utils.lifespan.init_sandbox_provider", MagicMock())
monkeypatch.setattr("server.utils.lifespan.shutdown_sandbox_provider", MagicMock())
mock_tasker = MagicMock()
mock_tasker.start = AsyncMock()
mock_tasker.shutdown = AsyncMock()
monkeypatch.setattr("server.utils.lifespan.tasker", mock_tasker)
# 知识库、模型缓存、AgentRepository、内置技能
mock_kb = MagicMock()
mock_kb.initialize = AsyncMock()
monkeypatch.setattr("server.utils.lifespan.knowledge_base", mock_kb)
monkeypatch.setattr("server.utils.lifespan.model_cache", MagicMock())
async def _noop(*args, **kwargs):
pass
mock_agent_repo = MagicMock()
mock_agent_repo.ensure_default_agent = AsyncMock()
mock_agent_repo.ensure_general_purpose_subagent = AsyncMock()
mock_agent_repo.ensure_web_search_subagent = AsyncMock()
mock_agent_repo.ensure_deep_research_agents = AsyncMock()
monkeypatch.setattr("server.utils.lifespan.AgentRepository", lambda session: mock_agent_repo)
monkeypatch.setattr("server.utils.lifespan.get_all_model_providers", AsyncMock())
monkeypatch.setattr("server.utils.lifespan.init_builtin_skills", _noop)
# LangGraph checkpointer
checkpointer_mock = MagicMock()
checkpointer_mock.setup = AsyncMock()
monkeypatch.setattr("server.utils.lifespan.AsyncPostgresSaver", lambda pool: checkpointer_mock)
monkeypatch.setattr("server.utils.lifespan.get_version", lambda: "0.0.0-test")
return mocks
async def test_lifespan_starts_and_stops_channel_gateway(app, lifespan_mocks):
"""验证 lifespan 启动时会启动多渠道网关,关闭时会停止。"""
from server.utils.lifespan import lifespan
async with lifespan(app):
pass
bootstrap_mock = lifespan_mocks["channel_bootstrap"]
bootstrap_mock.start.assert_awaited_once_with(app)
bootstrap_mock.stop.assert_awaited_once()
async def test_lifespan_logs_but_continues_when_channel_start_fails(app, lifespan_mocks, caplog):
"""验证渠道网关启动失败时应用仍可启动,并在关闭时安全停止。"""
from server.utils.lifespan import lifespan
lifespan_mocks["channel_bootstrap"].start.side_effect = RuntimeError("channel boom")
with caplog.at_level("ERROR"):
async with lifespan(app):
pass
bootstrap_mock = lifespan_mocks["channel_bootstrap"]
bootstrap_mock.start.assert_awaited_once_with(app)
bootstrap_mock.stop.assert_awaited_once()
assert "Failed to start channel gateway during startup" in caplog.text