Skip to main content
Glama
server-manager.test.tsโ€ข6.75 kB
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { ServerManager, type ServerManagerOptions } from '../../lib/server-manager.js'; import type { DatabaseConfig } from '../../types/index.js'; // Mock all the dependencies vi.mock('@modelcontextprotocol/sdk/server/index.js', () => ({ Server: vi.fn().mockImplementation(() => ({ setRequestHandler: vi.fn(), connect: vi.fn().mockResolvedValue(undefined), close: vi.fn().mockResolvedValue(undefined) })) })); vi.mock('@modelcontextprotocol/sdk/server/stdio.js', () => ({ StdioServerTransport: vi.fn().mockImplementation(() => ({ start: vi.fn().mockResolvedValue(undefined), close: vi.fn().mockResolvedValue(undefined) })) })); vi.mock('../../lib/logger.js', () => ({ Logger: vi.fn().mockImplementation(() => ({ info: vi.fn(), error: vi.fn(), warn: vi.fn(), debug: vi.fn() })) })); vi.mock('../../lib/database.js', () => ({ LibSQLConnectionPool: vi.fn().mockImplementation(() => ({ initialize: vi.fn().mockResolvedValue(undefined), close: vi.fn().mockResolvedValue(undefined), getConnection: vi.fn().mockResolvedValue({}), getStatus: vi.fn().mockReturnValue({ totalConnections: 1 }) })) })); vi.mock('../../lib/base-tool.js', () => ({ ToolRegistry: vi.fn().mockImplementation(() => ({ register: vi.fn(), getToolDefinitions: vi.fn().mockReturnValue([]), getAll: vi.fn().mockReturnValue([]) })) })); // Mock all the tool imports vi.mock('../../tools/read-query.js', () => ({ ReadQueryTool: vi.fn().mockImplementation(() => ({ name: 'read-query' })) })); vi.mock('../../tools/write-query.js', () => ({ WriteQueryTool: vi.fn().mockImplementation(() => ({ name: 'write-query' })) })); vi.mock('../../tools/create-table.js', () => ({ CreateTableTool: vi.fn().mockImplementation(() => ({ name: 'create-table' })) })); vi.mock('../../tools/alter-table.js', () => ({ AlterTableTool: vi.fn().mockImplementation(() => ({ name: 'alter-table' })) })); vi.mock('../../tools/list-tables.js', () => ({ ListTablesTool: vi.fn().mockImplementation(() => ({ name: 'list-tables' })) })); vi.mock('../../tools/describe-table.js', () => ({ DescribeTableTool: vi.fn().mockImplementation(() => ({ name: 'describe-table' })) })); describe('ServerManager', () => { let serverManager: ServerManager; let mockConfig: DatabaseConfig; let mockOptions: ServerManagerOptions; beforeEach(() => { vi.clearAllMocks(); mockConfig = { url: 'file:///tmp/test.db' }; mockOptions = { config: mockConfig, developmentMode: false, enableHotReload: false }; serverManager = new ServerManager(mockOptions); }); afterEach(async () => { // Clean up any running server if (serverManager.isServerRunning()) { await serverManager.stop(); } }); describe('constructor', () => { it('should create a ServerManager instance', () => { expect(serverManager).toBeInstanceOf(ServerManager); }); it('should accept configuration options', () => { const devOptions: ServerManagerOptions = { config: mockConfig, developmentMode: true, enableHotReload: true }; const devServerManager = new ServerManager(devOptions); expect(devServerManager).toBeInstanceOf(ServerManager); }); }); describe('isServerRunning', () => { it('should return false initially', () => { expect(serverManager.isServerRunning()).toBe(false); }); }); describe('getStatus', () => { it('should return initial status', () => { const status = serverManager.getStatus(); expect(status).toEqual({ running: false, shuttingDown: false }); }); it('should return development mode status', () => { const devOptions: ServerManagerOptions = { config: mockConfig, developmentMode: true, enableHotReload: true }; const devServerManager = new ServerManager(devOptions); const status = devServerManager.getStatus(); expect(status.running).toBe(false); expect(status.shuttingDown).toBe(false); }); }); describe('start', () => { it('should throw error when starting already running server', async () => { // Mock as already running const runningManager = new ServerManager(mockOptions); // Start it first await runningManager.start(); // Try to start again await expect(runningManager.start()).rejects.toThrow('Server is already running'); }); it('should initialize in production mode', async () => { await serverManager.start(); const status = serverManager.getStatus(); expect(status.running).toBe(true); }); it('should initialize in development mode', async () => { const devOptions: ServerManagerOptions = { config: mockConfig, developmentMode: true, enableHotReload: true }; const devServerManager = new ServerManager(devOptions); await devServerManager.start(); const status = devServerManager.getStatus(); expect(status.running).toBe(true); }); }); describe('stop', () => { it('should handle stopping when not running', async () => { // Should not throw await expect(serverManager.stop()).resolves.toBeUndefined(); }); it('should stop running server', async () => { await serverManager.start(); expect(serverManager.isServerRunning()).toBe(true); await serverManager.stop(); expect(serverManager.isServerRunning()).toBe(false); }); }); describe('reload', () => { it('should handle reload when not running', async () => { // Should throw error await expect(serverManager.reload()).rejects.toThrow('Cannot reload: server is not running'); }); it('should reload running server', async () => { await serverManager.start(); // Should not throw await expect(serverManager.reload()).resolves.toBeUndefined(); expect(serverManager.isServerRunning()).toBe(true); }); }); describe('error handling', () => { it('should handle initialization errors', async () => { // Mock database initialization to fail const { LibSQLConnectionPool } = await import('../../lib/database.js'); const mockPool = { initialize: vi.fn().mockRejectedValue(new Error('Database connection failed')), close: vi.fn().mockResolvedValue(undefined) }; vi.mocked(LibSQLConnectionPool).mockImplementation(() => mockPool as any); const errorManager = new ServerManager(mockOptions); await expect(errorManager.start()).rejects.toThrow('Database connection failed'); }); }); });

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/Xexr/mcp-libsql'

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