command-queue.test.js
3.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/**
* Unit Tests — engine/command-queue.js
*/
import { describe, it, expect } from 'vitest';
const { CommandQueue, CommandLaneClearedError } = require('../../src/engine/command-queue');
describe('CommandQueue', () => {
describe('basic enqueue', () => {
it('should execute a simple task', async () => {
const q = new CommandQueue();
const result = await q.enqueue('main', async () => 42);
expect(result).toBe(42);
});
it('should execute tasks in order within a lane', async () => {
const q = new CommandQueue();
const order = [];
await Promise.all([
q.enqueue('main', async () => { order.push(1); }),
q.enqueue('main', async () => { order.push(2); }),
q.enqueue('main', async () => { order.push(3); }),
]);
expect(order).toEqual([1, 2, 3]);
});
it('should run different lanes in parallel', async () => {
const q = new CommandQueue();
const results = [];
await Promise.all([
q.enqueue('A', async () => { results.push('A'); }),
q.enqueue('B', async () => { results.push('B'); }),
]);
expect(results).toContain('A');
expect(results).toContain('B');
});
});
describe('clearAll', () => {
it('should increment generation', () => {
const q = new CommandQueue();
const gen0 = q.generation;
q.clearAll();
expect(q.generation).toBe(gen0 + 1);
});
it('should reject queued tasks with CommandLaneClearedError', async () => {
const q = new CommandQueue();
// Enqueue a slow task to block the lane
q.enqueue('main', () => new Promise(r => setTimeout(r, 200)));
// Queue another behind it
const p = q.enqueue('main', async () => 'should not run');
// Clear immediately
q.clearAll();
await expect(p).rejects.toThrow(CommandLaneClearedError);
});
});
describe('clearLane', () => {
it('should clear a specific lane', () => {
const q = new CommandQueue();
q.enqueue('A', async () => {});
q.clearLane('A');
expect(q.size).toBe(0);
});
});
describe('size', () => {
it('should reflect active lane count', async () => {
const q = new CommandQueue();
expect(q.size).toBe(0);
const p = q.enqueue('lane1', () => new Promise(r => setTimeout(r, 100)));
expect(q.size).toBe(1);
await p;
});
});
describe('CommandLaneClearedError', () => {
it('should be an Error subclass', () => {
const err = new CommandLaneClearedError('test');
expect(err).toBeInstanceOf(Error);
expect(err.name).toBe('CommandLaneClearedError');
expect(err.lane).toBe('test');
});
it('should work without lane name', () => {
const err = new CommandLaneClearedError();
expect(err.message).toContain('cleared');
});
});
describe('error handling in tasks', () => {
it('should propagate task errors', async () => {
const q = new CommandQueue();
await expect(
q.enqueue('main', async () => { throw new Error('task failed'); })
).rejects.toThrow('task failed');
});
it('should continue lane after a failed task', async () => {
const q = new CommandQueue();
try {
await q.enqueue('main', async () => { throw new Error('fail'); });
} catch {}
// Next task should still work
const result = await q.enqueue('main', async () => 'ok');
expect(result).toBe('ok');
});
});
});