Skip to content

Commit

Permalink
test_runner: implement PriorityQueue for timers
Browse files Browse the repository at this point in the history
Signed-off-by: Erick Wendel <erick.workspace@gmail.com>
  • Loading branch information
ErickWendel committed May 1, 2023
1 parent e54a162 commit 71ffd10
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 20 deletions.
58 changes: 42 additions & 16 deletions lib/internal/test_runner/mock/fake_timers.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,30 @@

const {
DateNow,
SafeMap,
Symbol,
SafeSet,
globalThis,
} = primordials;

const PriorityQueue = require('internal/priority_queue');

function compareTimersLists(a, b) {
const expiryDiff = a.runAt - b.runAt;
if (expiryDiff === 0) {
if (a.id < b.id)
return -1;
if (a.id > b.id)
return 1;
}
return expiryDiff;
}

function setPosition(node, pos) {
node.priorityQueuePosition = pos;
}
class Timers {
#currentTimer = 1;
constructor() {
this.timers = new SafeMap();
this.timers = new PriorityQueue(compareTimersLists, setPosition);

this.setTimeout = this.#createTimer.bind(this, false);
this.clearTimeout = this.#clearTimer.bind(this);
Expand All @@ -18,20 +34,20 @@ class Timers {
}

#createTimer(isInterval, callback, delay, ...args) {
const timerId = Symbol('kTimerId');
const timer = {
const timerId = this.#currentTimer++;
this.timers.insert({
id: timerId,
callback,
runAt: DateNow() + delay,
interval: isInterval,
args,
};
this.timers.set(timerId, timer);
});

return timerId;
}

#clearTimer(timerId) {
this.timers.delete(timerId);
#clearTimer(position) {
this.timers.removeAt(position);
}

}
Expand All @@ -56,18 +72,27 @@ class FakeTimers {

this.now += time;
const timers = this.fakeTimers.timers;
const alreadyProcessed = new SafeSet();
while (true) {
const timer = timers.peek();

for (const timer of timers.values()) {
if (!timer) {
alreadyProcessed.clear();
break;
}

if (!(this.now >= timer.runAt)) continue;
if (alreadyProcessed.has(timer)) break;
alreadyProcessed.add(timer);

if (!(this.now >= timer.runAt)) continue;
timer.callback(...timer.args);
if (timer.interval) {
timer.runAt = this.now + (timer.runAt - this.now) % timer.args[0];
continue;
}

timers.delete(timer.id);
// if (timer.interval) {
// timer.runAt = this.now + (timer.runAt - this.now) % timer.args[0];
// continue;
// }

timers.removeAt(alreadyProcessed.size - 1);
}
}

Expand All @@ -89,6 +114,7 @@ class FakeTimers {
globalThis.setInterval = this.fakeTimers.setInterval;
globalThis.clearInterval = this.fakeTimers.clearInterval;

// this.#dispatchPendingTimers()
}

reset() {
Expand Down
8 changes: 4 additions & 4 deletions test/parallel/test-runner-mocking-fake-timers.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ describe('Faketimers Test Suite', () => {
});

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

global.setTimeout(fn, 2000);

fakeTimers.tick(1000);
fakeTimers.tick(1000);
t.mock.fakeTimers.tick(1000);
t.mock.fakeTimers.tick(1000);

assert.strictEqual(fn.mock.callCount(), 1);
});
Expand Down

0 comments on commit 71ffd10

Please sign in to comment.