ptest: Allow all test runs to be logged
Check the environment variable `PTEST_LOG_ALL`, and if it is set, write
the output of all test runs to a log file instead of just the failures.
Failed test are still written to failure-nnnn.log, but successful runs
are written to success-nnnn.log. If the environment variable is not
set, ptest behaves as before, only writing to log files when there is a
failure.
Signed-off-by: David Brown <david.brown@linaro.org>
diff --git a/ptest/src/main.rs b/ptest/src/main.rs
index f6b8602..a543e73 100644
--- a/ptest/src/main.rs
+++ b/ptest/src/main.rs
@@ -14,9 +14,10 @@
use log::{debug, error, warn};
use std::{
collections::HashSet,
+ env,
fs::{self, OpenOptions},
io::{ErrorKind, stdout, Write},
- process::{Command, Output},
+ process::Command,
result,
sync::{
Arc,
@@ -82,6 +83,15 @@
total: usize,
}
+/// Result of a test run.
+struct TestResult {
+ /// Was this run successful.
+ success: bool,
+
+ /// The captured output.
+ output: Vec<u8>,
+}
+
impl State {
fn new(total: usize) -> Arc<Mutex<State>> {
Arc::new(Mutex::new(State {
@@ -101,46 +111,41 @@
self.status();
}
- fn done(&mut self, fs: &FeatureSet, output: Result<Option<Output>>) {
+ fn done(&mut self, fs: &FeatureSet, output: Result<TestResult>) {
let key = fs.textual();
self.running.remove(&key);
self.done.insert(key.clone());
match output {
- Ok(None) => {
- // println!("Success {} ({} running)", key, self.running.len());
- }
- Ok(Some(output)) => {
- // Write the output into a file.
- let mut count = 1;
- let (mut fd, logname) = loop {
- let name = format!("./failure-{:04}.log", count);
- count += 1;
- match OpenOptions::new()
- .create_new(true)
- .write(true)
- .open(&name)
- {
- Ok(file) => break (file, name),
- Err(ref err) if err.kind() == ErrorKind::AlreadyExists => continue,
- Err(err) => {
- error!("Unable to write log file to current directory: {:?}", err);
- return;
+ Ok(output) => {
+ if !output.success || log_all() {
+ // Write the output into a file.
+ let mut count = 1;
+ let (mut fd, logname) = loop {
+ let base = if output.success { "success" } else { "failure" };
+ let name = format!("./{}-{:04}.log", base, count);
+ count += 1;
+ match OpenOptions::new()
+ .create_new(true)
+ .write(true)
+ .open(&name)
+ {
+ Ok(file) => break (file, name),
+ Err(ref err) if err.kind() == ErrorKind::AlreadyExists => continue,
+ Err(err) => {
+ error!("Unable to write log file to current directory: {:?}", err);
+ return;
+ }
}
+ };
+ fd.write_all(&output.output).unwrap();
+ if !output.success {
+ error!("Failure {} log:{:?} ({} running)", key, logname,
+ self.running.len());
}
- };
- writeln!(&mut fd, "Test failure {}", key).unwrap();
- writeln!(&mut fd, "time: {}", Local::now().to_rfc3339()).unwrap();
- writeln!(&mut fd, "----------------------------------------").unwrap();
- writeln!(&mut fd, "stdout:").unwrap();
- fd.write_all(&output.stdout).unwrap();
- writeln!(&mut fd, "----------------------------------------").unwrap();
- writeln!(&mut fd, "\nstderr:").unwrap();
- fd.write_all(&output.stderr).unwrap();
- error!("Failure {} log:{:?} ({} running)", key, logname,
- self.running.len());
+ }
}
Err(err) => {
- error!("Unable to run test {:?} ({:?})", key, err);
+ error!("Unable to run test {:?} ({:?}", key, err);
}
}
self.status();
@@ -239,18 +244,31 @@
/// Run a test for this given feature set. Output is captured and will be returned if there is
/// an error. Each will be run successively, and the first failure will be returned.
/// Otherwise, it returns None, which means everything worked.
- fn run(&self) -> Result<Option<Output>> {
+ fn run(&self) -> Result<TestResult> {
+ let mut output = vec![];
+ let mut success = true;
for v in &self.values {
- let output = Command::new("bash")
+ let cmdout = Command::new("bash")
.arg("./ci/sim_run.sh")
.current_dir("..")
.env(&self.env, v)
.output()?;
- if !output.status.success() {
- return Ok(Some(output));
+ // Grab the output for logging, etc.
+ writeln!(&mut output, "Test {} {}",
+ if cmdout.status.success() { "success" } else { "FAILURE" },
+ self.textual())?;
+ writeln!(&mut output, "time: {}", Local::now().to_rfc3339())?;
+ writeln!(&mut output, "----------------------------------------")?;
+ writeln!(&mut output, "stdout:")?;
+ output.extend(&cmdout.stdout);
+ writeln!(&mut output, "----------------------------------------")?;
+ writeln!(&mut output, "stderr:")?;
+ output.extend(&cmdout.stderr);
+ if !cmdout.status.success() {
+ success = false;
}
}
- return Ok(None);
+ Ok(TestResult { success, output })
}
/// Convert this feature set into a textual representation
@@ -282,3 +300,8 @@
.as_hash()?.get(&features)?
.as_vec()
}
+
+/// Query if we should be logging all tests and not only failures.
+fn log_all() -> bool {
+ env::var("PTEST_LOG_ALL").is_ok()
+}