@taicode/common-base 1.7.2 → 1.7.3

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.
@@ -0,0 +1,1033 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { FlowQueue } from './flow-queue';
3
+ describe('FlowQueue', () => {
4
+ let flowQueue;
5
+ let mockProcessor;
6
+ beforeEach(() => {
7
+ // 重置 mock processor
8
+ mockProcessor = vi.fn();
9
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
10
+ });
11
+ describe('基本功能', () => {
12
+ it('应该正确初始化', () => {
13
+ expect(flowQueue.successOutputs.size).toBe(0);
14
+ expect(flowQueue.erroredOutputs.size).toBe(0);
15
+ expect(flowQueue['pendingInputs'].length).toBe(0);
16
+ expect(flowQueue['processedInputs'].length).toBe(0);
17
+ });
18
+ it('应该接受输入并开始处理', async () => {
19
+ const testInput = { id: 1, data: 'test' };
20
+ const expectedOutput = { id: 1, result: 'processed', timestamp: Date.now() };
21
+ mockProcessor = vi.fn().mockResolvedValue(expectedOutput);
22
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
23
+ flowQueue.input(testInput);
24
+ // 等待异步处理完成
25
+ await new Promise(resolve => setTimeout(resolve, 50));
26
+ expect(mockProcessor).toHaveBeenCalledWith(testInput);
27
+ expect(flowQueue.successOutputs.get(testInput)).toEqual(expectedOutput);
28
+ expect(flowQueue['processedInputs']).toContain(testInput);
29
+ expect(flowQueue['pendingInputs']).not.toContain(testInput);
30
+ });
31
+ it('应该能处理多个输入', async () => {
32
+ const inputs = [
33
+ { id: 1, data: 'test1' },
34
+ { id: 2, data: 'test2' },
35
+ { id: 3, data: 'test3' }
36
+ ];
37
+ mockProcessor = vi.fn().mockImplementation(async (input) => ({
38
+ id: input.id,
39
+ result: `processed_${input.data}`,
40
+ timestamp: Date.now()
41
+ }));
42
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
43
+ flowQueue.input(...inputs);
44
+ // 等待所有异步处理完成
45
+ await new Promise(resolve => setTimeout(resolve, 100));
46
+ expect(mockProcessor).toHaveBeenCalledTimes(3);
47
+ expect(flowQueue['processedInputs'].length).toBe(3);
48
+ expect(flowQueue['pendingInputs'].length).toBe(0);
49
+ inputs.forEach(input => {
50
+ const output = flowQueue.successOutputs.get(input);
51
+ expect(output.id).toBe(input.id);
52
+ expect(output.result).toBe(`processed_${input.data}`);
53
+ });
54
+ });
55
+ });
56
+ describe('错误处理', () => {
57
+ it('应该在处理失败时记录错误', async () => {
58
+ const testInput = { id: 1, data: 'test' };
59
+ const errorMessage = 'Processing failed';
60
+ mockProcessor = vi.fn().mockRejectedValue(new Error(errorMessage));
61
+ flowQueue = new FlowQueue({ retry: { maxRetries: 0 } }, mockProcessor); // 不重试
62
+ flowQueue.input(testInput);
63
+ await new Promise(resolve => setTimeout(resolve, 50));
64
+ const errorResult = flowQueue.erroredOutputs.get(testInput);
65
+ expect(errorResult).toBeInstanceOf(Error);
66
+ expect(errorResult.message).toBe(errorMessage);
67
+ expect(flowQueue['processedInputs']).toContain(testInput);
68
+ });
69
+ it('应该处理非 Error 类型的异常', async () => {
70
+ const testInput = { id: 1, data: 'test' };
71
+ const errorMessage = 'String error';
72
+ mockProcessor = vi.fn().mockRejectedValue(errorMessage);
73
+ flowQueue = new FlowQueue({ retry: { maxRetries: 0 } }, mockProcessor);
74
+ flowQueue.input(testInput);
75
+ await new Promise(resolve => setTimeout(resolve, 50));
76
+ const errorResult = flowQueue.erroredOutputs.get(testInput);
77
+ expect(errorResult).toBe(errorMessage);
78
+ });
79
+ });
80
+ describe('重试机制', () => {
81
+ it('应该在失败时重试', async () => {
82
+ const testInput = { id: 1, data: 'test' };
83
+ const successOutput = { id: 1, result: 'success', timestamp: Date.now() };
84
+ // 前两次调用失败,第三次成功
85
+ mockProcessor = vi.fn()
86
+ .mockRejectedValueOnce(new Error('First failure'))
87
+ .mockRejectedValueOnce(new Error('Second failure'))
88
+ .mockResolvedValueOnce(successOutput);
89
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
90
+ flowQueue.input(testInput);
91
+ await new Promise(resolve => setTimeout(resolve, 100));
92
+ expect(mockProcessor).toHaveBeenCalledTimes(3);
93
+ expect(flowQueue.successOutputs.get(testInput)).toEqual(successOutput);
94
+ expect(flowQueue['processedInputs']).toContain(testInput);
95
+ });
96
+ it('应该在超过最大重试次数后停止重试', async () => {
97
+ const testInput = { id: 1, data: 'test' };
98
+ const errorMessage = 'Persistent failure';
99
+ mockProcessor = vi.fn().mockRejectedValue(new Error(errorMessage));
100
+ flowQueue = new FlowQueue({ retry: { maxRetries: 2 } }, mockProcessor);
101
+ flowQueue.input(testInput);
102
+ await new Promise(resolve => setTimeout(resolve, 100));
103
+ // 应该调用 3 次(初始 + 2 次重试)
104
+ expect(mockProcessor).toHaveBeenCalledTimes(3);
105
+ const errorResult = flowQueue.erroredOutputs.get(testInput);
106
+ expect(errorResult).toBeInstanceOf(Error);
107
+ expect(errorResult.message).toBe(errorMessage);
108
+ expect(flowQueue['processedInputs']).toContain(testInput);
109
+ });
110
+ it('应该使用默认的最大重试次数', async () => {
111
+ const testInput = { id: 1, data: 'test' };
112
+ mockProcessor = vi.fn().mockRejectedValue(new Error('Failure'));
113
+ flowQueue = new FlowQueue({}, mockProcessor); // 不指定 maxRetries
114
+ flowQueue.input(testInput);
115
+ await new Promise(resolve => setTimeout(resolve, 150));
116
+ // 应该调用 4 次(初始 + 3 次重试,默认值为 3)
117
+ expect(mockProcessor).toHaveBeenCalledTimes(4);
118
+ });
119
+ });
120
+ describe('回调机制', () => {
121
+ it('应该在成功处理后调用 onGenerate 回调', async () => {
122
+ const testInput = { id: 1, data: 'test' };
123
+ const expectedOutput = { id: 1, result: 'success', timestamp: Date.now() };
124
+ const callback = vi.fn();
125
+ mockProcessor = vi.fn().mockResolvedValue(expectedOutput);
126
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
127
+ const unsubscribe = flowQueue.onGenerate(callback);
128
+ flowQueue.input(testInput);
129
+ await new Promise(resolve => setTimeout(resolve, 50));
130
+ expect(callback).toHaveBeenCalledWith(expectedOutput);
131
+ expect(callback).toHaveBeenCalledTimes(1);
132
+ // 测试取消订阅
133
+ unsubscribe();
134
+ const anotherInput = { id: 2, data: 'test2' };
135
+ flowQueue.input(anotherInput);
136
+ await new Promise(resolve => setTimeout(resolve, 50));
137
+ // 回调不应该再被调用
138
+ expect(callback).toHaveBeenCalledTimes(1);
139
+ });
140
+ it('应该支持多个回调', async () => {
141
+ const testInput = { id: 1, data: 'test' };
142
+ const expectedOutput = { id: 1, result: 'success', timestamp: Date.now() };
143
+ const callback1 = vi.fn();
144
+ const callback2 = vi.fn();
145
+ mockProcessor = vi.fn().mockResolvedValue(expectedOutput);
146
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
147
+ flowQueue.onGenerate(callback1);
148
+ flowQueue.onGenerate(callback2);
149
+ flowQueue.input(testInput);
150
+ await new Promise(resolve => setTimeout(resolve, 50));
151
+ expect(callback1).toHaveBeenCalledWith(expectedOutput);
152
+ expect(callback2).toHaveBeenCalledWith(expectedOutput);
153
+ });
154
+ it('应该处理回调中的错误', async () => {
155
+ const testInput = { id: 1, data: 'test' };
156
+ const expectedOutput = { id: 1, result: 'success', timestamp: Date.now() };
157
+ const faultyCallback = vi.fn().mockImplementation(() => {
158
+ throw new Error('Callback error');
159
+ });
160
+ const normalCallback = vi.fn();
161
+ // Mock console.error 来验证错误被正确记录
162
+ const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
163
+ mockProcessor = vi.fn().mockResolvedValue(expectedOutput);
164
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
165
+ flowQueue.onGenerate(faultyCallback);
166
+ flowQueue.onGenerate(normalCallback);
167
+ flowQueue.input(testInput);
168
+ await new Promise(resolve => setTimeout(resolve, 50));
169
+ expect(faultyCallback).toHaveBeenCalled();
170
+ expect(normalCallback).toHaveBeenCalledWith(expectedOutput);
171
+ expect(consoleErrorSpy).toHaveBeenCalledWith('Error in onGenerate callback:', expect.any(Error));
172
+ consoleErrorSpy.mockRestore();
173
+ });
174
+ it('失败的处理不应该触发回调', async () => {
175
+ const testInput = { id: 1, data: 'test' };
176
+ const callback = vi.fn();
177
+ mockProcessor = vi.fn().mockRejectedValue(new Error('Failure'));
178
+ flowQueue = new FlowQueue({ retry: { maxRetries: 0 } }, mockProcessor);
179
+ flowQueue.onGenerate(callback);
180
+ flowQueue.input(testInput);
181
+ await new Promise(resolve => setTimeout(resolve, 50));
182
+ expect(callback).not.toHaveBeenCalled();
183
+ });
184
+ });
185
+ describe('并发处理', () => {
186
+ it('应该防止并发处理', async () => {
187
+ const inputs = [
188
+ { id: 1, data: 'test1' },
189
+ { id: 2, data: 'test2' }
190
+ ];
191
+ // 模拟较慢的处理器
192
+ mockProcessor = vi.fn().mockImplementation(async (input) => {
193
+ await new Promise(resolve => setTimeout(resolve, 30));
194
+ return { id: input.id, result: `processed_${input.data}`, timestamp: Date.now() };
195
+ });
196
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
197
+ // 快速添加两个输入
198
+ flowQueue.input(inputs[0]);
199
+ flowQueue.input(inputs[1]);
200
+ await new Promise(resolve => setTimeout(resolve, 100));
201
+ // 应该按顺序处理
202
+ expect(mockProcessor).toHaveBeenCalledTimes(2);
203
+ expect(flowQueue['processedInputs'].length).toBe(2);
204
+ });
205
+ });
206
+ describe('边界情况', () => {
207
+ it('应该处理空输入', () => {
208
+ flowQueue.input();
209
+ expect(flowQueue['pendingInputs'].length).toBe(0);
210
+ });
211
+ it('应该处理 processor 返回 undefined 的情况', async () => {
212
+ const testInput = { id: 1, data: 'test' };
213
+ mockProcessor = vi.fn().mockResolvedValue(undefined);
214
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
215
+ flowQueue.input(testInput);
216
+ await new Promise(resolve => setTimeout(resolve, 50));
217
+ expect(flowQueue.successOutputs.get(testInput)).toBeUndefined();
218
+ expect(flowQueue['processedInputs']).toContain(testInput);
219
+ });
220
+ it('应该正确处理输入关闭后的新输入', () => {
221
+ const testInput = { id: 1, data: 'test' };
222
+ flowQueue.closeInput();
223
+ flowQueue.input(testInput);
224
+ // 输入关闭后新添加的输入应该被忽略
225
+ expect(flowQueue['pendingInputs'].length).toBe(0);
226
+ });
227
+ it('应该处理 processor 抛出非标准错误的情况', async () => {
228
+ const testInput = { id: 1, data: 'test' };
229
+ // 抛出 null 错误
230
+ mockProcessor = vi.fn().mockRejectedValue(null);
231
+ flowQueue = new FlowQueue({ retry: { maxRetries: 0 } }, mockProcessor);
232
+ flowQueue.input(testInput);
233
+ await new Promise(resolve => setTimeout(resolve, 50));
234
+ const errorResult = flowQueue.erroredOutputs.get(testInput);
235
+ expect(errorResult).toBe(null);
236
+ });
237
+ it('应该处理 processor 抛出 undefined 错误的情况', async () => {
238
+ const testInput = { id: 1, data: 'test' };
239
+ // 抛出 undefined 错误
240
+ mockProcessor = vi.fn().mockRejectedValue(undefined);
241
+ flowQueue = new FlowQueue({ retry: { maxRetries: 0 } }, mockProcessor);
242
+ flowQueue.input(testInput);
243
+ await new Promise(resolve => setTimeout(resolve, 50));
244
+ const errorResult = flowQueue.erroredOutputs.get(testInput);
245
+ expect(errorResult).toBe(undefined);
246
+ });
247
+ });
248
+ describe('任务间延迟配置', () => {
249
+ it('应该在任务间应用基础延迟', async () => {
250
+ const inputs = [
251
+ { id: 1, data: 'test1' },
252
+ { id: 2, data: 'test2' }
253
+ ];
254
+ const processingTimes = [];
255
+ mockProcessor = vi.fn().mockImplementation(async (input) => {
256
+ processingTimes.push(Date.now());
257
+ return { id: input.id, result: `processed_${input.data}`, timestamp: Date.now() };
258
+ });
259
+ flowQueue = new FlowQueue({
260
+ delay: { base: 100 } // 100ms 延迟
261
+ }, mockProcessor);
262
+ const startTime = Date.now();
263
+ flowQueue.input(...inputs);
264
+ await new Promise(resolve => setTimeout(resolve, 300));
265
+ expect(mockProcessor).toHaveBeenCalledTimes(2);
266
+ // 验证任务间确实有延迟
267
+ if (processingTimes.length >= 2) {
268
+ const delayBetweenTasks = processingTimes[1] - processingTimes[0];
269
+ expect(delayBetweenTasks).toBeGreaterThanOrEqual(90); // 允许一些时序误差
270
+ }
271
+ });
272
+ it('应该支持自定义延迟函数', async () => {
273
+ const inputs = [
274
+ { id: 1, data: 'test1' },
275
+ { id: 2, data: 'test2' }
276
+ ];
277
+ let customDelayCallCount = 0;
278
+ const customDelayFn = vi.fn(() => {
279
+ customDelayCallCount++;
280
+ return customDelayCallCount * 50; // 递增延迟
281
+ });
282
+ mockProcessor = vi.fn().mockImplementation(async (input) => {
283
+ return { id: input.id, result: `processed_${input.data}`, timestamp: Date.now() };
284
+ });
285
+ flowQueue = new FlowQueue({
286
+ delay: { customDelayFn }
287
+ }, mockProcessor);
288
+ flowQueue.input(...inputs);
289
+ await new Promise(resolve => setTimeout(resolve, 200));
290
+ expect(customDelayFn).toHaveBeenCalled();
291
+ expect(mockProcessor).toHaveBeenCalledTimes(2);
292
+ });
293
+ it('应该支持延迟抖动', async () => {
294
+ const inputs = [
295
+ { id: 1, data: 'test1' },
296
+ { id: 2, data: 'test2' },
297
+ { id: 3, data: 'test3' }
298
+ ];
299
+ mockProcessor = vi.fn().mockImplementation(async (input) => {
300
+ return { id: input.id, result: `processed_${input.data}`, timestamp: Date.now() };
301
+ });
302
+ flowQueue = new FlowQueue({
303
+ delay: {
304
+ base: 100,
305
+ jitter: true,
306
+ jitterRange: 0.5 // 50% 抖动范围
307
+ }
308
+ }, mockProcessor);
309
+ flowQueue.input(...inputs);
310
+ await new Promise(resolve => setTimeout(resolve, 500));
311
+ expect(mockProcessor).toHaveBeenCalledTimes(3);
312
+ // 只验证抖动功能被启用,而不验证具体的时间差
313
+ // 因为时间差可能因为系统负载等因素而变化
314
+ expect(flowQueue.successOutputs.size).toBe(3);
315
+ });
316
+ });
317
+ describe('retry 方法', () => {
318
+ it('retry() 应该返回正确的重试数量', async () => {
319
+ const inputs = [
320
+ { id: 1, data: 'test1' },
321
+ { id: 2, data: 'test2' }
322
+ ];
323
+ mockProcessor = vi.fn().mockRejectedValue(new Error('处理失败'));
324
+ flowQueue = new FlowQueue({ retry: { maxRetries: 0 } }, mockProcessor);
325
+ flowQueue.input(...inputs);
326
+ await new Promise(resolve => setTimeout(resolve, 100));
327
+ expect(flowQueue.erroredOutputs.size).toBe(2);
328
+ const retryCount = flowQueue.retry();
329
+ expect(retryCount).toBe(2);
330
+ });
331
+ it('retry() 在没有失败输入时应该返回 0', () => {
332
+ const retryCount = flowQueue.retry();
333
+ expect(retryCount).toBe(0);
334
+ });
335
+ it('retry() 应该清除重试计数', async () => {
336
+ const testInput = { id: 1, data: 'test' };
337
+ // 让处理失败以触发重试计数,但要确保达到最大重试次数
338
+ mockProcessor = vi.fn().mockRejectedValue(new Error('处理失败'));
339
+ flowQueue = new FlowQueue({ retry: { maxRetries: 2 } }, mockProcessor);
340
+ flowQueue.input(testInput);
341
+ // 等待足够长的时间,确保重试过程完成
342
+ await new Promise(resolve => setTimeout(resolve, 200));
343
+ // 验证处理失败并且有重试计数
344
+ expect(flowQueue.erroredOutputs.has(testInput)).toBe(true);
345
+ // 执行 retry() 应该清除重试计数和错误记录
346
+ flowQueue.retry();
347
+ expect(flowQueue.erroredOutputs.has(testInput)).toBe(false);
348
+ expect(flowQueue['retryCount'].has(testInput)).toBe(false);
349
+ });
350
+ it('retry() 应该保持输入关闭状态', async () => {
351
+ const testInput = { id: 1, data: 'test' };
352
+ mockProcessor = vi.fn().mockRejectedValue(new Error('处理失败'));
353
+ flowQueue = new FlowQueue({ retry: { maxRetries: 0 } }, mockProcessor);
354
+ flowQueue.input(testInput);
355
+ flowQueue.closeInput();
356
+ await new Promise(resolve => setTimeout(resolve, 100));
357
+ expect(flowQueue['isInputClosed']).toBe(true);
358
+ flowQueue.retry();
359
+ expect(flowQueue['isInputClosed']).toBe(true); // 应该保持关闭状态
360
+ });
361
+ });
362
+ describe('重试策略', () => {
363
+ describe('立即重试 (immediate)', () => {
364
+ it('应该立即重试不延迟', async () => {
365
+ const testInput = { id: 1, data: 'test' };
366
+ const successOutput = { id: 1, result: 'success', timestamp: Date.now() };
367
+ mockProcessor = vi.fn()
368
+ .mockRejectedValueOnce(new Error('First failure'))
369
+ .mockResolvedValueOnce(successOutput);
370
+ const retryRule = { strategy: 'immediate' };
371
+ flowQueue = new FlowQueue({ retry: { maxRetries: 2, ...retryRule } }, mockProcessor);
372
+ flowQueue.input(testInput);
373
+ // 等待异步处理完成
374
+ await new Promise(resolve => setTimeout(resolve, 50));
375
+ expect(mockProcessor).toHaveBeenCalledTimes(2);
376
+ expect(flowQueue.successOutputs.get(testInput)).toEqual(successOutput);
377
+ });
378
+ });
379
+ describe('延迟计算', () => {
380
+ it('固定延迟应该返回基础延迟', () => {
381
+ const retryRule = {
382
+ strategy: 'fixed',
383
+ baseDelay: 1000
384
+ };
385
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3, ...retryRule } }, mockProcessor);
386
+ expect(flowQueue['calculateRetryDelay'](0)).toBe(1000);
387
+ expect(flowQueue['calculateRetryDelay'](1)).toBe(1000);
388
+ expect(flowQueue['calculateRetryDelay'](2)).toBe(1000);
389
+ });
390
+ it('指数退避应该返回递增延迟', () => {
391
+ const retryRule = {
392
+ strategy: 'exponential',
393
+ baseDelay: 1000,
394
+ multiplier: 2
395
+ };
396
+ flowQueue = new FlowQueue({ retry: { maxRetries: 5, ...retryRule } }, mockProcessor);
397
+ expect(flowQueue['calculateRetryDelay'](0)).toBe(1000); // 1000 * 2^0 = 1000
398
+ expect(flowQueue['calculateRetryDelay'](1)).toBe(2000); // 1000 * 2^1 = 2000
399
+ expect(flowQueue['calculateRetryDelay'](2)).toBe(4000); // 1000 * 2^2 = 4000
400
+ expect(flowQueue['calculateRetryDelay'](3)).toBe(8000); // 1000 * 2^3 = 8000
401
+ });
402
+ it('指数退避应该限制最大延迟时间', () => {
403
+ const retryRule = {
404
+ strategy: 'exponential',
405
+ baseDelay: 1000,
406
+ multiplier: 2,
407
+ maxDelay: 3000 // 限制最大延迟
408
+ };
409
+ flowQueue = new FlowQueue({ retry: { maxRetries: 5, ...retryRule } }, mockProcessor);
410
+ expect(flowQueue['calculateRetryDelay'](0)).toBe(1000); // 1000 * 2^0 = 1000
411
+ expect(flowQueue['calculateRetryDelay'](1)).toBe(2000); // 1000 * 2^1 = 2000
412
+ expect(flowQueue['calculateRetryDelay'](2)).toBe(3000); // min(1000 * 2^2, 3000) = 3000
413
+ expect(flowQueue['calculateRetryDelay'](3)).toBe(3000); // min(1000 * 2^3, 3000) = 3000
414
+ });
415
+ it('线性增长应该返回线性递增延迟', () => {
416
+ const retryRule = {
417
+ strategy: 'linear',
418
+ baseDelay: 1000
419
+ };
420
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3, ...retryRule } }, mockProcessor);
421
+ expect(flowQueue['calculateRetryDelay'](0)).toBe(1000); // 1000 * (0 + 1) = 1000
422
+ expect(flowQueue['calculateRetryDelay'](1)).toBe(2000); // 1000 * (1 + 1) = 2000
423
+ expect(flowQueue['calculateRetryDelay'](2)).toBe(3000); // 1000 * (2 + 1) = 3000
424
+ });
425
+ it('自定义策略应该使用自定义延迟函数', () => {
426
+ const customDelayFn = vi.fn()
427
+ .mockReturnValueOnce(500)
428
+ .mockReturnValueOnce(1500)
429
+ .mockReturnValueOnce(2500);
430
+ const retryRule = {
431
+ strategy: 'custom',
432
+ baseDelay: 1000,
433
+ customDelayFn
434
+ };
435
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3, ...retryRule } }, mockProcessor);
436
+ expect(flowQueue['calculateRetryDelay'](0)).toBe(500);
437
+ expect(flowQueue['calculateRetryDelay'](1)).toBe(1500);
438
+ expect(flowQueue['calculateRetryDelay'](2)).toBe(2500);
439
+ expect(customDelayFn).toHaveBeenCalledWith(0, 1000);
440
+ expect(customDelayFn).toHaveBeenCalledWith(1, 1000);
441
+ expect(customDelayFn).toHaveBeenCalledWith(2, 1000);
442
+ });
443
+ it('自定义策略应该处理错误的函数', () => {
444
+ const customDelayFn = vi.fn().mockReturnValue(500);
445
+ const retryRule = {
446
+ strategy: 'custom',
447
+ baseDelay: 1000,
448
+ customDelayFn
449
+ };
450
+ flowQueue = new FlowQueue({ retry: { maxRetries: 2, ...retryRule } }, mockProcessor);
451
+ expect(flowQueue['calculateRetryDelay'](0)).toBe(500);
452
+ expect(flowQueue['calculateRetryDelay'](1)).toBe(500);
453
+ expect(customDelayFn).toHaveBeenCalledWith(0, 1000);
454
+ expect(customDelayFn).toHaveBeenCalledWith(1, 1000);
455
+ });
456
+ it('应该为延迟添加随机抖动', () => {
457
+ const retryRule = {
458
+ strategy: 'fixed',
459
+ baseDelay: 1000,
460
+ jitter: true
461
+ };
462
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3, ...retryRule } }, mockProcessor);
463
+ // 多次计算延迟,验证有抖动
464
+ const delays = Array.from({ length: 10 }, () => flowQueue['calculateRetryDelay'](0));
465
+ // 所有延迟应该在合理范围内(900-1100ms)
466
+ delays.forEach(delay => {
467
+ expect(delay).toBeGreaterThanOrEqual(900);
468
+ expect(delay).toBeLessThanOrEqual(1100);
469
+ });
470
+ // 应该有一定的变化(不是所有值都相同)
471
+ const uniqueDelays = new Set(delays);
472
+ expect(uniqueDelays.size).toBeGreaterThan(1);
473
+ });
474
+ it('不应该为零延迟添加抖动', () => {
475
+ const retryRule = {
476
+ strategy: 'immediate',
477
+ jitter: true
478
+ };
479
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3, ...retryRule } }, mockProcessor);
480
+ const delay = flowQueue['calculateRetryDelay'](0);
481
+ expect(delay).toBe(0);
482
+ });
483
+ });
484
+ describe('集成测试', () => {
485
+ it('应该使用固定延迟策略进行重试', async () => {
486
+ const testInput = { id: 1, data: 'test' };
487
+ let attemptCount = 0;
488
+ mockProcessor = vi.fn().mockImplementation(async () => {
489
+ attemptCount++;
490
+ if (attemptCount <= 2) {
491
+ throw new Error(`Attempt ${attemptCount} failed`);
492
+ }
493
+ return { id: 1, result: 'success', timestamp: Date.now() };
494
+ });
495
+ const retryRule = {
496
+ strategy: 'fixed',
497
+ baseDelay: 100 // 使用较短的延迟以加快测试
498
+ };
499
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3, ...retryRule } }, mockProcessor);
500
+ flowQueue.input(testInput);
501
+ // 等待足够时间让所有重试完成
502
+ await new Promise(resolve => setTimeout(resolve, 500));
503
+ expect(mockProcessor).toHaveBeenCalledTimes(3);
504
+ const result = flowQueue.successOutputs.get(testInput);
505
+ expect(result.result).toBe('success');
506
+ });
507
+ });
508
+ });
509
+ describe('生命周期管理', () => {
510
+ describe('closeInput 方法', () => {
511
+ it('应该标记输入为关闭状态', () => {
512
+ const testInput = { id: 1, data: 'test' };
513
+ flowQueue.input(testInput);
514
+ expect(flowQueue['isInputClosed']).toBe(false);
515
+ flowQueue.closeInput();
516
+ expect(flowQueue['isInputClosed']).toBe(true);
517
+ });
518
+ it('在没有待处理输入时应该立即解决完成 Promise', async () => {
519
+ flowQueue.closeInput();
520
+ const completionPromise = flowQueue.awaitCompletion();
521
+ await expect(completionPromise).resolves.toBeUndefined();
522
+ });
523
+ it('在有待处理输入时应该等待处理完成', async () => {
524
+ const testInput = { id: 1, data: 'test' };
525
+ const expectedOutput = { id: 1, result: 'success', timestamp: Date.now() };
526
+ mockProcessor = vi.fn().mockImplementation(async () => {
527
+ await new Promise(resolve => setTimeout(resolve, 50));
528
+ return expectedOutput;
529
+ });
530
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
531
+ flowQueue.input(testInput);
532
+ flowQueue.closeInput();
533
+ const completionPromise = flowQueue.awaitCompletion();
534
+ await expect(completionPromise).resolves.toBeUndefined();
535
+ expect(flowQueue.successOutputs.get(testInput)).toEqual(expectedOutput);
536
+ });
537
+ });
538
+ describe('awaitCompletion 方法', () => {
539
+ it('在已完成状态下应该立即返回 resolved Promise', async () => {
540
+ flowQueue.closeInput();
541
+ const promise = flowQueue.awaitCompletion();
542
+ await expect(promise).resolves.toBeUndefined();
543
+ });
544
+ it('多次调用应该返回同一个 Promise', () => {
545
+ const testInput = { id: 1, data: 'test' };
546
+ flowQueue.input(testInput);
547
+ flowQueue.closeInput();
548
+ const promise1 = flowQueue.awaitCompletion();
549
+ const promise2 = flowQueue.awaitCompletion();
550
+ expect(promise1).toBe(promise2);
551
+ });
552
+ it('应该等待所有输入处理完成', async () => {
553
+ const inputs = [
554
+ { id: 1, data: 'test1' },
555
+ { id: 2, data: 'test2' },
556
+ { id: 3, data: 'test3' }
557
+ ];
558
+ mockProcessor = vi.fn().mockImplementation(async (input) => {
559
+ await new Promise(resolve => setTimeout(resolve, 30));
560
+ return { id: input.id, result: `processed_${input.data}`, timestamp: Date.now() };
561
+ });
562
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
563
+ flowQueue.input(...inputs);
564
+ flowQueue.closeInput();
565
+ const startTime = Date.now();
566
+ await flowQueue.awaitCompletion();
567
+ const endTime = Date.now();
568
+ expect(endTime - startTime).toBeGreaterThanOrEqual(80); // 至少处理了3个输入
569
+ expect(flowQueue['processedInputs'].length).toBe(3);
570
+ expect(flowQueue['pendingInputs'].length).toBe(0);
571
+ });
572
+ });
573
+ describe('isCompleted 属性', () => {
574
+ it('初始状态应该为 false', () => {
575
+ expect(flowQueue.isCompleted).toBe(false);
576
+ });
577
+ it('只调用 closeInput 但有待处理输入时应该为 false', () => {
578
+ const testInput = { id: 1, data: 'test' };
579
+ flowQueue.input(testInput);
580
+ flowQueue.closeInput();
581
+ expect(flowQueue.isCompleted).toBe(false);
582
+ });
583
+ it('调用 closeInput 且没有待处理输入时应该为 true', () => {
584
+ flowQueue.closeInput();
585
+ expect(flowQueue.isCompleted).toBe(true);
586
+ });
587
+ it('处理完所有输入后应该为 true', async () => {
588
+ const testInput = { id: 1, data: 'test' };
589
+ const expectedOutput = { id: 1, result: 'success', timestamp: Date.now() };
590
+ mockProcessor = vi.fn().mockResolvedValue(expectedOutput);
591
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
592
+ flowQueue.input(testInput);
593
+ flowQueue.closeInput();
594
+ await flowQueue.awaitCompletion();
595
+ expect(flowQueue.isCompleted).toBe(true);
596
+ });
597
+ it('在处理过程中应该为 false', async () => {
598
+ const testInput = { id: 1, data: 'test' };
599
+ mockProcessor = vi.fn().mockImplementation(async () => {
600
+ expect(flowQueue.isCompleted).toBe(false); // 处理过程中应该为 false
601
+ await new Promise(resolve => setTimeout(resolve, 50));
602
+ return { id: 1, result: 'success', timestamp: Date.now() };
603
+ });
604
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
605
+ flowQueue.input(testInput);
606
+ flowQueue.closeInput();
607
+ await flowQueue.awaitCompletion();
608
+ expect(flowQueue.isCompleted).toBe(true);
609
+ });
610
+ });
611
+ describe('cancel 方法', () => {
612
+ it('应该清除待处理的输入', async () => {
613
+ const inputs = [
614
+ { id: 1, data: 'test1' },
615
+ { id: 2, data: 'test2' },
616
+ { id: 3, data: 'test3' }
617
+ ];
618
+ // 使用慢速处理器确保输入还在队列中
619
+ mockProcessor = vi.fn().mockImplementation(async () => {
620
+ await new Promise(resolve => setTimeout(resolve, 100));
621
+ return { id: 1, result: 'test', timestamp: Date.now() };
622
+ });
623
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
624
+ flowQueue.input(...inputs);
625
+ // 立即取消,此时可能第一个已经开始处理,但后续的应该还在队列中
626
+ flowQueue.cancel();
627
+ expect(flowQueue['pendingInputs'].length).toBe(0);
628
+ });
629
+ it('应该清除重试计数', () => {
630
+ const testInput = { id: 1, data: 'test' };
631
+ // 手动设置重试计数来模拟重试状态
632
+ flowQueue['retryCount'].set(testInput, 2);
633
+ expect(flowQueue['retryCount'].has(testInput)).toBe(true);
634
+ flowQueue.cancel();
635
+ expect(flowQueue['retryCount'].has(testInput)).toBe(false);
636
+ });
637
+ it('应该标记为完成状态', async () => {
638
+ const testInput = { id: 1, data: 'test' };
639
+ flowQueue.input(testInput);
640
+ expect(flowQueue.isCompleted).toBe(false);
641
+ // 立即取消,这时队列应该立即变为完成状态
642
+ flowQueue.cancel();
643
+ // 等待一个短暂的时间确保取消操作完成
644
+ await new Promise(resolve => setTimeout(resolve, 10));
645
+ expect(flowQueue.isCompleted).toBe(true);
646
+ expect(flowQueue['isInputClosed']).toBe(true);
647
+ });
648
+ it('应该立即解决完成 Promise', async () => {
649
+ const testInput = { id: 1, data: 'test' };
650
+ flowQueue.input(testInput);
651
+ const completionPromise = flowQueue.awaitCompletion();
652
+ flowQueue.cancel();
653
+ await expect(completionPromise).resolves.toBeUndefined();
654
+ });
655
+ });
656
+ describe('reset 方法', () => {
657
+ it('应该清空所有数据状态', async () => {
658
+ const inputs = [
659
+ { id: 1, data: 'test1' },
660
+ { id: 2, data: 'test2' }
661
+ ];
662
+ mockProcessor = vi.fn().mockImplementation(async (input) => {
663
+ return { id: input.id, result: `processed_${input.data}`, timestamp: Date.now() };
664
+ });
665
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
666
+ // 添加输入并处理
667
+ flowQueue.input(...inputs);
668
+ await new Promise(resolve => setTimeout(resolve, 100));
669
+ // 验证有数据
670
+ expect(flowQueue['processedInputs'].length).toBeGreaterThan(0);
671
+ expect(flowQueue.successOutputs.size).toBeGreaterThan(0);
672
+ // 重置
673
+ flowQueue.reset();
674
+ // 验证所有数据被清空
675
+ expect(flowQueue['pendingInputs'].length).toBe(0);
676
+ expect(flowQueue['processedInputs'].length).toBe(0);
677
+ expect(flowQueue.successOutputs.size).toBe(0);
678
+ expect(flowQueue['retryCount'].size).toBe(0);
679
+ expect(flowQueue['isProcessing']).toBe(false);
680
+ expect(flowQueue['isInputClosed']).toBe(false);
681
+ expect(flowQueue['completionPromise']).toBe(null);
682
+ expect(flowQueue['completionResolve']).toBe(null);
683
+ });
684
+ it('重置后应该能重新开始处理', async () => {
685
+ const firstInput = { id: 1, data: 'first' };
686
+ const secondInput = { id: 2, data: 'second' };
687
+ mockProcessor = vi.fn().mockImplementation(async (input) => {
688
+ return { id: input.id, result: `processed_${input.data}`, timestamp: Date.now() };
689
+ });
690
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
691
+ // 第一轮处理
692
+ flowQueue.input(firstInput);
693
+ flowQueue.closeInput();
694
+ await flowQueue.awaitCompletion();
695
+ expect(flowQueue.isCompleted).toBe(true);
696
+ expect(flowQueue.successOutputs.size).toBe(1);
697
+ // 重置
698
+ flowQueue.reset();
699
+ // 第二轮处理
700
+ flowQueue.input(secondInput);
701
+ flowQueue.closeInput();
702
+ await flowQueue.awaitCompletion();
703
+ expect(flowQueue.isCompleted).toBe(true);
704
+ expect(flowQueue.successOutputs.size).toBe(1); // 只有第二轮的结果
705
+ expect(flowQueue.successOutputs.has(firstInput)).toBe(false); // 第一轮的结果被清除
706
+ expect(flowQueue.successOutputs.has(secondInput)).toBe(true); // 第二轮的结果存在
707
+ });
708
+ it('应该解决待解决的完成 Promise', async () => {
709
+ const testInput = { id: 1, data: 'test' };
710
+ // 使用慢速处理器
711
+ mockProcessor = vi.fn().mockImplementation(async () => {
712
+ await new Promise(resolve => setTimeout(resolve, 100));
713
+ return { id: 1, result: 'test', timestamp: Date.now() };
714
+ });
715
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
716
+ flowQueue.input(testInput);
717
+ flowQueue.closeInput();
718
+ const completionPromise = flowQueue.awaitCompletion();
719
+ // 立即重置,应该解决 Promise
720
+ flowQueue.reset();
721
+ await expect(completionPromise).resolves.toBeUndefined();
722
+ });
723
+ });
724
+ });
725
+ describe('两个 FlowQueue 结合使用场景', () => {
726
+ let firstQueue;
727
+ let secondQueue;
728
+ let firstProcessor;
729
+ let secondProcessor;
730
+ beforeEach(() => {
731
+ firstProcessor = vi.fn();
732
+ secondProcessor = vi.fn();
733
+ firstQueue = new FlowQueue({ retry: { maxRetries: 2 } }, firstProcessor);
734
+ secondQueue = new FlowQueue({ retry: { maxRetries: 2 } }, secondProcessor);
735
+ });
736
+ it('应该实现流水线处理:第一个队列的输出作为第二个队列的输入', async () => {
737
+ const inputs = [
738
+ { id: 1, data: 'test1' },
739
+ { id: 2, data: 'test2' },
740
+ { id: 3, data: 'test3' }
741
+ ];
742
+ // 第一个处理器:转换数据
743
+ firstProcessor = vi.fn().mockImplementation(async (input) => {
744
+ await new Promise(resolve => setTimeout(resolve, 20));
745
+ return {
746
+ id: input.id,
747
+ result: `processed_${input.data}`,
748
+ timestamp: Date.now()
749
+ };
750
+ });
751
+ // 第二个处理器:进一步处理
752
+ secondProcessor = vi.fn().mockImplementation(async (input) => {
753
+ await new Promise(resolve => setTimeout(resolve, 20));
754
+ return {
755
+ id: input.id,
756
+ finalResult: `final_${input.result}`,
757
+ processedAt: Date.now()
758
+ };
759
+ });
760
+ firstQueue = new FlowQueue({ retry: { maxRetries: 2 } }, firstProcessor);
761
+ secondQueue = new FlowQueue({ retry: { maxRetries: 2 } }, secondProcessor);
762
+ // 设置第一个队列的输出回调,将结果传递给第二个队列
763
+ firstQueue.onGenerate((output) => {
764
+ secondQueue.input(output);
765
+ });
766
+ // 开始处理
767
+ firstQueue.input(...inputs);
768
+ firstQueue.closeInput();
769
+ // 等待第一个队列完成
770
+ await firstQueue.awaitCompletion();
771
+ // 关闭第二个队列的输入
772
+ secondQueue.closeInput();
773
+ // 等待第二个队列完成
774
+ await secondQueue.awaitCompletion();
775
+ // 验证处理结果
776
+ expect(firstQueue.isCompleted).toBe(true);
777
+ expect(secondQueue.isCompleted).toBe(true);
778
+ expect(firstProcessor).toHaveBeenCalledTimes(3);
779
+ expect(secondProcessor).toHaveBeenCalledTimes(3);
780
+ // 验证数据流转
781
+ inputs.forEach(input => {
782
+ const firstOutput = firstQueue.successOutputs.get(input);
783
+ expect(firstOutput.result).toBe(`processed_${input.data}`);
784
+ const secondOutput = secondQueue.successOutputs.get(firstOutput);
785
+ expect(secondOutput).toBeDefined();
786
+ expect(secondOutput.finalResult).toBe(`final_processed_${input.data}`);
787
+ });
788
+ });
789
+ it('应该处理并行处理场景:两个队列同时处理相同输入', async () => {
790
+ const inputs = [
791
+ { id: 1, data: 'test1' },
792
+ { id: 2, data: 'test2' }
793
+ ];
794
+ // 第一个处理器:快速处理
795
+ firstProcessor = vi.fn().mockImplementation(async (input) => {
796
+ await new Promise(resolve => setTimeout(resolve, 10));
797
+ return {
798
+ id: input.id,
799
+ result: `fast_${input.data}`,
800
+ timestamp: Date.now()
801
+ };
802
+ });
803
+ // 第二个处理器:慢速处理
804
+ const slowProcessor = vi.fn().mockImplementation(async (input) => {
805
+ await new Promise(resolve => setTimeout(resolve, 50));
806
+ return {
807
+ id: input.id,
808
+ result: `slow_${input.data}`,
809
+ timestamp: Date.now()
810
+ };
811
+ });
812
+ firstQueue = new FlowQueue({ retry: { maxRetries: 2 } }, firstProcessor);
813
+ const slowQueue = new FlowQueue({ retry: { maxRetries: 2 } }, slowProcessor);
814
+ // 同时向两个队列添加相同输入
815
+ firstQueue.input(...inputs);
816
+ slowQueue.input(...inputs);
817
+ firstQueue.closeInput();
818
+ slowQueue.closeInput();
819
+ // 等待两个队列都完成
820
+ await Promise.all([
821
+ firstQueue.awaitCompletion(),
822
+ slowQueue.awaitCompletion()
823
+ ]);
824
+ // 验证两个队列都完成了处理
825
+ expect(firstQueue.isCompleted).toBe(true);
826
+ expect(slowQueue.isCompleted).toBe(true);
827
+ // 验证处理结果
828
+ inputs.forEach(input => {
829
+ const fastOutput = firstQueue.successOutputs.get(input);
830
+ const slowOutput = slowQueue.successOutputs.get(input);
831
+ expect(fastOutput.result).toBe(`fast_${input.data}`);
832
+ expect(slowOutput.result).toBe(`slow_${input.data}`);
833
+ });
834
+ });
835
+ it('应该处理错误传播场景:第一个队列的错误不影响第二个队列', async () => {
836
+ const inputs = [
837
+ { id: 1, data: 'success' },
838
+ { id: 2, data: 'fail' },
839
+ { id: 3, data: 'success' }
840
+ ];
841
+ // 第一个处理器:部分失败
842
+ firstProcessor = vi.fn().mockImplementation(async (input) => {
843
+ if (input.data === 'fail') {
844
+ throw new Error('Processing failed');
845
+ }
846
+ return {
847
+ id: input.id,
848
+ result: `processed_${input.data}`,
849
+ timestamp: Date.now()
850
+ };
851
+ });
852
+ // 第二个处理器:正常处理
853
+ secondProcessor = vi.fn().mockImplementation(async (input) => {
854
+ return {
855
+ id: input.id,
856
+ finalResult: `final_${input.result}`,
857
+ processedAt: Date.now()
858
+ };
859
+ });
860
+ firstQueue = new FlowQueue({ retry: { maxRetries: 1 } }, firstProcessor);
861
+ secondQueue = new FlowQueue({ retry: { maxRetries: 1 } }, secondProcessor);
862
+ // 只有成功的输出才传递给第二个队列
863
+ firstQueue.onGenerate((output) => {
864
+ secondQueue.input(output);
865
+ });
866
+ firstQueue.input(...inputs);
867
+ firstQueue.closeInput();
868
+ await firstQueue.awaitCompletion();
869
+ secondQueue.closeInput();
870
+ await secondQueue.awaitCompletion();
871
+ // 验证第一个队列有一个错误
872
+ const failedInput = inputs.find(i => i.data === 'fail');
873
+ const failedResult = firstQueue.erroredOutputs.get(failedInput);
874
+ expect(failedResult).toBeInstanceOf(Error);
875
+ expect(failedResult.message).toBe('Processing failed');
876
+ // 验证第二个队列只处理了成功的输出
877
+ expect(firstProcessor).toHaveBeenCalledTimes(4); // 3次初始 + 1次重试
878
+ expect(secondProcessor).toHaveBeenCalledTimes(2); // 只有2个成功的输出
879
+ expect(secondQueue.isCompleted).toBe(true);
880
+ });
881
+ it('应该支持条件分发:根据第一个队列的结果决定后续处理', async () => {
882
+ const inputs = [
883
+ { id: 1, data: 'priority_high' },
884
+ { id: 2, data: 'priority_low' },
885
+ { id: 3, data: 'priority_high' },
886
+ { id: 4, data: 'priority_medium' }
887
+ ];
888
+ firstProcessor = vi.fn().mockImplementation(async (input) => {
889
+ return {
890
+ id: input.id,
891
+ result: input.data,
892
+ timestamp: Date.now()
893
+ };
894
+ });
895
+ secondProcessor = vi.fn().mockImplementation(async (input) => {
896
+ return {
897
+ id: input.id,
898
+ finalResult: `high_priority_${input.result}`,
899
+ processedAt: Date.now()
900
+ };
901
+ });
902
+ const lowPriorityProcessor = vi.fn().mockImplementation(async (input) => {
903
+ return {
904
+ id: input.id,
905
+ finalResult: `low_priority_${input.result}`,
906
+ processedAt: Date.now()
907
+ };
908
+ });
909
+ firstQueue = new FlowQueue({ retry: { maxRetries: 2 } }, firstProcessor);
910
+ const highPriorityQueue = new FlowQueue({ retry: { maxRetries: 2 } }, secondProcessor);
911
+ const lowPriorityQueue = new FlowQueue({ retry: { maxRetries: 2 } }, lowPriorityProcessor); // 根据结果条件分发
912
+ firstQueue.onGenerate((output) => {
913
+ if (output.result.includes('high')) {
914
+ highPriorityQueue.input(output);
915
+ }
916
+ else {
917
+ lowPriorityQueue.input(output);
918
+ }
919
+ });
920
+ firstQueue.input(...inputs);
921
+ firstQueue.closeInput();
922
+ await firstQueue.awaitCompletion();
923
+ highPriorityQueue.closeInput();
924
+ lowPriorityQueue.closeInput();
925
+ await Promise.all([
926
+ highPriorityQueue.awaitCompletion(),
927
+ lowPriorityQueue.awaitCompletion()
928
+ ]);
929
+ // 验证分发逻辑
930
+ expect(secondProcessor).toHaveBeenCalledTimes(2); // 2个高优先级
931
+ expect(lowPriorityProcessor).toHaveBeenCalledTimes(2); // 2个非高优先级
932
+ // 验证所有队列都完成
933
+ expect(firstQueue.isCompleted).toBe(true);
934
+ expect(highPriorityQueue.isCompleted).toBe(true);
935
+ expect(lowPriorityQueue.isCompleted).toBe(true);
936
+ });
937
+ it('应该处理级联取消场景:取消第一个队列时自动取消后续队列', async () => {
938
+ const inputs = [
939
+ { id: 1, data: 'test1' },
940
+ { id: 2, data: 'test2' },
941
+ { id: 3, data: 'test3' },
942
+ { id: 4, data: 'test4' },
943
+ { id: 5, data: 'test5' }
944
+ ];
945
+ firstProcessor = vi.fn().mockImplementation(async (input) => {
946
+ await new Promise(resolve => setTimeout(resolve, 30));
947
+ return {
948
+ id: input.id,
949
+ result: `processed_${input.data}`,
950
+ timestamp: Date.now()
951
+ };
952
+ });
953
+ secondProcessor = vi.fn().mockImplementation(async (input) => {
954
+ await new Promise(resolve => setTimeout(resolve, 30));
955
+ return {
956
+ id: input.id,
957
+ finalResult: `final_${input.result}`,
958
+ processedAt: Date.now()
959
+ };
960
+ });
961
+ firstQueue = new FlowQueue({ retry: { maxRetries: 2 } }, firstProcessor);
962
+ secondQueue = new FlowQueue({ retry: { maxRetries: 2 } }, secondProcessor);
963
+ let cancelSecondQueue = false;
964
+ firstQueue.onGenerate((output) => {
965
+ if (!cancelSecondQueue) {
966
+ secondQueue.input(output);
967
+ }
968
+ });
969
+ firstQueue.input(...inputs);
970
+ // 等待一些处理开始
971
+ await new Promise(resolve => setTimeout(resolve, 50));
972
+ // 取消第一个队列,并标记不再向第二个队列添加输入
973
+ cancelSecondQueue = true;
974
+ firstQueue.cancel();
975
+ secondQueue.cancel();
976
+ // 等待取消操作完成和所有异步操作结束
977
+ await Promise.all([
978
+ firstQueue.awaitCompletion(),
979
+ secondQueue.awaitCompletion()
980
+ ]);
981
+ // 验证取消状态
982
+ expect(firstQueue.isCompleted).toBe(true);
983
+ expect(secondQueue.isCompleted).toBe(true);
984
+ expect(firstQueue['pendingInputs'].length).toBe(0);
985
+ expect(secondQueue['pendingInputs'].length).toBe(0);
986
+ // 等待确保没有更多处理
987
+ await new Promise(resolve => setTimeout(resolve, 50));
988
+ // 验证处理被中断 - 由于异步操作的时序不确定性,我们只验证处理确实被中断了
989
+ const firstCallCount = firstProcessor.mock.calls.length;
990
+ const secondCallCount = secondProcessor.mock.calls.length;
991
+ // 主要验证:处理次数应该少于总输入数,说明确实被取消了
992
+ expect(firstCallCount).toBeLessThan(inputs.length);
993
+ expect(secondCallCount).toBeLessThan(inputs.length);
994
+ });
995
+ it('应该支持重置功能', async () => {
996
+ const inputs = [
997
+ { id: 1, data: 'success' },
998
+ { id: 2, data: 'success' },
999
+ { id: 3, data: 'success' }
1000
+ ];
1001
+ // 第一次处理器
1002
+ firstProcessor = vi.fn().mockImplementation(async (input) => {
1003
+ return {
1004
+ id: input.id,
1005
+ result: `processed_${input.data}`,
1006
+ timestamp: Date.now()
1007
+ };
1008
+ });
1009
+ firstQueue = new FlowQueue({ retry: { maxRetries: 0 } }, firstProcessor);
1010
+ // 第一轮处理
1011
+ firstQueue.input(...inputs);
1012
+ await new Promise(resolve => setTimeout(resolve, 100));
1013
+ // 验证处理结果
1014
+ expect(firstQueue.successOutputs.size).toBe(3);
1015
+ // 测试重置功能
1016
+ firstQueue.reset();
1017
+ expect(firstQueue.successOutputs.size).toBe(0);
1018
+ expect(firstQueue['processedInputs'].length).toBe(0);
1019
+ expect(firstQueue.isCompleted).toBe(false);
1020
+ // 重置后重新处理
1021
+ firstQueue.input(...inputs);
1022
+ firstQueue.closeInput();
1023
+ await firstQueue.awaitCompletion();
1024
+ // 验证重置后的处理结果
1025
+ expect(firstQueue.successOutputs.size).toBe(3);
1026
+ expect(firstQueue.isCompleted).toBe(true);
1027
+ inputs.forEach(input => {
1028
+ const output = firstQueue.successOutputs.get(input);
1029
+ expect(output.result).toBe(`processed_${input.data}`);
1030
+ });
1031
+ });
1032
+ });
1033
+ });