Skip to main content
Glama
test_events.py15.4 kB
""" Test suite for the events system. This module contains tests for all event providers, the event manager, and MCP integration components. """ import asyncio import pytest import time from unittest.mock import Mock, MagicMock, patch from typing import Dict, Any, List # Import the events system components try: from ..events import ( EventManager, EventRouter, MCPEventIntegration, DocumentEventProvider, CommandExecutionEventProvider, ErrorEventProvider, create_event_system, initialize_event_system ) except ImportError: import sys import os # Add the parent directory to the path parent_dir = os.path.dirname(os.path.dirname(__file__)) sys.path.insert(0, parent_dir) from events import ( EventManager, EventRouter, MCPEventIntegration, DocumentEventProvider, CommandExecutionEventProvider, ErrorEventProvider, create_event_system, initialize_event_system ) class TestEventRouter: """Test cases for the EventRouter class.""" @pytest.fixture def event_router(self): """Create an EventRouter instance for testing.""" return EventRouter() @pytest.mark.asyncio async def test_add_remove_listener(self, event_router): """Test adding and removing event listeners.""" client_id = "test_client_1" event_types = ["document_changed", "command_executed"] # Add listener await event_router.add_listener(client_id, event_types) # Check that listener was added listeners = await event_router.get_active_listeners() assert client_id in listeners["clients"] assert set(listeners["clients"][client_id]) == set(event_types) # Remove listener await event_router.remove_listener(client_id, event_types) # Check that listener was removed listeners = await event_router.get_active_listeners() assert client_id not in listeners["clients"] @pytest.mark.asyncio async def test_broadcast_event(self, event_router): """Test broadcasting events to listeners.""" client_id = "test_client_1" event_type = "test_event" event_data = {"test": "data", "value": 42} # Add listener await event_router.add_listener(client_id, [event_type]) # Broadcast event await event_router.broadcast_event(event_type, event_data) # Check event history history = await event_router.get_event_history(limit=1) assert len(history) == 1 assert history[0]["type"] == event_type assert history[0]["data"]["test"] == "data" assert history[0]["listeners_notified"] == 1 @pytest.mark.asyncio async def test_event_history(self, event_router): """Test event history functionality.""" client_id = "test_client_1" # Add listener for all events await event_router.add_listener(client_id, ["*"]) # Broadcast multiple events for i in range(5): await event_router.broadcast_event(f"event_{i}", {"index": i}) # Get all history history = await event_router.get_event_history() assert len(history) == 5 # Get limited history limited_history = await event_router.get_event_history(limit=3) assert len(limited_history) == 3 # Get filtered history filtered_history = await event_router.get_event_history( event_types=["event_1", "event_3"] ) assert len(filtered_history) == 2 class TestEventManager: """Test cases for the EventManager class.""" @pytest.fixture def mock_freecad(self): """Create a mock FreeCAD application.""" mock_app = Mock() mock_app.signalDocumentChanged = Mock() mock_app.signalNewDocument = Mock() mock_app.signalDeleteDocument = Mock() mock_app.signalActiveDocument = Mock() # Mock GUI mock_gui = Mock() mock_selection = Mock() mock_selection.signalSelectionChanged = Mock() mock_gui.Selection = mock_selection mock_gui.Command = Mock() mock_gui.Command.CommandExecuted = Mock() mock_app.Gui = mock_gui return mock_app @pytest.fixture def event_manager(self, mock_freecad): """Create an EventManager instance for testing.""" return EventManager(mock_freecad) @pytest.mark.asyncio async def test_initialization(self, event_manager): """Test event manager initialization.""" # Should not be initialized initially assert not event_manager.is_initialized # Initialize success = await event_manager.initialize() assert success assert event_manager.is_initialized # Check that providers were created assert "document" in event_manager.providers assert "command" in event_manager.providers assert "error" in event_manager.providers @pytest.mark.asyncio async def test_add_remove_listeners(self, event_manager): """Test adding and removing event listeners.""" await event_manager.initialize() client_id = "test_client_1" event_types = ["document_changed"] # Add listener success = await event_manager.add_event_listener(client_id, event_types) assert success # Remove listener success = await event_manager.remove_event_listener(client_id, event_types) assert success @pytest.mark.asyncio async def test_get_system_status(self, event_manager): """Test getting system status.""" await event_manager.initialize() status = await event_manager.get_system_status() assert status["initialized"] is True assert status["freecad_available"] is True assert "providers" in status assert "router_stats" in status assert "active_listeners" in status @pytest.mark.asyncio async def test_custom_event_emission(self, event_manager): """Test emitting custom events.""" await event_manager.initialize() event_type = "custom_test_event" event_data = {"custom": "data"} success = await event_manager.emit_custom_event(event_type, event_data) assert success @pytest.mark.asyncio async def test_shutdown(self, event_manager): """Test event manager shutdown.""" await event_manager.initialize() assert event_manager.is_initialized await event_manager.shutdown() assert not event_manager.is_initialized class TestMCPEventIntegration: """Test cases for the MCPEventIntegration class.""" @pytest.fixture def mock_event_manager(self): """Create a mock EventManager.""" manager = Mock() manager.add_event_listener = Mock(return_value=True) manager.remove_event_listener = Mock(return_value=True) manager.get_system_status = Mock(return_value={ "initialized": True, "providers": {}, "router_stats": {}, "active_listeners": {} }) return manager @pytest.fixture def mcp_integration(self, mock_event_manager): """Create an MCPEventIntegration instance for testing.""" return MCPEventIntegration(mock_event_manager) @pytest.mark.asyncio async def test_client_registration(self, mcp_integration): """Test MCP client registration and unregistration.""" client_id = "mcp_test_client" client_info = {"version": "1.0", "name": "Test Client"} # Register client success = await mcp_integration.register_mcp_client(client_id, client_info) assert success # Check client info info = await mcp_integration.get_client_info(client_id) assert info["info"] == client_info # Unregister client success = await mcp_integration.unregister_mcp_client(client_id) assert success # Check client is gone info = await mcp_integration.get_client_info(client_id) assert info == {} @pytest.mark.asyncio async def test_event_subscriptions(self, mcp_integration): """Test event subscription management.""" client_id = "mcp_test_client" # Register client first await mcp_integration.register_mcp_client(client_id) # Subscribe to events event_types = ["document_changed", "error"] success = await mcp_integration.subscribe_to_events(client_id, event_types) assert success # Check subscription info = await mcp_integration.get_client_info(client_id) assert set(info["subscriptions"]) == set(event_types) # Unsubscribe success = await mcp_integration.unsubscribe_from_events(client_id, ["error"]) assert success # Check subscription updated info = await mcp_integration.get_client_info(client_id) assert "document_changed" in info["subscriptions"] assert "error" not in info["subscriptions"] @pytest.mark.asyncio async def test_notification_handling(self, mcp_integration): """Test event notification handling.""" client_id = "mcp_test_client" # Register client await mcp_integration.register_mcp_client(client_id) # Set up custom handler handled_events = [] def custom_handler(client_id, event_type, event_data): handled_events.append((client_id, event_type, event_data)) mcp_integration.set_notification_handler("test_event", custom_handler) # Handle notification event_data = {"test": "notification"} success = await mcp_integration.handle_event_notification( client_id, "test_event", event_data ) assert success # Check handler was called assert len(handled_events) == 1 assert handled_events[0] == (client_id, "test_event", event_data) @pytest.mark.asyncio async def test_cleanup_inactive_clients(self, mcp_integration): """Test cleanup of inactive clients.""" client_id = "inactive_client" # Register client await mcp_integration.register_mcp_client(client_id) # Simulate passage of time by modifying last_activity async with mcp_integration._lock: mcp_integration.mcp_clients[client_id]["last_activity"] = time.time() - 7200 # 2 hours ago # Cleanup with 1 hour timeout cleaned_up = await mcp_integration.cleanup_inactive_clients(timeout=3600) assert cleaned_up == 1 # Check client was removed info = await mcp_integration.get_client_info(client_id) assert info == {} class TestEventProviders: """Test cases for individual event providers.""" @pytest.fixture def mock_freecad(self): """Create a mock FreeCAD application.""" mock_app = Mock() mock_app.signalDocumentChanged = Mock() mock_app.signalNewDocument = Mock() mock_app.signalDeleteDocument = Mock() mock_app.signalActiveDocument = Mock() # Mock GUI mock_gui = Mock() mock_selection = Mock() mock_selection.signalSelectionChanged = Mock() mock_selection.getSelection = Mock(return_value=[]) mock_gui.Selection = mock_selection mock_gui.Command = Mock() mock_gui.Command.CommandExecuted = Mock() mock_app.Gui = mock_gui return mock_app @pytest.fixture def mock_event_router(self): """Create a mock event router.""" router = Mock() router.broadcast_event = Mock() return router def test_document_event_provider_creation(self, mock_freecad, mock_event_router): """Test creating a DocumentEventProvider.""" provider = DocumentEventProvider(mock_freecad, mock_event_router) assert provider.app == mock_freecad assert provider.event_router == mock_event_router def test_command_event_provider_creation(self, mock_freecad, mock_event_router): """Test creating a CommandExecutionEventProvider.""" provider = CommandExecutionEventProvider(mock_freecad, mock_event_router) assert provider.app == mock_freecad assert provider.event_router == mock_event_router assert provider.command_history == [] def test_error_event_provider_creation(self, mock_freecad, mock_event_router): """Test creating an ErrorEventProvider.""" provider = ErrorEventProvider(mock_freecad, mock_event_router) assert provider.app == mock_freecad assert provider.event_router == mock_event_router assert provider.error_history == [] def test_command_history(self, mock_freecad, mock_event_router): """Test command history functionality.""" provider = CommandExecutionEventProvider(mock_freecad, mock_event_router) # Simulate command execution provider._on_command_executed("TestCommand") # Check history history = provider.get_command_history() assert len(history) == 1 assert history[0]["command"] == "TestCommand" assert history[0]["type"] == "command_executed" def test_error_reporting(self, mock_freecad, mock_event_router): """Test manual error reporting.""" provider = ErrorEventProvider(mock_freecad, mock_event_router) # Report an error provider.report_error("Test error", "manual", {"detail": "test"}) # Check error history history = provider.get_error_history() assert len(history) == 1 assert history[0]["message"] == "Test error" assert history[0]["error_type"] == "manual" assert history[0]["detail"] == "test" class TestConvenienceFunctions: """Test cases for convenience functions.""" @patch('events.EventManager') @patch('events.MCPEventIntegration') def test_create_event_system(self, mock_mcp_class, mock_manager_class): """Test create_event_system function.""" mock_manager = Mock() mock_mcp = Mock() mock_manager_class.return_value = mock_manager mock_mcp_class.return_value = mock_mcp manager, mcp = create_event_system() assert manager == mock_manager assert mcp == mock_mcp @pytest.mark.asyncio @patch('events.EventManager') @patch('events.MCPEventIntegration') async def test_initialize_event_system(self, mock_mcp_class, mock_manager_class): """Test initialize_event_system function.""" mock_manager = Mock() mock_manager.initialize = Mock(return_value=True) mock_mcp = Mock() mock_manager_class.return_value = mock_manager mock_mcp_class.return_value = mock_mcp manager, mcp = await initialize_event_system() assert manager == mock_manager assert mcp == mock_mcp mock_manager.initialize.assert_called_once() if __name__ == "__main__": # Run tests if this file is executed directly pytest.main([__file__, "-v"])

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/jango-blockchained/mcp-freecad'

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