| """Unit tests for document management tools.""" |
|
|
| import json |
| from unittest.mock import AsyncMock, MagicMock, patch |
|
|
| import pytest |
| from mcp.server.fastmcp import Context |
|
|
| from src.mcp_server.features.documents.document_tools import register_document_tools |
|
|
|
|
| @pytest.fixture |
| def mock_mcp(): |
| """Create a mock MCP server for testing.""" |
| mock = MagicMock() |
| |
| mock._tools = {} |
|
|
| def tool_decorator(): |
| def decorator(func): |
| mock._tools[func.__name__] = func |
| return func |
|
|
| return decorator |
|
|
| mock.tool = tool_decorator |
| return mock |
|
|
|
|
| @pytest.fixture |
| def mock_context(): |
| """Create a mock context for testing.""" |
| return MagicMock(spec=Context) |
|
|
|
|
| @pytest.mark.asyncio |
| async def test_create_document_success(mock_mcp, mock_context): |
| """Test successful document creation.""" |
| |
| register_document_tools(mock_mcp) |
|
|
| |
| manage_document = mock_mcp._tools.get("manage_document") |
| assert manage_document is not None, "manage_document tool not registered" |
|
|
| |
| mock_response = MagicMock() |
| mock_response.status_code = 200 |
| mock_response.json.return_value = { |
| "document": {"id": "doc-123", "title": "Test Doc"}, |
| "message": "Document created successfully", |
| } |
|
|
| with patch("src.mcp_server.features.documents.document_tools.httpx.AsyncClient") as mock_client: |
| mock_async_client = AsyncMock() |
| mock_async_client.post.return_value = mock_response |
| mock_client.return_value.__aenter__.return_value = mock_async_client |
|
|
| |
| result = await manage_document( |
| mock_context, |
| action="create", |
| project_id="project-123", |
| title="Test Document", |
| document_type="spec", |
| content={"test": "content"}, |
| ) |
|
|
| result_data = json.loads(result) |
| assert result_data["success"] is True |
| assert result_data["document_id"] == "doc-123" |
| assert "Document created successfully" in result_data["message"] |
|
|
|
|
| @pytest.mark.asyncio |
| async def test_find_documents_success(mock_mcp, mock_context): |
| """Test successful document listing.""" |
| register_document_tools(mock_mcp) |
|
|
| |
| find_documents = mock_mcp._tools.get("find_documents") |
| assert find_documents is not None, "find_documents tool not registered" |
|
|
| |
| mock_response = MagicMock() |
| mock_response.status_code = 200 |
| mock_response.json.return_value = { |
| "documents": [ |
| {"id": "doc-1", "title": "Doc 1", "document_type": "spec"}, |
| {"id": "doc-2", "title": "Doc 2", "document_type": "design"}, |
| ] |
| } |
|
|
| with patch("src.mcp_server.features.documents.document_tools.httpx.AsyncClient") as mock_client: |
| mock_async_client = AsyncMock() |
| mock_async_client.get.return_value = mock_response |
| mock_client.return_value.__aenter__.return_value = mock_async_client |
|
|
| result = await find_documents(mock_context, project_id="project-123") |
|
|
| result_data = json.loads(result) |
| assert result_data["success"] is True |
| assert len(result_data["documents"]) == 2 |
| assert result_data["count"] == 2 |
|
|
|
|
| @pytest.mark.asyncio |
| async def test_update_document_partial_update(mock_mcp, mock_context): |
| """Test partial document update.""" |
| register_document_tools(mock_mcp) |
|
|
| |
| manage_document = mock_mcp._tools.get("manage_document") |
| assert manage_document is not None, "manage_document tool not registered" |
|
|
| |
| mock_response = MagicMock() |
| mock_response.status_code = 200 |
| mock_response.json.return_value = { |
| "doc": {"id": "doc-123", "title": "Updated Title"}, |
| "message": "Document updated successfully", |
| } |
|
|
| with patch("src.mcp_server.features.documents.document_tools.httpx.AsyncClient") as mock_client: |
| mock_async_client = AsyncMock() |
| mock_async_client.put.return_value = mock_response |
| mock_client.return_value.__aenter__.return_value = mock_async_client |
|
|
| |
| result = await manage_document( |
| mock_context, action="update", project_id="project-123", document_id="doc-123", title="Updated Title" |
| ) |
|
|
| result_data = json.loads(result) |
| assert result_data["success"] is True |
| assert "Document updated successfully" in result_data["message"] |
|
|
| |
| call_args = mock_async_client.put.call_args |
| sent_data = call_args[1]["json"] |
| assert sent_data == {"title": "Updated Title"} |
|
|
|
|
| @pytest.mark.asyncio |
| async def test_delete_document_not_found(mock_mcp, mock_context): |
| """Test deleting a non-existent document.""" |
| register_document_tools(mock_mcp) |
|
|
| |
| manage_document = mock_mcp._tools.get("manage_document") |
| assert manage_document is not None, "manage_document tool not registered" |
|
|
| |
| mock_response = MagicMock() |
| mock_response.status_code = 404 |
| mock_response.text = "Document not found" |
|
|
| with patch("src.mcp_server.features.documents.document_tools.httpx.AsyncClient") as mock_client: |
| mock_async_client = AsyncMock() |
| mock_async_client.delete.return_value = mock_response |
| mock_client.return_value.__aenter__.return_value = mock_async_client |
|
|
| result = await manage_document( |
| mock_context, action="delete", project_id="project-123", document_id="non-existent" |
| ) |
|
|
| result_data = json.loads(result) |
| assert result_data["success"] is False |
| |
| assert "error" in result_data |
| assert isinstance(result_data["error"], dict), "Error should be structured format, not string" |
| assert result_data["error"]["type"] == "http_error" |
| assert "404" in result_data["error"]["message"].lower() |
|
|