301 lines
No EOL
7.7 KiB
TypeScript
301 lines
No EOL
7.7 KiB
TypeScript
/**
|
|
* WebSocket Testing and Monitoring Utilities
|
|
* Provides tools for testing WebSocket functionality and monitoring performance
|
|
*/
|
|
|
|
interface WebSocketTestResult {
|
|
success: boolean;
|
|
message: string;
|
|
latency?: number;
|
|
error?: string;
|
|
}
|
|
|
|
interface WebSocketPerformanceMetrics {
|
|
connectionTime: number;
|
|
averageLatency: number;
|
|
messagesSent: number;
|
|
messagesReceived: number;
|
|
reconnections: number;
|
|
errors: number;
|
|
}
|
|
|
|
export class WebSocketTester {
|
|
private metrics: WebSocketPerformanceMetrics = {
|
|
connectionTime: 0,
|
|
averageLatency: 0,
|
|
messagesSent: 0,
|
|
messagesReceived: 0,
|
|
reconnections: 0,
|
|
errors: 0
|
|
};
|
|
|
|
private latencies: number[] = [];
|
|
private connectionStartTime: number = 0;
|
|
|
|
/**
|
|
* Test basic WebSocket connection
|
|
*/
|
|
async testConnection(token: string): Promise<WebSocketTestResult> {
|
|
return new Promise((resolve) => {
|
|
try {
|
|
const { io } = require('socket.io-client');
|
|
this.connectionStartTime = Date.now();
|
|
|
|
const socket = io('http://localhost:5137', {
|
|
auth: { token },
|
|
transports: ['websocket'],
|
|
timeout: 5000
|
|
});
|
|
|
|
const timeout = setTimeout(() => {
|
|
socket.close();
|
|
resolve({
|
|
success: false,
|
|
message: 'Connection timeout (5s)',
|
|
error: 'Timeout'
|
|
});
|
|
}, 5000);
|
|
|
|
socket.on('connect', () => {
|
|
clearTimeout(timeout);
|
|
const connectionTime = Date.now() - this.connectionStartTime;
|
|
this.metrics.connectionTime = connectionTime;
|
|
|
|
socket.close();
|
|
resolve({
|
|
success: true,
|
|
message: 'Connection successful',
|
|
latency: connectionTime
|
|
});
|
|
});
|
|
|
|
socket.on('connect_error', (error: any) => {
|
|
clearTimeout(timeout);
|
|
this.metrics.errors++;
|
|
resolve({
|
|
success: false,
|
|
message: 'Connection failed',
|
|
error: error.message
|
|
});
|
|
});
|
|
|
|
} catch (error: any) {
|
|
resolve({
|
|
success: false,
|
|
message: 'Test setup failed',
|
|
error: error.message
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test message round-trip latency
|
|
*/
|
|
async testMessageLatency(token: string, focusGroupId: string): Promise<WebSocketTestResult> {
|
|
return new Promise((resolve) => {
|
|
try {
|
|
const { io } = require('socket.io-client');
|
|
const startTime = Date.now();
|
|
|
|
const socket = io('http://localhost:5137', {
|
|
auth: { token },
|
|
transports: ['websocket'],
|
|
timeout: 5000
|
|
});
|
|
|
|
const timeout = setTimeout(() => {
|
|
socket.close();
|
|
resolve({
|
|
success: false,
|
|
message: 'Message test timeout',
|
|
error: 'Timeout'
|
|
});
|
|
}, 10000);
|
|
|
|
socket.on('connect', () => {
|
|
// Join focus group room
|
|
socket.emit('join_focus_group', { focus_group_id: focusGroupId });
|
|
});
|
|
|
|
socket.on('joined_focus_group', () => {
|
|
// Send a test event and measure response time
|
|
const messageStartTime = Date.now();
|
|
socket.emit('test_message', { timestamp: messageStartTime });
|
|
});
|
|
|
|
socket.on('test_response', () => {
|
|
clearTimeout(timeout);
|
|
const latency = Date.now() - startTime;
|
|
this.latencies.push(latency);
|
|
this.updateLatencyMetrics();
|
|
|
|
socket.close();
|
|
resolve({
|
|
success: true,
|
|
message: 'Message test successful',
|
|
latency
|
|
});
|
|
});
|
|
|
|
socket.on('error', (error: any) => {
|
|
clearTimeout(timeout);
|
|
this.metrics.errors++;
|
|
socket.close();
|
|
resolve({
|
|
success: false,
|
|
message: 'Message test failed',
|
|
error: error.message
|
|
});
|
|
});
|
|
|
|
} catch (error: any) {
|
|
resolve({
|
|
success: false,
|
|
message: 'Message test setup failed',
|
|
error: error.message
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Run comprehensive WebSocket test suite
|
|
*/
|
|
async runTestSuite(token: string, focusGroupId: string): Promise<{
|
|
connectionTest: WebSocketTestResult;
|
|
messageTest: WebSocketTestResult;
|
|
metrics: WebSocketPerformanceMetrics;
|
|
}> {
|
|
console.log('🧪 Starting WebSocket test suite...');
|
|
|
|
const connectionTest = await this.testConnection(token);
|
|
let messageTest: WebSocketTestResult = {
|
|
success: false,
|
|
message: 'Skipped due to connection failure'
|
|
};
|
|
|
|
if (connectionTest.success) {
|
|
messageTest = await this.testMessageLatency(token, focusGroupId);
|
|
}
|
|
|
|
return {
|
|
connectionTest,
|
|
messageTest,
|
|
metrics: { ...this.metrics }
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Update latency metrics
|
|
*/
|
|
private updateLatencyMetrics(): void {
|
|
if (this.latencies.length > 0) {
|
|
this.metrics.averageLatency =
|
|
this.latencies.reduce((sum, lat) => sum + lat, 0) / this.latencies.length;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Start performance monitoring
|
|
*/
|
|
startMonitoring(websocketHook: any): () => void {
|
|
const interval = setInterval(() => {
|
|
if (websocketHook.isConnected) {
|
|
this.logPerformanceMetrics();
|
|
}
|
|
}, 30000); // Log every 30 seconds
|
|
|
|
return () => clearInterval(interval);
|
|
}
|
|
|
|
/**
|
|
* Log performance metrics
|
|
*/
|
|
private logPerformanceMetrics(): void {
|
|
console.log('📊 WebSocket Performance Metrics:', {
|
|
averageLatency: `${this.metrics.averageLatency.toFixed(2)}ms`,
|
|
connectionTime: `${this.metrics.connectionTime}ms`,
|
|
messagesSent: this.metrics.messagesSent,
|
|
messagesReceived: this.metrics.messagesReceived,
|
|
reconnections: this.metrics.reconnections,
|
|
errors: this.metrics.errors,
|
|
uptime: this.connectionStartTime ?
|
|
`${Math.round((Date.now() - this.connectionStartTime) / 1000)}s` : '0s'
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Increment message counters
|
|
*/
|
|
incrementMessagesSent(): void {
|
|
this.metrics.messagesSent++;
|
|
}
|
|
|
|
incrementMessagesReceived(): void {
|
|
this.metrics.messagesReceived++;
|
|
}
|
|
|
|
incrementReconnections(): void {
|
|
this.metrics.reconnections++;
|
|
}
|
|
|
|
incrementErrors(): void {
|
|
this.metrics.errors++;
|
|
}
|
|
|
|
/**
|
|
* Get current metrics
|
|
*/
|
|
getMetrics(): WebSocketPerformanceMetrics {
|
|
return { ...this.metrics };
|
|
}
|
|
|
|
/**
|
|
* Reset metrics
|
|
*/
|
|
resetMetrics(): void {
|
|
this.metrics = {
|
|
connectionTime: 0,
|
|
averageLatency: 0,
|
|
messagesSent: 0,
|
|
messagesReceived: 0,
|
|
reconnections: 0,
|
|
errors: 0
|
|
};
|
|
this.latencies = [];
|
|
}
|
|
}
|
|
|
|
// Global tester instance
|
|
export const websocketTester = new WebSocketTester();
|
|
|
|
// Development-only testing function
|
|
export async function runWebSocketDiagnostics(token: string, focusGroupId: string) {
|
|
if (process.env.NODE_ENV !== 'development') {
|
|
console.warn('WebSocket diagnostics only available in development mode');
|
|
return;
|
|
}
|
|
|
|
console.log('🔧 Running WebSocket diagnostics...');
|
|
const results = await websocketTester.runTestSuite(token, focusGroupId);
|
|
|
|
console.log('📋 WebSocket Test Results:', {
|
|
connection: results.connectionTest.success ? '✅ PASS' : '❌ FAIL',
|
|
message: results.messageTest.success ? '✅ PASS' : '❌ FAIL',
|
|
connectionLatency: results.connectionTest.latency ?
|
|
`${results.connectionTest.latency}ms` : 'N/A',
|
|
messageLatency: results.messageTest.latency ?
|
|
`${results.messageTest.latency}ms` : 'N/A'
|
|
});
|
|
|
|
if (!results.connectionTest.success) {
|
|
console.error('❌ Connection Error:', results.connectionTest.error);
|
|
}
|
|
|
|
if (!results.messageTest.success) {
|
|
console.error('❌ Message Error:', results.messageTest.error);
|
|
}
|
|
|
|
return results;
|
|
} |