Files
SerpentRace/SerpentRace_Backend/tests/Application/Services/ChatConfiguration.test.ts

160 lines
5.9 KiB
TypeScript

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();
});
});
});