Skip to main content
Glama
test_basic_functionality.py10.5 kB
""" Basic tests for the Ceph MCP Server functionality. These tests help ensure your server is configured correctly and can communicate with your Ceph cluster. They're designed to be run against a real Ceph cluster in your development environment. """ import asyncio from unittest.mock import AsyncMock, patch import pytest from ceph_mcp.api.ceph_client import CephAPIError, CephClient from ceph_mcp.config.settings import settings from ceph_mcp.models.ceph_models import ClusterHealth, HealthStatus from ceph_mcp.server import CephMCPServer class TestConfiguration: """Test that configuration is properly loaded and validated.""" def test_settings_loaded(self) -> None: """Ensure settings are loaded from environment.""" assert settings.ceph_manager_url is not None assert settings.ceph_username is not None assert settings.mcp_server_name == "ceph-storage-assistant" def test_ceph_url_validation(self) -> None: """Test that Ceph URL validation works correctly.""" # The URL should be properly formatted assert str(settings.ceph_manager_url).startswith(("http://", "https://")) assert not str(settings.ceph_manager_url).endswith("/") class TestCephClient: """Test the Ceph API client functionality.""" @pytest.mark.asyncio async def test_client_context_manager(self) -> None: """Test that the client can be used as an async context manager.""" async with CephClient() as client: assert client.session is not None assert client.base_url == settings.ceph_manager_url # Session should be closed after exiting context assert client.session is None @pytest.mark.asyncio @pytest.mark.integration async def test_get_cluster_health_real(self) -> None: """Test getting real cluster health (requires running Ceph cluster).""" try: async with CephClient() as client: health = await client.get_cluster_health() # Basic validation that we got a health response assert isinstance(health, ClusterHealth) assert health.status in [ HealthStatus.OK, HealthStatus.WARN, HealthStatus.ERR, ] assert isinstance(health.summary, str) print(f"Cluster Health: {health.status.value}") print(f"Summary: {health.summary}") except CephAPIError as e: pytest.skip(f"Could not connect to Ceph cluster: {e}") @pytest.mark.asyncio @pytest.mark.integration async def test_get_hosts_real(self) -> None: """Test getting real host information (requires running Ceph cluster).""" try: async with CephClient() as client: hosts = await client.get_hosts() # Basic validation assert isinstance(hosts, list) if hosts: # If we have hosts, validate their structure host = hosts[0] assert hasattr(host, "hostname") assert hasattr(host, "addr") assert hasattr(host, "status") print(f"Found {len(hosts)} hosts") for host in hosts: print(f" - {host.hostname}: {host.status}") except CephAPIError as e: pytest.skip(f"Could not connect to Ceph cluster: {e}") @pytest.mark.asyncio async def test_authentication_error_handling(self) -> None: """Test that authentication errors are handled properly.""" # Create a client with invalid credentials with patch("ceph_mcp.config.settings.settings") as mock_settings: mock_settings.ceph_username = "invalid_user" mock_settings.ceph_password = "invalid_password" mock_settings.ceph_manager_url = settings.ceph_manager_url mock_settings.request_timeout_seconds = 5 mock_settings.max_retries = 1 client = CephClient() # This should raise a CephAPIError for authentication failure with pytest.raises(CephAPIError) as exc_info: async with client: await client.get_cluster_health() # The error should indicate authentication failure assert "authentication" in str(exc_info.value).lower() or "401" in str( exc_info.value ) class TestMCPServer: """Test the MCP server functionality.""" def test_server_initialization(self) -> None: """Test that the MCP server initializes correctly.""" server = CephMCPServer() assert server.server is not None assert server.health_handlers is not None assert server.host_handlers is not None @pytest.mark.asyncio async def test_tool_registration(self) -> None: """Test that tools are properly registered.""" server = CephMCPServer() # We can't easily test the actual MCP server without setting up # a full MCP client, but we can test that our handlers work assert server.health_handlers is not None assert server.host_handlers is not None class TestHandlers: """Test the request handlers.""" @pytest.mark.asyncio async def test_health_handler_with_mock(self) -> None: """Test health handler with mock Ceph client.""" from ceph_mcp.handlers.health_handlers import HealthHandlers # Create a mock cluster health response mock_health = ClusterHealth( status=HealthStatus.OK, summary="Cluster is healthy", checks={}, mutes=[] ) # Mock the entire cluster status mock_cluster_status = AsyncMock() mock_cluster_status.health = mock_health mock_cluster_status.get_host_summary.return_value = "All hosts online" mock_cluster_status.get_overall_summary.return_value = "Everything looks good" mock_cluster_status.total_hosts = 3 mock_cluster_status.online_hosts = 3 mock_cluster_status.total_osds = 12 mock_cluster_status.up_osds = 12 mock_cluster_status.in_osds = 12 mock_cluster_status.collected_at = pytest.approx( asyncio.get_event_loop().time() ) with patch("ceph_mcp.handlers.health_handlers.CephClient") as mock_client_class: mock_client = AsyncMock() mock_client.get_cluster_status.return_value = mock_cluster_status mock_client_class.return_value.__aenter__.return_value = mock_client handler = HealthHandlers() response = await handler.get_cluster_health_summary({}) assert response.success is True assert "healthy" in response.message.lower() assert response.data is not None @pytest.mark.integration class TestIntegration: """Integration tests that require a running Ceph cluster.""" @pytest.mark.asyncio async def test_full_health_check_workflow(self) -> None: """Test the complete workflow from handler to Ceph API.""" from ceph_mcp.handlers.health_handlers import HealthHandlers try: handler = HealthHandlers() response = await handler.get_cluster_health_summary({}) # Should get a successful response assert response.success is True assert response.data is not None assert "overall_health" in response.data print(f"Integration test result: {response.message}") except Exception as e: pytest.skip(f"Integration test failed - check Ceph connectivity: {e}") @pytest.mark.asyncio async def test_host_status_workflow(self) -> None: """Test the complete host status workflow.""" from ceph_mcp.handlers.health_handlers import HealthHandlers try: handler = HealthHandlers() response = await handler.get_host_status({}) assert response.success is True assert response.data is not None assert "hosts" in response.data print(f"Host status test result: {response.message}") except Exception as e: pytest.skip(f"Integration test failed - check Ceph connectivity: {e}") # Helper fixtures for testing @pytest.fixture def mock_ceph_health() -> ClusterHealth: """Fixture providing a mock Ceph health response.""" return ClusterHealth( status=HealthStatus.OK, summary="Cluster is operating normally", checks={}, mutes=[], overall_status_description="All systems are functioning correctly", ) # Utility function for manual testing async def manual_test_connection() -> None: """ Manual test function you can run to verify connectivity. Usage: python -c "from tests.test_basic_functionality import manual_test_connection; import asyncio; asyncio.run(manual_test_connection())" """ print(f"Testing connection to: {settings.ceph_manager_url}") print(f"Using username: {settings.ceph_username}") try: async with CephClient() as client: print("✅ Successfully created client connection") health = await client.get_cluster_health() print(f"✅ Cluster health: {health.status.value}") print(f" Summary: {health.summary}") hosts = await client.get_hosts() print(f"✅ Retrieved {len(hosts)} hosts") for host in hosts: print(f" - {host.hostname}: {host.status}") print("🎉 All tests passed! Your Ceph MCP server should work correctly.") except CephAPIError as e: print(f"❌ Ceph API Error: {e}") print(" Check your Ceph Manager URL, credentials, and network connectivity.") except Exception as e: print(f"❌ Unexpected error: {e}") print(" Check your configuration and try again.") if __name__ == "__main__": # Allow running this file directly for manual testing import sys if len(sys.argv) > 1 and sys.argv[1] == "test-connection": asyncio.run(manual_test_connection()) else: print( "Run 'python tests/test_basic_functionality.py test-connection' " "to test your Ceph connection" ) print("Or run 'uv run pytest tests/' to run the full test suite")

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/rajmohanram/ceph-mcp-server'

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