Skip to main content
Glama
index.test.ts7.63 kB
/** * Tests for centralized logger utility */ import winston from 'winston'; import { LogContext, LogLevel, TeamCityLogger, createLogger, getLogger } from './index'; describe('TeamCityLogger', () => { let mockLogger: jest.Mocked<winston.Logger>; beforeEach(() => { mockLogger = { debug: jest.fn(), info: jest.fn(), warn: jest.fn(), error: jest.fn(), child: jest.fn(), level: 'info', end: jest.fn(), } as unknown as jest.Mocked<winston.Logger>; jest.spyOn(winston, 'createLogger').mockReturnValue(mockLogger); }); afterEach(() => { jest.restoreAllMocks(); }); describe('constructor', () => { // Removed env-var dependent test: default configuration based on NODE_ENV/LOG_LEVEL it('should create logger with custom configuration', () => { const config = { name: 'test-service', level: 'debug' as LogLevel, enableConsole: true, enableFile: false, }; new TeamCityLogger(config); expect(winston.createLogger).toHaveBeenCalledWith( expect.objectContaining({ level: 'debug', defaultMeta: { service: 'test-service' }, }) ); }); // Removed env-var dependent test: LOG_LEVEL override from environment }); describe('logging methods', () => { let teamCityLogger: TeamCityLogger; beforeEach(() => { teamCityLogger = new TeamCityLogger(); }); it('should log debug messages', () => { const context: LogContext = { toolName: 'test-tool', requestId: 'req-123' }; teamCityLogger.debug('Debug message', context); expect(mockLogger.debug).toHaveBeenCalledWith('Debug message', context); }); it('should log info messages', () => { const context: LogContext = { buildId: 'build-456' }; teamCityLogger.info('Info message', context); expect(mockLogger.info).toHaveBeenCalledWith('Info message', context); }); it('should log warn messages', () => { teamCityLogger.warn('Warning message'); expect(mockLogger.warn).toHaveBeenCalledWith('Warning message', {}); }); it('should log error messages with Error object', () => { const error = new Error('Test error'); const context: LogContext = { projectId: 'proj-789' }; teamCityLogger.error('Error message', error, context); expect(mockLogger.error).toHaveBeenCalledWith('Error message', { ...context, error: 'Test error', stack: error.stack, }); }); it('should log error messages with string error', () => { teamCityLogger.error('Error message', 'String error'); expect(mockLogger.error).toHaveBeenCalledWith('Error message', { error: 'String error', }); }); it('should log error messages without error object', () => { teamCityLogger.error('Error message'); expect(mockLogger.error).toHaveBeenCalledWith('Error message', {}); }); }); describe('utility methods', () => { let teamCityLogger: TeamCityLogger; beforeEach(() => { teamCityLogger = new TeamCityLogger(); }); it('should generate unique request IDs', () => { const id1 = teamCityLogger.generateRequestId(); const id2 = teamCityLogger.generateRequestId(); expect(id1).toBeDefined(); expect(id2).toBeDefined(); expect(id1).not.toBe(id2); expect(id1).toMatch(/^\d+-\d+$/); }); it('should create child logger', () => { const childLogger = {} as winston.Logger; mockLogger.child.mockReturnValue(childLogger); const context: LogContext = { service: 'child-service' }; const result = teamCityLogger.child(context); expect(mockLogger.child).toHaveBeenCalledWith(context); expect(result).toBeInstanceOf(TeamCityLogger); }); it('should log tool execution - success', () => { const toolName = 'test-tool'; const args = { param1: 'value1' }; const result = { success: true }; const duration = 150; const context: LogContext = { requestId: 'req-123' }; teamCityLogger.logToolExecution(toolName, args, result, duration, context); expect(mockLogger.info).toHaveBeenCalledWith(`Tool executed successfully: ${toolName}`, { ...context, toolName, duration, args: JSON.stringify(args), success: true, }); }); it('should log tool execution - failure', () => { const toolName = 'test-tool'; const args = { param1: 'value1' }; const result = { success: false, error: 'Tool failed' }; const duration = 75; teamCityLogger.logToolExecution(toolName, args, result, duration); expect(mockLogger.error).toHaveBeenCalledWith(`Tool execution failed: ${toolName}`, { toolName, duration, args: JSON.stringify(args), success: false, error: 'Tool failed', }); }); it('should log TeamCity API requests', () => { const method = 'GET'; const url = '/api/builds'; const status = 200; const duration = 250; const context: LogContext = { requestId: 'req-456' }; teamCityLogger.logTeamCityRequest(method, url, status, duration, context); expect(mockLogger.debug).toHaveBeenCalledWith(`TeamCity API request: ${method} ${url}`, { ...context, method, url, status, duration, }); }); it('should log failed TeamCity API requests', () => { const method = 'POST'; const url = '/api/builds/trigger'; const status = 500; const duration = 1000; teamCityLogger.logTeamCityRequest(method, url, status, duration); expect(mockLogger.warn).toHaveBeenCalledWith( `TeamCity API request failed: ${method} ${url}`, { method, url, status, duration, } ); }); it('should log lifecycle events', () => { const event = 'server_start'; const details = { port: 3000, env: 'development' }; teamCityLogger.logLifecycle(event, details); expect(mockLogger.info).toHaveBeenCalledWith(`Server lifecycle: ${event}`, { lifecycle: event, ...details, }); }); it('should set and get log level', () => { teamCityLogger.setLevel('debug'); expect(mockLogger.level).toBe('debug'); expect(teamCityLogger.getLevel()).toBe('debug'); }); it('should get Winston instance', () => { const winston = teamCityLogger.getWinstonInstance(); expect(winston).toBe(mockLogger); }); }); }); describe('factory functions', () => { beforeEach(() => { // Clear module cache to reset singleton jest.clearAllMocks(); }); describe('createLogger', () => { it('should create new logger instance', () => { const logger = createLogger({ name: 'test-logger' }); expect(logger).toBeInstanceOf(TeamCityLogger); }); }); describe('getLogger', () => { it('should return singleton logger instance', () => { const logger1 = getLogger(); const logger2 = getLogger(); expect(logger1).toBe(logger2); expect(logger1).toBeInstanceOf(TeamCityLogger); }); it('should create new instance with config', () => { const config = { name: 'new-logger' }; const logger1 = getLogger(); const logger2 = getLogger(config); expect(logger1).not.toBe(logger2); }); }); }); // Convenience logger object tests removed - they're integration tests // The logger functionality is adequately tested through the class methods above

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Daghis/teamcity-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server