/** * Complete Multi-User System Test * Tests the full flow: Chrome Extension โ†’ Remote Server โ†’ LiveKit Agent โ†’ Voice Commands โ†’ Chrome Extension */ import WebSocket from 'ws'; const SERVER_URL = 'ws://localhost:3001/chrome'; const NUM_USERS = 2; class TestChromeUser { constructor(userId) { this.userId = userId; this.ws = null; this.sessionInfo = null; this.connected = false; this.liveKitAgentStarted = false; this.receivedMessages = []; } async connect() { return new Promise((resolve, reject) => { console.log(`\n๐Ÿ”Œ [User ${this.userId}] Connecting Chrome extension...`); this.ws = new WebSocket(SERVER_URL); this.ws.on('open', () => { console.log(`โœ… [User ${this.userId}] Chrome extension connected`); this.connected = true; // Generate unique user ID for this Chrome extension const chromeUserId = `user_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`; // Send connection info with user ID (simulating Chrome extension) const connectionInfo = { type: 'connection_info', userId: chromeUserId, // Chrome extension provides its own user ID userAgent: `TestChromeUser-${this.userId}`, timestamp: Date.now(), extensionId: `test-extension-${this.userId}` }; console.log(`๐Ÿ“ค [User ${this.userId}] Sending connection info with user ID: ${chromeUserId}`); this.ws.send(JSON.stringify(connectionInfo)); }); this.ws.on('message', (data) => { try { const message = JSON.parse(data.toString()); this.receivedMessages.push(message); console.log(`๐Ÿ“จ [User ${this.userId}] Received message:`, message); if (message.type === 'session_info') { this.sessionInfo = message.sessionInfo; console.log(`๐ŸŽฏ [User ${this.userId}] Session established:`, this.sessionInfo); // Check if LiveKit agent should be started setTimeout(() => { this.checkLiveKitAgent(); }, 2000); resolve(); } // Handle tool calls from LiveKit agent if (message.action === 'callTool') { console.log(`๐Ÿ”ง [User ${this.userId}] Received tool call from LiveKit agent:`, message.params); // Simulate Chrome extension response const response = { id: message.id, success: true, result: `Tool ${message.params.name} executed successfully for user ${this.userId}`, timestamp: Date.now() }; console.log(`๐Ÿ“ค [User ${this.userId}] Sending tool response:`, response); this.ws.send(JSON.stringify(response)); } } catch (error) { console.error(`โŒ [User ${this.userId}] Error parsing message:`, error); } }); this.ws.on('close', () => { console.log(`๐Ÿ”Œ [User ${this.userId}] Chrome extension disconnected`); this.connected = false; }); this.ws.on('error', (error) => { console.error(`โŒ [User ${this.userId}] WebSocket error:`, error); reject(error); }); // Timeout after 10 seconds setTimeout(() => { if (!this.sessionInfo) { reject(new Error(`[User ${this.userId}] Timeout waiting for session info`)); } }, 10000); }); } checkLiveKitAgent() { if (this.sessionInfo) { console.log(`๐Ÿค– [User ${this.userId}] LiveKit agent should be running for room: mcp-chrome-user-${this.sessionInfo.userId}`); this.liveKitAgentStarted = true; } } async sendTestVoiceCommand() { if (!this.connected || !this.ws) { throw new Error(`[User ${this.userId}] Not connected`); } // Simulate a voice command that would come from LiveKit agent const voiceCommand = { action: 'callTool', params: { name: 'chrome_navigate', arguments: { url: `https://example.com?user=${this.userId}&test=voice_command`, userContext: this.sessionInfo?.userId } }, id: `voice_${this.userId}_${Date.now()}`, source: 'livekit_agent' }; console.log(`๐ŸŽค [User ${this.userId}] Simulating voice command:`, voiceCommand); this.ws.send(JSON.stringify(voiceCommand)); } getStatus() { return { userId: this.userId, connected: this.connected, sessionInfo: this.sessionInfo, liveKitAgentStarted: this.liveKitAgentStarted, messagesReceived: this.receivedMessages.length }; } disconnect() { if (this.ws) { console.log(`๐Ÿ‘‹ [User ${this.userId}] Disconnecting Chrome extension`); this.ws.close(); } } } async function testCompleteMultiUserSystem() { console.log('๐Ÿš€ Starting Complete Multi-User System Test...\n'); console.log('This test verifies:'); console.log('1. Chrome Extension User ID Generation'); console.log('2. Remote Server Session Management'); console.log('3. Automatic LiveKit Agent Spawning'); console.log('4. User ID Consistency Across Components'); console.log('5. Voice Command Routing\n'); const users = []; try { // Step 1: Connect multiple Chrome extension users console.log('๐Ÿ“‹ STEP 1: Connecting Chrome Extension Users'); console.log('=' .repeat(50)); for (let i = 1; i <= NUM_USERS; i++) { const user = new TestChromeUser(i); users.push(user); console.log(`\n๐Ÿ”„ Connecting User ${i}...`); await user.connect(); console.log(`โœ… User ${i} connected successfully`); // Wait a bit between connections await new Promise(resolve => setTimeout(resolve, 1000)); } // Step 2: Verify session isolation console.log('\n๐Ÿ“‹ STEP 2: Verifying Session Isolation'); console.log('=' .repeat(50)); users.forEach(user => { const status = user.getStatus(); console.log(`๐Ÿ‘ค User ${status.userId}:`); console.log(` Session ID: ${status.sessionInfo?.sessionId}`); console.log(` User ID: ${status.sessionInfo?.userId}`); console.log(` LiveKit Agent: ${status.liveKitAgentStarted ? 'โœ… Started' : 'โŒ Not Started'}`); }); // Step 3: Test voice command routing console.log('\n๐Ÿ“‹ STEP 3: Testing Voice Command Routing'); console.log('=' .repeat(50)); for (const user of users) { console.log(`\n๐ŸŽค Testing voice command for User ${user.userId}...`); await user.sendTestVoiceCommand(); // Wait for response await new Promise(resolve => setTimeout(resolve, 2000)); } // Step 4: Verify user isolation console.log('\n๐Ÿ“‹ STEP 4: Verifying User Isolation'); console.log('=' .repeat(50)); users.forEach(user => { const status = user.getStatus(); console.log(`๐Ÿ‘ค User ${status.userId}: Received ${status.messagesReceived} messages`); }); console.log('\nโœ… Multi-User System Test Completed Successfully!'); console.log('\n๐Ÿ“Š SUMMARY:'); console.log(` Total Users: ${users.length}`); console.log(` All Connected: ${users.every(u => u.connected)}`); console.log(` All Have Sessions: ${users.every(u => u.sessionInfo)}`); console.log(` All Have LiveKit Agents: ${users.every(u => u.liveKitAgentStarted)}`); } catch (error) { console.error('โŒ Test failed:', error); } finally { // Cleanup console.log('\n๐Ÿงน Cleaning up connections...'); users.forEach(user => user.disconnect()); setTimeout(() => { console.log('โœ… Test cleanup completed'); process.exit(0); }, 2000); } } // Run the test testCompleteMultiUserSystem().catch(console.error);