qapinterface
Version:
Comprehensive API utilities for Node.js applications including authentication, security, request processing, and response handling with zero external dependencies
458 lines (357 loc) • 14.6 kB
JavaScript
/**
* Comprehensive unit tests for logging modules
* Tests logger creation, memory monitoring, and logging utilities with mocked dependencies
*/
const { expect } = require('chai');
const sinon = require('sinon');
// Import modules to test
const { createLogger } = require('../logging/logger-creator');
const { closeLogger } = require('../logging/logger-closer');
const { getLoggerInstance } = require('../logging/logger-instance');
const { startMemoryMonitoring } = require('../logging/memory-monitor-starter');
const { stopMemoryMonitoring } = require('../logging/memory-monitor-stopper');
const { initializeLogger, logger } = require('../asyncLogger');
const { memoryMonitor } = require('../utility/memoryMonitor');
describe('Logging Module Tests', () => {
describe('Logger Creator', () => {
it('should create logger instance', async () => {
const loggerInstance = await createLogger();
expect(typeof loggerInstance).to.equal('object');
expect(typeof loggerInstance.info).to.equal('function');
expect(typeof loggerInstance.error).to.equal('function');
expect(typeof loggerInstance.warn).to.equal('function');
expect(typeof loggerInstance.debug).to.equal('function');
});
it('should create logger with custom configuration', async () => {
const config = {
level: 'debug',
name: 'test-logger',
prettyPrint: true
};
const loggerInstance = await createLogger(config);
expect(typeof loggerInstance).to.equal('object');
expect(typeof loggerInstance.info).to.equal('function');
});
it('should handle logger creation errors', async () => {
// Mock error in logger creation
const originalConsoleError = console.error;
let errorLogged = false;
console.error = () => { errorLogged = true; };
try {
// Pass invalid configuration to trigger error
await createLogger({ invalidOption: 'invalid' });
} catch (error) {
expect(error instanceof Error).to.equal(true);
}
console.error = originalConsoleError;
});
it('should create logger with file output', async () => {
const config = {
level: 'info',
destination: './logs/test.log'
};
const loggerInstance = await createLogger(config);
expect(typeof loggerInstance).to.equal('object');
expect(typeof loggerInstance.info).to.equal('function');
});
it('should support different log levels', async () => {
const levels = ['fatal', 'error', 'warn', 'info', 'debug', 'trace'];
for (const level of levels) {
const loggerInstance = await createLogger({ level });
expect(typeof loggerInstance).to.equal('object');
}
});
});
describe('Logger Instance Management', () => {
it('should get current logger instance', () => {
const instance = getLoggerInstance();
// May be null if not initialized yet
if (instance) {
expect(typeof instance).to.equal('object');
expect(typeof instance.info).to.equal('function');
} else {
expect(instance).to.equal(null);
}
});
it('should handle logger instance updates', async () => {
const newLogger = await createLogger({ name: 'new-logger' });
// Assuming there's a setLoggerInstance function
if (typeof setLoggerInstance === 'function') {
setLoggerInstance(newLogger);
const retrievedInstance = getLoggerInstance();
expect(retrievedInstance).to.equal(newLogger);
}
});
});
describe('Logger Closer', () => {
it('should close logger gracefully', async () => {
const loggerInstance = await createLogger();
const closeResult = await closeLogger(loggerInstance);
// Should complete without throwing
expect(typeof closeResult).to.equal('undefined');
});
it('should handle closing null logger', async () => {
const closeResult = await closeLogger(null);
// Should handle gracefully
expect(typeof closeResult).to.equal('undefined');
});
it('should handle logger closing errors', async () => {
const mockLogger = {
flush: () => { throw new Error('Flush error'); }
};
try {
await closeLogger(mockLogger);
} catch (error) {
expect(error.message).to.equal('Flush error');
}
});
});
describe('Async Logger Initialization', () => {
it('should initialize logger asynchronously', async () => {
const loggerInstance = await initializeLogger();
expect(typeof loggerInstance).to.equal('object');
expect(typeof loggerInstance.info).to.equal('function');
});
it('should provide global logger access', () => {
// The logger getter should work
const globalLogger = logger;
if (globalLogger) {
expect(typeof globalLogger).to.equal('object');
}
});
it('should handle initialization errors', async () => {
// Mock createLogger to throw error
const originalRequire = require;
require = jest.fn((path) => {
if (path.includes('logger-creator')) {
return {
createLogger: () => { throw new Error('Init error'); }
};
}
return originalRequire(path);
});
const originalConsoleError = console.error;
let errorLogged = false;
console.error = () => { errorLogged = true; };
try {
await initializeLogger();
} catch (error) {
expect(error.message).to.equal('Init error');
expect(errorLogged).to.equal(true);
}
console.error = originalConsoleError;
require = originalRequire;
});
});
describe('Memory Monitor', () => {
it('should start memory monitoring', () => {
const monitor = memoryMonitor();
expect(typeof monitor).to.equal('object');
expect(typeof monitor.getUsage).to.equal('function');
expect(typeof monitor.startMonitoring).to.equal('function');
expect(typeof monitor.stopMonitoring).to.equal('function');
});
it('should get current memory usage', () => {
const monitor = memoryMonitor();
const usage = monitor.getUsage();
expect(typeof usage).to.equal('object');
expect(typeof usage.heapUsed).to.equal('number');
expect(typeof usage.heapTotal).to.equal('number');
expect(typeof usage.external).to.equal('number');
expect(usage.heapUsed > 0).to.equal(true);
});
it('should monitor memory over time', (done) => {
const monitor = memoryMonitor();
let sampleCount = 0;
monitor.startMonitoring((usage) => {
sampleCount++;
expect(typeof usage.heapUsed).to.equal('number');
if (sampleCount >= 3) {
monitor.stopMonitoring();
expect(sampleCount >= 3).to.equal(true);
done();
}
}, 100); // 100ms interval
});
it('should detect memory leaks', () => {
const monitor = memoryMonitor();
const initialUsage = monitor.getUsage();
// Create some objects to increase memory usage
const largeArray = new Array(10000).fill('memory test data');
const newUsage = monitor.getUsage();
expect(newUsage.heapUsed > initialUsage.heapUsed).to.equal(true);
// Clean up
largeArray.length = 0;
});
it('should format memory usage output', () => {
const monitor = memoryMonitor();
const formatted = monitor.formatUsage();
expect(typeof formatted).to.equal('string');
expect(formatted.includes('MB')).to.equal(true);
expect(formatted.includes('Heap')).to.equal(true);
});
it('should track memory trends', () => {
const monitor = memoryMonitor();
const trend = monitor.getTrend();
// Initially should have no trend data
if (trend) {
expect(typeof trend).to.equal('object');
expect(typeof trend.direction).to.equal('string');
expect(typeof trend.rate).to.equal('number');
}
});
});
describe('Memory Monitor Starter/Stopper', () => {
it('should start memory monitoring service', async () => {
const monitoringId = await startMemoryMonitoring({
interval: 1000,
threshold: 100 // 100MB threshold
});
expect(typeof monitoringId).to.equal('string');
expect(monitoringId.length > 0).to.equal(true);
});
it('should stop memory monitoring service', async () => {
const monitoringId = await startMemoryMonitoring({ interval: 1000 });
const stopped = await stopMemoryMonitoring(monitoringId);
expect(stopped).to.equal(true);
});
it('should handle invalid monitoring ID', async () => {
const stopped = await stopMemoryMonitoring('invalid-id');
expect(stopped).to.equal(false);
});
it('should configure monitoring thresholds', async () => {
const monitoringId = await startMemoryMonitoring({
interval: 500,
threshold: 50, // 50MB
alertCallback: (usage) => {
expect(typeof usage).to.equal('object');
}
});
expect(typeof monitoringId).to.equal('string');
// Clean up
await stopMemoryMonitoring(monitoringId);
});
});
describe('Console Logger Integration', () => {
it('should integrate with console logger', () => {
const { log, logError, logWarn, logInfo } = require('../utility/console-logger');
const originalLog = console.log;
const originalError = console.error;
const originalWarn = console.warn;
let logCalled = false;
let errorCalled = false;
let warnCalled = false;
console.log = () => { logCalled = true; };
console.error = () => { errorCalled = true; };
console.warn = () => { warnCalled = true; };
log('Test log message');
logError('Test error message');
logWarn('Test warning message');
logInfo('Test info message');
console.log = originalLog;
console.error = originalError;
console.warn = originalWarn;
expect(logCalled).to.equal(true);
expect(errorCalled).to.equal(true);
expect(warnCalled).to.equal(true);
});
it('should create source-bound loggers', () => {
const { createSourceLogger } = require('../utility/console-logger');
const apiLogger = createSourceLogger('API');
expect(typeof apiLogger).to.equal('object');
expect(typeof apiLogger.log).to.equal('function');
expect(typeof apiLogger.error).to.equal('function');
expect(typeof apiLogger.warn).to.equal('function');
expect(typeof apiLogger.info).to.equal('function');
});
it('should format timestamps correctly', () => {
const { logWithCustomTime } = require('../utility/console-logger');
const originalLog = console.log;
let loggedMessage = '';
console.log = (message) => { loggedMessage = message; };
const customTime = new Date('2025-01-01T12:30:45Z');
logWithCustomTime('Test message', customTime);
console.log = originalLog;
expect(loggedMessage.includes('12:30:45')).to.equal(true);
expect(loggedMessage.includes('Test message')).to.equal(true);
});
});
describe('Logging Integration Tests', () => {
it('should coordinate multiple logging systems', async () => {
// Initialize async logger
const asyncLoggerInstance = await initializeLogger();
// Start memory monitoring
const monitoringId = await startMemoryMonitoring({ interval: 1000 });
// Use console logger
const { log } = require('../utility/console-logger');
const originalLog = console.log;
let consoleLogCalled = false;
console.log = () => { consoleLogCalled = true; };
log('Integration test message');
console.log = originalLog;
expect(typeof asyncLoggerInstance).to.equal('object');
expect(typeof monitoringId).to.equal('string');
expect(consoleLogCalled).to.equal(true);
// Clean up
await stopMemoryMonitoring(monitoringId);
});
it('should handle logging errors gracefully', async () => {
const originalConsoleError = console.error;
let errorHandled = false;
console.error = () => { errorHandled = true; };
try {
// Force an error in logging
const badLogger = { info: () => { throw new Error('Log error'); } };
badLogger.info('This should fail');
} catch (error) {
expect(error.message).to.equal('Log error');
}
console.error = originalConsoleError;
});
it('should maintain performance under load', async () => {
const { log } = require('../utility/console-logger');
const originalLog = console.log;
let logCount = 0;
console.log = () => { logCount++; };
const startTime = Date.now();
// Log many messages quickly
for (let i = 0; i < 1000; i++) {
log(`Test message ${i}`);
}
const endTime = Date.now();
const duration = endTime - startTime;
console.log = originalLog;
expect(logCount).to.equal(1000);
expect(duration < 5000).to.equal(true); // Should complete in under 5 seconds
});
it('should rotate logs when configured', async () => {
const config = {
level: 'info',
destination: './logs/rotating.log',
rotate: {
size: '10MB',
count: 5
}
};
const loggerInstance = await createLogger(config);
expect(typeof loggerInstance).to.equal('object');
expect(typeof loggerInstance.info).to.equal('function');
});
it('should handle structured logging', async () => {
const loggerInstance = await createLogger({ level: 'info' });
if (loggerInstance && loggerInstance.info) {
// Should accept structured data
loggerInstance.info({
message: 'Structured log entry',
userId: 123,
action: 'login',
timestamp: new Date().toISOString()
});
// Should also accept string messages
loggerInstance.info('Simple string message');
}
expect(typeof loggerInstance).to.equal('object');
});
});
});
module.exports = { runLoggingTests: () => expect().to.be.undefined };