diff options
author | David Sherret <dsherret@users.noreply.github.com> | 2024-06-18 17:24:18 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-18 17:24:18 -0400 |
commit | cba212b9c63f80b73994cf6012c5db83b31eefc9 (patch) | |
tree | 1d0ed2fc73e22e0d31d185734aca6d610aadcac3 | |
parent | 7b5c5147631101dd57e42525eae245668f9ce6fd (diff) |
perf(node): ensure cjs wrapper module has deterministic output (#24248)
-rw-r--r-- | ext/node/analyze.rs | 6 | ||||
-rw-r--r-- | tests/integration/run_tests.rs | 128 |
2 files changed, 72 insertions, 62 deletions
diff --git a/ext/node/analyze.rs b/ext/node/analyze.rs index 3b06a90e0..d80108733 100644 --- a/ext/node/analyze.rs +++ b/ext/node/analyze.rs @@ -1,5 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use std::collections::BTreeSet; use std::collections::HashSet; use std::path::Path; use std::path::PathBuf; @@ -106,7 +107,8 @@ impl<TCjsCodeAnalyzer: CjsCodeAnalyzer> NodeCodeTranslator<TCjsCodeAnalyzer> { .to_string(), ]; - let mut all_exports = analysis.exports.into_iter().collect::<HashSet<_>>(); + // use a BTreeSet to make the output deterministic for v8's code cache + let mut all_exports = analysis.exports.into_iter().collect::<BTreeSet<_>>(); if !analysis.reexports.is_empty() { let mut errors = Vec::new(); @@ -159,7 +161,7 @@ impl<TCjsCodeAnalyzer: CjsCodeAnalyzer> NodeCodeTranslator<TCjsCodeAnalyzer> { &'a self, entry_specifier: &url::Url, reexports: Vec<String>, - all_exports: &mut HashSet<String>, + all_exports: &mut BTreeSet<String>, // this goes through the modules concurrently, so collect // the errors in order to be deterministic errors: &mut Vec<anyhow::Error>, diff --git a/tests/integration/run_tests.rs b/tests/integration/run_tests.rs index 0d1804a28..b8263be29 100644 --- a/tests/integration/run_tests.rs +++ b/tests/integration/run_tests.rs @@ -5043,8 +5043,8 @@ fn run_etag_delete_source_cache() { #[test] fn code_cache_test() { - let deno_dir = TempDir::new(); let test_context = TestContextBuilder::new().use_temp_cwd().build(); + let deno_dir = test_context.deno_dir(); let temp_dir = test_context.temp_dir(); temp_dir.write("main.js", "console.log('Hello World - A');"); @@ -5052,17 +5052,14 @@ fn code_cache_test() { { let output = test_context .new_command() - .env("DENO_DIR", deno_dir.path()) - .arg("run") - .arg("-Ldebug") - .arg("main.js") + .args("run -Ldebug main.js") .split_output() .run(); output .assert_stdout_matches_text("Hello World - A[WILDCARD]") .assert_stderr_matches_text("[WILDCARD]Updating V8 code cache for ES module: file:///[WILDCARD]/main.js[WILDCARD]"); - assert!(!output.stderr().contains("V8 code cache hit")); + assert_not_contains!(output.stderr(), "V8 code cache hit"); // Check that the code cache database exists. let code_cache_path = deno_dir.path().join(CODE_CACHE_DB_FILE_NAME); @@ -5073,35 +5070,28 @@ fn code_cache_test() { { let output = test_context .new_command() - .env("DENO_DIR", deno_dir.path()) - .arg("run") - .arg("-Ldebug") - .arg("main.js") + .args("run -Ldebug main.js") .split_output() .run(); output .assert_stdout_matches_text("Hello World - A[WILDCARD]") .assert_stderr_matches_text("[WILDCARD]V8 code cache hit for ES module: file:///[WILDCARD]/main.js[WILDCARD]"); - assert!(!output.stderr().contains("Updating V8 code cache")); + assert_not_contains!(output.stderr(), "Updating V8 code cache"); } // Rerun with --no-code-cache. { let output = test_context .new_command() - .env("DENO_DIR", deno_dir.path()) - .arg("run") - .arg("-Ldebug") - .arg("--no-code-cache") - .arg("main.js") + .args("run -Ldebug --no-code-cache main.js") .split_output() .run(); output .assert_stdout_matches_text("Hello World - A[WILDCARD]") .skip_stderr_check(); - assert!(!output.stderr().contains("V8 code cache")); + assert_not_contains!(output.stderr(), "V8 code cache"); } // Modify the script, and make sure that the cache is rejected. @@ -5109,27 +5099,21 @@ fn code_cache_test() { { let output = test_context .new_command() - .env("DENO_DIR", deno_dir.path()) - .arg("run") - .arg("-Ldebug") - .arg("main.js") + .args("run -Ldebug main.js") .split_output() .run(); output .assert_stdout_matches_text("Hello World - B[WILDCARD]") .assert_stderr_matches_text("[WILDCARD]Updating V8 code cache for ES module: file:///[WILDCARD]/main.js[WILDCARD]"); - assert!(!output.stderr().contains("V8 code cache hit")); + assert_not_contains!(output.stderr(), "V8 code cache hit"); } } #[test] fn code_cache_npm_test() { - let deno_dir = TempDir::new(); - let test_context = TestContextBuilder::new() - .use_temp_cwd() - .use_http_server() - .build(); + let test_context = TestContextBuilder::for_npm().use_temp_cwd().build(); + let deno_dir = test_context.deno_dir(); let temp_dir = test_context.temp_dir(); temp_dir.write( "main.js", @@ -5140,12 +5124,7 @@ fn code_cache_npm_test() { { let output = test_context .new_command() - .env("DENO_DIR", deno_dir.path()) - .envs(env_vars_for_npm_tests()) - .arg("run") - .arg("-Ldebug") - .arg("-A") - .arg("main.js") + .args("run -Ldebug -A main.js") .split_output() .run(); @@ -5153,7 +5132,7 @@ fn code_cache_npm_test() { .assert_stdout_matches_text("Hello World[WILDCARD]") .assert_stderr_matches_text("[WILDCARD]Updating V8 code cache for ES module: file:///[WILDCARD]/main.js[WILDCARD]") .assert_stderr_matches_text("[WILDCARD]Updating V8 code cache for ES module: file:///[WILDCARD]/chalk/5.[WILDCARD]/source/index.js[WILDCARD]"); - assert!(!output.stderr().contains("V8 code cache hit")); + assert_not_contains!(output.stderr(), "V8 code cache hit"); // Check that the code cache database exists. let code_cache_path = deno_dir.path().join(CODE_CACHE_DB_FILE_NAME); @@ -5164,12 +5143,7 @@ fn code_cache_npm_test() { { let output = test_context .new_command() - .env("DENO_DIR", deno_dir.path()) - .envs(env_vars_for_npm_tests()) - .arg("run") - .arg("-Ldebug") - .arg("-A") - .arg("main.js") + .args("run -Ldebug -A main.js") .split_output() .run(); @@ -5177,17 +5151,14 @@ fn code_cache_npm_test() { .assert_stdout_matches_text("Hello World[WILDCARD]") .assert_stderr_matches_text("[WILDCARD]V8 code cache hit for ES module: file:///[WILDCARD]/main.js[WILDCARD]") .assert_stderr_matches_text("[WILDCARD]V8 code cache hit for ES module: file:///[WILDCARD]/chalk/5.[WILDCARD]/source/index.js[WILDCARD]"); - assert!(!output.stderr().contains("Updating V8 code cache")); + assert_not_contains!(output.stderr(), "Updating V8 code cache"); } } #[test] fn code_cache_npm_with_require_test() { - let deno_dir = TempDir::new(); - let test_context = TestContextBuilder::new() - .use_temp_cwd() - .use_http_server() - .build(); + let test_context = TestContextBuilder::for_npm().use_temp_cwd().build(); + let deno_dir = test_context.deno_dir(); let temp_dir = test_context.temp_dir(); temp_dir.write( "main.js", @@ -5198,12 +5169,7 @@ fn code_cache_npm_with_require_test() { { let output = test_context .new_command() - .env("DENO_DIR", deno_dir.path()) - .envs(env_vars_for_npm_tests()) - .arg("run") - .arg("-Ldebug") - .arg("-A") - .arg("main.js") + .args("run -Ldebug -A main.js") .split_output() .run(); @@ -5213,7 +5179,7 @@ fn code_cache_npm_with_require_test() { .assert_stderr_matches_text("[WILDCARD]Updating V8 code cache for ES module: file:///[WILDCARD]/autoprefixer/[WILDCARD]/autoprefixer.js[WILDCARD]") .assert_stderr_matches_text("[WILDCARD]Updating V8 code cache for script: file:///[WILDCARD]/autoprefixer/[WILDCARD]/autoprefixer.js[WILDCARD]") .assert_stderr_matches_text("[WILDCARD]Updating V8 code cache for script: file:///[WILDCARD]/browserslist/[WILDCARD]/index.js[WILDCARD]"); - assert!(!output.stderr().contains("V8 code cache hit")); + assert_not_contains!(output.stderr(), "V8 code cache hit"); // Check that the code cache database exists. let code_cache_path = deno_dir.path().join(CODE_CACHE_DB_FILE_NAME); @@ -5224,12 +5190,7 @@ fn code_cache_npm_with_require_test() { { let output = test_context .new_command() - .env("DENO_DIR", deno_dir.path()) - .envs(env_vars_for_npm_tests()) - .arg("run") - .arg("-Ldebug") - .arg("-A") - .arg("main.js") + .args("run -Ldebug -A main.js") .split_output() .run(); @@ -5239,7 +5200,54 @@ fn code_cache_npm_with_require_test() { .assert_stderr_matches_text("[WILDCARD]V8 code cache hit for ES module: file:///[WILDCARD]/autoprefixer/[WILDCARD]/autoprefixer.js[WILDCARD]") .assert_stderr_matches_text("[WILDCARD]V8 code cache hit for script: file:///[WILDCARD]/autoprefixer/[WILDCARD]/autoprefixer.js[WILDCARD]") .assert_stderr_matches_text("[WILDCARD]V8 code cache hit for script: file:///[WILDCARD]/browserslist/[WILDCARD]/index.js[WILDCARD]"); - assert!(!output.stderr().contains("Updating V8 code cache")); + assert_not_contains!(output.stderr(), "Updating V8 code cache"); + } +} + +#[test] +fn code_cache_npm_cjs_wrapper_module_many_exports() { + // The code cache was being invalidated because the CJS wrapper module + // had indeterministic output. + let test_context = TestContextBuilder::for_npm().use_temp_cwd().build(); + let temp_dir = test_context.temp_dir(); + temp_dir.write( + "main.js", + // this package has a few exports + "import { hello } from \"npm:@denotest/cjs-reexport-collision\";hello.sayHello();", + ); + + // First run with no prior cache. + { + let output = test_context + .new_command() + .args("run -Ldebug -A main.js") + .split_output() + .run(); + + assert_not_contains!(output.stderr(), "V8 code cache hit"); + assert_contains!(output.stderr(), "Updating V8 code cache"); + output.skip_stdout_check(); + } + + // 2nd run with cache. + { + let output = test_context + .new_command() + .args("run -Ldebug -A main.js") + .split_output() + .run(); + assert_contains!(output.stderr(), "V8 code cache hit"); + assert_not_contains!(output.stderr(), "Updating V8 code cache"); + output.skip_stdout_check(); + + // should have two occurrences of this (one for entrypoint and one for wrapper module) + assert_eq!( + output + .stderr() + .split("V8 code cache hit for ES module") + .count(), + 3 + ); } } |