@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,590 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* V2 API Compatibility Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests that V2 import paths work via aliases and class interfaces match.
|
|
5
|
+
* Verifies method signatures and type compatibility.
|
|
6
|
+
*
|
|
7
|
+
* @module v3/testing/v2-compat/api-compat.test
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { describe, it, expect, beforeEach, afterEach, vi, type Mock } from 'vitest';
|
|
11
|
+
import {
|
|
12
|
+
V2CompatibilityValidator,
|
|
13
|
+
V2_API_INTERFACES,
|
|
14
|
+
type V2APIInterface,
|
|
15
|
+
type ValidationResult,
|
|
16
|
+
} from './compatibility-validator.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Mock V3 module registry for testing
|
|
20
|
+
*/
|
|
21
|
+
interface MockModuleRegistry {
|
|
22
|
+
getClass: Mock<(name: string) => MockClass | null>;
|
|
23
|
+
getClasses: Mock<() => string[]>;
|
|
24
|
+
resolveImport: Mock<(path: string) => string | null>;
|
|
25
|
+
getMethodSignature: Mock<(className: string, method: string) => string | null>;
|
|
26
|
+
checkTypeCompatibility: Mock<(v2Type: string, v3Type: string) => boolean>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Mock class representation
|
|
31
|
+
*/
|
|
32
|
+
interface MockClass {
|
|
33
|
+
name: string;
|
|
34
|
+
v3Name: string;
|
|
35
|
+
methods: MockMethod[];
|
|
36
|
+
staticMethods: MockMethod[];
|
|
37
|
+
properties: MockProperty[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Mock method representation
|
|
42
|
+
*/
|
|
43
|
+
interface MockMethod {
|
|
44
|
+
name: string;
|
|
45
|
+
signature: string;
|
|
46
|
+
v2Signature?: string;
|
|
47
|
+
compatible: boolean;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Mock property representation
|
|
52
|
+
*/
|
|
53
|
+
interface MockProperty {
|
|
54
|
+
name: string;
|
|
55
|
+
type: string;
|
|
56
|
+
readonly: boolean;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* V3 class implementations mapping
|
|
61
|
+
*/
|
|
62
|
+
const V3_CLASSES: Record<string, MockClass> = {
|
|
63
|
+
'UnifiedSwarmCoordinator': {
|
|
64
|
+
name: 'UnifiedSwarmCoordinator',
|
|
65
|
+
v3Name: 'UnifiedSwarmCoordinator',
|
|
66
|
+
methods: [
|
|
67
|
+
{ name: 'initialize', signature: '(config?: SwarmConfig): Promise<void>', compatible: true },
|
|
68
|
+
{ name: 'spawn', signature: '(agentType: string, config?: AgentConfig): Promise<Agent>', v2Signature: '(type: string, config?: AgentConfig): Promise<Agent>', compatible: true },
|
|
69
|
+
{ name: 'addAgent', signature: '(agent: Agent): Promise<void>', compatible: true },
|
|
70
|
+
{ name: 'removeAgent', signature: '(agentId: string): Promise<void>', compatible: true },
|
|
71
|
+
{ name: 'broadcast', signature: '(message: Message): Promise<void>', compatible: true },
|
|
72
|
+
{ name: 'consensus', signature: '(proposal: Proposal): Promise<ConsensusResult>', compatible: true },
|
|
73
|
+
{ name: 'getStatus', signature: '(): Promise<SwarmStatus>', compatible: true },
|
|
74
|
+
{ name: 'shutdown', signature: '(): Promise<void>', compatible: true },
|
|
75
|
+
{ name: 'init', signature: '(topology: string): Promise<void>', compatible: true },
|
|
76
|
+
],
|
|
77
|
+
staticMethods: [],
|
|
78
|
+
properties: [
|
|
79
|
+
{ name: 'topology', type: 'string', readonly: true },
|
|
80
|
+
{ name: 'agentCount', type: 'number', readonly: true },
|
|
81
|
+
{ name: 'status', type: 'SwarmStatus', readonly: true },
|
|
82
|
+
],
|
|
83
|
+
},
|
|
84
|
+
'UnifiedMemoryService': {
|
|
85
|
+
name: 'UnifiedMemoryService',
|
|
86
|
+
v3Name: 'UnifiedMemoryService',
|
|
87
|
+
methods: [
|
|
88
|
+
{ name: 'store', signature: '(entry: MemoryEntry): Promise<string>', compatible: true },
|
|
89
|
+
{ name: 'search', signature: '(query: string, options?: SearchOptions): Promise<MemoryEntry[]>', v2Signature: '(search: string): Promise<MemoryEntry[]>', compatible: true },
|
|
90
|
+
{ name: 'query', signature: '(search: string): Promise<MemoryEntry[]>', compatible: true },
|
|
91
|
+
{ name: 'delete', signature: '(id: string): Promise<boolean>', compatible: true },
|
|
92
|
+
{ name: 'clear', signature: '(): Promise<void>', compatible: true },
|
|
93
|
+
{ name: 'getStats', signature: '(): Promise<MemoryStats>', compatible: true },
|
|
94
|
+
],
|
|
95
|
+
staticMethods: [],
|
|
96
|
+
properties: [
|
|
97
|
+
{ name: 'backend', type: 'string', readonly: true },
|
|
98
|
+
{ name: 'stats', type: 'MemoryStats', readonly: true },
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
'AgentLifecycleService': {
|
|
102
|
+
name: 'AgentLifecycleService',
|
|
103
|
+
v3Name: 'AgentLifecycleService',
|
|
104
|
+
methods: [
|
|
105
|
+
{ name: 'spawn', signature: '(config: AgentConfig): Promise<Agent>', compatible: true },
|
|
106
|
+
{ name: 'terminate', signature: '(id: string): Promise<void>', compatible: true },
|
|
107
|
+
{ name: 'list', signature: '(): Promise<Agent[]>', compatible: true },
|
|
108
|
+
{ name: 'getInfo', signature: '(id: string): Promise<AgentInfo>', compatible: true },
|
|
109
|
+
{ name: 'getStatus', signature: '(id: string): Promise<AgentStatus>', compatible: true },
|
|
110
|
+
],
|
|
111
|
+
staticMethods: [],
|
|
112
|
+
properties: [
|
|
113
|
+
{ name: 'agents', type: 'Map<string, Agent>', readonly: true },
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
'TaskExecutionService': {
|
|
117
|
+
name: 'TaskExecutionService',
|
|
118
|
+
v3Name: 'TaskExecutionService',
|
|
119
|
+
methods: [
|
|
120
|
+
{ name: 'create', signature: '(definition: TaskDefinition): Promise<Task>', compatible: true },
|
|
121
|
+
{ name: 'assign', signature: '(taskId: string, agentId: string): Promise<void>', compatible: true },
|
|
122
|
+
{ name: 'complete', signature: '(taskId: string, result?: TaskResult): Promise<void>', v2Signature: '(taskId: string, result?: any): Promise<void>', compatible: true },
|
|
123
|
+
{ name: 'getStatus', signature: '(taskId: string): Promise<TaskStatus>', compatible: true },
|
|
124
|
+
],
|
|
125
|
+
staticMethods: [],
|
|
126
|
+
properties: [
|
|
127
|
+
{ name: 'tasks', type: 'Map<string, Task>', readonly: true },
|
|
128
|
+
],
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* V2 to V3 import alias mapping
|
|
134
|
+
*/
|
|
135
|
+
const IMPORT_ALIASES: Record<string, string> = {
|
|
136
|
+
'@sparkleideas/claude-flow/hive-mind': '@sparkleideas/swarm',
|
|
137
|
+
'@sparkleideas/claude-flow/swarm': '@sparkleideas/swarm',
|
|
138
|
+
'@sparkleideas/claude-flow/memory': '@sparkleideas/memory',
|
|
139
|
+
'@sparkleideas/claude-flow/agents': '@sparkleideas/agent-lifecycle',
|
|
140
|
+
'@sparkleideas/claude-flow/tasks': '@sparkleideas/task-execution',
|
|
141
|
+
'@sparkleideas/claude-flow/hooks': '@sparkleideas/hooks',
|
|
142
|
+
'@sparkleideas/claude-flow/config': '@sparkleideas/config',
|
|
143
|
+
'@sparkleideas/claude-flow': '@sparkleideas/core',
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* V2 to V3 class name mapping
|
|
148
|
+
*/
|
|
149
|
+
const CLASS_ALIASES: Record<string, string> = {
|
|
150
|
+
'HiveMind': 'UnifiedSwarmCoordinator',
|
|
151
|
+
'SwarmCoordinator': 'UnifiedSwarmCoordinator',
|
|
152
|
+
'MemoryManager': 'UnifiedMemoryService',
|
|
153
|
+
'AgentManager': 'AgentLifecycleService',
|
|
154
|
+
'TaskOrchestrator': 'TaskExecutionService',
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Create mock module registry
|
|
159
|
+
*/
|
|
160
|
+
function createMockModuleRegistry(): MockModuleRegistry {
|
|
161
|
+
return {
|
|
162
|
+
getClass: vi.fn().mockImplementation((name: string) => {
|
|
163
|
+
const v3Name = CLASS_ALIASES[name] || name;
|
|
164
|
+
return V3_CLASSES[v3Name] || null;
|
|
165
|
+
}),
|
|
166
|
+
getClasses: vi.fn().mockReturnValue(Object.keys(V3_CLASSES)),
|
|
167
|
+
resolveImport: vi.fn().mockImplementation((path: string) => {
|
|
168
|
+
return IMPORT_ALIASES[path] || null;
|
|
169
|
+
}),
|
|
170
|
+
getMethodSignature: vi.fn().mockImplementation((className: string, methodName: string) => {
|
|
171
|
+
const v3Name = CLASS_ALIASES[className] || className;
|
|
172
|
+
const classInfo = V3_CLASSES[v3Name];
|
|
173
|
+
if (!classInfo) return null;
|
|
174
|
+
|
|
175
|
+
const method = classInfo.methods.find(m => m.name === methodName);
|
|
176
|
+
return method?.signature || null;
|
|
177
|
+
}),
|
|
178
|
+
checkTypeCompatibility: vi.fn().mockImplementation((v2Type: string, v3Type: string) => {
|
|
179
|
+
// Simplified type compatibility check
|
|
180
|
+
if (v2Type === v3Type) return true;
|
|
181
|
+
if (v2Type === 'any') return true;
|
|
182
|
+
if (v3Type.includes(v2Type)) return true;
|
|
183
|
+
return false;
|
|
184
|
+
}),
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
describe('V2 API Compatibility', () => {
|
|
189
|
+
let validator: V2CompatibilityValidator;
|
|
190
|
+
let mockRegistry: MockModuleRegistry;
|
|
191
|
+
|
|
192
|
+
beforeEach(() => {
|
|
193
|
+
mockRegistry = createMockModuleRegistry();
|
|
194
|
+
validator = new V2CompatibilityValidator({
|
|
195
|
+
verbose: false,
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
afterEach(() => {
|
|
200
|
+
vi.clearAllMocks();
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
describe('Import Path Aliases', () => {
|
|
204
|
+
it.each(Object.entries(IMPORT_ALIASES))('should resolve V2 import "%s" to V3 "%s"', (v2Path, v3Path) => {
|
|
205
|
+
const resolved = mockRegistry.resolveImport(v2Path);
|
|
206
|
+
|
|
207
|
+
expect(resolved).toBe(v3Path);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('should resolve @sparkleideas/claude-flow/hive-mind to @sparkleideas/swarm', () => {
|
|
211
|
+
const resolved = mockRegistry.resolveImport('@sparkleideas/claude-flow/hive-mind');
|
|
212
|
+
|
|
213
|
+
expect(resolved).toBe('@sparkleideas/swarm');
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('should resolve @sparkleideas/claude-flow/memory to @sparkleideas/memory', () => {
|
|
217
|
+
const resolved = mockRegistry.resolveImport('@sparkleideas/claude-flow/memory');
|
|
218
|
+
|
|
219
|
+
expect(resolved).toBe('@sparkleideas/memory');
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('should return null for unknown import paths', () => {
|
|
223
|
+
const resolved = mockRegistry.resolveImport('unknown-package');
|
|
224
|
+
|
|
225
|
+
expect(resolved).toBeNull();
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
describe('Class Name Aliases', () => {
|
|
230
|
+
it.each(Object.entries(CLASS_ALIASES))('should map V2 class "%s" to V3 "%s"', (v2Name, v3Name) => {
|
|
231
|
+
const classInfo = mockRegistry.getClass(v2Name);
|
|
232
|
+
|
|
233
|
+
expect(classInfo).not.toBeNull();
|
|
234
|
+
expect(classInfo?.v3Name).toBe(v3Name);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it('should get HiveMind as UnifiedSwarmCoordinator', () => {
|
|
238
|
+
const classInfo = mockRegistry.getClass('HiveMind');
|
|
239
|
+
|
|
240
|
+
expect(classInfo).not.toBeNull();
|
|
241
|
+
expect(classInfo?.name).toBe('UnifiedSwarmCoordinator');
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it('should get MemoryManager as UnifiedMemoryService', () => {
|
|
245
|
+
const classInfo = mockRegistry.getClass('MemoryManager');
|
|
246
|
+
|
|
247
|
+
expect(classInfo).not.toBeNull();
|
|
248
|
+
expect(classInfo?.name).toBe('UnifiedMemoryService');
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
describe('HiveMind Interface', () => {
|
|
253
|
+
const hiveMindInterface = V2_API_INTERFACES.find(i => i.name === 'HiveMind')!;
|
|
254
|
+
|
|
255
|
+
it('should have all HiveMind methods available', () => {
|
|
256
|
+
const classInfo = mockRegistry.getClass('HiveMind');
|
|
257
|
+
|
|
258
|
+
expect(classInfo).not.toBeNull();
|
|
259
|
+
|
|
260
|
+
for (const method of hiveMindInterface.methods) {
|
|
261
|
+
const hasMethod = classInfo!.methods.some(m => m.name === method.name);
|
|
262
|
+
expect(hasMethod).toBe(true);
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it('should have compatible initialize signature', () => {
|
|
267
|
+
const signature = mockRegistry.getMethodSignature('HiveMind', 'initialize');
|
|
268
|
+
|
|
269
|
+
expect(signature).toContain('Promise<void>');
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it('should have compatible spawn signature', () => {
|
|
273
|
+
const signature = mockRegistry.getMethodSignature('HiveMind', 'spawn');
|
|
274
|
+
|
|
275
|
+
expect(signature).toContain('Promise<Agent>');
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it('should have compatible getStatus signature', () => {
|
|
279
|
+
const signature = mockRegistry.getMethodSignature('HiveMind', 'getStatus');
|
|
280
|
+
|
|
281
|
+
expect(signature).toContain('Promise');
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it('should have compatible shutdown signature', () => {
|
|
285
|
+
const signature = mockRegistry.getMethodSignature('HiveMind', 'shutdown');
|
|
286
|
+
|
|
287
|
+
expect(signature).toContain('Promise<void>');
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
describe('SwarmCoordinator Interface', () => {
|
|
292
|
+
const swarmInterface = V2_API_INTERFACES.find(i => i.name === 'SwarmCoordinator')!;
|
|
293
|
+
|
|
294
|
+
it('should have all SwarmCoordinator methods available', () => {
|
|
295
|
+
const classInfo = mockRegistry.getClass('SwarmCoordinator');
|
|
296
|
+
|
|
297
|
+
expect(classInfo).not.toBeNull();
|
|
298
|
+
|
|
299
|
+
for (const method of swarmInterface.methods) {
|
|
300
|
+
const hasMethod = classInfo!.methods.some(m => m.name === method.name);
|
|
301
|
+
expect(hasMethod).toBe(true);
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it('should have compatible init signature', () => {
|
|
306
|
+
const signature = mockRegistry.getMethodSignature('SwarmCoordinator', 'init');
|
|
307
|
+
|
|
308
|
+
expect(signature).toContain('topology');
|
|
309
|
+
expect(signature).toContain('Promise<void>');
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
it('should have compatible addAgent signature', () => {
|
|
313
|
+
const signature = mockRegistry.getMethodSignature('SwarmCoordinator', 'addAgent');
|
|
314
|
+
|
|
315
|
+
expect(signature).toContain('Agent');
|
|
316
|
+
expect(signature).toContain('Promise<void>');
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
it('should have compatible broadcast signature', () => {
|
|
320
|
+
const signature = mockRegistry.getMethodSignature('SwarmCoordinator', 'broadcast');
|
|
321
|
+
|
|
322
|
+
expect(signature).toContain('Message');
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
it('should have compatible consensus signature', () => {
|
|
326
|
+
const signature = mockRegistry.getMethodSignature('SwarmCoordinator', 'consensus');
|
|
327
|
+
|
|
328
|
+
expect(signature).toContain('Proposal');
|
|
329
|
+
expect(signature).toContain('ConsensusResult');
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
describe('MemoryManager Interface', () => {
|
|
334
|
+
const memoryInterface = V2_API_INTERFACES.find(i => i.name === 'MemoryManager')!;
|
|
335
|
+
|
|
336
|
+
it('should have all MemoryManager methods available', () => {
|
|
337
|
+
const classInfo = mockRegistry.getClass('MemoryManager');
|
|
338
|
+
|
|
339
|
+
expect(classInfo).not.toBeNull();
|
|
340
|
+
|
|
341
|
+
for (const method of memoryInterface.methods) {
|
|
342
|
+
const hasMethod = classInfo!.methods.some(m =>
|
|
343
|
+
m.name === method.name || (method.name === 'query' && m.name === 'search')
|
|
344
|
+
);
|
|
345
|
+
expect(hasMethod).toBe(true);
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
it('should have compatible store signature', () => {
|
|
350
|
+
const signature = mockRegistry.getMethodSignature('MemoryManager', 'store');
|
|
351
|
+
|
|
352
|
+
expect(signature).toContain('MemoryEntry');
|
|
353
|
+
expect(signature).toContain('Promise<string>');
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
it('should have query aliased to search', () => {
|
|
357
|
+
const classInfo = mockRegistry.getClass('MemoryManager');
|
|
358
|
+
const hasQuery = classInfo!.methods.some(m => m.name === 'query');
|
|
359
|
+
const hasSearch = classInfo!.methods.some(m => m.name === 'search');
|
|
360
|
+
|
|
361
|
+
expect(hasQuery || hasSearch).toBe(true);
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
it('should have compatible delete signature', () => {
|
|
365
|
+
const signature = mockRegistry.getMethodSignature('MemoryManager', 'delete');
|
|
366
|
+
|
|
367
|
+
expect(signature).toContain('Promise<boolean>');
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
it('should have compatible getStats signature', () => {
|
|
371
|
+
const signature = mockRegistry.getMethodSignature('MemoryManager', 'getStats');
|
|
372
|
+
|
|
373
|
+
expect(signature).toContain('MemoryStats');
|
|
374
|
+
});
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
describe('AgentManager Interface', () => {
|
|
378
|
+
const agentInterface = V2_API_INTERFACES.find(i => i.name === 'AgentManager')!;
|
|
379
|
+
|
|
380
|
+
it('should have all AgentManager methods available', () => {
|
|
381
|
+
const classInfo = mockRegistry.getClass('AgentManager');
|
|
382
|
+
|
|
383
|
+
expect(classInfo).not.toBeNull();
|
|
384
|
+
|
|
385
|
+
for (const method of agentInterface.methods) {
|
|
386
|
+
const hasMethod = classInfo!.methods.some(m => m.name === method.name);
|
|
387
|
+
expect(hasMethod).toBe(true);
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
it('should have compatible spawn signature', () => {
|
|
392
|
+
const signature = mockRegistry.getMethodSignature('AgentManager', 'spawn');
|
|
393
|
+
|
|
394
|
+
expect(signature).toContain('AgentConfig');
|
|
395
|
+
expect(signature).toContain('Promise<Agent>');
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
it('should have compatible terminate signature', () => {
|
|
399
|
+
const signature = mockRegistry.getMethodSignature('AgentManager', 'terminate');
|
|
400
|
+
|
|
401
|
+
expect(signature).toContain('Promise<void>');
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
it('should have compatible list signature', () => {
|
|
405
|
+
const signature = mockRegistry.getMethodSignature('AgentManager', 'list');
|
|
406
|
+
|
|
407
|
+
expect(signature).toContain('Promise<Agent[]>');
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
it('should have compatible getInfo signature', () => {
|
|
411
|
+
const signature = mockRegistry.getMethodSignature('AgentManager', 'getInfo');
|
|
412
|
+
|
|
413
|
+
expect(signature).toContain('AgentInfo');
|
|
414
|
+
});
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
describe('TaskOrchestrator Interface', () => {
|
|
418
|
+
const taskInterface = V2_API_INTERFACES.find(i => i.name === 'TaskOrchestrator')!;
|
|
419
|
+
|
|
420
|
+
it('should have all TaskOrchestrator methods available', () => {
|
|
421
|
+
const classInfo = mockRegistry.getClass('TaskOrchestrator');
|
|
422
|
+
|
|
423
|
+
expect(classInfo).not.toBeNull();
|
|
424
|
+
|
|
425
|
+
for (const method of taskInterface.methods) {
|
|
426
|
+
const hasMethod = classInfo!.methods.some(m => m.name === method.name);
|
|
427
|
+
expect(hasMethod).toBe(true);
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
it('should have compatible create signature', () => {
|
|
432
|
+
const signature = mockRegistry.getMethodSignature('TaskOrchestrator', 'create');
|
|
433
|
+
|
|
434
|
+
expect(signature).toContain('TaskDefinition');
|
|
435
|
+
expect(signature).toContain('Promise<Task>');
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
it('should have compatible assign signature', () => {
|
|
439
|
+
const signature = mockRegistry.getMethodSignature('TaskOrchestrator', 'assign');
|
|
440
|
+
|
|
441
|
+
expect(signature).toContain('taskId');
|
|
442
|
+
expect(signature).toContain('agentId');
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
it('should have compatible complete signature', () => {
|
|
446
|
+
const signature = mockRegistry.getMethodSignature('TaskOrchestrator', 'complete');
|
|
447
|
+
|
|
448
|
+
expect(signature).toContain('taskId');
|
|
449
|
+
expect(signature).toContain('Promise<void>');
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
it('should have compatible getStatus signature', () => {
|
|
453
|
+
const signature = mockRegistry.getMethodSignature('TaskOrchestrator', 'getStatus');
|
|
454
|
+
|
|
455
|
+
expect(signature).toContain('TaskStatus');
|
|
456
|
+
});
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
describe('Type Compatibility', () => {
|
|
460
|
+
it('should accept any type as compatible', () => {
|
|
461
|
+
const compatible = mockRegistry.checkTypeCompatibility('any', 'string');
|
|
462
|
+
|
|
463
|
+
expect(compatible).toBe(true);
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
it('should accept same types as compatible', () => {
|
|
467
|
+
const compatible = mockRegistry.checkTypeCompatibility('string', 'string');
|
|
468
|
+
|
|
469
|
+
expect(compatible).toBe(true);
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
it('should accept subtype compatibility', () => {
|
|
473
|
+
const compatible = mockRegistry.checkTypeCompatibility('Agent', 'Agent | null');
|
|
474
|
+
|
|
475
|
+
expect(compatible).toBe(true);
|
|
476
|
+
});
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
describe('Full API Validation', () => {
|
|
480
|
+
it('should pass full API validation', async () => {
|
|
481
|
+
const result: ValidationResult = await validator.validateAPI();
|
|
482
|
+
|
|
483
|
+
expect(result.category).toBe('api');
|
|
484
|
+
expect(result.totalChecks).toBeGreaterThan(0);
|
|
485
|
+
expect(result.passedChecks).toBeGreaterThan(0);
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
it('should detect all V2 API interfaces', async () => {
|
|
489
|
+
const result = await validator.validateAPI();
|
|
490
|
+
const classChecks = result.checks.filter(c => c.name.startsWith('API Class:'));
|
|
491
|
+
|
|
492
|
+
expect(classChecks.length).toBeGreaterThanOrEqual(V2_API_INTERFACES.length);
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
it('should verify method signatures', async () => {
|
|
496
|
+
const result = await validator.validateAPI();
|
|
497
|
+
const methodChecks = result.checks.filter(c => c.name.includes('Method:'));
|
|
498
|
+
|
|
499
|
+
expect(methodChecks.length).toBeGreaterThan(0);
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
it('should provide migration paths', async () => {
|
|
503
|
+
const result = await validator.validateAPI();
|
|
504
|
+
const withMigration = result.checks.filter(c => c.migrationPath);
|
|
505
|
+
|
|
506
|
+
expect(withMigration.length).toBeGreaterThan(0);
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
it('should report minimal breaking changes', async () => {
|
|
510
|
+
const result = await validator.validateAPI();
|
|
511
|
+
|
|
512
|
+
// Most interfaces should be compatible
|
|
513
|
+
expect(result.breakingChanges).toBeLessThan(result.totalChecks * 0.2);
|
|
514
|
+
});
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
describe('Backward Compatible Usage Patterns', () => {
|
|
518
|
+
it('should support V2 HiveMind instantiation pattern', () => {
|
|
519
|
+
// V2 pattern: const hive = new HiveMind(config);
|
|
520
|
+
// V3 equivalent: const hive = new UnifiedSwarmCoordinator(config);
|
|
521
|
+
const classInfo = mockRegistry.getClass('HiveMind');
|
|
522
|
+
|
|
523
|
+
expect(classInfo).not.toBeNull();
|
|
524
|
+
expect(classInfo?.methods.some(m => m.name === 'initialize')).toBe(true);
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
it('should support V2 MemoryManager query pattern', () => {
|
|
528
|
+
// V2 pattern: const results = await memory.query('search term');
|
|
529
|
+
// V3 equivalent: const results = await memory.search('search term');
|
|
530
|
+
const classInfo = mockRegistry.getClass('MemoryManager');
|
|
531
|
+
const hasQueryOrSearch = classInfo?.methods.some(m =>
|
|
532
|
+
m.name === 'query' || m.name === 'search'
|
|
533
|
+
);
|
|
534
|
+
|
|
535
|
+
expect(hasQueryOrSearch).toBe(true);
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
it('should support V2 agent spawn pattern', () => {
|
|
539
|
+
// V2 pattern: const agent = await manager.spawn({ type: 'coder' });
|
|
540
|
+
// V3 equivalent: const agent = await lifecycle.spawn({ agentType: 'coder' });
|
|
541
|
+
const classInfo = mockRegistry.getClass('AgentManager');
|
|
542
|
+
|
|
543
|
+
expect(classInfo?.methods.some(m => m.name === 'spawn')).toBe(true);
|
|
544
|
+
});
|
|
545
|
+
});
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
describe('API Coverage', () => {
|
|
549
|
+
it('should define all core V2 API interfaces', () => {
|
|
550
|
+
const coreInterfaces = ['HiveMind', 'SwarmCoordinator', 'MemoryManager', 'AgentManager', 'TaskOrchestrator'];
|
|
551
|
+
|
|
552
|
+
for (const name of coreInterfaces) {
|
|
553
|
+
const iface = V2_API_INTERFACES.find(i => i.name === name);
|
|
554
|
+
expect(iface).toBeDefined();
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
it('should have V3 equivalents for all interfaces', () => {
|
|
559
|
+
for (const iface of V2_API_INTERFACES) {
|
|
560
|
+
expect(iface.v3Equivalent).toBeDefined();
|
|
561
|
+
expect(iface.v3Equivalent).not.toBe('');
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
it('should define methods for all interfaces', () => {
|
|
566
|
+
for (const iface of V2_API_INTERFACES) {
|
|
567
|
+
expect(iface.methods.length).toBeGreaterThan(0);
|
|
568
|
+
}
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
it('should define method signatures correctly', () => {
|
|
572
|
+
for (const iface of V2_API_INTERFACES) {
|
|
573
|
+
for (const method of iface.methods) {
|
|
574
|
+
expect(method.name).toBeDefined();
|
|
575
|
+
expect(method.signature).toBeDefined();
|
|
576
|
+
expect(method.signature).toContain(':');
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
it('should cover common method patterns', () => {
|
|
582
|
+
const allMethods = V2_API_INTERFACES.flatMap(i => i.methods.map(m => m.name));
|
|
583
|
+
|
|
584
|
+
expect(allMethods).toContain('initialize');
|
|
585
|
+
expect(allMethods).toContain('spawn');
|
|
586
|
+
expect(allMethods).toContain('store');
|
|
587
|
+
expect(allMethods).toContain('create');
|
|
588
|
+
expect(allMethods).toContain('getStatus');
|
|
589
|
+
});
|
|
590
|
+
});
|