git-subtree-dir: vendor/ruvector git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
669 lines
25 KiB
JavaScript
669 lines
25 KiB
JavaScript
"use strict";
|
|
/**
|
|
* Integration Tests - Comprehensive tests for agentic coordination
|
|
*
|
|
* Tests:
|
|
* - Multi-agent coordination
|
|
* - Failover scenarios
|
|
* - Load distribution
|
|
* - Performance benchmarks
|
|
*/
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const agent_coordinator_1 = require("./agent-coordinator");
|
|
const regional_agent_1 = require("./regional-agent");
|
|
const swarm_manager_1 = require("./swarm-manager");
|
|
const coordination_protocol_1 = require("./coordination-protocol");
|
|
/**
|
|
* Test utilities
|
|
*/
|
|
class TestUtils {
|
|
static async sleep(ms) {
|
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
}
|
|
static generateRandomVector(dimensions) {
|
|
return Array.from({ length: dimensions }, () => Math.random());
|
|
}
|
|
static async measureLatency(fn) {
|
|
const start = Date.now();
|
|
const result = await fn();
|
|
const latency = Date.now() - start;
|
|
return { result, latency };
|
|
}
|
|
}
|
|
/**
|
|
* Test Suite 1: Agent Coordinator Tests
|
|
*/
|
|
describe('AgentCoordinator', () => {
|
|
let coordinator;
|
|
beforeEach(() => {
|
|
const config = {
|
|
maxAgentsPerRegion: 10,
|
|
healthCheckInterval: 5000,
|
|
taskTimeout: 10000,
|
|
retryBackoffBase: 100,
|
|
retryBackoffMax: 5000,
|
|
loadBalancingStrategy: 'round-robin',
|
|
failoverThreshold: 3,
|
|
enableClaudeFlowHooks: false, // Disable for testing
|
|
};
|
|
coordinator = new agent_coordinator_1.AgentCoordinator(config);
|
|
});
|
|
afterEach(async () => {
|
|
await coordinator.shutdown();
|
|
});
|
|
test('should register agents successfully', async () => {
|
|
const registration = {
|
|
agentId: 'test-agent-1',
|
|
region: 'us-east',
|
|
endpoint: 'https://us-east.ruvector.io/agent/test-agent-1',
|
|
capabilities: ['query', 'index'],
|
|
capacity: 1000,
|
|
registeredAt: Date.now(),
|
|
};
|
|
await coordinator.registerAgent(registration);
|
|
const status = coordinator.getStatus();
|
|
expect(status.totalAgents).toBe(1);
|
|
expect(status.regionDistribution['us-east']).toBe(1);
|
|
});
|
|
test('should distribute tasks using round-robin', async () => {
|
|
// Register multiple agents
|
|
for (let i = 0; i < 3; i++) {
|
|
await coordinator.registerAgent({
|
|
agentId: `agent-${i}`,
|
|
region: 'us-east',
|
|
endpoint: `https://us-east.ruvector.io/agent/agent-${i}`,
|
|
capabilities: ['query'],
|
|
capacity: 1000,
|
|
registeredAt: Date.now(),
|
|
});
|
|
}
|
|
// Submit tasks
|
|
const taskIds = [];
|
|
for (let i = 0; i < 6; i++) {
|
|
const taskId = await coordinator.submitTask({
|
|
type: 'query',
|
|
payload: { query: `test-query-${i}` },
|
|
priority: 1,
|
|
maxRetries: 3,
|
|
});
|
|
taskIds.push(taskId);
|
|
}
|
|
expect(taskIds.length).toBe(6);
|
|
await TestUtils.sleep(1000);
|
|
const status = coordinator.getStatus();
|
|
expect(status.queuedTasks + status.activeTasks).toBeGreaterThan(0);
|
|
});
|
|
test('should handle agent failures with circuit breaker', async () => {
|
|
const registration = {
|
|
agentId: 'failing-agent',
|
|
region: 'us-west',
|
|
endpoint: 'https://us-west.ruvector.io/agent/failing-agent',
|
|
capabilities: ['query'],
|
|
capacity: 1000,
|
|
registeredAt: Date.now(),
|
|
};
|
|
await coordinator.registerAgent(registration);
|
|
// Simulate agent going unhealthy
|
|
coordinator.updateAgentMetrics({
|
|
agentId: 'failing-agent',
|
|
region: 'us-west',
|
|
cpuUsage: 95,
|
|
memoryUsage: 95,
|
|
activeStreams: 1000,
|
|
queryLatency: 5000,
|
|
timestamp: Date.now(),
|
|
healthy: false,
|
|
});
|
|
const status = coordinator.getStatus();
|
|
expect(status.healthyAgents).toBe(0);
|
|
});
|
|
test('should enforce max agents per region', async () => {
|
|
const config = {
|
|
maxAgentsPerRegion: 2,
|
|
healthCheckInterval: 5000,
|
|
taskTimeout: 10000,
|
|
retryBackoffBase: 100,
|
|
retryBackoffMax: 5000,
|
|
loadBalancingStrategy: 'round-robin',
|
|
failoverThreshold: 3,
|
|
enableClaudeFlowHooks: false,
|
|
};
|
|
const limitedCoordinator = new agent_coordinator_1.AgentCoordinator(config);
|
|
// Register agents
|
|
await limitedCoordinator.registerAgent({
|
|
agentId: 'agent-1',
|
|
region: 'eu-west',
|
|
endpoint: 'https://eu-west.ruvector.io/agent/agent-1',
|
|
capabilities: ['query'],
|
|
capacity: 1000,
|
|
registeredAt: Date.now(),
|
|
});
|
|
await limitedCoordinator.registerAgent({
|
|
agentId: 'agent-2',
|
|
region: 'eu-west',
|
|
endpoint: 'https://eu-west.ruvector.io/agent/agent-2',
|
|
capabilities: ['query'],
|
|
capacity: 1000,
|
|
registeredAt: Date.now(),
|
|
});
|
|
// Third agent should fail
|
|
await expect(limitedCoordinator.registerAgent({
|
|
agentId: 'agent-3',
|
|
region: 'eu-west',
|
|
endpoint: 'https://eu-west.ruvector.io/agent/agent-3',
|
|
capabilities: ['query'],
|
|
capacity: 1000,
|
|
registeredAt: Date.now(),
|
|
})).rejects.toThrow('has reached max agent capacity');
|
|
await limitedCoordinator.shutdown();
|
|
});
|
|
});
|
|
/**
|
|
* Test Suite 2: Regional Agent Tests
|
|
*/
|
|
describe('RegionalAgent', () => {
|
|
let agent;
|
|
beforeEach(() => {
|
|
const config = {
|
|
agentId: 'test-agent-us-east-1',
|
|
region: 'us-east',
|
|
coordinatorEndpoint: 'coordinator.ruvector.io',
|
|
localStoragePath: '/tmp/test-agent',
|
|
maxConcurrentStreams: 100,
|
|
metricsReportInterval: 5000,
|
|
syncInterval: 2000,
|
|
enableClaudeFlowHooks: false,
|
|
vectorDimensions: 768,
|
|
capabilities: ['query', 'index', 'sync'],
|
|
};
|
|
agent = new regional_agent_1.RegionalAgent(config);
|
|
});
|
|
afterEach(async () => {
|
|
await agent.shutdown();
|
|
});
|
|
test('should process query successfully', async () => {
|
|
// Index some vectors
|
|
await agent.indexVectors([
|
|
{
|
|
id: 'vec-1',
|
|
vector: TestUtils.generateRandomVector(768),
|
|
metadata: { category: 'test' },
|
|
},
|
|
{
|
|
id: 'vec-2',
|
|
vector: TestUtils.generateRandomVector(768),
|
|
metadata: { category: 'test' },
|
|
},
|
|
]);
|
|
// Query
|
|
const result = await agent.processQuery({
|
|
id: 'query-1',
|
|
vector: TestUtils.generateRandomVector(768),
|
|
topK: 2,
|
|
timeout: 5000,
|
|
});
|
|
expect(result.matches.length).toBeGreaterThan(0);
|
|
expect(result.region).toBe('us-east');
|
|
expect(result.latency).toBeGreaterThan(0);
|
|
});
|
|
test('should validate query dimensions', async () => {
|
|
await expect(agent.processQuery({
|
|
id: 'query-invalid',
|
|
vector: TestUtils.generateRandomVector(512), // Wrong dimension
|
|
topK: 10,
|
|
timeout: 5000,
|
|
})).rejects.toThrow('Invalid vector dimensions');
|
|
});
|
|
test('should apply filters in query', async () => {
|
|
// Index vectors with different metadata
|
|
await agent.indexVectors([
|
|
{
|
|
id: 'vec-1',
|
|
vector: TestUtils.generateRandomVector(768),
|
|
metadata: { category: 'A', type: 'test' },
|
|
},
|
|
{
|
|
id: 'vec-2',
|
|
vector: TestUtils.generateRandomVector(768),
|
|
metadata: { category: 'B', type: 'test' },
|
|
},
|
|
{
|
|
id: 'vec-3',
|
|
vector: TestUtils.generateRandomVector(768),
|
|
metadata: { category: 'A', type: 'prod' },
|
|
},
|
|
]);
|
|
// Query with filter
|
|
const result = await agent.processQuery({
|
|
id: 'query-filtered',
|
|
vector: TestUtils.generateRandomVector(768),
|
|
topK: 10,
|
|
filters: { category: 'A' },
|
|
timeout: 5000,
|
|
});
|
|
// Should only return vectors with category 'A'
|
|
expect(result.matches.length).toBeGreaterThan(0);
|
|
});
|
|
test('should enforce rate limiting', async () => {
|
|
// Try to exceed max concurrent streams
|
|
const promises = [];
|
|
for (let i = 0; i < 150; i++) {
|
|
promises.push(agent.processQuery({
|
|
id: `query-${i}`,
|
|
vector: TestUtils.generateRandomVector(768),
|
|
topK: 5,
|
|
timeout: 5000,
|
|
}).catch(err => err));
|
|
}
|
|
const results = await Promise.all(promises);
|
|
const rateLimitErrors = results.filter(r => r instanceof Error && r.message.includes('Rate limit'));
|
|
expect(rateLimitErrors.length).toBeGreaterThan(0);
|
|
});
|
|
test('should handle sync payloads from other regions', async () => {
|
|
const syncPayload = {
|
|
type: 'index',
|
|
data: [
|
|
{
|
|
id: 'sync-vec-1',
|
|
vector: TestUtils.generateRandomVector(768),
|
|
metadata: { synced: true },
|
|
},
|
|
],
|
|
timestamp: Date.now(),
|
|
sourceRegion: 'us-west',
|
|
};
|
|
await agent.handleSyncPayload(syncPayload);
|
|
const status = agent.getStatus();
|
|
expect(status.indexSize).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
/**
|
|
* Test Suite 3: Swarm Manager Tests
|
|
*/
|
|
describe('SwarmManager', () => {
|
|
let coordinator;
|
|
let swarmManager;
|
|
beforeEach(() => {
|
|
const coordinatorConfig = {
|
|
maxAgentsPerRegion: 10,
|
|
healthCheckInterval: 5000,
|
|
taskTimeout: 10000,
|
|
retryBackoffBase: 100,
|
|
retryBackoffMax: 5000,
|
|
loadBalancingStrategy: 'adaptive',
|
|
failoverThreshold: 3,
|
|
enableClaudeFlowHooks: false,
|
|
};
|
|
coordinator = new agent_coordinator_1.AgentCoordinator(coordinatorConfig);
|
|
const swarmConfig = {
|
|
topology: 'mesh',
|
|
minAgentsPerRegion: 1,
|
|
maxAgentsPerRegion: 5,
|
|
scaleUpThreshold: 80,
|
|
scaleDownThreshold: 20,
|
|
scaleUpCooldown: 30000,
|
|
scaleDownCooldown: 60000,
|
|
healthCheckInterval: 5000,
|
|
enableAutoScaling: true,
|
|
enableClaudeFlowHooks: false,
|
|
regions: ['us-east', 'us-west', 'eu-west'],
|
|
};
|
|
swarmManager = new swarm_manager_1.SwarmManager(swarmConfig, coordinator);
|
|
});
|
|
afterEach(async () => {
|
|
await swarmManager.shutdown();
|
|
await coordinator.shutdown();
|
|
});
|
|
test('should spawn initial agents for all regions', async () => {
|
|
await TestUtils.sleep(1000); // Wait for initialization
|
|
const status = swarmManager.getStatus();
|
|
expect(status.totalAgents).toBeGreaterThanOrEqual(3); // At least 1 per region
|
|
expect(Object.keys(status.metrics.regionMetrics).length).toBe(3);
|
|
});
|
|
test('should spawn additional agents in specific region', async () => {
|
|
const initialStatus = swarmManager.getStatus();
|
|
const initialCount = initialStatus.totalAgents;
|
|
await swarmManager.spawnAgent('us-east');
|
|
const newStatus = swarmManager.getStatus();
|
|
expect(newStatus.totalAgents).toBe(initialCount + 1);
|
|
});
|
|
test('should calculate swarm metrics correctly', async () => {
|
|
await TestUtils.sleep(1000);
|
|
const metrics = swarmManager.calculateSwarmMetrics();
|
|
expect(metrics.totalAgents).toBeGreaterThan(0);
|
|
expect(metrics.regionMetrics).toBeDefined();
|
|
expect(Object.keys(metrics.regionMetrics).length).toBe(3);
|
|
for (const region of ['us-east', 'us-west', 'eu-west']) {
|
|
expect(metrics.regionMetrics[region]).toBeDefined();
|
|
expect(metrics.regionMetrics[region].agentCount).toBeGreaterThan(0);
|
|
}
|
|
});
|
|
test('should despawn agent and redistribute tasks', async () => {
|
|
await TestUtils.sleep(1000);
|
|
const status = swarmManager.getStatus();
|
|
const agentIds = Object.keys(status.metrics.regionMetrics);
|
|
if (agentIds.length > 0) {
|
|
const initialCount = status.totalAgents;
|
|
// Get first agent ID from any region
|
|
const regionMetrics = Object.values(status.metrics.regionMetrics);
|
|
const firstRegion = regionMetrics[0];
|
|
// We'll need to track spawned agents to despawn them
|
|
// For now, just verify the mechanism works
|
|
expect(initialCount).toBeGreaterThan(0);
|
|
}
|
|
});
|
|
});
|
|
/**
|
|
* Test Suite 4: Coordination Protocol Tests
|
|
*/
|
|
describe('CoordinationProtocol', () => {
|
|
let protocol1;
|
|
let protocol2;
|
|
beforeEach(() => {
|
|
const config1 = {
|
|
nodeId: 'node-1',
|
|
heartbeatInterval: 2000,
|
|
messageTimeout: 5000,
|
|
consensusTimeout: 10000,
|
|
maxMessageQueueSize: 1000,
|
|
enableClaudeFlowHooks: false,
|
|
pubSubTopics: ['sync', 'metrics', 'alerts'],
|
|
};
|
|
const config2 = {
|
|
nodeId: 'node-2',
|
|
heartbeatInterval: 2000,
|
|
messageTimeout: 5000,
|
|
consensusTimeout: 10000,
|
|
maxMessageQueueSize: 1000,
|
|
enableClaudeFlowHooks: false,
|
|
pubSubTopics: ['sync', 'metrics', 'alerts'],
|
|
};
|
|
protocol1 = new coordination_protocol_1.CoordinationProtocol(config1);
|
|
protocol2 = new coordination_protocol_1.CoordinationProtocol(config2);
|
|
// Connect protocols
|
|
protocol1.registerNode('node-2');
|
|
protocol2.registerNode('node-1');
|
|
// Set up message forwarding
|
|
protocol1.on('message:transmit', (message) => {
|
|
if (message.to === 'node-2' || !message.to) {
|
|
protocol2.receiveMessage(message);
|
|
}
|
|
});
|
|
protocol2.on('message:transmit', (message) => {
|
|
if (message.to === 'node-1' || !message.to) {
|
|
protocol1.receiveMessage(message);
|
|
}
|
|
});
|
|
});
|
|
afterEach(async () => {
|
|
await protocol1.shutdown();
|
|
await protocol2.shutdown();
|
|
});
|
|
test('should send and receive messages between nodes', async () => {
|
|
let receivedMessage = false;
|
|
protocol2.on('request:received', (message) => {
|
|
receivedMessage = true;
|
|
expect(message.from).toBe('node-1');
|
|
});
|
|
await protocol1.sendMessage('node-2', 'request', { test: 'data' });
|
|
await TestUtils.sleep(100);
|
|
expect(receivedMessage).toBe(true);
|
|
});
|
|
test('should handle request-response pattern', async () => {
|
|
protocol2.on('request:received', async (message) => {
|
|
await protocol2.sendResponse(message.id, message.from, {
|
|
status: 'ok',
|
|
data: 'response',
|
|
});
|
|
});
|
|
const response = await protocol1.sendMessage('node-2', 'request', { query: 'test' }, { expectResponse: true });
|
|
expect(response.status).toBe('ok');
|
|
});
|
|
test('should broadcast messages to all nodes', async () => {
|
|
let received = false;
|
|
protocol2.on('broadcast:received', (message) => {
|
|
received = true;
|
|
expect(message.type).toBe('broadcast');
|
|
});
|
|
await protocol1.broadcastMessage('broadcast', { event: 'test' });
|
|
await TestUtils.sleep(100);
|
|
expect(received).toBe(true);
|
|
});
|
|
test('should handle consensus proposals', async () => {
|
|
// Node 2 auto-approves proposals
|
|
protocol2.on('consensus:proposed', async (proposal) => {
|
|
// Auto-approve handled internally in test setup
|
|
});
|
|
const approved = await protocol1.proposeConsensus('schema_change', { change: 'add_field' }, 1 // Only need 1 vote (from proposer)
|
|
);
|
|
expect(approved).toBe(true);
|
|
});
|
|
test('should handle pub/sub topics', async () => {
|
|
let receivedMessage = false;
|
|
// Subscribe node 2 to 'sync' topic
|
|
protocol2.subscribe('sync', 'node-2');
|
|
protocol2.on('topic:message', (data) => {
|
|
if (data.topicName === 'sync') {
|
|
receivedMessage = true;
|
|
expect(data.message.payload.data).toBe('sync-data');
|
|
}
|
|
});
|
|
// Publish to topic
|
|
await protocol1.publishToTopic('sync', { data: 'sync-data' });
|
|
await TestUtils.sleep(100);
|
|
expect(receivedMessage).toBe(true);
|
|
});
|
|
test('should detect unhealthy nodes', async () => {
|
|
let unhealthyDetected = false;
|
|
protocol1.on('node:unhealthy', (data) => {
|
|
unhealthyDetected = true;
|
|
expect(data.nodeId).toBe('node-2');
|
|
});
|
|
// Stop node 2 heartbeat
|
|
await protocol2.shutdown();
|
|
// Wait for health check to detect
|
|
await TestUtils.sleep(7000);
|
|
expect(unhealthyDetected).toBe(true);
|
|
});
|
|
});
|
|
/**
|
|
* Test Suite 5: Performance Benchmarks
|
|
*/
|
|
describe('Performance Benchmarks', () => {
|
|
test('should handle high query throughput', async () => {
|
|
const config = {
|
|
agentId: 'perf-agent',
|
|
region: 'us-east',
|
|
coordinatorEndpoint: 'coordinator.ruvector.io',
|
|
localStoragePath: '/tmp/perf-agent',
|
|
maxConcurrentStreams: 1000,
|
|
metricsReportInterval: 30000,
|
|
syncInterval: 5000,
|
|
enableClaudeFlowHooks: false,
|
|
vectorDimensions: 768,
|
|
capabilities: ['query'],
|
|
};
|
|
const agent = new regional_agent_1.RegionalAgent(config);
|
|
// Index vectors
|
|
const vectors = Array.from({ length: 10000 }, (_, i) => ({
|
|
id: `vec-${i}`,
|
|
vector: TestUtils.generateRandomVector(768),
|
|
metadata: { index: i },
|
|
}));
|
|
await agent.indexVectors(vectors);
|
|
// Run queries
|
|
const queryCount = 1000;
|
|
const queries = [];
|
|
const startTime = Date.now();
|
|
for (let i = 0; i < queryCount; i++) {
|
|
queries.push(agent.processQuery({
|
|
id: `perf-query-${i}`,
|
|
vector: TestUtils.generateRandomVector(768),
|
|
topK: 10,
|
|
timeout: 5000,
|
|
}).catch(() => null) // Ignore rate limit errors
|
|
);
|
|
}
|
|
const results = await Promise.all(queries);
|
|
const successfulQueries = results.filter(r => r !== null);
|
|
const totalTime = Date.now() - startTime;
|
|
const qps = (successfulQueries.length / totalTime) * 1000;
|
|
console.log(`\nPerformance Benchmark:`);
|
|
console.log(`Total queries: ${queryCount}`);
|
|
console.log(`Successful: ${successfulQueries.length}`);
|
|
console.log(`Time: ${totalTime}ms`);
|
|
console.log(`QPS: ${qps.toFixed(2)}`);
|
|
expect(successfulQueries.length).toBeGreaterThan(0);
|
|
expect(qps).toBeGreaterThan(1); // At least 1 QPS
|
|
await agent.shutdown();
|
|
});
|
|
test('should scale agents based on load', async () => {
|
|
const coordinatorConfig = {
|
|
maxAgentsPerRegion: 10,
|
|
healthCheckInterval: 5000,
|
|
taskTimeout: 10000,
|
|
retryBackoffBase: 100,
|
|
retryBackoffMax: 5000,
|
|
loadBalancingStrategy: 'adaptive',
|
|
failoverThreshold: 3,
|
|
enableClaudeFlowHooks: false,
|
|
};
|
|
const coordinator = new agent_coordinator_1.AgentCoordinator(coordinatorConfig);
|
|
const swarmConfig = {
|
|
topology: 'mesh',
|
|
minAgentsPerRegion: 1,
|
|
maxAgentsPerRegion: 5,
|
|
scaleUpThreshold: 70,
|
|
scaleDownThreshold: 30,
|
|
scaleUpCooldown: 1000, // Short cooldown for testing
|
|
scaleDownCooldown: 2000,
|
|
healthCheckInterval: 1000,
|
|
enableAutoScaling: true,
|
|
enableClaudeFlowHooks: false,
|
|
regions: ['us-east'],
|
|
};
|
|
const swarmManager = new swarm_manager_1.SwarmManager(swarmConfig, coordinator);
|
|
await TestUtils.sleep(1000);
|
|
const initialCount = swarmManager.getStatus().totalAgents;
|
|
// Spawn additional agents to simulate scale-up
|
|
await swarmManager.spawnAgent('us-east');
|
|
await swarmManager.spawnAgent('us-east');
|
|
await TestUtils.sleep(500);
|
|
const scaledCount = swarmManager.getStatus().totalAgents;
|
|
expect(scaledCount).toBeGreaterThan(initialCount);
|
|
await swarmManager.shutdown();
|
|
await coordinator.shutdown();
|
|
}, 15000);
|
|
});
|
|
/**
|
|
* Test Suite 6: Failover Scenarios
|
|
*/
|
|
describe('Failover Scenarios', () => {
|
|
test('should handle agent failure and task redistribution', async () => {
|
|
const coordinatorConfig = {
|
|
maxAgentsPerRegion: 10,
|
|
healthCheckInterval: 1000,
|
|
taskTimeout: 5000,
|
|
retryBackoffBase: 100,
|
|
retryBackoffMax: 2000,
|
|
loadBalancingStrategy: 'round-robin',
|
|
failoverThreshold: 2,
|
|
enableClaudeFlowHooks: false,
|
|
};
|
|
const coordinator = new agent_coordinator_1.AgentCoordinator(coordinatorConfig);
|
|
// Register two agents
|
|
await coordinator.registerAgent({
|
|
agentId: 'agent-1',
|
|
region: 'us-east',
|
|
endpoint: 'https://us-east.ruvector.io/agent/agent-1',
|
|
capabilities: ['query'],
|
|
capacity: 1000,
|
|
registeredAt: Date.now(),
|
|
});
|
|
await coordinator.registerAgent({
|
|
agentId: 'agent-2',
|
|
region: 'us-east',
|
|
endpoint: 'https://us-east.ruvector.io/agent/agent-2',
|
|
capabilities: ['query'],
|
|
capacity: 1000,
|
|
registeredAt: Date.now(),
|
|
});
|
|
// Submit tasks
|
|
await coordinator.submitTask({
|
|
type: 'query',
|
|
payload: { query: 'test' },
|
|
priority: 1,
|
|
maxRetries: 3,
|
|
});
|
|
// Simulate agent-1 failure
|
|
coordinator.updateAgentMetrics({
|
|
agentId: 'agent-1',
|
|
region: 'us-east',
|
|
cpuUsage: 100,
|
|
memoryUsage: 100,
|
|
activeStreams: 1000,
|
|
queryLatency: 10000,
|
|
timestamp: Date.now(),
|
|
healthy: false,
|
|
});
|
|
await TestUtils.sleep(2000);
|
|
const status = coordinator.getStatus();
|
|
expect(status.healthyAgents).toBe(1); // Only agent-2 healthy
|
|
await coordinator.shutdown();
|
|
});
|
|
test('should handle network partition in coordination protocol', async () => {
|
|
const protocol1 = new coordination_protocol_1.CoordinationProtocol({
|
|
nodeId: 'node-1',
|
|
heartbeatInterval: 1000,
|
|
messageTimeout: 5000,
|
|
consensusTimeout: 10000,
|
|
maxMessageQueueSize: 1000,
|
|
enableClaudeFlowHooks: false,
|
|
pubSubTopics: [],
|
|
});
|
|
const protocol2 = new coordination_protocol_1.CoordinationProtocol({
|
|
nodeId: 'node-2',
|
|
heartbeatInterval: 1000,
|
|
messageTimeout: 5000,
|
|
consensusTimeout: 10000,
|
|
maxMessageQueueSize: 1000,
|
|
enableClaudeFlowHooks: false,
|
|
pubSubTopics: [],
|
|
});
|
|
protocol1.registerNode('node-2');
|
|
protocol2.registerNode('node-1');
|
|
// Set up message forwarding
|
|
let networkPartitioned = false;
|
|
protocol1.on('message:transmit', (message) => {
|
|
if (!networkPartitioned && message.to === 'node-2') {
|
|
protocol2.receiveMessage(message);
|
|
}
|
|
});
|
|
// Normal communication
|
|
await protocol1.sendMessage('node-2', 'request', { test: 'data' });
|
|
await TestUtils.sleep(100);
|
|
// Simulate network partition
|
|
networkPartitioned = true;
|
|
let unhealthyDetected = false;
|
|
protocol1.on('node:unhealthy', (data) => {
|
|
if (data.nodeId === 'node-2') {
|
|
unhealthyDetected = true;
|
|
}
|
|
});
|
|
// Wait for health check to detect partition
|
|
await TestUtils.sleep(4000);
|
|
expect(unhealthyDetected).toBe(true);
|
|
await protocol1.shutdown();
|
|
await protocol2.shutdown();
|
|
}, 10000);
|
|
});
|
|
console.log('\n=== Integration Tests ===');
|
|
console.log('Run with: npm test');
|
|
console.log('Tests include:');
|
|
console.log(' - Agent Coordinator: Registration, load balancing, failover');
|
|
console.log(' - Regional Agent: Query processing, indexing, rate limiting');
|
|
console.log(' - Swarm Manager: Auto-scaling, health monitoring, metrics');
|
|
console.log(' - Coordination Protocol: Messaging, consensus, pub/sub');
|
|
console.log(' - Performance: High throughput, latency benchmarks');
|
|
console.log(' - Failover: Agent failure, network partition, recovery');
|
|
//# sourceMappingURL=integration-tests.js.map
|