Export exit codes to JSON output

This commit is contained in:
Jordi Chauzi authored and David Peter committed 2021-05-10 14:55:04 +02:00
1 parent 9e57bf613c
commit 3fcc6a187b
7 files changed
+53 -6

No files matched your search

+1
View File
@@ -1,6 +1,7 @@
# unreleased
- Add command exit code to output if it fails, see #342 (@KaindlJulian)
- Export command exit code to JSON output, see #371 (@JordiChauzi)
## Features
+31 -5
View File
@@ -1,6 +1,6 @@
use std::cmp;
use std::io;
use std::process::Stdio;
use std::process::{ExitStatus, Stdio};
use colored::*;
use statistical::{mean, median, standard_deviation};
@@ -46,7 +46,7 @@ pub fn time_shell_command(
show_output: bool,
failure_action: CmdFailureAction,
shell_spawning_time: Option<TimingResult>,
) -> io::Result<(TimingResult, bool)> {
) -> io::Result<(TimingResult, ExitStatus)> {
let (stdout, stderr) = if show_output {
(Stdio::inherit(), Stdio::inherit())
} else {
@@ -88,7 +88,7 @@ pub fn time_shell_command(
time_user,
time_system,
},
result.status.success(),
result.status,
))
}
@@ -201,6 +201,26 @@ fn run_cleanup_command(
run_intermediate_command(shell, command, show_output, error_output)
}
#[cfg(unix)]
fn extract_exit_code(status: ExitStatus) -> i32 {
use std::os::unix::process::ExitStatusExt;
/* From the ExitStatus::code documentation:
"On Unix, this will return None if the process was terminated by a signal."
In that case, ExitStatusExt::signal should never return None.
*/
status.code().unwrap_or_else(|| status.signal().unwrap())
}
#[cfg(not(unix))]
fn extract_exit_code(status: ExitStatus) -> i32 {
/* From the ExitStatus::code documentation:
"On Unix, this will return None if the process was terminated by a signal."
On the other configurations, ExitStatus::code should never return None.
*/
status.code().unwrap()
}
/// Run the benchmark for a single shell command
pub fn run_benchmark(
num: usize,
@@ -228,6 +248,7 @@ pub fn run_benchmark(
let mut times_real: Vec<Second> = vec![];
let mut times_user: Vec<Second> = vec![];
let mut times_system: Vec<Second> = vec![];
let mut exit_codes: Vec<i32> = vec![];
let mut all_succeeded = true;
// Run init command
@@ -280,13 +301,14 @@ pub fn run_benchmark(
let prepare_res = run_preparation_command(&options.shell, &prepare_cmd, options.show_output)?;
// Initial timing run
let (res, success) = time_shell_command(
let (res, status) = time_shell_command(
&options.shell,
cmd,
options.show_output,
options.failure_action,
Some(shell_spawning_time),
)?;
let success = status.success();
// Determine number of benchmark runs
let runs_in_min_time = (options.min_time_sec
@@ -310,6 +332,7 @@ pub fn run_benchmark(
times_real.push(res.time_real);
times_user.push(res.time_user);
times_system.push(res.time_system);
exit_codes.push(extract_exit_code(status));
all_succeeded = all_succeeded && success;
@@ -328,17 +351,19 @@ pub fn run_benchmark(
progress_bar.as_ref().map(|bar| bar.set_message(msg.to_owned()));
let (res, success) = time_shell_command(
let (res, status) = time_shell_command(
&options.shell,
cmd,
options.show_output,
options.failure_action,
Some(shell_spawning_time),
)?;
let success = status.success();
times_real.push(res.time_real);
times_user.push(res.time_user);
times_system.push(res.time_system);
exit_codes.push(extract_exit_code(status));
all_succeeded = all_succeeded && success;
@@ -438,6 +463,7 @@ pub fn run_benchmark(
t_min,
t_max,
times_real,
exit_codes,
cmd.get_parameters()
.iter()
.map(|(name, value)| ((*name).to_string(), value.to_string()))
+4
View File
@@ -99,6 +99,7 @@ fn test_asciidoc_table_row() {
0.10745223440000001,
0.10697327940000001,
],
vec![0, 0, 0], // exit codes
BTreeMap::new(), // param
);
@@ -151,6 +152,7 @@ fn test_asciidoc_table_row_command_escape() {
0.10745223440000001,
0.10697327940000001,
],
vec![0, 0, 0], // exit codes
BTreeMap::new(), // param
);
let exps = format!(
@@ -185,6 +187,7 @@ fn test_asciidoc() {
5.0,
6.0,
vec![7.0, 8.0, 9.0],
vec![0, 0, 0],
{
let mut params = BTreeMap::new();
params.insert("foo".into(), "1".into());
@@ -202,6 +205,7 @@ fn test_asciidoc() {
15.0,
16.0,
vec![17.0, 18.0, 19.0],
vec![0, 0, 0],
{
let mut params = BTreeMap::new();
params.insert("foo".into(), "1".into());
+3 -1
View File
@@ -17,7 +17,7 @@ impl Exporter for CsvExporter {
{
let mut headers: Vec<Cow<[u8]>> = [
// The list of times cannot be exported to the CSV file - omit it.
// The list of times and exit codes cannot be exported to the CSV file - omit them.
"command", "mean", "stddev", "median", "user", "system", "min", "max",
]
.iter()
@@ -68,6 +68,7 @@ fn test_csv() {
5.0,
6.0,
vec![7.0, 8.0, 9.0],
vec![0, 0, 0],
{
let mut params = BTreeMap::new();
params.insert("foo".into(), "one".into());
@@ -85,6 +86,7 @@ fn test_csv() {
15.0,
16.5,
vec![17.0, 18.0, 19.0],
vec![0, 0, 0],
{
let mut params = BTreeMap::new();
params.insert("foo".into(), "one".into());
+8
View File
@@ -102,6 +102,7 @@ fn test_markdown_format_ms() {
0.1023, // min
0.1080, // max
vec![0.1, 0.1, 0.1], // times
vec![0, 0, 0], // exit codes
BTreeMap::new(), // parameter
));
@@ -115,6 +116,7 @@ fn test_markdown_format_ms() {
2.0020, // min
2.0080, // max
vec![2.0, 2.0, 2.0], // times
vec![0, 0, 0], // exit codes
BTreeMap::new(), // parameter
));
@@ -150,6 +152,7 @@ fn test_markdown_format_s() {
2.0020, // min
2.0080, // max
vec![2.0, 2.0, 2.0], // times
vec![0, 0, 0], // exit codes
BTreeMap::new(), // parameter
));
@@ -163,6 +166,7 @@ fn test_markdown_format_s() {
0.1023, // min
0.1080, // max
vec![0.1, 0.1, 0.1], // times
vec![0, 0, 0], // exit codes
BTreeMap::new(), // parameter
));
@@ -197,6 +201,7 @@ fn test_markdown_format_time_unit_s() {
0.1023, // min
0.1080, // max
vec![0.1, 0.1, 0.1], // times
vec![0, 0, 0], // exit codes
BTreeMap::new(), // parameter
));
@@ -210,6 +215,7 @@ fn test_markdown_format_time_unit_s() {
2.0020, // min
2.0080, // max
vec![2.0, 2.0, 2.0], // times
vec![0, 0, 0], // exit codes
BTreeMap::new(), // parameter
));
@@ -250,6 +256,7 @@ fn test_markdown_format_time_unit_ms() {
2.0020, // min
2.0080, // max
vec![2.0, 2.0, 2.0], // times
vec![0, 0, 0], // exit codes
BTreeMap::new(), // parameter
));
@@ -263,6 +270,7 @@ fn test_markdown_format_time_unit_ms() {
0.1023, // min
0.1080, // max
vec![0.1, 0.1, 0.1], // times
vec![0, 0, 0], // exit codes
BTreeMap::new(), // parameter
));
+1
View File
@@ -157,6 +157,7 @@ fn create_result(name: &str, mean: Scalar) -> BenchmarkResult {
min: mean,
max: mean,
times: None,
exit_codes: Vec::new(),
parameters: BTreeMap::new(),
}
}
+5
View File
@@ -268,6 +268,9 @@ pub struct BenchmarkResult {
#[serde(skip_serializing_if = "Option::is_none")]
pub times: Option<Vec<Second>>,
/// All run exit codes
pub exit_codes: Vec<i32>,
/// Any parameter values used
#[serde(skip_serializing_if = "BTreeMap::is_empty")]
pub parameters: BTreeMap<String, String>,
@@ -285,6 +288,7 @@ impl BenchmarkResult {
min: Second,
max: Second,
times: Vec<Second>,
exit_codes: Vec<i32>,
parameters: BTreeMap<String, String>,
) -> Self {
BenchmarkResult {
@@ -297,6 +301,7 @@ impl BenchmarkResult {
min,
max,
times: Some(times),
exit_codes,
parameters,
}
}