import { WebSocketService } from '../../../src/Application/Services/WebSocketService'; import { Server as HttpServer } from 'http'; import { EventEmitter } from 'events'; describe('Chat Configuration', () => { let mockHttpServer: HttpServer; beforeAll(() => { // Create a more complete HTTP server mock that extends EventEmitter const httpServerMock = new EventEmitter(); // Add necessary methods that Socket.IO expects Object.assign(httpServerMock, { on: jest.fn(), listen: jest.fn(), close: jest.fn(), listeners: jest.fn().mockReturnValue([]), removeListener: jest.fn(), removeAllListeners: jest.fn(), setMaxListeners: jest.fn(), getMaxListeners: jest.fn().mockReturnValue(0), listenerCount: jest.fn().mockReturnValue(0), prependListener: jest.fn(), prependOnceListener: jest.fn(), off: jest.fn(), once: jest.fn(), emit: jest.fn(), // HTTP server specific timeout: 0, keepAliveTimeout: 5000, maxHeadersCount: null, headersTimeout: 60000, requestTimeout: 0 }); mockHttpServer = httpServerMock as unknown as HttpServer; }); afterEach(() => { // Clean up environment variables delete process.env.CHAT_MAX_MESSAGES_PER_USER; delete process.env.CHAT_MESSAGE_CLEANUP_WEEKS; delete process.env.CHAT_INACTIVITY_TIMEOUT_MINUTES; }); describe('Environment Variable Configuration', () => { it('should use default chat configuration values', () => { const service = new WebSocketService(mockHttpServer); expect(service['maxMessagesPerUser']).toBe(100); expect(service['messageCleanupWeeks']).toBe(4); expect(service['chatTimeout']).toBe(30); }); it('should use environment variable for CHAT_MAX_MESSAGES_PER_USER', () => { process.env.CHAT_MAX_MESSAGES_PER_USER = '50'; const service = new WebSocketService(mockHttpServer); expect(service['maxMessagesPerUser']).toBe(50); }); it('should use environment variable for CHAT_MESSAGE_CLEANUP_WEEKS', () => { // Arrange process.env.CHAT_MESSAGE_CLEANUP_WEEKS = '8'; // Act const service = new WebSocketService(mockHttpServer); // Assert expect(service['messageCleanupWeeks']).toBe(8); }); it('should use environment variable for CHAT_INACTIVITY_TIMEOUT_MINUTES', () => { // Arrange process.env.CHAT_INACTIVITY_TIMEOUT_MINUTES = '60'; // Act const service = new WebSocketService(mockHttpServer); // Assert expect(service['chatTimeout']).toBe(60); }); it('should handle invalid numeric environment variables gracefully', () => { // Arrange process.env.CHAT_MAX_MESSAGES_PER_USER = 'invalid'; process.env.CHAT_MESSAGE_CLEANUP_WEEKS = 'also-invalid'; process.env.CHAT_INACTIVITY_TIMEOUT_MINUTES = 'not-a-number'; // Act const service = new WebSocketService(mockHttpServer); // Assert - parseInt of invalid strings returns NaN expect(service['maxMessagesPerUser']).toBe(NaN); expect(service['messageCleanupWeeks']).toBe(NaN); expect(service['chatTimeout']).toBe(NaN); }); }); describe('Rate Limiting Logic', () => { it('should initialize with empty user message counts', () => { // Act const service = new WebSocketService(mockHttpServer); // Assert expect(service['userMessageCounts']).toBeDefined(); expect(service['userMessageCounts'].size).toBe(0); }); it('should allow messages within rate limit', () => { // Arrange process.env.CHAT_MAX_MESSAGES_PER_USER = '5'; const service = new WebSocketService(mockHttpServer); const userId = 'test-user'; // Act & Assert - should allow first 5 messages for (let i = 0; i < 5; i++) { expect(service['checkMessageRateLimit'](userId)).toBe(true); } }); it('should block messages when rate limit exceeded', () => { // Arrange process.env.CHAT_MAX_MESSAGES_PER_USER = '3'; const service = new WebSocketService(mockHttpServer); const userId = 'test-user'; // Act - send 3 messages (should be allowed) for (let i = 0; i < 3; i++) { expect(service['checkMessageRateLimit'](userId)).toBe(true); } // Assert - 4th message should be blocked expect(service['checkMessageRateLimit'](userId)).toBe(false); }); it('should reset rate limit after time window', (done) => { // Arrange process.env.CHAT_MAX_MESSAGES_PER_USER = '2'; const service = new WebSocketService(mockHttpServer); const userId = 'test-user'; // Act - exhaust rate limit expect(service['checkMessageRateLimit'](userId)).toBe(true); expect(service['checkMessageRateLimit'](userId)).toBe(true); expect(service['checkMessageRateLimit'](userId)).toBe(false); // Should be blocked // Mock time passage by manipulating the internal state const userStats = service['userMessageCounts'].get(userId)!; userStats.lastReset = Date.now() - (60 * 1000 + 1); // More than 1 minute ago service['userMessageCounts'].set(userId, userStats); // Assert - should be allowed again after reset expect(service['checkMessageRateLimit'](userId)).toBe(true); done(); }); }); });