307 lines
11 KiB
JavaScript
307 lines
11 KiB
JavaScript
/**
|
|
* Complete Integration Test for Multi-User Chrome MCP System
|
|
*
|
|
* This test demonstrates the complete flow:
|
|
* 1. Multiple Chrome extensions connect with unique user IDs
|
|
* 2. Remote server automatically spawns LiveKit agents for each user
|
|
* 3. Voice commands are routed to the correct Chrome extension
|
|
* 4. Session isolation is maintained
|
|
*/
|
|
|
|
import WebSocket from 'ws';
|
|
import fetch from 'node-fetch';
|
|
|
|
const CHROME_WS_URL = 'ws://localhost:3001/chrome';
|
|
const MCP_HTTP_URL = 'http://localhost:3001/mcp';
|
|
|
|
class IntegratedUser {
|
|
constructor(userNumber) {
|
|
this.userNumber = userNumber;
|
|
this.chromeUserId = `user_${Date.now()}_${userNumber}_${Math.random().toString(36).substring(2, 10)}`;
|
|
this.ws = null;
|
|
this.sessionInfo = null;
|
|
this.receivedCommands = [];
|
|
this.liveKitAgentExpected = false;
|
|
}
|
|
|
|
async connectChromeExtension() {
|
|
return new Promise((resolve, reject) => {
|
|
console.log(`\n🔌 [User ${this.userNumber}] Connecting Chrome extension...`);
|
|
console.log(` Generated User ID: ${this.chromeUserId}`);
|
|
|
|
this.ws = new WebSocket(CHROME_WS_URL);
|
|
|
|
this.ws.on('open', () => {
|
|
console.log(`✅ [User ${this.userNumber}] Chrome WebSocket connected`);
|
|
|
|
// Send connection info with unique user ID
|
|
const connectionInfo = {
|
|
type: 'connection_info',
|
|
userId: this.chromeUserId,
|
|
userAgent: `IntegratedTestUser-${this.userNumber}`,
|
|
timestamp: Date.now(),
|
|
extensionId: `integrated-test-${this.userNumber}`
|
|
};
|
|
|
|
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(`🎯 [User ${this.userNumber}] Session established:`);
|
|
console.log(` Session ID: ${this.sessionInfo.sessionId}`);
|
|
console.log(` User ID: ${this.sessionInfo.userId}`);
|
|
console.log(` Expected LiveKit Room: mcp-chrome-user-${this.sessionInfo.userId}`);
|
|
|
|
this.liveKitAgentExpected = true;
|
|
resolve();
|
|
}
|
|
|
|
// Handle voice commands from LiveKit agent
|
|
if (message.action === 'callTool') {
|
|
this.receivedCommands.push({
|
|
...message,
|
|
receivedAt: Date.now()
|
|
});
|
|
|
|
console.log(`🎤 [User ${this.userNumber}] Received voice command: ${message.params.name}`);
|
|
console.log(` Arguments:`, message.params.arguments);
|
|
|
|
// Simulate Chrome extension executing the command
|
|
const response = {
|
|
id: message.id,
|
|
success: true,
|
|
result: {
|
|
message: `Command ${message.params.name} executed successfully`,
|
|
executedBy: `ChromeExtension-User${this.userNumber}`,
|
|
userId: this.chromeUserId,
|
|
timestamp: Date.now()
|
|
}
|
|
};
|
|
|
|
this.ws.send(JSON.stringify(response));
|
|
console.log(`📤 [User ${this.userNumber}] Sent command response`);
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error(`❌ [User ${this.userNumber}] Error parsing message:`, error);
|
|
}
|
|
});
|
|
|
|
this.ws.on('error', (error) => {
|
|
console.error(`❌ [User ${this.userNumber}] WebSocket error:`, error);
|
|
reject(error);
|
|
});
|
|
|
|
setTimeout(() => {
|
|
if (!this.sessionInfo) {
|
|
reject(new Error(`[User ${this.userNumber}] Timeout waiting for session info`));
|
|
}
|
|
}, 10000);
|
|
});
|
|
}
|
|
|
|
async simulateVoiceCommand(toolName, args) {
|
|
console.log(`🎙️ [User ${this.userNumber}] Simulating voice command: ${toolName}`);
|
|
|
|
const payload = {
|
|
jsonrpc: '2.0',
|
|
id: `voice_${this.userNumber}_${Date.now()}`,
|
|
method: 'tools/call',
|
|
params: {
|
|
name: toolName,
|
|
arguments: {
|
|
...args,
|
|
userContext: this.chromeUserId
|
|
}
|
|
}
|
|
};
|
|
|
|
const headers = {
|
|
'Content-Type': 'application/json',
|
|
'chrome-user-id': this.chromeUserId, // Route to this specific user
|
|
'user-agent': `LiveKitAgent-User${this.userNumber}`
|
|
};
|
|
|
|
try {
|
|
const response = await fetch(MCP_HTTP_URL, {
|
|
method: 'POST',
|
|
headers: headers,
|
|
body: JSON.stringify(payload)
|
|
});
|
|
|
|
const result = await response.json();
|
|
console.log(`📨 [User ${this.userNumber}] Voice command response:`, result.result || result.error);
|
|
return result;
|
|
} catch (error) {
|
|
console.error(`❌ [User ${this.userNumber}] Error sending voice command:`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
getStatus() {
|
|
return {
|
|
userNumber: this.userNumber,
|
|
chromeUserId: this.chromeUserId,
|
|
sessionId: this.sessionInfo?.sessionId,
|
|
liveKitAgentExpected: this.liveKitAgentExpected,
|
|
commandsReceived: this.receivedCommands.length,
|
|
lastCommand: this.receivedCommands[this.receivedCommands.length - 1]?.params?.name
|
|
};
|
|
}
|
|
|
|
disconnect() {
|
|
if (this.ws) {
|
|
console.log(`👋 [User ${this.userNumber}] Disconnecting Chrome extension`);
|
|
this.ws.close();
|
|
}
|
|
}
|
|
}
|
|
|
|
async function runCompleteIntegrationTest() {
|
|
console.log('🚀 COMPLETE INTEGRATION TEST FOR MULTI-USER CHROME MCP SYSTEM');
|
|
console.log('=' .repeat(80));
|
|
console.log('This test demonstrates:');
|
|
console.log('✓ Multiple Chrome extensions with unique user IDs');
|
|
console.log('✓ Automatic LiveKit agent spawning');
|
|
console.log('✓ Voice command routing with session isolation');
|
|
console.log('✓ End-to-end user experience');
|
|
console.log('=' .repeat(80));
|
|
|
|
const users = [];
|
|
const NUM_USERS = 3;
|
|
|
|
try {
|
|
// Phase 1: Connect Chrome Extensions
|
|
console.log('\n📋 PHASE 1: Chrome Extension Connections');
|
|
console.log('-' .repeat(50));
|
|
|
|
for (let i = 1; i <= NUM_USERS; i++) {
|
|
const user = new IntegratedUser(i);
|
|
users.push(user);
|
|
|
|
await user.connectChromeExtension();
|
|
console.log(`✅ User ${i} Chrome extension connected successfully`);
|
|
|
|
// Wait between connections to see the flow clearly
|
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
}
|
|
|
|
// Phase 2: Verify LiveKit Agent Spawning
|
|
console.log('\n📋 PHASE 2: LiveKit Agent Verification');
|
|
console.log('-' .repeat(50));
|
|
|
|
console.log('⏳ Waiting for LiveKit agents to start...');
|
|
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
|
|
users.forEach(user => {
|
|
const status = user.getStatus();
|
|
console.log(`🤖 User ${status.userNumber}: LiveKit agent expected for room mcp-chrome-user-${status.chromeUserId}`);
|
|
});
|
|
|
|
// Phase 3: Test Voice Commands
|
|
console.log('\n📋 PHASE 3: Voice Command Testing');
|
|
console.log('-' .repeat(50));
|
|
|
|
const voiceCommands = [
|
|
{ tool: 'chrome_navigate', args: { url: 'https://www.google.com' } },
|
|
{ tool: 'chrome_click_element', args: { selector: '#search-button' } },
|
|
{ tool: 'chrome_get_web_content', args: { selector: 'body' } }
|
|
];
|
|
|
|
for (let i = 0; i < users.length; i++) {
|
|
const user = users[i];
|
|
const command = voiceCommands[i % voiceCommands.length];
|
|
|
|
console.log(`\n🎤 Testing voice command for User ${user.userNumber}:`);
|
|
console.log(` Command: ${command.tool}`);
|
|
console.log(` Target: ${command.args.url || command.args.selector || 'page content'}`);
|
|
|
|
await user.simulateVoiceCommand(command.tool, command.args);
|
|
|
|
// Wait for command to be processed
|
|
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
}
|
|
|
|
// Phase 4: Test Session Isolation
|
|
console.log('\n📋 PHASE 4: Session Isolation Testing');
|
|
console.log('-' .repeat(50));
|
|
|
|
console.log('🔒 Testing that commands only go to the intended user...');
|
|
|
|
// Send a command from User 1 that should only affect User 1
|
|
await users[0].simulateVoiceCommand('chrome_navigate', {
|
|
url: 'https://example.com/isolation-test',
|
|
testId: 'isolation-test-user-1'
|
|
});
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
|
|
// Phase 5: Results Analysis
|
|
console.log('\n📋 PHASE 5: Results Analysis');
|
|
console.log('-' .repeat(50));
|
|
|
|
let totalCommandsSent = NUM_USERS + 1; // 3 initial commands + 1 isolation test
|
|
let totalCommandsReceived = 0;
|
|
let isolationSuccess = true;
|
|
|
|
console.log('\n📊 USER STATUS REPORT:');
|
|
users.forEach(user => {
|
|
const status = user.getStatus();
|
|
totalCommandsReceived += status.commandsReceived;
|
|
|
|
console.log(`\n👤 User ${status.userNumber}:`);
|
|
console.log(` Chrome User ID: ${status.chromeUserId}`);
|
|
console.log(` Session ID: ${status.sessionId}`);
|
|
console.log(` Commands Received: ${status.commandsReceived}`);
|
|
console.log(` Last Command: ${status.lastCommand || 'None'}`);
|
|
console.log(` LiveKit Agent Expected: ${status.liveKitAgentExpected ? '✅' : '❌'}`);
|
|
});
|
|
|
|
// Check isolation: User 1 should have received 2 commands, others should have 1 each
|
|
const user1Commands = users[0].getStatus().commandsReceived;
|
|
const user2Commands = users[1].getStatus().commandsReceived;
|
|
const user3Commands = users[2].getStatus().commandsReceived;
|
|
|
|
if (user1Commands !== 2 || user2Commands !== 1 || user3Commands !== 1) {
|
|
isolationSuccess = false;
|
|
}
|
|
|
|
// Final Results
|
|
console.log('\n🎯 FINAL RESULTS:');
|
|
console.log('=' .repeat(50));
|
|
console.log(`📤 Total Commands Sent: ${totalCommandsSent}`);
|
|
console.log(`📥 Total Commands Received: ${totalCommandsReceived}`);
|
|
console.log(`🎯 Command Routing: ${totalCommandsReceived === totalCommandsSent ? '✅ SUCCESS' : '❌ FAILED'}`);
|
|
console.log(`🔒 Session Isolation: ${isolationSuccess ? '✅ SUCCESS' : '❌ FAILED'}`);
|
|
console.log(`🤖 LiveKit Agents: ${users.every(u => u.liveKitAgentExpected) ? '✅ ALL EXPECTED' : '❌ SOME MISSING'}`);
|
|
|
|
if (totalCommandsReceived === totalCommandsSent && isolationSuccess) {
|
|
console.log('\n🎉 COMPLETE INTEGRATION TEST PASSED! 🎉');
|
|
console.log('✅ Multi-user Chrome MCP system is working correctly');
|
|
} else {
|
|
console.log('\n❌ COMPLETE INTEGRATION TEST FAILED!');
|
|
console.log('❌ Issues detected in multi-user system');
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('\n❌ Integration test failed:', error);
|
|
} finally {
|
|
// Cleanup
|
|
console.log('\n🧹 Cleaning up test connections...');
|
|
users.forEach(user => user.disconnect());
|
|
|
|
setTimeout(() => {
|
|
console.log('✅ Integration test completed');
|
|
process.exit(0);
|
|
}, 3000);
|
|
}
|
|
}
|
|
|
|
// Run the complete integration test
|
|
runCompleteIntegrationTest().catch(console.error);
|