Skip to content

Commit fee0589

Browse files
bartlomiejuclaude
andauthored
feat: disable ops and resources sanitizers by default in deno test (#33158)
## Summary Changes the default for `sanitizeOps` and `sanitizeResources` from `true` to `false` in `Deno.test()`. This aligns with what most users expect -- tests no longer fail due to leaked async ops or resources unless explicitly opted in. ### Before ```ts // This test FAILS by default -- the timer leak triggers the ops sanitizer Deno.test("my test", () => { setTimeout(() => {}, 1000); }); ``` ``` ERRORS my test => ./main.ts:1:6 error: Leaks detected: - A timer was started in this test, but never completed. ``` ### After ```ts // This test PASSES by default -- no sanitizers enabled Deno.test("my test", () => { setTimeout(() => {}, 1000); }); ``` To re-enable sanitizers, users have three options: **1. CLI flags (e.g. for CI)** ```sh deno test --sanitize-ops --sanitize-resources ``` **2. Environment variables (e.g. for CI)** ```sh DENO_TEST_SANITIZE_OPS=1 DENO_TEST_SANITIZE_RESOURCES=1 deno test ``` **3. Per-test opt-in** ```ts Deno.test({ name: "my test", sanitizeOps: true, sanitizeResources: true, fn() { setTimeout(() => {}, 1000); }, }); ``` ### What's unchanged - `sanitizeExit` default remains `true` - Per-test `sanitizeOps: true` / `sanitizeResources: true` continues to work - Test steps still inherit sanitizer settings from their parent test Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 607c73f commit fee0589

17 files changed

Lines changed: 88 additions & 15 deletions

File tree

cli/args/flags.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,8 @@ pub struct TestFlags {
559559
pub filter: Option<String>,
560560
pub shuffle: Option<u64>,
561561
pub trace_leaks: bool,
562+
pub sanitize_ops: bool,
563+
pub sanitize_resources: bool,
562564
pub watch: Option<WatchFlagsWithPaths>,
563565
pub reporter: TestReporterConfig,
564566
pub junit_path: Option<String>,
@@ -4379,6 +4381,20 @@ or <c>**/__tests__/**</>:
43794381
.action(ArgAction::SetTrue)
43804382
.help_heading(TEST_HEADING),
43814383
)
4384+
.arg(
4385+
Arg::new("sanitize-ops")
4386+
.long("sanitize-ops")
4387+
.help("Enable the ops sanitizer, which ensures that all async ops started in a test are completed before the test ends")
4388+
.action(ArgAction::SetTrue)
4389+
.help_heading(TEST_HEADING),
4390+
)
4391+
.arg(
4392+
Arg::new("sanitize-resources")
4393+
.long("sanitize-resources")
4394+
.help("Enable the resources sanitizer, which ensures that all resources opened in a test are closed before the test ends")
4395+
.action(ArgAction::SetTrue)
4396+
.help_heading(TEST_HEADING),
4397+
)
43824398
.arg(
43834399
Arg::new("doc")
43844400
.long("doc")
@@ -7334,6 +7350,8 @@ fn test_parse(
73347350

73357351
let no_run = matches.get_flag("no-run");
73367352
let trace_leaks = matches.get_flag("trace-leaks");
7353+
let sanitize_ops = matches.get_flag("sanitize-ops");
7354+
let sanitize_resources = matches.get_flag("sanitize-resources");
73377355
let doc = matches.get_flag("doc");
73387356
let filter = matches.remove_one::<String>("filter");
73397357
let clean = matches.get_flag("clean");
@@ -7401,6 +7419,8 @@ fn test_parse(
74017419
permit_no_files: permit_no_files_parse(matches),
74027420
parallel: matches.get_flag("parallel"),
74037421
trace_leaks,
7422+
sanitize_ops,
7423+
sanitize_resources,
74047424
watch: watch_arg_parse_with_paths(matches)?,
74057425
reporter,
74067426
junit_path,
@@ -11588,6 +11608,8 @@ mod tests {
1158811608
shuffle: None,
1158911609
parallel: false,
1159011610
trace_leaks: true,
11611+
sanitize_ops: false,
11612+
sanitize_resources: false,
1159111613
coverage_dir: Some("cov".to_string()),
1159211614
coverage_raw_data_only: false,
1159311615
clean: true,
@@ -11695,6 +11717,8 @@ mod tests {
1169511717
},
1169611718
parallel: false,
1169711719
trace_leaks: false,
11720+
sanitize_ops: false,
11721+
sanitize_resources: false,
1169811722
coverage_dir: None,
1169911723
coverage_raw_data_only: false,
1170011724
clean: false,
@@ -11739,6 +11763,8 @@ mod tests {
1173911763
},
1174011764
parallel: false,
1174111765
trace_leaks: false,
11766+
sanitize_ops: false,
11767+
sanitize_resources: false,
1174211768
coverage_dir: None,
1174311769
coverage_raw_data_only: false,
1174411770
clean: false,
@@ -11877,6 +11903,8 @@ mod tests {
1187711903
},
1187811904
parallel: false,
1187911905
trace_leaks: false,
11906+
sanitize_ops: false,
11907+
sanitize_resources: false,
1188011908
coverage_dir: None,
1188111909
coverage_raw_data_only: false,
1188211910
clean: false,
@@ -11914,6 +11942,8 @@ mod tests {
1191411942
},
1191511943
parallel: false,
1191611944
trace_leaks: false,
11945+
sanitize_ops: false,
11946+
sanitize_resources: false,
1191711947
coverage_dir: None,
1191811948
coverage_raw_data_only: false,
1191911949
clean: false,
@@ -11950,6 +11980,8 @@ mod tests {
1195011980
},
1195111981
parallel: false,
1195211982
trace_leaks: false,
11983+
sanitize_ops: false,
11984+
sanitize_resources: false,
1195311985
coverage_dir: None,
1195411986
coverage_raw_data_only: false,
1195511987
clean: false,
@@ -11988,6 +12020,8 @@ mod tests {
1198812020
},
1198912021
parallel: false,
1199012022
trace_leaks: false,
12023+
sanitize_ops: false,
12024+
sanitize_resources: false,
1199112025
coverage_dir: None,
1199212026
coverage_raw_data_only: false,
1199312027
clean: false,

cli/args/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,8 @@ pub struct WorkspaceTestOptions {
204204
pub shuffle: Option<u64>,
205205
pub concurrent_jobs: NonZeroUsize,
206206
pub trace_leaks: bool,
207+
pub sanitize_ops: bool,
208+
pub sanitize_resources: bool,
207209
pub reporter: TestReporterConfig,
208210
pub junit_path: Option<String>,
209211
pub hide_stacktraces: bool,
@@ -220,6 +222,13 @@ impl WorkspaceTestOptions {
220222
no_run: test_flags.no_run,
221223
shuffle: test_flags.shuffle,
222224
trace_leaks: test_flags.trace_leaks,
225+
sanitize_ops: test_flags.sanitize_ops
226+
|| std::env::var("DENO_TEST_SANITIZE_OPS").ok().as_deref() == Some("1"),
227+
sanitize_resources: test_flags.sanitize_resources
228+
|| std::env::var("DENO_TEST_SANITIZE_RESOURCES")
229+
.ok()
230+
.as_deref()
231+
== Some("1"),
223232
reporter: test_flags.reporter,
224233
junit_path: test_flags.junit_path.clone(),
225234
hide_stacktraces: test_flags.hide_stacktraces,

cli/js/40_test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,8 @@ function testInner(
263263
const defaults = {
264264
ignore: false,
265265
only: false,
266-
sanitizeOps: true,
267-
sanitizeResources: true,
266+
sanitizeOps: Deno[Deno.internal].testSanitizeOps ?? false,
267+
sanitizeResources: Deno[Deno.internal].testSanitizeResources ?? false,
268268
sanitizeExit: true,
269269
permissions: null,
270270
};

cli/lsp/testing/execution.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,8 @@ impl TestRun {
331331
filter,
332332
shuffle: None,
333333
trace_leaks: false,
334+
sanitize_ops: false,
335+
sanitize_resources: false,
334336
},
335337
))
336338
}

cli/tools/test/mod.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,8 @@ pub struct TestSpecifierOptions {
590590
pub shuffle: Option<u64>,
591591
pub filter: TestFilter,
592592
pub trace_leaks: bool,
593+
pub sanitize_ops: bool,
594+
pub sanitize_resources: bool,
593595
}
594596

595597
impl TestSummary {
@@ -705,6 +707,22 @@ async fn configure_main_worker(
705707
)
706708
.map_err(|e| CoreErrorKind::Js(e).into_box())?;
707709
}
710+
if options.sanitize_ops {
711+
worker
712+
.execute_script_static(
713+
located_script_name!(),
714+
"Deno[Deno.internal].testSanitizeOps = true;",
715+
)
716+
.map_err(|e| CoreErrorKind::Js(e).into_box())?;
717+
}
718+
if options.sanitize_resources {
719+
worker
720+
.execute_script_static(
721+
located_script_name!(),
722+
"Deno[Deno.internal].testSanitizeResources = true;",
723+
)
724+
.map_err(|e| CoreErrorKind::Js(e).into_box())?;
725+
}
708726

709727
let op_state = worker.op_state();
710728

@@ -1683,6 +1701,8 @@ pub async fn run_tests(
16831701
filter: TestFilter::from_flag(&workspace_test_options.filter),
16841702
shuffle: workspace_test_options.shuffle,
16851703
trace_leaks: workspace_test_options.trace_leaks,
1704+
sanitize_ops: workspace_test_options.sanitize_ops,
1705+
sanitize_resources: workspace_test_options.sanitize_resources,
16861706
},
16871707
},
16881708
)
@@ -1908,6 +1928,8 @@ pub async fn run_tests_with_watch(
19081928
filter: TestFilter::from_flag(&workspace_test_options.filter),
19091929
shuffle: workspace_test_options.shuffle,
19101930
trace_leaks: workspace_test_options.trace_leaks,
1931+
sanitize_ops: workspace_test_options.sanitize_ops,
1932+
sanitize_resources: workspace_test_options.sanitize_resources,
19111933
},
19121934
},
19131935
)

cli/tsc/dts/lib.deno.ns.d.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -831,13 +831,19 @@ declare namespace Deno {
831831
* not await. This helps in preventing logic errors and memory leaks
832832
* in the application code.
833833
*
834-
* @default {true} */
834+
* Can also be enabled globally with the `--sanitize-ops` CLI flag or
835+
* the `DENO_TEST_SANITIZE_OPS=1` environment variable.
836+
*
837+
* @default {false} */
835838
sanitizeOps?: boolean;
836839
/** Ensure the test step does not "leak" resources - like open files or
837840
* network connections - by ensuring the open resources at the start of the
838841
* test match the open resources at the end of the test.
839842
*
840-
* @default {true} */
843+
* Can also be enabled globally with the `--sanitize-resources` CLI flag or
844+
* the `DENO_TEST_SANITIZE_RESOURCES=1` environment variable.
845+
*
846+
* @default {false} */
841847
sanitizeResources?: boolean;
842848
/** Ensure the test case does not prematurely cause the process to exit,
843849
* for example via a call to {@linkcode Deno.exit}.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"args": "test --trace-leaks ops_sanitizer_closed_inside_started_before.ts",
2+
"args": "test --sanitize-ops --trace-leaks ops_sanitizer_closed_inside_started_before.ts",
33
"exitCode": 1,
44
"output": "ops_sanitizer_closed_inside_started_before.out"
55
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"args": "test --trace-leaks ops_sanitizer_multiple_timeout_tests.ts",
2+
"args": "test --sanitize-ops --trace-leaks ops_sanitizer_multiple_timeout_tests.ts",
33
"exitCode": 1,
44
"output": "ops_sanitizer_multiple_timeout_tests.out"
55
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"args": "test ops_sanitizer_multiple_timeout_tests.ts",
2+
"args": "test --sanitize-ops ops_sanitizer_multiple_timeout_tests.ts",
33
"exitCode": 1,
44
"output": "ops_sanitizer_multiple_timeout_tests_no_trace.out"
55
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
2-
"args": "test --no-check ops_sanitizer_nexttick.ts",
2+
"args": "test --sanitize-ops --no-check ops_sanitizer_nexttick.ts",
33
"output": "ops_sanitizer_nexttick.out"
44
}

0 commit comments

Comments
 (0)