/** * Test script for multi-user session management * This script simulates multiple Chrome extension connections to test session isolation */ import WebSocket from 'ws'; const SERVER_URL = 'ws://localhost:3001/chrome'; const NUM_CONNECTIONS = 3; class TestConnection { constructor(id) { this.id = id; this.ws = null; this.sessionInfo = null; this.connected = false; } async connect() { return new Promise((resolve, reject) => { console.log(`๐Ÿ”Œ Connection ${this.id}: Connecting to ${SERVER_URL}`); this.ws = new WebSocket(SERVER_URL); this.ws.on('open', () => { console.log(`โœ… Connection ${this.id}: Connected`); this.connected = true; // Send connection info const connectionInfo = { type: 'connection_info', userAgent: `TestAgent-${this.id}`, timestamp: Date.now(), extensionId: `test-extension-${this.id}` }; this.ws.send(JSON.stringify(connectionInfo)); }); this.ws.on('message', (data) => { try { const message = JSON.parse(data.toString()); if (message.type === 'session_info') { this.sessionInfo = message.sessionInfo; console.log(`๐Ÿ“‹ Connection ${this.id}: Received session info:`, this.sessionInfo); resolve(); } else { console.log(`๐Ÿ“จ Connection ${this.id}: Received message:`, message); } } catch (error) { console.error(`โŒ Connection ${this.id}: Error parsing message:`, error); } }); this.ws.on('close', () => { console.log(`๐Ÿ”Œ Connection ${this.id}: Disconnected`); this.connected = false; }); this.ws.on('error', (error) => { console.error(`โŒ Connection ${this.id}: Error:`, error); reject(error); }); // Timeout after 5 seconds setTimeout(() => { if (!this.sessionInfo) { reject(new Error(`Connection ${this.id}: Timeout waiting for session info`)); } }, 5000); }); } async sendTestMessage() { if (!this.connected || !this.ws) { throw new Error(`Connection ${this.id}: Not connected`); } const testMessage = { action: 'callTool', params: { name: 'chrome_navigate', arguments: { url: `https://example.com?user=${this.id}` } }, id: `test_${this.id}_${Date.now()}` }; console.log(`๐Ÿ“ค Connection ${this.id}: Sending test message:`, testMessage); this.ws.send(JSON.stringify(testMessage)); } disconnect() { if (this.ws) { this.ws.close(); } } } async function testMultiUserSessions() { console.log('๐Ÿš€ Starting multi-user session test...\n'); const connections = []; try { // Create and connect multiple test connections for (let i = 1; i <= NUM_CONNECTIONS; i++) { const connection = new TestConnection(i); connections.push(connection); console.log(`\n--- Connecting User ${i} ---`); await connection.connect(); // Wait a bit between connections await new Promise(resolve => setTimeout(resolve, 1000)); } console.log('\n๐ŸŽ‰ All connections established successfully!'); console.log('\n๐Ÿ“Š Session Summary:'); connections.forEach(conn => { console.log(` User ${conn.id}: Session ${conn.sessionInfo.sessionId}, User ID: ${conn.sessionInfo.userId}`); }); // Test sending messages from each connection console.log('\n--- Testing Message Routing ---'); for (const connection of connections) { await connection.sendTestMessage(); await new Promise(resolve => setTimeout(resolve, 500)); } // Wait for responses console.log('\nโณ Waiting for responses...'); await new Promise(resolve => setTimeout(resolve, 3000)); // Test session isolation by checking unique session IDs const sessionIds = connections.map(conn => conn.sessionInfo.sessionId); const uniqueSessionIds = new Set(sessionIds); console.log('\n๐Ÿ” Session Isolation Test:'); console.log(` Total connections: ${connections.length}`); console.log(` Unique session IDs: ${uniqueSessionIds.size}`); console.log(` Session isolation: ${uniqueSessionIds.size === connections.length ? 'โœ… PASS' : 'โŒ FAIL'}`); // Test user ID uniqueness const userIds = connections.map(conn => conn.sessionInfo.userId); const uniqueUserIds = new Set(userIds); console.log(` Unique user IDs: ${uniqueUserIds.size}`); console.log(` User ID isolation: ${uniqueUserIds.size === connections.length ? 'โœ… PASS' : 'โŒ FAIL'}`); } catch (error) { console.error('โŒ Test failed:', error); } finally { // Clean up connections console.log('\n๐Ÿงน Cleaning up connections...'); connections.forEach(conn => conn.disconnect()); setTimeout(() => { console.log('โœ… Test completed'); process.exit(0); }, 1000); } } async function testSessionPersistence() { console.log('\n๐Ÿ”„ Testing session persistence...'); const connection = new TestConnection('persistence'); try { await connection.connect(); const originalSessionId = connection.sessionInfo.sessionId; console.log(`๐Ÿ“‹ Original session: ${originalSessionId}`); // Disconnect and reconnect connection.disconnect(); await new Promise(resolve => setTimeout(resolve, 1000)); await connection.connect(); const newSessionId = connection.sessionInfo.sessionId; console.log(`๐Ÿ“‹ New session: ${newSessionId}`); console.log(`๐Ÿ”„ Session persistence: ${originalSessionId === newSessionId ? 'โŒ FAIL (sessions should be different)' : 'โœ… PASS (new session created)'}`); connection.disconnect(); } catch (error) { console.error('โŒ Session persistence test failed:', error); } } // Run tests async function runAllTests() { try { await testMultiUserSessions(); await new Promise(resolve => setTimeout(resolve, 2000)); await testSessionPersistence(); } catch (error) { console.error('โŒ Tests failed:', error); process.exit(1); } } // Check if server is running console.log('๐Ÿ” Checking if remote server is running...'); const testWs = new WebSocket(SERVER_URL); testWs.on('open', () => { testWs.close(); console.log('โœ… Server is running, starting tests...\n'); runAllTests(); }); testWs.on('error', (error) => { console.error('โŒ Cannot connect to server. Please start the remote server first:'); console.error(' cd app/remote-server && npm run dev'); console.error('\nError:', error.message); process.exit(1); });