Refactor system tests to use assert_cmd

This commit is contained in:
Ted Mielczarek 2018-07-27 12:07:08 -04:00
Родитель a8606b1203
Коммит 13701e3903
3 изменённых файлов: 115 добавлений и 103 удалений

8
Cargo.lock сгенерированный
Просмотреть файл

@ -20,7 +20,7 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"escargot 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "escargot 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"predicates 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "predicates 0.5.2 (git+https://github.com/luser/predicates-rs?branch=function-unsized)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -742,7 +742,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "predicates" name = "predicates"
version = "0.5.2" version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/luser/predicates-rs?branch=function-unsized#56592bae5e0dbce03b0d6f82a5063844d336c91a"
dependencies = [ dependencies = [
"difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"float-cmp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "float-cmp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -964,7 +964,7 @@ dependencies = [
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)", "openssl 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)",
"predicates 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "predicates 0.5.2 (git+https://github.com/luser/predicates-rs?branch=function-unsized)",
"redis 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "redis 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"retry 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "retry 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1618,7 +1618,7 @@ dependencies = [
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
"checksum podio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "780fb4b6698bbf9cf2444ea5d22411cef2953f0824b98f33cf454ec5615645bd" "checksum podio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "780fb4b6698bbf9cf2444ea5d22411cef2953f0824b98f33cf454ec5615645bd"
"checksum predicates 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f3dc50ff273939a7688f8bccd748add1a0822dd6a9aa132b52600c7c45cc6409" "checksum predicates 0.5.2 (git+https://github.com/luser/predicates-rs?branch=function-unsized)" = "<none>"
"checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07" "checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
"checksum rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "512870020642bb8c221bf68baa1b2573da814f6ccfe5c9699b1c303047abe9b1" "checksum rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "512870020642bb8c221bf68baa1b2573da814f6ccfe5c9699b1c303047abe9b1"

Просмотреть файл

@ -96,3 +96,6 @@ unstable = []
[workspace] [workspace]
exclude = ["tests/test-crate"] exclude = ["tests/test-crate"]
[patch.crates-io]
predicates = { git = "https://github.com/luser/predicates-rs", branch = "function-unsized" }

Просмотреть файл

@ -16,16 +16,20 @@
#![allow(dead_code, unused_imports)] #![allow(dead_code, unused_imports)]
extern crate assert_cmd;
extern crate cc; extern crate cc;
extern crate env_logger; extern crate env_logger;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
extern crate predicates;
extern crate sccache; extern crate sccache;
extern crate serde_json; extern crate serde_json;
extern crate tempdir; extern crate tempdir;
extern crate which; extern crate which;
use assert_cmd::prelude::*;
use log::LogLevel::Trace; use log::LogLevel::Trace;
use predicates::prelude::*;
use sccache::server::ServerInfo; use sccache::server::ServerInfo;
use std::collections::HashMap; use std::collections::HashMap;
use std::env; use std::env;
@ -39,10 +43,10 @@ use std::process::{
Output, Output,
Stdio, Stdio,
}; };
use std::str;
use tempdir::TempDir; use tempdir::TempDir;
use which::which_in; use which::which_in;
struct Compiler { struct Compiler {
pub name: &'static str, pub name: &'static str,
pub exe: OsString, pub exe: OsString,
@ -59,59 +63,22 @@ const COMPILERS: &'static [&'static str] = &["clang"];
//TODO: could test gcc when targeting mingw. //TODO: could test gcc when targeting mingw.
fn find_sccache_binary() -> PathBuf { fn stop() {
// Older versions of cargo put the test binary next to the sccache binary. trace!("sccache --stop-server");
// Newer versions put it in the deps/ subdirectory. drop(Command::main_binary().unwrap()
let exe = env::current_exe().unwrap(); .arg("--stop-server")
let this_dir = exe.parent().unwrap(); .stdout(Stdio::null())
let dirs = &[&this_dir, &this_dir.parent().unwrap()]; .stderr(Stdio::null())
dirs .status());
.iter()
.map(|d| d.join("sccache").with_extension(env::consts::EXE_EXTENSION))
.filter_map(|d| fs::metadata(&d).ok().map(|_| d))
.next()
.expect(&format!("Error: sccache binary not found, looked in `{:?}`. Do you need to run `cargo build`?", dirs))
} }
fn do_run<T: AsRef<OsStr>>(exe: &Path, args: &[T], cwd: &Path, env_vars: &[(OsString, OsString)]) -> Output { fn zero_stats() {
let mut cmd = Command::new(exe); trace!("sccache --zero-stats");
cmd.args(args) drop(Command::main_binary().unwrap()
.current_dir(cwd) .arg("--zero-stats")
.stdout(Stdio::piped()) .stdout(Stdio::null())
.stderr(Stdio::piped()); .stderr(Stdio::null())
for &(ref k, ref v) in env_vars.iter() { .status());
cmd.env(k, v);
}
trace!("do_run: {:?}", cmd);
cmd.spawn()
.unwrap_or_else(|e| { panic!("failed to execute child: {}", e) })
.wait_with_output()
.unwrap()
}
fn run_stdout<T>(exe: &Path, args: &[T], cwd: &Path, env_vars: &[(OsString, OsString)]) -> String
where T: AsRef<OsStr> + fmt::Debug,
{
let output = do_run(exe, args, cwd, env_vars);
assert!(output.status.success(), "Failed to run {:?} {:?}", exe, args);
String::from_utf8(output.stdout).expect("Couldn't convert stdout to String")
}
fn run<T: AsRef<OsStr>>(exe: &Path, args: &[T], cwd: &Path, env_vars: &[(OsString, OsString)]) -> bool {
let output = do_run(exe, args, cwd, env_vars);
if output.status.success() {
true
} else {
let va = args.iter().map(|a| a.as_ref().to_str().unwrap()).collect::<Vec<_>>();
println!("Process `{:?} {}` failed:", exe, va.join(" "));
print!("stdout: `");
io::stdout().write(&output.stdout).unwrap();
println!("`");
print!("stderr: `");
io::stdout().write(&output.stderr).unwrap();
println!("`");
false
}
} }
macro_rules! vec_from { macro_rules! vec_from {
@ -128,9 +95,16 @@ fn compile_cmdline<T: AsRef<OsStr>>(compiler: &str, exe: T, input: &str, output:
} }
} }
fn get_stats(sccache: &Path, cwd: &Path) -> ServerInfo { fn get_stats<F: 'static + Fn(ServerInfo)>(f: F) {
let output = run_stdout(sccache, &["--show-stats", "--stats-format=json"], cwd, &[]); Command::main_binary().unwrap()
serde_json::from_str(&output).expect("Failed to parse JSON stats") .args(&["--show-stats", "--stats-format=json"])
.assert()
.success()
.stdout(predicate::function(move |output: &[u8]| {
let s = str::from_utf8(output).expect("Output not UTF-8");
f(serde_json::from_str(s).expect("Failed to parse JSON stats"));
true
}));
} }
fn write_source(path: &Path, filename: &str, contents: &str) { fn write_source(path: &Path, filename: &str, contents: &str) {
@ -139,11 +113,10 @@ fn write_source(path: &Path, filename: &str, contents: &str) {
f.write_all(contents.as_bytes()).unwrap(); f.write_all(contents.as_bytes()).unwrap();
} }
fn run_sccache_command_test(sccache: &Path, compiler: Compiler, tempdir: &Path) { fn run_sccache_command_test(compiler: Compiler, tempdir: &Path) {
let Compiler { name, exe, env_vars } = compiler; let Compiler { name, exe, env_vars } = compiler;
// Ensure there's no existing sccache server running. // Ensure there's no existing sccache server running.
trace!("stop server"); stop();
do_run(sccache, &["--stop-server"], tempdir, &[]);
// Create a subdir for the cache. // Create a subdir for the cache.
let cache = tempdir.join("cache"); let cache = tempdir.join("cache");
fs::create_dir_all(&cache).unwrap(); fs::create_dir_all(&cache).unwrap();
@ -151,13 +124,12 @@ fn run_sccache_command_test(sccache: &Path, compiler: Compiler, tempdir: &Path)
trace!("start server"); trace!("start server");
// Don't run this with run() because on Windows `wait_with_output` // Don't run this with run() because on Windows `wait_with_output`
// will hang because the internal server process is not detached. // will hang because the internal server process is not detached.
assert!(Command::new(sccache) Command::main_binary().unwrap()
.arg("--start-server") .arg("--start-server")
.current_dir(tempdir) .env("SCCACHE_DIR", &cache)
.env("SCCACHE_DIR", &cache) .status()
.status() .unwrap()
.unwrap() .success();
.success());
trace!("run_sccache_command_test: {}", name); trace!("run_sccache_command_test: {}", name);
// Compile a source file. // Compile a source file.
const INPUT: &'static str = "test.c"; const INPUT: &'static str = "test.c";
@ -173,30 +145,47 @@ fn run_sccache_command_test(sccache: &Path, compiler: Compiler, tempdir: &Path)
let out_file = tempdir.join("test.o"); let out_file = tempdir.join("test.o");
trace!("compile"); trace!("compile");
assert_eq!(true, run(sccache, &compile_cmdline(name, &exe, INPUT, OUTPUT), tempdir, &env_vars)); Command::main_binary().unwrap()
.args(&compile_cmdline(name, &exe, INPUT, OUTPUT))
.current_dir(tempdir)
.envs(env_vars.clone())
.assert()
.success();
assert_eq!(true, fs::metadata(&out_file).and_then(|m| Ok(m.len() > 0)).unwrap()); assert_eq!(true, fs::metadata(&out_file).and_then(|m| Ok(m.len() > 0)).unwrap());
trace!("request stats"); trace!("request stats");
let info = get_stats(sccache, tempdir); get_stats(|info| {
assert_eq!(1, info.stats.compile_requests); assert_eq!(1, info.stats.compile_requests);
assert_eq!(1, info.stats.requests_executed); assert_eq!(1, info.stats.requests_executed);
assert_eq!(0, info.stats.cache_hits); assert_eq!(0, info.stats.cache_hits);
assert_eq!(1, info.stats.cache_misses); assert_eq!(1, info.stats.cache_misses);
});
trace!("compile"); trace!("compile");
fs::remove_file(&out_file).unwrap(); fs::remove_file(&out_file).unwrap();
assert_eq!(true, run(sccache, &compile_cmdline(name, &exe, INPUT, OUTPUT), tempdir, &env_vars)); Command::main_binary().unwrap()
.args(&compile_cmdline(name, &exe, INPUT, OUTPUT))
.current_dir(tempdir)
.envs(env_vars.clone())
.assert()
.success();
assert_eq!(true, fs::metadata(&out_file).and_then(|m| Ok(m.len() > 0)).unwrap()); assert_eq!(true, fs::metadata(&out_file).and_then(|m| Ok(m.len() > 0)).unwrap());
trace!("request stats"); trace!("request stats");
let info = get_stats(sccache, tempdir); get_stats(|info| {
assert_eq!(2, info.stats.compile_requests); assert_eq!(2, info.stats.compile_requests);
assert_eq!(2, info.stats.requests_executed); assert_eq!(2, info.stats.requests_executed);
assert_eq!(1, info.stats.cache_hits); assert_eq!(1, info.stats.cache_hits);
assert_eq!(1, info.stats.cache_misses); assert_eq!(1, info.stats.cache_misses);
});
if name == "cl.exe" { if name == "cl.exe" {
// Check that -deps works. // Check that -deps works.
trace!("compile with -deps"); trace!("compile with -deps");
let mut args = compile_cmdline(name, &exe, INPUT, OUTPUT); let mut args = compile_cmdline(name, &exe, INPUT, OUTPUT);
args.push("-depstest.d".into()); args.push("-depstest.d".into());
assert_eq!(true, run(sccache, &args, tempdir, &env_vars)); Command::main_binary().unwrap()
.args(&args)
.current_dir(tempdir)
.envs(env_vars.clone())
.assert()
.success();
// Check the contents // Check the contents
let mut f = File::open(tempdir.join("test.d")).expect("Failed to open dep file"); let mut f = File::open(tempdir.join("test.d")).expect("Failed to open dep file");
let mut buf = String::new(); let mut buf = String::new();
@ -212,14 +201,17 @@ fn run_sccache_command_test(sccache: &Path, compiler: Compiler, tempdir: &Path)
trace!("test -MP with -Werror"); trace!("test -MP with -Werror");
let mut args = compile_cmdline(name, &exe, INPUT_ERR, OUTPUT); let mut args = compile_cmdline(name, &exe, INPUT_ERR, OUTPUT);
args.extend(vec_from!(OsString, "-MD", "-MP", "-MF", "foo.pp", "-Werror")); args.extend(vec_from!(OsString, "-MD", "-MP", "-MF", "foo.pp", "-Werror"));
let output = do_run(sccache, &args, tempdir, &env_vars);
assert!(!output.status.success());
// This should fail, but the error should be from the #error! // This should fail, but the error should be from the #error!
let stderr = String::from_utf8(output.stderr).expect("Couldn't convert stderr to String"); Command::main_binary().unwrap()
assert!(stderr.find("to generate dependencies you must specify either -M or -MM").is_none(), "Should not have complained about commandline arguments"); .args(&args)
.current_dir(tempdir)
.envs(env_vars.clone())
.assert()
.failure()
.stderr(predicates::str::contains(
"to generate dependencies you must specify either -M or -MM").from_utf8().not());
trace!("test -fprofile-generate with different source inputs"); trace!("test -fprofile-generate with different source inputs");
do_run(sccache, &["--zero-stats"], tempdir, &[]); zero_stats();
const SRC: &str = "source.c"; const SRC: &str = "source.c";
write_source(&tempdir, SRC, "/*line 1*/ write_source(&tempdir, SRC, "/*line 1*/
#ifndef UNDEFINED #ifndef UNDEFINED
@ -233,16 +225,28 @@ int main(int argc, char** argv) {
let mut args = compile_cmdline(name, &exe, SRC, OUTPUT); let mut args = compile_cmdline(name, &exe, SRC, OUTPUT);
args.extend(vec_from!(OsString, "-fprofile-generate")); args.extend(vec_from!(OsString, "-fprofile-generate"));
trace!("compile source.c (1)"); trace!("compile source.c (1)");
assert_eq!(true, run(sccache, &args, tempdir, &env_vars)); Command::main_binary().unwrap()
let info = get_stats(sccache, tempdir); .args(&args)
assert_eq!(0, info.stats.cache_hits); .current_dir(tempdir)
assert_eq!(1, info.stats.cache_misses); .envs(env_vars.clone())
.assert()
.success();
get_stats(|info| {
assert_eq!(0, info.stats.cache_hits);
assert_eq!(1, info.stats.cache_misses);
});
// Compile the same source again to ensure we can get a cache hit. // Compile the same source again to ensure we can get a cache hit.
trace!("compile source.c (2)"); trace!("compile source.c (2)");
assert_eq!(true, run(sccache, &args, tempdir, &env_vars)); Command::main_binary().unwrap()
let info = get_stats(sccache, tempdir); .args(&args)
assert_eq!(1, info.stats.cache_hits); .current_dir(tempdir)
assert_eq!(1, info.stats.cache_misses); .envs(env_vars.clone())
.assert()
.success();
get_stats(|info| {
assert_eq!(1, info.stats.cache_hits);
assert_eq!(1, info.stats.cache_misses);
});
// Now write out a slightly different source file that will preprocess to the same thing, // Now write out a slightly different source file that will preprocess to the same thing,
// modulo line numbers. This should not be a cache hit because line numbers are important // modulo line numbers. This should not be a cache hit because line numbers are important
// with -fprofile-generate. // with -fprofile-generate.
@ -257,13 +261,19 @@ int main(int argc, char** argv) {
} }
"); ");
trace!("compile source.c (3)"); trace!("compile source.c (3)");
assert_eq!(true, run(sccache, &args, tempdir, &env_vars)); Command::main_binary().unwrap()
let info = get_stats(sccache, tempdir); .args(&args)
assert_eq!(1, info.stats.cache_hits); .current_dir(tempdir)
assert_eq!(2, info.stats.cache_misses); .envs(env_vars.clone())
.assert()
.success();
get_stats(|info| {
assert_eq!(1, info.stats.cache_hits);
assert_eq!(2, info.stats.cache_misses);
});
} }
trace!("stop server"); trace!("stop server");
assert_eq!(true, run(sccache, &["--stop-server"], tempdir, &[])); stop();
} }
#[cfg(unix)] #[cfg(unix)]
@ -311,13 +321,12 @@ fn test_sccache_command() {
Err(_) => {}, Err(_) => {},
} }
let tempdir = TempDir::new("sccache_system_test").unwrap(); let tempdir = TempDir::new("sccache_system_test").unwrap();
let sccache = find_sccache_binary();
let compilers = find_compilers(); let compilers = find_compilers();
if compilers.is_empty() { if compilers.is_empty() {
warn!("No compilers found, skipping test"); warn!("No compilers found, skipping test");
} else { } else {
for compiler in compilers { for compiler in compilers {
run_sccache_command_test(&sccache, compiler, tempdir.path()) run_sccache_command_test(compiler, tempdir.path())
} }
} }
} }