Skip to main content
Glama
session-manager.test.ts5.08 kB
/** * Session Management Production Tests * THE IMPLEMENTOR'S RULE: Session management isn't glamorous, but it keeps the lights on * * Target: Cover session.ts (0% → 85%) * Focus: Lifecycle, cleanup, timeout handling */ import { describe, test, expect, beforeEach, afterEach, vi } from 'vitest'; import { SessionManager } from '../../../src/http/session'; // Mock the StreamableHTTPServerTransport const mockTransport = { close: vi.fn(), handleRequest: vi.fn() }; vi.mock('@modelcontextprotocol/sdk/server/streamableHttp.js', () => ({ StreamableHTTPServerTransport: vi.fn().mockImplementation(() => mockTransport) })); describe('SessionManager - Production Coverage', () => { let sessionManager: SessionManager; beforeEach(() => { sessionManager = new SessionManager(); vi.clearAllMocks(); vi.useFakeTimers(); }); afterEach(() => { vi.useRealTimers(); }); describe('Session Creation', () => { test('should create session with UUID', () => { const sessionId = sessionManager.createSession(mockTransport as any); expect(sessionId).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i); }); test('should store session transport', () => { const sessionId = sessionManager.createSession(mockTransport as any); const retrievedTransport = sessionManager.getSession(sessionId); expect(retrievedTransport).toBe(mockTransport); }); test('should increment active session count', () => { expect(sessionManager.getActiveSessionCount()).toBe(0); sessionManager.createSession(mockTransport as any); expect(sessionManager.getActiveSessionCount()).toBe(1); sessionManager.createSession(mockTransport as any); expect(sessionManager.getActiveSessionCount()).toBe(2); }); }); describe('Session Retrieval', () => { test('should return null for non-existent session', () => { const transport = sessionManager.getSession('non-existent-session'); expect(transport).toBeNull(); }); test('should update lastAccessed when retrieving session', () => { const sessionId = sessionManager.createSession(mockTransport as any); // Advance time vi.advanceTimersByTime(5000); const transport = sessionManager.getSession(sessionId); expect(transport).toBe(mockTransport); // Session should still be accessible after timeout advance vi.advanceTimersByTime(25 * 60 * 1000); // 25 minutes (less than 30 min timeout) const transportAfter = sessionManager.getSession(sessionId); expect(transportAfter).toBe(mockTransport); }); }); describe('Session Termination', () => { test('should terminate existing session successfully', () => { const sessionId = sessionManager.createSession(mockTransport as any); const result = sessionManager.terminateSession(sessionId); expect(result).toBe(true); expect(mockTransport.close).toHaveBeenCalled(); expect(sessionManager.getActiveSessionCount()).toBe(0); }); test('should return false for non-existent session termination', () => { const result = sessionManager.terminateSession('non-existent-session'); expect(result).toBe(false); expect(mockTransport.close).not.toHaveBeenCalled(); }); test('should handle transport cleanup errors gracefully', () => { const faultyTransport = { close: vi.fn().mockImplementation(() => { throw new Error('Transport cleanup failed'); }), handleRequest: vi.fn() }; const sessionId = sessionManager.createSession(faultyTransport as any); // Should not throw despite transport cleanup error expect(() => sessionManager.terminateSession(sessionId)).not.toThrow(); expect(sessionManager.getActiveSessionCount()).toBe(0); }); }); describe('Automatic Session Cleanup', () => { test('should auto-cleanup sessions after timeout', () => { const sessionId = sessionManager.createSession(mockTransport as any); expect(sessionManager.getActiveSessionCount()).toBe(1); // Advance time beyond 30-minute timeout vi.advanceTimersByTime(31 * 60 * 1000); expect(sessionManager.getActiveSessionCount()).toBe(0); expect(sessionManager.getSession(sessionId)).toBeNull(); }); test('should not cleanup recently accessed sessions', () => { const sessionId = sessionManager.createSession(mockTransport as any); // Access session multiple times within timeout window vi.advanceTimersByTime(15 * 60 * 1000); // 15 minutes sessionManager.getSession(sessionId); vi.advanceTimersByTime(15 * 60 * 1000); // Another 15 minutes (30 total) sessionManager.getSession(sessionId); vi.advanceTimersByTime(20 * 60 * 1000); // 20 more minutes (50 total, but last access was 20 min ago) expect(sessionManager.getActiveSessionCount()).toBe(1); // Still active }); }); });

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/sylweriusz/mcp-neo4j-memory-server'

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