Add tests to rustbuild

In order to run tests, previous commits have cfg'd out various parts of
rustbuild. Generally speaking, these are filesystem-related operations
and process-spawning related parts. Then, rustbuild is run "as normal"
and the various steps that where run are retrieved from the cache and
checked against the expected results.

Note that this means that the current implementation primarily tests
"what" we build, but doesn't actually test that what we build *will*
build. In other words, it doesn't do any form of dependency verification
for any crate. This is possible to implement, but is considered future
work.

This implementation strives to cfg out as little code as possible; it
also does not currently test anywhere near all of rustbuild. The current
tests are also not checked for "correctness," rather, they simply
represent what we do as of this commit, which may be wrong.

Test cases are drawn from the old implementation of rustbuild, though
the expected results may vary.
This commit is contained in:
Mark Simulacrum 2018-03-10 07:03:06 -07:00
parent 8fd42ec130
commit 42fde21c27
6 changed files with 514 additions and 2 deletions

17
src/Cargo.lock generated
View File

@ -124,6 +124,7 @@ dependencies = [
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
@ -528,6 +529,11 @@ name = "diff"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "difference"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "dlmalloc"
version = "0.0.0"
@ -1233,6 +1239,15 @@ name = "pkg-config"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "pretty_assertions"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "proc-macro2"
version = "0.2.3"
@ -2683,6 +2698,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum curl-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f46e49c7125131f5afaded06944d6888b55cbdf8eba05dae73c954019b907961"
"checksum derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6fcb923bab47a948f1b01cec2f758fdebba95c9ebc255458654b2b88efe59d71"
"checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a"
"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
"checksum ena 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b449f3b18c89d2dbe40548d2ee4fa58ea0a08b761992da6ecb9788e4688834"
@ -2755,6 +2771,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0fce5d8b5cc33983fc74f78ad552b5522ab41442c4ca91606e4236eb4b5ceefc"
"checksum pest_derive 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ab94faafeb93f4c5e3ce81ca0e5a779529a602ad5d09ae6d21996bfb8b6a52bf"
"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
"checksum pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a029430f0d744bc3d15dd474d591bed2402b645d024583082b9f63bb936dac6"
"checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0"
"checksum proc-macro2 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "388d7ea47318c5ccdeb9ba6312cee7d3f65dd2804be8580a170fce410d50b786"
"checksum pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdf85cda6cadfae5428a54661d431330b312bc767ddbc57adbedc24da66e32"

View File

@ -42,3 +42,6 @@ serde_json = "1.0.2"
toml = "0.4"
lazy_static = "0.2"
time = "0.1"
[dev-dependencies]
pretty_assertions = "0.5"

View File

@ -401,12 +401,16 @@ impl<'a> Builder<'a> {
}
pub fn execute_cli(&self) {
StepDescription::run(&Builder::get_step_descriptions(self.kind), self, &self.paths);
self.run_step_descriptions(&Builder::get_step_descriptions(self.kind), &self.paths);
}
pub fn default_doc(&self, paths: Option<&[PathBuf]>) {
let paths = paths.unwrap_or(&[]);
StepDescription::run(&Builder::get_step_descriptions(Kind::Doc), self, paths);
self.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), paths);
}
fn run_step_descriptions(&self, v: &[StepDescription], paths: &[PathBuf]) {
StepDescription::run(v, self, paths);
}
/// Obtain a compiler at a given stage and for a given host. Explicitly does
@ -862,3 +866,474 @@ impl<'a> Builder<'a> {
out
}
}
#[cfg(test)]
mod __test {
use config::Config;
use super::*;
fn configure(host: &[&str], target: &[&str]) -> Config {
let mut config = Config::default_opts();
config.run_host_only = true;
config.build = INTERNER.intern_str("A");
config.hosts = vec![config.build].clone().into_iter()
.chain(host.iter().map(|s| INTERNER.intern_str(s))).collect::<Vec<_>>();
config.targets = config.hosts.clone().into_iter()
.chain(target.iter().map(|s| INTERNER.intern_str(s))).collect::<Vec<_>>();
config
}
fn first<A, B>(v: Vec<(A, B)>) -> Vec<A> {
v.into_iter().map(|(a, _)| a).collect::<Vec<_>>()
}
#[test]
fn dist_baseline() {
let build = Build::new(configure(&[], &[]));
let mut builder = Builder::new(&build);
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
let a = INTERNER.intern_str("A");
assert_eq!(first(builder.cache.all::<dist::Docs>()), &[
dist::Docs { stage: 2, host: a },
]);
assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[
dist::Mingw { host: a },
]);
assert_eq!(first(builder.cache.all::<dist::Rustc>()), &[
dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
]);
assert_eq!(first(builder.cache.all::<dist::Std>()), &[
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: a,
},
]);
assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
}
#[test]
fn dist_with_targets() {
let build = Build::new(configure(&[], &["B"]));
let mut builder = Builder::new(&build);
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
let a = INTERNER.intern_str("A");
let b = INTERNER.intern_str("B");
assert_eq!(first(builder.cache.all::<dist::Docs>()), &[
dist::Docs { stage: 2, host: a },
dist::Docs { stage: 2, host: b },
]);
assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[
dist::Mingw { host: a },
dist::Mingw { host: b },
]);
assert_eq!(first(builder.cache.all::<dist::Rustc>()), &[
dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
]);
assert_eq!(first(builder.cache.all::<dist::Std>()), &[
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: a,
},
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: b,
},
]);
assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
}
#[test]
fn dist_with_hosts() {
let build = Build::new(configure(&["B"], &[]));
let mut builder = Builder::new(&build);
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
let a = INTERNER.intern_str("A");
let b = INTERNER.intern_str("B");
assert_eq!(first(builder.cache.all::<dist::Docs>()), &[
dist::Docs { stage: 2, host: a },
dist::Docs { stage: 2, host: b },
]);
assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[
dist::Mingw { host: a },
dist::Mingw { host: b },
]);
assert_eq!(first(builder.cache.all::<dist::Rustc>()), &[
dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
]);
assert_eq!(first(builder.cache.all::<dist::Std>()), &[
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: a,
},
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: b,
},
]);
assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
}
#[test]
fn dist_with_targets_and_hosts() {
let build = Build::new(configure(&["B"], &["C"]));
let mut builder = Builder::new(&build);
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
let a = INTERNER.intern_str("A");
let b = INTERNER.intern_str("B");
let c = INTERNER.intern_str("C");
assert_eq!(first(builder.cache.all::<dist::Docs>()), &[
dist::Docs { stage: 2, host: a },
dist::Docs { stage: 2, host: b },
dist::Docs { stage: 2, host: c },
]);
assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[
dist::Mingw { host: a },
dist::Mingw { host: b },
dist::Mingw { host: c },
]);
assert_eq!(first(builder.cache.all::<dist::Rustc>()), &[
dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
]);
assert_eq!(first(builder.cache.all::<dist::Std>()), &[
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: a,
},
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: b,
},
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: c,
},
]);
assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
}
#[test]
fn dist_with_target_flag() {
let mut config = configure(&["B"], &["C"]);
config.run_host_only = false; // as-if --target=C was passed
let build = Build::new(config);
let mut builder = Builder::new(&build);
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
let a = INTERNER.intern_str("A");
let b = INTERNER.intern_str("B");
let c = INTERNER.intern_str("C");
assert_eq!(first(builder.cache.all::<dist::Docs>()), &[
dist::Docs { stage: 2, host: a },
dist::Docs { stage: 2, host: b },
dist::Docs { stage: 2, host: c },
]);
assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[
dist::Mingw { host: a },
dist::Mingw { host: b },
dist::Mingw { host: c },
]);
assert_eq!(first(builder.cache.all::<dist::Rustc>()), &[]);
assert_eq!(first(builder.cache.all::<dist::Std>()), &[
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: a,
},
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: b,
},
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: c,
},
]);
assert_eq!(first(builder.cache.all::<dist::Src>()), &[]);
}
#[test]
fn dist_with_same_targets_and_hosts() {
let build = Build::new(configure(&["B"], &["B"]));
let mut builder = Builder::new(&build);
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
let a = INTERNER.intern_str("A");
let b = INTERNER.intern_str("B");
assert_eq!(first(builder.cache.all::<dist::Docs>()), &[
dist::Docs { stage: 2, host: a },
dist::Docs { stage: 2, host: b },
]);
assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[
dist::Mingw { host: a },
dist::Mingw { host: b },
]);
assert_eq!(first(builder.cache.all::<dist::Rustc>()), &[
dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
]);
assert_eq!(first(builder.cache.all::<dist::Std>()), &[
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: a,
},
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: b,
},
]);
assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
assert_eq!(first(builder.cache.all::<compile::Std>()), &[
compile::Std {
compiler: Compiler { host: a, stage: 0 },
target: a,
},
compile::Std {
compiler: Compiler { host: a, stage: 1 },
target: a,
},
compile::Std {
compiler: Compiler { host: a, stage: 2 },
target: a,
},
compile::Std {
compiler: Compiler { host: a, stage: 1 },
target: b,
},
compile::Std {
compiler: Compiler { host: a, stage: 2 },
target: b,
},
]);
assert_eq!(first(builder.cache.all::<compile::Test>()), &[
compile::Test {
compiler: Compiler { host: a, stage: 0 },
target: a,
},
compile::Test {
compiler: Compiler { host: a, stage: 1 },
target: a,
},
compile::Test {
compiler: Compiler { host: a, stage: 2 },
target: a,
},
compile::Test {
compiler: Compiler { host: a, stage: 1 },
target: b,
},
compile::Test {
compiler: Compiler { host: a, stage: 2 },
target: b,
},
]);
assert_eq!(first(builder.cache.all::<compile::Assemble>()), &[
compile::Assemble {
target_compiler: Compiler { host: a, stage: 0 },
},
compile::Assemble {
target_compiler: Compiler { host: a, stage: 1 },
},
compile::Assemble {
target_compiler: Compiler { host: a, stage: 2 },
},
compile::Assemble {
target_compiler: Compiler { host: b, stage: 2 },
},
]);
}
#[test]
fn build_default() {
let build = Build::new(configure(&["B"], &["C"]));
let mut builder = Builder::new(&build);
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
let a = INTERNER.intern_str("A");
let b = INTERNER.intern_str("B");
let c = INTERNER.intern_str("C");
assert!(!builder.cache.all::<compile::Std>().is_empty());
assert!(!builder.cache.all::<compile::Assemble>().is_empty());
assert_eq!(first(builder.cache.all::<compile::Rustc>()), &[
compile::Rustc {
compiler: Compiler { host: a, stage: 0 },
target: a,
},
compile::Rustc {
compiler: Compiler { host: a, stage: 1 },
target: a,
},
compile::Rustc {
compiler: Compiler { host: a, stage: 2 },
target: a,
},
compile::Rustc {
compiler: Compiler { host: b, stage: 2 },
target: a,
},
compile::Rustc {
compiler: Compiler { host: a, stage: 0 },
target: b,
},
compile::Rustc {
compiler: Compiler { host: a, stage: 1 },
target: b,
},
compile::Rustc {
compiler: Compiler { host: a, stage: 2 },
target: b,
},
compile::Rustc {
compiler: Compiler { host: b, stage: 2 },
target: b,
},
]);
assert_eq!(first(builder.cache.all::<compile::Test>()), &[
compile::Test {
compiler: Compiler { host: a, stage: 0 },
target: a,
},
compile::Test {
compiler: Compiler { host: a, stage: 1 },
target: a,
},
compile::Test {
compiler: Compiler { host: a, stage: 2 },
target: a,
},
compile::Test {
compiler: Compiler { host: b, stage: 2 },
target: a,
},
compile::Test {
compiler: Compiler { host: a, stage: 0 },
target: b,
},
compile::Test {
compiler: Compiler { host: a, stage: 1 },
target: b,
},
compile::Test {
compiler: Compiler { host: a, stage: 2 },
target: b,
},
compile::Test {
compiler: Compiler { host: b, stage: 2 },
target: b,
},
compile::Test {
compiler: Compiler { host: a, stage: 2 },
target: c,
},
compile::Test {
compiler: Compiler { host: b, stage: 2 },
target: c,
},
]);
}
#[test]
fn build_with_target_flag() {
let mut config = configure(&["B"], &["C"]);
config.run_host_only = false;
let build = Build::new(config);
let mut builder = Builder::new(&build);
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
let a = INTERNER.intern_str("A");
let b = INTERNER.intern_str("B");
let c = INTERNER.intern_str("C");
assert!(!builder.cache.all::<compile::Std>().is_empty());
assert_eq!(first(builder.cache.all::<compile::Assemble>()), &[
compile::Assemble {
target_compiler: Compiler { host: a, stage: 0 },
},
compile::Assemble {
target_compiler: Compiler { host: a, stage: 1 },
},
compile::Assemble {
target_compiler: Compiler { host: b, stage: 1 },
},
compile::Assemble {
target_compiler: Compiler { host: a, stage: 2 },
},
compile::Assemble {
target_compiler: Compiler { host: b, stage: 2 },
},
]);
assert_eq!(first(builder.cache.all::<compile::Rustc>()), &[
compile::Rustc {
compiler: Compiler { host: a, stage: 0 },
target: a,
},
compile::Rustc {
compiler: Compiler { host: a, stage: 1 },
target: a,
},
compile::Rustc {
compiler: Compiler { host: a, stage: 0 },
target: b,
},
compile::Rustc {
compiler: Compiler { host: a, stage: 1 },
target: b,
},
]);
assert_eq!(first(builder.cache.all::<compile::Test>()), &[
compile::Test {
compiler: Compiler { host: a, stage: 0 },
target: a,
},
compile::Test {
compiler: Compiler { host: a, stage: 1 },
target: a,
},
compile::Test {
compiler: Compiler { host: a, stage: 2 },
target: a,
},
compile::Test {
compiler: Compiler { host: b, stage: 2 },
target: a,
},
compile::Test {
compiler: Compiler { host: a, stage: 0 },
target: b,
},
compile::Test {
compiler: Compiler { host: a, stage: 1 },
target: b,
},
compile::Test {
compiler: Compiler { host: a, stage: 2 },
target: b,
},
compile::Test {
compiler: Compiler { host: b, stage: 2 },
target: b,
},
compile::Test {
compiler: Compiler { host: a, stage: 2 },
target: c,
},
compile::Test {
compiler: Compiler { host: b, stage: 2 },
target: c,
},
]);
}
}

