Skip to main content
Glama
ooples

MCP Console Automation Server

TestDataLoader.ts7.58 kB
/** * Test Data Loader * * Implements fixture loading from multiple formats (JSON, YAML, CSV) * with caching and optional schema validation. */ import * as fs from 'fs'; import * as path from 'path'; import * as yaml from 'js-yaml'; import { TestFixture, FixtureMetadata } from '../types/test-framework.js'; export interface LoaderOptions { cache?: boolean; validateSchema?: boolean; encoding?: BufferEncoding; } export class TestDataLoader { private cache: Map<string, TestFixture>; private metadata: Map<string, FixtureMetadata>; constructor() { this.cache = new Map(); this.metadata = new Map(); } /** * Load a fixture from file */ async loadFixture( filePath: string, options: LoaderOptions = {} ): Promise<TestFixture> { const opts = { cache: true, validateSchema: false, encoding: 'utf-8' as BufferEncoding, ...options, }; // Check cache first if (opts.cache && this.cache.has(filePath)) { return this.cache.get(filePath)!; } // Resolve absolute path const absolutePath = path.isAbsolute(filePath) ? filePath : path.resolve(process.cwd(), filePath); // Check if file exists if (!fs.existsSync(absolutePath)) { throw new Error(`Fixture file not found: ${absolutePath}`); } // Determine format from extension const ext = path.extname(absolutePath).toLowerCase(); const format = this.getFormatFromExtension(ext); // Load file content const content = await fs.promises.readFile(absolutePath, opts.encoding); // Parse based on format const data = await this.parseContent(content, format); // Create fixture const fixture: TestFixture = { name: path.basename(absolutePath, ext), data, format, path: absolutePath, }; // Validate schema if requested if (opts.validateSchema && fixture.schema) { this.validateSchema(fixture.data, fixture.schema); } // Cache if enabled if (opts.cache) { this.cache.set(filePath, fixture); } return fixture; } /** * Load JSON fixture */ async loadJSON(filePath: string, options?: LoaderOptions): Promise<any> { const fixture = await this.loadFixture(filePath, options); if (fixture.format !== 'json') { throw new Error(`Expected JSON format, got ${fixture.format}`); } return fixture.data; } /** * Load YAML fixture */ async loadYAML(filePath: string, options?: LoaderOptions): Promise<any> { const fixture = await this.loadFixture(filePath, options); if (fixture.format !== 'yaml') { throw new Error(`Expected YAML format, got ${fixture.format}`); } return fixture.data; } /** * Load CSV fixture */ async loadCSV(filePath: string, options?: LoaderOptions): Promise<any[]> { const fixture = await this.loadFixture(filePath, options); if (fixture.format !== 'csv') { throw new Error(`Expected CSV format, got ${fixture.format}`); } return fixture.data; } /** * Load multiple fixtures */ async loadFixtures( filePaths: string[], options?: LoaderOptions ): Promise<TestFixture[]> { return Promise.all( filePaths.map((path) => this.loadFixture(path, options)) ); } /** * Clear cache */ clearCache(): void { this.cache.clear(); } /** * Get cached fixture */ getCached(filePath: string): TestFixture | undefined { return this.cache.get(filePath); } /** * Check if fixture is cached */ isCached(filePath: string): boolean { return this.cache.has(filePath); } /** * Store fixture metadata */ setMetadata(name: string, metadata: FixtureMetadata): void { this.metadata.set(name, metadata); } /** * Get fixture metadata */ getMetadata(name: string): FixtureMetadata | undefined { return this.metadata.get(name); } /** * Parse content based on format */ private async parseContent( content: string, format: TestFixture['format'] ): Promise<any> { switch (format) { case 'json': return JSON.parse(content); case 'yaml': return yaml.load(content); case 'csv': return this.parseCSV(content); case 'sql': // For SQL, just return the raw content // Actual SQL execution would be handled by the test environment return content; default: throw new Error(`Unsupported format: ${format}`); } } /** * Parse CSV content into array of objects */ private parseCSV(content: string): any[] { const lines = content.trim().split('\n'); if (lines.length === 0) { return []; } // First line is headers const headers = this.parseCSVLine(lines[0]); // Parse remaining lines as data const data: any[] = []; for (let i = 1; i < lines.length; i++) { const values = this.parseCSVLine(lines[i]); if (values.length === 0) continue; // Skip empty lines const row: any = {}; headers.forEach((header, index) => { const value = values[index] || ''; // Try to parse as number or boolean row[header] = this.parseValue(value); }); data.push(row); } return data; } /** * Parse a single CSV line (handles quoted values) */ private parseCSVLine(line: string): string[] { const values: string[] = []; let current = ''; let inQuotes = false; for (let i = 0; i < line.length; i++) { const char = line[i]; if (char === '"') { inQuotes = !inQuotes; } else if (char === ',' && !inQuotes) { values.push(current.trim()); current = ''; } else { current += char; } } // Add last value values.push(current.trim()); return values; } /** * Parse value (convert to number or boolean if possible) */ private parseValue(value: string): any { // Try boolean if (value.toLowerCase() === 'true') return true; if (value.toLowerCase() === 'false') return false; // Try number const num = Number(value); if (!isNaN(num) && value !== '') return num; // Return as string return value; } /** * Get format from file extension */ private getFormatFromExtension(ext: string): TestFixture['format'] { const normalized = ext.toLowerCase().replace('.', ''); switch (normalized) { case 'json': return 'json'; case 'yaml': case 'yml': return 'yaml'; case 'csv': return 'csv'; case 'sql': return 'sql'; default: throw new Error(`Unsupported file extension: ${ext}`); } } /** * Validate data against JSON schema */ private validateSchema(data: any, schema: any): void { // Basic validation - in production you'd use a library like ajv if (!schema) return; if (schema.type === 'array' && !Array.isArray(data)) { throw new Error('Schema validation failed: expected array'); } if (schema.type === 'object' && typeof data !== 'object') { throw new Error('Schema validation failed: expected object'); } // Check required fields if (schema.required && Array.isArray(schema.required)) { for (const field of schema.required) { if (!(field in data)) { throw new Error( `Schema validation failed: missing required field "${field}"` ); } } } // Note: For production use, integrate a proper JSON Schema validator like ajv } }

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/ooples/mcp-console-automation'

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