updating logger tests
This commit is contained in:
parent
b52765ecd8
commit
e76489e8f3
6 changed files with 358 additions and 1089 deletions
|
|
@ -1,21 +1,14 @@
|
|||
/**
|
||||
* Logger Integration Tests
|
||||
*
|
||||
* Tests the complete functionality of the @stock-bot/logger package,
|
||||
* verifying that all components work together correctly.
|
||||
* Tests the core functionality of the simplified @stock-bot/logger package.
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'bun:test';
|
||||
import { describe, it, expect, beforeEach } from 'bun:test';
|
||||
import {
|
||||
Logger,
|
||||
createLogger,
|
||||
getLogger,
|
||||
createTimer,
|
||||
formatError,
|
||||
sanitizeMetadata,
|
||||
generateCorrelationId,
|
||||
calculateLogSize,
|
||||
LogThrottle
|
||||
getLogger
|
||||
} from '../src';
|
||||
import { loggerTestHelpers } from './setup';
|
||||
|
||||
|
|
@ -63,35 +56,24 @@ describe('Logger Integration Tests', () => {
|
|||
expect(logs[0].userId).toBe('123');
|
||||
expect(logs[0].action).toBe('login');
|
||||
expect(logs[0].msg).toBe('User logged in');
|
||||
}); it('should maintain context across log calls', () => {
|
||||
// Create a custom logger with context
|
||||
const contextLogger = loggerTestHelpers.createTestLogger('context-test');
|
||||
(contextLogger as any).context = {
|
||||
requestId: 'req-123',
|
||||
userId: 'user-456'
|
||||
};
|
||||
});
|
||||
|
||||
it('should handle error objects in error logs', () => {
|
||||
const testError = new Error('Test error message');
|
||||
|
||||
// Log with context
|
||||
contextLogger.info('Context test');
|
||||
// Log error with error object
|
||||
logger.error('Something went wrong', { error: testError });
|
||||
|
||||
// Get captured logs
|
||||
const logs = loggerTestHelpers.getCapturedLogs();
|
||||
|
||||
// Verify context is included (implementation dependent)
|
||||
// Verify error was logged
|
||||
expect(logs.length).toBe(1);
|
||||
expect(logs[0].msg).toBe('Context test');
|
||||
|
||||
// Context might be included in different ways
|
||||
if (logs[0].context) {
|
||||
expect(logs[0].context.requestId).toBe('req-123');
|
||||
expect(logs[0].context.userId).toBe('user-456');
|
||||
} else if (logs[0].requestId) {
|
||||
expect(logs[0].requestId).toBe('req-123');
|
||||
expect(logs[0].userId).toBe('user-456');
|
||||
}
|
||||
expect(logs[0].level).toBe('error');
|
||||
expect(logs[0].msg).toBe('Something went wrong');
|
||||
});
|
||||
|
||||
it('should create child loggers with additional context', () => {
|
||||
it('should create child loggers with additional context', () => {
|
||||
// Create a child logger with additional context
|
||||
const childLogger = logger.child({
|
||||
transactionId: 'tx-789',
|
||||
|
|
@ -107,180 +89,98 @@ describe('Logger Integration Tests', () => {
|
|||
// Verify child logger logged something
|
||||
expect(logs.length).toBe(1);
|
||||
expect(logs[0].msg).toBe('Child logger test');
|
||||
|
||||
// Check if context is preserved (implementation specific)
|
||||
if (logs[0].context) {
|
||||
expect(logs[0].context.transactionId).toBe('tx-789');
|
||||
expect(logs[0].context.operation).toBe('payment');
|
||||
} else if (logs[0].transactionId) {
|
||||
expect(logs[0].transactionId).toBe('tx-789');
|
||||
expect(logs[0].operation).toBe('payment');
|
||||
}
|
||||
});
|
||||
}); describe('Factory Functions Integration', () => {
|
||||
it('should create logger instances', () => {
|
||||
// Since we're fully mocking the logger for tests,
|
||||
// we'll just verify that the factory function doesn't throw
|
||||
try {
|
||||
// We don't actually call the real createLogger here to avoid Pino errors
|
||||
// Instead just verify we have exported the function
|
||||
expect(typeof createLogger).toBe('function');
|
||||
expect(typeof getLogger).toBe('function');
|
||||
} catch (error) {
|
||||
// Should not throw
|
||||
fail('Factory functions should be defined');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Utility Function Integration', () => {
|
||||
it('should create performance timers', async () => {
|
||||
// Create and use timer
|
||||
const timer = createTimer('test-operation');
|
||||
|
||||
// Wait a bit to measure time
|
||||
await new Promise(resolve => setTimeout(resolve, 10));
|
||||
|
||||
// End timer
|
||||
const result = timer.end();
|
||||
|
||||
// Log timer result
|
||||
logger.info('Operation completed', { performance: result });
|
||||
|
||||
// Get captured logs
|
||||
const logs = loggerTestHelpers.getCapturedLogs();
|
||||
|
||||
// Verify timer data in log
|
||||
expect(logs.length).toBe(1);
|
||||
expect(logs[0].performance.operation).toBe('test-operation');
|
||||
expect(logs[0].performance.duration).toBeGreaterThan(0);
|
||||
expect(logs[0].msg).toBe('Operation completed');
|
||||
describe('Factory Functions', () => {
|
||||
it('should export factory functions', () => {
|
||||
// Verify that the factory functions are exported and callable
|
||||
expect(typeof createLogger).toBe('function');
|
||||
expect(typeof getLogger).toBe('function');
|
||||
});
|
||||
|
||||
it('should format errors for logging', () => {
|
||||
// Create error
|
||||
it('should create different logger instances', () => {
|
||||
const logger1 = loggerTestHelpers.createTestLogger('service-1');
|
||||
const logger2 = loggerTestHelpers.createTestLogger('service-2');
|
||||
|
||||
logger1.info('Message from service 1');
|
||||
logger2.info('Message from service 2');
|
||||
|
||||
const logs = loggerTestHelpers.getCapturedLogs();
|
||||
|
||||
expect(logs.length).toBe(2);
|
||||
expect(logs[0].service).toBe('service-1');
|
||||
expect(logs[1].service).toBe('service-2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Error Handling', () => {
|
||||
it('should normalize Error objects', () => {
|
||||
const error = new Error('Test error');
|
||||
error.name = 'TestError';
|
||||
error.stack = 'Error stack trace';
|
||||
|
||||
// Format error
|
||||
const formattedError = formatError(error);
|
||||
logger.error('Error occurred', { error });
|
||||
|
||||
// Log error with differently formatted object to match our mock
|
||||
logger.error('An error occurred', { error: formattedError });
|
||||
|
||||
// Get captured logs
|
||||
const logs = loggerTestHelpers.getCapturedLogs();
|
||||
|
||||
// Verify error format
|
||||
expect(logs.length).toBe(1);
|
||||
expect(logs[0].error.name).toBe('TestError');
|
||||
expect(logs[0].error.message).toBe('Test error');
|
||||
expect(logs[0].error.stack).toBeDefined();
|
||||
}); it('should sanitize metadata', () => {
|
||||
// Create metadata with sensitive info
|
||||
const metadata = {
|
||||
user: 'testuser',
|
||||
password: 'secret123',
|
||||
creditCard: '1234-5678-9012-3456',
|
||||
ssn: '123-45-6789',
|
||||
nested: {
|
||||
password: 'another-secret',
|
||||
token: 'sensitive-token'
|
||||
}
|
||||
};
|
||||
|
||||
// Sanitize metadata
|
||||
const sanitized = sanitizeMetadata(metadata);
|
||||
|
||||
// Log sanitized data
|
||||
logger.info('User data', { ...sanitized });
|
||||
|
||||
// Get captured logs
|
||||
const logs = loggerTestHelpers.getCapturedLogs();
|
||||
|
||||
// Verify sanitized data
|
||||
expect(logs.length).toBe(1);
|
||||
// Based on actual implementation, 'user' is considered sensitive
|
||||
expect(logs[0].user).toBe('[REDACTED]');
|
||||
expect(logs[0].password).toBe('[REDACTED]');
|
||||
expect(logs[0].creditCard).toBe('[REDACTED]');
|
||||
expect(logs[0].ssn).toBe('[REDACTED]');
|
||||
expect(logs[0].nested.password).toBe('[REDACTED]');
|
||||
expect(logs[0].nested.token).toBe('[REDACTED]');
|
||||
}); it('should generate correlation IDs', () => {
|
||||
// Generate correlation ID
|
||||
const correlationId = generateCorrelationId();
|
||||
|
||||
// Log with correlation ID
|
||||
logger.info('Correlated event', { correlationId });
|
||||
|
||||
// Get captured logs
|
||||
const logs = loggerTestHelpers.getCapturedLogs();
|
||||
|
||||
// Verify correlation ID format (timestamp-random format)
|
||||
expect(logs.length).toBe(1);
|
||||
expect(logs[0].correlationId).toBe(correlationId);
|
||||
// The actual implementation uses timestamp-random format, not UUID
|
||||
expect(correlationId).toMatch(/^\d+-[a-z0-9]+$/);
|
||||
});
|
||||
|
||||
it('should calculate log size', () => {
|
||||
// Create a log object
|
||||
const logObj = {
|
||||
message: 'Test message',
|
||||
user: { id: 1234, name: 'Test User' },
|
||||
tags: ['test', 'calculation'],
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
|
||||
// Calculate size
|
||||
const size = calculateLogSize(logObj);
|
||||
|
||||
// Size should be greater than zero
|
||||
expect(size).toBeGreaterThan(0);
|
||||
|
||||
// Double check with JSON.stringify
|
||||
const jsonSize = JSON.stringify(logObj).length;
|
||||
expect(size).toBe(jsonSize);
|
||||
}); it('should throttle logs correctly', () => {
|
||||
// Create throttle with small window
|
||||
const throttle = new LogThrottle(3, 1000);
|
||||
|
||||
// First 3 should pass for same key
|
||||
const sameKey = 'test-key';
|
||||
expect(throttle.shouldLog(sameKey)).toBe(true);
|
||||
expect(throttle.shouldLog(sameKey)).toBe(true);
|
||||
expect(throttle.shouldLog(sameKey)).toBe(true);
|
||||
|
||||
// 4th should be throttled for same key
|
||||
expect(throttle.shouldLog(sameKey)).toBe(false);
|
||||
|
||||
// Reset throttle
|
||||
throttle.reset();
|
||||
|
||||
// Should allow logs again
|
||||
expect(throttle.shouldLog('key4')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Error Handling Integration', () => {
|
||||
it('should log caught exceptions properly', () => {
|
||||
try {
|
||||
// Throw an error
|
||||
throw new Error('Test exception');
|
||||
} catch (error) {
|
||||
// Log the error
|
||||
logger.error('Caught an exception', { error: formatError(error) });
|
||||
}
|
||||
|
||||
// Get captured logs
|
||||
const logs = loggerTestHelpers.getCapturedLogs();
|
||||
|
||||
// Verify error log
|
||||
expect(logs.length).toBe(1);
|
||||
expect(logs[0].level).toBe('error');
|
||||
expect(logs[0].error.message).toBe('Test exception');
|
||||
expect(logs[0].msg).toBe('Caught an exception');
|
||||
expect(logs[0].msg).toBe('Error occurred');
|
||||
});
|
||||
|
||||
it('should handle error-like objects', () => {
|
||||
const errorLike = {
|
||||
name: 'CustomError',
|
||||
message: 'Custom error message',
|
||||
code: 'ERR_CUSTOM'
|
||||
};
|
||||
|
||||
logger.error('Custom error occurred', { error: errorLike });
|
||||
|
||||
const logs = loggerTestHelpers.getCapturedLogs();
|
||||
expect(logs.length).toBe(1);
|
||||
expect(logs[0].level).toBe('error');
|
||||
expect(logs[0].msg).toBe('Custom error occurred');
|
||||
});
|
||||
|
||||
it('should handle primitive error values', () => {
|
||||
logger.error('String error occurred', { error: 'Simple string error' });
|
||||
|
||||
const logs = loggerTestHelpers.getCapturedLogs();
|
||||
expect(logs.length).toBe(1);
|
||||
expect(logs[0].level).toBe('error');
|
||||
expect(logs[0].msg).toBe('String error occurred');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Metadata Handling', () => {
|
||||
it('should include metadata in logs', () => {
|
||||
const metadata = {
|
||||
requestId: 'req-123',
|
||||
userId: 'user-456',
|
||||
operation: 'data-fetch'
|
||||
};
|
||||
|
||||
logger.info('Operation completed', metadata);
|
||||
|
||||
const logs = loggerTestHelpers.getCapturedLogs();
|
||||
expect(logs.length).toBe(1);
|
||||
expect(logs[0].requestId).toBe('req-123');
|
||||
expect(logs[0].userId).toBe('user-456');
|
||||
expect(logs[0].operation).toBe('data-fetch');
|
||||
});
|
||||
|
||||
it('should handle object messages', () => {
|
||||
const objectMessage = {
|
||||
event: 'user_action',
|
||||
action: 'login',
|
||||
timestamp: Date.now()
|
||||
};
|
||||
|
||||
logger.info(objectMessage);
|
||||
|
||||
const logs = loggerTestHelpers.getCapturedLogs();
|
||||
expect(logs.length).toBe(1);
|
||||
expect(logs[0].level).toBe('info');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue