Skip to main content
Glama
e2e-cleanup.ts6.81 kB
/** * E2E Test Cleanup Utilities * * Provides utilities for cleaning up test data in E2E tests. * Each test should clean up its own data to ensure isolation. * * Requirements: 13.3 * - Each test should clean up its own data in afterEach * - Use unique user IDs and session IDs per test * - Verify database is in clean state after test suite */ import type { PoolClient } from "pg"; /** * Test context for tracking test-specific data that needs cleanup. */ export interface E2ETestContext { userId: string; sessionId: string; memoryIds: string[]; testStartTime: Date; } /** * Creates a new E2E test context with unique identifiers. * Uses a counter-based approach for deterministic, unique IDs. * * @param testName - Name of the test for identification * @returns E2E test context with unique identifiers */ let testCounter = 0; export function createE2ETestContext(testName: string): E2ETestContext { testCounter++; const timestamp = Date.now(); const sanitizedName = testName.replace(/[^a-zA-Z0-9]/g, "-").substring(0, 20); return { userId: `e2e-user-${testCounter}-${timestamp}`, sessionId: `e2e-session-${testCounter}-${timestamp}-${sanitizedName}`, memoryIds: [], testStartTime: new Date(), }; } /** * Resets the test counter. Call this in global setup if needed. */ export function resetTestCounter(): void { testCounter = 0; } /** * Tracks a memory ID for cleanup. * * @param context - E2E test context * @param memoryId - Memory ID to track */ export function trackMemoryId(context: E2ETestContext, memoryId: string): void { context.memoryIds.push(memoryId); } /** * Cleans up all test data for a specific user. * This is the primary cleanup method - removes all data associated with a user ID. * * @param client - Database client * @param userId - User ID to clean up * @returns Promise resolving when cleanup is complete */ export async function cleanupUserData(client: PoolClient, userId: string): Promise<void> { // Delete in order respecting foreign key constraints // 1. Delete memory_links (references memories) await client.query( "DELETE FROM memory_links WHERE source_id IN (SELECT id FROM memories WHERE user_id = $1)", [userId] ); // 2. Delete memory_connections (references memories) await client.query( "DELETE FROM memory_connections WHERE source_id IN (SELECT id FROM memories WHERE user_id = $1)", [userId] ); // 3. Delete memory_metadata (references memories) await client.query( "DELETE FROM memory_metadata WHERE memory_id IN (SELECT id FROM memories WHERE user_id = $1)", [userId] ); // 4. Delete memory_embeddings (references memories) await client.query( "DELETE FROM memory_embeddings WHERE memory_id IN (SELECT id FROM memories WHERE user_id = $1)", [userId] ); // 5. Delete memories await client.query("DELETE FROM memories WHERE user_id = $1", [userId]); } /** * Cleans up specific memories by ID. * Use this when you need to clean up specific memories rather than all user data. * * @param client - Database client * @param memoryIds - Array of memory IDs to clean up * @returns Promise resolving when cleanup is complete */ export async function cleanupMemories(client: PoolClient, memoryIds: string[]): Promise<void> { if (memoryIds.length === 0) return; // Delete in order respecting foreign key constraints // 1. Delete memory_links await client.query("DELETE FROM memory_links WHERE source_id = ANY($1) OR target_id = ANY($1)", [ memoryIds, ]); // 2. Delete memory_connections await client.query( "DELETE FROM memory_connections WHERE source_id = ANY($1) OR target_id = ANY($1)", [memoryIds] ); // 3. Delete memory_metadata await client.query("DELETE FROM memory_metadata WHERE memory_id = ANY($1)", [memoryIds]); // 4. Delete memory_embeddings await client.query("DELETE FROM memory_embeddings WHERE memory_id = ANY($1)", [memoryIds]); // 5. Delete memories await client.query("DELETE FROM memories WHERE id = ANY($1)", [memoryIds]); } /** * Cleans up all E2E test data (data created by E2E tests). * This identifies E2E test data by the user ID pattern. * * @param client - Database client * @returns Promise resolving when cleanup is complete */ export async function cleanupAllE2ETestData(client: PoolClient): Promise<void> { // Find all E2E test user IDs const result = await client.query( "SELECT DISTINCT user_id FROM memories WHERE user_id LIKE 'e2e-user-%' OR user_id LIKE 'test-user-%'" ); for (const row of result.rows) { await cleanupUserData(client, row.user_id); } } /** * Verifies the database is in a clean state (no E2E test data remains). * * @param client - Database client * @returns Promise resolving to verification result */ export async function verifyCleanState(client: PoolClient): Promise<{ isClean: boolean; remainingTestUsers: string[]; remainingMemoryCount: number; }> { // Check for remaining E2E test data const userResult = await client.query( "SELECT DISTINCT user_id FROM memories WHERE user_id LIKE 'e2e-user-%' OR user_id LIKE 'test-user-%'" ); const countResult = await client.query( "SELECT COUNT(*) as count FROM memories WHERE user_id LIKE 'e2e-user-%' OR user_id LIKE 'test-user-%'" ); const remainingTestUsers = userResult.rows.map((row) => row.user_id); const remainingMemoryCount = parseInt(countResult.rows[0].count, 10); return { isClean: remainingTestUsers.length === 0, remainingTestUsers, remainingMemoryCount, }; } /** * Gets database statistics for debugging. * * @param client - Database client * @returns Promise resolving to database statistics */ export async function getDatabaseStats(client: PoolClient): Promise<{ totalMemories: number; totalEmbeddings: number; totalConnections: number; totalLinks: number; testMemories: number; }> { const [memoriesResult, embeddingsResult, connectionsResult, linksResult, testMemoriesResult] = await Promise.all([ client.query("SELECT COUNT(*) as count FROM memories"), client.query("SELECT COUNT(*) as count FROM memory_embeddings"), client.query("SELECT COUNT(*) as count FROM memory_connections"), client.query("SELECT COUNT(*) as count FROM memory_links"), client.query( "SELECT COUNT(*) as count FROM memories WHERE user_id LIKE 'e2e-user-%' OR user_id LIKE 'test-user-%'" ), ]); return { totalMemories: parseInt(memoriesResult.rows[0].count, 10), totalEmbeddings: parseInt(embeddingsResult.rows[0].count, 10), totalConnections: parseInt(connectionsResult.rows[0].count, 10), totalLinks: parseInt(linksResult.rows[0].count, 10), testMemories: parseInt(testMemoriesResult.rows[0].count, 10), }; }

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