#![allow(dead_code, unused_imports)]
use client::connect_with_retry;
use commands::{
DEFAULT_PORT,
request_stats,
};
use env_logger;
use log::LogLevel::Trace;
use std::collections::HashMap;
use std::env;
use std::ffi::{OsStr,OsString};
use std::fs;
use std::io::{
self,
Write,
};
use std::path::{Path,PathBuf};
use std::process::{
Command,
Output,
Stdio,
};
use tempdir::TempDir;
use test::utils::*;
use which::which_in;
#[cfg(all(unix, not(target_os="macos")))]
const COMPILERS: &'static [&'static str] = &["gcc", "clang"];
#[cfg(target_os="macos")]
const COMPILERS: &'static [&'static str] = &["clang"];
#[cfg(target_env="msvc")]
const COMPILERS: &'static[&'static str] = &["cl.exe"];
fn do_run<T: AsRef<OsStr>>(exe: &Path, args: &[T], cwd: &Path) -> Output {
let mut cmd = Command::new(exe);
cmd.args(args)
.current_dir(cwd)
.stdout(Stdio::piped())
.stderr(Stdio::piped());
trace!("do_run: {:?}", cmd);
cmd.spawn()
.unwrap_or_else(|e| { panic!("failed to execute child: {}", e) })
.wait_with_output()
.unwrap()
}
fn run<T: AsRef<OsStr>>(exe: &Path, args: &[T], cwd: &Path) -> bool {
let output = do_run(exe, args, cwd);
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 {
( $t:ty, $( $x:expr ),* ) => {
vec!($( Into::<$t>::into(&$x), )*)
};
}
fn compile_cmdline<T: AsRef<OsStr>>(compiler: &str, exe: T, input: &str, output: &str) -> Vec<OsString> {
match compiler {
"gcc" | "clang" => vec_from!(OsString, exe.as_ref(), "-c", input, "-o", output),
"cl.exe" => vec_from!(OsString, exe, "-c", input, format!("-Fo{}", output)),
_ => panic!("Unsupported compiler: {}", compiler),
}
}
fn print_stats(stats: &HashMap<String, CacheStat>) {
for (k, v) in stats.iter() {
trace!(" {}: {:?}", k, v);
}
}
fn run_sccache_command_test<T: AsRef<OsStr>>(sccache: &Path, compiler: &str, exe: T, tempdir: &Path) {
trace!("stop server");
do_run(sccache, &["--stop-server"], tempdir);
let cache = tempdir.join("cache");
fs::create_dir_all(&cache).unwrap();
trace!("start server");
assert!(Command::new(sccache)
.arg("--start-server")
.current_dir(tempdir)
.env("SCCACHE_DIR", &cache)
.status()
.unwrap()
.success());
trace!("run_sccache_command_test: {}", compiler);
let original_source_file = Path::new(file!()).parent().unwrap().join("test.c");
let source_file = tempdir.join("test.c");
trace!("fs::copy({:?}, {:?})", original_source_file, source_file);
fs::copy(&original_source_file, &source_file).unwrap();
let out_file = tempdir.join("test.o");
let input = source_file.file_name().unwrap().to_str().unwrap();
let output = out_file.file_name().unwrap().to_str().unwrap();
trace!("compile");
assert_eq!(true, run(sccache, &compile_cmdline(compiler, exe.as_ref(), &input, &output), tempdir));
assert_eq!(true, fs::metadata(&out_file).and_then(|m| Ok(m.len() > 0)).unwrap());
trace!("connect");
let conn = connect_with_retry(DEFAULT_PORT).unwrap();
trace!("request stats");
let stats = cache_stats_map(request_stats(conn).unwrap());
if log_enabled!(Trace) {
trace!("stats:");
print_stats(&stats);
}
assert_eq!(&CacheStat::Count(1), stats.get("Compile requests").unwrap());
assert_eq!(&CacheStat::Count(1), stats.get("Compile requests executed").unwrap());
assert_eq!(&CacheStat::Count(0), stats.get("Cache hits").unwrap());
assert_eq!(&CacheStat::Count(1), stats.get("Cache misses").unwrap());
trace!("compile");
fs::remove_file(&out_file).unwrap();
assert_eq!(true, run(sccache, &compile_cmdline(compiler, exe.as_ref(), &input, &output), tempdir));
assert_eq!(true, fs::metadata(&out_file).and_then(|m| Ok(m.len() > 0)).unwrap());
trace!("connect");
let conn = connect_with_retry(DEFAULT_PORT).unwrap();
trace!("request stats");
let stats = cache_stats_map(request_stats(conn).unwrap());
if log_enabled!(Trace) {
trace!("stats:");
print_stats(&stats);
}
assert_eq!(&CacheStat::Count(2), stats.get("Compile requests").unwrap());
assert_eq!(&CacheStat::Count(2), stats.get("Compile requests executed").unwrap());
assert_eq!(&CacheStat::Count(1), stats.get("Cache hits").unwrap());
assert_eq!(&CacheStat::Count(1), stats.get("Cache misses").unwrap());
trace!("stop server");
assert_eq!(true, run(sccache, &["--stop-server"], tempdir));
}
#[cfg(any(unix, target_env="msvc"))]
fn find_compilers() -> Vec<(&'static str, OsString)> {
let cwd = env::current_dir().unwrap();
COMPILERS.iter()
.filter_map(|c| {
match which_in(c, env::var_os("PATH"), &cwd) {
Ok(full_path) => match full_path.canonicalize() {
Ok(full_path_canon) => Some((*c, full_path_canon.into_os_string())),
Err(_) => None,
},
Err(_) => None,
}
})
.collect::<Vec<_>>()
}
#[test]
#[cfg(any(unix, target_env="msvc"))]
fn test_sccache_command() {
match env_logger::init() {
Ok(_) => {},
Err(_) => {},
}
let tempdir = TempDir::new("sccache_system_test").unwrap();
let sccache = env::current_exe().unwrap().parent().unwrap().join("sccache").with_extension(env::consts::EXE_EXTENSION);
match fs::metadata(&sccache) {
Ok(_) => {},
Err(_) => panic!("Error: sccache binary not found at `{:?}. Do you need to run `cargo build`?", sccache),
}
let compilers = find_compilers();
if compilers.is_empty() {
assert!(true, "No compilers found, skipping test");
} else {
for (compiler, path) in compilers {
run_sccache_command_test(&sccache, compiler, path, tempdir.path())
}
}
}