refactor: 更新WebSocket相关测试和location_broadcast模块
- 更新location_broadcast网关以支持原生WebSocket - 修改WebSocket认证守卫和中间件 - 更新相关的测试文件和规范 - 添加WebSocket测试工具 - 完善Zulip服务的测试覆盖 技术改进: - 统一WebSocket实现架构 - 优化性能监控和限流中间件 - 更新测试用例以适配新的WebSocket实现
This commit is contained in:
118
test/utils/websocket-client.ts
Normal file
118
test/utils/websocket-client.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* 原生 WebSocket 客户端测试工具
|
||||
*
|
||||
* 用于替代 Socket.IO 客户端进行测试
|
||||
*/
|
||||
|
||||
import WebSocket from 'ws';
|
||||
|
||||
export interface WebSocketTestClient {
|
||||
connect(): Promise<void>;
|
||||
disconnect(): void;
|
||||
send(event: string, data: any): void;
|
||||
on(event: string, callback: (data: any) => void): void;
|
||||
off(event: string, callback?: (data: any) => void): void;
|
||||
waitForEvent(event: string, timeout?: number): Promise<any>;
|
||||
isConnected(): boolean;
|
||||
}
|
||||
|
||||
export class WebSocketTestClientImpl implements WebSocketTestClient {
|
||||
private ws: WebSocket | null = null;
|
||||
private eventHandlers = new Map<string, Set<(data: any) => void>>();
|
||||
private connected = false;
|
||||
|
||||
constructor(private url: string) {}
|
||||
|
||||
async connect(): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.ws = new WebSocket(this.url);
|
||||
|
||||
this.ws.on('open', () => {
|
||||
this.connected = true;
|
||||
resolve();
|
||||
});
|
||||
|
||||
this.ws.on('error', (error) => {
|
||||
reject(error);
|
||||
});
|
||||
|
||||
this.ws.on('message', (data) => {
|
||||
try {
|
||||
const message = JSON.parse(data.toString());
|
||||
const { event, data: eventData } = message;
|
||||
|
||||
const handlers = this.eventHandlers.get(event);
|
||||
if (handlers) {
|
||||
handlers.forEach(handler => handler(eventData));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to parse WebSocket message:', error);
|
||||
}
|
||||
});
|
||||
|
||||
this.ws.on('close', () => {
|
||||
this.connected = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
disconnect(): void {
|
||||
if (this.ws) {
|
||||
this.ws.close();
|
||||
this.ws = null;
|
||||
this.connected = false;
|
||||
}
|
||||
}
|
||||
|
||||
send(event: string, data: any): void {
|
||||
if (this.ws && this.connected) {
|
||||
const message = JSON.stringify({ event, data });
|
||||
this.ws.send(message);
|
||||
} else {
|
||||
throw new Error('WebSocket is not connected');
|
||||
}
|
||||
}
|
||||
|
||||
on(event: string, callback: (data: any) => void): void {
|
||||
if (!this.eventHandlers.has(event)) {
|
||||
this.eventHandlers.set(event, new Set());
|
||||
}
|
||||
this.eventHandlers.get(event)!.add(callback);
|
||||
}
|
||||
|
||||
off(event: string, callback?: (data: any) => void): void {
|
||||
const handlers = this.eventHandlers.get(event);
|
||||
if (handlers) {
|
||||
if (callback) {
|
||||
handlers.delete(callback);
|
||||
} else {
|
||||
handlers.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async waitForEvent(event: string, timeout: number = 5000): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timer = setTimeout(() => {
|
||||
this.off(event, handler);
|
||||
reject(new Error(`Timeout waiting for event: ${event}`));
|
||||
}, timeout);
|
||||
|
||||
const handler = (data: any) => {
|
||||
clearTimeout(timer);
|
||||
this.off(event, handler);
|
||||
resolve(data);
|
||||
};
|
||||
|
||||
this.on(event, handler);
|
||||
});
|
||||
}
|
||||
|
||||
isConnected(): boolean {
|
||||
return this.connected;
|
||||
}
|
||||
}
|
||||
|
||||
export function createWebSocketTestClient(url: string): WebSocketTestClient {
|
||||
return new WebSocketTestClientImpl(url);
|
||||
}
|
||||
Reference in New Issue
Block a user