Files
Profa 2253d05618 feat: flatten project structure — archive v2, promote v3 to root
Remove the nested v3/ subdirectory by moving all active source code,
tests, configs, and assets directly to the project root. Archive v2/
(dead code, 847MB) to v2-archive.tar.gz.

Key changes:
- Move v3/src/ → src/, v3/tests/ → tests/, v3/packages/ → packages/
- Move v3/tsconfig.json, v3/vitest.config.ts to root
- Merge v3/package.json into root package.json (ESM, scripts, deps, exports)
- Merge v3/scripts/ into scripts/, v3/implementation/ into docs/implementation/
- Update all CI workflows to remove "cd v3 &&" and v3/ path prefixes
- Fix all init installer path resolution (3-level-up → 2-level-up)
- Fix hooks to use "node ./dist/cli/bundle.js" instead of bare "aqe"
- Update settings.json ADR/DDD directories to docs/implementation/
- Fix helper scripts (statusline, adr-compliance, ddd-tracker, guidance-hooks)
- Update 58 agent definitions: aqe/v3/ → aqe/ memory namespaces
- Update 15 guidance shards: v3/src/ → src/ path references
- Fix sync interfaces: remove v3/ and v2/ path references
- Fix test path calculations (process.cwd() + '..' no longer needed)
- Fix flaky perf test threshold (500ms → 1000ms for CI environments)
- Fix complexity-analyzer test to match ADR-051 keyword-based eligibility

Build passes, 17,901 tests pass, CLI and MCP bundles verified.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:35:41 +00:00

553 lines
16 KiB
TypeScript

