Skip to content

Commit

Permalink
refactor(timers): refactor timers to use one async op per timer (#12862)
Browse files Browse the repository at this point in the history
This change also makes the timers implementation closer to the spec, and
sets up the stage to implement AbortSignal.timeout() (whatwg/dom#1032).

Fixes #8965
Fixes #10974
Fixes #11398
  • Loading branch information
Andreu Botella authored Dec 7, 2021
1 parent 5027826 commit 33da15a
Show file tree
Hide file tree
Showing 8 changed files with 456 additions and 593 deletions.
6 changes: 6 additions & 0 deletions cli/tests/integration/test_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,12 @@ itest!(ops_sanitizer_timeout_failure {
output: "test/ops_sanitizer_timeout_failure.out",
});

itest!(ops_sanitizer_multiple_timeout_tests {
args: "test test/ops_sanitizer_multiple_timeout_tests.ts",
exit_code: 1,
output: "test/ops_sanitizer_multiple_timeout_tests.out",
});

itest!(ops_sanitizer_nexttick {
args: "test test/ops_sanitizer_nexttick.ts",
output: "test/ops_sanitizer_nexttick.out",
Expand Down
57 changes: 57 additions & 0 deletions cli/tests/testdata/test/ops_sanitizer_multiple_timeout_tests.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
Check [WILDCARD]/testdata/test/ops_sanitizer_multiple_timeout_tests.ts
running 2 tests from [WILDCARD]/testdata/test/ops_sanitizer_multiple_timeout_tests.ts
test test 1 ... FAILED ([WILDCARD])
test test 2 ... FAILED ([WILDCARD])

failures:

test 1
AssertionError: Test case is leaking async ops.
Before:
- dispatched: 0
- completed: 0
After:
- dispatched: [WILDCARD]
- completed: [WILDCARD]
Ops:
op_sleep:
Before:
- dispatched: 0
- completed: 0
After:
- dispatched: [WILDCARD]
- completed: [WILDCARD]

Make sure to await all promises returned from Deno APIs before
finishing test case.
at [WILDCARD]

test 2
AssertionError: Test case is leaking async ops.
Before:
- dispatched: [WILDCARD]
- completed: [WILDCARD]
After:
- dispatched: [WILDCARD]
- completed: [WILDCARD]
Ops:
op_sleep:
Before:
- dispatched: [WILDCARD]
- completed: [WILDCARD]
After:
- dispatched: [WILDCARD]
- completed: [WILDCARD]

Make sure to await all promises returned from Deno APIs before
finishing test case.
at [WILDCARD]

failures:

test 1
test 2

test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out ([WILDCARD])

error: Test failed
10 changes: 10 additions & 0 deletions cli/tests/testdata/test/ops_sanitizer_multiple_timeout_tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// https://github.com/denoland/deno/issues/8965

function test() {
setTimeout(() => {}, 10000);
setTimeout(() => {}, 10001);
}

Deno.test("test 1", test);

Deno.test("test 2", test);
10 changes: 5 additions & 5 deletions cli/tests/testdata/test/ops_sanitizer_unstable.out
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ Before:
- dispatched: 1
- completed: 1
After:
- dispatched: 3
- completed: 2
- dispatched: [WILDCARD]
- completed: [WILDCARD]
Ops:
op_global_timer:
op_sleep:
Before:
- dispatched: 1
- completed: 1
After:
- dispatched: 3
- completed: 2
- dispatched: [WILDCARD]
- completed: [WILDCARD]

Make sure to await all promises returned from Deno APIs before
finishing test case.
Expand Down
2 changes: 1 addition & 1 deletion cli/tests/testdata/worker_drop_handle_race.js.out
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error: Uncaught (in worker "") Error
throw new Error();
^
at [WILDCARD]/workers/drop_handle_race.js:2:9
at fire (deno:ext/timers/[WILDCARD])
at Object.action (deno:ext/timers/[WILDCARD])
at handleTimerMacrotask (deno:ext/timers/[WILDCARD])
error: Uncaught (in promise) Error: Unhandled error event in child worker.
at Worker.#pollControl (deno:runtime/js/11_workers.js:[WILDCARD])
84 changes: 84 additions & 0 deletions cli/tests/unit/timers_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
Deferred,
deferred,
delay,
unreachable,
} from "./test_util.ts";

Deno.test(async function functionParameterBindingSuccess() {
Expand Down Expand Up @@ -206,6 +207,60 @@ Deno.test(function intervalCancelInvalidSilentFail() {
clearInterval(2147483647);
});

Deno.test(async function callbackTakesLongerThanInterval() {
const promise = deferred();

let timeEndOfFirstCallback: number | undefined;
const interval = setInterval(() => {
if (timeEndOfFirstCallback === undefined) {
// First callback
Deno.sleepSync(300);
timeEndOfFirstCallback = Date.now();
} else {
// Second callback
assert(Date.now() - 100 >= timeEndOfFirstCallback);
clearInterval(interval);
promise.resolve();
}
}, 100);

await promise;
});

// https://github.com/denoland/deno/issues/11398
Deno.test(async function clearTimeoutAfterNextTimerIsDue1() {
const promise = deferred();

setTimeout(() => {
promise.resolve();
}, 300);

const interval = setInterval(() => {
Deno.sleepSync(400);
// Both the interval and the timeout's due times are now in the past.
clearInterval(interval);
}, 100);

await promise;
});

// https://github.com/denoland/deno/issues/11398
Deno.test(async function clearTimeoutAfterNextTimerIsDue2() {
const promise = deferred();

const timeout1 = setTimeout(unreachable, 100);

setTimeout(() => {
promise.resolve();
}, 200);

Deno.sleepSync(300);
// Both of the timeouts' due times are now in the past.
clearTimeout(timeout1);

await promise;
});

Deno.test(async function fireCallbackImmediatelyWhenDelayOverMaxValue() {
let count = 0;
setTimeout(() => {
Expand Down Expand Up @@ -346,6 +401,35 @@ Deno.test(async function timerMaxCpuBug() {
assert(opsDispatched_ - opsDispatched < 10);
});

Deno.test(async function timerOrdering() {
const array: number[] = [];
const donePromise = deferred();

function push(n: number) {
array.push(n);
if (array.length === 6) {
donePromise.resolve();
}
}

setTimeout(() => {
push(1);
setTimeout(() => push(4));
}, 0);
setTimeout(() => {
push(2);
setTimeout(() => push(5));
}, 0);
setTimeout(() => {
push(3);
setTimeout(() => push(6));
}, 0);

await donePromise;

assertEquals(array, [1, 2, 3, 4, 5, 6]);
});

Deno.test(async function timerBasicMicrotaskOrdering() {
let s = "";
let count = 0;
Expand Down
Loading

0 comments on commit 33da15a

Please sign in to comment.