summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuca Casonato <hello@lcas.dev>2023-09-14 16:38:15 +0200
committerGitHub <noreply@github.com>2023-09-14 16:38:15 +0200
commit851f795001a9164572d02606587ddc5193bdfd2d (patch)
tree77a129ff766013dd9ea0cb83d6a84a40e4f1f0f7
parentbbb348aa33b56e15f376e8e7ee7b71bd5badd936 (diff)
fix: output traces for op sanitizer in more cases (#20494)
This adds traces for the "started outside test, closed inside test" case.
-rw-r--r--cli/js/40_testing.js33
-rw-r--r--cli/tests/integration/test_tests.rs6
-rw-r--r--cli/tests/testdata/test/ops_sanitizer_closed_inside_started_before.out19
-rw-r--r--cli/tests/testdata/test/ops_sanitizer_closed_inside_started_before.ts5
-rw-r--r--cli/tools/test/mod.rs14
-rw-r--r--cli/worker.rs12
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 {