Files
proffesor-for-testing__agen…/tests/unit/agents/BaseAgent.enhanced.test.ts
Profa 2b71ae4eb8 release: v1.3.6 - Security, Quality & Documentation Overhaul
## 🔒 Security Fixes

### eval() Removal - Critical Security Vulnerability Fixed
- **File**: `src/agents/TestDataArchitectAgent.ts`
- **Impact**: Eliminated arbitrary code execution risk
- **Solution**: Implemented safe expression evaluator with parser-based approach
- **Supports**:
  - Comparison operators: `===`, `!==`, `==`, `!=`, `>`, `<`, `>=`, `<=`
  - Logical operators: `&&`, `||`
  - Boolean values: `true`, `false`
  - Number and string comparisons
- **Lines**: 102 lines added (safeEvaluateExpression + parseValue methods)

## ✨ UX Enhancements

### CLAUDE.md Append Strategy - User-Requested Feature
- **File**: `src/cli/commands/init.ts`
- **User Feedback**: "AQE instructions should append by default, not prepend"
- **Interactive Mode**: Prompts user to choose prepend or append
- **--yes Mode**: Defaults to append (less disruptive to existing configs)
- **Features**:
  - Auto-backup existing CLAUDE.md to CLAUDE.md.backup
  - Clear visual separator (---) between sections
  - User confirmation messages
- **Lines**: 49 lines modified

### CLI Skills Count Fix - Accurate Display
- **File**: `src/cli/commands/skills/index.ts`
- **Before**: Showed "8/17" (hardcoded, incorrect)
- **After**: Shows "34/34" (dynamic, accurate)
- **Solution**: Added `getTotalQESkillsCount()` method using `QE_SKILLS.flatMap()`
- **Future-proof**: Auto-updates when skills added
- **Lines**: 11 lines modified

## 🎓 New Agent - Cherry-Picked from PR #22

