@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.
Files changed (42) hide show
  1. package/README.md +547 -0
  2. package/__tests__/framework.test.ts +21 -0
  3. package/package.json +61 -0
  4. package/src/fixtures/agent-fixtures.ts +793 -0
  5. package/src/fixtures/agents.ts +212 -0
  6. package/src/fixtures/configurations.ts +491 -0
  7. package/src/fixtures/index.ts +21 -0
  8. package/src/fixtures/mcp-fixtures.ts +1030 -0
  9. package/src/fixtures/memory-entries.ts +328 -0
  10. package/src/fixtures/memory-fixtures.ts +750 -0
  11. package/src/fixtures/swarm-fixtures.ts +837 -0
  12. package/src/fixtures/tasks.ts +309 -0
  13. package/src/helpers/assertion-helpers.ts +616 -0
  14. package/src/helpers/assertions.ts +286 -0
  15. package/src/helpers/create-mock.ts +200 -0
  16. package/src/helpers/index.ts +182 -0
  17. package/src/helpers/mock-factory.ts +711 -0
  18. package/src/helpers/setup-teardown.ts +678 -0
  19. package/src/helpers/swarm-instance.ts +326 -0
  20. package/src/helpers/test-application.ts +310 -0
  21. package/src/helpers/test-utils.ts +670 -0
  22. package/src/index.ts +232 -0
  23. package/src/mocks/index.ts +29 -0
  24. package/src/mocks/mock-mcp-client.ts +723 -0
  25. package/src/mocks/mock-services.ts +793 -0
  26. package/src/regression/api-contract.ts +473 -0
  27. package/src/regression/index.ts +46 -0
  28. package/src/regression/integration-regression.ts +416 -0
  29. package/src/regression/performance-baseline.ts +356 -0
  30. package/src/regression/regression-runner.ts +339 -0
  31. package/src/regression/security-regression.ts +331 -0
  32. package/src/setup.ts +127 -0
  33. package/src/v2-compat/api-compat.test.ts +590 -0
  34. package/src/v2-compat/cli-compat.test.ts +484 -0
  35. package/src/v2-compat/compatibility-validator.ts +1072 -0
  36. package/src/v2-compat/hooks-compat.test.ts +602 -0
  37. package/src/v2-compat/index.ts +58 -0
  38. package/src/v2-compat/mcp-compat.test.ts +557 -0
  39. package/src/v2-compat/report-generator.ts +441 -0
  40. package/tmp.json +0 -0
  41. package/tsconfig.json +20 -0
  42. 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
+ }