summaryrefslogtreecommitdiff
path: root/cli/tools/test/mod.rs
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2024-01-08 12:18:42 -0500
committerGitHub <noreply@github.com>2024-01-08 17:18:42 +0000
commite212e1fc35ddae63f457f0f2a2e95154e008941f (patch)
tree6c1f553fbc529bfcab6413049af8f32ed31d1dfd /cli/tools/test/mod.rs
parentee45d5bf8f2e1826b2a106b030abe891cfc0b37c (diff)
perf: skip expanding exclude globs (#21817)
We were calling `expand_glob` on our excludes, which is very expensive and unnecessary because we can pattern match while traversing instead. 1. Doesn't expand "exclude" globs. Instead pattern matches while walking the directory. 2. Splits up the "include" into base paths and applicable file patterns. This causes less pattern matching to occur because we're only pattern matching on patterns that might match and not ones in completely unrelated directories.
Diffstat (limited to 'cli/tools/test/mod.rs')
-rw-r--r--cli/tools/test/mod.rs75
1 files changed, 55 insertions, 20 deletions
diff --git a/cli/tools/test/mod.rs b/cli/tools/test/mod.rs
index 2a5e87b2a..2c226db4d 100644
--- a/cli/tools/test/mod.rs
+++ b/cli/tools/test/mod.rs
@@ -1,7 +1,6 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use crate::args::CliOptions;
-use crate::args::FilesConfig;
use crate::args::Flags;
use crate::args::TestFlags;
use crate::args::TestReporterConfig;
@@ -17,6 +16,8 @@ use crate::module_loader::ModuleLoadPreparer;
use crate::ops;
use crate::util::file_watcher;
use crate::util::fs::collect_specifiers;
+use crate::util::glob::FilePatterns;
+use crate::util::glob::PathOrPattern;
use crate::util::path::get_extension;
use crate::util::path::is_script_ext;
use crate::util::path::mapped_specifier_for_tsc;
@@ -1048,14 +1049,41 @@ pub async fn report_tests(
(Ok(()), receiver)
}
+fn is_supported_test_path_predicate(
+ path: &Path,
+ patterns: &FilePatterns,
+) -> bool {
+ if !is_script_ext(path) {
+ false
+ } else if has_supported_test_path_name(path) {
+ true
+ } else {
+ // allow someone to explicitly specify a path
+ let matches_exact_path_or_pattern = patterns
+ .include
+ .as_ref()
+ .map(|p| {
+ p.inner().iter().any(|p| match p {
+ PathOrPattern::Path(p) => p == path,
+ PathOrPattern::Pattern(p) => p.matches_path(path),
+ })
+ })
+ .unwrap_or(false);
+ matches_exact_path_or_pattern
+ }
+}
+
/// Checks if the path has a basename and extension Deno supports for tests.
pub(crate) fn is_supported_test_path(path: &Path) -> bool {
+ has_supported_test_path_name(path) && is_script_ext(path)
+}
+
+fn has_supported_test_path_name(path: &Path) -> bool {
if let Some(name) = path.file_stem() {
let basename = name.to_string_lossy();
- (basename.ends_with("_test")
+ basename.ends_with("_test")
|| basename.ends_with(".test")
- || basename == "test")
- && is_script_ext(path)
+ || basename == "test"
} else {
false
}
@@ -1094,13 +1122,15 @@ fn is_supported_test_ext(path: &Path) -> bool {
/// - Specifiers matching the `is_supported_test_path` are marked as `TestMode::Executable`.
/// - Specifiers matching both predicates are marked as `TestMode::Both`
fn collect_specifiers_with_test_mode(
- files: &FilesConfig,
+ files: FilePatterns,
include_inline: &bool,
) -> Result<Vec<(ModuleSpecifier, TestMode)>, AnyError> {
- let module_specifiers = collect_specifiers(files, is_supported_test_path)?;
+ // todo(dsherret): there's no need to collect twice as it's slow
+ let module_specifiers =
+ collect_specifiers(files.clone(), is_supported_test_path_predicate)?;
if *include_inline {
- return collect_specifiers(files, is_supported_test_ext).map(
+ return collect_specifiers(files, |p, _| is_supported_test_ext(p)).map(
|specifiers| {
specifiers
.into_iter()
@@ -1136,7 +1166,7 @@ fn collect_specifiers_with_test_mode(
/// as well.
async fn fetch_specifiers_with_test_mode(
file_fetcher: &FileFetcher,
- files: &FilesConfig,
+ files: FilePatterns,
doc: &bool,
) -> Result<Vec<(ModuleSpecifier, TestMode)>, AnyError> {
let mut specifiers_with_mode = collect_specifiers_with_test_mode(files, doc)?;
@@ -1174,7 +1204,7 @@ pub async fn run_tests(
let specifiers_with_mode = fetch_specifiers_with_test_mode(
file_fetcher,
- &test_options.files,
+ test_options.files.clone(),
&test_options.doc,
)
.await?;
@@ -1264,8 +1294,11 @@ pub async fn run_tests_with_watch(
let test_options = cli_options.resolve_test_options(test_flags)?;
let _ = watcher_communicator.watch_paths(cli_options.watch_paths());
- if let Some(include) = &test_options.files.include {
- let _ = watcher_communicator.watch_paths(include.clone());
+ if let Some(set) = &test_options.files.include {
+ let watch_paths = set.base_paths();
+ if !watch_paths.is_empty() {
+ let _ = watcher_communicator.watch_paths(watch_paths);
+ }
}
let graph_kind = cli_options.type_check_mode().as_graph_kind();
@@ -1274,13 +1307,18 @@ pub async fn run_tests_with_watch(
let module_graph_builder = factory.module_graph_builder().await?;
let file_fetcher = factory.file_fetcher()?;
let test_modules = if test_options.doc {
- collect_specifiers(&test_options.files, is_supported_test_ext)
+ collect_specifiers(test_options.files.clone(), |p, _| {
+ is_supported_test_ext(p)
+ })
} else {
- collect_specifiers(&test_options.files, is_supported_test_path)
+ collect_specifiers(
+ test_options.files.clone(),
+ is_supported_test_path_predicate,
+ )
}?;
+
let permissions =
Permissions::from_options(&cli_options.permissions_options())?;
-
let graph = module_graph_builder
.create_graph(graph_kind, test_modules.clone())
.await?;
@@ -1293,16 +1331,13 @@ pub async fn run_tests_with_watch(
let test_modules_to_reload = if let Some(changed_paths) = changed_paths
{
- let changed_specifiers = changed_paths
- .into_iter()
- .filter_map(|p| ModuleSpecifier::from_file_path(p).ok())
- .collect::<HashSet<_>>();
let mut result = Vec::new();
+ let changed_paths = changed_paths.into_iter().collect::<HashSet<_>>();
for test_module_specifier in test_modules {
if has_graph_root_local_dependent_changed(
&graph,
&test_module_specifier,
- &changed_specifiers,
+ &changed_paths,
) {
result.push(test_module_specifier.clone());
}
@@ -1317,7 +1352,7 @@ pub async fn run_tests_with_watch(
let module_load_preparer = factory.module_load_preparer().await?;
let specifiers_with_mode = fetch_specifiers_with_test_mode(
file_fetcher,
- &test_options.files,
+ test_options.files.clone(),
&test_options.doc,
)
.await?