From 22fbdd3f06222187511504001a984c6ada8ac6d5 Mon Sep 17 00:00:00 2001 From: Mika Fischer Date: Wed, 25 Oct 2023 09:52:39 +0200 Subject: [PATCH] test_runner: fix incorrect cleanup of timers Removal of mocket timers from the priority queue was broken. It used the timerId instead of the position in the queue as index. This lead to removal of incorrect timers from the queue causing timers not to be scheduled at all. Also, aborts caused removal from the queue even when the timer was already triggered, and thus no longer present in the queue. Fixes: https://github.com/nodejs/node/issues/50365 --- lib/internal/test_runner/mock/mock_timers.js | 24 ++++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/lib/internal/test_runner/mock/mock_timers.js b/lib/internal/test_runner/mock/mock_timers.js index 407a671eda7a8c..85512cc4b66a51 100644 --- a/lib/internal/test_runner/mock/mock_timers.js +++ b/lib/internal/test_runner/mock/mock_timers.js @@ -260,20 +260,23 @@ class MockTimers { #createTimer(isInterval, callback, delay, ...args) { const timerId = this.#currentTimer++; - this.#executionQueue.insert({ + const timer = { __proto__: null, id: timerId, callback, runAt: this.#now + delay, interval: isInterval ? delay : undefined, args, - }); - - return timerId; + }; + this.#executionQueue.insert(timer); + return timer; } - #clearTimer(position) { - this.#executionQueue.removeAt(position); + #clearTimer(timer) { + if (timer.priorityQueuePosition !== undefined) { + this.#executionQueue.removeAt(timer.priorityQueuePosition); + timer.priorityQueuePosition = undefined; + } } #createDate() { @@ -397,10 +400,10 @@ class MockTimers { emitter.emit('data', result); }; - const timerId = this.#createTimer(true, callback, interval, options); + const timer = this.#createTimer(true, callback, interval, options); const clearListeners = () => { emitter.removeAllListeners(); - context.#clearTimer(timerId); + context.#clearTimer(timer); }; const iterator = { __proto__: null, @@ -453,11 +456,11 @@ class MockTimers { } const onabort = () => { - clearFn(id); + clearFn(timer); return reject(abortIt(options.signal)); }; - const id = timerFn(() => { + const timer = timerFn(() => { return resolve(result); }, ms); @@ -620,6 +623,7 @@ class MockTimers { FunctionPrototypeApply(timer.callback, undefined, timer.args); this.#executionQueue.shift(); + timer.priorityQueuePosition = undefined; if (timer.interval !== undefined) { timer.runAt += timer.interval;