add knowledge_sync_service tests

This commit is contained in:
phernandez
2024-12-27 13:19:15 -06:00
parent e45e36bb96
commit 99e7673fc8
3 changed files with 195 additions and 5 deletions
+11 -5
View File
@@ -11,6 +11,7 @@ from basic_memory import db
from basic_memory.config import ProjectConfig
from basic_memory.db import DatabaseType
from basic_memory.markdown.knowledge_writer import KnowledgeWriter
from basic_memory.markdown.knowledge_parser import KnowledgeParser
from basic_memory.models import Base
from basic_memory.models.knowledge import Entity
from basic_memory.repository.document_repository import DocumentRepository
@@ -22,10 +23,10 @@ from basic_memory.services import (
ObservationService,
RelationService,
DocumentService,
KnowledgeService,
FileChangeScanner,
FileService
)
from basic_memory.services.file_service import FileService
from basic_memory.services import KnowledgeService
@pytest_asyncio.fixture
@@ -67,7 +68,6 @@ async def session_maker(engine_factory) -> async_sessionmaker[AsyncSession]:
return session_maker
@pytest_asyncio.fixture(scope="function")
async def document_repository(
session_maker: async_sessionmaker[AsyncSession],
@@ -140,8 +140,14 @@ def knowledge_writer():
return KnowledgeWriter()
@pytest.fixture
def knowledge_parser():
"""Create parser instance."""
return KnowledgeParser()
@pytest_asyncio.fixture
def file_change_scanner(document_repository, entity_repository) -> FileChangeScanner:
def file_sync_service(document_repository, entity_repository) -> FileChangeScanner:
"""Create FileChangeScanner instance."""
return FileChangeScanner(document_repository, entity_repository)
@@ -176,4 +182,4 @@ async def sample_entity(entity_repository: EntityRepository) -> Entity:
"path_id": "test/test_entity",
"file_path": "test/test_entity.md",
}
return await entity_repository.create(entity_data)
return await entity_repository.create(entity_data)
@@ -0,0 +1,184 @@
"""Tests for knowledge sync service."""
import pytest
import pytest_asyncio
from pathlib import Path
from typing import AsyncGenerator
from sqlalchemy.ext.asyncio import AsyncSession
from basic_memory.services.sync.knowledge_sync_service import KnowledgeSyncService
from basic_memory.services import KnowledgeService, FileChangeScanner
from basic_memory.markdown import KnowledgeParser
from basic_memory.utils.file_utils import compute_checksum
@pytest_asyncio.fixture
async def knowledge_sync_service(
file_sync_service: FileChangeScanner, # from conftest
knowledge_service: KnowledgeService, # from conftest
knowledge_parser: KnowledgeParser # need to add to conftest
) -> KnowledgeSyncService:
"""Create knowledge sync service for testing."""
return KnowledgeSyncService(file_sync_service, knowledge_service, knowledge_parser)
async def create_test_entity_file(
path: Path,
entity_type: str = "test",
name: str = "Test Entity",
content: str = "test content"
) -> None:
"""Create a test entity file with frontmatter."""
path.parent.mkdir(parents=True, exist_ok=True)
# Create basic entity markdown
file_content = f"""---
type: {entity_type}
id: {entity_type}/{name.lower().replace(' ', '_')}
created: 2024-12-27T10:00:00Z
modified: 2024-12-27T10:00:00Z
tags: [test]
---
# {name}
{content}
## Observations
- [test] First observation #test
- [test] Second observation #test
## Relations
- relates_to [[Other_Entity]]
"""
path.write_text(file_content)
@pytest.mark.asyncio
async def test_sync_new_entity(
knowledge_sync_service: KnowledgeSyncService,
test_config,
):
"""Test syncing a new entity file."""
knowledge_dir = test_config.knowledge_dir
test_file = knowledge_dir / "test" / "test_entity.md"
# Create test file
await create_test_entity_file(test_file)
# Run sync
changes = await knowledge_sync_service.sync(knowledge_dir)
# Verify changes
assert len(changes.new) == 1
assert "test/test_entity.md" in changes.new
# Verify entity in DB
entity = await knowledge_sync_service.knowledge_service.get_entity_by_path_id("test/test_entity")
assert entity.name == "Test Entity"
assert entity.entity_type == "test"
assert len(entity.observations) == 2
assert len(entity.outbound_relations) == 1
@pytest.mark.asyncio
async def test_sync_modified_entity(
knowledge_sync_service: KnowledgeSyncService,
test_config,
entity_repository,
):
"""Test syncing a modified entity file."""
knowledge_dir = test_config.knowledge_dir
test_file = knowledge_dir / "test" / "test_entity.md"
# Create initial file and sync
await create_test_entity_file(test_file)
await knowledge_sync_service.sync(knowledge_dir)
# Modify file
await create_test_entity_file(
test_file,
content="modified content",
name="Test Entity" # Keep same name/path
)
# Run sync again
changes = await knowledge_sync_service.sync(knowledge_dir)
# Verify changes
assert len(changes.modified) == 1
assert "test/test_entity.md" in changes.modified
# Verify entity updated
entity = await knowledge_sync_service.knowledge_service.get_entity_by_path_id("test/test_entity")
assert "modified content" in entity.description
@pytest.mark.asyncio
async def test_sync_moved_entity(
knowledge_sync_service: KnowledgeSyncService,
test_config,
entity_repository
):
"""Test syncing a moved entity file."""
knowledge_dir = test_config.knowledge_dir
original_file = knowledge_dir / "test" / "original.md"
new_file = knowledge_dir / "test" / "moved.md"
# Create initial file and sync
await create_test_entity_file(original_file, name="Original")
await knowledge_sync_service.sync(knowledge_dir)
# Create new file with same content
new_file.parent.mkdir(parents=True, exist_ok=True)
await create_test_entity_file(new_file, name="Moved")
original_file.unlink()
# Run sync
changes = await knowledge_sync_service.sync(knowledge_dir)
# Verify changes
assert len(changes.moved) == 1
assert "test/moved.md" in changes.moved
assert changes.moved["test/moved.md"].moved_from == "test/original.md"
# Verify entity updated
with pytest.raises(Exception):
# Original should be gone
await knowledge_sync_service.knowledge_service.get_entity_by_path_id("test/original")
# New entity should exist
entity = await knowledge_sync_service.knowledge_service.get_entity_by_path_id("test/moved")
assert entity.name == "Moved"
assert len(entity.observations) == 2
assert len(entity.outbound_relations) == 1
@pytest.mark.asyncio
async def test_sync_deleted_entity(
knowledge_sync_service: KnowledgeSyncService,
test_config,
entity_repository
):
"""Test syncing a deleted entity file."""
knowledge_dir = test_config.knowledge_dir
test_file = knowledge_dir / "test" / "to_delete.md"
# Create initial file and sync
await create_test_entity_file(test_file)
await knowledge_sync_service.sync(knowledge_dir)
# Delete file
test_file.unlink()
# Run sync
changes = await knowledge_sync_service.sync(knowledge_dir)
# Verify changes
assert len(changes.deleted) == 1
assert "test/to_delete.md" in changes.deleted
# Verify entity deleted
with pytest.raises(Exception):
await knowledge_sync_service.knowledge_service.get_entity_by_path_id("test/to_delete")