Skip to main content
Glama
ooples

MCP Console Automation Server

SnapshotManager.test.ts10.8 kB
/** * SnapshotManager Test Suite * Tests snapshot capture, storage, and management */ import { SnapshotManager } from '../testing/SnapshotManager.js'; import { SessionSnapshot } from '../types/test-framework.js'; import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; describe('SnapshotManager', () => { let manager: SnapshotManager; let testDir: string; beforeEach(() => { // Create temporary test directory testDir = path.join(os.tmpdir(), `snapshot-test-${Date.now()}`); fs.mkdirSync(testDir, { recursive: true }); manager = new SnapshotManager(testDir); }); afterEach(() => { // Clean up test directory if (fs.existsSync(testDir)) { fs.rmSync(testDir, { recursive: true, force: true }); } }); describe('capture', () => { it('should capture snapshot with all data', async () => { const snapshot = await manager.capture( 'test-session', 'test output', { status: 'success' }, { author: 'test' } ); expect(snapshot.sessionId).toBe('test-session'); expect(snapshot.output).toBe('test output'); expect(snapshot.state).toEqual({ status: 'success' }); expect(snapshot.metadata.author).toBe('test'); expect(snapshot.timestamp).toBeGreaterThan(0); expect(snapshot.hash).toBeDefined(); }); it('should generate hash for integrity', async () => { const snapshot = await manager.capture('test-session', 'output', {}, {}); expect(snapshot.hash).toMatch(/^[a-f0-9]{64}$/); }); }); describe('save and load', () => { it('should save snapshot to disk', async () => { const snapshot = await manager.capture('test-session', 'output', {}, {}); const filepath = await manager.save(snapshot); expect(fs.existsSync(filepath)).toBe(true); expect(filepath).toContain('test-session'); }); it('should load snapshot from disk', async () => { const original = await manager.capture( 'test-session', 'test output', { value: 123 }, {} ); const filepath = await manager.save(original); const loaded = await manager.load(filepath); expect(loaded.sessionId).toBe(original.sessionId); expect(loaded.output).toBe(original.output); expect(loaded.state).toEqual(original.state); expect(loaded.hash).toBe(original.hash); }); it('should verify hash on load', async () => { const snapshot = await manager.capture('test-session', 'output', {}, {}); const filepath = await manager.save(snapshot); // Corrupt the file const content = JSON.parse(fs.readFileSync(filepath, 'utf8')); content.output = 'corrupted'; fs.writeFileSync(filepath, JSON.stringify(content)); await expect(manager.load(filepath)).rejects.toThrow('hash mismatch'); }); it('should save with pretty formatting', async () => { const snapshot = await manager.capture('test-session', 'output', {}, {}); const filepath = await manager.save(snapshot, { pretty: true }); const content = fs.readFileSync(filepath, 'utf8'); expect(content).toContain('\n'); expect(content).toContain(' '); }); it('should save without pretty formatting', async () => { const snapshot = await manager.capture('test-session', 'output', {}, {}); const filepath = await manager.save(snapshot, { pretty: false }); const content = fs.readFileSync(filepath, 'utf8'); expect(content).not.toContain('\n '); }); }); describe('loadBySessionId', () => { it('should load most recent snapshot by session ID', async () => { const snap1 = await manager.capture('test-session', 'output 1', {}, {}); await manager.save(snap1); // Wait a bit to ensure different timestamp await new Promise((resolve) => setTimeout(resolve, 10)); const snap2 = await manager.capture('test-session', 'output 2', {}, {}); await manager.save(snap2); const loaded = await manager.loadBySessionId('test-session'); expect(loaded.output).toBe('output 2'); }); it('should load snapshot by session ID and timestamp', async () => { const snap1 = await manager.capture('test-session', 'output 1', {}, {}); await manager.save(snap1); const snap2 = await manager.capture('test-session', 'output 2', {}, {}); await manager.save(snap2); const loaded = await manager.loadBySessionId( 'test-session', snap1.timestamp ); expect(loaded.output).toBe('output 1'); }); it('should throw if session not found', async () => { await expect(manager.loadBySessionId('nonexistent')).rejects.toThrow( 'No snapshots found' ); }); }); describe('listSnapshots', () => { it('should list all snapshots', async () => { const snap1 = await manager.capture('session1', 'output', {}, {}); const snap2 = await manager.capture('session2', 'output', {}, {}); await manager.save(snap1); await manager.save(snap2); const snapshots = await manager.listSnapshots(); expect(snapshots.length).toBe(2); }); it('should filter by session ID', async () => { const snap1 = await manager.capture('session1', 'output', {}, {}); const snap2 = await manager.capture('session2', 'output', {}, {}); const snap3 = await manager.capture('session1', 'output2', {}, {}); await manager.save(snap1); await manager.save(snap2); await manager.save(snap3); const snapshots = await manager.listSnapshots('session1'); expect(snapshots.length).toBe(2); }); it('should return empty array when no snapshots exist', async () => { const snapshots = await manager.listSnapshots(); expect(snapshots).toEqual([]); }); }); describe('delete operations', () => { it('should delete a snapshot', async () => { const snapshot = await manager.capture('test-session', 'output', {}, {}); const filepath = await manager.save(snapshot); await manager.delete(filepath); expect(fs.existsSync(filepath)).toBe(false); }); it('should delete all snapshots for a session', async () => { const snap1 = await manager.capture('session1', 'output1', {}, {}); const snap2 = await manager.capture('session1', 'output2', {}, {}); const snap3 = await manager.capture('session2', 'output3', {}, {}); await manager.save(snap1); await manager.save(snap2); await manager.save(snap3); const count = await manager.deleteBySessionId('session1'); expect(count).toBe(2); const remaining = await manager.listSnapshots(); expect(remaining.length).toBe(1); }); it('should delete all snapshots', async () => { const snap1 = await manager.capture('session1', 'output', {}, {}); const snap2 = await manager.capture('session2', 'output', {}, {}); await manager.save(snap1); await manager.save(snap2); const count = await manager.deleteAll(); expect(count).toBe(2); const remaining = await manager.listSnapshots(); expect(remaining).toEqual([]); }); }); describe('getStats', () => { it('should return statistics', async () => { const snap1 = await manager.capture('session1', 'output', {}, {}); const snap2 = await manager.capture('session2', 'output', {}, {}); await manager.save(snap1); await manager.save(snap2); const stats = await manager.getStats(); expect(stats.totalSnapshots).toBe(2); expect(stats.sessions).toBe(2); expect(stats.totalSize).toBeGreaterThan(0); expect(stats.oldestTimestamp).toBeDefined(); expect(stats.newestTimestamp).toBeDefined(); }); it('should return zero stats when no snapshots', async () => { const stats = await manager.getStats(); expect(stats.totalSnapshots).toBe(0); expect(stats.totalSize).toBe(0); expect(stats.sessions).toBe(0); }); }); describe('cleanup', () => { it('should keep only N most recent snapshots per session', async () => { // Create 5 snapshots for same session for (let i = 0; i < 5; i++) { const snap = await manager.capture('session1', `output ${i}`, {}, {}); await manager.save(snap); await new Promise((resolve) => setTimeout(resolve, 10)); } const deleted = await manager.cleanup(3); expect(deleted).toBe(2); const remaining = await manager.listSnapshots('session1'); expect(remaining.length).toBe(3); }); it('should handle multiple sessions independently', async () => { // Create snapshots for two sessions for (let i = 0; i < 3; i++) { const snap1 = await manager.capture('session1', `output ${i}`, {}, {}); const snap2 = await manager.capture('session2', `output ${i}`, {}, {}); await manager.save(snap1); await manager.save(snap2); await new Promise((resolve) => setTimeout(resolve, 10)); } await manager.cleanup(2); const s1 = await manager.listSnapshots('session1'); const s2 = await manager.listSnapshots('session2'); expect(s1.length).toBe(2); expect(s2.length).toBe(2); }); }); describe('export', () => { it('should export as JSON', async () => { const snapshot = await manager.capture( 'test-session', 'output', { value: 123 }, {} ); const exported = await manager.export(snapshot, 'json'); expect(exported).toContain('"sessionId"'); expect(exported).toContain('"output"'); const parsed = JSON.parse(exported); expect(parsed.sessionId).toBe('test-session'); }); it('should export as YAML', async () => { const snapshot = await manager.capture( 'test-session', 'output', { value: 123 }, {} ); const exported = await manager.export(snapshot, 'yaml'); expect(exported).toContain('sessionId: test-session'); expect(exported).toContain('output: |'); }); it('should export as text', async () => { const snapshot = await manager.capture( 'test-session', 'output', { value: 123 }, {} ); const exported = await manager.export(snapshot, 'text'); expect(exported).toContain('=== Session Snapshot ==='); expect(exported).toContain('Session ID: test-session'); expect(exported).toContain('--- Output ---'); }); it('should throw for unsupported format', async () => { const snapshot = await manager.capture('test-session', 'output', {}, {}); await expect(manager.export(snapshot, 'xml' as any)).rejects.toThrow( 'Unsupported' ); }); }); });

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