Skip to main content
Glama
global-teardown.ts5.81 kB
/** * Global Teardown for Test Framework * * Runs once after all tests complete. * Used for: * - Stopping test containers via Docker Compose * - Cleaning up test database infrastructure * - Closing connections * - Generating final reports * * Handles: * - KEEP_CONTAINERS_RUNNING=true case (preserves containers) * - Signal handlers for SIGINT/SIGTERM (graceful cleanup) * * Note: Since global setup and teardown run in separate processes in Vitest, * we cannot share the TestContainerManager instance. Instead, we use Docker * Compose directly to check and stop containers. * * Requirements: 2.1, 2.2, 2.4, 2.5, 6.3 * * @module __tests__/setup/global-teardown */ import { DockerComposeWrapper } from "../../containers/docker-compose-wrapper"; /** * Flag to track if cleanup has already been performed. * Prevents duplicate cleanup from signal handlers. */ let cleanupPerformed = false; /** * Performs container cleanup using Docker Compose directly. * * Since global setup and teardown run in separate processes in Vitest, * we cannot share the TestContainerManager instance. Instead, we use * Docker Compose directly to check and stop containers. * * This function: * 1. Checks KEEP_CONTAINERS_RUNNING setting * 2. Checks AUTO_START_CONTAINERS setting (if false, we didn't start containers) * 3. Uses docker compose down to stop test containers * * Requirements: * - 2.1: Stop containers that were started by manager * - 2.2: Stop containers even if tests fail or are interrupted * - 6.3: Honor KEEP_CONTAINERS_RUNNING setting * * @returns Promise resolving when cleanup is complete */ async function performContainerCleanup(): Promise<void> { // Prevent duplicate cleanup if (cleanupPerformed) { return; } cleanupPerformed = true; // Check if we should keep containers running if (process.env.KEEP_CONTAINERS_RUNNING === "true") { console.log(" Keeping containers running (KEEP_CONTAINERS_RUNNING=true)"); return; } // Check if auto-start was disabled (we didn't start containers) if (process.env.AUTO_START_CONTAINERS === "false") { console.log(" Skipping cleanup (AUTO_START_CONTAINERS=false)"); return; } // Check if database setup was skipped if (process.env.SKIP_DB_SETUP === "true") { console.log(" Skipping cleanup (SKIP_DB_SETUP=true)"); return; } try { const composeWrapper = new DockerComposeWrapper(); const composeFile = process.env.TEST_COMPOSE_FILE ?? "docker-compose.test.yml"; // Check if test containers are running const services = await composeWrapper.ps(composeFile); const runningServices = services.filter((s) => s.status === "running"); if (runningServices.length === 0) { console.log(" No test containers running - skipping cleanup"); return; } // Stop containers const preserveData = process.env.PRESERVE_TEST_DATA === "true"; await composeWrapper.down(composeFile, { volumes: !preserveData, timeout: 10, }); console.log(" ✅ Container cleanup complete"); } catch (error) { // Log error but don't throw - cleanup should be best-effort const errorMessage = error instanceof Error ? error.message : String(error); console.error(` ⚠️ Container cleanup error: ${errorMessage}`); } } /** * Signal handler for graceful shutdown. * * Handles SIGINT (Ctrl+C) and SIGTERM signals to ensure * containers are properly cleaned up when tests are interrupted. * * Requirement 2.5: Perform graceful container cleanup on SIGINT/SIGTERM * * @param signal - The signal that was received */ function handleSignal(signal: string): void { console.log(`\n🛑 Received ${signal} - performing graceful cleanup...`); // Perform cleanup synchronously since we're in a signal handler // Note: We can't use async/await directly in signal handlers performContainerCleanup() .then(() => { console.log("✅ Graceful shutdown complete"); process.exit(0); }) .catch((error) => { console.error("❌ Error during graceful shutdown:", error); process.exit(1); }); } /** * Registers signal handlers for graceful shutdown. * * This ensures containers are cleaned up even when: * - User presses Ctrl+C (SIGINT) * - Process is terminated (SIGTERM) * * Requirement 2.5: Handle SIGINT/SIGTERM for graceful cleanup */ function registerSignalHandlers(): void { // Only register handlers once const signalHandlersRegistered = (global as Record<string, unknown>).__signalHandlersRegistered; if (signalHandlersRegistered) { return; } (global as Record<string, unknown>).__signalHandlersRegistered = true; // Register SIGINT handler (Ctrl+C) process.on("SIGINT", () => handleSignal("SIGINT")); // Register SIGTERM handler (kill command) process.on("SIGTERM", () => handleSignal("SIGTERM")); } /** * Global teardown function for Vitest. * * This function: * 1. Registers signal handlers for graceful shutdown * 2. Stops containers via TestContainerManager * 3. Performs final cleanup * * Requirements: * - 2.1: Stop containers that were started * - 2.2: Stop containers even if tests fail * - 2.4: Leave pre-existing containers running * - 2.5: Handle SIGINT/SIGTERM gracefully * - 6.3: Honor KEEP_CONTAINERS_RUNNING setting * * @returns Promise resolving when teardown is complete */ export default async function globalTeardown(): Promise<void> { console.log("\n🧹 Cleaning up ThoughtMCP Test Framework..."); // Register signal handlers for any late signals registerSignalHandlers(); // Perform container cleanup try { await performContainerCleanup(); } catch (error) { console.error("❌ Teardown error:", error); } console.log("✅ Test framework cleanup complete\n"); }

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/keyurgolani/ThoughtMcp'

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