server.test.ts•6.8 kB
import { McpConfigManager } from '@src/config/mcpConfigManager.js';
import { MCP_SERVER_CAPABILITIES, MCP_SERVER_NAME, MCP_SERVER_VERSION } from '@src/constants.js';
// Import the mocked modules
import logger from '@src/logger/logger.js';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import configReloadService from './application/services/configReloadService.js';
import { ClientManager } from './core/client/clientManager.js';
import { ServerManager } from './core/server/serverManager.js';
import { setupServer } from './server.js';
import { createTransports } from './transport/transportFactory.js';
// Mock dependencies
vi.mock('@src/logger/logger.ts', () => ({
  default: {
    info: vi.fn(),
    error: vi.fn(),
    warn: vi.fn(),
    debug: vi.fn(),
  },
}));
vi.mock('./transport/transportFactory.js', () => ({
  createTransports: vi.fn(),
}));
vi.mock('./core/client/clientManager.js', () => ({
  ClientManager: {
    getOrCreateInstance: vi.fn(),
  },
}));
vi.mock('./core/server/serverManager.js', () => ({
  ServerManager: {
    getOrCreateInstance: vi.fn(),
  },
}));
vi.mock('@src/config/mcpConfigManager.ts', () => ({
  McpConfigManager: {
    getInstance: vi.fn(),
  },
  ConfigChangeEvent: {
    TRANSPORT_CONFIG_CHANGED: 'transportConfigChanged',
  },
}));
vi.mock('./application/services/configReloadService.js', () => ({
  default: {
    initialize: vi.fn(),
  },
}));
describe('server', () => {
  let mockTransports: any;
  let mockClients: any;
  let mockServerManager: any;
  let mockConfigManager: any;
  let mockClientManager: any;
  beforeEach(() => {
    vi.resetAllMocks();
    // Setup mock transports
    mockTransports = {
      stdio: { name: 'stdio' },
      http: { name: 'http' },
    };
    vi.mocked(createTransports).mockReturnValue(mockTransports);
    // Setup mock clients
    mockClients = new Map([
      ['client1', { connect: vi.fn() }],
      ['client2', { connect: vi.fn() }],
    ]);
    mockClientManager = {
      createClients: vi.fn().mockResolvedValue(mockClients),
      initializeClientsAsync: vi.fn().mockReturnValue(mockClients),
      setInstructionAggregator: vi.fn(),
    };
    vi.mocked(ClientManager.getOrCreateInstance).mockReturnValue(mockClientManager);
    // Setup mock server manager
    mockServerManager = {
      start: vi.fn(),
      stop: vi.fn(),
      getStatus: vi.fn().mockReturnValue('running'),
      setInstructionAggregator: vi.fn(),
    };
    vi.mocked(ServerManager.getOrCreateInstance).mockReturnValue(mockServerManager);
    // Setup mock config manager
    mockConfigManager = {
      getTransportConfig: vi.fn().mockReturnValue({ mcpServers: {} }),
    };
    vi.mocked(McpConfigManager.getInstance).mockReturnValue(mockConfigManager);
  });
  describe('setupServer', () => {
    it('should set up server successfully', async () => {
      const result = await setupServer();
      expect(result.serverManager).toBe(mockServerManager);
      expect(result.loadingManager).toBeDefined();
      expect(result.loadingPromise).toBeDefined();
      expect(result.instructionAggregator).toBeDefined();
    });
    it('should get transport configuration from McpConfigManager', async () => {
      // Clear the call count before the test to isolate this test
      vi.mocked(McpConfigManager.getInstance).mockClear();
      vi.mocked(mockConfigManager.getTransportConfig).mockClear();
      await setupServer();
      // Check that methods were called during setupServer
      expect(McpConfigManager.getInstance).toHaveBeenCalled();
      expect(mockConfigManager.getTransportConfig).toHaveBeenCalled();
    });
    it('should create transports from configuration', async () => {
      await setupServer();
      expect(createTransports).toHaveBeenCalledWith({ mcpServers: {} });
    });
    it('should log transport creation', async () => {
      await setupServer();
      expect(logger.info).toHaveBeenCalledWith('Created 2 transports');
    });
    it('should create clients for each transport', async () => {
      await setupServer();
      expect(mockClientManager.createClients).toHaveBeenCalledWith(mockTransports);
    });
    it('should log client creation', async () => {
      await setupServer();
      expect(logger.info).toHaveBeenCalledWith('Connected to 2 MCP servers synchronously');
    });
    it('should create ServerManager instance with correct parameters', async () => {
      await setupServer();
      expect(ServerManager.getOrCreateInstance).toHaveBeenCalledWith(
        { name: MCP_SERVER_NAME, version: MCP_SERVER_VERSION },
        { capabilities: MCP_SERVER_CAPABILITIES },
        mockClients,
        mockTransports,
      );
    });
    it('should initialize config reload service', async () => {
      await setupServer();
      expect(configReloadService.initialize).toHaveBeenCalledWith(mockTransports);
    });
    it('should log successful setup completion', async () => {
      await setupServer();
      expect(logger.info).toHaveBeenCalledWith('Synchronous server setup completed - all MCP servers connected');
    });
    it('should return the ServerManager instance', async () => {
      const result = await setupServer();
      expect(result.serverManager).toBe(mockServerManager);
      expect(result.loadingManager).toBeDefined();
      expect(result.loadingPromise).toBeDefined();
    });
  });
  describe('error handling', () => {
    it('should handle transport creation errors', async () => {
      const error = new Error('Transport creation failed');
      vi.mocked(createTransports).mockImplementation(() => {
        throw error;
      });
      await expect(setupServer()).rejects.toThrow('Transport creation failed');
      expect(logger.error).toHaveBeenCalledWith('Failed to set up server: Transport creation failed');
    });
    it('should handle client creation errors gracefully with sync loading', async () => {
      const error = new Error('Client creation failed');
      mockClientManager.createClients.mockRejectedValue(error);
      await expect(setupServer()).rejects.toThrow('Client creation failed');
      expect(mockClientManager.createClients).toHaveBeenCalled();
    });
    it('should handle ServerManager creation errors', async () => {
      const error = new Error('ServerManager creation failed');
      vi.mocked(ServerManager.getOrCreateInstance).mockImplementation(() => {
        throw error;
      });
      await expect(setupServer()).rejects.toThrow('ServerManager creation failed');
    });
    it('should rethrow errors after logging', async () => {
      const error = new Error('Test error');
      vi.mocked(createTransports).mockImplementation(() => {
        throw error;
      });
      await expect(setupServer()).rejects.toThrow(error);
    });
  });
});