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:
curo1305
2026-05-18 15:23:57 +02:00
parent b9b0918d3a
commit 399ed8b5df
2 changed files with 124 additions and 0 deletions
+5
View File
@@ -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()
+119
View File
@@ -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"