mirror of
https://github.com/proffesor-for-testing/agentic-qe.git
synced 2026-09-19 08:45:47 +08:00
5a2883a4a0
Agentic Quality Engineering Fleet - AI-driven quality management platform Features: - 16 specialized QE agents for comprehensive testing - AI-powered test generation with 95% coverage targets - O(log n) sublinear algorithms for massive scale - Parallel test execution with intelligent orchestration - Real-time coverage analysis and gap detection - Smart quality gates with ML-driven decisions - Security scanning (SAST, DAST, dependency analysis) - Performance testing with load orchestration - Flaky test detection with automatic stabilization - API contract validation with breaking change detection - Test data generation (10,000+ records/sec) - Production intelligence (convert incidents to tests) - Chaos engineering for resilience testing - MCP integration with Claude Code - Multi-framework support (Jest, Mocha, Cypress, Playwright) Architecture: - TypeScript implementation - MCP (Model Context Protocol) integration - Claude Code agent orchestration - Event-driven agent coordination - Distributed fleet management - Cross-session memory persistence Documentation: - Complete API documentation (TypeDoc) - User guides (Getting Started, MCP Integration, Test Generation, etc.) - Architecture deep-dive - CLI reference - Contributing guidelines - MIT License Tech Stack: - TypeScript 5.3+ - Node.js 18+ - @anthropic-ai/sdk ^0.64.0 - @modelcontextprotocol/sdk ^1.18.2 - Jest for testing - Winston for logging - SQLite for persistence Project Structure: - src/ - Source code (agents, core, MCP, CLI) - tests/ - Comprehensive test suite - docs/ - Complete documentation - .claude/ - Agent definitions and commands - config/ - Configuration files 🤖 Generated with Claude Code https://claude.com/claude-code Co-Authored-By: Claude <noreply@anthropic.com>
450 lines
16 KiB
TypeScript
450 lines
16 KiB
TypeScript
/**
|
|
* Integration Tests for Claude Flow Coordination
|
|
* Validates coordination between AQE agents and Claude Flow memory system
|
|
*/
|
|
|
|
import { spawn } from 'child_process';
|
|
import { promisify } from 'util';
|
|
import * as fs from 'fs-extra';
|
|
import * as path from 'path';
|
|
|
|
const execAsync = promisify(spawn);
|
|
|
|
describe('Claude Flow Coordination Integration', () => {
|
|
const testNamespace = 'aqe-test';
|
|
const timeout = 30000; // 30 seconds
|
|
|
|
beforeAll(async () => {
|
|
// Ensure Claude Flow is available
|
|
try {
|
|
await execCommand('npx claude-flow@alpha --version');
|
|
} catch (error) {
|
|
console.warn('Claude Flow not available, skipping integration tests');
|
|
pending('Claude Flow not available');
|
|
}
|
|
}, timeout);
|
|
|
|
beforeEach(async () => {
|
|
// Clean up test namespace
|
|
try {
|
|
await execCommand(`npx claude-flow@alpha memory clear --namespace ${testNamespace}`);
|
|
} catch (error) {
|
|
// Ignore if namespace doesn't exist
|
|
}
|
|
});
|
|
|
|
afterEach(async () => {
|
|
// Clean up after each test
|
|
try {
|
|
await execCommand(`npx claude-flow@alpha memory clear --namespace ${testNamespace}`);
|
|
} catch (error) {
|
|
// Ignore cleanup errors
|
|
}
|
|
});
|
|
|
|
describe('Memory Operations', () => {
|
|
it('should store and retrieve agent coordination data', async () => {
|
|
const testData = {
|
|
agentId: 'test-generator-001',
|
|
status: 'active',
|
|
currentTask: 'generating-unit-tests',
|
|
progress: 75,
|
|
timestamp: new Date().toISOString()
|
|
};
|
|
|
|
// Store data
|
|
await execCommand(
|
|
`npx claude-flow@alpha memory store "agents/test-generator-001" '${JSON.stringify(testData)}' --namespace ${testNamespace}`
|
|
);
|
|
|
|
// Retrieve data
|
|
const retrievedData = await execCommand(
|
|
`npx claude-flow@alpha memory retrieve "agents/test-generator-001" --namespace ${testNamespace}`
|
|
);
|
|
|
|
const parsed = JSON.parse(retrievedData);
|
|
expect(parsed.agentId).toBe(testData.agentId);
|
|
expect(parsed.status).toBe(testData.status);
|
|
expect(parsed.progress).toBe(testData.progress);
|
|
}, timeout);
|
|
|
|
it('should handle concurrent memory operations', async () => {
|
|
const agents = ['test-gen', 'coverage-analyzer', 'quality-gate'];
|
|
const promises = agents.map(async (agentId, index) => {
|
|
const data = {
|
|
agentId,
|
|
task: `task-${index}`,
|
|
timestamp: new Date().toISOString()
|
|
};
|
|
|
|
await execCommand(
|
|
`npx claude-flow@alpha memory store "agents/${agentId}" '${JSON.stringify(data)}' --namespace ${testNamespace}`
|
|
);
|
|
|
|
return execCommand(
|
|
`npx claude-flow@alpha memory retrieve "agents/${agentId}" --namespace ${testNamespace}`
|
|
);
|
|
});
|
|
|
|
const results = await Promise.all(promises);
|
|
|
|
results.forEach((result, index) => {
|
|
const parsed = JSON.parse(result);
|
|
expect(parsed.agentId).toBe(agents[index]);
|
|
expect(parsed.task).toBe(`task-${index}`);
|
|
});
|
|
}, timeout);
|
|
|
|
it('should search coordination data across agents', async () => {
|
|
// Store test data for multiple agents
|
|
const testAgents = [
|
|
{ id: 'test-gen-1', status: 'active', type: 'generator' },
|
|
{ id: 'test-gen-2', status: 'idle', type: 'generator' },
|
|
{ id: 'coverage-1', status: 'active', type: 'analyzer' }
|
|
];
|
|
|
|
for (const agent of testAgents) {
|
|
await execCommand(
|
|
`npx claude-flow@alpha memory store "agents/${agent.id}" '${JSON.stringify(agent)}' --namespace ${testNamespace}`
|
|
);
|
|
}
|
|
|
|
// Search for active agents
|
|
const searchResults = await execCommand(
|
|
`npx claude-flow@alpha memory search "status.*active" --namespace ${testNamespace}`
|
|
);
|
|
|
|
expect(searchResults).toContain('test-gen-1');
|
|
expect(searchResults).toContain('coverage-1');
|
|
expect(searchResults).not.toContain('test-gen-2');
|
|
}, timeout);
|
|
});
|
|
|
|
describe('Hook System Integration', () => {
|
|
it('should execute pre-task hooks for test generation', async () => {
|
|
const taskId = 'generate-tests-001';
|
|
const hookResult = await execCommand(
|
|
`npx claude-flow@alpha hooks pre-task --task-id "${taskId}" --description "Generate unit tests for user service"`
|
|
);
|
|
|
|
expect(hookResult).toContain('pre-task');
|
|
expect(hookResult).toContain(taskId);
|
|
}, timeout);
|
|
|
|
it('should execute post-edit hooks after file modifications', async () => {
|
|
const testFile = '/tmp/test-file.js';
|
|
|
|
// Create a test file
|
|
await fs.writeFile(testFile, 'console.log("test");');
|
|
|
|
const hookResult = await execCommand(
|
|
`npx claude-flow@alpha hooks post-edit --file "${testFile}" --memory-key "test-edits"`
|
|
);
|
|
|
|
expect(hookResult).toContain('post-edit');
|
|
|
|
// Cleanup
|
|
await fs.remove(testFile);
|
|
}, timeout);
|
|
|
|
it('should notify other agents of task completion', async () => {
|
|
const message = 'Test generation completed: 50 tests created with 95% coverage';
|
|
|
|
const hookResult = await execCommand(
|
|
`npx claude-flow@alpha hooks notify --message "${message}"`
|
|
);
|
|
|
|
expect(hookResult).toContain('notify');
|
|
}, timeout);
|
|
|
|
it('should handle session management for agent coordination', async () => {
|
|
const sessionId = `aqe-session-${Date.now()}`;
|
|
|
|
// Start session
|
|
const startResult = await execCommand(
|
|
`npx claude-flow@alpha hooks session-start --session-id "${sessionId}" --agents 3`
|
|
);
|
|
|
|
expect(startResult).toContain('session-start');
|
|
|
|
// End session
|
|
const endResult = await execCommand(
|
|
`npx claude-flow@alpha hooks session-end --session-id "${sessionId}" --export-metrics true`
|
|
);
|
|
|
|
expect(endResult).toContain('session-end');
|
|
}, timeout);
|
|
});
|
|
|
|
describe('Agent Coordination Patterns', () => {
|
|
it('should coordinate test generation workflow', async () => {
|
|
const workflowId = `test-gen-workflow-${Date.now()}`;
|
|
|
|
// Store workflow state
|
|
const workflowState = {
|
|
id: workflowId,
|
|
phase: 'generation',
|
|
agents: {
|
|
'test-generator': 'active',
|
|
'coverage-analyzer': 'pending',
|
|
'quality-gate': 'pending'
|
|
},
|
|
progress: {
|
|
testsGenerated: 0,
|
|
coverageAnalyzed: 0,
|
|
qualityChecked: 0
|
|
}
|
|
};
|
|
|
|
await execCommand(
|
|
`npx claude-flow@alpha memory store "workflows/${workflowId}" '${JSON.stringify(workflowState)}' --namespace ${testNamespace}`
|
|
);
|
|
|
|
// Simulate test generator updating progress
|
|
workflowState.agents['test-generator'] = 'completed';
|
|
workflowState.agents['coverage-analyzer'] = 'active';
|
|
workflowState.progress.testsGenerated = 100;
|
|
|
|
await execCommand(
|
|
`npx claude-flow@alpha memory store "workflows/${workflowId}" '${JSON.stringify(workflowState)}' --namespace ${testNamespace}`
|
|
);
|
|
|
|
// Verify coordination state
|
|
const retrievedState = await execCommand(
|
|
`npx claude-flow@alpha memory retrieve "workflows/${workflowId}" --namespace ${testNamespace}`
|
|
);
|
|
|
|
const parsed = JSON.parse(retrievedState);
|
|
expect(parsed.agents['test-generator']).toBe('completed');
|
|
expect(parsed.agents['coverage-analyzer']).toBe('active');
|
|
expect(parsed.progress.testsGenerated).toBe(100);
|
|
}, timeout);
|
|
|
|
it('should handle agent failure and recovery coordination', async () => {
|
|
const agentId = 'failing-agent-001';
|
|
|
|
// Store failing agent state
|
|
const failureState = {
|
|
agentId,
|
|
status: 'error',
|
|
error: 'Network timeout during test execution',
|
|
timestamp: new Date().toISOString(),
|
|
retryCount: 0
|
|
};
|
|
|
|
await execCommand(
|
|
`npx claude-flow@alpha memory store "agents/${agentId}" '${JSON.stringify(failureState)}' --namespace ${testNamespace}`
|
|
);
|
|
|
|
// Simulate recovery attempt
|
|
failureState.status = 'recovering';
|
|
failureState.retryCount = 1;
|
|
|
|
await execCommand(
|
|
`npx claude-flow@alpha memory store "agents/${agentId}" '${JSON.stringify(failureState)}' --namespace ${testNamespace}`
|
|
);
|
|
|
|
// Verify recovery state
|
|
const recoveryState = await execCommand(
|
|
`npx claude-flow@alpha memory retrieve "agents/${agentId}" --namespace ${testNamespace}`
|
|
);
|
|
|
|
const parsed = JSON.parse(recoveryState);
|
|
expect(parsed.status).toBe('recovering');
|
|
expect(parsed.retryCount).toBe(1);
|
|
}, timeout);
|
|
|
|
it('should coordinate load balancing across agents', async () => {
|
|
const testAgents = ['agent-1', 'agent-2', 'agent-3'];
|
|
const workloads = [25, 50, 75]; // Different workload percentages
|
|
|
|
// Store workload information for each agent
|
|
for (let i = 0; i < testAgents.length; i++) {
|
|
const workloadState = {
|
|
agentId: testAgents[i],
|
|
currentWorkload: workloads[i],
|
|
capacity: 100,
|
|
availableFor: workloads[i] < 80 ? 'new-tasks' : 'none',
|
|
taskQueue: Array(Math.floor(workloads[i] / 10)).fill('task')
|
|
};
|
|
|
|
await execCommand(
|
|
`npx claude-flow@alpha memory store "workload/${testAgents[i]}" '${JSON.stringify(workloadState)}' --namespace ${testNamespace}`
|
|
);
|
|
}
|
|
|
|
// Find agents available for new tasks
|
|
const searchResult = await execCommand(
|
|
`npx claude-flow@alpha memory search "availableFor.*new-tasks" --namespace ${testNamespace}`
|
|
);
|
|
|
|
expect(searchResult).toContain('agent-1');
|
|
expect(searchResult).toContain('agent-2');
|
|
expect(searchResult).not.toContain('agent-3'); // Should be at capacity
|
|
}, timeout);
|
|
});
|
|
|
|
describe('Performance and Scalability', () => {
|
|
it('should handle large-scale coordination data efficiently', async () => {
|
|
const numAgents = 100;
|
|
const startTime = Date.now();
|
|
|
|
// Store data for many agents
|
|
const promises = Array(numAgents).fill(0).map(async (_, index) => {
|
|
const agentData = {
|
|
agentId: `agent-${index}`,
|
|
status: index % 3 === 0 ? 'active' : index % 3 === 1 ? 'idle' : 'busy',
|
|
task: `task-${index}`,
|
|
progress: Math.floor(Math.random() * 100)
|
|
};
|
|
|
|
await execCommand(
|
|
`npx claude-flow@alpha memory store "scale-test/${agentData.agentId}" '${JSON.stringify(agentData)}' --namespace ${testNamespace}`
|
|
);
|
|
});
|
|
|
|
await Promise.all(promises);
|
|
const endTime = Date.now();
|
|
|
|
expect(endTime - startTime).toBeLessThan(10000); // Should complete within 10 seconds
|
|
|
|
// Verify we can still query efficiently
|
|
const queryStart = Date.now();
|
|
const activeAgents = await execCommand(
|
|
`npx claude-flow@alpha memory search "status.*active" --namespace ${testNamespace}`
|
|
);
|
|
const queryEnd = Date.now();
|
|
|
|
expect(queryEnd - queryStart).toBeLessThan(1000); // Query should be fast
|
|
expect(activeAgents.split('\n').length).toBeGreaterThan(1); // Should find some active agents
|
|
}, timeout);
|
|
|
|
it('should maintain coordination under concurrent operations', async () => {
|
|
const concurrentOps = 20;
|
|
const promises = Array(concurrentOps).fill(0).map(async (_, index) => {
|
|
// Mix of store and retrieve operations
|
|
if (index % 2 === 0) {
|
|
const data = { operation: 'store', index, timestamp: Date.now() };
|
|
await execCommand(
|
|
`npx claude-flow@alpha memory store "concurrent/${index}" '${JSON.stringify(data)}' --namespace ${testNamespace}`
|
|
);
|
|
} else {
|
|
try {
|
|
await execCommand(
|
|
`npx claude-flow@alpha memory retrieve "concurrent/${index - 1}" --namespace ${testNamespace}`
|
|
);
|
|
} catch (error) {
|
|
// Handle case where data doesn't exist yet
|
|
}
|
|
}
|
|
});
|
|
|
|
// All operations should complete without errors
|
|
await expect(Promise.all(promises)).resolves.toBeDefined();
|
|
}, timeout);
|
|
});
|
|
|
|
describe('Error Handling and Resilience', () => {
|
|
it('should handle network interruptions gracefully', async () => {
|
|
// This test simulates network issues by attempting operations on invalid namespaces
|
|
await expect(
|
|
execCommand(`npx claude-flow@alpha memory store "test" "data" --namespace "invalid/namespace"`)
|
|
).rejects.toThrow();
|
|
}, timeout);
|
|
|
|
it('should recover from memory corruption scenarios', async () => {
|
|
const validData = { test: 'data', number: 42 };
|
|
|
|
// Store valid data
|
|
await execCommand(
|
|
`npx claude-flow@alpha memory store "corruption-test" '${JSON.stringify(validData)}' --namespace ${testNamespace}`
|
|
);
|
|
|
|
// Verify we can retrieve it
|
|
const retrieved = await execCommand(
|
|
`npx claude-flow@alpha memory retrieve "corruption-test" --namespace ${testNamespace}`
|
|
);
|
|
|
|
const parsed = JSON.parse(retrieved);
|
|
expect(parsed.test).toBe('data');
|
|
expect(parsed.number).toBe(42);
|
|
}, timeout);
|
|
|
|
it('should handle malformed data gracefully', async () => {
|
|
// Attempt to store invalid JSON (this should be caught by Claude Flow)
|
|
await expect(
|
|
execCommand(`npx claude-flow@alpha memory store "malformed" 'invalid-json{' --namespace ${testNamespace}`)
|
|
).rejects.toThrow();
|
|
}, timeout);
|
|
});
|
|
|
|
describe('Security and Access Control', () => {
|
|
it('should isolate data between namespaces', async () => {
|
|
const namespace1 = `${testNamespace}-1`;
|
|
const namespace2 = `${testNamespace}-2`;
|
|
|
|
const data1 = { namespace: 1, secret: 'secret1' };
|
|
const data2 = { namespace: 2, secret: 'secret2' };
|
|
|
|
// Store data in different namespaces
|
|
await execCommand(
|
|
`npx claude-flow@alpha memory store "secret-data" '${JSON.stringify(data1)}' --namespace ${namespace1}`
|
|
);
|
|
|
|
await execCommand(
|
|
`npx claude-flow@alpha memory store "secret-data" '${JSON.stringify(data2)}' --namespace ${namespace2}`
|
|
);
|
|
|
|
// Retrieve from each namespace
|
|
const retrieved1 = await execCommand(
|
|
`npx claude-flow@alpha memory retrieve "secret-data" --namespace ${namespace1}`
|
|
);
|
|
|
|
const retrieved2 = await execCommand(
|
|
`npx claude-flow@alpha memory retrieve "secret-data" --namespace ${namespace2}`
|
|
);
|
|
|
|
const parsed1 = JSON.parse(retrieved1);
|
|
const parsed2 = JSON.parse(retrieved2);
|
|
|
|
expect(parsed1.secret).toBe('secret1');
|
|
expect(parsed2.secret).toBe('secret2');
|
|
expect(parsed1.secret).not.toBe(parsed2.secret);
|
|
|
|
// Cleanup
|
|
await execCommand(`npx claude-flow@alpha memory clear --namespace ${namespace1}`);
|
|
await execCommand(`npx claude-flow@alpha memory clear --namespace ${namespace2}`);
|
|
}, timeout);
|
|
});
|
|
});
|
|
|
|
// Helper function to execute commands and return output
|
|
async function execCommand(command: string): Promise<string> {
|
|
return new Promise((resolve, reject) => {
|
|
const [cmd, ...args] = command.split(' ');
|
|
const child = spawn(cmd, args, { shell: true });
|
|
|
|
let stdout = '';
|
|
let stderr = '';
|
|
|
|
child.stdout?.on('data', (data) => {
|
|
stdout += data.toString();
|
|
});
|
|
|
|
child.stderr?.on('data', (data) => {
|
|
stderr += data.toString();
|
|
});
|
|
|
|
child.on('close', (code) => {
|
|
if (code === 0) {
|
|
resolve(stdout.trim());
|
|
} else {
|
|
reject(new Error(`Command failed with code ${code}: ${stderr}`));
|
|
}
|
|
});
|
|
|
|
child.on('error', (error) => {
|
|
reject(error);
|
|
});
|
|
});
|
|
} |