import { ExecutionContext, CallHandler } from '@nestjs/common'; import { of, throwError } from 'rxjs'; import { AuditLogInterceptor } from '../../../src/shared/interceptors/audit-log.interceptor'; describe('AuditLogInterceptor', () => { let interceptor: AuditLogInterceptor; const createMockContext = ( method: string = 'POST', url: string = '/backup-share/store', body: any = {}, sourceService: string = 'identity-service', sourceIp: string = '127.0.0.1', ): ExecutionContext => { return { switchToHttp: () => ({ getRequest: () => ({ method, url, body, sourceService, sourceIp, }), }), } as ExecutionContext; }; const createMockCallHandler = (response: any = {}): CallHandler => ({ handle: () => of(response), }); const createErrorCallHandler = (error: Error): CallHandler => ({ handle: () => throwError(() => error), }); beforeEach(() => { interceptor = new AuditLogInterceptor(); }); describe('intercept', () => { it('should allow request to proceed', (done) => { const context = createMockContext(); const handler = createMockCallHandler({ success: true }); interceptor.intercept(context, handler).subscribe({ next: (response) => { expect(response).toEqual({ success: true }); done(); }, }); }); it('should not modify the response', (done) => { const context = createMockContext(); const originalResponse = { shareId: '123', success: true }; const handler = createMockCallHandler(originalResponse); interceptor.intercept(context, handler).subscribe({ next: (response) => { expect(response).toEqual(originalResponse); done(); }, }); }); it('should propagate errors', (done) => { const context = createMockContext(); const error = new Error('Test error'); const handler = createErrorCallHandler(error); interceptor.intercept(context, handler).subscribe({ error: (err) => { expect(err).toBe(error); done(); }, }); }); it('should sanitize sensitive fields in body', () => { const sensitiveBody = { userId: '12345', encryptedShareData: 'secret-data', recoveryToken: 'secret-token', password: 'secret-password', publicKey: '02abc...', }; // Access the private method through prototype const sanitized = (interceptor as any).sanitizeBody(sensitiveBody); expect(sanitized.userId).toBe('12345'); expect(sanitized.publicKey).toBe('02abc...'); expect(sanitized.encryptedShareData).toBe('[REDACTED]'); expect(sanitized.recoveryToken).toBe('[REDACTED]'); expect(sanitized.password).toBe('[REDACTED]'); }); it('should handle null body', () => { const sanitized = (interceptor as any).sanitizeBody(null); expect(sanitized).toBeNull(); }); it('should handle undefined body', () => { const sanitized = (interceptor as any).sanitizeBody(undefined); expect(sanitized).toBeUndefined(); }); it('should handle empty body', () => { const sanitized = (interceptor as any).sanitizeBody({}); expect(sanitized).toEqual({}); }); it('should not modify original body object', () => { const originalBody = { userId: '12345', encryptedShareData: 'secret-data', }; const bodyCopy = { ...originalBody }; (interceptor as any).sanitizeBody(originalBody); expect(originalBody).toEqual(bodyCopy); }); }); describe('logging behavior', () => { it('should handle different HTTP methods', (done) => { const methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH']; let completed = 0; methods.forEach((method) => { const context = createMockContext(method, '/test'); const handler = createMockCallHandler(); interceptor.intercept(context, handler).subscribe({ complete: () => { completed++; if (completed === methods.length) { done(); } }, }); }); }); it('should handle different URL paths', (done) => { const paths = [ '/backup-share/store', '/backup-share/retrieve', '/backup-share/revoke', '/health', ]; let completed = 0; paths.forEach((url) => { const context = createMockContext('GET', url); const handler = createMockCallHandler(); interceptor.intercept(context, handler).subscribe({ complete: () => { completed++; if (completed === paths.length) { done(); } }, }); }); }); it('should handle unknown source service', (done) => { const context = createMockContext('POST', '/test', {}, undefined, '127.0.0.1'); const handler = createMockCallHandler(); interceptor.intercept(context, handler).subscribe({ complete: () => { done(); }, }); }); it('should handle unknown source IP', (done) => { const context = createMockContext('POST', '/test', {}, 'identity-service', undefined); const handler = createMockCallHandler(); interceptor.intercept(context, handler).subscribe({ complete: () => { done(); }, }); }); }); });