Skip to main content
Glama
test_native_markdown.py8.74 kB
""" Tests for native markdown import/export functionality. Tests the Google Drive API native markdown support for both importing markdown to Google Docs and exporting Google Docs to markdown. """ import pytest from unittest.mock import Mock, MagicMock, patch from googleapiclient.http import MediaInMemoryUpload from google_docs_mcp.api.drive import create_google_doc_from_markdown from google_docs_mcp.api.documents import _export_document_as_markdown from fastmcp.exceptions import ToolError class TestMarkdownImport: """Tests for native markdown import via Drive API.""" @patch('google_docs_mcp.api.drive.get_drive_client') def test_create_doc_from_markdown_basic(self, mock_get_drive): """Test basic markdown import creates document correctly.""" # Setup mock mock_drive = MagicMock() mock_get_drive.return_value = mock_drive mock_response = { 'id': 'test-doc-id-123', 'name': 'Test Document', 'webViewLink': 'https://docs.google.com/document/d/test-doc-id-123/edit' } mock_drive.files().create().execute.return_value = mock_response # Execute markdown_content = "# Test Heading\n\nThis is **bold** text." result = create_google_doc_from_markdown( title="Test Document", markdown_content=markdown_content ) # Verify assert 'test-doc-id-123' in result assert 'Test Document' in result assert 'Successfully created' in result # Verify API call - get the actual call arguments # The call chain is files().create(...), so we look at the create call call_args_list = mock_drive.files().create.call_args_list # Find the call with arguments (not the intermediate () call) actual_call = [call for call in call_args_list if call[1]][0] call_kwargs = actual_call[1] # Check metadata assert call_kwargs['body']['name'] == 'Test Document' assert call_kwargs['body']['mimeType'] == 'application/vnd.google-apps.document' assert call_kwargs['supportsAllDrives'] is True assert call_kwargs['fields'] == 'id,name,webViewLink' # Check media upload media = call_kwargs['media_body'] assert isinstance(media, MediaInMemoryUpload) @patch('google_docs_mcp.api.drive.get_drive_client') def test_create_doc_with_parent_folder(self, mock_get_drive): """Test markdown import with parent folder ID.""" # Setup mock mock_drive = MagicMock() mock_get_drive.return_value = mock_drive mock_response = { 'id': 'test-doc-id-456', 'name': 'Doc in Folder', 'webViewLink': 'https://docs.google.com/document/d/test-doc-id-456/edit' } mock_drive.files().create().execute.return_value = mock_response # Execute result = create_google_doc_from_markdown( title="Doc in Folder", markdown_content="Test content", parent_folder_id="folder-123" ) # Verify assert 'test-doc-id-456' in result # Verify parent folder was set create_call = mock_drive.files().create call_kwargs = create_call.call_args[1] assert call_kwargs['body']['parents'] == ['folder-123'] @patch('google_docs_mcp.api.drive.get_drive_client') def test_create_doc_permission_error(self, mock_get_drive): """Test handling of permission errors during import.""" # Setup mock to raise permission error mock_drive = MagicMock() mock_get_drive.return_value = mock_drive mock_drive.files().create().execute.side_effect = Exception("403 Permission denied") # Execute and verify error with pytest.raises(ToolError) as exc_info: create_google_doc_from_markdown( title="Test", markdown_content="Test" ) assert "Permission denied" in str(exc_info.value) @patch('google_docs_mcp.api.drive.get_drive_client') def test_create_doc_folder_not_found(self, mock_get_drive): """Test handling of folder not found errors.""" # Setup mock to raise 404 error mock_drive = MagicMock() mock_get_drive.return_value = mock_drive mock_drive.files().create().execute.side_effect = Exception("404 Not found") # Execute and verify error with pytest.raises(ToolError) as exc_info: create_google_doc_from_markdown( title="Test", markdown_content="Test", parent_folder_id="nonexistent-folder" ) assert "Parent folder not found" in str(exc_info.value) class TestMarkdownExport: """Tests for native markdown export via Drive API.""" @patch('google_docs_mcp.api.documents.get_drive_client') def test_export_document_as_markdown_basic(self, mock_get_drive): """Test basic markdown export from document.""" # Setup mock mock_drive = MagicMock() mock_get_drive.return_value = mock_drive markdown_bytes = b"# Test Heading\n\nThis is **bold** text." mock_drive.files().export().execute.return_value = markdown_bytes # Execute result = _export_document_as_markdown(document_id="doc-123") # Verify assert result == "# Test Heading\n\nThis is **bold** text." # Verify API call - get the actual call arguments call_args_list = mock_drive.files().export.call_args_list # Find the call with arguments (not the intermediate () call) actual_call = [call for call in call_args_list if call[1]][0] call_kwargs = actual_call[1] assert call_kwargs['fileId'] == 'doc-123' assert call_kwargs['mimeType'] == 'text/markdown' @patch('google_docs_mcp.api.documents.get_drive_client') def test_export_with_max_length(self, mock_get_drive): """Test markdown export with max_length truncation.""" # Setup mock mock_drive = MagicMock() mock_get_drive.return_value = mock_drive long_markdown = "A" * 1000 mock_drive.files().export().execute.return_value = long_markdown.encode('utf-8') # Execute with max_length result = _export_document_as_markdown( document_id="doc-123", max_length=100 ) # Verify truncation assert len(result) > 100 # Includes truncation message assert "Markdown truncated to 100 chars" in result assert "1000 total" in result @patch('google_docs_mcp.api.documents.get_drive_client') def test_export_permission_error(self, mock_get_drive): """Test handling of permission errors during export.""" # Setup mock to raise permission error mock_drive = MagicMock() mock_get_drive.return_value = mock_drive mock_drive.files().export().execute.side_effect = Exception("403 Permission denied") # Execute and verify error with pytest.raises(ToolError) as exc_info: _export_document_as_markdown(document_id="doc-123") assert "Permission denied" in str(exc_info.value) @patch('google_docs_mcp.api.documents.get_drive_client') def test_export_document_not_found(self, mock_get_drive): """Test handling of document not found errors.""" # Setup mock to raise 404 error mock_drive = MagicMock() mock_get_drive.return_value = mock_drive mock_drive.files().export().execute.side_effect = Exception("404 Not found") # Execute and verify error with pytest.raises(ToolError) as exc_info: _export_document_as_markdown(document_id="nonexistent-doc") assert "Document not found" in str(exc_info.value) @patch('google_docs_mcp.api.documents.get_drive_client') @patch('google_docs_mcp.api.documents.log') def test_export_with_tab_id_warning(self, mock_log, mock_get_drive): """Test that warning is logged when tab_id is specified.""" # Setup mock mock_drive = MagicMock() mock_get_drive.return_value = mock_drive markdown_bytes = b"# Test" mock_drive.files().export().execute.return_value = markdown_bytes # Execute with tab_id result = _export_document_as_markdown( document_id="doc-123", tab_id="tab-456" ) # Verify warning was logged warning_logged = any( 'tab_id' in str(call) and 'entire document' in str(call) for call in mock_log.call_args_list ) assert warning_logged, "Expected warning about tab_id exporting entire document"

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/nickweedon/google-docs-mcp-docker'

If you have feedback or need assistance with the MCP directory API, please join our Discord server