"use strict"; /** * Integration test for WebSocket session updates * Tests the complete flow of real-time WebSocket communication for hedging sessions */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const globals_1 = require("@jest/globals"); const ws_1 = __importDefault(require("ws")); const HedgingManager_1 = require("../../src/core/HedgingManager"); const WebSocketManager_1 = require("../../src/services/WebSocketManager"); (0, globals_1.describe)('WebSocket Session Updates Integration', () => { let hedgingManager; let webSocketManager; let testSessionId; let wsServer; let wsPort = 8080; (0, globals_1.beforeAll)(async () => { // Initialize hedging manager hedgingManager = new HedgingManager_1.HedgingManager({ accounts: './config/accounts.json', hedging: './config/hedging-config.json', marketData: './config/market-data-config.json' }); // Initialize WebSocket manager webSocketManager = new WebSocketManager_1.WebSocketManager({ port: wsPort, heartbeatInterval: 30000, reconnectInterval: 5000, maxReconnectAttempts: 5, connectionTimeout: 10000 }); await hedgingManager.initialize(); await webSocketManager.initialize(); }); (0, globals_1.afterAll)(async () => { if (hedgingManager) { await hedgingManager.shutdown(); } if (webSocketManager) { await webSocketManager.shutdown(); } if (wsServer) { wsServer.close(); } }); (0, globals_1.beforeEach)(async () => { // Create a test session for each test const sessionRequest = { name: 'WebSocket Test Session', accountIds: ['account-1', 'account-2'], volumeTarget: 10000, strategy: { symbol: 'ETH/USD', volumeDistribution: 'equal', priceRange: { min: 0.001, max: 0.01 }, timing: { minInterval: 30, maxInterval: 120, orderSize: { min: 100, max: 500 } }, riskLimits: { maxPositionSize: 0.1, stopLossThreshold: 0.05, maxSlippage: 0.02 }, orderTypes: { primary: 'limit', fallback: 'market' } } }; try { const session = await hedgingManager.createSession(sessionRequest); testSessionId = session.id; } catch (error) { testSessionId = 'mock-session-id'; } }); (0, globals_1.describe)('WebSocket Connection', () => { (0, globals_1.it)('should establish WebSocket connection', (done) => { const ws = new ws_1.default(`ws://localhost:${wsPort}/ws/sessions/${testSessionId}`); ws.on('open', () => { (0, globals_1.expect)(ws.readyState).toBe(ws_1.default.OPEN); ws.close(); done(); }); ws.on('error', (error) => { // This test should fail initially since WebSocket server doesn't exist yet (0, globals_1.expect)(error.message).toContain('ECONNREFUSED'); done(); }); }); (0, globals_1.it)('should authenticate WebSocket connection', (done) => { const ws = new ws_1.default(`ws://localhost:${wsPort}/ws/sessions/${testSessionId}`, { headers: { 'Authorization': 'Bearer test-api-key' } }); ws.on('open', () => { // Send authentication message const authMessage = { type: 'authenticate', token: 'test-api-key' }; ws.send(JSON.stringify(authMessage)); }); ws.on('message', (data) => { const message = JSON.parse(data.toString()); if (message.type === 'authenticated') { (0, globals_1.expect)(message.success).toBe(true); ws.close(); done(); } }); ws.on('error', (error) => { // This test should fail initially since WebSocket server doesn't exist yet (0, globals_1.expect)(error.message).toContain('ECONNREFUSED'); done(); }); }); (0, globals_1.it)('should reject unauthenticated connections', (done) => { const ws = new ws_1.default(`ws://localhost:${wsPort}/ws/sessions/${testSessionId}`); ws.on('open', () => { // Don't send authentication setTimeout(() => { (0, globals_1.expect)(ws.readyState).toBe(ws_1.default.CLOSED); done(); }, 1000); }); ws.on('error', (error) => { // This test should fail initially since WebSocket server doesn't exist yet (0, globals_1.expect)(error.message).toContain('ECONNREFUSED'); done(); }); }); }); (0, globals_1.describe)('Session Subscription', () => { (0, globals_1.it)('should subscribe to session updates', (done) => { const ws = new ws_1.default(`ws://localhost:${wsPort}/ws/sessions/${testSessionId}`, { headers: { 'Authorization': 'Bearer test-api-key' } }); ws.on('open', () => { // Authenticate first ws.send(JSON.stringify({ type: 'authenticate', token: 'test-api-key' })); }); ws.on('message', (data) => { const message = JSON.parse(data.toString()); if (message.type === 'authenticated') { // Subscribe to session updates const subscription = { type: 'subscribe', sessionId: testSessionId, channels: ['status', 'orders', 'risk', 'metrics'] }; ws.send(JSON.stringify(subscription)); } else if (message.type === 'subscribed') { (0, globals_1.expect)(message.success).toBe(true); (0, globals_1.expect)(message.channels).toEqual(['status', 'orders', 'risk', 'metrics']); ws.close(); done(); } }); ws.on('error', (error) => { // This test should fail initially since WebSocket server doesn't exist yet (0, globals_1.expect)(error.message).toContain('ECONNREFUSED'); done(); }); }); (0, globals_1.it)('should validate subscription channels', (done) => { const ws = new ws_1.default(`ws://localhost:${wsPort}/ws/sessions/${testSessionId}`, { headers: { 'Authorization': 'Bearer test-api-key' } }); ws.on('open', () => { ws.send(JSON.stringify({ type: 'authenticate', token: 'test-api-key' })); }); ws.on('message', (data) => { const message = JSON.parse(data.toString()); if (message.type === 'authenticated') { // Subscribe with invalid channel const invalidSubscription = { type: 'subscribe', sessionId: testSessionId, channels: ['invalid_channel'] }; ws.send(JSON.stringify(invalidSubscription)); } else if (message.type === 'error') { (0, globals_1.expect)(message.error.code).toBe('INVALID_CHANNEL'); ws.close(); done(); } }); ws.on('error', (error) => { // This test should fail initially since WebSocket server doesn't exist yet (0, globals_1.expect)(error.message).toContain('ECONNREFUSED'); done(); }); }); }); (0, globals_1.describe)('Real-time Updates', () => { (0, globals_1.it)('should receive status updates', (done) => { const ws = new ws_1.default(`ws://localhost:${wsPort}/ws/sessions/${testSessionId}`, { headers: { 'Authorization': 'Bearer test-api-key' } }); let updateReceived = false; ws.on('open', () => { ws.send(JSON.stringify({ type: 'authenticate', token: 'test-api-key' })); }); ws.on('message', (data) => { const message = JSON.parse(data.toString()); if (message.type === 'authenticated') { // Subscribe to status updates ws.send(JSON.stringify({ type: 'subscribe', sessionId: testSessionId, channels: ['status'] })); } else if (message.type === 'session_update' && message.channel === 'status') { const updateMessage = message; (0, globals_1.expect)(updateMessage.sessionId).toBe(testSessionId); (0, globals_1.expect)(updateMessage.channel).toBe('status'); (0, globals_1.expect)(updateMessage.data.status).toBeDefined(); (0, globals_1.expect)(updateMessage.timestamp).toBeDefined(); updateReceived = true; ws.close(); done(); } }); ws.on('error', (error) => { // This test should fail initially since WebSocket server doesn't exist yet (0, globals_1.expect)(error.message).toContain('ECONNREFUSED'); done(); }); // Timeout if no update received setTimeout(() => { if (!updateReceived) { ws.close(); done(); } }, 5000); }); (0, globals_1.it)('should receive order updates', (done) => { const ws = new ws_1.default(`ws://localhost:${wsPort}/ws/sessions/${testSessionId}`, { headers: { 'Authorization': 'Bearer test-api-key' } }); let updateReceived = false; ws.on('open', () => { ws.send(JSON.stringify({ type: 'authenticate', token: 'test-api-key' })); }); ws.on('message', (data) => { const message = JSON.parse(data.toString()); if (message.type === 'authenticated') { // Subscribe to order updates ws.send(JSON.stringify({ type: 'subscribe', sessionId: testSessionId, channels: ['orders'] })); } else if (message.type === 'session_update' && message.channel === 'orders') { const updateMessage = message; (0, globals_1.expect)(updateMessage.sessionId).toBe(testSessionId); (0, globals_1.expect)(updateMessage.channel).toBe('orders'); (0, globals_1.expect)(updateMessage.data.orders).toBeDefined(); (0, globals_1.expect)(Array.isArray(updateMessage.data.orders)).toBe(true); updateReceived = true; ws.close(); done(); } }); ws.on('error', (error) => { // This test should fail initially since WebSocket server doesn't exist yet (0, globals_1.expect)(error.message).toContain('ECONNREFUSED'); done(); }); // Timeout if no update received setTimeout(() => { if (!updateReceived) { ws.close(); done(); } }, 5000); }); (0, globals_1.it)('should receive risk updates', (done) => { const ws = new ws_1.default(`ws://localhost:${wsPort}/ws/sessions/${testSessionId}`, { headers: { 'Authorization': 'Bearer test-api-key' } }); let updateReceived = false; ws.on('open', () => { ws.send(JSON.stringify({ type: 'authenticate', token: 'test-api-key' })); }); ws.on('message', (data) => { const message = JSON.parse(data.toString()); if (message.type === 'authenticated') { // Subscribe to risk updates ws.send(JSON.stringify({ type: 'subscribe', sessionId: testSessionId, channels: ['risk'] })); } else if (message.type === 'session_update' && message.channel === 'risk') { const updateMessage = message; (0, globals_1.expect)(updateMessage.sessionId).toBe(testSessionId); (0, globals_1.expect)(updateMessage.channel).toBe('risk'); (0, globals_1.expect)(updateMessage.data.riskBreaches).toBeDefined(); (0, globals_1.expect)(Array.isArray(updateMessage.data.riskBreaches)).toBe(true); updateReceived = true; ws.close(); done(); } }); ws.on('error', (error) => { // This test should fail initially since WebSocket server doesn't exist yet (0, globals_1.expect)(error.message).toContain('ECONNREFUSED'); done(); }); // Timeout if no update received setTimeout(() => { if (!updateReceived) { ws.close(); done(); } }, 5000); }); (0, globals_1.it)('should receive metrics updates', (done) => { const ws = new ws_1.default(`ws://localhost:${wsPort}/ws/sessions/${testSessionId}`, { headers: { 'Authorization': 'Bearer test-api-key' } }); let updateReceived = false; ws.on('open', () => { ws.send(JSON.stringify({ type: 'authenticate', token: 'test-api-key' })); }); ws.on('message', (data) => { const message = JSON.parse(data.toString()); if (message.type === 'authenticated') { // Subscribe to metrics updates ws.send(JSON.stringify({ type: 'subscribe', sessionId: testSessionId, channels: ['metrics'] })); } else if (message.type === 'session_update' && message.channel === 'metrics') { const updateMessage = message; (0, globals_1.expect)(updateMessage.sessionId).toBe(testSessionId); (0, globals_1.expect)(updateMessage.channel).toBe('metrics'); (0, globals_1.expect)(updateMessage.data.metrics).toBeDefined(); (0, globals_1.expect)(updateMessage.data.metrics.volume).toBeDefined(); (0, globals_1.expect)(updateMessage.data.metrics.orders).toBeDefined(); (0, globals_1.expect)(updateMessage.data.metrics.performance).toBeDefined(); (0, globals_1.expect)(updateMessage.data.metrics.risk).toBeDefined(); updateReceived = true; ws.close(); done(); } }); ws.on('error', (error) => { // This test should fail initially since WebSocket server doesn't exist yet (0, globals_1.expect)(error.message).toContain('ECONNREFUSED'); done(); }); // Timeout if no update received setTimeout(() => { if (!updateReceived) { ws.close(); done(); } }, 5000); }); }); (0, globals_1.describe)('Connection Management', () => { (0, globals_1.it)('should handle connection heartbeat', (done) => { const ws = new ws_1.default(`ws://localhost:${wsPort}/ws/sessions/${testSessionId}`, { headers: { 'Authorization': 'Bearer test-api-key' } }); let heartbeatReceived = false; ws.on('open', () => { ws.send(JSON.stringify({ type: 'authenticate', token: 'test-api-key' })); }); ws.on('message', (data) => { const message = JSON.parse(data.toString()); if (message.type === 'authenticated') { // Subscribe to updates ws.send(JSON.stringify({ type: 'subscribe', sessionId: testSessionId, channels: ['status'] })); } else if (message.type === 'heartbeat') { (0, globals_1.expect)(message.timestamp).toBeDefined(); heartbeatReceived = true; ws.close(); done(); } }); ws.on('error', (error) => { // This test should fail initially since WebSocket server doesn't exist yet (0, globals_1.expect)(error.message).toContain('ECONNREFUSED'); done(); }); // Timeout if no heartbeat received setTimeout(() => { if (!heartbeatReceived) { ws.close(); done(); } }, 10000); }); (0, globals_1.it)('should handle connection reconnection', (done) => { const ws = new ws_1.default(`ws://localhost:${wsPort}/ws/sessions/${testSessionId}`, { headers: { 'Authorization': 'Bearer test-api-key' } }); ws.on('open', () => { ws.send(JSON.stringify({ type: 'authenticate', token: 'test-api-key' })); }); ws.on('message', (data) => { const message = JSON.parse(data.toString()); if (message.type === 'authenticated') { // Subscribe to updates ws.send(JSON.stringify({ type: 'subscribe', sessionId: testSessionId, channels: ['status'] })); // Simulate connection drop and reconnect setTimeout(() => { ws.close(); // Reconnect const ws2 = new ws_1.default(`ws://localhost:${wsPort}/ws/sessions/${testSessionId}`, { headers: { 'Authorization': 'Bearer test-api-key' } }); ws2.on('open', () => { ws2.send(JSON.stringify({ type: 'authenticate', token: 'test-api-key' })); }); ws2.on('message', (data) => { const message = JSON.parse(data.toString()); if (message.type === 'authenticated') { ws2.close(); done(); } }); ws2.on('error', (error) => { // This test should fail initially since WebSocket server doesn't exist yet (0, globals_1.expect)(error.message).toContain('ECONNREFUSED'); done(); }); }, 1000); } }); ws.on('error', (error) => { // This test should fail initially since WebSocket server doesn't exist yet (0, globals_1.expect)(error.message).toContain('ECONNREFUSED'); done(); }); }); (0, globals_1.it)('should handle multiple concurrent connections', (done) => { const connections = []; let connectedCount = 0; // Create multiple connections for (let i = 0; i < 5; i++) { const ws = new ws_1.default(`ws://localhost:${wsPort}/ws/sessions/${testSessionId}`, { headers: { 'Authorization': 'Bearer test-api-key' } }); ws.on('open', () => { ws.send(JSON.stringify({ type: 'authenticate', token: 'test-api-key' })); }); ws.on('message', (data) => { const message = JSON.parse(data.toString()); if (message.type === 'authenticated') { connectedCount++; if (connectedCount === 5) { // Close all connections connections.forEach(conn => conn.close()); done(); } } }); ws.on('error', (error) => { // This test should fail initially since WebSocket server doesn't exist yet (0, globals_1.expect)(error.message).toContain('ECONNREFUSED'); done(); }); connections.push(ws); } }); }); (0, globals_1.describe)('Error Handling', () => { (0, globals_1.it)('should handle invalid session ID', (done) => { const ws = new ws_1.default(`ws://localhost:${wsPort}/ws/sessions/invalid-session-id`, { headers: { 'Authorization': 'Bearer test-api-key' } }); ws.on('open', () => { ws.send(JSON.stringify({ type: 'authenticate', token: 'test-api-key' })); }); ws.on('message', (data) => { const message = JSON.parse(data.toString()); if (message.type === 'error') { (0, globals_1.expect)(message.error.code).toBe('SESSION_NOT_FOUND'); ws.close(); done(); } }); ws.on('error', (error) => { // This test should fail initially since WebSocket server doesn't exist yet (0, globals_1.expect)(error.message).toContain('ECONNREFUSED'); done(); }); }); (0, globals_1.it)('should handle malformed messages', (done) => { const ws = new ws_1.default(`ws://localhost:${wsPort}/ws/sessions/${testSessionId}`, { headers: { 'Authorization': 'Bearer test-api-key' } }); ws.on('open', () => { ws.send(JSON.stringify({ type: 'authenticate', token: 'test-api-key' })); }); ws.on('message', (data) => { const message = JSON.parse(data.toString()); if (message.type === 'authenticated') { // Send malformed message ws.send('invalid json'); } else if (message.type === 'error') { (0, globals_1.expect)(message.error.code).toBe('INVALID_MESSAGE_FORMAT'); ws.close(); done(); } }); ws.on('error', (error) => { // This test should fail initially since WebSocket server doesn't exist yet (0, globals_1.expect)(error.message).toContain('ECONNREFUSED'); done(); }); }); }); }); //# sourceMappingURL=test_websocket_updates.js.map