Skip to main content
Glama
global-setup.ts9.6 kB
/** * Global Setup for Test Framework * * Runs once before all tests start. * Used for: * - Starting test containers (PostgreSQL, Ollama) via TestContainerManager * - Setting up test database infrastructure * - Initializing test environment * - Loading test configuration * - Running database migrations * * Set SKIP_DB_SETUP=true to skip database setup for unit tests that don't need it. * Set AUTO_START_CONTAINERS=false to skip automatic container startup. * * Requirements: 1.1, 1.2, 1.3, 6.1, 7.4 * * @module __tests__/setup/global-setup */ import { existsSync, readFileSync } from "fs"; import { resolve } from "path"; import { ContainerLogger, DockerComposeWrapper, EnvironmentConfigurator, PortAllocator, TestContainerManager, } from "../../containers/index.js"; import { DatabaseConnectionManager } from "../../database/connection-manager.js"; import { SchemaMigrationSystem } from "../../database/schema-migration.js"; /** * Global state to track the TestContainerManager instance. * This is used by global-teardown.ts to clean up containers. */ let containerManager: TestContainerManager | null = null; /** * Gets the TestContainerManager instance for use in teardown. * @returns The TestContainerManager instance or null if not initialized */ export function getContainerManager(): TestContainerManager | null { return containerManager; } /** * Loads environment variables from a .env file. * @param envPath - Path to the .env file */ function loadEnvFile(envPath: string): void { if (!existsSync(envPath)) { return; } const envContent = readFileSync(envPath, "utf-8"); envContent.split("\n").forEach((line) => { const trimmed = line.trim(); if (trimmed && !trimmed.startsWith("#")) { const [key, ...valueParts] = trimmed.split("="); const value = valueParts.join("="); if (key && value && !process.env[key]) { process.env[key] = value; } } }); } /** * Sets default environment variables for tests that skip database setup. */ function setMinimalEnvironment(): void { process.env.DATABASE_URL = process.env.DATABASE_URL ?? "postgresql://test:test@localhost:5433/thoughtmcp_test"; process.env.DB_HOST = process.env.DB_HOST ?? "localhost"; process.env.DB_PORT = process.env.DB_PORT ?? "5433"; process.env.DB_NAME = process.env.DB_NAME ?? "thoughtmcp_test"; process.env.DB_USER = process.env.DB_USER ?? "test"; process.env.DB_PASSWORD = process.env.DB_PASSWORD ?? "test"; process.env.EMBEDDING_MODEL = process.env.EMBEDDING_MODEL ?? "nomic-embed-text"; process.env.EMBEDDING_DIMENSION = process.env.EMBEDDING_DIMENSION ?? "768"; process.env.OLLAMA_HOST = process.env.OLLAMA_HOST ?? "http://localhost:11434"; process.env.LOG_LEVEL = process.env.LOG_LEVEL ?? "ERROR"; } /** * Sets default test configuration environment variables. */ function setDefaultTestConfiguration(): void { process.env.DB_POOL_SIZE = process.env.DB_POOL_SIZE ?? "5"; process.env.EMBEDDING_MODEL = process.env.EMBEDDING_MODEL ?? "nomic-embed-text"; process.env.EMBEDDING_DIMENSION = process.env.EMBEDDING_DIMENSION ?? "768"; process.env.OLLAMA_HOST = process.env.OLLAMA_HOST ?? "http://localhost:11434"; process.env.LOG_LEVEL = process.env.LOG_LEVEL ?? "ERROR"; process.env.CACHE_TTL = process.env.CACHE_TTL ?? "300"; process.env.MAX_PROCESSING_TIME = process.env.MAX_PROCESSING_TIME ?? "30000"; } /** * Initializes and starts test containers using TestContainerManager. * * Requirements: * - 1.1: Check if required containers are already running * - 1.2: Start containers if not running * - 1.3: Wait for health checks to pass * - 6.1: Handle AUTO_START_CONTAINERS=false * - 7.4: Handle Docker unavailable when AUTO_START_CONTAINERS=false * * @returns Promise resolving when containers are ready */ async function initializeContainers(): Promise<void> { // Check if auto-start is disabled if (process.env.AUTO_START_CONTAINERS === "false") { console.log("⏭️ Skipping container auto-start (AUTO_START_CONTAINERS=false)"); console.log(" Assuming containers are managed externally"); return; } console.log("🐳 Initializing test containers..."); // Create container management components const composeWrapper = new DockerComposeWrapper(); const portAllocator = new PortAllocator(); const envConfigurator = new EnvironmentConfigurator(); const logger = new ContainerLogger("test-setup", true); // Create TestContainerManager containerManager = new TestContainerManager( composeWrapper, portAllocator, envConfigurator, logger ); try { // Start containers (handles reuse, port allocation, health checks) const containers = await containerManager.startContainers(); if (containers.length === 0) { // AUTO_START_CONTAINERS was false or containers were already running console.log(" Using existing containers or external management"); return; } // Log container status for (const container of containers) { const reusedLabel = container.startedByManager ? "started" : "reused"; console.log(` ✅ ${container.service}: ${reusedLabel} on port ${container.port}`); } console.log("✅ Test containers ready"); } catch (error) { // Requirement 7.4: Handle Docker unavailable gracefully const errorMessage = error instanceof Error ? error.message : String(error); // If Docker is unavailable but AUTO_START_CONTAINERS is not explicitly false, // we should fail with a clear error message if ( errorMessage.includes("Docker is not available") || errorMessage.includes("Docker is not installed") || errorMessage.includes("Docker daemon is not running") ) { console.error("❌ Docker is not available for test containers"); console.error(" Options:"); console.error(" 1. Start Docker Desktop or Docker daemon"); console.error(" 2. Set AUTO_START_CONTAINERS=false and start containers manually:"); console.error(" docker compose -f docker-compose.test.yml up -d"); throw error; } // Re-throw other errors console.error("❌ Failed to initialize test containers:", errorMessage); throw error; } } /** * Runs database migrations. * @returns Promise resolving when migrations are complete */ async function runMigrations(): Promise<void> { console.log("📦 Running database migrations..."); const dbManager = new DatabaseConnectionManager({ host: process.env.DB_HOST ?? "localhost", port: parseInt(process.env.DB_PORT ?? "5433", 10), database: process.env.DB_NAME ?? "thoughtmcp_test", user: process.env.DB_USER ?? "postgres", password: process.env.DB_PASSWORD ?? "postgres", poolSize: parseInt(process.env.DB_POOL_SIZE ?? "5", 10), }); try { await dbManager.connect(); const migrationSystem = new SchemaMigrationSystem(dbManager); await migrationSystem.runMigrations(); console.log("✅ Database migrations completed"); } catch (error) { console.error("❌ Failed to run migrations:", error); throw error; } finally { await dbManager.disconnect(); } } /** * Global setup function for Vitest. * * This function: * 1. Sets test environment * 2. Loads .env.test file if present * 3. Initializes test containers (if AUTO_START_CONTAINERS is not false) * 4. Runs database migrations (if SKIP_DB_SETUP is not true) * * @returns Promise resolving when setup is complete */ export default async function globalSetup(): Promise<void> { console.log("🚀 Starting ThoughtMCP Test Framework..."); // Set test environment process.env.NODE_ENV = "test"; // Load .env.test file if it exists const envTestPath = resolve(process.cwd(), ".env.test"); loadEnvFile(envTestPath); // Skip database setup if SKIP_DB_SETUP is set (for unit tests that don't need database) if (process.env.SKIP_DB_SETUP === "true") { console.log("⏭️ Skipping database setup (SKIP_DB_SETUP=true)"); setMinimalEnvironment(); console.log("✅ Test environment configured (no database)"); return; } // Validate required environment variables const requiredEnvVars = [ "DATABASE_URL", "DB_HOST", "DB_PORT", "DB_NAME", "DB_USER", "DB_PASSWORD", ]; const missingVars = requiredEnvVars.filter((varName) => !process.env[varName]); if (missingVars.length > 0) { console.warn(`⚠️ Missing environment variables: ${missingVars.join(", ")}`); console.warn(" Using default test configuration..."); // Set default test environment variables process.env.DATABASE_URL = process.env.DATABASE_URL ?? "postgresql://test:test@localhost:5433/thoughtmcp_test"; process.env.DB_HOST = process.env.DB_HOST ?? "localhost"; process.env.DB_PORT = process.env.DB_PORT ?? "5433"; process.env.DB_NAME = process.env.DB_NAME ?? "thoughtmcp_test"; process.env.DB_USER = process.env.DB_USER ?? "test"; process.env.DB_PASSWORD = process.env.DB_PASSWORD ?? "test"; } // Set default test configuration setDefaultTestConfiguration(); console.log("✅ Test environment configured"); console.log(` Database: ${process.env.DB_HOST}:${process.env.DB_PORT}/${process.env.DB_NAME}`); console.log(` Embedding Model: ${process.env.EMBEDDING_MODEL}`); console.log(` Log Level: ${process.env.LOG_LEVEL}`); // Initialize test containers (before migrations) // Requirements: 1.1, 1.2, 1.3, 6.1, 7.4 await initializeContainers(); // Run database migrations await runMigrations(); }

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