mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-01-06 10:38:50 +01:00
🐛 fix: Redis Cluster Bug + 🧪 Enhance Test Coverage (#10518)
* ✨ feat: Implement scanIterator method for Redis cluster client This resolves the bug where `ServerConfigsCacheRedis#getAll` returns an empty object when a Redis Cluster (instead of a single node server is used) * ✨ feat: Update cache integration tests for Redis cluster support
This commit is contained in:
parent
f228f2a91d
commit
8c531b921e
14 changed files with 81 additions and 134 deletions
|
|
@ -7,17 +7,13 @@ describe('limiterCache', () => {
|
|||
beforeEach(() => {
|
||||
originalEnv = { ...process.env };
|
||||
|
||||
// Clear cache-related env vars
|
||||
delete process.env.USE_REDIS;
|
||||
delete process.env.REDIS_URI;
|
||||
delete process.env.USE_REDIS_CLUSTER;
|
||||
delete process.env.REDIS_PING_INTERVAL;
|
||||
delete process.env.REDIS_KEY_PREFIX;
|
||||
|
||||
// Set test configuration
|
||||
// Set test configuration with fallback defaults for local testing
|
||||
process.env.REDIS_PING_INTERVAL = '0';
|
||||
process.env.REDIS_KEY_PREFIX = 'Cache-Integration-Test';
|
||||
process.env.REDIS_RETRY_MAX_ATTEMPTS = '5';
|
||||
process.env.USE_REDIS = process.env.USE_REDIS || 'true';
|
||||
process.env.USE_REDIS_CLUSTER = process.env.USE_REDIS_CLUSTER || 'false';
|
||||
process.env.REDIS_URI = process.env.REDIS_URI || 'redis://127.0.0.1:6379';
|
||||
|
||||
// Clear require cache to reload modules
|
||||
jest.resetModules();
|
||||
|
|
@ -43,10 +39,6 @@ describe('limiterCache', () => {
|
|||
});
|
||||
|
||||
test('should return RedisStore with sendCommand when USE_REDIS is true', async () => {
|
||||
process.env.USE_REDIS = 'true';
|
||||
process.env.USE_REDIS_CLUSTER = 'false';
|
||||
process.env.REDIS_URI = 'redis://127.0.0.1:6379';
|
||||
|
||||
const cacheFactory = await import('../../cacheFactory');
|
||||
const redisClients = await import('../../redisClients');
|
||||
const { ioredisClient } = redisClients;
|
||||
|
|
|
|||
|
|
@ -33,17 +33,13 @@ describe('sessionCache', () => {
|
|||
beforeEach(() => {
|
||||
originalEnv = { ...process.env };
|
||||
|
||||
// Clear cache-related env vars
|
||||
delete process.env.USE_REDIS;
|
||||
delete process.env.REDIS_URI;
|
||||
delete process.env.USE_REDIS_CLUSTER;
|
||||
delete process.env.REDIS_PING_INTERVAL;
|
||||
delete process.env.REDIS_KEY_PREFIX;
|
||||
|
||||
// Set test configuration
|
||||
// Set test configuration with fallback defaults for local testing
|
||||
process.env.REDIS_PING_INTERVAL = '0';
|
||||
process.env.REDIS_KEY_PREFIX = 'Cache-Integration-Test';
|
||||
process.env.REDIS_RETRY_MAX_ATTEMPTS = '5';
|
||||
process.env.USE_REDIS = process.env.USE_REDIS || 'true';
|
||||
process.env.USE_REDIS_CLUSTER = process.env.USE_REDIS_CLUSTER || 'false';
|
||||
process.env.REDIS_URI = process.env.REDIS_URI || 'redis://127.0.0.1:6379';
|
||||
|
||||
// Clear require cache to reload modules
|
||||
jest.resetModules();
|
||||
|
|
@ -55,10 +51,6 @@ describe('sessionCache', () => {
|
|||
});
|
||||
|
||||
test('should return ConnectRedis store when USE_REDIS is true', async () => {
|
||||
process.env.USE_REDIS = 'true';
|
||||
process.env.USE_REDIS_CLUSTER = 'false';
|
||||
process.env.REDIS_URI = 'redis://127.0.0.1:6379';
|
||||
|
||||
const cacheFactory = await import('../../cacheFactory');
|
||||
const redisClients = await import('../../redisClients');
|
||||
const { ioredisClient } = redisClients;
|
||||
|
|
@ -138,10 +130,6 @@ describe('sessionCache', () => {
|
|||
});
|
||||
|
||||
test('should handle namespace with and without trailing colon', async () => {
|
||||
process.env.USE_REDIS = 'true';
|
||||
process.env.USE_REDIS_CLUSTER = 'false';
|
||||
process.env.REDIS_URI = 'redis://127.0.0.1:6379';
|
||||
|
||||
const cacheFactory = await import('../../cacheFactory');
|
||||
|
||||
const store1 = cacheFactory.sessionCache('namespace1');
|
||||
|
|
@ -152,10 +140,6 @@ describe('sessionCache', () => {
|
|||
});
|
||||
|
||||
test('should register error handler for Redis connection', async () => {
|
||||
process.env.USE_REDIS = 'true';
|
||||
process.env.USE_REDIS_CLUSTER = 'false';
|
||||
process.env.REDIS_URI = 'redis://127.0.0.1:6379';
|
||||
|
||||
const cacheFactory = await import('../../cacheFactory');
|
||||
const redisClients = await import('../../redisClients');
|
||||
const { ioredisClient } = redisClients;
|
||||
|
|
@ -173,10 +157,6 @@ describe('sessionCache', () => {
|
|||
});
|
||||
|
||||
test('should handle session expiration with TTL', async () => {
|
||||
process.env.USE_REDIS = 'true';
|
||||
process.env.USE_REDIS_CLUSTER = 'false';
|
||||
process.env.REDIS_URI = 'redis://127.0.0.1:6379';
|
||||
|
||||
const cacheFactory = await import('../../cacheFactory');
|
||||
const redisClients = await import('../../redisClients');
|
||||
const { ioredisClient } = redisClients;
|
||||
|
|
|
|||
|
|
@ -30,18 +30,13 @@ describe('standardCache', () => {
|
|||
beforeEach(() => {
|
||||
originalEnv = { ...process.env };
|
||||
|
||||
// Clear cache-related env vars
|
||||
delete process.env.USE_REDIS;
|
||||
delete process.env.REDIS_URI;
|
||||
delete process.env.USE_REDIS_CLUSTER;
|
||||
delete process.env.REDIS_PING_INTERVAL;
|
||||
delete process.env.REDIS_KEY_PREFIX;
|
||||
delete process.env.FORCED_IN_MEMORY_CACHE_NAMESPACES;
|
||||
|
||||
// Set test configuration
|
||||
// Set test configuration with fallback defaults for local testing
|
||||
process.env.REDIS_PING_INTERVAL = '0';
|
||||
process.env.REDIS_KEY_PREFIX = 'Cache-Integration-Test';
|
||||
process.env.REDIS_RETRY_MAX_ATTEMPTS = '5';
|
||||
process.env.USE_REDIS = process.env.USE_REDIS || 'true';
|
||||
process.env.USE_REDIS_CLUSTER = 'false';
|
||||
process.env.REDIS_URI = 'redis://127.0.0.1:6379';
|
||||
|
||||
// Clear require cache to reload modules
|
||||
jest.resetModules();
|
||||
|
|
@ -119,10 +114,6 @@ describe('standardCache', () => {
|
|||
|
||||
describe('when connecting to a Redis server', () => {
|
||||
test('should handle different namespaces with correct prefixes', async () => {
|
||||
process.env.USE_REDIS = 'true';
|
||||
process.env.USE_REDIS_CLUSTER = 'false';
|
||||
process.env.REDIS_URI = 'redis://127.0.0.1:6379';
|
||||
|
||||
const cacheFactory = await import('../../cacheFactory');
|
||||
|
||||
const cache1 = cacheFactory.standardCache('namespace-one');
|
||||
|
|
@ -148,9 +139,6 @@ describe('standardCache', () => {
|
|||
});
|
||||
|
||||
test('should respect FORCED_IN_MEMORY_CACHE_NAMESPACES', async () => {
|
||||
process.env.USE_REDIS = 'true';
|
||||
process.env.USE_REDIS_CLUSTER = 'false';
|
||||
process.env.REDIS_URI = 'redis://127.0.0.1:6379';
|
||||
process.env.FORCED_IN_MEMORY_CACHE_NAMESPACES = 'ROLES'; // Use a valid cache key
|
||||
|
||||
const cacheFactory = await import('../../cacheFactory');
|
||||
|
|
@ -167,10 +155,6 @@ describe('standardCache', () => {
|
|||
});
|
||||
|
||||
test('should handle TTL correctly', async () => {
|
||||
process.env.USE_REDIS = 'true';
|
||||
process.env.USE_REDIS_CLUSTER = 'false';
|
||||
process.env.REDIS_URI = 'redis://127.0.0.1:6379';
|
||||
|
||||
const cacheFactory = await import('../../cacheFactory');
|
||||
testCache = cacheFactory.standardCache('ttl-test', 1000); // 1 second TTL
|
||||
|
||||
|
|
|
|||
|
|
@ -26,17 +26,13 @@ describe('violationCache', () => {
|
|||
beforeEach(() => {
|
||||
originalEnv = { ...process.env };
|
||||
|
||||
// Clear cache-related env vars
|
||||
delete process.env.USE_REDIS;
|
||||
delete process.env.REDIS_URI;
|
||||
delete process.env.USE_REDIS_CLUSTER;
|
||||
delete process.env.REDIS_PING_INTERVAL;
|
||||
delete process.env.REDIS_KEY_PREFIX;
|
||||
|
||||
// Set test configuration
|
||||
// Set test configuration with fallback defaults for local testing
|
||||
process.env.REDIS_PING_INTERVAL = '0';
|
||||
process.env.REDIS_KEY_PREFIX = 'Cache-Integration-Test';
|
||||
process.env.REDIS_RETRY_MAX_ATTEMPTS = '5';
|
||||
process.env.USE_REDIS = process.env.USE_REDIS || 'true';
|
||||
process.env.USE_REDIS_CLUSTER = process.env.USE_REDIS_CLUSTER || 'false';
|
||||
process.env.REDIS_URI = process.env.REDIS_URI || 'redis://127.0.0.1:6379';
|
||||
|
||||
// Clear require cache to reload modules
|
||||
jest.resetModules();
|
||||
|
|
@ -48,10 +44,6 @@ describe('violationCache', () => {
|
|||
});
|
||||
|
||||
test('should create violation cache with Redis when USE_REDIS is true', async () => {
|
||||
process.env.USE_REDIS = 'true';
|
||||
process.env.USE_REDIS_CLUSTER = 'false';
|
||||
process.env.REDIS_URI = 'redis://127.0.0.1:6379';
|
||||
|
||||
const cacheFactory = await import('../../cacheFactory');
|
||||
const redisClients = await import('../../redisClients');
|
||||
const { ioredisClient } = redisClients;
|
||||
|
|
@ -119,10 +111,6 @@ describe('violationCache', () => {
|
|||
});
|
||||
|
||||
test('should respect namespace prefixing', async () => {
|
||||
process.env.USE_REDIS = 'true';
|
||||
process.env.USE_REDIS_CLUSTER = 'false';
|
||||
process.env.REDIS_URI = 'redis://127.0.0.1:6379';
|
||||
|
||||
const cacheFactory = await import('../../cacheFactory');
|
||||
const redisClients = await import('../../redisClients');
|
||||
const { ioredisClient } = redisClients;
|
||||
|
|
@ -157,10 +145,6 @@ describe('violationCache', () => {
|
|||
});
|
||||
|
||||
test('should respect TTL settings', async () => {
|
||||
process.env.USE_REDIS = 'true';
|
||||
process.env.USE_REDIS_CLUSTER = 'false';
|
||||
process.env.REDIS_URI = 'redis://127.0.0.1:6379';
|
||||
|
||||
const cacheFactory = await import('../../cacheFactory');
|
||||
const redisClients = await import('../../redisClients');
|
||||
const { ioredisClient } = redisClients;
|
||||
|
|
@ -193,10 +177,6 @@ describe('violationCache', () => {
|
|||
});
|
||||
|
||||
test('should handle complex violation data structures', async () => {
|
||||
process.env.USE_REDIS = 'true';
|
||||
process.env.USE_REDIS_CLUSTER = 'false';
|
||||
process.env.REDIS_URI = 'redis://127.0.0.1:6379';
|
||||
|
||||
const cacheFactory = await import('../../cacheFactory');
|
||||
const redisClients = await import('../../redisClients');
|
||||
const { ioredisClient } = redisClients;
|
||||
|
|
|
|||
|
|
@ -9,9 +9,13 @@ describe('redisClients Integration Tests', () => {
|
|||
let keyvRedisClient: RedisClientType | RedisClusterType | null = null;
|
||||
|
||||
// Helper function to test set/get/delete operations
|
||||
const testRedisOperations = async (client: RedisClient, keyPrefix: string): Promise<void> => {
|
||||
// Wait cluster to fully initialize
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
const testRedisOperations = async (
|
||||
client: RedisClient,
|
||||
keyPrefix: string,
|
||||
readyPromise?: Promise<void>,
|
||||
): Promise<void> => {
|
||||
// Wait for connection and topology discovery to complete
|
||||
if (readyPromise) await readyPromise;
|
||||
|
||||
const testKey = `${keyPrefix}-test-key`;
|
||||
const testValue = `${keyPrefix}-test-value`;
|
||||
|
|
@ -35,18 +39,13 @@ describe('redisClients Integration Tests', () => {
|
|||
beforeEach(() => {
|
||||
originalEnv = { ...process.env };
|
||||
|
||||
// Clear Redis-related env vars
|
||||
delete process.env.USE_REDIS;
|
||||
delete process.env.REDIS_URI;
|
||||
delete process.env.USE_REDIS_CLUSTER;
|
||||
delete process.env.REDIS_PING_INTERVAL;
|
||||
delete process.env.REDIS_KEY_PREFIX;
|
||||
|
||||
// Set common test configuration
|
||||
process.env.REDIS_PING_INTERVAL = '0';
|
||||
// Set common test configuration with fallback defaults for local testing
|
||||
process.env.REDIS_PING_INTERVAL = '1000';
|
||||
process.env.REDIS_KEY_PREFIX = 'Redis-Integration-Test';
|
||||
process.env.REDIS_RETRY_MAX_ATTEMPTS = '5';
|
||||
process.env.REDIS_PING_INTERVAL = '1000';
|
||||
process.env.USE_REDIS = process.env.USE_REDIS || 'true';
|
||||
process.env.USE_REDIS_CLUSTER = process.env.USE_REDIS_CLUSTER || 'false';
|
||||
process.env.REDIS_URI = process.env.REDIS_URI || 'redis://127.0.0.1:6379';
|
||||
|
||||
// Clear module cache to reload module
|
||||
jest.resetModules();
|
||||
|
|
@ -105,10 +104,6 @@ describe('redisClients Integration Tests', () => {
|
|||
|
||||
describe('when connecting to a Redis instance', () => {
|
||||
test('should connect and perform set/get/delete operations', async () => {
|
||||
process.env.USE_REDIS = 'true';
|
||||
process.env.USE_REDIS_CLUSTER = 'false';
|
||||
process.env.REDIS_URI = 'redis://127.0.0.1:6379';
|
||||
|
||||
const clients = await import('../redisClients');
|
||||
ioredisClient = clients.ioredisClient;
|
||||
await testRedisOperations(ioredisClient!, 'ioredis-single');
|
||||
|
|
@ -117,7 +112,6 @@ describe('redisClients Integration Tests', () => {
|
|||
|
||||
describe('when connecting to a Redis cluster', () => {
|
||||
test('should connect to cluster and perform set/get/delete operations', async () => {
|
||||
process.env.USE_REDIS = 'true';
|
||||
process.env.USE_REDIS_CLUSTER = 'true';
|
||||
process.env.REDIS_URI =
|
||||
'redis://127.0.0.1:7001,redis://127.0.0.1:7002,redis://127.0.0.1:7003';
|
||||
|
|
@ -142,26 +136,21 @@ describe('redisClients Integration Tests', () => {
|
|||
|
||||
describe('when connecting to a Redis instance', () => {
|
||||
test('should connect and perform set/get/delete operations', async () => {
|
||||
process.env.USE_REDIS = 'true';
|
||||
process.env.USE_REDIS_CLUSTER = 'false';
|
||||
process.env.REDIS_URI = 'redis://127.0.0.1:6379';
|
||||
|
||||
const clients = await import('../redisClients');
|
||||
keyvRedisClient = clients.keyvRedisClient;
|
||||
await testRedisOperations(keyvRedisClient!, 'keyv-single');
|
||||
await testRedisOperations(keyvRedisClient!, 'keyv-single', clients.keyvRedisClientReady!);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when connecting to a Redis cluster', () => {
|
||||
test('should connect to cluster and perform set/get/delete operations', async () => {
|
||||
process.env.USE_REDIS = 'true';
|
||||
process.env.USE_REDIS_CLUSTER = 'true';
|
||||
process.env.REDIS_URI =
|
||||
'redis://127.0.0.1:7001,redis://127.0.0.1:7002,redis://127.0.0.1:7003';
|
||||
|
||||
const clients = await import('../redisClients');
|
||||
keyvRedisClient = clients.keyvRedisClient;
|
||||
await testRedisOperations(keyvRedisClient!, 'keyv-cluster');
|
||||
await testRedisOperations(keyvRedisClient!, 'keyv-cluster', clients.keyvRedisClientReady!);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue