Skip to main content
Glama
ooples

MCP Console Automation Server

global-setup.ts13.4 kB
/** * Global Jest Setup * * This file runs once before all test suites across all workers. * It initializes test infrastructure and external dependencies. */ import { TestServerManager } from '../utils/test-servers.js'; import { Logger } from '../../src/utils/logger.js'; import * as fs from 'fs/promises'; import * as path from 'path'; // Global test configuration const GLOBAL_CONFIG = { testDataDir: path.join(process.cwd(), 'tests', 'data'), logLevel: process.env.CI ? 'warn' : 'debug', testTimeout: 30000, maxRetries: 3, cleanup: { tempFiles: true, testServers: true, dockerContainers: true, kubernetesResources: true } }; let testServerManager: TestServerManager; let globalCleanupHandlers: (() => Promise<void>)[] = []; export default async function globalSetup(): Promise<void> { console.log('🚀 Starting global test setup...'); try { // Set test environment variables setupEnvironmentVariables(); // Initialize logger for testing process.env.LOG_LEVEL = GLOBAL_CONFIG.logLevel; const logger = Logger.getInstance(); logger.info('Global test setup initialized'); // Create test data directory await ensureTestDataDirectory(); // Initialize test server manager testServerManager = new TestServerManager(); await testServerManager.initialize(); // Start essential test servers await startEssentialTestServers(); // Setup Docker test environment await setupDockerTestEnvironment(); // Setup Kubernetes test environment await setupKubernetesTestEnvironment(); // Register cleanup handlers setupGlobalCleanupHandlers(); // Verify all systems are ready await verifyTestEnvironment(); console.log('✅ Global test setup completed successfully'); } catch (error) { console.error('❌ Global test setup failed:', error); // Attempt cleanup on failure await performGlobalCleanup(); throw error; } } /** * Setup environment variables for testing */ function setupEnvironmentVariables(): void { const testEnvVars = { NODE_ENV: 'test', LOG_LEVEL: GLOBAL_CONFIG.logLevel, TEST_TIMEOUT: GLOBAL_CONFIG.testTimeout.toString(), DISABLE_TELEMETRY: 'true', JEST_WORKER_ID: process.env.JEST_WORKER_ID || '1', // Protocol-specific test configurations DOCKER_TEST_IMAGE: 'alpine:latest', KUBERNETES_TEST_NAMESPACE: 'test-console-automation', SSH_TEST_HOST: 'localhost', SSH_TEST_PORT: '2222', SERIAL_TEST_PORT: process.platform === 'win32' ? 'COM99' : '/dev/ttyS99', // Security test configurations ENABLE_SECURITY_TESTS: 'true', SECURITY_TEST_TIMEOUT: '180000', // Performance test configurations ENABLE_PERFORMANCE_TESTS: 'true', PERFORMANCE_TEST_ITERATIONS: '10', PERFORMANCE_TEST_CONCURRENT_SESSIONS: '5' }; Object.entries(testEnvVars).forEach(([key, value]) => { if (!process.env[key]) { process.env[key] = value; } }); } /** * Ensure test data directory exists */ async function ensureTestDataDirectory(): Promise<void> { try { await fs.access(GLOBAL_CONFIG.testDataDir); } catch { await fs.mkdir(GLOBAL_CONFIG.testDataDir, { recursive: true }); } // Create subdirectories for different test types const subdirs = [ 'fixtures', 'temp', 'logs', 'certificates', 'keys', 'docker', 'kubernetes', 'serial-data' ]; for (const subdir of subdirs) { const dirPath = path.join(GLOBAL_CONFIG.testDataDir, subdir); try { await fs.access(dirPath); } catch { await fs.mkdir(dirPath, { recursive: true }); } } } /** * Start essential test servers */ async function startEssentialTestServers(): Promise<void> { console.log('Starting essential test servers...'); try { // SSH test server const sshServer = testServerManager .createServer('ssh') .withPort(parseInt(process.env.SSH_TEST_PORT || '2222')) .withAuth({ username: 'test', password: 'test123' }) .withFeatures({ sftp: true, exec: true }) .build(); await testServerManager.startServer('ssh-test', sshServer); // HTTP test server for webhooks and APIs const httpServer = testServerManager .createServer('http') .withPort(3000) .withRoutes({ '/webhook': { method: 'POST', response: { status: 'ok' } }, '/health': { method: 'GET', response: { status: 'healthy' } } }) .build(); await testServerManager.startServer('http-test', httpServer); // WebSocket test server const wsServer = testServerManager .createServer('websocket') .withPort(8080) .withProtocols(['terminal', 'shell']) .build(); await testServerManager.startServer('websocket-test', wsServer); console.log('✅ Essential test servers started'); } catch (error) { console.error('❌ Failed to start essential test servers:', error); throw error; } } /** * Setup Docker test environment */ async function setupDockerTestEnvironment(): Promise<void> { if (!isDockerAvailable()) { console.log('⚠️ Docker not available, skipping Docker test setup'); return; } console.log('Setting up Docker test environment...'); try { // Pull required test images const testImages = [ 'alpine:latest', 'ubuntu:20.04', 'nginx:alpine', 'node:18-alpine' ]; for (const image of testImages) { await pullDockerImage(image); } // Create test network await createDockerNetwork('console-automation-test'); console.log('✅ Docker test environment ready'); } catch (error) { console.error('❌ Docker test environment setup failed:', error); // Don't fail the entire setup for Docker issues } } /** * Setup Kubernetes test environment */ async function setupKubernetesTestEnvironment(): Promise<void> { if (!isKubernetesAvailable()) { console.log('⚠️ Kubernetes not available, skipping K8s test setup'); return; } console.log('Setting up Kubernetes test environment...'); try { const namespace = process.env.KUBERNETES_TEST_NAMESPACE; // Create test namespace await createKubernetesNamespace(namespace); // Deploy test pods await deployTestPods(namespace); console.log('✅ Kubernetes test environment ready'); } catch (error) { console.error('❌ Kubernetes test environment setup failed:', error); // Don't fail the entire setup for K8s issues } } /** * Setup global cleanup handlers */ function setupGlobalCleanupHandlers(): void { // Register cleanup on process exit process.on('exit', () => { console.log('Process exit detected, performing cleanup...'); }); process.on('SIGINT', async () => { console.log('SIGINT received, performing graceful shutdown...'); await performGlobalCleanup(); process.exit(0); }); process.on('SIGTERM', async () => { console.log('SIGTERM received, performing graceful shutdown...'); await performGlobalCleanup(); process.exit(0); }); process.on('uncaughtException', async (error) => { console.error('Uncaught exception:', error); await performGlobalCleanup(); process.exit(1); }); process.on('unhandledRejection', async (reason, promise) => { console.error('Unhandled rejection at:', promise, 'reason:', reason); await performGlobalCleanup(); process.exit(1); }); } /** * Verify test environment is ready */ async function verifyTestEnvironment(): Promise<void> { console.log('Verifying test environment...'); const verifications = [ verifyTestDataDirectory(), verifyTestServers(), verifyDockerEnvironment(), verifyKubernetesEnvironment() ]; const results = await Promise.allSettled(verifications); const failures = results .map((result, index) => ({ result, index })) .filter(({ result }) => result.status === 'rejected') .map(({ result, index }) => ({ check: ['TestData', 'TestServers', 'Docker', 'Kubernetes'][index], error: (result as PromiseRejectedResult).reason })); if (failures.length > 0) { console.warn('⚠️ Some environment verifications failed:', failures); } else { console.log('✅ All environment verifications passed'); } } /** * Perform global cleanup */ async function performGlobalCleanup(): Promise<void> { console.log('Performing global cleanup...'); try { // Run all registered cleanup handlers for (const cleanup of globalCleanupHandlers) { try { await cleanup(); } catch (error) { console.error('Cleanup handler failed:', error); } } // Stop test servers if (testServerManager) { await testServerManager.stopAllServers(); await testServerManager.dispose(); } // Clean up Docker resources if (GLOBAL_CONFIG.cleanup.dockerContainers) { await cleanupDockerResources(); } // Clean up Kubernetes resources if (GLOBAL_CONFIG.cleanup.kubernetesResources) { await cleanupKubernetesResources(); } // Clean up temp files if (GLOBAL_CONFIG.cleanup.tempFiles) { await cleanupTempFiles(); } console.log('✅ Global cleanup completed'); } catch (error) { console.error('❌ Global cleanup failed:', error); } } // Helper functions function isDockerAvailable(): boolean { try { const { execSync } = require('child_process'); execSync('docker --version', { stdio: 'ignore' }); return true; } catch { return false; } } function isKubernetesAvailable(): boolean { try { const { execSync } = require('child_process'); execSync('kubectl version --client', { stdio: 'ignore' }); return true; } catch { return false; } } async function pullDockerImage(image: string): Promise<void> { const { execSync } = require('child_process'); console.log(`Pulling Docker image: ${image}`); execSync(`docker pull ${image}`, { stdio: 'inherit' }); } async function createDockerNetwork(name: string): Promise<void> { const { execSync } = require('child_process'); try { execSync(`docker network create ${name}`, { stdio: 'ignore' }); } catch { // Network might already exist } } async function createKubernetesNamespace(namespace: string): Promise<void> { const { execSync } = require('child_process'); try { execSync(`kubectl create namespace ${namespace}`, { stdio: 'ignore' }); } catch { // Namespace might already exist } } async function deployTestPods(namespace: string): Promise<void> { const { execSync } = require('child_process'); const podManifest = ` apiVersion: v1 kind: Pod metadata: name: test-pod namespace: ${namespace} spec: containers: - name: test-container image: alpine:latest command: ['sleep', '3600'] `; const manifestPath = path.join(GLOBAL_CONFIG.testDataDir, 'test-pod.yaml'); await fs.writeFile(manifestPath, podManifest); try { execSync(`kubectl apply -f ${manifestPath}`, { stdio: 'ignore' }); } catch (error) { console.warn('Failed to deploy test pod:', error); } } async function verifyTestDataDirectory(): Promise<void> { await fs.access(GLOBAL_CONFIG.testDataDir); } async function verifyTestServers(): Promise<void> { const servers = testServerManager.getActiveServers(); if (servers.length === 0) { throw new Error('No test servers are running'); } } async function verifyDockerEnvironment(): Promise<void> { if (isDockerAvailable()) { const { execSync } = require('child_process'); execSync('docker info', { stdio: 'ignore' }); } } async function verifyKubernetesEnvironment(): Promise<void> { if (isKubernetesAvailable()) { const { execSync } = require('child_process'); execSync('kubectl cluster-info', { stdio: 'ignore' }); } } async function cleanupDockerResources(): Promise<void> { if (!isDockerAvailable()) return; try { const { execSync } = require('child_process'); // Stop and remove test containers execSync('docker container prune -f', { stdio: 'ignore' }); // Remove test network execSync('docker network rm console-automation-test', { stdio: 'ignore' }); } catch (error) { console.warn('Docker cleanup warnings:', error); } } async function cleanupKubernetesResources(): Promise<void> { if (!isKubernetesAvailable()) return; try { const { execSync } = require('child_process'); const namespace = process.env.KUBERNETES_TEST_NAMESPACE; // Delete test namespace and all resources execSync(`kubectl delete namespace ${namespace}`, { stdio: 'ignore' }); } catch (error) { console.warn('Kubernetes cleanup warnings:', error); } } async function cleanupTempFiles(): Promise<void> { const tempDir = path.join(GLOBAL_CONFIG.testDataDir, 'temp'); try { const files = await fs.readdir(tempDir); for (const file of files) { await fs.unlink(path.join(tempDir, file)); } } catch (error) { console.warn('Temp file cleanup warnings:', error); } } // Export cleanup function for programmatic use export async function cleanup(): Promise<void> { await performGlobalCleanup(); } // Store reference for global teardown (global as any).__GLOBAL_SETUP__ = { testServerManager, cleanup: performGlobalCleanup, config: GLOBAL_CONFIG };

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/ooples/mcp-console-automation'

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