2026-04-30 14:11:46 +08:00
|
|
|
|
"""Memory 检索:无 recent fallback;compaction 后事实 stale。"""
|
2026-04-03 10:12:59 +08:00
|
|
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
2026-04-30 14:11:46 +08:00
|
|
|
|
from unittest.mock import AsyncMock, MagicMock
|
2026-04-03 10:12:59 +08:00
|
|
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
|
|
|
|
from app.features.memory import repo as memory_repo
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-04-30 14:11:46 +08:00
|
|
|
|
@pytest.mark.asyncio
|
|
|
|
|
|
async def test_search_facts_async_does_not_use_recent_fallback(
|
2026-04-03 10:12:59 +08:00
|
|
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
|
|
|
|
) -> None:
|
|
|
|
|
|
calls: list[bool] = []
|
|
|
|
|
|
|
2026-04-30 14:11:46 +08:00
|
|
|
|
async def boom(*_a, **_k):
|
2026-04-03 10:12:59 +08:00
|
|
|
|
calls.append(True)
|
2026-04-30 14:11:46 +08:00
|
|
|
|
raise AssertionError("get_facts_for_user should not run")
|
2026-04-03 10:12:59 +08:00
|
|
|
|
|
2026-04-30 14:11:46 +08:00
|
|
|
|
monkeypatch.setattr(memory_repo, "get_facts_for_user", boom)
|
2026-04-03 10:12:59 +08:00
|
|
|
|
|
|
|
|
|
|
mock_session = MagicMock()
|
2026-04-30 14:11:46 +08:00
|
|
|
|
result = MagicMock()
|
|
|
|
|
|
result.unique.return_value.scalars.return_value.all.return_value = []
|
|
|
|
|
|
mock_session.execute = AsyncMock(return_value=result)
|
2026-04-03 10:12:59 +08:00
|
|
|
|
|
2026-04-30 14:11:46 +08:00
|
|
|
|
out = await memory_repo.search_facts_for_user_async(
|
2026-04-03 10:12:59 +08:00
|
|
|
|
mock_session, "user-1", "no_such_subject_xyz", 5
|
|
|
|
|
|
)
|
|
|
|
|
|
assert out == []
|
|
|
|
|
|
assert calls == []
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-04-30 14:11:46 +08:00
|
|
|
|
@pytest.mark.asyncio
|
|
|
|
|
|
async def test_search_facts_async_empty_query_returns_empty_without_fallback(
|
2026-04-03 10:12:59 +08:00
|
|
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
|
|
|
|
) -> None:
|
2026-04-30 14:11:46 +08:00
|
|
|
|
calls: list[bool] = []
|
2026-04-03 10:12:59 +08:00
|
|
|
|
|
2026-04-30 14:11:46 +08:00
|
|
|
|
async def boom(*_a, **_k):
|
|
|
|
|
|
calls.append(True)
|
|
|
|
|
|
raise AssertionError("get_facts_for_user should not run")
|
2026-04-03 10:12:59 +08:00
|
|
|
|
|
2026-04-30 14:11:46 +08:00
|
|
|
|
monkeypatch.setattr(memory_repo, "get_facts_for_user", boom)
|
2026-04-03 10:12:59 +08:00
|
|
|
|
|
|
|
|
|
|
mock_session = MagicMock()
|
2026-04-30 14:11:46 +08:00
|
|
|
|
out = await memory_repo.search_facts_for_user_async(mock_session, "user-1", "", 5)
|
|
|
|
|
|
assert out == []
|
|
|
|
|
|
assert calls == []
|
2026-04-03 10:12:59 +08:00
|
|
|
|
|
|
|
|
|
|
|
2026-04-30 14:11:46 +08:00
|
|
|
|
@pytest.mark.asyncio
|
|
|
|
|
|
async def test_mark_facts_stale_for_excluded_chunk_returns_rowcount() -> None:
|
2026-04-03 10:12:59 +08:00
|
|
|
|
session = MagicMock()
|
2026-04-30 14:11:46 +08:00
|
|
|
|
session.execute = AsyncMock(return_value=MagicMock(rowcount=3))
|
|
|
|
|
|
n = await memory_repo.mark_facts_stale_for_excluded_chunk(
|
2026-04-03 10:12:59 +08:00
|
|
|
|
session, user_id="u1", chunk_id="chunk-9"
|
|
|
|
|
|
)
|
|
|
|
|
|
assert n == 3
|