Fix a timeout bug in zebra_test::command

And add tests for the command functionality.

Also document some remaining bugs (see #1140).
This commit is contained in:
teor 2020-10-09 22:37:43 +10:00 committed by Deirdre Connolly
parent 92f0c934cf
commit 32bbc19c6b
4 changed files with 23 additions and 6 deletions

1
Cargo.lock generated
View File

@ -3292,6 +3292,7 @@ dependencies = [
"proptest", "proptest",
"regex", "regex",
"spandoc", "spandoc",
"tempdir",
"thiserror", "thiserror",
"tokio", "tokio",
"tower", "tower",

View File

@ -22,6 +22,7 @@ thiserror = "1.0.21"
pretty_assertions = "0.6.1" pretty_assertions = "0.6.1"
owo-colors = "1.1.3" owo-colors = "1.1.3"
proptest = "0.10.1" proptest = "0.10.1"
tempdir = "0.3.7"
[dev-dependencies] [dev-dependencies]
tokio = { version = "0.2", features = ["full"] } tokio = { version = "0.2", features = ["full"] }

View File

@ -123,6 +123,7 @@ pub struct TestChild<T> {
} }
impl<T> TestChild<T> { impl<T> TestChild<T> {
/// Kill the child process.
#[spandoc::spandoc] #[spandoc::spandoc]
pub fn kill(&mut self) -> Result<()> { pub fn kill(&mut self) -> Result<()> {
/// SPANDOC: Killing child process /// SPANDOC: Killing child process
@ -131,6 +132,9 @@ impl<T> TestChild<T> {
Ok(()) Ok(())
} }
/// Waits for the child process to exit, then returns its output.
///
/// Ignores any configured timeouts.
#[spandoc::spandoc] #[spandoc::spandoc]
pub fn wait_with_output(self) -> Result<TestOutput<T>> { pub fn wait_with_output(self) -> Result<TestOutput<T>> {
/// SPANDOC: waiting for command to exit /// SPANDOC: waiting for command to exit
@ -146,11 +150,18 @@ impl<T> TestChild<T> {
}) })
} }
/// Set a timeout for `expect_stdout`.
///
/// Does not apply to `wait_with_output`.
pub fn with_timeout(mut self, timeout: Duration) -> Self { pub fn with_timeout(mut self, timeout: Duration) -> Self {
self.deadline = Some(Instant::now() + timeout); self.deadline = Some(Instant::now() + timeout);
self self
} }
/// Checks each line of the child's stdout against `regex`, and returns matching lines.
///
/// Kills the child after the configured timeout has elapsed.
/// Note: the timeout is only checked after each line.
#[instrument(skip(self))] #[instrument(skip(self))]
pub fn expect_stdout(&mut self, regex: &str) -> Result<&mut Self> { pub fn expect_stdout(&mut self, regex: &str) -> Result<&mut Self> {
if self.stdout.is_none() { if self.stdout.is_none() {
@ -186,7 +197,10 @@ impl<T> TestChild<T> {
} }
} }
if self.past_deadline() && !self.is_running() { if self.past_deadline() && self.is_running() {
// If the process exits between is_running and kill, we will see
// spurious errors here. If that happens, ignore "no such process"
// errors from kill.
self.kill()?; self.kill()?;
} }

View File

@ -44,13 +44,14 @@ fn testdir() -> Result<TempDir> {
} }
/// Extension trait for methods on `tempdir::TempDir` for using it as a test /// Extension trait for methods on `tempdir::TempDir` for using it as a test
/// directory. /// directory for `zebrad`.
trait TestDirExt trait ZebradTestDirExt
where where
Self: Borrow<TempDir> + Sized, Self: Borrow<TempDir> + Sized,
{ {
/// Spawn the zebrad as a child process in this test directory, potentially /// Spawn `zebrad` with `args` as a child process in this test directory,
/// taking ownership of the tempdir for the duration of the child process. /// potentially taking ownership of the tempdir for the duration of the
/// child process.
fn spawn_child(self, args: &[&str]) -> Result<TestChild<Self>>; fn spawn_child(self, args: &[&str]) -> Result<TestChild<Self>>;
/// Add the given config to the test directory and use it for all /// Add the given config to the test directory and use it for all
@ -58,7 +59,7 @@ where
fn with_config(self, config: ZebradConfig) -> Result<Self>; fn with_config(self, config: ZebradConfig) -> Result<Self>;
} }
impl<T> TestDirExt for T impl<T> ZebradTestDirExt for T
where where
Self: Borrow<TempDir> + Sized, Self: Borrow<TempDir> + Sized,
{ {