mirror of
https://github.com/denoland/deno.git
synced 2024-12-25 16:49:18 -05:00
feat(test): add --shuffle flag to randomize test ordering (#11163)
This commit is contained in:
parent
bdeb4f430b
commit
e8258e0210
11 changed files with 136 additions and 8 deletions
15
Cargo.lock
generated
15
Cargo.lock
generated
|
@ -568,6 +568,7 @@ dependencies = [
|
||||||
"os_pipe",
|
"os_pipe",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project",
|
"pin-project",
|
||||||
|
"rand 0.8.4",
|
||||||
"regex",
|
"regex",
|
||||||
"ring",
|
"ring",
|
||||||
"rustyline",
|
"rustyline",
|
||||||
|
@ -645,7 +646,7 @@ version = "0.24.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"deno_core",
|
"deno_core",
|
||||||
"deno_web",
|
"deno_web",
|
||||||
"rand 0.8.3",
|
"rand 0.8.4",
|
||||||
"ring",
|
"ring",
|
||||||
"tokio",
|
"tokio",
|
||||||
"uuid",
|
"uuid",
|
||||||
|
@ -2529,9 +2530,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.8.3"
|
version = "0.8.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
|
checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"rand_chacha 0.3.0",
|
"rand_chacha 0.3.0",
|
||||||
|
@ -3553,7 +3554,7 @@ checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"libc",
|
"libc",
|
||||||
"rand 0.8.3",
|
"rand 0.8.4",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"remove_dir_all",
|
"remove_dir_all",
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
|
@ -3831,7 +3832,7 @@ dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
"radix_trie",
|
"radix_trie",
|
||||||
"rand 0.8.3",
|
"rand 0.8.4",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"trust-dns-proto",
|
"trust-dns-proto",
|
||||||
|
@ -3854,7 +3855,7 @@ dependencies = [
|
||||||
"ipnet",
|
"ipnet",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
"rand 0.8.3",
|
"rand 0.8.4",
|
||||||
"serde",
|
"serde",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
@ -3926,7 +3927,7 @@ dependencies = [
|
||||||
"httparse",
|
"httparse",
|
||||||
"input_buffer",
|
"input_buffer",
|
||||||
"log",
|
"log",
|
||||||
"rand 0.8.3",
|
"rand 0.8.4",
|
||||||
"rustls",
|
"rustls",
|
||||||
"sha-1",
|
"sha-1",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
|
|
@ -71,6 +71,7 @@ num_cpus = "1.13.0"
|
||||||
percent-encoding = "2.1.0"
|
percent-encoding = "2.1.0"
|
||||||
pin-project = "1.0.6"
|
pin-project = "1.0.6"
|
||||||
regex = "1.4.3"
|
regex = "1.4.3"
|
||||||
|
rand = { version = "0.8.3", features = [ "small_rng" ] }
|
||||||
ring = "0.16.20"
|
ring = "0.16.20"
|
||||||
rustyline = { version = "8.0.0", default-features = false }
|
rustyline = { version = "8.0.0", default-features = false }
|
||||||
rustyline-derive = "0.4.0"
|
rustyline-derive = "0.4.0"
|
||||||
|
|
29
cli/flags.rs
29
cli/flags.rs
|
@ -103,6 +103,7 @@ pub enum DenoSubcommand {
|
||||||
allow_none: bool,
|
allow_none: bool,
|
||||||
include: Option<Vec<String>>,
|
include: Option<Vec<String>>,
|
||||||
filter: Option<String>,
|
filter: Option<String>,
|
||||||
|
shuffle: Option<u64>,
|
||||||
concurrent_jobs: usize,
|
concurrent_jobs: usize,
|
||||||
},
|
},
|
||||||
Types,
|
Types,
|
||||||
|
@ -1016,6 +1017,20 @@ fn test_subcommand<'a, 'b>() -> App<'a, 'b> {
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.help("Run tests with this string or pattern in the test name"),
|
.help("Run tests with this string or pattern in the test name"),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("shuffle")
|
||||||
|
.long("shuffle")
|
||||||
|
.value_name("NUMBER")
|
||||||
|
.help("(UNSTABLE): Shuffle the order in which the tests are run")
|
||||||
|
.min_values(0)
|
||||||
|
.max_values(1)
|
||||||
|
.require_equals(true)
|
||||||
|
.takes_value(true)
|
||||||
|
.validator(|val: String| match val.parse::<u64>() {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(_) => Err("Shuffle seed should be a number".to_string()),
|
||||||
|
}),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("coverage")
|
Arg::with_name("coverage")
|
||||||
.long("coverage")
|
.long("coverage")
|
||||||
|
@ -1686,7 +1701,17 @@ fn test_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
|
||||||
let quiet = matches.is_present("quiet");
|
let quiet = matches.is_present("quiet");
|
||||||
let filter = matches.value_of("filter").map(String::from);
|
let filter = matches.value_of("filter").map(String::from);
|
||||||
|
|
||||||
flags.watch = matches.is_present("watch");
|
let shuffle = if matches.is_present("shuffle") {
|
||||||
|
let value = if let Some(value) = matches.value_of("shuffle") {
|
||||||
|
value.parse::<u64>().unwrap()
|
||||||
|
} else {
|
||||||
|
rand::random::<u64>()
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(value)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
if matches.is_present("script_arg") {
|
if matches.is_present("script_arg") {
|
||||||
let script_arg: Vec<String> = matches
|
let script_arg: Vec<String> = matches
|
||||||
|
@ -1730,6 +1755,7 @@ fn test_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
|
||||||
quiet,
|
quiet,
|
||||||
include,
|
include,
|
||||||
filter,
|
filter,
|
||||||
|
shuffle,
|
||||||
allow_none,
|
allow_none,
|
||||||
concurrent_jobs,
|
concurrent_jobs,
|
||||||
};
|
};
|
||||||
|
@ -3366,6 +3392,7 @@ mod tests {
|
||||||
allow_none: true,
|
allow_none: true,
|
||||||
quiet: false,
|
quiet: false,
|
||||||
include: Some(svec!["dir1/", "dir2/"]),
|
include: Some(svec!["dir1/", "dir2/"]),
|
||||||
|
shuffle: None,
|
||||||
concurrent_jobs: 1,
|
concurrent_jobs: 1,
|
||||||
},
|
},
|
||||||
unstable: true,
|
unstable: true,
|
||||||
|
|
|
@ -984,6 +984,7 @@ async fn test_command(
|
||||||
quiet: bool,
|
quiet: bool,
|
||||||
allow_none: bool,
|
allow_none: bool,
|
||||||
filter: Option<String>,
|
filter: Option<String>,
|
||||||
|
shuffle: Option<u64>,
|
||||||
concurrent_jobs: usize,
|
concurrent_jobs: usize,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
if let Some(ref coverage_dir) = flags.coverage_dir {
|
if let Some(ref coverage_dir) = flags.coverage_dir {
|
||||||
|
@ -1172,6 +1173,7 @@ async fn test_command(
|
||||||
quiet,
|
quiet,
|
||||||
true,
|
true,
|
||||||
filter.clone(),
|
filter.clone(),
|
||||||
|
shuffle,
|
||||||
concurrent_jobs,
|
concurrent_jobs,
|
||||||
)
|
)
|
||||||
.map(|res| res.map(|_| ()))
|
.map(|res| res.map(|_| ()))
|
||||||
|
@ -1207,6 +1209,7 @@ async fn test_command(
|
||||||
quiet,
|
quiet,
|
||||||
allow_none,
|
allow_none,
|
||||||
filter,
|
filter,
|
||||||
|
shuffle,
|
||||||
concurrent_jobs,
|
concurrent_jobs,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -1314,6 +1317,7 @@ fn get_subcommand(
|
||||||
include,
|
include,
|
||||||
allow_none,
|
allow_none,
|
||||||
filter,
|
filter,
|
||||||
|
shuffle,
|
||||||
concurrent_jobs,
|
concurrent_jobs,
|
||||||
} => test_command(
|
} => test_command(
|
||||||
flags,
|
flags,
|
||||||
|
@ -1324,6 +1328,7 @@ fn get_subcommand(
|
||||||
quiet,
|
quiet,
|
||||||
allow_none,
|
allow_none,
|
||||||
filter,
|
filter,
|
||||||
|
shuffle,
|
||||||
concurrent_jobs,
|
concurrent_jobs,
|
||||||
)
|
)
|
||||||
.boxed_local(),
|
.boxed_local(),
|
||||||
|
|
|
@ -114,3 +114,15 @@ itest!(unhandled_rejection {
|
||||||
exit_code: 1,
|
exit_code: 1,
|
||||||
output: "test/unhandled_rejection.out",
|
output: "test/unhandled_rejection.out",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
itest!(shuffle {
|
||||||
|
args: "test --shuffle test/shuffle",
|
||||||
|
exit_code: 0,
|
||||||
|
output_str: Some("[WILDCARD]"),
|
||||||
|
});
|
||||||
|
|
||||||
|
itest!(shuffle_with_seed {
|
||||||
|
args: "test --shuffle=42 test/shuffle",
|
||||||
|
exit_code: 0,
|
||||||
|
output: "test/shuffle.out",
|
||||||
|
});
|
||||||
|
|
39
cli/tests/test/shuffle.out
Normal file
39
cli/tests/test/shuffle.out
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
Check [WILDCARD]/test/shuffle/foo_test.ts
|
||||||
|
Check [WILDCARD]/test/shuffle/baz_test.ts
|
||||||
|
Check [WILDCARD]/test/shuffle/bar_test.ts
|
||||||
|
running 10 tests from [WILDCARD]/test/shuffle/foo_test.ts
|
||||||
|
test test 2 ... ok ([WILDCARD])
|
||||||
|
test test 3 ... ok ([WILDCARD])
|
||||||
|
test test 6 ... ok ([WILDCARD])
|
||||||
|
test test 9 ... ok ([WILDCARD])
|
||||||
|
test test 8 ... ok ([WILDCARD])
|
||||||
|
test test 7 ... ok ([WILDCARD])
|
||||||
|
test test 5 ... ok ([WILDCARD])
|
||||||
|
test test 4 ... ok ([WILDCARD])
|
||||||
|
test test 1 ... ok ([WILDCARD])
|
||||||
|
test test 0 ... ok ([WILDCARD])
|
||||||
|
running 10 tests from [WILDCARD]/test/shuffle/baz_test.ts
|
||||||
|
test test 2 ... ok ([WILDCARD])
|
||||||
|
test test 3 ... ok ([WILDCARD])
|
||||||
|
test test 6 ... ok ([WILDCARD])
|
||||||
|
test test 9 ... ok ([WILDCARD])
|
||||||
|
test test 8 ... ok ([WILDCARD])
|
||||||
|
test test 7 ... ok ([WILDCARD])
|
||||||
|
test test 5 ... ok ([WILDCARD])
|
||||||
|
test test 4 ... ok ([WILDCARD])
|
||||||
|
test test 1 ... ok ([WILDCARD])
|
||||||
|
test test 0 ... ok ([WILDCARD])
|
||||||
|
running 10 tests from [WILDCARD]/test/shuffle/bar_test.ts
|
||||||
|
test test 2 ... ok ([WILDCARD])
|
||||||
|
test test 3 ... ok ([WILDCARD])
|
||||||
|
test test 6 ... ok ([WILDCARD])
|
||||||
|
test test 9 ... ok ([WILDCARD])
|
||||||
|
test test 8 ... ok ([WILDCARD])
|
||||||
|
test test 7 ... ok ([WILDCARD])
|
||||||
|
test test 5 ... ok ([WILDCARD])
|
||||||
|
test test 4 ... ok ([WILDCARD])
|
||||||
|
test test 1 ... ok ([WILDCARD])
|
||||||
|
test test 0 ... ok ([WILDCARD])
|
||||||
|
|
||||||
|
test result: ok. 30 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ([WILDCARD])
|
||||||
|
|
3
cli/tests/test/shuffle/bar_test.ts
Normal file
3
cli/tests/test/shuffle/bar_test.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
Deno.test(`test ${i}`, () => {});
|
||||||
|
}
|
3
cli/tests/test/shuffle/baz_test.ts
Normal file
3
cli/tests/test/shuffle/baz_test.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
Deno.test(`test ${i}`, () => {});
|
||||||
|
}
|
3
cli/tests/test/shuffle/foo_test.ts
Normal file
3
cli/tests/test/shuffle/foo_test.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
Deno.test(`test ${i}`, () => {});
|
||||||
|
}
|
|
@ -21,6 +21,9 @@ use deno_core::serde_json::json;
|
||||||
use deno_core::url::Url;
|
use deno_core::url::Url;
|
||||||
use deno_core::ModuleSpecifier;
|
use deno_core::ModuleSpecifier;
|
||||||
use deno_runtime::permissions::Permissions;
|
use deno_runtime::permissions::Permissions;
|
||||||
|
use rand::rngs::SmallRng;
|
||||||
|
use rand::seq::SliceRandom;
|
||||||
|
use rand::SeedableRng;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
@ -343,8 +346,19 @@ pub async fn run_tests(
|
||||||
quiet: bool,
|
quiet: bool,
|
||||||
allow_none: bool,
|
allow_none: bool,
|
||||||
filter: Option<String>,
|
filter: Option<String>,
|
||||||
|
shuffle: Option<u64>,
|
||||||
concurrent_jobs: usize,
|
concurrent_jobs: usize,
|
||||||
) -> Result<bool, AnyError> {
|
) -> Result<bool, AnyError> {
|
||||||
|
let test_modules = if let Some(seed) = shuffle {
|
||||||
|
let mut rng = SmallRng::seed_from_u64(seed);
|
||||||
|
let mut test_modules = test_modules.clone();
|
||||||
|
test_modules.sort();
|
||||||
|
test_modules.shuffle(&mut rng);
|
||||||
|
test_modules
|
||||||
|
} else {
|
||||||
|
test_modules
|
||||||
|
};
|
||||||
|
|
||||||
if !doc_modules.is_empty() {
|
if !doc_modules.is_empty() {
|
||||||
let mut test_programs = Vec::new();
|
let mut test_programs = Vec::new();
|
||||||
|
|
||||||
|
@ -450,6 +464,7 @@ pub async fn run_tests(
|
||||||
let test_options = json!({
|
let test_options = json!({
|
||||||
"disableLog": quiet,
|
"disableLog": quiet,
|
||||||
"filter": filter,
|
"filter": filter,
|
||||||
|
"shuffle": shuffle,
|
||||||
});
|
});
|
||||||
|
|
||||||
let test_module = deno_core::resolve_path("$deno$test.js")?;
|
let test_module = deno_core::resolve_path("$deno$test.js")?;
|
||||||
|
|
|
@ -217,6 +217,7 @@ finishing test case.`;
|
||||||
async function runTests({
|
async function runTests({
|
||||||
disableLog = false,
|
disableLog = false,
|
||||||
filter = null,
|
filter = null,
|
||||||
|
shuffle = null,
|
||||||
} = {}) {
|
} = {}) {
|
||||||
const originalConsole = globalThis.console;
|
const originalConsole = globalThis.console;
|
||||||
if (disableLog) {
|
if (disableLog) {
|
||||||
|
@ -234,6 +235,24 @@ finishing test case.`;
|
||||||
only: only.length > 0,
|
only: only.length > 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (shuffle !== null) {
|
||||||
|
// http://en.wikipedia.org/wiki/Linear_congruential_generator
|
||||||
|
const nextInt = (function (state) {
|
||||||
|
const m = 0x80000000;
|
||||||
|
const a = 1103515245;
|
||||||
|
const c = 12345;
|
||||||
|
|
||||||
|
return function (max) {
|
||||||
|
return state = ((a * state + c) % m) % max;
|
||||||
|
};
|
||||||
|
}(shuffle));
|
||||||
|
|
||||||
|
for (let i = pending.length - 1; i > 0; i--) {
|
||||||
|
const j = nextInt(i);
|
||||||
|
[pending[i], pending[j]] = [pending[j], pending[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const test of pending) {
|
for (const test of pending) {
|
||||||
const {
|
const {
|
||||||
name,
|
name,
|
||||||
|
|
Loading…
Reference in a new issue