bca19b7741
新增测试文件: - agent/executor-extended.test.ts, presets/ - context/manager-extended.test.ts - core/agent.test.ts, providers.test.ts - lsp/cli.test.ts, client-extended.test.ts, index.test.ts - permission/file-prompt.test.ts, prompt.test.ts - skills/builtin/ - tools/filesystem/write_file-extended.test.ts - tools/git/git_commit-extended.test.ts - tools/load_description.test.ts - tools/todo/todo-manager.test.ts - tools/tool-search.test.ts - types/ - utils/config-extended.test.ts, diff-extended.test.ts 修改现有测试: - agent/manager.test.ts - tools/skill/skill.test.ts - utils/config.test.ts, diff.test.ts, image.test.ts
327 lines
8.8 KiB
TypeScript
327 lines
8.8 KiB
TypeScript
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
import { AgentManager, resetAgentManager, getAgentManager } from '../../../src/agent/manager.js';
|
|
import type { AgentInfo } from '../../../src/agent/types.js';
|
|
import type { AgentConfig } from '../../../src/types/index.js';
|
|
|
|
// Mock AgentExecutor - 使用延迟执行
|
|
vi.mock('../../../src/agent/executor.js', () => ({
|
|
AgentExecutor: vi.fn().mockImplementation(() => ({
|
|
execute: vi.fn().mockImplementation(async () => {
|
|
// 延迟 200ms,让测试能在执行完成前检查状态
|
|
await new Promise((r) => setTimeout(r, 200));
|
|
return {
|
|
success: true,
|
|
text: '任务完成',
|
|
steps: 3,
|
|
sessionId: 'test-session',
|
|
};
|
|
}),
|
|
})),
|
|
}));
|
|
|
|
describe('AgentManager - Agent 管理器', () => {
|
|
let manager: AgentManager;
|
|
const mockAgentInfo: AgentInfo = {
|
|
name: 'test-agent',
|
|
description: '测试 Agent',
|
|
mode: 'subagent',
|
|
prompt: '你是一个测试助手',
|
|
};
|
|
|
|
const mockConfig: AgentConfig = {
|
|
provider: 'anthropic',
|
|
apiKey: 'test-key',
|
|
model: 'claude-3-5-sonnet-20241022',
|
|
maxTokens: 4096,
|
|
systemPrompt: '测试系统提示词',
|
|
};
|
|
|
|
const mockContext = {
|
|
parentSessionId: 'parent-123',
|
|
workdir: '/test',
|
|
};
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
resetAgentManager();
|
|
manager = new AgentManager();
|
|
});
|
|
|
|
describe('getAgentManager - 单例获取', () => {
|
|
it('返回相同的实例', () => {
|
|
resetAgentManager();
|
|
const instance1 = getAgentManager();
|
|
const instance2 = getAgentManager();
|
|
expect(instance1).toBe(instance2);
|
|
});
|
|
|
|
it('resetAgentManager 重置实例', () => {
|
|
const instance1 = getAgentManager();
|
|
resetAgentManager();
|
|
const instance2 = getAgentManager();
|
|
expect(instance1).not.toBe(instance2);
|
|
});
|
|
});
|
|
|
|
describe('runInBackground - 后台运行', () => {
|
|
it('返回 agent ID', async () => {
|
|
const agentId = await manager.runInBackground(
|
|
mockAgentInfo,
|
|
'测试任务',
|
|
'执行测试',
|
|
mockConfig,
|
|
{} as any,
|
|
mockContext
|
|
);
|
|
|
|
expect(agentId).toBeDefined();
|
|
expect(typeof agentId).toBe('string');
|
|
expect(agentId.length).toBe(8); // 短 ID
|
|
});
|
|
|
|
it('创建初始状态的记录', async () => {
|
|
const agentId = await manager.runInBackground(
|
|
mockAgentInfo,
|
|
'测试任务',
|
|
'执行测试',
|
|
mockConfig,
|
|
{} as any,
|
|
mockContext
|
|
);
|
|
|
|
const agent = manager.getAgent(agentId);
|
|
expect(agent).not.toBeNull();
|
|
expect(agent!.agentName).toBe('test-agent');
|
|
expect(agent!.description).toBe('测试任务');
|
|
expect(agent!.prompt).toBe('执行测试');
|
|
expect(agent!.startedAt).toBeInstanceOf(Date);
|
|
// 由于是异步执行,初始状态应该是 running
|
|
// 但由于测试环境的原因,可能已经变成其他状态
|
|
expect(['running', 'completed', 'failed']).toContain(agent!.status);
|
|
});
|
|
});
|
|
|
|
describe('getAgent - 获取 Agent', () => {
|
|
it('返回存在的 Agent', async () => {
|
|
const agentId = await manager.runInBackground(
|
|
mockAgentInfo,
|
|
'测试任务',
|
|
'执行测试',
|
|
mockConfig,
|
|
{} as any,
|
|
mockContext
|
|
);
|
|
|
|
const agent = manager.getAgent(agentId);
|
|
expect(agent).not.toBeNull();
|
|
expect(agent!.id).toBe(agentId);
|
|
});
|
|
|
|
it('返回 null 当 Agent 不存在', () => {
|
|
const agent = manager.getAgent('non-existent');
|
|
expect(agent).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('getAgentOutput - 获取输出', () => {
|
|
it('返回 null 当 Agent 不存在', async () => {
|
|
const result = await manager.getAgentOutput('non-existent', false);
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it('非阻塞模式立即返回状态', async () => {
|
|
const agentId = await manager.runInBackground(
|
|
mockAgentInfo,
|
|
'测试任务',
|
|
'执行测试',
|
|
mockConfig,
|
|
{} as any,
|
|
mockContext
|
|
);
|
|
|
|
const result = await manager.getAgentOutput(agentId, false);
|
|
expect(result).not.toBeNull();
|
|
expect(result!.id).toBe(agentId);
|
|
});
|
|
|
|
it('阻塞模式等待完成', async () => {
|
|
const agentId = await manager.runInBackground(
|
|
mockAgentInfo,
|
|
'测试任务',
|
|
'执行测试',
|
|
mockConfig,
|
|
{} as any,
|
|
mockContext
|
|
);
|
|
|
|
// 使用阻塞模式等待
|
|
const result = await manager.getAgentOutput(agentId, true, 5);
|
|
expect(result).not.toBeNull();
|
|
// 等待后应该是完成状态
|
|
expect(['completed', 'failed']).toContain(result!.status);
|
|
});
|
|
});
|
|
|
|
describe('listAgents - 列出所有 Agent', () => {
|
|
it('返回所有 Agent', async () => {
|
|
await manager.runInBackground(
|
|
mockAgentInfo,
|
|
'任务1',
|
|
'执行1',
|
|
mockConfig,
|
|
{} as any,
|
|
mockContext
|
|
);
|
|
await manager.runInBackground(
|
|
mockAgentInfo,
|
|
'任务2',
|
|
'执行2',
|
|
mockConfig,
|
|
{} as any,
|
|
mockContext
|
|
);
|
|
|
|
const agents = manager.listAgents();
|
|
expect(agents.length).toBe(2);
|
|
});
|
|
|
|
it('空管理器返回空数组', () => {
|
|
const agents = manager.listAgents();
|
|
expect(agents).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe('listRunningAgents - 列出运行中的 Agent', () => {
|
|
it('返回数组', async () => {
|
|
await manager.runInBackground(
|
|
mockAgentInfo,
|
|
'任务1',
|
|
'执行1',
|
|
mockConfig,
|
|
{} as any,
|
|
mockContext
|
|
);
|
|
|
|
const running = manager.listRunningAgents();
|
|
expect(Array.isArray(running)).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('cleanup - 清理', () => {
|
|
it('清理已完成的 Agent', async () => {
|
|
const agentId = await manager.runInBackground(
|
|
mockAgentInfo,
|
|
'任务',
|
|
'执行',
|
|
mockConfig,
|
|
{} as any,
|
|
mockContext
|
|
);
|
|
|
|
// 等待一段时间让 Agent 完成(无论成功或失败)
|
|
await new Promise((r) => setTimeout(r, 100));
|
|
|
|
// 确认 Agent 不再是 running 状态
|
|
const beforeCleanup = manager.getAgent(agentId);
|
|
expect(beforeCleanup).not.toBeNull();
|
|
expect(['completed', 'failed']).toContain(beforeCleanup?.status);
|
|
|
|
// 设置 maxAge 为 0,立即清理
|
|
manager.cleanup(0);
|
|
|
|
const agent = manager.getAgent(agentId);
|
|
expect(agent).toBeNull();
|
|
});
|
|
|
|
it('不清理运行中的 Agent', async () => {
|
|
const agentId = await manager.runInBackground(
|
|
mockAgentInfo,
|
|
'任务',
|
|
'执行',
|
|
mockConfig,
|
|
{} as any,
|
|
mockContext
|
|
);
|
|
|
|
// 立即清理(不等待)
|
|
manager.cleanup(0);
|
|
|
|
// cleanup 应该不会报错
|
|
// Agent 可能还在运行(取决于执行速度)
|
|
// 这里只验证 cleanup 不会崩溃
|
|
expect(true).toBe(true);
|
|
});
|
|
|
|
it('使用默认 maxAge', async () => {
|
|
const agentId = await manager.runInBackground(
|
|
mockAgentInfo,
|
|
'任务',
|
|
'执行',
|
|
mockConfig,
|
|
{} as any,
|
|
mockContext
|
|
);
|
|
|
|
// 等待完成
|
|
await new Promise((r) => setTimeout(r, 300));
|
|
|
|
// 使用默认 maxAge(1 小时),不应该清理刚完成的
|
|
manager.cleanup();
|
|
|
|
// Agent 应该还在(因为未超过 1 小时)
|
|
const agent = manager.getAgent(agentId);
|
|
expect(agent).not.toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('完成回调', () => {
|
|
it('多个等待者都收到通知', async () => {
|
|
const agentId = await manager.runInBackground(
|
|
mockAgentInfo,
|
|
'任务',
|
|
'执行',
|
|
mockConfig,
|
|
{} as any,
|
|
mockContext
|
|
);
|
|
|
|
// 并发等待
|
|
const [result1, result2] = await Promise.all([
|
|
manager.getAgentOutput(agentId, true, 5),
|
|
manager.getAgentOutput(agentId, true, 5),
|
|
]);
|
|
|
|
expect(result1).not.toBeNull();
|
|
expect(result2).not.toBeNull();
|
|
expect(result1!.id).toBe(agentId);
|
|
expect(result2!.id).toBe(agentId);
|
|
});
|
|
});
|
|
|
|
describe('已完成 Agent 的阻塞查询', () => {
|
|
it('已完成的 Agent 阻塞查询立即返回', async () => {
|
|
const agentId = await manager.runInBackground(
|
|
mockAgentInfo,
|
|
'任务',
|
|
'执行',
|
|
mockConfig,
|
|
{} as any,
|
|
mockContext
|
|
);
|
|
|
|
// 等待完成
|
|
await manager.getAgentOutput(agentId, true, 5);
|
|
|
|
// 再次阻塞查询应立即返回
|
|
const startTime = Date.now();
|
|
const result = await manager.getAgentOutput(agentId, true, 10);
|
|
const elapsed = Date.now() - startTime;
|
|
|
|
expect(result).not.toBeNull();
|
|
expect(result!.status).not.toBe('running');
|
|
// 应该立即返回,不需要等 10 秒
|
|
expect(elapsed).toBeLessThan(1000);
|
|
});
|
|
});
|
|
});
|