nestjs-request-deduplication
Version:
[](https://www.npmjs.com/package/nestjs-request-deduplication) [](https://gith
214 lines (213 loc) • 9.91 kB
JavaScript
import { __awaiter } from "tslib";
import { Test } from '@nestjs/testing';
import { RequestDeduplicationService } from './request-deduplication.service';
import { REQUEST_DEDUPLICATION_MODULE_OPTIONS } from '../constants';
import { RedisAdapter, MemcachedAdapter, MemoryAdapter } from '../storages';
import { StorageType } from '../interfaces';
jest.mock('../storages/redis.adapter');
jest.mock('../storages/memcached.adapter');
jest.mock('../storages/memory.adapter');
describe('RequestDeduplicationService', () => {
let service;
let mockStorage;
beforeEach(() => __awaiter(void 0, void 0, void 0, function* () {
const mockLogger = {
error: jest.fn(),
warn: jest.fn(),
log: jest.fn(),
debug: jest.fn(),
verbose: jest.fn(),
fatal: jest.fn(),
setLogLevels: jest.fn(),
localInstance: null,
registerLocalInstanceRef: jest.fn(),
};
mockStorage = {
init: jest.fn().mockResolvedValue(undefined),
get: jest.fn(),
set: jest.fn().mockResolvedValue(undefined),
delete: jest.fn().mockResolvedValue(undefined),
logger: mockLogger,
};
const module = yield Test.createTestingModule({
providers: [
RequestDeduplicationService,
{
provide: REQUEST_DEDUPLICATION_MODULE_OPTIONS,
useValue: {
ttl: 1000,
},
},
],
}).compile();
service = module.get(RequestDeduplicationService);
Object.defineProperty(RequestDeduplicationService, 'storageAdapter', {
value: mockStorage,
writable: true,
});
}));
describe('processRequest', () => {
it('should return true for first-time requests', () => __awaiter(void 0, void 0, void 0, function* () {
mockStorage.get.mockResolvedValue('');
const result = yield service.processRequest('test-key', 'value', 1000);
expect(result).toBe(true);
expect(mockStorage.get).toHaveBeenCalledWith('test-key');
expect(mockStorage.set).toHaveBeenCalledWith('test-key', 'value', 1000);
}));
it('should return false for duplicate requests', () => __awaiter(void 0, void 0, void 0, function* () {
mockStorage.get.mockResolvedValue('existing-value');
const result = yield service.processRequest('test-key', 'value', 1000);
expect(result).toBe(false);
expect(mockStorage.get).toHaveBeenCalledWith('test-key');
expect(mockStorage.set).not.toHaveBeenCalled();
}));
it('should throw error when storage fails', () => __awaiter(void 0, void 0, void 0, function* () {
mockStorage.get.mockRejectedValue(new Error('Storage error'));
yield expect(service.processRequest('test-key', 'value', 1000)).rejects.toThrow('Storage error');
}));
});
describe('deleteRequest', () => {
it('should delete existing request', () => __awaiter(void 0, void 0, void 0, function* () {
yield service.deleteRequest('test-key');
expect(mockStorage.delete).toHaveBeenCalledWith('test-key');
}));
it('should handle delete errors gracefully', () => __awaiter(void 0, void 0, void 0, function* () {
mockStorage.delete.mockRejectedValue(new Error('Delete error'));
yield expect(service.deleteRequest('test-key')).resolves.not.toThrow();
}));
});
describe('storage initialization', () => {
it('should initialize memory storage by default', () => __awaiter(void 0, void 0, void 0, function* () {
yield service.onModuleInit();
expect(service['storage']).toBeDefined();
}));
it('should initialize redis storage when config provided', () => __awaiter(void 0, void 0, void 0, function* () {
const moduleWithRedis = yield Test.createTestingModule({
providers: [
RequestDeduplicationService,
{
provide: REQUEST_DEDUPLICATION_MODULE_OPTIONS,
useValue: {
ttl: 1000,
redisConfig: {
host: 'localhost',
port: 6379,
},
},
},
],
}).compile();
const serviceWithRedis = moduleWithRedis.get(RequestDeduplicationService);
yield serviceWithRedis.onModuleInit();
expect(serviceWithRedis['storage']).toBeDefined();
}));
it('should initialize memcached storage when config provided', () => __awaiter(void 0, void 0, void 0, function* () {
const moduleWithMemcached = yield Test.createTestingModule({
providers: [
RequestDeduplicationService,
{
provide: REQUEST_DEDUPLICATION_MODULE_OPTIONS,
useValue: {
ttl: 1000,
memcachedConfig: {
servers: ['localhost:11211'],
},
},
},
],
}).compile();
const serviceWithMemcached = moduleWithMemcached.get(RequestDeduplicationService);
yield serviceWithMemcached.onModuleInit();
expect(serviceWithMemcached['storage']).toBeDefined();
}));
});
describe('storage adapter initialization', () => {
beforeEach(() => {
// Reset using proper type
RequestDeduplicationService.storageAdapter =
undefined;
jest.clearAllMocks();
});
it('should initialize Redis adapter when redisConfig is provided', () => __awaiter(void 0, void 0, void 0, function* () {
const moduleRef = yield Test.createTestingModule({
providers: [
RequestDeduplicationService,
{
provide: REQUEST_DEDUPLICATION_MODULE_OPTIONS,
useValue: {
storage: StorageType.REDIS,
redisConfig: {
url: 'redis://localhost:6379',
},
},
},
],
}).compile();
const service = moduleRef.get(RequestDeduplicationService);
yield service.onModuleInit();
const adapter = RequestDeduplicationService.storageAdapter;
expect(RedisAdapter).toHaveBeenCalledWith(expect.objectContaining({
redisConfig: expect.any(Object),
}));
expect(adapter.init).toHaveBeenCalled();
}));
it('should initialize Memcached adapter when memcachedConfig is provided', () => __awaiter(void 0, void 0, void 0, function* () {
const moduleRef = yield Test.createTestingModule({
providers: [
RequestDeduplicationService,
{
provide: REQUEST_DEDUPLICATION_MODULE_OPTIONS,
useValue: {
storage: StorageType.MEMCACHED,
memcachedConfig: {
uri: 'localhost:11211',
},
},
},
],
}).compile();
const service = moduleRef.get(RequestDeduplicationService);
yield service.onModuleInit();
const adapter = RequestDeduplicationService.storageAdapter;
expect(MemcachedAdapter).toHaveBeenCalledWith(expect.objectContaining({
memcachedConfig: expect.any(Object),
}));
expect(adapter.init).toHaveBeenCalled();
}));
it('should initialize Memory adapter when no specific config is provided', () => __awaiter(void 0, void 0, void 0, function* () {
const moduleRef = yield Test.createTestingModule({
providers: [
RequestDeduplicationService,
{
provide: REQUEST_DEDUPLICATION_MODULE_OPTIONS,
useValue: {
storage: StorageType.MEMORY,
},
},
],
}).compile();
const service = moduleRef.get(RequestDeduplicationService);
yield service.onModuleInit();
const adapter = RequestDeduplicationService.storageAdapter;
expect(MemoryAdapter).toHaveBeenCalled();
expect(adapter.init).toHaveBeenCalled();
}));
it('should throw error if storage adapter initialization fails', () => __awaiter(void 0, void 0, void 0, function* () {
const initError = new Error('Failed to initialize storage');
MemoryAdapter.prototype.init.mockRejectedValueOnce(initError);
const moduleRef = yield Test.createTestingModule({
providers: [
RequestDeduplicationService,
{
provide: REQUEST_DEDUPLICATION_MODULE_OPTIONS,
useValue: {
storage: StorageType.MEMORY,
},
},
],
}).compile();
const service = moduleRef.get(RequestDeduplicationService);
yield expect(service.onModuleInit()).rejects.toThrow(initError);
}));
});
});