Skip to main content
Glama

Context Pods

by conorluddy
helpers.tsโ€ข5.17 kB
/** * Test helper utilities for Context-Pods tests */ import { spawn } from 'node:child_process'; import { mkdir, writeFile } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { randomBytes } from 'node:crypto'; import type { ChildProcess } from 'node:child_process'; interface TestServerOptions { port?: number; args?: string[]; env?: Record<string, string>; } interface TestServerResult { process: ChildProcess; port: number; stop: () => Promise<void>; } interface WaitForOptions { timeout?: number; interval?: number; } interface CapturedConsole { log: string[]; error: string[]; warn: string[]; } interface ConsoleCapture { captured: CapturedConsole; restore: () => void; } /** * Create a temporary directory for tests */ export const createTempDir = async (prefix = 'context-pods-test'): Promise<string> => { const random = randomBytes(8).toString('hex'); const dir = join(tmpdir(), `${prefix}-${random}`); await mkdir(dir, { recursive: true }); return dir; }; /** * Start a test MCP server */ export const startTestServer = async ( serverPath: string, options: TestServerOptions = {}, ): Promise<TestServerResult> => { const { port = 0, args = [], env = {} } = options; const serverProcess = spawn('node', [serverPath, ...args], { env: { ...process.env, ...env, MCP_SERVER_PORT: port.toString(), }, stdio: ['pipe', 'pipe', 'pipe'], }); // Wait for server to be ready await new Promise<void>((resolve, reject) => { const timeout = setTimeout(() => { serverProcess.kill(); reject(new Error('Server startup timeout')); }, 10000); const dataHandler = (data: Buffer): void => { if (data.toString().includes('Server started')) { clearTimeout(timeout); resolve(); } }; serverProcess.stdout?.on('data', dataHandler); serverProcess.on('error', (error) => { clearTimeout(timeout); reject(error); }); }); const stop = async (): Promise<void> => { serverProcess.kill(); await new Promise<void>((resolve) => { serverProcess.on('exit', () => resolve()); }); }; return { process: serverProcess, port, stop, }; }; /** * Wait for a condition to be true */ export const waitFor = async ( condition: () => boolean | Promise<boolean>, options: WaitForOptions = {}, ): Promise<void> => { const { timeout = 5000, interval = 100 } = options; const startTime = Date.now(); while (Date.now() - startTime < timeout) { if (await condition()) { return; } await new Promise((resolve) => setTimeout(resolve, interval)); } throw new Error(`Timeout waiting for condition after ${timeout}ms`); }; /** * Create a mock template directory structure */ export const createMockTemplate = async ( baseDir: string, templateName: string, files: Record<string, string>, ): Promise<string> => { const templateDir = join(baseDir, templateName); await mkdir(templateDir, { recursive: true }); // Write template files for (const [path, content] of Object.entries(files)) { const filePath = join(templateDir, path); const fileDir = join(filePath, '..'); await mkdir(fileDir, { recursive: true }); await writeFile(filePath, content, 'utf-8'); } return templateDir; }; /** * Capture console output during a test */ export const captureConsole = (): ConsoleCapture => { // Store original console methods with proper binding const originalLog = (...args: unknown[]): void => { // eslint-disable-next-line no-console console.log(...args); }; const originalError = (...args: unknown[]): void => { // eslint-disable-next-line no-console console.error(...args); }; const originalWarn = (...args: unknown[]): void => { // eslint-disable-next-line no-console console.warn(...args); }; const captured: CapturedConsole = { log: [], error: [], warn: [], }; // Override console methods globalThis.console.log = (...args: unknown[]): void => { captured.log.push(args.map(String).join(' ')); }; globalThis.console.error = (...args: unknown[]): void => { captured.error.push(args.map(String).join(' ')); }; globalThis.console.warn = (...args: unknown[]): void => { captured.warn.push(args.map(String).join(' ')); }; const restore = (): void => { globalThis.console.log = originalLog; globalThis.console.error = originalError; globalThis.console.warn = originalWarn; }; return { captured, restore, }; }; /** * Create a test timeout with proper cleanup */ export const withTimeout = async <T>( promise: Promise<T>, timeoutMs: number, message = 'Operation timed out', ): Promise<T> => { let timeoutId: NodeJS.Timeout; const timeoutPromise = new Promise<never>((_, reject) => { timeoutId = setTimeout(() => reject(new Error(message)), timeoutMs); }); try { const result = await Promise.race([promise, timeoutPromise]); clearTimeout(timeoutId!); return result; } catch (error) { clearTimeout(timeoutId!); throw error; } };

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/conorluddy/ContextPods'

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