mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-08-29 03:56:43 +08:00
94 lines
3.0 KiB
Python
94 lines
3.0 KiB
Python
"""Agent 会话删除的请求级事务边界测试。"""
|
|
|
|
from types import SimpleNamespace
|
|
from unittest.mock import AsyncMock, Mock
|
|
|
|
import pytest
|
|
|
|
from app.application.messaging.chat import AgentChatService
|
|
|
|
|
|
def _principal() -> SimpleNamespace:
|
|
"""构造拥有目标会话的普通用户。"""
|
|
return SimpleNamespace(id=1, name="alice", is_superuser=False)
|
|
|
|
|
|
def _chat() -> SimpleNamespace:
|
|
"""构造应用服务投影所需的最小会话记录。"""
|
|
return SimpleNamespace(
|
|
id=9,
|
|
session_id="session-9",
|
|
client_session_id=None,
|
|
title="事务会话",
|
|
channel=None,
|
|
source=None,
|
|
user_id="1",
|
|
username="alice",
|
|
original_chat_id=None,
|
|
message_count=0,
|
|
created_at=None,
|
|
updated_at=None,
|
|
display_messages=[],
|
|
agent_messages=[],
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_delete_stages_then_commits_once() -> None:
|
|
"""有权限的会话删除只能由 Service 在暂存成功后提交一次。"""
|
|
calls: list[str] = []
|
|
repository = Mock()
|
|
repository.async_get = AsyncMock(return_value=_chat())
|
|
repository.async_stage_delete = AsyncMock(
|
|
side_effect=lambda **_kwargs: calls.append("stage") or True
|
|
)
|
|
unit_of_work = Mock()
|
|
unit_of_work.commit = AsyncMock(
|
|
side_effect=lambda: calls.append("commit")
|
|
)
|
|
unit_of_work.rollback = AsyncMock()
|
|
service = AgentChatService(repository, unit_of_work)
|
|
|
|
assert await service.delete("session-9", _principal()) is True
|
|
|
|
assert calls == ["stage", "commit"]
|
|
unit_of_work.rollback.assert_not_awaited()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_delete_rolls_back_flush_failure() -> None:
|
|
"""暂存删除失败必须回滚并传播原异常。"""
|
|
error = RuntimeError("flush failed")
|
|
repository = Mock()
|
|
repository.async_get = AsyncMock(return_value=_chat())
|
|
repository.async_stage_delete = AsyncMock(side_effect=error)
|
|
unit_of_work = Mock()
|
|
unit_of_work.commit = AsyncMock()
|
|
unit_of_work.rollback = AsyncMock()
|
|
service = AgentChatService(repository, unit_of_work)
|
|
|
|
with pytest.raises(RuntimeError) as raised:
|
|
await service.delete("session-9", _principal())
|
|
|
|
assert raised.value is error
|
|
unit_of_work.commit.assert_not_awaited()
|
|
unit_of_work.rollback.assert_awaited_once_with()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_delete_missing_chat_does_not_open_write_transaction() -> None:
|
|
"""会话不存在时保持旧 False 返回,且不执行 stage 或 commit。"""
|
|
repository = Mock()
|
|
repository.async_get = AsyncMock(return_value=None)
|
|
repository.async_stage_delete = AsyncMock()
|
|
unit_of_work = Mock()
|
|
unit_of_work.commit = AsyncMock()
|
|
unit_of_work.rollback = AsyncMock()
|
|
service = AgentChatService(repository, unit_of_work)
|
|
|
|
assert await service.delete("missing", _principal()) is False
|
|
|
|
repository.async_stage_delete.assert_not_awaited()
|
|
unit_of_work.commit.assert_not_awaited()
|
|
unit_of_work.rollback.assert_not_awaited()
|