Mock ioRedis for connection failure

213 views Asked by At

I'm using ioredis npm library in my production code : file: redisManager.ts

    import Redis from 'ioredis';
    import EventEmitter from "events";
    import {Logger} from "@aws-lambda-powertools/logger";
    
    const logger: Logger= new Logger({serviceName: 'redisManager'});
    
    export class RedisManager extends EventEmitter {
        protected readonly redisClient: Redis;
    
        constructor() {
            super();
                this.redisClient = new Redis(Number(process.env.REDIS_PORT), process.env.REDIS_HOST);
            this.redisClient.on('error', err => {
                logger.error(`Got an error from Redis: ${err.message}`);
                this.emit('error', err);
            });
        }
    
        getRedisClient(): Redis {
            return this.redisClient;
        }
    
        waitForRedisConnection = (): Promise<void> => {
            return new Promise<void>((resolve, reject) => {
                this.redisClient.on('connect', () => logger.info(`Got "connect" event from Redis. Stream is connected to the server`));
                this.redisClient.on('ready', () => {
                    logger.info(`Got "ready" event from Redis. Connection established.`);    
                    resolve();
                });
                this.redisClient.on('error', async (err) => {
                    logger.error(`Got "error" event from Redis. Details: [${err.message}]`);
                    reject(err);
                });
            });
        }

        async addKey(redisKey : string, ttl: number) {
            return this.redisClient.set(redisKey, 'The value', "PX", ttl);
        }
    }
    
    export async function getRedisManager(): Promise<RedisManager> {
        try {
             const redisManager = new RedisManager();
             await redisManager.waitForRedisConnection();
            } catch (err) {
              logger.error(`Get Redis manager failed with error: ${err.message}`);
              throw err;
            }
        }
    }

file app.ts

export const lambdaHandler = async (event: SQSEvent, context: Context): Promise<SQSBatchResponse> => {
    context.callbackWaitsForEmptyEventLoop = false;
    const batchFailures: SQSBatchResponse = {
        "batchItemFailures": []
    };
    try {
        const redisManager: RedisManager = await getRedisManager();
        await Promise.all(event.Records.map(async (sqsRecord: SQSRecord) => {
            try {
                const settingConfig = JSON.parse(sqsRecord.body) as SettingsConfig;
                await redisManager.addKey(settingConfig, 333333);
            } catch (e) {
                const error = e as Error;
                logger.error(`Lambda failed. on messageId=${sqsRecord.messageId}: ${error.message}`);
                batchFailures.batchItemFailures.push({itemIdentifier: sqsRecord.messageId})
            }
        }));
        logger.info(SUCCESS_MESSAGE);
    } catch (e) {
        const error = e as Error;
        logger.error(`Lambda execution failed. Got error: ${error.message}`);
        throw error;
    } finally {
        logger.info(JSON.stringify(batchFailures, null, 2));
        return batchFailures;
    }
};

I want to simulate connection failure while connecting to Redis via jest.

import {beforeAll, beforeEach, describe, expect, it, jest} from '@jest/globals';
import RedisMock from 'ioredis-mock';
import Redis from "ioredis";
jest.mock('ioredis', () => jest.requireActual('ioredis-mock'));
describe('lambdaHandler()', () => {
 it('Redis connection fail ', async () => {
          const result: SQSBatchResponse = await lambdaHandler(sqsTriggerEvent, CONTEXT);
}
}

How do I make redisClient.on('error') to be triggered, in unit test?
Note: In all other tests to simulate get and set from Redis I'm using ioredis-mock and it works perfectly.

0

There are 0 answers