Skip to main content
Glama
test_classic_handler.py10.8 kB
from datetime import datetime, timezone from unittest.mock import AsyncMock, patch import pytest from mcp_email_server.config import EmailServer, EmailSettings from mcp_email_server.emails.classic import ClassicEmailHandler, EmailClient from mcp_email_server.emails.models import AttachmentDownloadResponse, EmailMetadata, EmailMetadataPageResponse @pytest.fixture def email_settings(): return EmailSettings( account_name="test_account", full_name="Test User", email_address="test@example.com", incoming=EmailServer( user_name="test_user", password="test_password", host="imap.example.com", port=993, use_ssl=True, ), outgoing=EmailServer( user_name="test_user", password="test_password", host="smtp.example.com", port=465, use_ssl=True, ), ) @pytest.fixture def classic_handler(email_settings): return ClassicEmailHandler(email_settings) class TestClassicEmailHandler: def test_init(self, email_settings): """Test initialization of ClassicEmailHandler.""" handler = ClassicEmailHandler(email_settings) assert handler.email_settings == email_settings assert isinstance(handler.incoming_client, EmailClient) assert isinstance(handler.outgoing_client, EmailClient) # Check that clients are initialized correctly assert handler.incoming_client.email_server == email_settings.incoming assert handler.outgoing_client.email_server == email_settings.outgoing assert handler.outgoing_client.sender == f"{email_settings.full_name} <{email_settings.email_address}>" @pytest.mark.asyncio async def test_get_emails(self, classic_handler): """Test get_emails method.""" # Create test data now = datetime.now(timezone.utc) email_data = { "email_id": "123", "subject": "Test Subject", "from": "sender@example.com", "to": ["recipient@example.com"], "date": now, "attachments": [], } # Mock the get_emails_stream method to yield our test data mock_stream = AsyncMock() mock_stream.__aiter__.return_value = [email_data] # Mock the get_email_count method mock_count = AsyncMock(return_value=1) # Apply the mocks with patch.object(classic_handler.incoming_client, "get_emails_metadata_stream", return_value=mock_stream): with patch.object(classic_handler.incoming_client, "get_email_count", mock_count): # Call the method result = await classic_handler.get_emails_metadata( page=1, page_size=10, before=now, since=None, subject="Test", from_address="sender@example.com", to_address=None, ) # Verify the result assert isinstance(result, EmailMetadataPageResponse) assert result.page == 1 assert result.page_size == 10 assert result.before == now assert result.since is None assert result.subject == "Test" assert len(result.emails) == 1 assert isinstance(result.emails[0], EmailMetadata) assert result.emails[0].subject == "Test Subject" assert result.emails[0].sender == "sender@example.com" assert result.emails[0].date == now assert result.emails[0].attachments == [] assert result.total == 1 # Verify the client methods were called correctly classic_handler.incoming_client.get_emails_metadata_stream.assert_called_once_with( 1, 10, now, None, "Test", "sender@example.com", None, "desc", "INBOX" ) mock_count.assert_called_once_with( now, None, "Test", from_address="sender@example.com", to_address=None, mailbox="INBOX" ) @pytest.mark.asyncio async def test_get_emails_with_mailbox(self, classic_handler): """Test get_emails method with custom mailbox.""" now = datetime.now(timezone.utc) email_data = { "email_id": "456", "subject": "Sent Mail Subject", "from": "me@example.com", "to": ["recipient@example.com"], "date": now, "attachments": [], } mock_stream = AsyncMock() mock_stream.__aiter__.return_value = [email_data] mock_count = AsyncMock(return_value=1) with patch.object(classic_handler.incoming_client, "get_emails_metadata_stream", return_value=mock_stream): with patch.object(classic_handler.incoming_client, "get_email_count", mock_count): result = await classic_handler.get_emails_metadata( page=1, page_size=10, mailbox="Sent", ) assert isinstance(result, EmailMetadataPageResponse) assert len(result.emails) == 1 # Verify mailbox parameter was passed correctly classic_handler.incoming_client.get_emails_metadata_stream.assert_called_once_with( 1, 10, None, None, None, None, None, "desc", "Sent" ) mock_count.assert_called_once_with(None, None, None, from_address=None, to_address=None, mailbox="Sent") @pytest.mark.asyncio async def test_send_email(self, classic_handler): """Test send_email method.""" # Mock the outgoing_client.send_email method mock_send = AsyncMock() # Apply the mock with patch.object(classic_handler.outgoing_client, "send_email", mock_send): # Call the method await classic_handler.send_email( recipients=["recipient@example.com"], subject="Test Subject", body="Test Body", cc=["cc@example.com"], bcc=["bcc@example.com"], ) # Verify the client method was called correctly mock_send.assert_called_once_with( ["recipient@example.com"], "Test Subject", "Test Body", ["cc@example.com"], ["bcc@example.com"], False, None, ) @pytest.mark.asyncio async def test_send_email_with_attachments(self, classic_handler, tmp_path): """Test send_email method with attachments.""" # Create a temporary test file test_file = tmp_path / "test_attachment.txt" test_file.write_text("This is a test attachment") # Mock the outgoing_client.send_email method mock_send = AsyncMock() # Apply the mock with patch.object(classic_handler.outgoing_client, "send_email", mock_send): # Call the method with attachments await classic_handler.send_email( recipients=["recipient@example.com"], subject="Test Subject", body="Test Body with attachment", attachments=[str(test_file)], ) # Verify the client method was called correctly with attachments mock_send.assert_called_once_with( ["recipient@example.com"], "Test Subject", "Test Body with attachment", None, None, False, [str(test_file)], ) @pytest.mark.asyncio async def test_delete_emails(self, classic_handler): """Test delete_emails method.""" mock_delete = AsyncMock(return_value=(["123", "456"], [])) with patch.object(classic_handler.incoming_client, "delete_emails", mock_delete): deleted_ids, failed_ids = await classic_handler.delete_emails( email_ids=["123", "456"], mailbox="INBOX", ) assert deleted_ids == ["123", "456"] assert failed_ids == [] mock_delete.assert_called_once_with(["123", "456"], "INBOX") @pytest.mark.asyncio async def test_delete_emails_with_failures(self, classic_handler): """Test delete_emails method with some failures.""" mock_delete = AsyncMock(return_value=(["123"], ["456"])) with patch.object(classic_handler.incoming_client, "delete_emails", mock_delete): deleted_ids, failed_ids = await classic_handler.delete_emails( email_ids=["123", "456"], mailbox="Trash", ) assert deleted_ids == ["123"] assert failed_ids == ["456"] mock_delete.assert_called_once_with(["123", "456"], "Trash") @pytest.mark.asyncio async def test_delete_emails_custom_mailbox(self, classic_handler): """Test delete_emails method with custom mailbox.""" mock_delete = AsyncMock(return_value=(["789"], [])) with patch.object(classic_handler.incoming_client, "delete_emails", mock_delete): deleted_ids, failed_ids = await classic_handler.delete_emails( email_ids=["789"], mailbox="Archive", ) assert deleted_ids == ["789"] assert failed_ids == [] mock_delete.assert_called_once_with(["789"], "Archive") @pytest.mark.asyncio async def test_download_attachment(self, classic_handler, tmp_path): """Test download_attachment method.""" save_path = str(tmp_path / "downloaded_attachment.pdf") mock_result = { "email_id": "123", "attachment_name": "document.pdf", "mime_type": "application/pdf", "size": 1024, "saved_path": save_path, } mock_download = AsyncMock(return_value=mock_result) with patch.object(classic_handler.incoming_client, "download_attachment", mock_download): result = await classic_handler.download_attachment( email_id="123", attachment_name="document.pdf", save_path=save_path, ) assert isinstance(result, AttachmentDownloadResponse) assert result.email_id == "123" assert result.attachment_name == "document.pdf" assert result.mime_type == "application/pdf" assert result.size == 1024 assert result.saved_path == save_path mock_download.assert_called_once_with("123", "document.pdf", save_path)

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/ai-zerolab/mcp-email-server'

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