mirror of
https://github.com/proffesor-for-testing/agentic-qe.git
synced 2026-09-19 08:45:47 +08:00
b91627f282
Phase 1: Test Determinism - Create SeededRandom utility with Mulberry32 PRNG (src/utils/SeededRandom.ts) - Migrate 258+ Math.random() calls to SeededRandom across 65+ test files - Add timer test utilities (tests/helpers/timerTestUtils.ts) - Add jest.useFakeTimers() pattern to 13 test files Phase 2: Type Safety (63.5% reduction) - Reduce `any` types from ~1,800 to 656 - Add 50+ new interfaces across agents, core, mcp, cli modules - Fix all TypeScript errors (0 errors, build passes) - Replace Record<string, any> with Record<string, unknown> - Add proper type guards for hook methods (PostTaskData, TaskErrorData) Key improvements: - agents/: 105 → 0 any types (100% reduction) - mcp/: 226 → 102 any types (55% reduction) - cli/: 277 → 168 any types (39% reduction) - core/: 199 → 175 any types (12% reduction) Closes #149 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
234 lines
9.2 KiB
JavaScript
234 lines
9.2 KiB
JavaScript
/**
|
|
* Integration Test Suite: Memory Persistence
|
|
* Tests Claude Flow memory operations, cross-session persistence, and state management
|
|
*/
|
|
|
|
const { execSync } = require('child_process');
|
|
const fs = require('fs').promises;
|
|
const path = require('path');
|
|
const { createSeededRandom } = require('../../src/utils/SeededRandom');
|
|
|
|
describe('Memory Persistence Integration Tests', () => {
|
|
const memoryNamespace = 'aqe-memory-test';
|
|
const testSessionId = `session-${Date.now()}`;
|
|
|
|
beforeEach(async () => {
|
|
// Clear any existing test data
|
|
try {
|
|
await execCommand(`npx claude-flow@alpha memory clear --namespace "${memoryNamespace}"`);
|
|
} catch (error) {
|
|
// Namespace might not exist, continue
|
|
}
|
|
});
|
|
|
|
describe('Basic Memory Operations', () => {
|
|
test('6. Store and retrieve test execution state', async () => {
|
|
const testState = {
|
|
currentSuite: 'UserService',
|
|
testsCompleted: 15,
|
|
testsFailed: 2,
|
|
coverage: 85.7,
|
|
timestamp: new Date().toISOString()
|
|
};
|
|
|
|
// Store state
|
|
await execCommand(`npx claude-flow@alpha memory store "test-execution-state" '${JSON.stringify(testState)}' --namespace "${memoryNamespace}"`);
|
|
|
|
// Retrieve state
|
|
const retrievedState = await execCommand(`npx claude-flow@alpha memory get "test-execution-state" --namespace "${memoryNamespace}"`);
|
|
const parsedState = JSON.parse(retrievedState.trim());
|
|
|
|
expect(parsedState.currentSuite).toBe('UserService');
|
|
expect(parsedState.testsCompleted).toBe(15);
|
|
expect(parsedState.coverage).toBe(85.7);
|
|
});
|
|
|
|
test('7. Agent coordination through shared memory', async () => {
|
|
const coordinationData = {
|
|
agentQueue: ['qe-test-generator', 'qe-coverage-analyzer', 'qe-quality-gate'],
|
|
currentAgent: 'qe-test-generator',
|
|
sharedContext: {
|
|
projectPath: '/test/project',
|
|
framework: 'jest',
|
|
targetCoverage: 90
|
|
}
|
|
};
|
|
|
|
// Store coordination data
|
|
await execCommand(`npx claude-flow@alpha memory store "agent-coordination" '${JSON.stringify(coordinationData)}' --namespace "${memoryNamespace}"`);
|
|
|
|
// Simulate agent updating coordination state
|
|
const updatedData = { ...coordinationData };
|
|
updatedData.currentAgent = 'qe-coverage-analyzer';
|
|
updatedData.agentQueue.shift(); // Remove completed agent
|
|
|
|
await execCommand(`npx claude-flow@alpha memory store "agent-coordination" '${JSON.stringify(updatedData)}' --namespace "${memoryNamespace}"`);
|
|
|
|
// Verify update
|
|
const finalState = await execCommand(`npx claude-flow@alpha memory get "agent-coordination" --namespace "${memoryNamespace}"`);
|
|
const parsedFinalState = JSON.parse(finalState.trim());
|
|
|
|
expect(parsedFinalState.currentAgent).toBe('qe-coverage-analyzer');
|
|
expect(parsedFinalState.agentQueue).toHaveLength(2);
|
|
});
|
|
|
|
test('8. Memory namespace isolation', async () => {
|
|
const namespace1 = 'aqe-project-a';
|
|
const namespace2 = 'aqe-project-b';
|
|
|
|
// Store same key in different namespaces
|
|
await execCommand(`npx claude-flow@alpha memory store "project-config" '{"name": "Project A"}' --namespace "${namespace1}"`);
|
|
await execCommand(`npx claude-flow@alpha memory store "project-config" '{"name": "Project B"}' --namespace "${namespace2}"`);
|
|
|
|
// Retrieve from each namespace
|
|
const configA = await execCommand(`npx claude-flow@alpha memory get "project-config" --namespace "${namespace1}"`);
|
|
const configB = await execCommand(`npx claude-flow@alpha memory get "project-config" --namespace "${namespace2}"`);
|
|
|
|
expect(JSON.parse(configA.trim()).name).toBe('Project A');
|
|
expect(JSON.parse(configB.trim()).name).toBe('Project B');
|
|
});
|
|
});
|
|
|
|
describe('Cross-Session Persistence', () => {
|
|
test('9. Session state preservation across restarts', async () => {
|
|
const sessionState = {
|
|
sessionId: testSessionId,
|
|
agentStates: {
|
|
'qe-test-generator': { status: 'completed', output: 'test-files' },
|
|
'qe-coverage-analyzer': { status: 'running', progress: 65 }
|
|
},
|
|
globalContext: {
|
|
totalTests: 150,
|
|
passRate: 94.5
|
|
}
|
|
};
|
|
|
|
// Store session state
|
|
await execCommand(`npx claude-flow@alpha memory store "session-${testSessionId}" '${JSON.stringify(sessionState)}' --namespace "${memoryNamespace}"`);
|
|
|
|
// Simulate session restart by clearing local cache (if any)
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
|
|
// Restore session state
|
|
const restoredState = await execCommand(`npx claude-flow@alpha memory get "session-${testSessionId}" --namespace "${memoryNamespace}"`);
|
|
const parsedRestoredState = JSON.parse(restoredState.trim());
|
|
|
|
expect(parsedRestoredState.sessionId).toBe(testSessionId);
|
|
expect(parsedRestoredState.agentStates['qe-test-generator'].status).toBe('completed');
|
|
expect(parsedRestoredState.globalContext.totalTests).toBe(150);
|
|
});
|
|
|
|
test('10. Memory-based agent recovery after failure', async () => {
|
|
const agentCheckpoint = {
|
|
agentId: 'qe-coverage-001',
|
|
lastOperation: 'analyzing-coverage',
|
|
processedFiles: ['user.service.js', 'auth.service.js'],
|
|
pendingFiles: ['payment.service.js', 'notification.service.js'],
|
|
partialResults: {
|
|
totalLines: 2500,
|
|
coveredLines: 2100
|
|
},
|
|
checkpointTimestamp: new Date().toISOString()
|
|
};
|
|
|
|
// Store checkpoint
|
|
await execCommand(`npx claude-flow@alpha memory store "agent-checkpoint-qe-coverage-001" '${JSON.stringify(agentCheckpoint)}' --namespace "${memoryNamespace}"`);
|
|
|
|
// Simulate agent failure and recovery
|
|
const recoveryState = await execCommand(`npx claude-flow@alpha memory get "agent-checkpoint-qe-coverage-001" --namespace "${memoryNamespace}"`);
|
|
const parsedRecoveryState = JSON.parse(recoveryState.trim());
|
|
|
|
expect(parsedRecoveryState.agentId).toBe('qe-coverage-001');
|
|
expect(parsedRecoveryState.processedFiles).toHaveLength(2);
|
|
expect(parsedRecoveryState.pendingFiles).toHaveLength(2);
|
|
expect(parsedRecoveryState.partialResults.coveredLines).toBe(2100);
|
|
});
|
|
});
|
|
|
|
describe('Memory Performance and Scalability', () => {
|
|
test('11. High-volume memory operations', async () => {
|
|
const startTime = Date.now();
|
|
const operations = [];
|
|
|
|
// Store 100 test result records
|
|
const rng = createSeededRandom(27200);
|
|
for (let i = 0; i < 100; i++) {
|
|
const testResult = {
|
|
testId: `test-${i}`,
|
|
suite: `Suite${Math.floor(i / 10)}`,
|
|
status: i % 10 === 0 ? 'failed' : 'passed',
|
|
duration: rng.random() * 1000,
|
|
timestamp: new Date().toISOString()
|
|
};
|
|
|
|
operations.push(
|
|
execCommand(`npx claude-flow@alpha memory store "test-result-${i}" '${JSON.stringify(testResult)}' --namespace "${memoryNamespace}"`)
|
|
);
|
|
}
|
|
|
|
await Promise.all(operations);
|
|
const endTime = Date.now();
|
|
|
|
expect(endTime - startTime).toBeLessThan(10000); // Should complete within 10 seconds
|
|
|
|
// Verify a few random entries
|
|
const randomIndices = [5, 25, 75];
|
|
for (const index of randomIndices) {
|
|
const result = await execCommand(`npx claude-flow@alpha memory get "test-result-${index}" --namespace "${memoryNamespace}"`);
|
|
const parsedResult = JSON.parse(result.trim());
|
|
expect(parsedResult.testId).toBe(`test-${index}`);
|
|
}
|
|
});
|
|
|
|
test('12. Memory cleanup and garbage collection', async () => {
|
|
// Store temporary data with TTL simulation
|
|
const tempData = Array.from({ length: 50 }, (_, i) => ({
|
|
key: `temp-data-${i}`,
|
|
value: { data: `temporary-${i}`, created: Date.now() }
|
|
}));
|
|
|
|
// Store all temp data
|
|
for (const item of tempData) {
|
|
await execCommand(`npx claude-flow@alpha memory store "${item.key}" '${JSON.stringify(item.value)}' --namespace "${memoryNamespace}"`);
|
|
}
|
|
|
|
// Simulate cleanup of old data (remove every other item)
|
|
const cleanupOperations = [];
|
|
for (let i = 0; i < tempData.length; i += 2) {
|
|
cleanupOperations.push(
|
|
execCommand(`npx claude-flow@alpha memory delete "${tempData[i].key}" --namespace "${memoryNamespace}"`)
|
|
);
|
|
}
|
|
|
|
await Promise.all(cleanupOperations);
|
|
|
|
// Verify cleanup worked
|
|
let remainingItems = 0;
|
|
for (let i = 1; i < tempData.length; i += 2) {
|
|
try {
|
|
await execCommand(`npx claude-flow@alpha memory get "${tempData[i].key}" --namespace "${memoryNamespace}"`);
|
|
remainingItems++;
|
|
} catch (error) {
|
|
// Item was deleted, expected
|
|
}
|
|
}
|
|
|
|
expect(remainingItems).toBe(25); // Half should remain
|
|
});
|
|
});
|
|
});
|
|
|
|
// Helper function for command execution
|
|
async function execCommand(command) {
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
const result = execSync(command, {
|
|
encoding: 'utf8',
|
|
timeout: 5000 // 5 second timeout
|
|
});
|
|
resolve(result);
|
|
} catch (error) {
|
|
reject(error);
|
|
}
|
|
});
|
|
} |