import { RedisService } from '../../../src/Application/Services/RedisService'; import { logStartup, logError } from '../../../src/Application/Services/Logger'; describe('RedisService', () => { let redisService: RedisService; beforeAll(async () => { redisService = RedisService.getInstance(); try { await redisService.connect(); } catch (error) { console.log('Redis not available for testing, skipping Redis tests'); return; } }); afterAll(async () => { if (redisService.isRedisConnected()) { await redisService.disconnect(); } }); beforeEach(async () => { // Skip tests if Redis is not connected if (!redisService.isRedisConnected()) { return; } // Clean up test data const activeChats = await redisService.getAllActiveChats(); for (const chat of activeChats) { if (chat.chatId.startsWith('test-')) { await redisService.removeActiveChat(chat.chatId); } } await redisService.removeActiveUser('test-user-1'); await redisService.removeActiveUser('test-user-2'); }); describe('Active Chat Management', () => { it('should store and retrieve active chats', async () => { if (!redisService.isRedisConnected()) { return; } const testChatData = { chatId: 'test-chat-1', participants: ['user-1', 'user-2'], lastActivity: new Date(), messageCount: 5, chatType: 'direct' as const, name: 'Test Chat' }; await redisService.setActiveChat('test-chat-1', testChatData); const retrieved = await redisService.getActiveChat('test-chat-1'); expect(retrieved).toBeDefined(); expect(retrieved!.chatId).toBe('test-chat-1'); expect(retrieved!.participants).toEqual(['user-1', 'user-2']); expect(retrieved!.messageCount).toBe(5); expect(retrieved!.chatType).toBe('direct'); expect(retrieved!.name).toBe('Test Chat'); }); it('should return null for non-existent chat', async () => { if (!redisService.isRedisConnected()) { return; } const retrieved = await redisService.getActiveChat('non-existent-chat'); expect(retrieved).toBeNull(); }); it('should remove active chats', async () => { if (!redisService.isRedisConnected()) { return; } const testChatData = { chatId: 'test-chat-2', participants: ['user-1', 'user-2'], lastActivity: new Date(), messageCount: 0, chatType: 'group' as const }; await redisService.setActiveChat('test-chat-2', testChatData); let retrieved = await redisService.getActiveChat('test-chat-2'); expect(retrieved).toBeDefined(); await redisService.removeActiveChat('test-chat-2'); retrieved = await redisService.getActiveChat('test-chat-2'); expect(retrieved).toBeNull(); }); it('should update chat activity', async () => { if (!redisService.isRedisConnected()) { return; } const originalTime = new Date(Date.now() - 60000); // 1 minute ago const testChatData = { chatId: 'test-chat-3', participants: ['user-1', 'user-2'], lastActivity: originalTime, messageCount: 5, chatType: 'direct' as const }; await redisService.setActiveChat('test-chat-3', testChatData); // Wait a bit to ensure timestamp difference await new Promise(resolve => setTimeout(resolve, 10)); await redisService.updateChatActivity('test-chat-3', 6); const retrieved = await redisService.getActiveChat('test-chat-3'); expect(retrieved).toBeDefined(); expect(retrieved!.messageCount).toBe(6); expect(retrieved!.lastActivity.getTime()).toBeGreaterThan(originalTime.getTime()); }); }); describe('Active User Management', () => { it('should store and retrieve active users', async () => { if (!redisService.isRedisConnected()) { return; } const testUserData = { userId: 'test-user-1', activeChatIds: ['chat-1', 'chat-2'], lastActivity: new Date(), isOnline: true }; await redisService.setActiveUser('test-user-1', testUserData); const retrieved = await redisService.getActiveUser('test-user-1'); expect(retrieved).toBeDefined(); expect(retrieved!.userId).toBe('test-user-1'); expect(retrieved!.activeChatIds).toEqual(['chat-1', 'chat-2']); expect(retrieved!.isOnline).toBe(true); }); it('should manage user-chat associations', async () => { if (!redisService.isRedisConnected()) { return; } // Add user to chats await redisService.addUserToChat('test-user-2', 'chat-1'); await redisService.addUserToChat('test-user-2', 'chat-2'); let activeChatIds = await redisService.getUserActiveChats('test-user-2'); expect(activeChatIds).toContain('chat-1'); expect(activeChatIds).toContain('chat-2'); // Remove user from one chat await redisService.removeUserFromChat('test-user-2', 'chat-1'); activeChatIds = await redisService.getUserActiveChats('test-user-2'); expect(activeChatIds).not.toContain('chat-1'); expect(activeChatIds).toContain('chat-2'); }); }); describe('Inactive Chat Cleanup', () => { it('should identify inactive chats', async () => { if (!redisService.isRedisConnected()) { return; } const oldTime = new Date(Date.now() - 2 * 60 * 60 * 1000); // 2 hours ago const recentTime = new Date(); // Create an inactive chat await redisService.setActiveChat('test-inactive-chat', { chatId: 'test-inactive-chat', participants: ['user-1', 'user-2'], lastActivity: oldTime, messageCount: 3, chatType: 'direct' }); // Create an active chat await redisService.setActiveChat('test-active-chat', { chatId: 'test-active-chat', participants: ['user-1', 'user-3'], lastActivity: recentTime, messageCount: 1, chatType: 'direct' }); const inactiveChats = await redisService.getInactiveChats(60); // 60 minutes expect(inactiveChats).toContain('test-inactive-chat'); expect(inactiveChats).not.toContain('test-active-chat'); // Cleanup await redisService.removeActiveChat('test-inactive-chat'); await redisService.removeActiveChat('test-active-chat'); }); it('should cleanup inactive chats', async () => { if (!redisService.isRedisConnected()) { return; } const oldTime = new Date(Date.now() - 2 * 60 * 60 * 1000); // 2 hours ago await redisService.setActiveChat('test-cleanup-chat', { chatId: 'test-cleanup-chat', participants: ['user-1', 'user-2'], lastActivity: oldTime, messageCount: 0, chatType: 'direct' }); const cleanedUp = await redisService.cleanupInactiveChats(60); expect(cleanedUp).toContain('test-cleanup-chat'); // Verify chat was removed const retrieved = await redisService.getActiveChat('test-cleanup-chat'); expect(retrieved).toBeNull(); }); }); describe('Health Check', () => { it('should ping Redis successfully', async () => { if (!redisService.isRedisConnected()) { return; } const pingResult = await redisService.ping(); expect(pingResult).toBe(true); }); it('should report connection status', () => { const isConnected = redisService.isRedisConnected(); expect(typeof isConnected).toBe('boolean'); }); }); });