Skip to main content
Glama
2389-research

MCP Agent Social Media Server

session-lifecycle.test.ts9.55 kB
// ABOUTME: Integration tests for session lifecycle management // ABOUTME: Tests session creation, validation, cleanup, and edge cases import { afterEach, beforeEach, describe, expect, it, jest } from '@jest/globals'; import type { ApiClient } from '../../src/api-client.js'; import { logger } from '../../src/logger.js'; import { metrics } from '../../src/metrics.js'; import { SessionManager } from '../../src/session-manager.js'; import { createPostToolHandler } from '../../src/tools/create-post.js'; import { loginToolHandler } from '../../src/tools/login.js'; describe('Session Lifecycle Integration Tests', () => { let sessionManager: SessionManager; let apiClient: jest.Mocked<ApiClient>; beforeEach(() => { process.env.TEAM_NAME = 'test-team'; sessionManager = new SessionManager(); apiClient = { fetchPosts: jest.fn(), createPost: jest.fn(), } as jest.Mocked<ApiClient>; // Set up default mock responses apiClient.fetchPosts.mockResolvedValue({ posts: [], total: 0, has_more: false, }); apiClient.createPost.mockImplementation(async (teamName, postData) => ({ post: { id: `post-${Date.now()}`, team_name: teamName, author_name: postData.author_name, content: postData.content, tags: postData.tags || [], timestamp: new Date().toISOString(), parent_post_id: postData.parent_post_id, deleted: false, }, })); metrics.reset(); }); afterEach(async () => { await sessionManager.clearAllSessions(); }); describe('Session Creation and Validation', () => { it('should handle session lifecycle correctly', async () => { const sessionId = 'lifecycle-test-session'; const loginContext = { sessionManager, getSessionId: () => sessionId, }; // Initial state - no session expect(sessionManager.hasValidSession(sessionId)).toBe(false); expect(sessionManager.getSessionCount()).toBe(0); // Login creates session const loginResult = await loginToolHandler({ agent_name: 'lifecycle-agent' }, loginContext); const loginResponse = JSON.parse(loginResult.content[0].text); expect(loginResponse.success).toBe(true); expect(sessionManager.hasValidSession(sessionId)).toBe(true); expect(sessionManager.getSessionCount()).toBe(1); // Session enables authenticated operations const createContext = { sessionManager, apiClient, getSessionId: () => sessionId, }; const createResult = await createPostToolHandler( { content: 'Authenticated post' }, createContext, ); const createResponse = JSON.parse(createResult.content[0].text); expect(createResponse.success).toBe(true); // Session deletion await sessionManager.deleteSession(sessionId); expect(sessionManager.hasValidSession(sessionId)).toBe(false); expect(sessionManager.getSessionCount()).toBe(0); // Operations fail after session deletion const postDeleteResult = await createPostToolHandler( { content: 'Should fail' }, createContext, ); const postDeleteResponse = JSON.parse(postDeleteResult.content[0].text); expect(postDeleteResponse.success).toBe(false); expect(postDeleteResponse.error).toBe('Authentication required'); }); it('should handle re-login scenarios', async () => { const sessionId = 'relogin-test'; const loginContext = { sessionManager, getSessionId: () => sessionId, }; // First login await loginToolHandler({ agent_name: 'agent-one' }, loginContext); let session = sessionManager.getSession(sessionId); expect(session?.agentName).toBe('agent-one'); // Re-login with different agent const reloginResult = await loginToolHandler({ agent_name: 'agent-two' }, loginContext); const reloginResponse = JSON.parse(reloginResult.content[0].text); expect(reloginResponse.success).toBe(true); expect(reloginResponse.agent_name).toBe('agent-two'); // Session should be updated session = sessionManager.getSession(sessionId); expect(session?.agentName).toBe('agent-two'); expect(sessionManager.getSessionCount()).toBe(1); // Still only one session }); it('should handle concurrent sessions', async () => { const sessions = ['session-1', 'session-2', 'session-3']; const agents = ['agent-1', 'agent-2', 'agent-3']; // Create multiple sessions for (let i = 0; i < sessions.length; i++) { const loginContext = { sessionManager, getSessionId: () => sessions[i], }; await loginToolHandler({ agent_name: agents[i] }, loginContext); } expect(sessionManager.getSessionCount()).toBe(3); // Each session should work independently for (let i = 0; i < sessions.length; i++) { const createContext = { sessionManager, apiClient, getSessionId: () => sessions[i], }; const result = await createPostToolHandler( { content: `Post from ${agents[i]}` }, createContext, ); const response = JSON.parse(result.content[0].text); expect(response.success).toBe(true); expect(response.post.author_name).toBe(agents[i]); } }); it('should clean up old sessions', async () => { // Create sessions with different ages const oldSessionId = 'old-session'; const newSessionId = 'new-session'; // Create old session and manually age it await sessionManager.createSession(oldSessionId, 'old-agent'); const oldSession = sessionManager.getSession(oldSessionId); if (oldSession) { // Set timestamp to 2 hours ago oldSession.loginTimestamp = new Date(Date.now() - 2 * 60 * 60 * 1000); } // Create new session await sessionManager.createSession(newSessionId, 'new-agent'); expect(sessionManager.getSessionCount()).toBe(2); // Clean up sessions older than 1 hour const removed = await sessionManager.cleanupOldSessions(60 * 60 * 1000); expect(removed).toBe(1); expect(sessionManager.getSessionCount()).toBe(1); expect(sessionManager.hasValidSession(oldSessionId)).toBe(false); expect(sessionManager.hasValidSession(newSessionId)).toBe(true); logger.info('Session cleanup completed', { removed, remaining: 1 }); }); }); describe('Session Security', () => { it('should isolate sessions from each other', async () => { const aliceSessionId = 'alice-session'; const bobSessionId = 'bob-session'; // Alice logs in const aliceLoginContext = { sessionManager, getSessionId: () => aliceSessionId, }; await loginToolHandler({ agent_name: 'alice' }, aliceLoginContext); // Bob logs in const bobLoginContext = { sessionManager, getSessionId: () => bobSessionId, }; await loginToolHandler({ agent_name: 'bob' }, bobLoginContext); // Alice creates a post const aliceCreateContext = { sessionManager, apiClient, getSessionId: () => aliceSessionId, }; const alicePost = await createPostToolHandler( { content: 'Alice private post' }, aliceCreateContext, ); const aliceResponse = JSON.parse(alicePost.content[0].text); expect(aliceResponse.post.author_name).toBe('alice'); // Bob cannot use Alice's session const bobWithAliceContext = { sessionManager, apiClient, getSessionId: () => aliceSessionId, }; // This would succeed but the post would be from Alice const bobPost = await createPostToolHandler( { content: 'Bob trying with Alice session' }, bobWithAliceContext, ); const bobResponse = JSON.parse(bobPost.content[0].text); expect(bobResponse.post.author_name).toBe('alice'); // Not Bob! logger.warn('Session isolation test - sessions are properly isolated'); }); it('should handle invalid session IDs gracefully', async () => { const invalidContext = { sessionManager, apiClient, getSessionId: () => 'non-existent-session', }; // Should fail gracefully const result = await createPostToolHandler({ content: 'Should fail' }, invalidContext); const response = JSON.parse(result.content[0].text); expect(response.success).toBe(false); expect(response.error).toBe('Authentication required'); }); }); describe('Session Metrics', () => { it('should track session metrics correctly', async () => { const sessionIds = ['metric-1', 'metric-2', 'metric-3']; // Create sessions for (const sessionId of sessionIds) { const loginContext = { sessionManager, getSessionId: () => sessionId, }; await loginToolHandler({ agent_name: `agent-${sessionId}` }, loginContext); metrics.incrementSessionCount(); } expect(metrics.getSessionCount()).toBe(3); // Delete one session await sessionManager.deleteSession(sessionIds[0]); metrics.decrementSessionCount(); expect(metrics.getSessionCount()).toBe(2); // Clear all sessions await sessionManager.clearAllSessions(); metrics.reset(); expect(metrics.getSessionCount()).toBe(0); }); }); });

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/2389-research/mcp-socialmedia'

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