diff options
author | Luca Casonato <hello@lcas.dev> | 2023-09-14 16:38:15 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-09-14 16:38:15 +0200 |
commit | 851f795001a9164572d02606587ddc5193bdfd2d (patch) | |
tree | 77a129ff766013dd9ea0cb83d6a84a40e4f1f0f7 /cli | |
parent | bbb348aa33b56e15f376e8e7ee7b71bd5badd936 (diff) |
fix: output traces for op sanitizer in more cases (#20494)
This adds traces for the "started outside test, closed inside test"
case.
Diffstat (limited to 'cli')
-rw-r--r-- | cli/js/40_testing.js | 33 | ||||
-rw-r--r-- | cli/tests/integration/test_tests.rs | 6 | ||||
-rw-r--r-- | cli/tests/testdata/test/ops_sanitizer_closed_inside_started_before.out | 19 | ||||
-rw-r--r-- | cli/tests/testdata/test/ops_sanitizer_closed_inside_started_before.ts | 5 | ||||
-rw-r--r-- | cli/tools/test/mod.rs | 14 | ||||
-rw-r--r-- | cli/worker.rs | 12 |
6 files changed, 74 insertions, 15 deletions
diff --git a/cli/js/40_testing.js b/cli/js/40_testing.js index 37eb6be8f..443b91596 100644 --- a/cli/js/40_testing.js +++ b/cli/js/40_testing.js @@ -206,15 +206,30 @@ function assertOps(fn) { } else if (dispatchedDiff < completedDiff) { const [name, hint] = OP_DETAILS[key] || [key, null]; const count = completedDiff - dispatchedDiff; - ArrayPrototypePush( - details, - `${count} async operation${count === 1 ? "" : "s"} to ${name} ${ - count === 1 ? "was" : "were" - } started before this test, but ${ - count === 1 ? "was" : "were" - } completed during the test. Async operations should not complete in a test if they were not started in that test. - ${hint ? `This is often caused by not ${hint}.` : ""}`, - ); + let message = `${count} async operation${ + count === 1 ? "" : "s" + } to ${name} ${ + count === 1 ? "was" : "were" + } started before this test, but ${ + count === 1 ? "was" : "were" + } completed during the test. Async operations should not complete in a test if they were not started in that test.`; + if (hint) { + message += ` This is often caused by not ${hint}.`; + } + const traces = []; + for (const [id, { opName, stack }] of preTraces) { + if (opName !== key) continue; + if (MapPrototypeHas(postTraces, id)) continue; + ArrayPrototypePush(traces, stack); + } + if (traces.length === 1) { + message += " The operation was started here:\n"; + message += traces[0]; + } else if (traces.length > 1) { + message += " The operations were started here:\n"; + message += ArrayPrototypeJoin(traces, "\n\n"); + } + ArrayPrototypePush(details, message); } } return { failed: { leakedOps: [details, core.isOpCallTracingEnabled()] } }; diff --git a/cli/tests/integration/test_tests.rs b/cli/tests/integration/test_tests.rs index 042e84078..b4bf842ff 100644 --- a/cli/tests/integration/test_tests.rs +++ b/cli/tests/integration/test_tests.rs @@ -255,6 +255,12 @@ itest!(trace_ops_catch_error { // output: "test/ops_sanitizer_missing_details.out", // }); +itest!(ops_sanitizer_closed_inside_started_before { + args: "test --trace-ops test/ops_sanitizer_closed_inside_started_before.ts", + exit_code: 1, + output: "test/ops_sanitizer_closed_inside_started_before.out", +}); + itest!(ops_sanitizer_nexttick { args: "test --no-check test/ops_sanitizer_nexttick.ts", output: "test/ops_sanitizer_nexttick.out", diff --git a/cli/tests/testdata/test/ops_sanitizer_closed_inside_started_before.out b/cli/tests/testdata/test/ops_sanitizer_closed_inside_started_before.out new file mode 100644 index 000000000..37fb0a319 --- /dev/null +++ b/cli/tests/testdata/test/ops_sanitizer_closed_inside_started_before.out @@ -0,0 +1,19 @@ +Check [WILDCARD]test/ops_sanitizer_closed_inside_started_before.ts +running 1 test from ./test/ops_sanitizer_closed_inside_started_before.ts +test 1 ... FAILED [WILDCARD] + + ERRORS + +test 1 => ./test/ops_sanitizer_closed_inside_started_before.ts:[WILDCARD] +error: Leaking async ops: + - 1 async operation to sleep for a duration was started before this test, but was completed during the test. Async operations should not complete in a test if they were not started in that test. This is often caused by not cancelling a `setTimeout` or `setInterval` call. The operation was started here: + at [WILDCARD] + at [WILDCARD]/cli/tests/testdata/test/ops_sanitizer_closed_inside_started_before.ts:[WILDCARD] + + FAILURES + +test 1 => ./test/ops_sanitizer_closed_inside_started_before.ts:[WILDCARD] + +FAILED | 0 passed | 1 failed [WILDCARD] + +error: Test failed diff --git a/cli/tests/testdata/test/ops_sanitizer_closed_inside_started_before.ts b/cli/tests/testdata/test/ops_sanitizer_closed_inside_started_before.ts new file mode 100644 index 000000000..97d3d72c8 --- /dev/null +++ b/cli/tests/testdata/test/ops_sanitizer_closed_inside_started_before.ts @@ -0,0 +1,5 @@ +const timer = setTimeout(() => {}, 10000000000); + +Deno.test("test 1", () => { + clearTimeout(timer); +}); diff --git a/cli/tools/test/mod.rs b/cli/tools/test/mod.rs index 87ca7f3f5..0708e00c0 100644 --- a/cli/tools/test/mod.rs +++ b/cli/tools/test/mod.rs @@ -433,6 +433,13 @@ pub async fn test_specifier( let mut coverage_collector = worker.maybe_setup_coverage_collector().await?; + if options.trace_ops { + worker.execute_script_static( + located_script_name!(), + "Deno[Deno.internal].core.enableOpCallTracing();", + )?; + } + // We execute the main module as a side module so that import.meta.main is not set. match worker.execute_side_module_possibly_with_npm().await { Ok(()) => {} @@ -450,12 +457,7 @@ pub async fn test_specifier( } let mut worker = worker.into_main_worker(); - if options.trace_ops { - worker.js_runtime.execute_script_static( - located_script_name!(), - "Deno[Deno.internal].core.enableOpCallTracing();", - )?; - } + worker.dispatch_load_event(located_script_name!())?; let tests = { diff --git a/cli/worker.rs b/cli/worker.rs index ef321ff88..45968afe7 100644 --- a/cli/worker.rs +++ b/cli/worker.rs @@ -12,6 +12,7 @@ use deno_core::futures::FutureExt; use deno_core::located_script_name; use deno_core::parking_lot::Mutex; use deno_core::url::Url; +use deno_core::v8; use deno_core::CompiledWasmModuleStore; use deno_core::Extension; use deno_core::ModuleId; @@ -279,6 +280,17 @@ impl CliMainWorker { Ok(None) } } + + pub fn execute_script_static( + &mut self, + name: &'static str, + source_code: &'static str, + ) -> Result<v8::Global<v8::Value>, AnyError> { + self + .worker + .js_runtime + .execute_script_static(name, source_code) + } } pub struct CliMainWorkerFactory { |