Skip to main content
Glama

Cut-Copy-Paste Clipboard Server

session-manager.test.ts•6.92 kB
import { SessionManager } from '../session-manager.js'; import { DatabaseManager } from '../database.js'; import { existsSync, rmSync } from 'fs'; import { join } from 'path'; import { tmpdir } from 'os'; describe('SessionManager', () => { let dbPath: string; let dbManager: DatabaseManager; let sessionManager: SessionManager; beforeEach(() => { const uniqueId = `${Date.now()}-${process.pid}-${Math.random().toString(36).slice(2, 9)}`; dbPath = join(tmpdir(), `test-clipboard-${uniqueId}.db`); dbManager = new DatabaseManager(dbPath); sessionManager = new SessionManager(dbManager); }); afterEach(() => { if (dbManager) { dbManager.close(); const keyPath = dbManager.getEncryptionKeyPath(); if (keyPath && existsSync(keyPath)) { rmSync(keyPath); } } if (existsSync(dbPath)) { rmSync(dbPath); } }); describe('Session Creation - RED', () => { it('should create session with unique ID', () => { const sessionId = sessionManager.createSession(); expect(sessionId).toBeDefined(); expect(typeof sessionId).toBe('string'); expect(sessionId.length).toBeGreaterThan(0); }); it('should store session in database', () => { const sessionId = sessionManager.createSession(); const db = dbManager.getConnection(); const session = db.prepare('SELECT * FROM sessions WHERE session_id = ?').get(sessionId) as | { session_id: string; created_at: number; last_activity: number } | undefined; expect(session).toBeDefined(); expect(session?.session_id).toBe(sessionId); }); it('should track creation timestamp', () => { const beforeCreate = Date.now(); const sessionId = sessionManager.createSession(); const afterCreate = Date.now(); const db = dbManager.getConnection(); const session = db.prepare('SELECT * FROM sessions WHERE session_id = ?').get(sessionId) as | { created_at: number } | undefined; expect(session?.created_at).toBeGreaterThanOrEqual(beforeCreate); expect(session?.created_at).toBeLessThanOrEqual(afterCreate); }); it('should generate cryptographically secure session IDs', () => { const ids = new Set<string>(); for (let i = 0; i < 100; i++) { ids.add(sessionManager.createSession()); } // All 100 IDs should be unique expect(ids.size).toBe(100); }); }); describe('Session Retrieval - RED', () => { it('should retrieve existing session', () => { const sessionId = sessionManager.createSession(); const session = sessionManager.getSession(sessionId); expect(session).toBeDefined(); expect(session?.sessionId).toBe(sessionId); }); it('should return null for non-existent session', () => { const session = sessionManager.getSession('non-existent-id'); expect(session).toBeNull(); }); it('should update last_activity timestamp on retrieval', () => { const sessionId = sessionManager.createSession(); // Wait a bit to ensure timestamp difference const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); return wait(10).then(() => { const beforeGet = Date.now(); sessionManager.getSession(sessionId); const afterGet = Date.now(); const db = dbManager.getConnection(); const session = db.prepare('SELECT * FROM sessions WHERE session_id = ?').get(sessionId) as | { last_activity: number } | undefined; expect(session?.last_activity).toBeGreaterThanOrEqual(beforeGet); expect(session?.last_activity).toBeLessThanOrEqual(afterGet); }); }); }); describe('Session Cleanup - RED', () => { it('should remove sessions older than timeout', () => { const sessionId = sessionManager.createSession(); // Manually set old timestamp const db = dbManager.getConnection(); const oneDayAgo = Date.now() - 25 * 60 * 60 * 1000; // 25 hours ago db.prepare('UPDATE sessions SET last_activity = ? WHERE session_id = ?').run( oneDayAgo, sessionId ); const removed = sessionManager.cleanupExpiredSessions(); expect(removed).toBeGreaterThan(0); const session = db.prepare('SELECT * FROM sessions WHERE session_id = ?').get(sessionId); expect(session).toBeUndefined(); }); it('should preserve active sessions', () => { const sessionId = sessionManager.createSession(); sessionManager.cleanupExpiredSessions(); const db = dbManager.getConnection(); const session = db.prepare('SELECT * FROM sessions WHERE session_id = ?').get(sessionId); expect(session).toBeDefined(); }); it('should cascade delete related data', () => { const sessionId = sessionManager.createSession(); const db = dbManager.getConnection(); // Add some related data db.prepare( `INSERT INTO clipboard_buffer (session_id, content, source_file, start_line, end_line, copied_at, operation_type) VALUES (?, ?, ?, ?, ?, ?, ?)` ).run(sessionId, 'test content', 'test.ts', 1, 5, Date.now(), 'copy'); // Set old timestamp const oneDayAgo = Date.now() - 25 * 60 * 60 * 1000; db.prepare('UPDATE sessions SET last_activity = ? WHERE session_id = ?').run( oneDayAgo, sessionId ); sessionManager.cleanupExpiredSessions(); // Check cascade delete const clipboard = db .prepare('SELECT * FROM clipboard_buffer WHERE session_id = ?') .get(sessionId); expect(clipboard).toBeUndefined(); }); it('should return count of removed sessions', () => { // Create multiple expired sessions const db = dbManager.getConnection(); const oneDayAgo = Date.now() - 25 * 60 * 60 * 1000; for (let i = 0; i < 3; i++) { const sessionId = sessionManager.createSession(); db.prepare('UPDATE sessions SET last_activity = ? WHERE session_id = ?').run( oneDayAgo, sessionId ); } const removed = sessionManager.cleanupExpiredSessions(); expect(removed).toBe(3); }); }); describe('Custom timeout - RED', () => { it('should use custom timeout when provided', () => { const customTimeout = 1000; // 1 second const customSessionManager = new SessionManager(dbManager, customTimeout); const sessionId = customSessionManager.createSession(); // Set timestamp to 2 seconds ago const db = dbManager.getConnection(); const twoSecondsAgo = Date.now() - 2000; db.prepare('UPDATE sessions SET last_activity = ? WHERE session_id = ?').run( twoSecondsAgo, sessionId ); const removed = customSessionManager.cleanupExpiredSessions(); expect(removed).toBe(1); }); }); });

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/Pr0j3c7t0dd-Ltd/cut-copy-paste-mcp'

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