mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
c44291830c
Signed-off-by: phernandez <paul@basicmachines.co> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
312 lines
10 KiB
Python
312 lines
10 KiB
Python
"""Tests for typed API clients."""
|
|
|
|
import pytest
|
|
from unittest.mock import MagicMock
|
|
|
|
from basic_memory.mcp.clients import (
|
|
KnowledgeClient,
|
|
SearchClient,
|
|
MemoryClient,
|
|
DirectoryClient,
|
|
ResourceClient,
|
|
ProjectClient,
|
|
)
|
|
|
|
|
|
class TestKnowledgeClient:
|
|
"""Tests for KnowledgeClient."""
|
|
|
|
def test_init(self):
|
|
"""Test client initialization."""
|
|
mock_http = MagicMock()
|
|
client = KnowledgeClient(mock_http, "project-123")
|
|
assert client.http_client is mock_http
|
|
assert client.project_id == "project-123"
|
|
assert client._base_path == "/v2/projects/project-123/knowledge"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_create_entity(self, monkeypatch):
|
|
"""Test create_entity calls correct endpoint."""
|
|
from basic_memory.mcp.clients import knowledge as knowledge_mod
|
|
|
|
mock_response = MagicMock()
|
|
mock_response.json.return_value = {
|
|
"permalink": "test",
|
|
"title": "Test",
|
|
"file_path": "test.md",
|
|
"note_type": "note",
|
|
"content_type": "text/markdown",
|
|
"observations": [],
|
|
"relations": [],
|
|
"created_at": "2024-01-01T00:00:00",
|
|
"updated_at": "2024-01-01T00:00:00",
|
|
}
|
|
|
|
async def mock_call_post(client, url, **kwargs):
|
|
assert "/v2/projects/proj-123/knowledge/entities" in url
|
|
return mock_response
|
|
|
|
monkeypatch.setattr(knowledge_mod, "call_post", mock_call_post)
|
|
|
|
mock_http = MagicMock()
|
|
client = KnowledgeClient(mock_http, "proj-123")
|
|
result = await client.create_entity({"title": "Test"})
|
|
assert result.title == "Test"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_resolve_entity(self, monkeypatch):
|
|
"""Test resolve_entity returns external_id."""
|
|
from basic_memory.mcp.clients import knowledge as knowledge_mod
|
|
|
|
mock_response = MagicMock()
|
|
mock_response.json.return_value = {"external_id": "entity-uuid-123"}
|
|
|
|
async def mock_call_post(client, url, **kwargs):
|
|
assert "/v2/projects/proj-123/knowledge/resolve" in url
|
|
return mock_response
|
|
|
|
monkeypatch.setattr(knowledge_mod, "call_post", mock_call_post)
|
|
|
|
mock_http = MagicMock()
|
|
client = KnowledgeClient(mock_http, "proj-123")
|
|
result = await client.resolve_entity("my-note")
|
|
assert result == "entity-uuid-123"
|
|
|
|
|
|
class TestSearchClient:
|
|
"""Tests for SearchClient."""
|
|
|
|
def test_init(self):
|
|
"""Test client initialization."""
|
|
mock_http = MagicMock()
|
|
client = SearchClient(mock_http, "project-123")
|
|
assert client.http_client is mock_http
|
|
assert client.project_id == "project-123"
|
|
assert client._base_path == "/v2/projects/project-123/search"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_search(self, monkeypatch):
|
|
"""Test search calls correct endpoint."""
|
|
from basic_memory.mcp.clients import search as search_mod
|
|
|
|
mock_response = MagicMock()
|
|
mock_response.json.return_value = {
|
|
"results": [],
|
|
"current_page": 1,
|
|
"page_size": 10,
|
|
}
|
|
|
|
async def mock_call_post(client, url, **kwargs):
|
|
assert "/v2/projects/proj-123/search/" in url
|
|
assert kwargs.get("params") == {"page": 1, "page_size": 10}
|
|
return mock_response
|
|
|
|
monkeypatch.setattr(search_mod, "call_post", mock_call_post)
|
|
|
|
mock_http = MagicMock()
|
|
client = SearchClient(mock_http, "proj-123")
|
|
result = await client.search({"text": "query"}, page=1, page_size=10)
|
|
assert result.results == []
|
|
assert result.current_page == 1
|
|
|
|
|
|
class TestMemoryClient:
|
|
"""Tests for MemoryClient."""
|
|
|
|
def test_init(self):
|
|
"""Test client initialization."""
|
|
mock_http = MagicMock()
|
|
client = MemoryClient(mock_http, "project-123")
|
|
assert client.http_client is mock_http
|
|
assert client.project_id == "project-123"
|
|
assert client._base_path == "/v2/projects/project-123/memory"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_build_context(self, monkeypatch):
|
|
"""Test build_context calls correct endpoint."""
|
|
from basic_memory.mcp.clients import memory as memory_mod
|
|
from datetime import datetime
|
|
|
|
mock_response = MagicMock()
|
|
mock_response.json.return_value = {
|
|
"results": [],
|
|
"metadata": {
|
|
"depth": 1,
|
|
"generated_at": datetime.now().isoformat(),
|
|
},
|
|
}
|
|
|
|
async def mock_call_get(client, url, **kwargs):
|
|
assert "/v2/projects/proj-123/memory/specs/search" in url
|
|
return mock_response
|
|
|
|
monkeypatch.setattr(memory_mod, "call_get", mock_call_get)
|
|
|
|
mock_http = MagicMock()
|
|
client = MemoryClient(mock_http, "proj-123")
|
|
result = await client.build_context("specs/search")
|
|
assert result.results == []
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_recent(self, monkeypatch):
|
|
"""Test recent calls correct endpoint."""
|
|
from basic_memory.mcp.clients import memory as memory_mod
|
|
from datetime import datetime
|
|
|
|
mock_response = MagicMock()
|
|
mock_response.json.return_value = {
|
|
"results": [],
|
|
"metadata": {
|
|
"depth": 2,
|
|
"generated_at": datetime.now().isoformat(),
|
|
},
|
|
}
|
|
|
|
async def mock_call_get(client, url, **kwargs):
|
|
assert "/v2/projects/proj-123/memory/recent" in url
|
|
params = kwargs.get("params", {})
|
|
assert params.get("timeframe") == "7d"
|
|
assert params.get("depth") == 2
|
|
return mock_response
|
|
|
|
monkeypatch.setattr(memory_mod, "call_get", mock_call_get)
|
|
|
|
mock_http = MagicMock()
|
|
client = MemoryClient(mock_http, "proj-123")
|
|
result = await client.recent(timeframe="7d", depth=2)
|
|
assert result.results == []
|
|
assert result.metadata.depth == 2
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_recent_with_types(self, monkeypatch):
|
|
"""Test recent with types filter."""
|
|
from basic_memory.mcp.clients import memory as memory_mod
|
|
from datetime import datetime
|
|
|
|
mock_response = MagicMock()
|
|
mock_response.json.return_value = {
|
|
"results": [],
|
|
"metadata": {
|
|
"depth": 1,
|
|
"generated_at": datetime.now().isoformat(),
|
|
},
|
|
}
|
|
|
|
async def mock_call_get(client, url, **kwargs):
|
|
assert "/v2/projects/proj-123/memory/recent" in url
|
|
params = kwargs.get("params", {})
|
|
assert params.get("type") == "note,spec"
|
|
return mock_response
|
|
|
|
monkeypatch.setattr(memory_mod, "call_get", mock_call_get)
|
|
|
|
mock_http = MagicMock()
|
|
client = MemoryClient(mock_http, "proj-123")
|
|
result = await client.recent(types=["note", "spec"])
|
|
assert result.results == []
|
|
|
|
|
|
class TestDirectoryClient:
|
|
"""Tests for DirectoryClient."""
|
|
|
|
def test_init(self):
|
|
"""Test client initialization."""
|
|
mock_http = MagicMock()
|
|
client = DirectoryClient(mock_http, "project-123")
|
|
assert client.http_client is mock_http
|
|
assert client.project_id == "project-123"
|
|
assert client._base_path == "/v2/projects/project-123/directory"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_list(self, monkeypatch):
|
|
"""Test list calls correct endpoint."""
|
|
from basic_memory.mcp.clients import directory as directory_mod
|
|
|
|
mock_response = MagicMock()
|
|
mock_response.json.return_value = [{"name": "folder", "type": "directory"}]
|
|
|
|
async def mock_call_get(client, url, **kwargs):
|
|
assert "/v2/projects/proj-123/directory/list" in url
|
|
return mock_response
|
|
|
|
monkeypatch.setattr(directory_mod, "call_get", mock_call_get)
|
|
|
|
mock_http = MagicMock()
|
|
client = DirectoryClient(mock_http, "proj-123")
|
|
result = await client.list("/")
|
|
assert len(result) == 1
|
|
assert result[0]["name"] == "folder"
|
|
|
|
|
|
class TestResourceClient:
|
|
"""Tests for ResourceClient."""
|
|
|
|
def test_init(self):
|
|
"""Test client initialization."""
|
|
mock_http = MagicMock()
|
|
client = ResourceClient(mock_http, "project-123")
|
|
assert client.http_client is mock_http
|
|
assert client.project_id == "project-123"
|
|
assert client._base_path == "/v2/projects/project-123/resource"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_read(self, monkeypatch):
|
|
"""Test read calls correct endpoint."""
|
|
from basic_memory.mcp.clients import resource as resource_mod
|
|
|
|
mock_response = MagicMock()
|
|
mock_response.text = "# Note content"
|
|
|
|
async def mock_call_get(client, url, **kwargs):
|
|
assert "/v2/projects/proj-123/resource/entity-123" in url
|
|
return mock_response
|
|
|
|
monkeypatch.setattr(resource_mod, "call_get", mock_call_get)
|
|
|
|
mock_http = MagicMock()
|
|
client = ResourceClient(mock_http, "proj-123")
|
|
result = await client.read("entity-123")
|
|
assert result.text == "# Note content"
|
|
|
|
|
|
class TestProjectClient:
|
|
"""Tests for ProjectClient."""
|
|
|
|
def test_init(self):
|
|
"""Test client initialization."""
|
|
mock_http = MagicMock()
|
|
client = ProjectClient(mock_http)
|
|
assert client.http_client is mock_http
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_list_projects(self, monkeypatch):
|
|
"""Test list_projects calls correct endpoint."""
|
|
from basic_memory.mcp.clients import project as project_mod
|
|
|
|
mock_response = MagicMock()
|
|
mock_response.json.return_value = {
|
|
"projects": [
|
|
{
|
|
"id": 1,
|
|
"external_id": "uuid-123",
|
|
"name": "test-project",
|
|
"path": "/path/to/project",
|
|
"is_default": True,
|
|
}
|
|
],
|
|
"default_project": "test-project",
|
|
}
|
|
|
|
async def mock_call_get(client, url, **kwargs):
|
|
assert "/v2/projects" in url
|
|
return mock_response
|
|
|
|
monkeypatch.setattr(project_mod, "call_get", mock_call_get)
|
|
|
|
mock_http = MagicMock()
|
|
client = ProjectClient(mock_http)
|
|
result = await client.list_projects()
|
|
assert len(result.projects) == 1
|
|
assert result.projects[0].name == "test-project"
|
|
assert result.default_project == "test-project"
|