Skip to main content
Glama
test-data-seeder.ts6.01 kB
import { E2EAssertions } from './assertions.js'; import { callUniversalTool, callTasksTool } from './enhanced-tool-caller.js'; import { CompanyFactory, TaskFactory } from '../fixtures/index.js'; import type { McpToolResponse, TestDataObject } from '../types/index.js'; interface CacheMetrics { hits: number; misses: number; creations: number; size: number; } export class TestDataSeeder { private cache = new Map<string, any>(); private metrics: CacheMetrics = { hits: 0, misses: 0, creations: 0, size: 0, }; private readonly maxCacheSize = 100; private readonly suiteId: string; constructor(suiteId: string = 'default') { this.suiteId = suiteId; console.log(`[SEEDER] Created instance for suite: ${suiteId}`); } // Factory method for suite-specific instances static createForSuite(suiteId: string): TestDataSeeder { return new TestDataSeeder(suiteId); } // Static instance for backward compatibility private static defaultInstance: TestDataSeeder | null = null; private static getDefaultInstance(): TestDataSeeder { if (!this.defaultInstance) { this.defaultInstance = new TestDataSeeder('default-legacy'); } return this.defaultInstance; } async ensureCompany( tag: string, targetArray: TestDataObject[] ): Promise<any> { const cacheKey = `${this.suiteId}:company-${tag}`; if (this.cache.has(cacheKey)) { this.metrics.hits++; const cached = this.cache.get(cacheKey); if (!targetArray.includes(cached)) targetArray.push(cached); console.log( `[SEEDER] Cache hit for company ${tag} in suite ${this.suiteId}` ); return cached; } this.metrics.misses++; if (targetArray.length > 0) { console.log(`[SEEDER] Using existing company from array for ${tag}`); return targetArray[0]; } console.log( `[SEEDER] Creating company for tag: ${tag} in suite: ${this.suiteId}` ); const companyData = CompanyFactory.create(); const response = (await callUniversalTool('create-record', { resource_type: 'companies', record_data: companyData as any, })) as McpToolResponse; if (response.isError) { throw new Error(`Failed to create company for ${tag}: ${response.error}`); } const company = E2EAssertions.expectMcpData(response); if (!(company as any)?.id?.record_id) { throw new Error(`Invalid company response for ${tag}`); } this.setCachedItem(cacheKey, company); this.metrics.creations++; targetArray.push(company); console.log( `[SEEDER] Created company ${(company as any).id.record_id} for ${tag} in suite ${this.suiteId}` ); return company; } async ensureTask(tag: string, targetArray: TestDataObject[]): Promise<any> { const cacheKey = `${this.suiteId}:task-${tag}`; if (this.cache.has(cacheKey)) { this.metrics.hits++; const cached = this.cache.get(cacheKey); if (!targetArray.includes(cached)) targetArray.push(cached); console.log( `[SEEDER] Cache hit for task ${tag} in suite ${this.suiteId}` ); return cached; } this.metrics.misses++; if (targetArray.length > 0) { console.log(`[SEEDER] Using existing task from array for ${tag}`); return targetArray[0]; } console.log( `[SEEDER] Creating task for tag: ${tag} in suite: ${this.suiteId}` ); const taskData = TaskFactory.create(); const response = (await callTasksTool('create-record', { resource_type: 'tasks', record_data: { content: taskData.content, format: 'plaintext', deadline_at: taskData.due_date, }, })) as McpToolResponse; if (response.isError) { throw new Error(`Failed to create task for ${tag}: ${response.error}`); } const task = E2EAssertions.expectMcpData(response); if (!(task as any)?.id?.task_id) { throw new Error(`Invalid task response for ${tag}`); } this.setCachedItem(cacheKey, task); this.metrics.creations++; targetArray.push(task); console.log( `[SEEDER] Created task ${(task as any).id.task_id} for ${tag} in suite ${this.suiteId}` ); return task; } private setCachedItem(key: string, value: any): void { // Enforce cache size limit if (this.cache.size >= this.maxCacheSize) { const firstKey = this.cache.keys().next().value; this.cache.delete(firstKey); console.log( `[SEEDER] Cache evicted oldest entry to maintain size limit (${this.maxCacheSize})` ); } this.cache.set(key, value); this.metrics.size = this.cache.size; } clearCache(): void { const sizeBefore = this.cache.size; this.cache.clear(); this.metrics.size = 0; console.log( `[SEEDER] Cleared cache for suite ${this.suiteId} (removed ${sizeBefore} entries)` ); } getMetrics(): CacheMetrics { return { ...this.metrics, size: this.cache.size }; } logMetrics(): void { const metrics = this.getMetrics(); const hitRate = metrics.hits + metrics.misses > 0 ? ((metrics.hits / (metrics.hits + metrics.misses)) * 100).toFixed(1) : '0'; console.log( `[SEEDER] Cache metrics for ${this.suiteId}: ${JSON.stringify({ ...metrics, hitRate: `${hitRate}%`, })}` ); } // Static methods for backward compatibility static async ensureCompany( tag: string, targetArray: TestDataObject[] ): Promise<any> { return this.getDefaultInstance().ensureCompany(tag, targetArray); } static async ensureTask( tag: string, targetArray: TestDataObject[] ): Promise<any> { return this.getDefaultInstance().ensureTask(tag, targetArray); } static clearCache(): void { this.getDefaultInstance().clearCache(); } static getMetrics(): CacheMetrics { return this.getDefaultInstance().getMetrics(); } static logMetrics(): void { this.getDefaultInstance().logMetrics(); } }

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/kesslerio/attio-mcp-server'

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