// Verifies REDIS_URL with embedded password is parsed correctly by // ioredis. Production runs against a Coolify Redis service that requires // auth — a hardcoded localhost fallback or a URL parser that drops the // password would silently fall back to "no auth" and ECONNREFUSED. const mockCtor = jest.fn(); jest.mock('ioredis', () => // ioredis is a constructor — record arguments and stub event handlers. jest.fn().mockImplementation((url, opts) => { mockCtor(url, opts); return { on: () => {}, ping: async () => 'PONG', }; }) ); beforeEach(() => { mockCtor.mockReset(); // Clear the cached singleton so each test gets a fresh ctor call. jest.resetModules(); }); describe('redis client URL handling', () => { test('passes REDIS_URL with password through to ioredis verbatim', () => { process.env.REDIS_URL = 'redis://default:s3cret-pass@cache-host:6379/0'; const { getRedisClient } = require('../../src/utils/redis'); getRedisClient(); expect(mockCtor).toHaveBeenCalledTimes(1); expect(mockCtor.mock.calls[0][0]).toBe('redis://default:s3cret-pass@cache-host:6379/0'); }); test('falls back to 127.0.0.1 default when REDIS_URL is unset', () => { delete process.env.REDIS_URL; const { getRedisClient } = require('../../src/utils/redis'); getRedisClient(); expect(mockCtor.mock.calls[0][0]).toBe('redis://127.0.0.1:6379'); }); test('passes enableOfflineQueue=false so degraded mode fails fast', () => { process.env.REDIS_URL = 'redis://localhost:6379'; const { getRedisClient } = require('../../src/utils/redis'); getRedisClient(); expect(mockCtor.mock.calls[0][1]).toMatchObject({ enableOfflineQueue: false, maxRetriesPerRequest: 1, }); }); test('rediss:// TLS scheme passes through (Upstash / managed Redis)', () => { process.env.REDIS_URL = 'rediss://user:t0ken@host.upstash.io:6379'; const { getRedisClient } = require('../../src/utils/redis'); getRedisClient(); expect(mockCtor.mock.calls[0][0]).toBe('rediss://user:t0ken@host.upstash.io:6379'); }); }); describe('no hardcoded localhost Redis anywhere else', () => { test('only src/utils/redis.js has the localhost default; nothing else', () => { const { execSync } = require('child_process'); const out = execSync( 'grep -rn "127.0.0.1.*6379\\|localhost.*6379" /home/kev/mastermind/vyndr/src --include="*.js" || true', ).toString(); const lines = out.split('\n').filter((l) => l.trim()); // Permit only the one fallback inside src/utils/redis.js. const offenders = lines.filter((l) => !l.includes('src/utils/redis.js')); expect(offenders).toEqual([]); }); });