@debugmcp/mcp-debugger
Version:
Run-time step-through debugging for LLM agents.
151 lines (118 loc) • 4.42 kB
text/typescript
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { handleStdioCommand } from '../../../src/cli/stdio-command.js';
import type { Logger as WinstonLoggerType } from 'winston';
import { DebugMcpServer } from '../../../src/server.js';
vi.mock('../../../src/server.js');
describe('STDIO Command Handler', () => {
let mockLogger: WinstonLoggerType;
let mockServerFactory: ReturnType<typeof vi.fn>;
let mockExitProcess: ReturnType<typeof vi.fn>;
let mockServer: DebugMcpServer;
beforeEach(() => {
// Create mock logger
mockLogger = {
error: vi.fn(),
warn: vi.fn(),
info: vi.fn(),
debug: vi.fn(),
level: 'info'
} as any;
// Create mock server with proper structure
mockServer = {
server: {
connect: vi.fn().mockResolvedValue(undefined)
},
start: vi.fn().mockResolvedValue(undefined),
stop: vi.fn().mockResolvedValue(undefined)
} as any;
// Create mock server factory
mockServerFactory = vi.fn().mockReturnValue(mockServer);
// Create mock exit function
mockExitProcess = vi.fn();
});
it('should start server successfully in stdio mode', async () => {
const options = {
logLevel: 'debug',
logFile: '/tmp/test.log'
};
await handleStdioCommand(options, {
logger: mockLogger,
serverFactory: mockServerFactory,
exitProcess: mockExitProcess
});
// Verify log level was set
expect(mockLogger.level).toBe('debug');
// Verify info log was called
expect(mockLogger.info).toHaveBeenCalledWith('Starting Debug MCP Server in stdio mode');
// Verify server factory was called with correct options
expect(mockServerFactory).toHaveBeenCalledWith({
logLevel: 'debug',
logFile: '/tmp/test.log'
});
// Verify server start was called
expect(mockServer.start).toHaveBeenCalled();
// Verify success log
expect(mockLogger.info).toHaveBeenCalledWith('Server started successfully in stdio mode');
// Verify process did not exit
expect(mockExitProcess).not.toHaveBeenCalled();
});
it('should not change log level if not provided in options', async () => {
const options = {};
mockLogger.level = 'warn';
await handleStdioCommand(options, {
logger: mockLogger,
serverFactory: mockServerFactory,
exitProcess: mockExitProcess
});
// Verify log level was not changed
expect(mockLogger.level).toBe('warn');
// Verify server factory was called with correct options
expect(mockServerFactory).toHaveBeenCalledWith({
logLevel: undefined,
logFile: undefined
});
});
it('should handle server start failure', async () => {
const options = {};
const error = new Error('Server start failed');
// Make server.start reject
mockServer.start = vi.fn().mockRejectedValue(error);
await handleStdioCommand(options, {
logger: mockLogger,
serverFactory: mockServerFactory,
exitProcess: mockExitProcess
});
// Verify error was logged
expect(mockLogger.error).toHaveBeenCalledWith('Failed to start server in stdio mode', { error });
// Verify process exited with code 1
expect(mockExitProcess).toHaveBeenCalledWith(1);
});
it('should use process.exit by default if exitProcess is not provided', async () => {
const processExitSpy = vi.spyOn(process, 'exit').mockImplementation(() => undefined as never);
const error = new Error('Server start failed');
// Make server.start reject
mockServer.start = vi.fn().mockRejectedValue(error);
await handleStdioCommand({}, {
logger: mockLogger,
serverFactory: mockServerFactory
});
// Verify process.exit was called
expect(processExitSpy).toHaveBeenCalledWith(1);
processExitSpy.mockRestore();
});
it('should handle server factory throwing an error', async () => {
const error = new Error('Factory error');
mockServerFactory.mockImplementation(() => {
throw error;
});
await handleStdioCommand({}, {
logger: mockLogger,
serverFactory: mockServerFactory,
exitProcess: mockExitProcess
});
// Verify error was logged
expect(mockLogger.error).toHaveBeenCalledWith('Failed to start server in stdio mode', { error });
// Verify process exited with code 1
expect(mockExitProcess).toHaveBeenCalledWith(1);
});
});