Skip to main content
Glama

MaverickMCP

by wshobson
MIT License
165
  • Apple
test_production_validation.py24.2 kB
""" Production Validation Test Suite for MaverickMCP. This suite validates that the system is ready for production deployment by testing configuration, environment setup, monitoring, backup procedures, and production-like load scenarios. Validates: - Environment configuration correctness - SSL/TLS configuration (when available) - Monitoring and alerting systems - Backup and recovery procedures - Load testing with production-like scenarios - Security configuration in production mode - Database migration status and integrity - Performance optimization effectiveness """ import asyncio import os import ssl import time from pathlib import Path from unittest.mock import patch import pytest from fastapi.testclient import TestClient from maverick_mcp.api.api_server import create_api_app from maverick_mcp.config.settings import get_settings from maverick_mcp.config.validation import get_validation_status from maverick_mcp.data.models import SessionLocal from maverick_mcp.data.performance import ( cleanup_performance_systems, get_performance_metrics, initialize_performance_systems, ) from maverick_mcp.utils.monitoring import get_metrics, initialize_monitoring @pytest.fixture(scope="session") def production_settings(): """Get production-like settings.""" with patch.dict( os.environ, { "ENVIRONMENT": "production", "AUTH_ENABLED": "true", "SECURITY_ENABLED": "true", "JWT_SECRET": "test-jwt-secret-for-production-validation-tests-minimum-32-chars", "DATABASE_URL": "postgresql://test:test@localhost/test_prod_db", }, ): return get_settings() @pytest.fixture def production_app(production_settings): """Create production-configured app.""" return create_api_app() @pytest.fixture def production_client(production_app): """Create client for production testing.""" return TestClient(production_app) class TestEnvironmentConfiguration: """Test production environment configuration.""" @pytest.mark.skip(reason="Incompatible with global test environment configuration") def test_environment_variables_set(self, production_settings): """Test that all required environment variables are set.""" # Critical environment variables for production critical_vars = [ "DATABASE_URL", "JWT_SECRET", "ENVIRONMENT", ] # Check that critical vars are set (not default values) for var in critical_vars: env_value = os.getenv(var) if var == "DATABASE_URL": # Should not be default SQLite in production if env_value is None: pytest.skip(f"{var} not set in test environment") if env_value: assert ( "sqlite" not in env_value.lower() or "memory" not in env_value.lower() ) elif var == "JWT_SECRET": # Should not be default/weak secret if env_value is None: pytest.skip(f"{var} not set in test environment") if env_value: assert len(env_value) >= 32 assert env_value != "your-secret-key-here" assert env_value != "development-key" elif var == "ENVIRONMENT": if env_value is None: pytest.skip(f"{var} not set in test environment") assert env_value in ["production", "staging"] def test_security_configuration(self, production_settings): """Test security configuration for production.""" # Authentication should be enabled assert production_settings.auth.enabled is True # Secure cookies in production if production_settings.environment == "production": # Cookie security should be enabled (skip if not implemented) if not hasattr(production_settings, "cookie_secure"): pytest.skip("Cookie secure setting not implemented yet") # JWT configuration assert production_settings.auth.jwt_algorithm in ["RS256", "HS256"] assert ( production_settings.auth.jwt_access_token_expire_minutes <= 60 ) # Not too long # Redis configuration (should not use default) if hasattr(production_settings.auth, "redis_url"): redis_url = production_settings.auth.redis_url assert "localhost" not in redis_url or os.getenv("REDIS_HOST") is not None def test_database_configuration(self, production_settings): """Test database configuration for production.""" # Get database URL from environment or settings database_url = os.getenv("DATABASE_URL", "") if not database_url: pytest.skip("DATABASE_URL not set in environment") # Should use production database (not SQLite) assert ( "postgresql" in database_url.lower() or "mysql" in database_url.lower() ) and "sqlite" not in database_url.lower() # Should not use default credentials if "postgresql://" in database_url: assert "password" not in database_url or "your-password" not in database_url assert ( "localhost" not in database_url or os.getenv("DATABASE_HOST") is not None ) # Test database connection try: with SessionLocal() as session: result = session.execute("SELECT 1") assert result.scalar() == 1 except Exception as e: pytest.skip(f"Database connection test skipped: {e}") def test_logging_configuration(self, production_settings): """Test logging configuration for production.""" # Log level should be appropriate for production assert production_settings.api.log_level.upper() in ["INFO", "WARNING", "ERROR"] # Should not be DEBUG in production if production_settings.environment == "production": assert production_settings.api.log_level.upper() != "DEBUG" def test_api_configuration(self, production_settings): """Test API configuration for production.""" # Debug features should be disabled if production_settings.environment == "production": assert production_settings.api.debug is False # CORS should be properly configured cors_origins = production_settings.api.cors_origins assert cors_origins is not None # Should not allow all origins in production if production_settings.environment == "production": assert "*" not in cors_origins class TestSystemValidation: """Test system validation and health checks.""" def test_configuration_validation(self): """Test configuration validation system.""" validation_status = get_validation_status() # Should have validation status assert "valid" in validation_status assert "warnings" in validation_status assert "errors" in validation_status # In production, should have minimal warnings/errors if os.getenv("ENVIRONMENT") == "production": assert len(validation_status["errors"]) == 0 assert len(validation_status["warnings"]) <= 2 # Allow some minor warnings def test_health_check_endpoint(self, production_client): """Test health check endpoint functionality.""" response = production_client.get("/health") assert response.status_code == 200 health_data = response.json() assert "status" in health_data assert health_data["status"] in ["healthy", "degraded"] # Should include service information assert "services" in health_data assert "version" in health_data # Should include circuit breakers assert "circuit_breakers" in health_data @pytest.mark.integration def test_database_health(self): """Test database health and connectivity.""" try: with SessionLocal() as session: # Test basic connectivity from sqlalchemy import text result = session.execute(text("SELECT 1 as health_check")) assert result.scalar() == 1 # Test transaction capability # Session already has a transaction, so just test query # Use SQLite-compatible query for testing result = session.execute( text("SELECT COUNT(*) FROM sqlite_master WHERE type='table'") if "sqlite" in str(session.bind.url) else text("SELECT COUNT(*) FROM information_schema.tables") ) assert result.scalar() >= 0 # Should return some count except Exception as e: pytest.fail(f"Database health check failed: {e}") @pytest.mark.asyncio @pytest.mark.integration async def test_performance_systems_health(self): """Test performance systems health.""" # Initialize performance systems performance_status = await initialize_performance_systems() # Should initialize successfully assert isinstance(performance_status, dict) assert "redis_manager" in performance_status # Get performance metrics metrics = await get_performance_metrics() assert "redis_manager" in metrics assert "request_cache" in metrics assert "query_optimizer" in metrics assert "timestamp" in metrics # Cleanup await cleanup_performance_systems() def test_monitoring_systems(self): """Test monitoring systems are functional.""" try: # Initialize monitoring initialize_monitoring() # Get metrics metrics_data = get_metrics() assert isinstance(metrics_data, str) # Should be Prometheus format assert ( "# HELP" in metrics_data or "# TYPE" in metrics_data or len(metrics_data) > 0 ) except Exception as e: pytest.skip(f"Monitoring test skipped: {e}") class TestSSLTLSConfiguration: """Test SSL/TLS configuration (when available).""" def test_ssl_certificate_validity(self): """Test SSL certificate validity.""" # This would test actual SSL certificate in production # For testing, we check if SSL context can be created try: context = ssl.create_default_context() assert context.check_hostname is True assert context.verify_mode == ssl.CERT_REQUIRED except Exception as e: pytest.skip(f"SSL test skipped: {e}") def test_tls_configuration(self, production_client): """Test TLS configuration.""" # Test security headers are present production_client.get("/health") # Should have security headers in production security_headers = [ "X-Content-Type-Options", "X-Frame-Options", "X-XSS-Protection", ] # Note: These would be set by security middleware # Check if security middleware is active for _header in security_headers: # In test environment, headers might not be set # In production, they should be present if os.getenv("ENVIRONMENT") == "production": # assert header in response.headers pass # Skip for test environment def test_secure_cookie_configuration(self, production_client, production_settings): """Test secure cookie configuration.""" if production_settings.environment != "production": pytest.skip("Secure cookie test only for production") # Test that cookies are set with secure flags test_user = { "email": "ssl_test@example.com", "password": "TestPass123!", "name": "SSL Test User", } # Register and login production_client.post("/auth/register", json=test_user) login_response = production_client.post( "/auth/login", json={"email": test_user["email"], "password": test_user["password"]}, ) # Check cookie headers for security flags cookie_header = login_response.headers.get("set-cookie", "") if cookie_header: # Should have Secure flag in production assert "Secure" in cookie_header assert "HttpOnly" in cookie_header assert "SameSite" in cookie_header class TestBackupAndRecovery: """Test backup and recovery procedures.""" def test_database_backup_capability(self): """Test database backup capability.""" try: with SessionLocal() as session: # Test that we can read critical tables critical_tables = [ "mcp_users", "mcp_api_keys", "auth_audit_log", ] for table in critical_tables: try: result = session.execute(f"SELECT COUNT(*) FROM {table}") count = result.scalar() assert count >= 0 # Should be able to count rows except Exception as e: # Table might not exist in test environment pytest.skip(f"Table {table} not found: {e}") except Exception as e: pytest.skip(f"Database backup test skipped: {e}") def test_configuration_backup(self): """Test configuration backup capability.""" # Test that critical configuration can be backed up critical_config_files = [ "alembic.ini", ".env", # Note: should not backup .env with secrets "pyproject.toml", ] project_root = Path(__file__).parent.parent for config_file in critical_config_files: config_path = project_root / config_file if config_path.exists(): # Should be readable assert config_path.is_file() assert os.access(config_path, os.R_OK) else: # Some files might not exist in test environment pass def test_graceful_shutdown_capability(self, production_app): """Test graceful shutdown capability.""" # Test that app can handle shutdown signals # This is more of a conceptual test since we can't actually shut down # Check that shutdown handlers are registered # This would be tested in actual deployment assert hasattr(production_app, "router") assert production_app.router is not None class TestLoadTesting: """Test system under production-like load.""" @pytest.mark.skip( reason="Long-running load test - disabled to conserve CI resources" ) @pytest.mark.asyncio @pytest.mark.integration async def test_concurrent_user_load(self, production_client): """Test system under concurrent user load.""" # Create multiple test users test_users = [] for i in range(5): user = { "email": f"loadtest{i}@example.com", "password": "LoadTest123!", "name": f"Load Test User {i}", } test_users.append(user) # Register user response = production_client.post("/auth/register", json=user) if response.status_code not in [200, 201]: pytest.skip("User registration failed in load test") # Simulate concurrent operations async def user_session(user_data): """Simulate a complete user session.""" results = [] # Login login_response = production_client.post( "/auth/login", json={"email": user_data["email"], "password": user_data["password"]}, ) results.append(("login", login_response.status_code)) if login_response.status_code == 200: csrf_token = login_response.json().get("csrf_token") # Multiple API calls for _ in range(3): profile_response = production_client.get( "/user/profile", headers={"X-CSRF-Token": csrf_token} ) results.append(("profile", profile_response.status_code)) return results # Run concurrent sessions tasks = [user_session(user) for user in test_users] session_results = await asyncio.gather(*tasks, return_exceptions=True) # Analyze results all_results = [] for result in session_results: if isinstance(result, list): all_results.extend(result) # Should have mostly successful responses success_rate = sum( 1 for op, status in all_results if status in [200, 201] ) / len(all_results) assert success_rate >= 0.8 # At least 80% success rate @pytest.mark.skip( reason="Long-running performance test - disabled to conserve CI resources" ) def test_api_endpoint_performance(self, production_client): """Test API endpoint performance.""" # Test key endpoints for performance endpoints_to_test = [ "/health", "/", ] performance_results = {} for endpoint in endpoints_to_test: times = [] for _ in range(5): start_time = time.time() response = production_client.get(endpoint) end_time = time.time() if response.status_code == 200: times.append(end_time - start_time) if times: avg_time = sum(times) / len(times) max_time = max(times) performance_results[endpoint] = { "avg_time": avg_time, "max_time": max_time, } # Performance assertions assert avg_time < 1.0 # Average response under 1 second assert max_time < 2.0 # Max response under 2 seconds @pytest.mark.skip( reason="Long-running memory test - disabled to conserve CI resources" ) def test_memory_usage_stability(self, production_client): """Test memory usage stability under load.""" # Make multiple requests to test for memory leaks initial_response_time = None final_response_time = None for i in range(20): start_time = time.time() response = production_client.get("/health") end_time = time.time() if response.status_code == 200: response_time = end_time - start_time if i == 0: initial_response_time = response_time elif i == 19: final_response_time = response_time # Response time should not degrade significantly (indicating memory leaks) if initial_response_time and final_response_time: degradation_ratio = final_response_time / initial_response_time assert degradation_ratio < 3.0 # Should not be 3x slower class TestProductionReadinessChecklist: """Final production readiness checklist.""" def test_database_migrations_applied(self): """Test that all database migrations are applied.""" try: with SessionLocal() as session: # Check that migration tables exist result = session.execute(""" SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'alembic_version' """) migration_table_exists = result.scalar() is not None if migration_table_exists: # Check current migration version version_result = session.execute( "SELECT version_num FROM alembic_version" ) current_version = version_result.scalar() assert current_version is not None assert len(current_version) > 0 except Exception as e: pytest.skip(f"Database migration check skipped: {e}") def test_security_features_enabled(self, production_settings): """Test that all security features are enabled.""" # Authentication enabled assert production_settings.auth.enabled is True # Proper environment assert production_settings.environment in ["production", "staging"] def test_performance_optimizations_active(self): """Test that performance optimizations are active.""" # This would test actual performance optimizations # For now, test that performance modules can be imported try: from maverick_mcp.data.performance import ( query_optimizer, redis_manager, request_cache, ) assert redis_manager is not None assert request_cache is not None assert query_optimizer is not None except ImportError as e: pytest.fail(f"Performance optimization modules not available: {e}") def test_monitoring_and_logging_ready(self): """Test that monitoring and logging are ready.""" try: # Test logging configuration from maverick_mcp.utils.logging import get_logger logger = get_logger("production_test") assert logger is not None # Test monitoring availability from maverick_mcp.utils.monitoring import get_metrics metrics = get_metrics() assert isinstance(metrics, str) except Exception as e: pytest.skip(f"Monitoring test skipped: {e}") @pytest.mark.integration def test_final_system_integration(self, production_client): """Final system integration test.""" # Test complete workflow with unique email import uuid unique_id = str(uuid.uuid4())[:8] test_user = { "email": f"final_test_{unique_id}@example.com", "password": "FinalTest123!", "name": "Final Test User", } # 1. Health check health_response = production_client.get("/health") assert health_response.status_code == 200 # 2. User registration register_response = production_client.post("/auth/signup", json=test_user) assert register_response.status_code in [200, 201] # 3. User login login_response = production_client.post( "/auth/login", json={"email": test_user["email"], "password": test_user["password"]}, ) assert login_response.status_code == 200 # Get tokens from response login_data = login_response.json() access_token = login_data.get("access_token") # If no access token in response body, it might be in cookies if not access_token: # For cookie-based auth, we just need to make sure login succeeded assert "user" in login_data or "message" in login_data # 4. Authenticated API access (with cookies) profile_response = production_client.get("/user/profile") assert profile_response.status_code == 200 else: # Bearer token auth headers = {"Authorization": f"Bearer {access_token}"} # 4. Authenticated API access profile_response = production_client.get("/user/profile", headers=headers) assert profile_response.status_code == 200 if __name__ == "__main__": pytest.main([__file__, "-v", "--tb=short"])

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/wshobson/maverick-mcp'

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