test(server): 添加 server 模块单元测试
- 新增 vitest 配置和测试基础设施 - 添加 adapter.test.ts: 测试 Core 模块初始化和 Agent 管理 (18 tests) - 添加 token.test.ts: 测试 Token 生成、验证和中间件 (25 tests) - 添加 handler.test.ts: 测试权限处理器 (18 tests) - 添加 ws.test.ts: 测试 WebSocket 连接和消息处理 (19 tests) - 添加 sse.test.ts: 测试 SSE 事件发送 (14 tests) - 添加 sessions.test.ts: 测试会话路由 (16 tests) - 添加 config.test.ts: 测试配置路由 (10 tests) - 添加 context.test.ts: 测试上下文压缩路由 (9 tests) - 添加 providers.test.ts: 测试 Provider 管理路由 (18 tests) - 添加 manager.test.ts: 测试 SessionManager (48 tests) 总计 195 个测试,覆盖率从 0% 提升至 29.59%
This commit is contained in:
@@ -0,0 +1,341 @@
|
||||
/**
|
||||
* Agent Adapter 测试
|
||||
*
|
||||
* 测试 initCore、getOrCreateAgent、配置错误处理等关键功能
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import {
|
||||
createMockCoreModule,
|
||||
createMockProviderRegistry,
|
||||
createMockAgentRegistry,
|
||||
createConfigurationErrorMock,
|
||||
} from '../../mocks/core.mock.js';
|
||||
|
||||
// 由于 adapter.ts 使用动态 import,需要特殊处理
|
||||
// 我们需要在每个测试中重新导入模块以确保 mock 生效
|
||||
|
||||
describe('Agent Adapter', () => {
|
||||
// 存储原始模块状态
|
||||
let originalCwd: typeof process.cwd;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.resetModules();
|
||||
originalCwd = process.cwd;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
process.cwd = originalCwd;
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('initCore - Core 模块初始化', () => {
|
||||
it('成功加载 Core 模块时返回 true', async () => {
|
||||
const mockCore = createMockCoreModule();
|
||||
|
||||
vi.doMock('@ai-assistant/core', () => mockCore);
|
||||
|
||||
const { initCore } = await import('../../../src/agent/adapter.js');
|
||||
const result = await initCore();
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('Core 模块缺少必要导出时返回 false', async () => {
|
||||
const incompleteCore = {
|
||||
Agent: undefined,
|
||||
toolRegistry: undefined,
|
||||
loadConfig: undefined,
|
||||
};
|
||||
|
||||
vi.doMock('@ai-assistant/core', () => incompleteCore);
|
||||
|
||||
const { initCore } = await import('../../../src/agent/adapter.js');
|
||||
const result = await initCore();
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('Core 模块加载失败时返回 false', async () => {
|
||||
vi.doMock('@ai-assistant/core', () => {
|
||||
throw new Error('Module not found');
|
||||
});
|
||||
|
||||
const { initCore } = await import('../../../src/agent/adapter.js');
|
||||
const result = await initCore();
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('调用 ProviderRegistry.init()', async () => {
|
||||
const mockProviderRegistry = createMockProviderRegistry({
|
||||
isInitialized: vi.fn().mockReturnValue(false),
|
||||
});
|
||||
const mockCore = createMockCoreModule({
|
||||
providerRegistry: mockProviderRegistry,
|
||||
});
|
||||
|
||||
vi.doMock('@ai-assistant/core', () => mockCore);
|
||||
|
||||
const { initCore } = await import('../../../src/agent/adapter.js');
|
||||
await initCore();
|
||||
|
||||
expect(mockCore.getProviderRegistry().init).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('ProviderRegistry 已初始化时不重复调用 init()', async () => {
|
||||
const mockProviderRegistry = createMockProviderRegistry({
|
||||
isInitialized: vi.fn().mockReturnValue(true),
|
||||
});
|
||||
const mockCore = createMockCoreModule({
|
||||
providerRegistry: mockProviderRegistry,
|
||||
});
|
||||
|
||||
vi.doMock('@ai-assistant/core', () => mockCore);
|
||||
|
||||
const { initCore } = await import('../../../src/agent/adapter.js');
|
||||
await initCore();
|
||||
|
||||
expect(mockCore.getProviderRegistry().init).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('调用 AgentRegistry.init() 并传入 process.cwd()', async () => {
|
||||
const testCwd = '/test/workdir';
|
||||
process.cwd = vi.fn().mockReturnValue(testCwd);
|
||||
|
||||
const mockAgentRegistry = createMockAgentRegistry({
|
||||
isInitialized: vi.fn().mockReturnValue(false),
|
||||
});
|
||||
const mockCore = createMockCoreModule({
|
||||
agentRegistry: mockAgentRegistry,
|
||||
});
|
||||
|
||||
vi.doMock('@ai-assistant/core', () => mockCore);
|
||||
|
||||
const { initCore } = await import('../../../src/agent/adapter.js');
|
||||
await initCore();
|
||||
|
||||
expect(mockCore.agentRegistry.init).toHaveBeenCalledWith(testCwd);
|
||||
});
|
||||
|
||||
it('AgentRegistry 已初始化时不重复调用 init()', async () => {
|
||||
const mockAgentRegistry = createMockAgentRegistry({
|
||||
isInitialized: vi.fn().mockReturnValue(true),
|
||||
});
|
||||
const mockCore = createMockCoreModule({
|
||||
agentRegistry: mockAgentRegistry,
|
||||
});
|
||||
|
||||
vi.doMock('@ai-assistant/core', () => mockCore);
|
||||
|
||||
const { initCore } = await import('../../../src/agent/adapter.js');
|
||||
await initCore();
|
||||
|
||||
expect(mockCore.agentRegistry.init).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('isCoreAvailable - Core 模块可用性检查', () => {
|
||||
it('Core 未初始化时返回 false', async () => {
|
||||
vi.resetModules();
|
||||
const { isCoreAvailable } = await import('../../../src/agent/adapter.js');
|
||||
expect(isCoreAvailable()).toBe(false);
|
||||
});
|
||||
|
||||
it('Core 初始化后返回 true', async () => {
|
||||
const mockCore = createMockCoreModule();
|
||||
vi.doMock('@ai-assistant/core', () => mockCore);
|
||||
|
||||
const { initCore, isCoreAvailable } = await import('../../../src/agent/adapter.js');
|
||||
await initCore();
|
||||
|
||||
expect(isCoreAvailable()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getOrCreateAgent - Agent 创建与缓存', () => {
|
||||
it('Core 未初始化时返回 null', async () => {
|
||||
vi.resetModules();
|
||||
const { getOrCreateAgent } = await import('../../../src/agent/adapter.js');
|
||||
const agent = getOrCreateAgent('session-1');
|
||||
expect(agent).toBeNull();
|
||||
});
|
||||
|
||||
it('成功创建 Agent 实例', async () => {
|
||||
const mockCore = createMockCoreModule();
|
||||
vi.doMock('@ai-assistant/core', () => mockCore);
|
||||
|
||||
// Mock session manager
|
||||
vi.doMock('../../../src/session/manager.js', () => ({
|
||||
getSessionManager: vi.fn().mockReturnValue({
|
||||
exists: vi.fn().mockReturnValue(true),
|
||||
get: vi.fn().mockReturnValue({ id: 'session-1' }),
|
||||
}),
|
||||
}));
|
||||
|
||||
// Mock permission handler
|
||||
vi.doMock('../../../src/permission/handler.js', () => ({
|
||||
createServerPermissionCallback: vi.fn().mockReturnValue(async () => ({ allow: true })),
|
||||
}));
|
||||
|
||||
const { initCore, getOrCreateAgent } = await import('../../../src/agent/adapter.js');
|
||||
await initCore();
|
||||
|
||||
const agent = getOrCreateAgent('session-1');
|
||||
|
||||
expect(agent).not.toBeNull();
|
||||
expect(mockCore.Agent).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('重复获取同一 session 返回缓存的 Agent', async () => {
|
||||
const mockCore = createMockCoreModule();
|
||||
vi.doMock('@ai-assistant/core', () => mockCore);
|
||||
|
||||
vi.doMock('../../../src/session/manager.js', () => ({
|
||||
getSessionManager: vi.fn().mockReturnValue({
|
||||
exists: vi.fn().mockReturnValue(true),
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.doMock('../../../src/permission/handler.js', () => ({
|
||||
createServerPermissionCallback: vi.fn().mockReturnValue(async () => ({ allow: true })),
|
||||
}));
|
||||
|
||||
const { initCore, getOrCreateAgent } = await import('../../../src/agent/adapter.js');
|
||||
await initCore();
|
||||
|
||||
const agent1 = getOrCreateAgent('session-1');
|
||||
const agent2 = getOrCreateAgent('session-1');
|
||||
|
||||
expect(agent1).toBe(agent2);
|
||||
// Agent 构造函数只应被调用一次
|
||||
expect(mockCore.Agent).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('ConfigurationError 时返回 null', async () => {
|
||||
const mockCore = createMockCoreModule({
|
||||
loadConfig: createConfigurationErrorMock('未配置 API Key', 'deepseek'),
|
||||
});
|
||||
vi.doMock('@ai-assistant/core', () => mockCore);
|
||||
|
||||
vi.doMock('../../../src/session/manager.js', () => ({
|
||||
getSessionManager: vi.fn().mockReturnValue({
|
||||
exists: vi.fn().mockReturnValue(true),
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.doMock('../../../src/permission/handler.js', () => ({
|
||||
createServerPermissionCallback: vi.fn().mockReturnValue(async () => ({ allow: true })),
|
||||
}));
|
||||
|
||||
const { initCore, getOrCreateAgent } = await import('../../../src/agent/adapter.js');
|
||||
await initCore();
|
||||
|
||||
const agent = getOrCreateAgent('session-1');
|
||||
|
||||
expect(agent).toBeNull();
|
||||
});
|
||||
|
||||
it('非 ConfigurationError 时重新抛出', async () => {
|
||||
const mockCore = createMockCoreModule({
|
||||
loadConfig: vi.fn().mockImplementation(() => {
|
||||
throw new Error('Other error');
|
||||
}),
|
||||
});
|
||||
vi.doMock('@ai-assistant/core', () => mockCore);
|
||||
|
||||
vi.doMock('../../../src/session/manager.js', () => ({
|
||||
getSessionManager: vi.fn().mockReturnValue({
|
||||
exists: vi.fn().mockReturnValue(true),
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.doMock('../../../src/permission/handler.js', () => ({
|
||||
createServerPermissionCallback: vi.fn().mockReturnValue(async () => ({ allow: true })),
|
||||
}));
|
||||
|
||||
const { initCore, getOrCreateAgent } = await import('../../../src/agent/adapter.js');
|
||||
await initCore();
|
||||
|
||||
expect(() => getOrCreateAgent('session-1')).toThrow('Other error');
|
||||
});
|
||||
});
|
||||
|
||||
describe('destroyAgent - Agent 销毁', () => {
|
||||
it('从缓存中移除 Agent', async () => {
|
||||
const mockCore = createMockCoreModule();
|
||||
vi.doMock('@ai-assistant/core', () => mockCore);
|
||||
|
||||
vi.doMock('../../../src/session/manager.js', () => ({
|
||||
getSessionManager: vi.fn().mockReturnValue({
|
||||
exists: vi.fn().mockReturnValue(true),
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.doMock('../../../src/permission/handler.js', () => ({
|
||||
createServerPermissionCallback: vi.fn().mockReturnValue(async () => ({ allow: true })),
|
||||
}));
|
||||
|
||||
const { initCore, getOrCreateAgent, destroyAgent } = await import('../../../src/agent/adapter.js');
|
||||
await initCore();
|
||||
|
||||
// 创建 Agent
|
||||
getOrCreateAgent('session-1');
|
||||
expect(mockCore.Agent).toHaveBeenCalledTimes(1);
|
||||
|
||||
// 销毁 Agent
|
||||
destroyAgent('session-1');
|
||||
|
||||
// 再次获取应创建新 Agent
|
||||
getOrCreateAgent('session-1');
|
||||
expect(mockCore.Agent).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAgentStats - Agent 统计信息', () => {
|
||||
it('Core 未初始化时返回 available: false', async () => {
|
||||
vi.resetModules();
|
||||
const { getAgentStats } = await import('../../../src/agent/adapter.js');
|
||||
const stats = getAgentStats('session-1');
|
||||
expect(stats).toEqual({ available: false });
|
||||
});
|
||||
|
||||
it('Agent 不存在时返回 available: true 但无其他信息', async () => {
|
||||
const mockCore = createMockCoreModule();
|
||||
vi.doMock('@ai-assistant/core', () => mockCore);
|
||||
|
||||
const { initCore, getAgentStats } = await import('../../../src/agent/adapter.js');
|
||||
await initCore();
|
||||
|
||||
const stats = getAgentStats('non-existent-session');
|
||||
expect(stats).toEqual({ available: true });
|
||||
});
|
||||
|
||||
it('Agent 存在时返回完整统计信息', async () => {
|
||||
const mockCore = createMockCoreModule();
|
||||
vi.doMock('@ai-assistant/core', () => mockCore);
|
||||
|
||||
vi.doMock('../../../src/session/manager.js', () => ({
|
||||
getSessionManager: vi.fn().mockReturnValue({
|
||||
exists: vi.fn().mockReturnValue(true),
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.doMock('../../../src/permission/handler.js', () => ({
|
||||
createServerPermissionCallback: vi.fn().mockReturnValue(async () => ({ allow: true })),
|
||||
}));
|
||||
|
||||
const { initCore, getOrCreateAgent, getAgentStats } = await import('../../../src/agent/adapter.js');
|
||||
await initCore();
|
||||
|
||||
// 创建 Agent
|
||||
getOrCreateAgent('session-1');
|
||||
|
||||
const stats = getAgentStats('session-1');
|
||||
expect(stats.available).toBe(true);
|
||||
expect(stats.toolCount).toEqual({ core: 5, discovered: 0, total: 5 });
|
||||
expect(stats.contextUsage).toBe('10k / 200k');
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user