test: add memory database tests and update conftest for DB isolation
conftest patches mdb._DB_PATH and calls init_db() after directory creation so all existing tests continue to work with the new DB layer. New test_memory_db.py covers upsert, search, remove, migration, and the updated list_memories/lookup_memories integration paths. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,7 @@ def tmp_pyra_home(tmp_path, monkeypatch):
|
||||
|
||||
import pyra.plugins.loader as pl
|
||||
import pyra.plugins.executor as pe
|
||||
import pyra.memory.database as mdb
|
||||
|
||||
b.VAULT_PATH = fake_home / "vault"
|
||||
b.BLOCKED_PREFIXES = [b.VAULT_PATH]
|
||||
@@ -35,6 +36,8 @@ def tmp_pyra_home(tmp_path, monkeypatch):
|
||||
mi._INDEX_FILE = fake_home / "memory" / "MEMORY_INDEX.md"
|
||||
mr._MEMORY_ROOT = fake_home / "memory"
|
||||
mw._MEMORY_ROOT = fake_home / "memory"
|
||||
mdb._DB_PATH = fake_home / "memory" / "memory.db"
|
||||
mdb._MEMORY_ROOT = fake_home / "memory"
|
||||
vr._KEYS_FILE = fake_home / "vault" / "secrets" / "api_keys.json"
|
||||
vw._KEYS_FILE = fake_home / "vault" / "secrets" / "api_keys.json"
|
||||
si._LOG_FILE = fake_home / "security.log"
|
||||
@@ -52,6 +55,8 @@ def tmp_pyra_home(tmp_path, monkeypatch):
|
||||
(fake_home / "plugins").mkdir()
|
||||
(fake_home / "logs").mkdir()
|
||||
|
||||
mdb.init_db()
|
||||
|
||||
# Reset plugin registry singleton so tests don't share state
|
||||
from pyra.plugins.registry import PluginRegistry
|
||||
PluginRegistry.reset()
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
import json
|
||||
|
||||
|
||||
def test_init_creates_db(tmp_pyra_home):
|
||||
from pyra.memory import database
|
||||
assert database._DB_PATH.exists()
|
||||
|
||||
|
||||
def test_upsert_and_list(tmp_pyra_home):
|
||||
from pyra.memory import database
|
||||
database.upsert(
|
||||
"user/profile.md",
|
||||
content="# Profile\n\nI am a developer.",
|
||||
category="user",
|
||||
size_bytes=30,
|
||||
modified="2026-05-18T10:00:00",
|
||||
summary="Developer profile",
|
||||
keywords=["developer", "profile"],
|
||||
)
|
||||
rows = database.list_all()
|
||||
assert len(rows) == 1
|
||||
row = rows[0]
|
||||
assert row["path"] == "user/profile.md"
|
||||
assert row["category"] == "user"
|
||||
assert row["summary"] == "Developer profile"
|
||||
assert row["keywords"] == ["developer", "profile"]
|
||||
|
||||
|
||||
def test_upsert_overwrites(tmp_pyra_home):
|
||||
from pyra.memory import database
|
||||
database.upsert("context/notes.md", content="old", category="context",
|
||||
modified="2026-05-18T10:00:00")
|
||||
database.upsert("context/notes.md", content="new", category="context",
|
||||
summary="updated", modified="2026-05-18T11:00:00")
|
||||
rows = database.list_all()
|
||||
assert len(rows) == 1
|
||||
assert rows[0]["summary"] == "updated"
|
||||
|
||||
|
||||
def test_remove(tmp_pyra_home):
|
||||
from pyra.memory import database
|
||||
database.upsert("knowledge/facts.md", content="Some facts.", category="knowledge",
|
||||
modified="2026-05-18T10:00:00")
|
||||
assert len(database.list_all()) == 1
|
||||
database.remove("knowledge/facts.md")
|
||||
assert len(database.list_all()) == 0
|
||||
|
||||
|
||||
def test_search_fts(tmp_pyra_home):
|
||||
from pyra.memory import database
|
||||
database.upsert("user/profile.md", content="I enjoy building AI tools.",
|
||||
category="user", modified="2026-05-18T10:00:00",
|
||||
summary="Personal bio", keywords=["AI", "tools"])
|
||||
database.upsert("knowledge/cooking.md", content="Pasta recipes and techniques.",
|
||||
category="knowledge", modified="2026-05-18T10:00:00",
|
||||
summary="Cooking notes", keywords=["pasta", "cooking"])
|
||||
results = database.search("AI tools")
|
||||
assert len(results) == 1
|
||||
assert results[0]["file"] == "user/profile.md"
|
||||
assert results[0]["summary"] == "Personal bio"
|
||||
assert "AI" in results[0]["keywords"]
|
||||
|
||||
|
||||
def test_search_no_match(tmp_pyra_home):
|
||||
from pyra.memory import database
|
||||
database.upsert("user/profile.md", content="Hello world.", category="user",
|
||||
modified="2026-05-18T10:00:00")
|
||||
results = database.search("xyzzy")
|
||||
assert results == []
|
||||
|
||||
|
||||
def test_search_invalid_query_returns_empty(tmp_pyra_home):
|
||||
from pyra.memory import database
|
||||
database.upsert("user/profile.md", content="Hello world.", category="user",
|
||||
modified="2026-05-18T10:00:00")
|
||||
# FTS5 special chars that could raise OperationalError are handled gracefully
|
||||
results = database.search('"unclosed quote')
|
||||
assert isinstance(results, list)
|
||||
|
||||
|
||||
def test_migrate_from_files(tmp_pyra_home):
|
||||
from pyra.memory.writer import write_memory
|
||||
from pyra.memory import database
|
||||
|
||||
write_memory("user/note.md", "Migration test content.")
|
||||
|
||||
# Wipe DB to simulate fresh state before migration
|
||||
database.remove("user/note.md")
|
||||
assert database.list_all() == []
|
||||
|
||||
# Manually call migrate — it should re-populate from the .md file
|
||||
database.migrate_from_files()
|
||||
rows = database.list_all()
|
||||
assert any(r["path"] == "user/note.md" for r in rows)
|
||||
|
||||
|
||||
def test_list_memories_uses_db(tmp_pyra_home):
|
||||
from pyra.memory.writer import write_memory
|
||||
from pyra.memory.reader import list_memories
|
||||
|
||||
write_memory("context/project.md", "# Project\n\nActive tasks.")
|
||||
memories = list_memories()
|
||||
names = [m.name for m in memories]
|
||||
assert "context/project.md" in names
|
||||
|
||||
|
||||
def test_lookup_memories_uses_fts(tmp_pyra_home):
|
||||
from pyra.memory.writer import write_memory
|
||||
from pyra.memory.reader import lookup_memories
|
||||
|
||||
write_memory(
|
||||
"knowledge/python.md",
|
||||
"Python is a high-level programming language.",
|
||||
summary="Python overview",
|
||||
keywords=["python", "programming"],
|
||||
)
|
||||
results = lookup_memories("programming language")
|
||||
assert len(results) >= 1
|
||||
assert results[0]["file"] == "knowledge/python.md"
|
||||
Reference in New Issue
Block a user