mirror of
https://github.com/proffesor-for-testing/agentic-qe.git
synced 2026-09-19 08:45:47 +08:00
2253d05618
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>
542 lines
18 KiB
TypeScript
542 lines
18 KiB
TypeScript
/**
|
|
* Defect Intelligence MinCut Integration Test
|
|
* ============================================================================
|
|
*
|
|
* Tests the MinCut topology awareness integration in the defect-intelligence
|
|
* domain coordinator per ADR-047.
|
|
*
|
|
* ADR-047: MinCut Self-Organizing QE Integration
|
|
*/
|
|
|
|
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
import type { Mock } from 'vitest';
|
|
|
|
import {
|
|
DefectIntelligenceCoordinator,
|
|
type CoordinatorConfig,
|
|
} from '../../../src/domains/defect-intelligence/coordinator';
|
|
|
|
import {
|
|
QueenMinCutBridge,
|
|
createQueenMinCutBridge,
|
|
} from '../../../src/coordination/mincut/queen-integration';
|
|
|
|
import {
|
|
getSharedMinCutGraph,
|
|
resetSharedMinCutState,
|
|
} from '../../../src/coordination/mincut';
|
|
|
|
import type { MinCutHealth, WeakVertex } from '../../../src/coordination/mincut/interfaces';
|
|
import type { DomainName } from '../../../src/shared/types';
|
|
import type { EventBus, AgentCoordinator, AgentInfo, MemoryBackend } from '../../../src/kernel/interfaces';
|
|
|
|
// ============================================================================
|
|
// Mock Helpers
|
|
// ============================================================================
|
|
|
|
function createMockEventBus(): EventBus & { publish: Mock } {
|
|
return {
|
|
publish: vi.fn().mockResolvedValue(undefined),
|
|
subscribe: vi.fn().mockReturnValue('sub-1'),
|
|
unsubscribe: vi.fn(),
|
|
once: vi.fn(),
|
|
listSubscribers: vi.fn().mockReturnValue([]),
|
|
} as EventBus & { publish: Mock };
|
|
}
|
|
|
|
function createMockMemoryBackend(): MemoryBackend {
|
|
const store = new Map<string, any>();
|
|
return {
|
|
get: vi.fn().mockImplementation((key: string) => Promise.resolve(store.get(key) ?? null)),
|
|
set: vi.fn().mockImplementation((key: string, value: any) => {
|
|
store.set(key, value);
|
|
return Promise.resolve();
|
|
}),
|
|
delete: vi.fn().mockImplementation((key: string) => {
|
|
store.delete(key);
|
|
return Promise.resolve(true);
|
|
}),
|
|
search: vi.fn().mockResolvedValue([]),
|
|
has: vi.fn().mockImplementation((key: string) => Promise.resolve(store.has(key))),
|
|
clear: vi.fn().mockImplementation(() => {
|
|
store.clear();
|
|
return Promise.resolve();
|
|
}),
|
|
list: vi.fn().mockResolvedValue([]),
|
|
keys: vi.fn().mockResolvedValue([]),
|
|
} as unknown as MemoryBackend;
|
|
}
|
|
|
|
function createMockAgentCoordinator(agents: AgentInfo[] = []): AgentCoordinator & {
|
|
listAgents: Mock;
|
|
spawn: Mock;
|
|
stop: Mock;
|
|
canSpawn: Mock;
|
|
} {
|
|
return {
|
|
listAgents: vi.fn().mockReturnValue(agents),
|
|
spawn: vi.fn().mockResolvedValue({ success: true, value: `agent-${Date.now()}` }),
|
|
stop: vi.fn().mockResolvedValue(undefined),
|
|
canSpawn: vi.fn().mockReturnValue(true),
|
|
getAgent: vi.fn(),
|
|
} as unknown as AgentCoordinator & {
|
|
listAgents: Mock;
|
|
spawn: Mock;
|
|
stop: Mock;
|
|
canSpawn: Mock;
|
|
};
|
|
}
|
|
|
|
function createMockAgent(overrides: Partial<AgentInfo> = {}): AgentInfo {
|
|
return {
|
|
id: `agent-${Math.random().toString(36).slice(2, 8)}`,
|
|
name: 'test-agent',
|
|
domain: 'defect-intelligence' as DomainName,
|
|
type: 'analyzer',
|
|
status: 'running',
|
|
startedAt: new Date(),
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
function createTestBridge(options: {
|
|
agents?: AgentInfo[];
|
|
useSharedGraph?: boolean;
|
|
} = {}): {
|
|
bridge: QueenMinCutBridge;
|
|
mockEventBus: EventBus & { publish: Mock };
|
|
mockAgentCoordinator: AgentCoordinator & { listAgents: Mock };
|
|
} {
|
|
const mockEventBus = createMockEventBus();
|
|
const mockAgentCoordinator = createMockAgentCoordinator(options.agents ?? []);
|
|
|
|
const bridge = createQueenMinCutBridge(
|
|
mockEventBus,
|
|
mockAgentCoordinator,
|
|
{
|
|
includeInQueenHealth: true,
|
|
autoUpdateFromEvents: false,
|
|
persistData: false,
|
|
sharedGraph: options.useSharedGraph ? getSharedMinCutGraph() : undefined,
|
|
}
|
|
);
|
|
|
|
return { bridge, mockEventBus, mockAgentCoordinator };
|
|
}
|
|
|
|
function createTestCoordinator(
|
|
config: Partial<CoordinatorConfig> = {},
|
|
): {
|
|
coordinator: DefectIntelligenceCoordinator;
|
|
mockEventBus: EventBus;
|
|
mockMemory: MemoryBackend;
|
|
mockAgentCoordinator: AgentCoordinator;
|
|
} {
|
|
const mockEventBus = createMockEventBus();
|
|
const mockMemory = createMockMemoryBackend();
|
|
const mockAgentCoordinator = createMockAgentCoordinator();
|
|
|
|
const coordinator = new DefectIntelligenceCoordinator(
|
|
mockEventBus,
|
|
mockMemory,
|
|
mockAgentCoordinator,
|
|
{
|
|
// Disable features that require external services for testing
|
|
enableConsensus: false,
|
|
// Enable MinCut for testing
|
|
enableMinCutAwareness: true,
|
|
...config,
|
|
}
|
|
);
|
|
|
|
return { coordinator, mockEventBus, mockMemory, mockAgentCoordinator };
|
|
}
|
|
|
|
// ============================================================================
|
|
// Test Suite
|
|
// ============================================================================
|
|
|
|
describe('defect-intelligence MinCut Integration', () => {
|
|
beforeEach(() => {
|
|
resetSharedMinCutState();
|
|
});
|
|
|
|
afterEach(() => {
|
|
resetSharedMinCutState();
|
|
});
|
|
|
|
// ==========================================================================
|
|
// Test: Coordinator accepts MinCut bridge via setter
|
|
// ==========================================================================
|
|
|
|
describe('MinCut bridge injection', () => {
|
|
it('should accept MinCut bridge injection', async () => {
|
|
const { coordinator } = createTestCoordinator();
|
|
const { bridge } = createTestBridge();
|
|
await bridge.initialize();
|
|
|
|
// Set the bridge
|
|
coordinator.setMinCutBridge(bridge);
|
|
|
|
// Verify bridge is accessible via topology health check
|
|
const isHealthy = coordinator.isTopologyHealthy();
|
|
expect(typeof isHealthy).toBe('boolean');
|
|
});
|
|
|
|
it('should work without MinCut bridge (graceful degradation)', async () => {
|
|
const { coordinator } = createTestCoordinator();
|
|
|
|
// Without a bridge, isTopologyHealthy should return true (assume healthy)
|
|
expect(coordinator.isTopologyHealthy()).toBe(true);
|
|
|
|
// Other methods should not throw
|
|
expect(coordinator.getDomainWeakVertices()).toEqual([]);
|
|
expect(coordinator.isDomainWeakPoint()).toBe(false);
|
|
});
|
|
|
|
it('should work with MinCut awareness disabled', async () => {
|
|
const { coordinator } = createTestCoordinator({
|
|
enableMinCutAwareness: false,
|
|
});
|
|
|
|
// Should return true when awareness is disabled
|
|
expect(coordinator.isTopologyHealthy()).toBe(true);
|
|
});
|
|
});
|
|
|
|
// ==========================================================================
|
|
// Test: isTopologyHealthy() returns correct status
|
|
// ==========================================================================
|
|
|
|
describe('topology health reporting', () => {
|
|
it('should report topology health correctly with healthy topology', async () => {
|
|
const agents = [
|
|
createMockAgent({ id: 'agent-1', domain: 'defect-intelligence' }),
|
|
createMockAgent({ id: 'agent-2', domain: 'defect-intelligence' }),
|
|
createMockAgent({ id: 'agent-3', domain: 'defect-intelligence' }),
|
|
];
|
|
|
|
const { coordinator } = createTestCoordinator();
|
|
const { bridge } = createTestBridge({ agents });
|
|
await bridge.initialize();
|
|
|
|
// Add interconnections between agents
|
|
const graph = bridge.getGraph();
|
|
graph.addEdge({
|
|
source: 'agent:agent-1',
|
|
target: 'agent:agent-2',
|
|
weight: 1.0,
|
|
type: 'coordination',
|
|
bidirectional: true,
|
|
});
|
|
graph.addEdge({
|
|
source: 'agent:agent-2',
|
|
target: 'agent:agent-3',
|
|
weight: 1.0,
|
|
type: 'coordination',
|
|
bidirectional: true,
|
|
});
|
|
graph.addEdge({
|
|
source: 'agent:agent-1',
|
|
target: 'agent:agent-3',
|
|
weight: 1.0,
|
|
type: 'coordination',
|
|
bidirectional: true,
|
|
});
|
|
|
|
coordinator.setMinCutBridge(bridge);
|
|
|
|
// With well-connected agents, topology should be healthy
|
|
const minCutHealth = bridge.getMinCutHealth();
|
|
expect(minCutHealth).toBeDefined();
|
|
expect(['healthy', 'idle', 'warning', 'critical']).toContain(minCutHealth.status);
|
|
});
|
|
|
|
it('should report idle status for empty topology', async () => {
|
|
const { coordinator } = createTestCoordinator();
|
|
const { bridge } = createTestBridge({ agents: [] });
|
|
await bridge.initialize();
|
|
|
|
coordinator.setMinCutBridge(bridge);
|
|
|
|
const minCutHealth = bridge.getMinCutHealth();
|
|
expect(minCutHealth.status).toBe('idle');
|
|
|
|
// Coordinator should still report healthy for idle topology
|
|
expect(coordinator.isTopologyHealthy()).toBe(true);
|
|
});
|
|
});
|
|
|
|
// ==========================================================================
|
|
// Test: getDomainWeakVertices() filters by domain
|
|
// ==========================================================================
|
|
|
|
describe('domain-filtered weak vertex detection', () => {
|
|
it('should filter weak vertices by domain', async () => {
|
|
const agents = [
|
|
createMockAgent({ id: 'di-agent-1', domain: 'defect-intelligence' }),
|
|
createMockAgent({ id: 'di-agent-2', domain: 'defect-intelligence' }),
|
|
createMockAgent({ id: 'tg-agent-1', domain: 'test-generation' }),
|
|
createMockAgent({ id: 'te-agent-1', domain: 'test-execution' }),
|
|
];
|
|
|
|
const { coordinator } = createTestCoordinator();
|
|
const { bridge } = createTestBridge({ agents });
|
|
await bridge.initialize();
|
|
|
|
const graph = bridge.getGraph();
|
|
// Connect defect-intelligence agents only
|
|
graph.addEdge({
|
|
source: 'agent:di-agent-1',
|
|
target: 'agent:di-agent-2',
|
|
weight: 1.0,
|
|
type: 'coordination',
|
|
bidirectional: true,
|
|
});
|
|
|
|
coordinator.setMinCutBridge(bridge);
|
|
|
|
// Get domain-specific weak vertices
|
|
const domainWeakVertices = coordinator.getDomainWeakVertices();
|
|
expect(Array.isArray(domainWeakVertices)).toBe(true);
|
|
|
|
// All returned vertices should belong to defect-intelligence domain
|
|
for (const wv of domainWeakVertices) {
|
|
expect(wv.vertex.domain).toBe('defect-intelligence');
|
|
}
|
|
});
|
|
|
|
it('should return empty array when domain has no weak vertices', async () => {
|
|
const agents = [
|
|
createMockAgent({ id: 'agent-1', domain: 'defect-intelligence' }),
|
|
createMockAgent({ id: 'agent-2', domain: 'defect-intelligence' }),
|
|
];
|
|
|
|
const { coordinator } = createTestCoordinator();
|
|
const { bridge } = createTestBridge({ agents });
|
|
await bridge.initialize();
|
|
|
|
// Strongly connect agents
|
|
const graph = bridge.getGraph();
|
|
graph.addEdge({
|
|
source: 'agent:agent-1',
|
|
target: 'agent:agent-2',
|
|
weight: 2.0,
|
|
type: 'coordination',
|
|
bidirectional: true,
|
|
});
|
|
|
|
coordinator.setMinCutBridge(bridge);
|
|
|
|
const domainWeakVertices = coordinator.getDomainWeakVertices();
|
|
expect(Array.isArray(domainWeakVertices)).toBe(true);
|
|
});
|
|
});
|
|
|
|
// ==========================================================================
|
|
// Test: getTopologyBasedRouting() avoids weak domains
|
|
// ==========================================================================
|
|
|
|
describe('topology-based routing', () => {
|
|
it('should route away from weak domains', async () => {
|
|
const agents = [
|
|
createMockAgent({ id: 'strong-1', domain: 'defect-intelligence' }),
|
|
createMockAgent({ id: 'strong-2', domain: 'defect-intelligence' }),
|
|
createMockAgent({ id: 'weak-1', domain: 'test-execution' }), // Isolated
|
|
];
|
|
|
|
const { coordinator } = createTestCoordinator();
|
|
const { bridge } = createTestBridge({ agents });
|
|
await bridge.initialize();
|
|
|
|
// Connect defect-intelligence agents, leave test-execution isolated
|
|
const graph = bridge.getGraph();
|
|
graph.addEdge({
|
|
source: 'agent:strong-1',
|
|
target: 'agent:strong-2',
|
|
weight: 2.0,
|
|
type: 'coordination',
|
|
bidirectional: true,
|
|
});
|
|
|
|
coordinator.setMinCutBridge(bridge);
|
|
|
|
// Get routing excluding weak domains
|
|
const targetDomains = ['test-generation', 'test-execution', 'coverage-analysis'];
|
|
const healthyRoutes = coordinator.getTopologyBasedRouting(targetDomains);
|
|
|
|
expect(Array.isArray(healthyRoutes)).toBe(true);
|
|
// Results should filter based on topology health
|
|
});
|
|
|
|
it('should include all domains when topology is healthy', async () => {
|
|
const agents = [
|
|
createMockAgent({ id: 'di-1', domain: 'defect-intelligence' }),
|
|
createMockAgent({ id: 'exec-1', domain: 'test-execution' }),
|
|
];
|
|
|
|
const { coordinator } = createTestCoordinator();
|
|
const { bridge } = createTestBridge({ agents });
|
|
await bridge.initialize();
|
|
|
|
// Connect all agents
|
|
const graph = bridge.getGraph();
|
|
graph.addEdge({
|
|
source: 'agent:di-1',
|
|
target: 'agent:exec-1',
|
|
weight: 1.5,
|
|
type: 'workflow',
|
|
bidirectional: true,
|
|
});
|
|
|
|
coordinator.setMinCutBridge(bridge);
|
|
|
|
const targetDomains = ['test-generation', 'test-execution'];
|
|
const healthyRoutes = coordinator.getTopologyBasedRouting(targetDomains);
|
|
|
|
// When all domains are well-connected, should return all
|
|
expect(healthyRoutes.length).toBeGreaterThanOrEqual(0);
|
|
});
|
|
});
|
|
|
|
// ==========================================================================
|
|
// Test: isDomainWeakPoint() detection
|
|
// ==========================================================================
|
|
|
|
describe('domain weak point detection', () => {
|
|
it('should handle critical topology state', async () => {
|
|
// Create a star topology where the hub is in defect-intelligence
|
|
const agents = [
|
|
createMockAgent({ id: 'hub', domain: 'defect-intelligence' }),
|
|
createMockAgent({ id: 'leaf-1', domain: 'test-execution' }),
|
|
createMockAgent({ id: 'leaf-2', domain: 'coverage-analysis' }),
|
|
];
|
|
|
|
const { coordinator } = createTestCoordinator();
|
|
const { bridge } = createTestBridge({ agents });
|
|
await bridge.initialize();
|
|
|
|
// All connections go through the hub
|
|
const graph = bridge.getGraph();
|
|
graph.addEdge({
|
|
source: 'agent:hub',
|
|
target: 'agent:leaf-1',
|
|
weight: 0.5,
|
|
type: 'coordination',
|
|
bidirectional: true,
|
|
});
|
|
graph.addEdge({
|
|
source: 'agent:hub',
|
|
target: 'agent:leaf-2',
|
|
weight: 0.5,
|
|
type: 'coordination',
|
|
bidirectional: true,
|
|
});
|
|
|
|
coordinator.setMinCutBridge(bridge);
|
|
|
|
// The method should return a boolean
|
|
const isWeakPoint = coordinator.isDomainWeakPoint();
|
|
expect(typeof isWeakPoint).toBe('boolean');
|
|
});
|
|
|
|
it('should not detect weak point in well-connected topology', async () => {
|
|
const agents = [
|
|
createMockAgent({ id: 'di-1', domain: 'defect-intelligence' }),
|
|
createMockAgent({ id: 'di-2', domain: 'defect-intelligence' }),
|
|
createMockAgent({ id: 'exec-1', domain: 'test-execution' }),
|
|
];
|
|
|
|
const { coordinator } = createTestCoordinator();
|
|
const { bridge } = createTestBridge({ agents });
|
|
await bridge.initialize();
|
|
|
|
// Create mesh topology
|
|
const graph = bridge.getGraph();
|
|
graph.addEdge({
|
|
source: 'agent:di-1',
|
|
target: 'agent:di-2',
|
|
weight: 2.0,
|
|
type: 'coordination',
|
|
bidirectional: true,
|
|
});
|
|
graph.addEdge({
|
|
source: 'agent:di-1',
|
|
target: 'agent:exec-1',
|
|
weight: 2.0,
|
|
type: 'workflow',
|
|
bidirectional: true,
|
|
});
|
|
graph.addEdge({
|
|
source: 'agent:di-2',
|
|
target: 'agent:exec-1',
|
|
weight: 2.0,
|
|
type: 'workflow',
|
|
bidirectional: true,
|
|
});
|
|
|
|
coordinator.setMinCutBridge(bridge);
|
|
|
|
const isWeakPoint = coordinator.isDomainWeakPoint();
|
|
expect(typeof isWeakPoint).toBe('boolean');
|
|
});
|
|
});
|
|
|
|
// ==========================================================================
|
|
// Test: Lifecycle integration
|
|
// ==========================================================================
|
|
|
|
describe('lifecycle integration', () => {
|
|
it('should properly initialize and dispose', async () => {
|
|
const { coordinator } = createTestCoordinator();
|
|
const { bridge } = createTestBridge();
|
|
await bridge.initialize();
|
|
|
|
coordinator.setMinCutBridge(bridge);
|
|
await coordinator.initialize();
|
|
|
|
// Should be able to check health
|
|
expect(coordinator.isTopologyHealthy()).toBe(true);
|
|
|
|
// Dispose should not throw
|
|
await coordinator.dispose();
|
|
});
|
|
|
|
it('should handle dispose without initialization', async () => {
|
|
const { coordinator } = createTestCoordinator();
|
|
|
|
// Dispose without initialize should not throw
|
|
await expect(coordinator.dispose()).resolves.not.toThrow();
|
|
});
|
|
});
|
|
|
|
// ==========================================================================
|
|
// Test: Shared graph integration
|
|
// ==========================================================================
|
|
|
|
describe('shared graph integration', () => {
|
|
it('should share graph state with other components', async () => {
|
|
const { coordinator } = createTestCoordinator();
|
|
const { bridge } = createTestBridge({ useSharedGraph: true });
|
|
|
|
// Add data to shared graph before bridge initialization
|
|
const sharedGraph = getSharedMinCutGraph();
|
|
sharedGraph.addVertex({
|
|
id: 'shared-agent-1',
|
|
type: 'agent',
|
|
domain: 'defect-intelligence' as DomainName,
|
|
weight: 1.0,
|
|
createdAt: new Date(),
|
|
});
|
|
|
|
await bridge.initialize();
|
|
coordinator.setMinCutBridge(bridge);
|
|
|
|
// Bridge should see shared data
|
|
const graph = bridge.getGraph();
|
|
expect(graph).toBe(sharedGraph);
|
|
expect(graph.hasVertex('shared-agent-1')).toBe(true);
|
|
});
|
|
});
|
|
});
|