mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
162 lines
5.0 KiB
Python
162 lines
5.0 KiB
Python
"""Tests for DocumentService."""
|
|
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
from typing import Tuple
|
|
|
|
import pytest
|
|
import pytest_asyncio
|
|
import yaml
|
|
from sqlalchemy import select
|
|
|
|
from basic_memory.models import Document
|
|
from basic_memory.services.document_service import (
|
|
DocumentNotFoundError,
|
|
DocumentWriteError,
|
|
DocumentError,
|
|
)
|
|
|
|
|
|
@pytest_asyncio.fixture
|
|
async def test_doc_path(document_service) -> Tuple[Path, str]:
|
|
path_id = "test_docs/test.md"
|
|
file_path = document_service.documents_base_path / path_id
|
|
return file_path, path_id
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_create_document_with_frontmatter(document_service, test_doc_path):
|
|
"""Test that created documents have proper frontmatter."""
|
|
|
|
file_path, path_id = test_doc_path
|
|
|
|
content = "# Test Document\n\nThis is a test."
|
|
doc = await document_service.create_document(path_id, content, {"type": "test"})
|
|
|
|
# Verify file content
|
|
file_content = file_path.read_text()
|
|
|
|
# Parse frontmatter
|
|
|
|
# Split content at the second "---" marker
|
|
_, frontmatter, doc_content = file_content.split("---", 2)
|
|
metadata = yaml.safe_load(frontmatter)
|
|
|
|
# Verify frontmatter contents
|
|
assert metadata["id"] == path_id
|
|
assert metadata["type"] == "test"
|
|
assert "created" in metadata
|
|
assert "modified" in metadata
|
|
|
|
# Verify timestamps are valid ISO format
|
|
datetime.fromisoformat(metadata["created"])
|
|
datetime.fromisoformat(metadata["modified"])
|
|
|
|
# Verify original content is preserved
|
|
assert content in doc_content
|
|
|
|
# Verify DB record
|
|
assert doc.path_id == path_id
|
|
assert doc.doc_metadata == {"type": "test"}
|
|
assert doc.checksum is not None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_create_document_cleanup_on_write_failure(document_service, test_doc_path):
|
|
"""Test that failed document creation cleans up DB record when file write fails."""
|
|
|
|
file_path, path_id = test_doc_path
|
|
|
|
def fail_write(self, content):
|
|
raise PermissionError("Mock write failure")
|
|
|
|
# Store original write_text method
|
|
original_write_text = Path.write_text
|
|
|
|
try:
|
|
# Replace write_text with our failing version
|
|
Path.write_text = fail_write
|
|
|
|
with pytest.raises(DocumentWriteError) as exc_info:
|
|
await document_service.create_document(path_id, "test content", {"type": "test"})
|
|
|
|
assert "Mock write failure" in str(exc_info.value)
|
|
|
|
# Verify DB record was cleaned up
|
|
query = select(Document).where(Document.path_id == path_id)
|
|
doc = await document_service.repository.find_one(query)
|
|
assert doc is None
|
|
|
|
# Verify no file was created
|
|
assert not file_path.exists()
|
|
|
|
finally:
|
|
# Restore original write_text method
|
|
Path.write_text = original_write_text
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_read_document_by_id(document_service, test_doc_path):
|
|
"""Test reading a document by ID."""
|
|
|
|
file_path, path_id = test_doc_path
|
|
|
|
# Create test document
|
|
content = "# Test Document\nTest content."
|
|
doc = await document_service.create_document(path_id, content, {"type": "test"})
|
|
|
|
# Read it back
|
|
retrieved_doc, retrieved_content = await document_service.read_document_by_path_id(path_id)
|
|
|
|
assert retrieved_doc.id == doc.id
|
|
assert retrieved_doc.path_id == path_id
|
|
assert content in retrieved_content # Original content should be in the result
|
|
assert "---" in retrieved_content # Should have frontmatter
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_read_document_by_id_not_found(document_service):
|
|
"""Test reading a document with non-existent ID."""
|
|
with pytest.raises(DocumentNotFoundError):
|
|
await document_service.read_document_by_path_id("99999")
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_read_document_by_id_file_error(document_service, test_doc_path):
|
|
"""Test reading a document where file is missing."""
|
|
|
|
file_path, path_id = test_doc_path
|
|
|
|
# Create test document without actually writing the file
|
|
doc = await document_service.repository.create({"path_id": path_id, "file_path": path_id, "checksum": "abc123"})
|
|
|
|
with pytest.raises(DocumentError):
|
|
await document_service.read_document_by_path_id(path_id)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_update_document_by_id(document_service, test_doc_path):
|
|
"""Test updating a document by ID."""
|
|
|
|
file_path, path_id = test_doc_path
|
|
|
|
# Create initial document
|
|
original_content = "# Original\nOriginal content."
|
|
doc = await document_service.create_document(path_id, original_content, {"type": "test"})
|
|
|
|
# Update it
|
|
new_content = "# Updated\nUpdated content."
|
|
updated_doc = await document_service.update_document_by_path_id(
|
|
path_id, new_content, {"type": "test", "status": "updated"}
|
|
)
|
|
|
|
# Verify DB record
|
|
assert updated_doc.id == doc.id
|
|
assert updated_doc.path_id == path_id
|
|
assert updated_doc.doc_metadata == {"type": "test", "status": "updated"}
|
|
|
|
# Verify file content
|
|
file_content = file_path.read_text()
|
|
assert new_content in file_content
|
|
assert "---" in file_content # Should have frontmatter
|