Skip to content

Commit ed3a873

Browse files
committed
test_runner: implement PriorityQueue for timers
Signed-off-by: Erick Wendel <[email protected]>
1 parent e54a162 commit ed3a873

File tree

2 files changed

+59
-30
lines changed

2 files changed

+59
-30
lines changed

lib/internal/test_runner/mock/fake_timers.js

+46-17
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,32 @@
33
const {
44
DateNow,
55
SafeMap,
6-
Symbol,
6+
SafeSet,
77
globalThis,
88
} = primordials;
99

10+
const console = require('console')
11+
const PriorityQueue = require('internal/priority_queue');
12+
13+
function compareTimersLists(a, b) {
14+
// console.log({ a, b})
15+
const expiryDiff = a.runAt - b.runAt;
16+
if (expiryDiff === 0) {
17+
if (a.id < b.id)
18+
return -1;
19+
if (a.id > b.id)
20+
return 1;
21+
}
22+
return expiryDiff;
23+
}
24+
25+
function setPosition(node, pos) {
26+
node.priorityQueuePosition = pos;
27+
}
1028
class Timers {
29+
#currentTimer = 1;
1130
constructor() {
12-
this.timers = new SafeMap();
31+
this.timers = new PriorityQueue(compareTimersLists, setPosition);
1332

1433
this.setTimeout = this.#createTimer.bind(this, false);
1534
this.clearTimeout = this.#clearTimer.bind(this);
@@ -18,20 +37,20 @@ class Timers {
1837
}
1938

2039
#createTimer(isInterval, callback, delay, ...args) {
21-
const timerId = Symbol('kTimerId');
22-
const timer = {
40+
const timerId = this.#currentTimer ++;
41+
this.timers.insert({
2342
id: timerId,
2443
callback,
2544
runAt: DateNow() + delay,
2645
interval: isInterval,
2746
args,
28-
};
29-
this.timers.set(timerId, timer);
47+
});
48+
3049
return timerId;
3150
}
3251

33-
#clearTimer(timerId) {
34-
this.timers.delete(timerId);
52+
#clearTimer(position) {
53+
this.timers.removeAt(position);
3554
}
3655

3756
}
@@ -49,25 +68,34 @@ class FakeTimers {
4968
}
5069

5170
tick(time = 0) {
52-
71+
5372
// if (!this.isEnabled) {
5473
// throw new Error('you should enable fakeTimers first by calling the .enable function');
5574
// }
5675

5776
this.now += time;
5877
const timers = this.fakeTimers.timers;
78+
const alreadyProcessed = new SafeSet();
79+
while (true) {
80+
const timer = timers.peek();
81+
82+
if(!timer) {
83+
alreadyProcessed.clear();
84+
break;
85+
}
5986

60-
for (const timer of timers.values()) {
87+
if(alreadyProcessed.has(timer)) break;
88+
alreadyProcessed.add(timer);
6189

6290
if (!(this.now >= timer.runAt)) continue;
63-
6491
timer.callback(...timer.args);
65-
if (timer.interval) {
66-
timer.runAt = this.now + (timer.runAt - this.now) % timer.args[0];
67-
continue;
68-
}
69-
70-
timers.delete(timer.id);
92+
93+
// if (timer.interval) {
94+
// timer.runAt = this.now + (timer.runAt - this.now) % timer.args[0];
95+
// continue;
96+
// }
97+
98+
timers.removeAt(alreadyProcessed.size - 1);
7199
}
72100
}
73101

@@ -89,6 +117,7 @@ class FakeTimers {
89117
globalThis.setInterval = this.fakeTimers.setInterval;
90118
globalThis.clearInterval = this.fakeTimers.clearInterval;
91119

120+
// this.#dispatchPendingTimers()
92121
}
93122

94123
reset() {

test/parallel/test-runner-mocking-fake-timers.js

+13-13
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,26 @@ describe('Faketimers Test Suite', () => {
2323
});
2424

2525
it('should advance in time and trigger timers when calling the .tick function multiple times', (t) => {
26-
fakeTimers.enable();
27-
const fn = mock.fn();
26+
t.mock.fakeTimers.enable();
27+
const fn = t.mock.fn();
2828

2929
global.setTimeout(fn, 2000);
3030

31-
fakeTimers.tick(1000);
32-
fakeTimers.tick(1000);
31+
t.mock.fakeTimers.tick(1000);
32+
t.mock.fakeTimers.tick(1000);
3333

3434
assert.strictEqual(fn.mock.callCount(), 1);
3535
});
3636

37-
it('should keep setTimeout working if fakeTimers are disabled', (t, done) => {
38-
const now = Date.now();
39-
const timeout = 2;
40-
const expected = () => now - timeout;
41-
global.setTimeout(common.mustCall(() => {
42-
assert.strictEqual(now - timeout, expected());
43-
done();
44-
}), timeout);
45-
});
37+
// it('should keep setTimeout working if fakeTimers are disabled', (t, done) => {
38+
// const now = Date.now();
39+
// const timeout = 2;
40+
// const expected = () => now - timeout;
41+
// global.setTimeout(common.mustCall(() => {
42+
// assert.strictEqual(now - timeout, expected());
43+
// done();
44+
// }), timeout);
45+
// });
4646

4747
});
4848
});

0 commit comments

Comments
 (0)