Skip to content

Commit

Permalink
Add tests for TestDirExt
Browse files Browse the repository at this point in the history
Some of these tests are ignored, because they trigger known TestDirExt
bugs. See ZcashFoundation#1140 for details.
  • Loading branch information
teor2345 committed Oct 11, 2020
1 parent 8c5c027 commit 7e94047
Showing 1 changed file with 169 additions and 0 deletions.
169 changes: 169 additions & 0 deletions zebra-test/tests/command.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
#![allow(clippy::try_err)]

use std::{process::Command, time::Duration};

use color_eyre::eyre::Result;
use tempdir::TempDir;

use zebra_test::{command::TestDirExt, prelude::Stdio};

/// Returns true if `cmd` with `args` runs successfully.
///
/// On failure, prints an error message to stderr.
/// (This message is captured by the test runner, use `cargo test -- --nocapture` to see it.)
///
/// The command's stdout and stderr are ignored.
fn is_command_available(cmd: &str, args: &[&str]) -> bool {
let status = Command::new(cmd)
.args(args)
.stdout(Stdio::null())
.stderr(Stdio::null())
.status();

match status {
Err(e) => {
eprintln!(
"Skipping test because '{} {:?}' returned error {:?}",
cmd, args, e
);
false
}
Ok(status) if !status.success() => {
eprintln!(
"Skipping test because '{} {:?}' returned status {:?}",
cmd, args, status
);
false
}
_ => true,
}
}

/// Test if a process that keeps on producing lines of output is killed after the timeout.
#[test]
fn kill_on_timeout_output_continuous_lines() -> Result<()> {
zebra_test::init();

// Ideally, we'd want to use the 'yes' command here, but BSD yes treats
// every string as an argument to repeat - so we can't test if it is
// present on the system.
const TEST_CMD: &str = "hexdump";
// Skip the test if the test system does not have the command
if !is_command_available(TEST_CMD, &["/dev/null"]) {
return Ok(());
}

// Without '-v', hexdump hides duplicate lines. But we want duplicate lines
// in this test.
let mut child = TempDir::new("zebra_test")?
.spawn_child_with_command(TEST_CMD, &["-v", "/dev/zero"])?
.with_timeout(Duration::from_secs(2));

// We need to use expect_stdout, because wait_with_output ignores timeouts.
// We use a non-matching regex, to trigger the timeout.
assert!(child.expect_stdout("this regex should not match").is_err());

Ok(())
}

/// Test if the tests pass for a process that produces a single line of output,
/// then exits before the timeout.
//
// TODO: create a similar test that pauses after output
#[test]
fn finish_before_timeout_output_single_line() -> Result<()> {
zebra_test::init();

const TEST_CMD: &str = "echo";
// Skip the test if the test system does not have the command
if !is_command_available(TEST_CMD, &[]) {
return Ok(());
}

let mut child = TempDir::new("zebra_test")?
.spawn_child_with_command(TEST_CMD, &["zebra_test_output"])?
.with_timeout(Duration::from_secs(2));

// We need to use expect_stdout, because wait_with_output ignores timeouts.
// We use a non-matching regex, to trigger the timeout.
assert!(child.expect_stdout("this regex should not match").is_err());

Ok(())
}

/// Test if a process that keeps on producing output, but doesn't produce any newlines,
/// is killed after the timeout.
///
/// This test fails due to bugs in TestDirExt, see #1140 for details.
#[test]
#[ignore]
fn kill_on_timeout_continuous_output_no_newlines() -> Result<()> {
zebra_test::init();

const TEST_CMD: &str = "cat";
// Skip the test if the test system does not have the command
if !is_command_available(TEST_CMD, &["/dev/null"]) {
return Ok(());
}

let mut child = TempDir::new("zebra_test")?
.spawn_child_with_command(TEST_CMD, &["/dev/zero"])?
.with_timeout(Duration::from_secs(2));

// We need to use expect_stdout, because wait_with_output ignores timeouts.
// We use a non-matching regex, to trigger the timeout.
assert!(child.expect_stdout("this regex should not match").is_err());

Ok(())
}

/// Test if tests pass for a process that produces a small amount of output,
/// with no newlines, then exits before the timeout.
//
// TODO: create a similar test that pauses after output
#[test]
fn finish_before_timeout_short_output_no_newlines() -> Result<()> {
zebra_test::init();

const TEST_CMD: &str = "printf";
// Skip the test if the test system does not have the command
// The empty argument is required, because printf expects at least one argument.
if !is_command_available(TEST_CMD, &[""]) {
return Ok(());
}

let mut child = TempDir::new("zebra_test")?
.spawn_child_with_command(TEST_CMD, &["zebra_test_output"])?
.with_timeout(Duration::from_secs(2));

// We need to use expect_stdout, because wait_with_output ignores timeouts.
// We use a non-matching regex, to trigger the timeout.
assert!(child.expect_stdout("this regex should not match").is_err());

Ok(())
}

/// Test if the timeout works for a process that produces no output.
///
/// This test fails due to bugs in TestDirExt, see #1140 for details.
#[test]
#[ignore]
fn kill_on_timeout_no_output() -> Result<()> {
zebra_test::init();

const TEST_CMD: &str = "sleep";
// Skip the test if the test system does not have the command
if !is_command_available(TEST_CMD, &["0"]) {
return Ok(());
}

let mut child = TempDir::new("zebra_test")?
.spawn_child_with_command(TEST_CMD, &["120"])?
.with_timeout(Duration::from_secs(2));

// We need to use expect_stdout, because wait_with_output ignores timeouts.
// We use a non-matching regex, to trigger the timeout.
assert!(child.expect_stdout("this regex should not match").is_err());

Ok(())
}

0 comments on commit 7e94047

Please sign in to comment.