Skip to content

Commit

Permalink
added test for throttled client-retry
Browse files Browse the repository at this point in the history
  • Loading branch information
f-w committed Dec 13, 2023
1 parent aaeb87c commit e46687f
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"name": "Test",
"runtimeExecutable": "yarn",
"autoAttachChildProcesses": true,
"runtimeArgs": ["test:e2e", "--detectOpenHandles", "notification"],
"runtimeArgs": ["test:e2e", "--detectOpenHandles", "redis"],
"outputCapture": "std",
// "console": "internalConsole",
"env": {
Expand Down
80 changes: 78 additions & 2 deletions test/redis.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { NestExpressApplication } from '@nestjs/platform-express';
import Bottleneck from 'bottleneck';
import dns from 'dns';
import Redis from 'ioredis';
import { merge } from 'lodash';
import mailer from 'nodemailer/lib/mailer';
import { RedisMemoryServer } from 'redis-memory-server';
import { BaseController } from 'src/api/common/base.controller';
import { NotificationsService } from 'src/api/notifications/notifications.service';
import { SubscriptionsService } from 'src/api/subscriptions/subscriptions.service';
import { AppConfigService } from 'src/config/app-config.service';
import { CronTasksService } from 'src/observers/cron-tasks.service';
import supertest from 'supertest';
import { setupApplication, wait } from './test-helper';
import { runAsSuperAdmin, setupApplication, wait } from './test-helper';

let app: NestExpressApplication;
let client: supertest.SuperTest<supertest.Test>;
Expand All @@ -26,6 +29,16 @@ beforeEach(async () => {

({ app, client } = await setupApplication({
adminIps: ['127.0.0.1'],
email: {
throttle: {
enabled: true,
datastore: 'ioredis',
clientOptions: {
host,
port,
},
},
},
sms: {
throttle: {
enabled: true,
Expand All @@ -46,17 +59,20 @@ afterEach(async () => {
await con.quit();
await BaseController.smsLimiter?.disconnect();
delete BaseController.smsLimiter;
await BaseController.emailLimiter?.disconnect();
delete BaseController.emailLimiter;
await app.close();
await redisServer.stop();
});

let promiseAllRes;
beforeEach(async () => {
(
BaseController.prototype.sendSMS as unknown as jest.SpyInstance
).mockRestore();
mockedFetch = jest.spyOn(global, 'fetch').mockResolvedValue(new Response());

await Promise.all([
promiseAllRes = await Promise.all([
subscriptionsService.create({
serviceName: 'smsThrottle',
channel: 'sms',
Expand All @@ -75,6 +91,12 @@ beforeEach(async () => {
userChannelId: '12345',
state: 'confirmed',
}),
subscriptionsService.create({
serviceName: 'myService',
channel: 'email',
userChannelId: 'bar@foo.com',
state: 'confirmed',
}),
]);
});

Expand Down Expand Up @@ -116,6 +138,60 @@ describe('POST /notifications', () => {
);
expect(data.length).toEqual(1);
});

it('should perform throttled client-retry', async () => {
await runAsSuperAdmin(async () => {
(
BaseController.prototype.sendEmail as unknown as jest.SpyInstance
).mockRestore();
jest
.spyOn(mailer.prototype, 'sendMail')
.mockImplementation(async function (this: any) {
if (this.options.host !== '127.0.0.1') {
// eslint-disable-next-line no-throw-literal
throw { command: 'CONN', code: 'ETIMEDOUT' };
}
return 'ok';
});
jest.spyOn(dns, 'lookup').mockImplementation((...args) => {
const cb: any = args[args.length - 1];
cb(null, [{ address: '127.0.0.2' }, { address: '127.0.0.1' }]);
});
const spiedBottleneckSchedule = jest.spyOn(
Bottleneck.prototype,
'schedule',
);
const res = await client
.post('/api/notifications')
.send({
serviceName: 'myService',
message: {
from: 'no_reply@bar.com',
subject: 'test',
textBody: 'test',
},
channel: 'email',
isBroadcast: true,
})
.set('Accept', 'application/json');
expect(res.status).toEqual(200);
const data = await notificationsService.findAll(
{
where: {
serviceName: 'myService',
},
},
undefined,
);
expect(data[0].dispatch?.failed).toBeUndefined();
expect(data[0].dispatch?.successful).toContain(promiseAllRes[3].id);
expect(spiedBottleneckSchedule).toBeCalledTimes(3);
expect(spiedBottleneckSchedule.mock.calls[2][0]).toMatchObject({
priority: 5,
expiration: 120000,
});
});
});
});

describe('CRON clearRedisDatastore', () => {
Expand Down

0 comments on commit e46687f

Please sign in to comment.