### CodeComplexityAnalyzerAgent Integration
- **Author**: @mondweep (PR #22)
- **Purpose**: Educational code complexity analysis and refactoring recommendations
- **Files**: 7 files, 2,758 lines of code
- **Capabilities**:
  - Cyclomatic complexity calculation
  - Cognitive complexity analysis
  - AI-powered refactoring suggestions
  - Quality scoring (0-100 scale)
  - Memory integration (`aqe/complexity/*`)
- **Test Coverage**: 529 lines, 13+ test scenarios
- **Documentation**: 754 lines (README + Claude agent definition)
- **Examples**: 871 lines (3 interactive examples)

## 🔧 Code Quality Improvements

### Agent Enhancements
- **BaseAgent.ts**: 136 lines modified
  - Improved property access patterns
  - Better encapsulation with public accessors
  - Enhanced lifecycle management

- **TestGeneratorAgent.ts**: 377 lines added
  - Comprehensive null safety improvements
  - Enhanced error handling
  - Better context validation

- **QualityGateAgent.ts**: 64 lines modified
  - Improved context handling
  - Better validation logic

### MCP Handler Improvements
- **test-generate.ts**: 33 lines modified (better parameter handling)
- **quality-analyze.ts**: 28 lines modified (context fix)
- **regression-risk-analyze.ts**: 85 lines modified (parameter aliasing fix)

### Infrastructure Additions
- **AgentLifecycleManager.ts**: 274 new lines (lifecycle coordination)
- **SwarmMemoryManager.ts**: 3 lines modified (improved coordination)
- **AgentRegistry.ts**: 20 lines added (better agent registration)

## 🧪 Testing Enhancements

### New Integration Tests (5 Test Suites)
- **fleet-management.integration.test.ts**: 491 lines
- **parameter-validation.integration.test.ts**: 606 lines
- **quality-analyze.integration.test.ts**: 393 lines
- **regression-risk.integration.test.ts**: 505 lines
- **test-execution.integration.test.ts**: 536 lines
- **test-harness.ts**: 289 lines (shared test utilities)
- **Total**: 2,820 lines of integration test coverage

### Enhanced Unit Tests
- **BaseAgent.enhanced.test.ts**: 909 lines (comprehensive BaseAgent testing)
- **TestGeneratorAgent.null-safety.test.ts**: 1,511 lines (null safety validation)
- **Total**: 2,420 lines of new unit test coverage

### Test Improvements
- **PredictionTools.test.ts**: 118 lines modified
- **Agent.test.ts**: 11 lines modified

## 📚 Documentation Expansion (27,439 insertions)

### Release Documentation (7 documents)
- **RELEASE-1.3.6-PREPARATION.md**: 443 lines (complete release checklist)
- **SECURITY-SCAN-RELEASE-1.3.6.md**: 422 lines (security validation)
- **THREE-ISSUE-FIXES-SUMMARY.md**: 196 lines (user-reported fixes)
- **CHERRY-PICK-PR22-SUMMARY.md**: 412 lines (integration details)
- **FINAL-STATUS-REPORT-2025-10-30.md**: 403 lines (status summary)
- **FINAL-MCP-VERIFICATION-SUMMARY.md**: 338 lines (MCP validation)
- **MCP-PRODUCTION-READINESS-REPORT.md**: 318 lines (production readiness)

### Technical Documentation (7 documents)
- **MCP-TOOLS-REFERENCE.md**: 1,555 lines (complete MCP API reference)
- **MCP-TOOLS-USER-GUIDE.md**: 626 lines (user guide)
- **MCP-TOOLS-AUTO-GENERATED.md**: 934 lines (auto-generated docs)
- **MCP-TOOLS-MIGRATION.md**: 437 lines (migration guide)
- **complexity-mitigation-plan.md**: 537 lines (code quality roadmap)
- **swarm-execution-report.md**: 985 lines (execution analysis)
- **HONEST-IMPLEMENTATION-ANALYSIS.md**: 62 lines (transparency report)

### Fix Documentation (7 documents)
- **MCP-TOOLS-COMPLETE-FIX-REPORT.md**: 619 lines (comprehensive fix report)
- **three-issue-fixes.md**: 345 lines (user-reported fixes)
- **quality-analyze-context-fix.md**: 195 lines
- **regression-risk-parameter-aliasing.md**: 303 lines
- **test-generator-agent-null-safety-fixes.md**: 422 lines
- **typescript-compilation-errors-fixed-2025-10-30.md**: 273 lines
- **MCP-TOOLS-FIX-SUMMARY.md**: 272 lines

### Refactoring Plans (4 documents)
- **swarm-memory-manager-refactoring-plan.md**: 796 lines
- **base-agent-refactoring-plan.md**: 658 lines
- **refactoring-summary.md**: 404 lines
- **REFACTORING_STATUS.md**: 210 lines

### Testing Documentation (6 documents)
- **mcp-tools-test-report.md**: 1,260 lines (comprehensive test report)
- **testing-workflow.md**: 691 lines (MCP testing guide)
- **TestGeneratorAgent-test-plan.md**: 318 lines (test plan)
- **coverage-analysis-2025-10-30.md**: 661 lines (coverage report)
- **regression-validation-report-2025-10-30.md**: 450 lines (regression validation)
- **README.md** (tests/integration/mcp): 277 lines (integration test guide)

### CI/CD Documentation (3 documents)
- **mcp-cicd-pipeline.md**: 402 lines (pipeline architecture)
- **mcp-pipeline-setup-summary.md**: 343 lines (setup guide)
- **mcp-cicd-implementation-notes.md**: 280 lines (implementation notes)

### MCP Verification (2 documents)
- **MCP-VERIFICATION-SUMMARY.md**: 286 lines
- **PR-22-ANALYSIS.md**: 373 lines

### Coverage Analysis (2 documents)
- **coverage-analysis-2025-10-30.md**: 661 lines
- **coverage-analysis-summary.json**: 417 lines (structured data)

## 🛠️ Scripts & Automation (5 Scripts, 2,117 Lines)

### New Utility Scripts
- **validate-mcp-tools.js**: 280 lines (MCP tool validation)
- **generate-mcp-report.js**: 252 lines (report generation)
- **generate-mcp-docs.js**: 270 lines (documentation generation)
- **verify-mcp-production-readiness.js**: 564 lines (production checks)
- **test-issue-fixes.js**: 224 lines (fix verification)
- **mcp-tools-summary.json**: 344 lines (structured summary)

## 📊 Examples & Guides

### MCP Integration Examples (2 Examples)
- **basic-test-generation.js**: 200 lines (starter example)
- **quality-analysis-pipeline.js**: 360 lines (advanced workflow)

## ⚙️ CI/CD Enhancements

### GitHub Actions Workflow
- **.github/workflows/mcp-tools-test.yml**: 197 lines
  - Automated MCP tool testing
  - Multi-environment validation
  - Production readiness checks

### Git Hooks
- **.husky/pre-commit**: 14 lines (pre-commit validation)

## 📦 Configuration Updates

### Version & Dependencies
- **package.json**: Version bumped to 1.3.6
- **package-lock.json**: Dependency lock updated
- **README.md**: Version references updated (27 lines modified)
- **.claude/settings.json**: 4 lines modified

### CHANGELOG
- **CHANGELOG.md**: 37 lines added
  - Complete v1.3.6 changelog entry
  - Security fixes documented
  - UX enhancements documented
  - Testing improvements documented

## 📈 Statistics Summary

### Code Changes
- **78 files changed**
- **27,439 insertions** (+)
- **181 deletions** (-)
- **Net change**: +27,258 lines

### Breakdown by Category
- **Source Code**: ~1,200 lines (agents, handlers, infrastructure)
- **Tests**: ~5,240 lines (integration + unit tests)
- **Documentation**: ~18,000 lines (guides, reports, plans)
- **Scripts**: ~2,117 lines (automation utilities)
- **Examples**: ~560 lines (MCP examples)
- **CI/CD**: ~211 lines (workflows + hooks)

### Quality Metrics
- ✅ **TypeScript Compilation**: 0 errors (16 errors fixed)
- ✅ **Security Vulnerabilities**: 0 critical (1 fixed)
- ✅ **Integration Tests**: 5 new test suites, 2,820 lines
- ✅ **Unit Tests**: 2,420 new lines
- ✅ **Documentation**: 100% comprehensive coverage
- ✅ **Backward Compatibility**: 100% maintained

## 🎯 User Impact

### Immediate Benefits
1. **Security**: Eliminates arbitrary code execution vulnerability
2. **UX**: Less disruptive CLAUDE.md initialization
3. **Accuracy**: Correct skills count display (34/34)
4. **Quality**: CodeComplexityAnalyzerAgent for refactoring guidance
5. **Reliability**: 16 TypeScript errors resolved

### Developer Experience
1. **Better Documentation**: 18,000+ lines of guides and references
2. **Better Testing**: 5,240 new lines of test coverage
3. **Better Tooling**: 2,117 lines of automation scripts
4. **Better Examples**: MCP integration examples
5. **Better CI/CD**: Automated testing and validation

## 🔄 Migration & Compatibility

### Breaking Changes
- **NONE** - Fully backward compatible

### Deprecations
- **NONE**

### New Features (Opt-in)
- CodeComplexityAnalyzerAgent (available via Claude Code or MCP)
- Interactive CLAUDE.md placement (interactive mode only)

## ✅ Verification

### Pre-Release Checks
- ✅ TypeScript compilation: 0 errors
- ✅ All three user-reported fixes verified
- ✅ Integration tests passing
- ✅ Documentation complete
- ✅ CHANGELOG updated
- ✅ Version numbers updated (package.json, README.md)
- ✅ Security scan: No vulnerabilities
- ✅ Backward compatibility verified

### Production Readiness
- ✅ MCP tools validated (54 tools)
- ✅ Agent registry verified (17 agents)
- ✅ Skills library verified (34 skills)
- ✅ CI/CD pipeline configured
- ✅ Pre-commit hooks installed

## 🙏 Acknowledgments

- **@mondweep**: CodeComplexityAnalyzerAgent contribution (PR #22)
- **User Feedback**: CLAUDE.md append strategy request
- **User Feedback**: CLI skills count display bug report
- **User Feedback**: eval() security concern

## 📝 Release Notes

**Version**: 1.3.6
**Date**: 2025-10-30
**Type**: Security & Quality Patch Release
**Status**: Production Ready

**Upgrade Recommendation**: 🔴 **HIGH PRIORITY**
- Security vulnerability fixed (eval() removal)
- User experience improvements
- Enhanced stability (16 TypeScript errors fixed)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-30 18:23:09 +00:00

910 lines
25 KiB
TypeScript

/**
* Enhanced BaseAgent Test Suite - Targeting High-Risk Areas (Lines 76-157)
* Focus: Uncovered code paths, edge cases, and high-defect-risk function2
*
* Target Coverage: >80% (currently 62.84%)
* High-Risk Area: Lines 76-157 (57.4% defect risk)
*/
import { BaseAgent, BaseAgentConfig } from '../../../src/agents/BaseAgent';
import { SwarmMemoryManager } from '../../../src/core/memory/SwarmMemoryManager';
import { EventEmitter } from 'events';
import {
QEAgentType as AgentType,
AgentStatus,
AgentCapability,
AgentContext,
QETask,
TaskAssignment,
MemoryStore
} from '../../../src/types';
import * as path from 'path';
import * as fs from 'fs-extra';
// Mock MemoryStore implementation for null memory scenarios
class NullMemoryStore implements MemoryStore {
async initialize(): Promise<void> {}
async store(key: string, value: any, ttl?: number): Promise<void> {}
async retrieve(key: string): Promise<any> {
return null;
}
async delete(key: string): Promise<void> {}
async query(pattern: string): Promise<any[]> {
return [];
}
async close(): Promise<void> {}
// Required by MemoryStoreAdapter
async set(key: string, value: any, ttl?: number): Promise<void> {}
async get(key: string): Promise<any> {
return null;
}
async clear(): Promise<void> {}
}
// Test agent implementation
class EnhancedTestAgent extends BaseAgent {
public shouldFailInit = false;
public shouldFailTask = false;
public shouldFailCleanup = false;
public taskResult: any = { success: true };
protected async initializeComponents(): Promise<void> {
if (this.shouldFailInit) throw new Error('Init component failed');
}
protected async performTask(task: QETask): Promise<any> {
if (this.shouldFailTask) throw new Error('Task perform failed');
return { ...this.taskResult, taskId: task.id };
}
protected async loadKnowledge(): Promise<void> {}
protected async cleanup(): Promise<void> {
if (this.shouldFailCleanup) throw new Error('Cleanup failed');
}
// Expose protected methods for testing
public exposeStoreMemory(key: string, value: any, ttl?: number) {
return this.storeMemory(key, value, ttl);
}
public exposeRetrieveMemory(key: string) {
return this.retrieveMemory(key);
}
public exposeStoreSharedMemory(key: string, value: any, ttl?: number) {
return this.storeSharedMemory(key, value, ttl);
}
public exposeRetrieveSharedMemory(agentType: AgentType, key: string) {
return this.retrieveSharedMemory(agentType, key);
}
public exposeEmitEvent(type: string, data: any, priority?: any) {
return this.emitEvent(type, data, priority);
}
public exposeBroadcastMessage(type: string, payload: any) {
return this.broadcastMessage(type, payload);
}
// Access protected properties
public getAgentDBConfig() {
return (this as any).agentDBConfig;
}
public getPerformanceTracker() {
return (this as any).performanceTracker;
}
public getLearningEngineInternal() {
return (this as any).learningEngine;
}
}
describe('BaseAgent - Enhanced Coverage (High-Risk Lines 76-157)', () => {
let memoryStore: SwarmMemoryManager;
let eventBus: EventEmitter;
let testDbPath: string;
const capabilities: AgentCapability[] = [
{
name: 'test-capability',
version: '1.0.0',
description: 'Test capability',
taskTypes: ['test'],
parameters: {}
}
];
const context: AgentContext = {
id: 'ctx',
type: 'test-generator',
status: AgentStatus.IDLE,
metadata: {}
};
beforeEach(async () => {
testDbPath = ':memory:';
memoryStore = new SwarmMemoryManager(testDbPath);
await memoryStore.initialize();
eventBus = new EventEmitter();
});
afterEach(async () => {
if (memoryStore) {
await memoryStore.close();
}
});
describe('Constructor - AgentDB Config Building (Lines 101-115)', () => {
it('should build AgentDB config from agentDBConfig parameter', () => {
const agentDBConfig = {
dbPath: '/custom/path.db',
enableQUICSync: true,
syncPort: 5000,
syncPeers: ['peer1:4433', 'peer2:4433'],
enableLearning: true,
enableReasoning: false,
cacheSize: 2000,
quantizationType: 'binary' as const
};
const agent = new EnhancedTestAgent({
type: 'test-generator' as AgentType,
capabilities,
context,
memoryStore,
eventBus,
agentDBConfig
});
const config = agent.getAgentDBConfig();
expect(config).toEqual(agentDBConfig);
expect(config?.dbPath).toBe('/custom/path.db');
expect(config?.enableQUICSync).toBe(true);
expect(config?.syncPort).toBe(5000);
expect(config?.quantizationType).toBe('binary');
});
it('should build AgentDB config from shorthand properties (agentDBPath)', () => {
const agent = new EnhancedTestAgent({
type: 'test-generator' as AgentType,
capabilities,
context,
memoryStore,
eventBus,
agentDBPath: '/shorthand/path.db'
});
const config = agent.getAgentDBConfig();
expect(config?.dbPath).toBe('/shorthand/path.db');
expect(config?.enableQUICSync).toBe(false);
expect(config?.syncPort).toBe(4433); // default
expect(config?.quantizationType).toBe('scalar'); // default
});
it('should build AgentDB config from shorthand properties (enableQUICSync)', () => {
const agent = new EnhancedTestAgent({
type: 'test-generator' as AgentType,
capabilities,
context,
memoryStore,
eventBus,
enableQUICSync: true,
syncPort: 9000,
syncPeers: ['peer1:9000']
});
const config = agent.getAgentDBConfig();
expect(config?.enableQUICSync).toBe(true);
expect(config?.syncPort).toBe(9000);
expect(config?.syncPeers).toEqual(['peer1:9000']);
expect(config?.dbPath).toBe('.agentdb/reasoningbank.db'); // default
});
it('should build AgentDB config with custom quantization type', () => {
const agent = new EnhancedTestAgent({
type: 'test-generator' as AgentType,
capabilities,
context,
memoryStore,
eventBus,
agentDBPath: '/path.db',
quantizationType: 'product'
});
const config = agent.getAgentDBConfig();
expect(config?.quantizationType).toBe('product');
});
it('should not build AgentDB config when no AgentDB params provided', () => {
const agent = new EnhancedTestAgent({
type: 'test-generator' as AgentType,
capabilities,
context,
memoryStore,
eventBus
});
const config = agent.getAgentDBConfig();
expect(config).toBeUndefined();
});
it('should enable learning in AgentDB config from enableLearning flag', () => {
const agent = new EnhancedTestAgent({
type: 'test-generator' as AgentType,
capabilities,
context,
memoryStore,
eventBus,
enableLearning: true,
agentDBPath: '/learning.db'
});
const config = agent.getAgentDBConfig();
expect(config?.enableLearning).toBe(true);
});
});
describe('Initialization - Learning Engine Integration (Lines 146-160)', () => {
it('should initialize PerformanceTracker when learning enabled with SwarmMemoryManager', async () => {
const agent = new EnhancedTestAgent({
type: 'test-generator' as AgentType,
capabilities,
context,
memoryStore, // SwarmMemoryManager instance
eventBus,
enableLearning: true
});
await agent.initialize();
const tracker = agent.getPerformanceTracker();
expect(tracker).toBeDefined();
const learningEngine = agent.getLearningEngineInternal();
expect(learningEngine).toBeDefined();
await agent.terminate();
});
it('should not initialize PerformanceTracker when learning disabled', async () => {
const agent = new EnhancedTestAgent({
type: 'test-generator' as AgentType,
capabilities,
context,
memoryStore,
eventBus,
enableLearning: false
});
await agent.initialize();
const tracker = agent.getPerformanceTracker();
expect(tracker).toBeUndefined();
await agent.terminate();
});
it('should initialize with custom learning config', async () => {
const learningConfig = {
alpha: 0.2,
gamma: 0.8,
epsilon: 0.3,
epsilonDecay: 0.95,
minEpsilon: 0.05
};
const agent = new EnhancedTestAgent({
type: 'test-generator' as AgentType,
capabilities,
context,
memoryStore,
eventBus,
enableLearning: true,
learningConfig
});
await agent.initialize();
const learningStatus = agent.getLearningStatus();
expect(learningStatus).not.toBeNull();
expect(learningStatus?.enabled).toBe(true);
await agent.terminate();
});
});
describe('AgentDB Integration Methods (Lines 371-422)', () => {
it('should initialize AgentDB with full config', async () => {
const agentDBPath = path.join(__dirname, '../../../.agentdb-test', `full-${Date.now()}.db`);
const agent = new EnhancedTestAgent({
type: 'test-generator' as AgentType,
capabilities,
context,
memoryStore,
eventBus
});
await agent.initialize();
const agentDBConfig = {
dbPath: agentDBPath,
enableQUICSync: false,
syncPort: 4433,
enableLearning: true,
enableReasoning: true,
cacheSize: 500
};
await agent.initializeAgentDB(agentDBConfig);
expect(agent.hasAgentDB()).toBe(true);
const status = await agent.getAgentDBStatus();
expect(status).not.toBeNull();
expect(status?.enabled).toBe(true);
await agent.terminate();
await fs.remove(path.dirname(agentDBPath));
});
it('should warn if AgentDB already initialized', async () => {
const agentDBPath = path.join(__dirname, '../../../.agentdb-test', `warn-${Date.now()}.db`);
const agent = new EnhancedTestAgent({
type: 'test-generator' as AgentType,
capabilities,
context,
memoryStore,
eventBus,
agentDBPath
});
await agent.initialize(); // Initializes AgentDB
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
// Try to initialize again
await agent.initializeAgentDB({ dbPath: agentDBPath });
expect(consoleSpy).toHaveBeenCalledWith(
expect.stringContaining('AgentDB already initialized')
);
consoleSpy.mockRestore();
await agent.terminate();
await fs.remove(path.dirname(agentDBPath));
});
it('should handle AgentDB initialization errors', async () => {
const agent = new EnhancedTestAgent({
type: 'test-generator' as AgentType,
capabilities,
context,
memoryStore,
eventBus
});
await agent.initialize();
// Invalid config that will cause AgentDB to fail
const invalidConfig = {
dbPath: '/invalid/\0/path.db' // Null byte in path
};
await expect(agent.initializeAgentDB(invalidConfig)).rejects.toThrow();
await agent.terminate();
});
it('should return AgentDB status with stats', async () => {
const agentDBPath = path.join(__dirname, '../../../.agentdb-test', `stats-${Date.now()}.db`);
const agent = new EnhancedTestAgent({
type: 'test-generator' as AgentType,
capabilities,
context,
memoryStore,
eventBus,
agentDBPath
});
await agent.initialize();
const status = await agent.getAgentDBStatus();
expect(status).not.toBeNull();
expect(status?.enabled).toBe(true);
expect(status?.stats).toBeDefined();
await agent.terminate();
await fs.remove(path.dirname(agentDBPath));
});
it('should return null for AgentDB status when not initialized', async () => {
const agent = new EnhancedTestAgent({
type: 'test-generator' as AgentType,
capabilities,
context,
memoryStore,
eventBus
});
await agent.initialize();
const status = await agent.getAgentDBStatus();
expect(status).toBeNull();
await agent.terminate();
});
});
describe('Memory Operations with Null Store (Lines 528-571)', () => {
it('should handle undefined memory store in storeMemory', async () => {
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
const agent = new EnhancedTestAgent({
type: 'test-generator' as AgentType,
capabilities,
context,
memoryStore,
eventBus
});
// Force memoryStore to undefined to test the warning path
(agent as any).memoryStore = undefined;
// Should warn but not throw
await agent.exposeStoreMemory('key', 'value');
expect(consoleSpy).toHaveBeenCalledWith(
expect.stringContaining('Memory store not available')
);
consoleSpy.mockRestore();
});
it('should handle undefined memory store in retrieveMemory', async () => {
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
const agent = new EnhancedTestAgent({
type: 'test-generator' as AgentType,
capabilities,
context,
memoryStore,
eventBus
});
// Force memoryStore to undefined
(agent as any).memoryStore = undefined;
const result = await agent.exposeRetrieveMemory('key');
expect(result).toBeNull();
expect(consoleSpy).toHaveBeenCalledWith(
expect.stringContaining('Memory store not available')
);
consoleSpy.mockRestore();
});
it('should handle undefined memory store in storeSharedMemory', async () => {
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
const agent = new EnhancedTestAgent({
type: 'test-generator' as AgentType,
capabilities,
context,
memoryStore,
eventBus
});
// Force memoryStore to undefined
(agent as any).memoryStore = undefined;
await agent.exposeStoreSharedMemory('shared', 'data');
expect(consoleSpy).toHaveBeenCalledWith(
expect.stringContaining('Memory store not available')
);
consoleSpy.mockRestore();
});
it('should handle undefined memory store in retrieveSharedMemory', async () => {
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
const agent = new EnhancedTestAgent({
type: 'test-generator' as AgentType,
capabilities,
context,
memoryStore,
eventBus
});
// Force memoryStore to undefined
(agent as any).memoryStore = undefined;
const result = await agent.exposeRetrieveSharedMemory('test-generator', 'key');
expect(result).toBeNull();
expect(consoleSpy).toHaveBeenCalledWith(
expect.stringContaining('Memory store not available')
);
consoleSpy.mockRestore();
});
it('should work normally with valid memory store', async () => {
const agent = new EnhancedTestAgent({
id: 'memory-normal',
type: 'test-generator' as AgentType,
capabilities,
context,
memoryStore,
eventBus
});
await agent.initialize();
// Normal operations should work
await agent.exposeStoreMemory('test', { data: 'value' });
const result = await agent.exposeRetrieveMemory('test');
expect(result).toEqual({ data: 'value' });
await agent.terminate();
});
});
describe('Task Lifecycle - Performance Metrics Edge Cases (Lines 1003-1016)', () => {
it('should calculate average execution time correctly for multiple tasks', async () => {
const agent = new EnhancedTestAgent({
id: 'metrics-agent',
type: 'test-executor' as AgentType,
capabilities,
context,
memoryStore,
eventBus
});
await agent.initialize();
// Execute multiple tasks
for (let i = 0; i < 5; i++) {
const task: QETask = {
id: `task-${i}`,
type: 'test',
payload: {},
priority: 1,
status: 'pending'
};
await agent.assignTask(task);
}
const metrics = agent.getStatus().performanceMetrics;
expect(metrics.tasksCompleted).toBe(5);
expect(metrics.averageExecutionTime).toBeGreaterThanOrEqual(0);
await agent.terminate();
});
it('should handle mixed success and error metrics', async () => {
const agent = new EnhancedTestAgent({
id: 'mixed-agent',
type: 'test-executor' as AgentType,
capabilities,
context,
memoryStore,
eventBus
});
await agent.initialize();
// Successful task
await agent.assignTask({
id: 'success',
type: 'test',
payload: {},
priority: 1,
status: 'pending'
});
// Failed task
agent.shouldFailTask = true;
try {
await agent.assignTask({
id: 'fail',
type: 'test',
payload: {},
priority: 1,
status: 'pending'
});
} catch (e) {
// Expected
}
const metrics = agent.getStatus().performanceMetrics;
expect(metrics.tasksCompleted).toBe(1);
expect(metrics.errorCount).toBe(1);
await agent.terminate();
});
});
describe('State Persistence Edge Cases (Lines 1026-1060)', () => {
it('should handle missing state gracefully during restore', async () => {
const agent = new EnhancedTestAgent({
id: 'restore-missing',
type: 'test-executor' as AgentType,
capabilities,
context,
memoryStore,
eventBus
});
// No state exists - should initialize with default metrics
await agent.initialize();
const metrics = agent.getStatus().performanceMetrics;
expect(metrics.tasksCompleted).toBe(0);
expect(metrics.errorCount).toBe(0);
expect(metrics.averageExecutionTime).toBe(0);
await agent.terminate();
});
it('should handle save state errors gracefully', async () => {
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
const agent = new EnhancedTestAgent({
id: 'save-fail',
type: 'test-executor' as AgentType,
capabilities,
context,
memoryStore,
eventBus
});
await agent.initialize();
// Mock store to fail
jest.spyOn(memoryStore, 'store').mockRejectedValueOnce(new Error('Store failed'));
// Termination should handle save error gracefully
await agent.terminate();
expect(consoleErrorSpy).toHaveBeenCalledWith(
expect.stringContaining('Could not save state'),
expect.any(Error)
);
consoleErrorSpy.mockRestore();
});
it('should handle reportStatus errors gracefully', async () => {
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
const agent = new EnhancedTestAgent({
id: 'report-fail',
type: 'test-executor' as AgentType,
capabilities,
context,
memoryStore,
eventBus
});
// Mock store to fail for reportStatus during initialization
jest.spyOn(memoryStore, 'store').mockRejectedValueOnce(new Error('Report failed'));
// Should handle error during initialization's reportStatus call
await agent.initialize();
expect(consoleSpy).toHaveBeenCalledWith(
expect.stringContaining('Could not report status'),
expect.any(Error)
);
consoleSpy.mockRestore();
await agent.terminate();
});
});
describe('Event Priority Variations (Lines 488-500)', () => {
it('should emit event with critical priority', (done) => {
const agent = new EnhancedTestAgent({
type: 'test-executor' as AgentType,
capabilities,
context,
memoryStore,
eventBus
});
eventBus.on('critical-event', (event) => {
expect(event.priority).toBe('critical');
done();
});
agent.exposeEmitEvent('critical-event', { urgent: true }, 'critical');
});
it('should emit event with low priority', (done) => {
const agent = new EnhancedTestAgent({
type: 'test-executor' as AgentType,
capabilities,
context,
memoryStore,
eventBus
});
eventBus.on('low-event', (event) => {
expect(event.priority).toBe('low');
done();
});
agent.exposeEmitEvent('low-event', { info: 'data' }, 'low');
});
it('should generate unique event IDs', () => {
const agent = new EnhancedTestAgent({
type: 'test-executor' as AgentType,
capabilities,
context,
memoryStore,
eventBus
});
const eventIds = new Set<string>();
eventBus.on('id-test', (event) => {
eventIds.add(event.id);
});
// Emit multiple events
for (let i = 0; i < 10; i++) {
agent.exposeEmitEvent('id-test', { index: i });
}
expect(eventIds.size).toBe(10); // All unique
});
});
describe('Task Assignment Generation (Lines 434-444)', () => {
it('should generate unique assignment IDs', async () => {
const agent = new EnhancedTestAgent({
type: 'test-executor' as AgentType,
capabilities,
context,
memoryStore,
eventBus
});
await agent.initialize();
const assignmentIds = new Set<string>();
// Capture assignment IDs
const originalExecute = agent.executeTask.bind(agent);
agent.executeTask = jest.fn(async (assignment) => {
assignmentIds.add(assignment.id);
return originalExecute(assignment);
});
for (let i = 0; i < 5; i++) {
await agent.assignTask({
id: `task-${i}`,
type: 'test',
payload: {},
priority: 1,
status: 'pending'
});
}
expect(assignmentIds.size).toBe(5); // All unique
await agent.terminate();
});
it('should set correct assignment status', async () => {
const agent = new EnhancedTestAgent({
id: 'assign-status',
type: 'test-executor' as AgentType,
capabilities,
context,
memoryStore,
eventBus
});
await agent.initialize();
let capturedAssignment: TaskAssignment | undefined;
const originalExecute = agent.executeTask.bind(agent);
agent.executeTask = jest.fn(async (assignment) => {
capturedAssignment = assignment;
return originalExecute(assignment);
});
await agent.assignTask({
id: 'task-status',
type: 'test',
payload: {},
priority: 1,
status: 'pending'
});
expect(capturedAssignment?.status).toBe('assigned');
expect(capturedAssignment?.agentId).toBe('assign-status');
expect(capturedAssignment?.assignedAt).toBeInstanceOf(Date);
await agent.terminate();
});
});
describe('Error Hook Edge Cases (Lines 947-956)', () => {
it('should handle errors in executeHook gracefully', async () => {
const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
const agent = new EnhancedTestAgent({
type: 'test-executor' as AgentType,
capabilities,
context,
memoryStore,
eventBus
});
// Trigger hook with non-existent method
await (agent as any).executeHook('non-existent-hook', {});
// Should not throw, just log error
expect(consoleSpy).not.toHaveBeenCalled(); // No error if method doesn't exist
consoleSpy.mockRestore();
});
});
describe('ID Generation Methods (Lines 1062-1072)', () => {
it('should generate unique agent IDs with timestamp and random component', () => {
const ids = new Set<string>();
for (let i = 0; i < 100; i++) {
const agent = new EnhancedTestAgent({
type: 'test-generator' as AgentType,
capabilities,
context,
memoryStore,
eventBus
});
ids.add(agent.getStatus().agentId.id);
}
expect(ids.size).toBe(100); // All unique
});
it('should generate message IDs with correct format', () => {
const agent = new EnhancedTestAgent({
type: 'test-executor' as AgentType,
capabilities,
context,
memoryStore,
eventBus
});
const messageIds = new Set<string>();
eventBus.on('agent.message', (msg) => {
messageIds.add(msg.id);
expect(msg.id).toMatch(/^msg-\d+-\w+$/);
});
for (let i = 0; i < 10; i++) {
agent.exposeBroadcastMessage('test', { index: i });
}
expect(messageIds.size).toBe(10);
});
});
});