/**
* Agentic QE v3 - MCP Server Tests
* Tests for the Model Context Protocol server
*/
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { MCPServer, createMCPServer } from '../../../src/mcp/server';
import { ToolRegistry, createToolRegistry } from '../../../src/mcp/tool-registry';
import { ALL_DOMAINS } from '../../../src/shared/types';
describe('MCP Server', () => {
let server: MCPServer;
beforeEach(async () => {
server = createMCPServer();
await server.initialize();
});
afterEach(async () => {
await server.dispose();
});
describe('initialization', () => {
it('should initialize server successfully', () => {
const tools = server.getTools();
expect(tools.length).toBeGreaterThan(0);
});
it('should register core tools', () => {
const tools = server.getTools();
const coreTools = tools.filter((t) => t.category === 'core');
expect(coreTools.length).toBeGreaterThanOrEqual(3); // init, status, health
});
it('should register task tools', () => {
const tools = server.getTools();
const taskTools = tools.filter((t) => t.category === 'task');
expect(taskTools.length).toBeGreaterThanOrEqual(4); // submit, list, status, cancel
});
it('should register agent tools', () => {
const tools = server.getTools();
const agentTools = tools.filter((t) => t.category === 'agent');
expect(agentTools.length).toBeGreaterThanOrEqual(3); // list, spawn, metrics
});
it('should register domain tools', () => {
const tools = server.getTools();
const domainTools = tools.filter((t) => t.category === 'domain');
expect(domainTools.length).toBeGreaterThanOrEqual(10); // Various domain tools
});
it('should register memory tools', () => {
const tools = server.getTools();
const memoryTools = tools.filter((t) => t.category === 'memory');
expect(memoryTools.length).toBeGreaterThanOrEqual(5); // store, retrieve, query, delete, usage
});
});
describe('tool definitions', () => {
it('should have valid tool names', () => {
const tools = server.getTools();
for (const tool of tools) {
expect(tool.name).toBeDefined();
expect(tool.name.startsWith('mcp__agentic_qe__')).toBe(true);
}
});
it('should have descriptions for all tools', () => {
const tools = server.getTools();
for (const tool of tools) {
expect(tool.description).toBeDefined();
expect(tool.description.length).toBeGreaterThan(0);
}
});
it('should have parameters defined for all tools', () => {
const tools = server.getTools();
for (const tool of tools) {
expect(Array.isArray(tool.parameters)).toBe(true);
}
});
});
describe('tool invocation', () => {
it('should fail when fleet not initialized', async () => {
await expect(
server.invoke('mcp__agentic_qe__fleet_status', {})
).rejects.toThrow();
});
it('should initialize fleet successfully', async () => {
const result = await server.invoke('mcp__agentic_qe__fleet_init', {
topology: 'hierarchical',
maxAgents: 5,
});
expect(result).toBeDefined();
expect((result as any).fleetId).toBeDefined();
expect((result as any).status).toBe('initialized');
}, 30000);
it('should get fleet status after init', async () => {
// First init
await server.invoke('mcp__agentic_qe__fleet_init', {
topology: 'hierarchical',
maxAgents: 5,
});
// Then get status
const result = await server.invoke('mcp__agentic_qe__fleet_status', {
verbose: true,
includeMetrics: true,
});
expect(result).toBeDefined();
expect((result as any).status).toBeDefined();
expect((result as any).uptime).toBeGreaterThanOrEqual(0);
});
it('should get fleet health after init', async () => {
// First init
await server.invoke('mcp__agentic_qe__fleet_init', {});
// Then get health
const result = await server.invoke('mcp__agentic_qe__fleet_health', {
detailed: true,
});
expect(result).toBeDefined();
expect((result as any).status).toBeDefined();
});
});
describe('task operations', () => {
beforeEach(async () => {
await server.invoke('mcp__agentic_qe__fleet_init', {
maxAgents: 5,
});
});
it('should submit a task', async () => {
const result = await server.invoke('mcp__agentic_qe__task_submit', {
type: 'generate-tests',
priority: 'p1',
});
expect(result).toBeDefined();
expect((result as any).taskId).toBeDefined();
});
it('should list tasks', async () => {
// Submit a task first
await server.invoke('mcp__agentic_qe__task_submit', {
type: 'generate-tests',
priority: 'p1',
});
// Then list
const result = await server.invoke('mcp__agentic_qe__task_list', {
limit: 10,
});
expect(Array.isArray(result)).toBe(true);
});
it('should get task status', async () => {
// Submit a task first
const submitResult = await server.invoke('mcp__agentic_qe__task_submit', {
type: 'generate-tests',
priority: 'p1',
});
// Then get status
const result = await server.invoke('mcp__agentic_qe__task_status', {
taskId: (submitResult as any).taskId,
});
expect(result).toBeDefined();
expect((result as any).taskId).toBe((submitResult as any).taskId);
});
it('should orchestrate tasks', async () => {
const result = await server.invoke('mcp__agentic_qe__task_orchestrate', {
task: 'Generate unit tests for the UserService class',
strategy: 'adaptive',
priority: 'high',
});
expect(result).toBeDefined();
expect((result as any).taskId).toBeDefined();
});
});
describe('agent operations', () => {
beforeEach(async () => {
await server.invoke('mcp__agentic_qe__fleet_init', {
maxAgents: 5,
});
});
it('should list agents', async () => {
const result = await server.invoke('mcp__agentic_qe__agent_list', {
limit: 10,
});
expect(Array.isArray(result)).toBe(true);
});
it('should spawn an agent', async () => {
const result = await server.invoke('mcp__agentic_qe__agent_spawn', {
domain: 'test-generation',
type: 'worker',
capabilities: ['unit-test', 'integration-test'],
});
expect(result).toBeDefined();
expect((result as any).agentId).toBeDefined();
expect((result as any).domain).toBe('test-generation');
});
it('should get agent metrics', async () => {
const result = await server.invoke('mcp__agentic_qe__agent_metrics', {
metric: 'all',
});
expect(result).toBeDefined();
expect((result as any).totalAgents).toBeGreaterThanOrEqual(0);
});
});
describe('memory operations', () => {
beforeEach(async () => {
await server.invoke('mcp__agentic_qe__fleet_init', {});
});
it('should store data in memory', async () => {
const result = await server.invoke('mcp__agentic_qe__memory_store', {
key: 'test-key',
value: { message: 'hello world' },
namespace: 'test',
});
expect(result).toBeDefined();
expect((result as any).stored).toBe(true);
});
it('should retrieve data from memory', async () => {
// Store first
await server.invoke('mcp__agentic_qe__memory_store', {
key: 'test-key-2',
value: { data: 123 },
namespace: 'test',
});
// Then retrieve
const result = await server.invoke('mcp__agentic_qe__memory_retrieve', {
key: 'test-key-2',
namespace: 'test',
});
expect(result).toBeDefined();
expect((result as any).found).toBe(true);
expect((result as any).value).toEqual({ data: 123 });
});
it('should delete from memory', async () => {
// Store first
await server.invoke('mcp__agentic_qe__memory_store', {
key: 'to-delete',
value: { temp: true },
namespace: 'test',
});
// Then delete
const result = await server.invoke('mcp__agentic_qe__memory_delete', {
key: 'to-delete',
namespace: 'test',
});
expect(result).toBeDefined();
expect((result as any).deleted).toBe(true);
});
});
describe('domain tools', () => {
beforeEach(async () => {
await server.invoke('mcp__agentic_qe__fleet_init', {});
});
it('should submit test generation task', async () => {
const result = await server.invoke('mcp__agentic_qe__test_generate_enhanced', {
// Provide inline source code to avoid file system operations
sourceCode: 'export function add(a: number, b: number): number { return a + b; }',
language: 'typescript',
testType: 'unit',
coverageGoal: 80,
});
expect(result).toBeDefined();
expect((result as any).taskId).toBeDefined();
}, 15000); // Extended timeout for task execution
it('should submit coverage analysis task', async () => {
// Use a non-existent path to trigger fast fallback path (no file system walking)
const result = await server.invoke('mcp__agentic_qe__coverage_analyze_sublinear', {
target: '/tmp/nonexistent-coverage-test-path',
includeRisk: true,
detectGaps: true,
});
expect(result).toBeDefined();
expect((result as any).taskId).toBeDefined();
}, 15000); // Extended timeout for task execution
it('should submit security scan task', async () => {
// Use a non-existent path to trigger fast fallback path (no file system walking)
const result = await server.invoke('mcp__agentic_qe__security_scan_comprehensive', {
target: '/tmp/nonexistent-security-test-path',
sast: true,
compliance: ['owasp'],
});
expect(result).toBeDefined();
expect((result as any).taskId).toBeDefined();
}, 15000); // Extended timeout for task execution
it('should submit quality assessment task', async () => {
// Use a non-existent path to trigger fast fallback path (no file system walking)
const result = await server.invoke('mcp__agentic_qe__quality_assess', {
target: '/tmp/nonexistent-quality-test-path',
runGate: true,
threshold: 80,
});
expect(result).toBeDefined();
expect((result as any).taskId).toBeDefined();
}, 15000); // Extended timeout for task execution
});
describe('statistics', () => {
it('should track tool statistics', async () => {
await server.invoke('mcp__agentic_qe__fleet_init', {});
const stats = server.getStats();
expect(stats.totalTools).toBeGreaterThan(0);
expect(stats.invocations).toBeGreaterThan(0);
});
});
});
describe('Tool Registry', () => {
let registry: ToolRegistry;
beforeEach(() => {
registry = createToolRegistry();
});
describe('registration', () => {
it('should register a tool', () => {
registry.register(
{
name: 'test_tool',
description: 'A test tool',
category: 'core',
parameters: [],
},
async () => ({ success: true, data: 'test' })
);
expect(registry.has('test_tool')).toBe(true);
});
it('should get tool definitions', () => {
registry.register(
{
name: 'tool1',
description: 'Tool 1',
category: 'core',
parameters: [],
},
async () => ({ success: true })
);
registry.register(
{
name: 'tool2',
description: 'Tool 2',
category: 'domain',
domain: 'test-generation',
lazyLoad: true,
parameters: [],
},
async () => ({ success: true })
);
const definitions = registry.getDefinitions();
expect(definitions.length).toBe(2);
});
it('should get tools by category', () => {
registry.register(
{
name: 'core_tool',
description: 'Core tool',
category: 'core',
parameters: [],
},
async () => ({ success: true })
);
registry.register(
{
name: 'domain_tool',
description: 'Domain tool',
category: 'domain',
parameters: [],
},
async () => ({ success: true })
);
const coreTools = registry.getByCategory('core');
expect(coreTools.length).toBe(1);
expect(coreTools[0].name).toBe('core_tool');
});
it('should get tools by domain', () => {
registry.register(
{
name: 'test_gen_tool',
description: 'Test generation tool',
category: 'domain',
domain: 'test-generation',
parameters: [],
},
async () => ({ success: true })
);
const tools = registry.getByDomain('test-generation');
expect(tools.length).toBe(1);
});
});
describe('invocation', () => {
it('should invoke a registered tool', async () => {
registry.register(
{
name: 'echo_tool',
description: 'Echo tool',
category: 'core',
parameters: [
{ name: 'message', type: 'string', description: 'Message to echo' },
],
},
async (params) => ({ success: true, data: params })
);
const result = await registry.invoke('echo_tool', { message: 'hello' });
expect(result.success).toBe(true);
expect(result.data).toEqual({ message: 'hello' });
});
it('should return error for unknown tool', async () => {
const result = await registry.invoke('unknown_tool', {});
expect(result.success).toBe(false);
expect(result.error).toContain('Tool not found');
});
it('should add metadata to results', async () => {
registry.register(
{
name: 'meta_tool',
description: 'Meta tool',
category: 'core',
parameters: [],
},
async () => ({ success: true, data: 'test' })
);
const result = await registry.invoke('meta_tool', {});
expect(result.metadata).toBeDefined();
expect(result.metadata?.requestId).toBeDefined();
expect(result.metadata?.executionTime).toBeGreaterThanOrEqual(0);
});
});
describe('lazy loading', () => {
it('should detect domains from message', () => {
const domains = registry.detectDomainsFromMessage(
'Generate unit tests for the UserService class'
);
expect(domains).toContain('test-generation');
});
it('should detect security domain from keywords', () => {
const domains = registry.detectDomainsFromMessage(
'Check for SQL injection vulnerabilities'
);
expect(domains).toContain('security-compliance');
});
it('should detect coverage domain from keywords', () => {
const domains = registry.detectDomainsFromMessage(
'Analyze code coverage and find gaps'
);
expect(domains).toContain('coverage-analysis');
});
it('should detect multiple domains', () => {
const domains = registry.detectDomainsFromMessage(
'Run security scan and generate test cases for accessibility'
);
expect(domains.length).toBeGreaterThan(1);
});
});
describe('statistics', () => {
it('should track tool statistics', () => {
registry.register(
{
name: 'stat_tool',
description: 'Stats tool',
category: 'core',
parameters: [],
},
async () => ({ success: true })
);
const stats = registry.getStats();
expect(stats.totalTools).toBe(1);
expect(stats.byCategory.core).toBe(1);
});
it('should track invocations', async () => {
registry.register(
{
name: 'counter_tool',
description: 'Counter tool',
category: 'core',
parameters: [],
},
async () => ({ success: true })
);
await registry.invoke('counter_tool', {});
await registry.invoke('counter_tool', {});
const stats = registry.getStats();
expect(stats.invocations).toBe(2);
});
});
});