@sparkleideas/testing 3.0.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +547 -0
- package/__tests__/framework.test.ts +21 -0
- package/package.json +61 -0
- package/src/fixtures/agent-fixtures.ts +793 -0
- package/src/fixtures/agents.ts +212 -0
- package/src/fixtures/configurations.ts +491 -0
- package/src/fixtures/index.ts +21 -0
- package/src/fixtures/mcp-fixtures.ts +1030 -0
- package/src/fixtures/memory-entries.ts +328 -0
- package/src/fixtures/memory-fixtures.ts +750 -0
- package/src/fixtures/swarm-fixtures.ts +837 -0
- package/src/fixtures/tasks.ts +309 -0
- package/src/helpers/assertion-helpers.ts +616 -0
- package/src/helpers/assertions.ts +286 -0
- package/src/helpers/create-mock.ts +200 -0
- package/src/helpers/index.ts +182 -0
- package/src/helpers/mock-factory.ts +711 -0
- package/src/helpers/setup-teardown.ts +678 -0
- package/src/helpers/swarm-instance.ts +326 -0
- package/src/helpers/test-application.ts +310 -0
- package/src/helpers/test-utils.ts +670 -0
- package/src/index.ts +232 -0
- package/src/mocks/index.ts +29 -0
- package/src/mocks/mock-mcp-client.ts +723 -0
- package/src/mocks/mock-services.ts +793 -0
- package/src/regression/api-contract.ts +473 -0
- package/src/regression/index.ts +46 -0
- package/src/regression/integration-regression.ts +416 -0
- package/src/regression/performance-baseline.ts +356 -0
- package/src/regression/regression-runner.ts +339 -0
- package/src/regression/security-regression.ts +331 -0
- package/src/setup.ts +127 -0
- package/src/v2-compat/api-compat.test.ts +590 -0
- package/src/v2-compat/cli-compat.test.ts +484 -0
- package/src/v2-compat/compatibility-validator.ts +1072 -0
- package/src/v2-compat/hooks-compat.test.ts +602 -0
- package/src/v2-compat/index.ts +58 -0
- package/src/v2-compat/mcp-compat.test.ts +557 -0
- package/src/v2-compat/report-generator.ts +441 -0
- package/tmp.json +0 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +12 -0
|
@@ -0,0 +1,837 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sparkleideas/testing - Swarm Fixtures
|
|
3
|
+
*
|
|
4
|
+
* Comprehensive mock swarm configurations, topologies, and coordination fixtures.
|
|
5
|
+
* Supports hierarchical-mesh, adaptive, and all consensus protocols.
|
|
6
|
+
*
|
|
7
|
+
* Based on ADR-003 (Single Coordination Engine) and V3 swarm specifications.
|
|
8
|
+
*/
|
|
9
|
+
import { vi, type Mock } from 'vitest';
|
|
10
|
+
import type { V3AgentType, AgentInstance, MockAgent, createMockAgent } from './agent-fixtures.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Swarm topology types
|
|
14
|
+
*/
|
|
15
|
+
export type SwarmTopology =
|
|
16
|
+
| 'hierarchical'
|
|
17
|
+
| 'mesh'
|
|
18
|
+
| 'ring'
|
|
19
|
+
| 'star'
|
|
20
|
+
| 'adaptive'
|
|
21
|
+
| 'hierarchical-mesh';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Consensus protocol types
|
|
25
|
+
*/
|
|
26
|
+
export type ConsensusProtocol = 'raft' | 'pbft' | 'gossip' | 'crdt' | 'byzantine';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Coordination status types
|
|
30
|
+
*/
|
|
31
|
+
export type CoordinationStatus =
|
|
32
|
+
| 'initializing'
|
|
33
|
+
| 'active'
|
|
34
|
+
| 'coordinating'
|
|
35
|
+
| 'consensus'
|
|
36
|
+
| 'error'
|
|
37
|
+
| 'shutdown';
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Swarm configuration interface
|
|
41
|
+
*/
|
|
42
|
+
export interface SwarmConfig {
|
|
43
|
+
topology: SwarmTopology;
|
|
44
|
+
maxAgents: number;
|
|
45
|
+
name?: string;
|
|
46
|
+
description?: string;
|
|
47
|
+
coordination: CoordinationConfig;
|
|
48
|
+
communication: CommunicationConfig;
|
|
49
|
+
autoScale?: AutoScaleConfig;
|
|
50
|
+
healthCheck?: HealthCheckConfig;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Coordination configuration
|
|
55
|
+
*/
|
|
56
|
+
export interface CoordinationConfig {
|
|
57
|
+
consensusProtocol: ConsensusProtocol;
|
|
58
|
+
heartbeatInterval: number;
|
|
59
|
+
electionTimeout: number;
|
|
60
|
+
consensusRequired?: boolean;
|
|
61
|
+
timeoutMs?: number;
|
|
62
|
+
retryPolicy?: {
|
|
63
|
+
maxRetries: number;
|
|
64
|
+
backoffMs: number;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Communication configuration
|
|
70
|
+
*/
|
|
71
|
+
export interface CommunicationConfig {
|
|
72
|
+
protocol: 'quic' | 'tcp' | 'websocket' | 'ipc';
|
|
73
|
+
maxMessageSize: number;
|
|
74
|
+
retryAttempts: number;
|
|
75
|
+
compressionEnabled?: boolean;
|
|
76
|
+
encryptionEnabled?: boolean;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Auto-scale configuration
|
|
81
|
+
*/
|
|
82
|
+
export interface AutoScaleConfig {
|
|
83
|
+
enabled: boolean;
|
|
84
|
+
minAgents: number;
|
|
85
|
+
maxAgents: number;
|
|
86
|
+
scaleUpThreshold: number;
|
|
87
|
+
scaleDownThreshold: number;
|
|
88
|
+
cooldownMs?: number;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Health check configuration
|
|
93
|
+
*/
|
|
94
|
+
export interface HealthCheckConfig {
|
|
95
|
+
enabled: boolean;
|
|
96
|
+
interval: number;
|
|
97
|
+
timeout: number;
|
|
98
|
+
unhealthyThreshold: number;
|
|
99
|
+
healthyThreshold: number;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Swarm state interface
|
|
104
|
+
*/
|
|
105
|
+
export interface SwarmState {
|
|
106
|
+
id: string;
|
|
107
|
+
topology: SwarmTopology;
|
|
108
|
+
status: CoordinationStatus;
|
|
109
|
+
agentCount: number;
|
|
110
|
+
activeAgentCount: number;
|
|
111
|
+
leaderId?: string;
|
|
112
|
+
createdAt: Date;
|
|
113
|
+
lastHeartbeat?: Date;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Swarm message interface
|
|
118
|
+
*/
|
|
119
|
+
export interface SwarmMessage<T = unknown> {
|
|
120
|
+
id: string;
|
|
121
|
+
from: string;
|
|
122
|
+
to: string | 'broadcast';
|
|
123
|
+
type: 'task' | 'result' | 'status' | 'coordination' | 'heartbeat' | 'election';
|
|
124
|
+
payload: T;
|
|
125
|
+
timestamp: Date;
|
|
126
|
+
correlationId?: string;
|
|
127
|
+
replyTo?: string;
|
|
128
|
+
ttl?: number;
|
|
129
|
+
priority?: number;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Swarm task interface
|
|
134
|
+
*/
|
|
135
|
+
export interface SwarmTask {
|
|
136
|
+
id: string;
|
|
137
|
+
name: string;
|
|
138
|
+
type: string;
|
|
139
|
+
payload: unknown;
|
|
140
|
+
priority: number;
|
|
141
|
+
assignedTo?: string;
|
|
142
|
+
status: 'pending' | 'assigned' | 'running' | 'completed' | 'failed' | 'cancelled';
|
|
143
|
+
dependencies?: string[];
|
|
144
|
+
deadline?: Date;
|
|
145
|
+
createdAt: Date;
|
|
146
|
+
startedAt?: Date;
|
|
147
|
+
completedAt?: Date;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Swarm task result interface
|
|
152
|
+
*/
|
|
153
|
+
export interface SwarmTaskResult {
|
|
154
|
+
taskId: string;
|
|
155
|
+
agentId: string;
|
|
156
|
+
success: boolean;
|
|
157
|
+
output?: unknown;
|
|
158
|
+
error?: Error;
|
|
159
|
+
duration: number;
|
|
160
|
+
metrics?: TaskMetrics;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Task metrics interface
|
|
165
|
+
*/
|
|
166
|
+
export interface TaskMetrics {
|
|
167
|
+
cpuTime: number;
|
|
168
|
+
memoryUsage: number;
|
|
169
|
+
ioOperations: number;
|
|
170
|
+
networkCalls: number;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Coordination result interface
|
|
175
|
+
*/
|
|
176
|
+
export interface CoordinationResult {
|
|
177
|
+
success: boolean;
|
|
178
|
+
completedTasks: number;
|
|
179
|
+
failedTasks: number;
|
|
180
|
+
totalDuration: number;
|
|
181
|
+
agentMetrics: Map<string, AgentCoordinationMetrics>;
|
|
182
|
+
consensusRounds?: number;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Agent coordination metrics
|
|
187
|
+
*/
|
|
188
|
+
export interface AgentCoordinationMetrics {
|
|
189
|
+
tasksCompleted: number;
|
|
190
|
+
tasksFailed: number;
|
|
191
|
+
averageTaskDuration: number;
|
|
192
|
+
messagesProcessed: number;
|
|
193
|
+
totalDuration: number;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Consensus request interface
|
|
198
|
+
*/
|
|
199
|
+
export interface ConsensusRequest<T = unknown> {
|
|
200
|
+
topic: string;
|
|
201
|
+
options: T[];
|
|
202
|
+
requiredVotes: number | 'majority' | 'all';
|
|
203
|
+
timeout: number;
|
|
204
|
+
voters?: string[];
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Consensus response interface
|
|
209
|
+
*/
|
|
210
|
+
export interface ConsensusResponse<T = unknown> {
|
|
211
|
+
topic: string;
|
|
212
|
+
decision: T | null;
|
|
213
|
+
votes: Map<string, T>;
|
|
214
|
+
consensus: boolean;
|
|
215
|
+
votingDuration: number;
|
|
216
|
+
participatingAgents: string[];
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Pre-defined swarm configurations for testing
|
|
221
|
+
*/
|
|
222
|
+
export const swarmConfigs: Record<string, SwarmConfig> = {
|
|
223
|
+
v3Default: {
|
|
224
|
+
topology: 'hierarchical-mesh',
|
|
225
|
+
maxAgents: 15,
|
|
226
|
+
name: 'V3 Default Swarm',
|
|
227
|
+
description: 'Standard V3 15-agent hierarchical-mesh swarm',
|
|
228
|
+
coordination: {
|
|
229
|
+
consensusProtocol: 'raft',
|
|
230
|
+
heartbeatInterval: 1000,
|
|
231
|
+
electionTimeout: 5000,
|
|
232
|
+
consensusRequired: true,
|
|
233
|
+
timeoutMs: 8000,
|
|
234
|
+
retryPolicy: { maxRetries: 3, backoffMs: 1000 },
|
|
235
|
+
},
|
|
236
|
+
communication: {
|
|
237
|
+
protocol: 'quic',
|
|
238
|
+
maxMessageSize: 1048576, // 1MB
|
|
239
|
+
retryAttempts: 3,
|
|
240
|
+
compressionEnabled: true,
|
|
241
|
+
encryptionEnabled: true,
|
|
242
|
+
},
|
|
243
|
+
autoScale: {
|
|
244
|
+
enabled: true,
|
|
245
|
+
minAgents: 5,
|
|
246
|
+
maxAgents: 15,
|
|
247
|
+
scaleUpThreshold: 0.8,
|
|
248
|
+
scaleDownThreshold: 0.3,
|
|
249
|
+
cooldownMs: 30000,
|
|
250
|
+
},
|
|
251
|
+
healthCheck: {
|
|
252
|
+
enabled: true,
|
|
253
|
+
interval: 5000,
|
|
254
|
+
timeout: 2000,
|
|
255
|
+
unhealthyThreshold: 3,
|
|
256
|
+
healthyThreshold: 2,
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
|
|
260
|
+
minimal: {
|
|
261
|
+
topology: 'mesh',
|
|
262
|
+
maxAgents: 5,
|
|
263
|
+
name: 'Minimal Swarm',
|
|
264
|
+
description: 'Lightweight swarm for testing',
|
|
265
|
+
coordination: {
|
|
266
|
+
consensusProtocol: 'gossip',
|
|
267
|
+
heartbeatInterval: 2000,
|
|
268
|
+
electionTimeout: 10000,
|
|
269
|
+
consensusRequired: false,
|
|
270
|
+
timeoutMs: 5000,
|
|
271
|
+
retryPolicy: { maxRetries: 5, backoffMs: 500 },
|
|
272
|
+
},
|
|
273
|
+
communication: {
|
|
274
|
+
protocol: 'tcp',
|
|
275
|
+
maxMessageSize: 65536, // 64KB
|
|
276
|
+
retryAttempts: 5,
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
|
|
280
|
+
highPerformance: {
|
|
281
|
+
topology: 'adaptive',
|
|
282
|
+
maxAgents: 50,
|
|
283
|
+
name: 'High Performance Swarm',
|
|
284
|
+
description: 'Optimized for maximum throughput',
|
|
285
|
+
coordination: {
|
|
286
|
+
consensusProtocol: 'pbft',
|
|
287
|
+
heartbeatInterval: 500,
|
|
288
|
+
electionTimeout: 3000,
|
|
289
|
+
consensusRequired: true,
|
|
290
|
+
timeoutMs: 5000,
|
|
291
|
+
retryPolicy: { maxRetries: 2, backoffMs: 250 },
|
|
292
|
+
},
|
|
293
|
+
communication: {
|
|
294
|
+
protocol: 'quic',
|
|
295
|
+
maxMessageSize: 4194304, // 4MB
|
|
296
|
+
retryAttempts: 2,
|
|
297
|
+
compressionEnabled: true,
|
|
298
|
+
encryptionEnabled: true,
|
|
299
|
+
},
|
|
300
|
+
autoScale: {
|
|
301
|
+
enabled: true,
|
|
302
|
+
minAgents: 10,
|
|
303
|
+
maxAgents: 50,
|
|
304
|
+
scaleUpThreshold: 0.7,
|
|
305
|
+
scaleDownThreshold: 0.2,
|
|
306
|
+
cooldownMs: 15000,
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
|
|
310
|
+
byzantineFault: {
|
|
311
|
+
topology: 'mesh',
|
|
312
|
+
maxAgents: 7,
|
|
313
|
+
name: 'Byzantine Fault Tolerant Swarm',
|
|
314
|
+
description: 'Tolerant to malicious actors',
|
|
315
|
+
coordination: {
|
|
316
|
+
consensusProtocol: 'byzantine',
|
|
317
|
+
heartbeatInterval: 1000,
|
|
318
|
+
electionTimeout: 10000,
|
|
319
|
+
consensusRequired: true,
|
|
320
|
+
timeoutMs: 15000,
|
|
321
|
+
retryPolicy: { maxRetries: 5, backoffMs: 2000 },
|
|
322
|
+
},
|
|
323
|
+
communication: {
|
|
324
|
+
protocol: 'tcp',
|
|
325
|
+
maxMessageSize: 1048576,
|
|
326
|
+
retryAttempts: 3,
|
|
327
|
+
encryptionEnabled: true,
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
|
|
331
|
+
hierarchicalOnly: {
|
|
332
|
+
topology: 'hierarchical',
|
|
333
|
+
maxAgents: 20,
|
|
334
|
+
name: 'Hierarchical Swarm',
|
|
335
|
+
description: 'Pure hierarchical coordination',
|
|
336
|
+
coordination: {
|
|
337
|
+
consensusProtocol: 'raft',
|
|
338
|
+
heartbeatInterval: 1000,
|
|
339
|
+
electionTimeout: 5000,
|
|
340
|
+
consensusRequired: false,
|
|
341
|
+
timeoutMs: 5000,
|
|
342
|
+
retryPolicy: { maxRetries: 3, backoffMs: 1000 },
|
|
343
|
+
},
|
|
344
|
+
communication: {
|
|
345
|
+
protocol: 'websocket',
|
|
346
|
+
maxMessageSize: 524288, // 512KB
|
|
347
|
+
retryAttempts: 3,
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
|
|
351
|
+
ringTopology: {
|
|
352
|
+
topology: 'ring',
|
|
353
|
+
maxAgents: 10,
|
|
354
|
+
name: 'Ring Topology Swarm',
|
|
355
|
+
description: 'Token-passing ring coordination',
|
|
356
|
+
coordination: {
|
|
357
|
+
consensusProtocol: 'gossip',
|
|
358
|
+
heartbeatInterval: 1500,
|
|
359
|
+
electionTimeout: 8000,
|
|
360
|
+
consensusRequired: true,
|
|
361
|
+
timeoutMs: 8000,
|
|
362
|
+
retryPolicy: { maxRetries: 4, backoffMs: 750 },
|
|
363
|
+
},
|
|
364
|
+
communication: {
|
|
365
|
+
protocol: 'tcp',
|
|
366
|
+
maxMessageSize: 262144, // 256KB
|
|
367
|
+
retryAttempts: 4,
|
|
368
|
+
},
|
|
369
|
+
},
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Pre-defined swarm states for testing
|
|
374
|
+
*/
|
|
375
|
+
export const swarmStates: Record<string, SwarmState> = {
|
|
376
|
+
active: {
|
|
377
|
+
id: 'swarm-001',
|
|
378
|
+
topology: 'hierarchical-mesh',
|
|
379
|
+
status: 'active',
|
|
380
|
+
agentCount: 15,
|
|
381
|
+
activeAgentCount: 15,
|
|
382
|
+
leaderId: 'agent-queen-001',
|
|
383
|
+
createdAt: new Date('2024-01-01T00:00:00Z'),
|
|
384
|
+
lastHeartbeat: new Date(),
|
|
385
|
+
},
|
|
386
|
+
|
|
387
|
+
initializing: {
|
|
388
|
+
id: 'swarm-002',
|
|
389
|
+
topology: 'mesh',
|
|
390
|
+
status: 'initializing',
|
|
391
|
+
agentCount: 5,
|
|
392
|
+
activeAgentCount: 3,
|
|
393
|
+
createdAt: new Date(),
|
|
394
|
+
},
|
|
395
|
+
|
|
396
|
+
coordinating: {
|
|
397
|
+
id: 'swarm-003',
|
|
398
|
+
topology: 'adaptive',
|
|
399
|
+
status: 'coordinating',
|
|
400
|
+
agentCount: 10,
|
|
401
|
+
activeAgentCount: 10,
|
|
402
|
+
leaderId: 'agent-coordinator-001',
|
|
403
|
+
createdAt: new Date('2024-01-10T00:00:00Z'),
|
|
404
|
+
lastHeartbeat: new Date(),
|
|
405
|
+
},
|
|
406
|
+
|
|
407
|
+
consensus: {
|
|
408
|
+
id: 'swarm-004',
|
|
409
|
+
topology: 'hierarchical-mesh',
|
|
410
|
+
status: 'consensus',
|
|
411
|
+
agentCount: 15,
|
|
412
|
+
activeAgentCount: 14,
|
|
413
|
+
leaderId: 'agent-queen-001',
|
|
414
|
+
createdAt: new Date('2024-01-05T00:00:00Z'),
|
|
415
|
+
lastHeartbeat: new Date(),
|
|
416
|
+
},
|
|
417
|
+
|
|
418
|
+
error: {
|
|
419
|
+
id: 'swarm-005',
|
|
420
|
+
topology: 'mesh',
|
|
421
|
+
status: 'error',
|
|
422
|
+
agentCount: 8,
|
|
423
|
+
activeAgentCount: 3,
|
|
424
|
+
createdAt: new Date('2024-01-01T00:00:00Z'),
|
|
425
|
+
lastHeartbeat: new Date(Date.now() - 60000), // 1 minute ago
|
|
426
|
+
},
|
|
427
|
+
|
|
428
|
+
shutdown: {
|
|
429
|
+
id: 'swarm-006',
|
|
430
|
+
topology: 'hierarchical',
|
|
431
|
+
status: 'shutdown',
|
|
432
|
+
agentCount: 10,
|
|
433
|
+
activeAgentCount: 0,
|
|
434
|
+
createdAt: new Date('2024-01-01T00:00:00Z'),
|
|
435
|
+
},
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Pre-defined swarm tasks for testing
|
|
440
|
+
*/
|
|
441
|
+
export const swarmTasks: Record<string, SwarmTask> = {
|
|
442
|
+
securityScan: {
|
|
443
|
+
id: 'task-security-001',
|
|
444
|
+
name: 'Security Scan',
|
|
445
|
+
type: 'security',
|
|
446
|
+
payload: { target: './src', scanType: 'full', severity: 'high' },
|
|
447
|
+
priority: 100,
|
|
448
|
+
status: 'pending',
|
|
449
|
+
createdAt: new Date(),
|
|
450
|
+
},
|
|
451
|
+
|
|
452
|
+
codeReview: {
|
|
453
|
+
id: 'task-review-001',
|
|
454
|
+
name: 'Code Review',
|
|
455
|
+
type: 'review',
|
|
456
|
+
payload: { files: ['src/main.ts'], rules: ['security', 'performance'] },
|
|
457
|
+
priority: 80,
|
|
458
|
+
status: 'assigned',
|
|
459
|
+
assignedTo: 'agent-reviewer-001',
|
|
460
|
+
createdAt: new Date(),
|
|
461
|
+
},
|
|
462
|
+
|
|
463
|
+
implementation: {
|
|
464
|
+
id: 'task-impl-001',
|
|
465
|
+
name: 'Feature Implementation',
|
|
466
|
+
type: 'coding',
|
|
467
|
+
payload: { feature: 'path-validation', module: 'security' },
|
|
468
|
+
priority: 70,
|
|
469
|
+
status: 'running',
|
|
470
|
+
assignedTo: 'agent-coder-001',
|
|
471
|
+
createdAt: new Date(Date.now() - 60000),
|
|
472
|
+
startedAt: new Date(Date.now() - 30000),
|
|
473
|
+
},
|
|
474
|
+
|
|
475
|
+
testing: {
|
|
476
|
+
id: 'task-test-001',
|
|
477
|
+
name: 'Unit Testing',
|
|
478
|
+
type: 'testing',
|
|
479
|
+
payload: { framework: 'vitest', coverage: 0.90 },
|
|
480
|
+
priority: 75,
|
|
481
|
+
status: 'completed',
|
|
482
|
+
assignedTo: 'agent-tester-001',
|
|
483
|
+
createdAt: new Date(Date.now() - 120000),
|
|
484
|
+
startedAt: new Date(Date.now() - 90000),
|
|
485
|
+
completedAt: new Date(Date.now() - 30000),
|
|
486
|
+
},
|
|
487
|
+
|
|
488
|
+
orchestration: {
|
|
489
|
+
id: 'task-orch-001',
|
|
490
|
+
name: 'Task Orchestration',
|
|
491
|
+
type: 'coordination',
|
|
492
|
+
payload: { subtasks: ['task-impl-001', 'task-test-001'], parallel: true },
|
|
493
|
+
priority: 90,
|
|
494
|
+
status: 'running',
|
|
495
|
+
assignedTo: 'agent-queen-001',
|
|
496
|
+
dependencies: ['task-security-001'],
|
|
497
|
+
createdAt: new Date(Date.now() - 180000),
|
|
498
|
+
startedAt: new Date(Date.now() - 120000),
|
|
499
|
+
},
|
|
500
|
+
};
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Pre-defined swarm messages for testing
|
|
504
|
+
*/
|
|
505
|
+
export const swarmMessages: Record<string, SwarmMessage> = {
|
|
506
|
+
taskAssignment: {
|
|
507
|
+
id: 'msg-001',
|
|
508
|
+
from: 'agent-queen-001',
|
|
509
|
+
to: 'agent-coder-001',
|
|
510
|
+
type: 'task',
|
|
511
|
+
payload: swarmTasks.implementation,
|
|
512
|
+
timestamp: new Date(),
|
|
513
|
+
correlationId: 'corr-001',
|
|
514
|
+
priority: 70,
|
|
515
|
+
},
|
|
516
|
+
|
|
517
|
+
taskResult: {
|
|
518
|
+
id: 'msg-002',
|
|
519
|
+
from: 'agent-coder-001',
|
|
520
|
+
to: 'agent-queen-001',
|
|
521
|
+
type: 'result',
|
|
522
|
+
payload: { taskId: 'task-impl-001', success: true, duration: 5000 },
|
|
523
|
+
timestamp: new Date(),
|
|
524
|
+
correlationId: 'corr-001',
|
|
525
|
+
replyTo: 'msg-001',
|
|
526
|
+
},
|
|
527
|
+
|
|
528
|
+
heartbeat: {
|
|
529
|
+
id: 'msg-003',
|
|
530
|
+
from: 'agent-queen-001',
|
|
531
|
+
to: 'broadcast',
|
|
532
|
+
type: 'heartbeat',
|
|
533
|
+
payload: { status: 'active', load: 0.6, taskCount: 5 },
|
|
534
|
+
timestamp: new Date(),
|
|
535
|
+
ttl: 5000,
|
|
536
|
+
},
|
|
537
|
+
|
|
538
|
+
election: {
|
|
539
|
+
id: 'msg-004',
|
|
540
|
+
from: 'agent-swarm-001',
|
|
541
|
+
to: 'broadcast',
|
|
542
|
+
type: 'election',
|
|
543
|
+
payload: { term: 5, candidateId: 'agent-swarm-001', lastLogIndex: 100 },
|
|
544
|
+
timestamp: new Date(),
|
|
545
|
+
priority: 100,
|
|
546
|
+
},
|
|
547
|
+
|
|
548
|
+
coordination: {
|
|
549
|
+
id: 'msg-005',
|
|
550
|
+
from: 'agent-queen-001',
|
|
551
|
+
to: 'agent-swarm-001',
|
|
552
|
+
type: 'coordination',
|
|
553
|
+
payload: { action: 'scale-up', targetAgents: 3 },
|
|
554
|
+
timestamp: new Date(),
|
|
555
|
+
correlationId: 'corr-002',
|
|
556
|
+
},
|
|
557
|
+
|
|
558
|
+
statusUpdate: {
|
|
559
|
+
id: 'msg-006',
|
|
560
|
+
from: 'agent-memory-001',
|
|
561
|
+
to: 'agent-queen-001',
|
|
562
|
+
type: 'status',
|
|
563
|
+
payload: { status: 'busy', currentTask: 'indexing', progress: 0.75 },
|
|
564
|
+
timestamp: new Date(),
|
|
565
|
+
},
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Pre-defined coordination results for testing
|
|
570
|
+
*/
|
|
571
|
+
export const coordinationResults: Record<string, CoordinationResult> = {
|
|
572
|
+
successful: {
|
|
573
|
+
success: true,
|
|
574
|
+
completedTasks: 10,
|
|
575
|
+
failedTasks: 0,
|
|
576
|
+
totalDuration: 15000,
|
|
577
|
+
agentMetrics: new Map([
|
|
578
|
+
['agent-queen-001', { tasksCompleted: 3, tasksFailed: 0, averageTaskDuration: 200, messagesProcessed: 50, totalDuration: 600 }],
|
|
579
|
+
['agent-coder-001', { tasksCompleted: 4, tasksFailed: 0, averageTaskDuration: 2000, messagesProcessed: 20, totalDuration: 8000 }],
|
|
580
|
+
['agent-tester-001', { tasksCompleted: 3, tasksFailed: 0, averageTaskDuration: 1500, messagesProcessed: 15, totalDuration: 4500 }],
|
|
581
|
+
]),
|
|
582
|
+
consensusRounds: 2,
|
|
583
|
+
},
|
|
584
|
+
|
|
585
|
+
partialFailure: {
|
|
586
|
+
success: true,
|
|
587
|
+
completedTasks: 8,
|
|
588
|
+
failedTasks: 2,
|
|
589
|
+
totalDuration: 20000,
|
|
590
|
+
agentMetrics: new Map([
|
|
591
|
+
['agent-queen-001', { tasksCompleted: 2, tasksFailed: 0, averageTaskDuration: 250, messagesProcessed: 40, totalDuration: 500 }],
|
|
592
|
+
['agent-coder-001', { tasksCompleted: 4, tasksFailed: 1, averageTaskDuration: 2500, messagesProcessed: 25, totalDuration: 10000 }],
|
|
593
|
+
['agent-tester-001', { tasksCompleted: 2, tasksFailed: 1, averageTaskDuration: 2000, messagesProcessed: 18, totalDuration: 4000 }],
|
|
594
|
+
]),
|
|
595
|
+
consensusRounds: 3,
|
|
596
|
+
},
|
|
597
|
+
|
|
598
|
+
failed: {
|
|
599
|
+
success: false,
|
|
600
|
+
completedTasks: 2,
|
|
601
|
+
failedTasks: 8,
|
|
602
|
+
totalDuration: 30000,
|
|
603
|
+
agentMetrics: new Map([
|
|
604
|
+
['agent-queen-001', { tasksCompleted: 1, tasksFailed: 2, averageTaskDuration: 500, messagesProcessed: 60, totalDuration: 500 }],
|
|
605
|
+
['agent-coder-001', { tasksCompleted: 1, tasksFailed: 3, averageTaskDuration: 5000, messagesProcessed: 30, totalDuration: 5000 }],
|
|
606
|
+
]),
|
|
607
|
+
consensusRounds: 5,
|
|
608
|
+
},
|
|
609
|
+
};
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Factory function to create swarm config with overrides
|
|
613
|
+
*/
|
|
614
|
+
export function createSwarmConfig(
|
|
615
|
+
base: keyof typeof swarmConfigs = 'v3Default',
|
|
616
|
+
overrides?: Partial<SwarmConfig>
|
|
617
|
+
): SwarmConfig {
|
|
618
|
+
return mergeDeep(swarmConfigs[base] as SwarmConfig & Record<string, unknown>, (overrides ?? {}) as Partial<SwarmConfig & Record<string, unknown>>);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* Factory function to create swarm state with overrides
|
|
623
|
+
*/
|
|
624
|
+
export function createSwarmState(
|
|
625
|
+
base: keyof typeof swarmStates = 'active',
|
|
626
|
+
overrides?: Partial<SwarmState>
|
|
627
|
+
): SwarmState {
|
|
628
|
+
return {
|
|
629
|
+
...swarmStates[base],
|
|
630
|
+
...overrides,
|
|
631
|
+
id: overrides?.id ?? swarmStates[base].id,
|
|
632
|
+
createdAt: overrides?.createdAt ?? swarmStates[base].createdAt,
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* Factory function to create swarm task with overrides
|
|
638
|
+
*/
|
|
639
|
+
export function createSwarmTask(
|
|
640
|
+
base: keyof typeof swarmTasks = 'implementation',
|
|
641
|
+
overrides?: Partial<SwarmTask>
|
|
642
|
+
): SwarmTask {
|
|
643
|
+
return {
|
|
644
|
+
...swarmTasks[base],
|
|
645
|
+
...overrides,
|
|
646
|
+
id: overrides?.id ?? `task-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
|
|
647
|
+
createdAt: overrides?.createdAt ?? new Date(),
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* Factory function to create swarm message with overrides
|
|
653
|
+
*/
|
|
654
|
+
export function createSwarmMessage<T = unknown>(
|
|
655
|
+
type: SwarmMessage['type'],
|
|
656
|
+
payload: T,
|
|
657
|
+
overrides?: Partial<SwarmMessage<T>>
|
|
658
|
+
): SwarmMessage<T> {
|
|
659
|
+
return {
|
|
660
|
+
id: `msg-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
|
|
661
|
+
from: 'agent-sender',
|
|
662
|
+
to: 'agent-receiver',
|
|
663
|
+
type,
|
|
664
|
+
payload,
|
|
665
|
+
timestamp: new Date(),
|
|
666
|
+
...overrides,
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* Factory function to create consensus request
|
|
672
|
+
*/
|
|
673
|
+
export function createConsensusRequest<T>(
|
|
674
|
+
topic: string,
|
|
675
|
+
options: T[],
|
|
676
|
+
overrides?: Partial<ConsensusRequest<T>>
|
|
677
|
+
): ConsensusRequest<T> {
|
|
678
|
+
return {
|
|
679
|
+
topic,
|
|
680
|
+
options,
|
|
681
|
+
requiredVotes: 'majority',
|
|
682
|
+
timeout: 5000,
|
|
683
|
+
...overrides,
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
/**
|
|
688
|
+
* Factory function to create coordination result
|
|
689
|
+
*/
|
|
690
|
+
export function createCoordinationResult(
|
|
691
|
+
base: keyof typeof coordinationResults = 'successful',
|
|
692
|
+
overrides?: Partial<CoordinationResult>
|
|
693
|
+
): CoordinationResult {
|
|
694
|
+
return {
|
|
695
|
+
...coordinationResults[base],
|
|
696
|
+
...overrides,
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
/**
|
|
701
|
+
* Create a batch of swarm tasks for testing
|
|
702
|
+
*/
|
|
703
|
+
export function createSwarmTaskBatch(
|
|
704
|
+
count: number,
|
|
705
|
+
type: string = 'coding'
|
|
706
|
+
): SwarmTask[] {
|
|
707
|
+
return Array.from({ length: count }, (_, i) => ({
|
|
708
|
+
id: `batch-task-${i}`,
|
|
709
|
+
name: `Batch Task ${i + 1}`,
|
|
710
|
+
type,
|
|
711
|
+
payload: { index: i },
|
|
712
|
+
priority: Math.floor(Math.random() * 100),
|
|
713
|
+
status: 'pending' as const,
|
|
714
|
+
createdAt: new Date(),
|
|
715
|
+
}));
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/**
|
|
719
|
+
* Deep merge utility
|
|
720
|
+
*/
|
|
721
|
+
function mergeDeep<T extends Record<string, unknown>>(
|
|
722
|
+
target: T,
|
|
723
|
+
source: Partial<T>
|
|
724
|
+
): T {
|
|
725
|
+
const output = { ...target } as Record<string, unknown>;
|
|
726
|
+
|
|
727
|
+
for (const key of Object.keys(source)) {
|
|
728
|
+
const sourceValue = source[key as keyof T];
|
|
729
|
+
if (sourceValue && typeof sourceValue === 'object' && !Array.isArray(sourceValue)) {
|
|
730
|
+
output[key] = mergeDeep(
|
|
731
|
+
(target[key as keyof T] as Record<string, unknown>) ?? {},
|
|
732
|
+
sourceValue as Record<string, unknown>
|
|
733
|
+
);
|
|
734
|
+
} else {
|
|
735
|
+
output[key] = sourceValue;
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
return output as T;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
/**
|
|
743
|
+
* Invalid swarm configurations for error testing
|
|
744
|
+
*/
|
|
745
|
+
export const invalidSwarmConfigs = {
|
|
746
|
+
zeroAgents: createSwarmConfig('v3Default', { maxAgents: 0 }),
|
|
747
|
+
|
|
748
|
+
negativeHeartbeat: createSwarmConfig('v3Default', {
|
|
749
|
+
coordination: {
|
|
750
|
+
consensusProtocol: 'raft',
|
|
751
|
+
heartbeatInterval: -100,
|
|
752
|
+
electionTimeout: 5000,
|
|
753
|
+
},
|
|
754
|
+
}),
|
|
755
|
+
|
|
756
|
+
invalidTopology: {
|
|
757
|
+
...swarmConfigs.v3Default,
|
|
758
|
+
topology: 'invalid-topology' as SwarmTopology,
|
|
759
|
+
},
|
|
760
|
+
|
|
761
|
+
invalidProtocol: createSwarmConfig('v3Default', {
|
|
762
|
+
coordination: {
|
|
763
|
+
consensusProtocol: 'invalid-protocol' as ConsensusProtocol,
|
|
764
|
+
heartbeatInterval: 1000,
|
|
765
|
+
electionTimeout: 5000,
|
|
766
|
+
},
|
|
767
|
+
}),
|
|
768
|
+
|
|
769
|
+
zeroMessageSize: createSwarmConfig('v3Default', {
|
|
770
|
+
communication: {
|
|
771
|
+
protocol: 'quic',
|
|
772
|
+
maxMessageSize: 0,
|
|
773
|
+
retryAttempts: 3,
|
|
774
|
+
},
|
|
775
|
+
}),
|
|
776
|
+
};
|
|
777
|
+
|
|
778
|
+
/**
|
|
779
|
+
* Mock swarm coordinator interface
|
|
780
|
+
*/
|
|
781
|
+
export interface MockSwarmCoordinator {
|
|
782
|
+
initialize: Mock<(config: SwarmConfig) => Promise<SwarmState>>;
|
|
783
|
+
coordinate: Mock<(agents: string[], task: SwarmTask) => Promise<CoordinationResult>>;
|
|
784
|
+
shutdown: Mock<(graceful?: boolean) => Promise<void>>;
|
|
785
|
+
addAgent: Mock<(agentId: string) => Promise<void>>;
|
|
786
|
+
removeAgent: Mock<(agentId: string) => Promise<void>>;
|
|
787
|
+
getState: Mock<() => SwarmState>;
|
|
788
|
+
broadcast: Mock<(message: SwarmMessage) => Promise<void>>;
|
|
789
|
+
requestConsensus: Mock<<T>(request: ConsensusRequest<T>) => Promise<ConsensusResponse<T>>>;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
/**
|
|
793
|
+
* Create a mock swarm coordinator
|
|
794
|
+
*/
|
|
795
|
+
export function createMockSwarmCoordinator(): MockSwarmCoordinator {
|
|
796
|
+
return {
|
|
797
|
+
initialize: vi.fn().mockResolvedValue(swarmStates.active),
|
|
798
|
+
coordinate: vi.fn().mockResolvedValue(coordinationResults.successful),
|
|
799
|
+
shutdown: vi.fn().mockResolvedValue(undefined),
|
|
800
|
+
addAgent: vi.fn().mockResolvedValue(undefined),
|
|
801
|
+
removeAgent: vi.fn().mockResolvedValue(undefined),
|
|
802
|
+
getState: vi.fn().mockReturnValue(swarmStates.active),
|
|
803
|
+
broadcast: vi.fn().mockResolvedValue(undefined),
|
|
804
|
+
requestConsensus: vi.fn().mockResolvedValue({
|
|
805
|
+
topic: 'test',
|
|
806
|
+
decision: 'option-1',
|
|
807
|
+
votes: new Map(),
|
|
808
|
+
consensus: true,
|
|
809
|
+
votingDuration: 100,
|
|
810
|
+
participatingAgents: [],
|
|
811
|
+
}),
|
|
812
|
+
};
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
/**
|
|
816
|
+
* Mock message bus interface
|
|
817
|
+
*/
|
|
818
|
+
export interface MockMessageBus {
|
|
819
|
+
publish: Mock<(message: SwarmMessage) => Promise<void>>;
|
|
820
|
+
subscribe: Mock<(pattern: string, handler: (message: SwarmMessage) => void) => () => void>;
|
|
821
|
+
unsubscribe: Mock<(pattern: string) => void>;
|
|
822
|
+
request: Mock<(message: SwarmMessage, timeout?: number) => Promise<SwarmMessage>>;
|
|
823
|
+
getStats: Mock<() => { messagesSent: number; messagesReceived: number }>;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
/**
|
|
827
|
+
* Create a mock message bus
|
|
828
|
+
*/
|
|
829
|
+
export function createMockMessageBus(): MockMessageBus {
|
|
830
|
+
return {
|
|
831
|
+
publish: vi.fn().mockResolvedValue(undefined),
|
|
832
|
+
subscribe: vi.fn().mockReturnValue(() => {}),
|
|
833
|
+
unsubscribe: vi.fn(),
|
|
834
|
+
request: vi.fn().mockResolvedValue(swarmMessages.taskResult),
|
|
835
|
+
getStats: vi.fn().mockReturnValue({ messagesSent: 0, messagesReceived: 0 }),
|
|
836
|
+
};
|
|
837
|
+
}
|