View File

@ -278,4 +278,16 @@ impl Cache {
.expect("invalid type mapped");
stepcache.get(step).cloned()
}
#[cfg(test)]
pub fn all<S: Ord + Copy + Step>(&mut self) -> Vec<(S, S::Output)> {
let cache = self.0.get_mut();
let type_id = TypeId::of::<S>();
let mut v = cache.remove(&type_id)
.map(|b| b.downcast::<HashMap<S, S::Output>>().expect("correct type"))
.map(|m| m.into_iter().collect::<Vec<_>>())
.unwrap_or_default();
v.sort_by_key(|&(a, _)| a);
v
}
}

View File

@ -132,6 +132,10 @@ extern crate num_cpus;
extern crate toml;
extern crate time;
#[cfg(test)]
#[macro_use]
extern crate pretty_assertions;
#[cfg(unix)]
extern crate libc;

View File

@ -1692,6 +1692,7 @@ impl Step for Bootstrap {
let mut cmd = Command::new(&build.initial_cargo);
cmd.arg("test")
.current_dir(build.src.join("src/bootstrap"))
.env("RUSTFLAGS", "-Cdebuginfo=2")
.env("CARGO_TARGET_DIR", build.out.join("bootstrap"))
.env("RUSTC_BOOTSTRAP", "1")
.env("RUSTC", &build.initial_rustc);