Files
life-echo/api/tests/test_conversation_history_turn_ids.py

75 lines
2.2 KiB
Python
Raw Normal View History

"""对话落库返回人/助 message id供 segment lineage 配对。"""
from __future__ import annotations
from contextlib import asynccontextmanager
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from sqlalchemy.ext.asyncio import AsyncSession
from app.features.conversation.history_store import HumanAiTurnIds
@asynccontextmanager
async def _capture_transactional(db):
yield db
await db.commit()
@pytest.mark.asyncio
async def test_record_human_ai_turn_returns_both_message_ids() -> None:
conv_id = "conv-1"
captured: list[object] = []
class FakeMsg:
def __init__(self, **kwargs) -> None:
for k, v in kwargs.items():
setattr(self, k, v)
class _FakeRepo:
@staticmethod
def add_conversation_message(msg: object, db) -> None:
captured.append(msg)
db = MagicMock(spec=AsyncSession)
db.commit = AsyncMock()
with patch(
"app.features.conversation.history_store.transactional",
_capture_transactional,
), patch(
"app.features.conversation.history_store.ConversationMessage",
FakeMsg,
), patch(
"app.features.conversation.history_store.repo",
_FakeRepo,
):
from app.features.conversation import history_store as hs
store = hs.ConversationHistoryStore(db)
store._sync_redis_best_effort = AsyncMock() # type: ignore[method-assign]
store._touch_conversation = AsyncMock() # type: ignore[method-assign]
out = await store.record_human_ai_turn(
conv_id,
"hello",
["reply a", "reply b"],
user_message_timestamp=None,
is_from_voice=False,
voice_session_id=None,
audio_duration_seconds=None,
tts_audio_urls=None,
segment_id="seg-1",
memory_retrieval_trace=None,
)
assert isinstance(out, HumanAiTurnIds)
assert len(captured) == 2
assert captured[0].role == "human"
assert captured[1].role == "ai"
assert captured[0].segment_id == "seg-1"
assert out.human_message_id == captured[0].id
assert out.assistant_message_id == captured[1].id
db.commit.assert_awaited_once()