From a7b418bfe59e2460d3d4432643a0415d2159d1d9 Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Fri, 11 Sep 2020 13:39:39 -0700 Subject: [PATCH] Add test for first checkpoint verification (#1018) * add test for first checkpoint sync Prior this this change we've not had any tests that verify our sync / network logic is well behaved. This PR cleans up the test helper code to make error reports more consistent and uses this cleaned up API to implement a checkpoint sync test which runs zebrad until it reads the first checkpoint event from stdout. Co-authored-by: teor * move include out of unix cfg Co-authored-by: teor --- Cargo.lock | 29 +++++ zebra-test/Cargo.toml | 2 + zebra-test/src/command.rs | 157 +++++++++++++++++++----- zebra-test/src/lib.rs | 8 ++ zebra-test/src/prelude.rs | 1 + zebrad/tests/acceptance.rs | 237 ++++++++++++++++++++++--------------- 6 files changed, 310 insertions(+), 124 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aa8b367c..7fbcccdb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -667,6 +667,12 @@ dependencies = [ "syn 1.0.38", ] +[[package]] +name = "difference" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" + [[package]] name = "digest" version = "0.8.1" @@ -1642,6 +1648,15 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "output_vt100" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "owning_ref" version = "0.4.1" @@ -1763,6 +1778,18 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" +[[package]] +name = "pretty_assertions" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427" +dependencies = [ + "ansi_term 0.11.0", + "ctor", + "difference", + "output_vt100", +] + [[package]] name = "primitive-types" version = "0.7.2" @@ -3255,8 +3282,10 @@ dependencies = [ "futures", "hex", "lazy_static", + "pretty_assertions", "regex", "spandoc", + "tempdir", "thiserror", "tokio", "tower", diff --git a/zebra-test/Cargo.toml b/zebra-test/Cargo.toml index c4b593f9..e07135a4 100644 --- a/zebra-test/Cargo.toml +++ b/zebra-test/Cargo.toml @@ -19,6 +19,8 @@ tracing-error = "0.1.2" spandoc = "0.2.0" regex = "1.3.9" thiserror = "1.0.20" +tempdir = "0.3.7" +pretty_assertions = "0.6.1" [dev-dependencies] tokio = { version = "0.2", features = ["full"] } diff --git a/zebra-test/src/command.rs b/zebra-test/src/command.rs index 270452fb..ea91de06 100644 --- a/zebra-test/src/command.rs +++ b/zebra-test/src/command.rs @@ -2,15 +2,21 @@ use color_eyre::{ eyre::{eyre, Context, Report, Result}, Help, SectionExt, }; -use std::path::PathBuf; -use std::process::{Child, Command, ExitStatus, Output}; - -#[cfg(unix)] -use std::os::unix::process::ExitStatusExt; use tracing::instrument; +use std::convert::Infallible as NoDir; +use std::fmt::Write as _; +#[cfg(unix)] +use std::os::unix::process::ExitStatusExt; +use std::path::Path; +use std::{ + io::{BufRead, BufReader, Lines, Read}, + process::{Child, ChildStdout, Command, ExitStatus, Output}, + time::{Duration, Instant}, +}; + /// Runs a command -pub fn test_cmd(command_path: &str, tempdir: &PathBuf) -> Result { +pub fn test_cmd(command_path: &str, tempdir: &Path) -> Result { let mut cmd = Command::new(command_path); cmd.current_dir(tempdir); @@ -24,11 +30,11 @@ pub trait CommandExt { /// wrapper for `output` fn on `Command` that constructs informative error /// reports - fn output2(&mut self) -> Result; + fn output2(&mut self) -> Result, Report>; /// wrapper for `spawn` fn on `Command` that constructs informative error /// reports - fn spawn2(&mut self) -> Result; + fn spawn2(&mut self, dir: T) -> Result, Report>; } impl CommandExt for Command { @@ -49,7 +55,7 @@ impl CommandExt for Command { /// wrapper for `output` fn on `Command` that constructs informative error /// reports - fn output2(&mut self) -> Result { + fn output2(&mut self) -> Result, Report> { let output = self.output(); let output = output @@ -57,6 +63,7 @@ impl CommandExt for Command { .with_section(|| format!("{:?}", self).header("Command:"))?; Ok(TestOutput { + dir: None, output, cmd: format!("{:?}", self), }) @@ -64,7 +71,7 @@ impl CommandExt for Command { /// wrapper for `spawn` fn on `Command` that constructs informative error /// reports - fn spawn2(&mut self) -> Result { + fn spawn2(&mut self, dir: T) -> Result, Report> { let cmd = format!("{:?}", self); let child = self.spawn(); @@ -72,7 +79,13 @@ impl CommandExt for Command { .wrap_err("failed to execute process") .with_section(|| cmd.clone().header("Command:"))?; - Ok(TestChild { child, cmd }) + Ok(TestChild { + child, + cmd, + dir, + deadline: None, + stdout: None, + }) } } @@ -101,12 +114,15 @@ impl TestStatus { } #[derive(Debug)] -pub struct TestChild { +pub struct TestChild { + dir: T, pub cmd: String, pub child: Child, + pub stdout: Option>>, + pub deadline: Option, } -impl TestChild { +impl TestChild { #[spandoc::spandoc] pub fn kill(&mut self) -> Result<()> { /// SPANDOC: Killing child process @@ -116,7 +132,7 @@ impl TestChild { } #[spandoc::spandoc] - pub fn wait_with_output(self) -> Result { + pub fn wait_with_output(self) -> Result> { /// SPANDOC: waiting for command to exit let output = self.child.wait_with_output().with_section({ let cmd = self.cmd.clone(); @@ -126,16 +142,81 @@ impl TestChild { Ok(TestOutput { output, cmd: self.cmd, + dir: Some(self.dir), }) } + + pub fn with_timeout(mut self, timeout: Duration) -> Self { + self.deadline = Some(Instant::now() + timeout); + self + } + + #[instrument(skip(self))] + pub fn expect_stdout(&mut self, regex: &str) -> Result<&mut Self> { + if self.stdout.is_none() { + self.stdout = self + .child + .stdout + .take() + .map(BufReader::new) + .map(BufRead::lines) + } + + let re = regex::Regex::new(regex).expect("regex must be valid"); + let mut lines = self + .stdout + .take() + .expect("child must capture stdout to call expect_stdout"); + + while !self.past_deadline() && self.is_running() { + let line = if let Some(line) = lines.next() { + line? + } else { + break; + }; + + // since we're about to discard this line write it to stdout so our + // test runner can capture it and display if the test fails, may + // cause weird reordering for stdout / stderr + println!("{}", line); + + if re.is_match(&line) { + self.stdout = Some(lines); + return Ok(self); + } + } + + if self.past_deadline() && !self.is_running() { + self.kill()?; + } + + let report = eyre!("stdout of command did not contain any matches for the given regex") + .context_from(self); + + Err(report) + } + + fn past_deadline(&self) -> bool { + self.deadline + .map(|deadline| Instant::now() > deadline) + .unwrap_or(false) + } + + fn is_running(&mut self) -> bool { + matches!(self.child.try_wait(), Ok(None)) + } } -pub struct TestOutput { +pub struct TestOutput { + #[allow(dead_code)] + // this just keeps the test dir around from `TestChild` so it doesnt get + // deleted during `wait_with_output` + dir: Option, pub cmd: String, pub output: Output, } -impl TestOutput { +impl TestOutput { pub fn assert_success(self) -> Result { if !self.output.status.success() { Err(eyre!("command exited unsuccessfully")).context_from(&self)?; @@ -227,7 +308,7 @@ impl TestOutput { pub trait ContextFrom { type Return; - fn context_from(self, source: &S) -> Self::Return; + fn context_from(self, source: S) -> Self::Return; } impl ContextFrom for Result @@ -237,13 +318,13 @@ where { type Return = Result; - fn context_from(self, source: &C) -> Self::Return { + fn context_from(self, source: C) -> Self::Return { self.map_err(|e| e.into()) .map_err(|report| report.context_from(source)) } } -impl ContextFrom for Report { +impl ContextFrom<&TestStatus> for Report { type Return = Report; fn context_from(self, source: &TestStatus) -> Self::Return { @@ -253,27 +334,47 @@ impl ContextFrom for Report { } } -impl ContextFrom for Report { +impl ContextFrom<&mut TestChild> for Report { type Return = Report; - fn context_from(self, source: &TestChild) -> Self::Return { - let command = || source.cmd.clone().header("Command:"); - let child = || format!("{:?}", source.child).header("Child Process:"); + fn context_from(mut self, source: &mut TestChild) -> Self::Return { + self = self.section(source.cmd.clone().header("Command:")); - self.with_section(command).with_section(child) + if let Ok(Some(status)) = source.child.try_wait() { + self = self.context_from(&status); + } + + let mut stdout_buf = String::new(); + let mut stderr_buf = String::new(); + + if let Some(stdout) = &mut source.stdout { + for line in stdout { + let line = if let Ok(line) = line { line } else { break }; + let _ = writeln!(&mut stdout_buf, "{}", line); + } + } else if let Some(stdout) = &mut source.child.stdout { + let _ = stdout.read_to_string(&mut stdout_buf); + } + + if let Some(stderr) = &mut source.child.stderr { + let _ = stderr.read_to_string(&mut stderr_buf); + } + + self.section(stdout_buf.header("Unread Stdout:")) + .section(stderr_buf.header("Unread Stderr:")) } } -impl ContextFrom for Report { +impl ContextFrom<&TestOutput> for Report { type Return = Report; - fn context_from(self, source: &TestOutput) -> Self::Return { + fn context_from(self, source: &TestOutput) -> Self::Return { self.with_section(|| source.cmd.clone().header("Command:")) .context_from(&source.output) } } -impl ContextFrom for Report { +impl ContextFrom<&Output> for Report { type Return = Report; fn context_from(self, source: &Output) -> Self::Return { @@ -294,7 +395,7 @@ impl ContextFrom for Report { } } -impl ContextFrom for Report { +impl ContextFrom<&ExitStatus> for Report { type Return = Report; fn context_from(self, source: &ExitStatus) -> Self::Return { diff --git a/zebra-test/src/lib.rs b/zebra-test/src/lib.rs index deefb195..77455ca1 100644 --- a/zebra-test/src/lib.rs +++ b/zebra-test/src/lib.rs @@ -69,6 +69,14 @@ pub fn init() { }) }); })) + .display_env_section(false) + // Once I make a release with + // https://github.com/yaahc/color-eyre/pull/57 I'm going to add a + // custom PanicMessage handler for skipping the message in panics + // when the message is the exact one created by panics in tests that + // returned an Err. It will still print the content of the Err in + // the case where an error is returned. + // .panic_message(SkipTestReturnedErrPanicMessages) .install() .unwrap(); }) diff --git a/zebra-test/src/prelude.rs b/zebra-test/src/prelude.rs index 3f9cd33f..7201bca8 100644 --- a/zebra-test/src/prelude.rs +++ b/zebra-test/src/prelude.rs @@ -4,3 +4,4 @@ pub use std::process::Stdio; pub use color_eyre; pub use color_eyre::eyre; pub use eyre::Result; +pub use pretty_assertions::{assert_eq, assert_ne}; diff --git a/zebrad/tests/acceptance.rs b/zebrad/tests/acceptance.rs index d4e83c10..30d317e0 100644 --- a/zebrad/tests/acceptance.rs +++ b/zebrad/tests/acceptance.rs @@ -16,9 +16,10 @@ use color_eyre::eyre::Result; use eyre::WrapErr; -use std::{fs, io::Write, path::PathBuf, time::Duration}; use tempdir::TempDir; +use std::{borrow::Borrow, fs, io::Write, time::Duration}; + use zebra_test::prelude::*; use zebrad::config::ZebradConfig; @@ -31,53 +32,76 @@ fn default_test_config() -> Result { Ok(config) } -#[derive(PartialEq)] -enum ConfigMode { - NoConfig, - Ephemeral, - Persistent, +fn persistent_test_config() -> Result { + let mut config = default_test_config()?; + config.state.ephemeral = false; + Ok(config) } -fn tempdir(config_mode: ConfigMode) -> Result<(PathBuf, impl Drop)> { - let dir = TempDir::new("zebrad_tests")?; +fn testdir() -> Result { + TempDir::new("zebrad_tests").map_err(Into::into) +} - if config_mode != ConfigMode::NoConfig { - let mut config = default_test_config()?; - if config_mode == ConfigMode::Persistent { - let cache_dir = dir.path().join("state"); - fs::create_dir(&cache_dir)?; - config.state.cache_dir = cache_dir; - config.state.ephemeral = false; +/// Extension trait for methods on `tempdir::TempDir` for using it as a test +/// directory. +trait TestDirExt +where + Self: Borrow + Sized, +{ + /// Spawn the zebrad as a child process in this test directory, potentially + /// taking ownership of the tempdir for the duration of the child process. + fn spawn_child(self, args: &[&str]) -> Result>; + + /// Add the given config to the test directory and use it for all + /// subsequently spawned processes. + fn with_config(self, config: ZebradConfig) -> Result; +} + +impl TestDirExt for T +where + Self: Borrow + Sized, +{ + fn spawn_child(self, args: &[&str]) -> Result> { + let tempdir = self.borrow(); + let mut cmd = test_cmd(env!("CARGO_BIN_EXE_zebrad"), tempdir.path())?; + + let default_config_path = tempdir.path().join("zebrad.toml"); + + if default_config_path.exists() { + cmd.arg("-c").arg(default_config_path); } - fs::File::create(dir.path().join("zebrad.toml"))? + Ok(cmd + .args(args) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn2(self) + .unwrap()) + } + + fn with_config(self, mut config: ZebradConfig) -> Result { + let dir = self.borrow().path(); + + if !config.state.ephemeral { + let cache_dir = dir.join("state"); + fs::create_dir(&cache_dir)?; + config.state.cache_dir = cache_dir; + } + + fs::File::create(dir.join("zebrad.toml"))? .write_all(toml::to_string(&config)?.as_bytes())?; + + Ok(self) } - - Ok((dir.path().to_path_buf(), dir)) -} - -fn get_child(args: &[&str], tempdir: &PathBuf) -> Result { - let mut cmd = test_cmd(env!("CARGO_BIN_EXE_zebrad"), &tempdir)?; - - let default_config_path = tempdir.join("zebrad.toml"); - if default_config_path.exists() { - cmd.args(&["-c", default_config_path.to_str().unwrap()]); - } - Ok(cmd - .args(args) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn2() - .unwrap()) } #[test] fn generate_no_args() -> Result<()> { zebra_test::init(); - let (tempdir, _guard) = tempdir(ConfigMode::Ephemeral)?; + let child = testdir()? + .with_config(default_test_config()?)? + .spawn_child(&["generate"])?; - let child = get_child(&["generate"], &tempdir)?; let output = child.wait_with_output()?; let output = output.assert_success()?; @@ -105,38 +129,36 @@ macro_rules! assert_with_context { #[test] fn generate_args() -> Result<()> { zebra_test::init(); - let (tempdir, _guard) = tempdir(ConfigMode::NoConfig)?; + let testdir = testdir()?; + let testdir = &testdir; // unexpected free argument `argument` - let child = get_child(&["generate", "argument"], &tempdir)?; + let child = testdir.spawn_child(&["generate", "argument"])?; let output = child.wait_with_output()?; output.assert_failure()?; // unrecognized option `-f` - let child = get_child(&["generate", "-f"], &tempdir)?; + let child = testdir.spawn_child(&["generate", "-f"])?; let output = child.wait_with_output()?; output.assert_failure()?; // missing argument to option `-o` - let child = get_child(&["generate", "-o"], &tempdir)?; + let child = testdir.spawn_child(&["generate", "-o"])?; let output = child.wait_with_output()?; output.assert_failure()?; // Add a config file name to tempdir path - let mut generated_config_path = tempdir.clone(); - generated_config_path.push("zebrad.toml"); + let generated_config_path = testdir.path().join("zebrad.toml"); // Valid - let child = get_child( - &["generate", "-o", generated_config_path.to_str().unwrap()], - &tempdir, - )?; + let child = + testdir.spawn_child(&["generate", "-o", generated_config_path.to_str().unwrap()])?; let output = child.wait_with_output()?; let output = output.assert_success()?; // Check if the temp dir still exist - assert_with_context!(tempdir.exists(), &output); + assert_with_context!(testdir.path().exists(), &output); // Check if the file was created assert_with_context!(generated_config_path.exists(), &output); @@ -147,9 +169,9 @@ fn generate_args() -> Result<()> { #[test] fn help_no_args() -> Result<()> { zebra_test::init(); - let (tempdir, _guard) = tempdir(ConfigMode::Ephemeral)?; + let testdir = testdir()?.with_config(default_test_config()?)?; - let child = get_child(&["help"], &tempdir)?; + let child = testdir.spawn_child(&["help"])?; let output = child.wait_with_output()?; let output = output.assert_success()?; @@ -165,15 +187,16 @@ fn help_no_args() -> Result<()> { #[test] fn help_args() -> Result<()> { zebra_test::init(); - let (tempdir, _guard) = tempdir(ConfigMode::NoConfig)?; + let testdir = testdir()?; + let testdir = &testdir; // The subcommand "argument" wasn't recognized. - let child = get_child(&["help", "argument"], &tempdir)?; + let child = testdir.spawn_child(&["help", "argument"])?; let output = child.wait_with_output()?; output.assert_failure()?; // option `-f` does not accept an argument - let child = get_child(&["help", "-f"], &tempdir)?; + let child = testdir.spawn_child(&["help", "-f"])?; let output = child.wait_with_output()?; output.assert_failure()?; @@ -183,10 +206,10 @@ fn help_args() -> Result<()> { #[test] fn revhex_args() -> Result<()> { zebra_test::init(); - let (tempdir, _guard) = tempdir(ConfigMode::Ephemeral)?; + let testdir = testdir()?.with_config(default_test_config()?)?; // Valid - let child = get_child(&["revhex", "33eeff55"], &tempdir)?; + let child = testdir.spawn_child(&["revhex", "33eeff55"])?; let output = child.wait_with_output()?; let output = output.assert_success()?; @@ -198,9 +221,9 @@ fn revhex_args() -> Result<()> { #[test] fn seed_no_args() -> Result<()> { zebra_test::init(); - let (tempdir, _guard) = tempdir(ConfigMode::Ephemeral)?; + let testdir = testdir()?.with_config(default_test_config()?)?; - let mut child = get_child(&["-v", "seed"], &tempdir)?; + let mut child = testdir.spawn_child(&["-v", "seed"])?; // Run the program and kill it at 1 second std::thread::sleep(Duration::from_secs(1)); @@ -220,20 +243,21 @@ fn seed_no_args() -> Result<()> { #[test] fn seed_args() -> Result<()> { zebra_test::init(); - let (tempdir, _guard) = tempdir(ConfigMode::Ephemeral)?; + let testdir = testdir()?.with_config(default_test_config()?)?; + let testdir = &testdir; // unexpected free argument `argument` - let child = get_child(&["seed", "argument"], &tempdir)?; + let child = testdir.spawn_child(&["seed", "argument"])?; let output = child.wait_with_output()?; output.assert_failure()?; // unrecognized option `-f` - let child = get_child(&["seed", "-f"], &tempdir)?; + let child = testdir.spawn_child(&["seed", "-f"])?; let output = child.wait_with_output()?; output.assert_failure()?; // unexpected free argument `start` - let child = get_child(&["seed", "start"], &tempdir)?; + let child = testdir.spawn_child(&["seed", "start"])?; let output = child.wait_with_output()?; output.assert_failure()?; @@ -244,9 +268,9 @@ fn seed_args() -> Result<()> { fn start_no_args() -> Result<()> { zebra_test::init(); // start caches state, so run one of the start tests with persistent state - let (tempdir, _guard) = tempdir(ConfigMode::Persistent)?; + let testdir = testdir()?.with_config(persistent_test_config()?)?; - let mut child = get_child(&["-v", "start"], &tempdir)?; + let mut child = testdir.spawn_child(&["-v", "start"])?; // Run the program and kill it at 1 second std::thread::sleep(Duration::from_secs(1)); @@ -268,10 +292,11 @@ fn start_no_args() -> Result<()> { #[test] fn start_args() -> Result<()> { zebra_test::init(); - let (tempdir, _guard) = tempdir(ConfigMode::Ephemeral)?; + let testdir = testdir()?.with_config(default_test_config()?)?; + let testdir = &testdir; // Any free argument is valid - let mut child = get_child(&["start", "argument"], &tempdir)?; + let mut child = testdir.spawn_child(&["start", "argument"])?; // Run the program and kill it at 1 second std::thread::sleep(Duration::from_secs(1)); child.kill()?; @@ -283,7 +308,7 @@ fn start_args() -> Result<()> { output.assert_failure()?; // unrecognized option `-f` - let child = get_child(&["start", "-f"], &tempdir)?; + let child = testdir.spawn_child(&["start", "-f"])?; let output = child.wait_with_output()?; output.assert_failure()?; @@ -293,9 +318,10 @@ fn start_args() -> Result<()> { #[test] fn persistent_mode() -> Result<()> { zebra_test::init(); - let (tempdir, _guard) = tempdir(ConfigMode::Persistent)?; + let testdir = testdir()?.with_config(persistent_test_config()?)?; + let testdir = &testdir; - let mut child = get_child(&["-v", "start"], &tempdir)?; + let mut child = testdir.spawn_child(&["-v", "start"])?; // Run the program and kill it at 1 second std::thread::sleep(Duration::from_secs(1)); @@ -306,7 +332,7 @@ fn persistent_mode() -> Result<()> { output.assert_was_killed()?; // Check that we have persistent sled database - let cache_dir = tempdir.join("state"); + let cache_dir = testdir.path().join("state"); assert_with_context!(cache_dir.read_dir()?.count() > 0, &output); Ok(()) @@ -315,10 +341,11 @@ fn persistent_mode() -> Result<()> { #[test] fn ephemeral_mode() -> Result<()> { zebra_test::init(); - let (tempdir, _guard) = tempdir(ConfigMode::Ephemeral)?; + let testdir = testdir()?.with_config(default_test_config()?)?; + let testdir = &testdir; // Any free argument is valid - let mut child = get_child(&["start", "argument"], &tempdir)?; + let mut child = testdir.spawn_child(&["start", "argument"])?; // Run the program and kill it at 1 second std::thread::sleep(Duration::from_secs(1)); child.kill()?; @@ -327,7 +354,7 @@ fn ephemeral_mode() -> Result<()> { // Make sure the command was killed output.assert_was_killed()?; - let cache_dir = tempdir.join("state"); + let cache_dir = testdir.path().join("state"); assert_with_context!(!cache_dir.exists(), &output); Ok(()) @@ -350,10 +377,10 @@ fn misconfigured_ephemeral_mode() -> Result<()> { fs::File::create(dir.path().join("zebrad.toml"))? .write_all(toml::to_string(&config)?.as_bytes())?; - let tempdir = dir.path().to_path_buf(); - // Any free argument is valid - let mut child = get_child(&["start", "argument"], &tempdir)?; + let mut child = dir + .with_config(config)? + .spawn_child(&["start", "argument"])?; // Run the program and kill it at 1 second std::thread::sleep(Duration::from_secs(1)); child.kill()?; @@ -363,7 +390,14 @@ fn misconfigured_ephemeral_mode() -> Result<()> { output.assert_was_killed()?; // Check that ephemeral takes precedence over cache_dir - assert_with_context!(cache_dir.read_dir()?.count() == 0, &output); + assert_with_context!( + cache_dir + .read_dir() + .expect("cache_dir should still exist") + .count() + == 0, + &output + ); Ok(()) } @@ -371,9 +405,9 @@ fn misconfigured_ephemeral_mode() -> Result<()> { #[test] fn app_no_args() -> Result<()> { zebra_test::init(); - let (tempdir, _guard) = tempdir(ConfigMode::Ephemeral)?; + let testdir = testdir()?.with_config(default_test_config()?)?; - let child = get_child(&[], &tempdir)?; + let child = testdir.spawn_child(&[])?; let output = child.wait_with_output()?; let output = output.assert_success()?; @@ -385,9 +419,9 @@ fn app_no_args() -> Result<()> { #[test] fn version_no_args() -> Result<()> { zebra_test::init(); - let (tempdir, _guard) = tempdir(ConfigMode::Ephemeral)?; + let testdir = testdir()?.with_config(default_test_config()?)?; - let child = get_child(&["version"], &tempdir)?; + let child = testdir.spawn_child(&["version"])?; let output = child.wait_with_output()?; let output = output.assert_success()?; @@ -399,15 +433,16 @@ fn version_no_args() -> Result<()> { #[test] fn version_args() -> Result<()> { zebra_test::init(); - let (tempdir, _guard) = tempdir(ConfigMode::Ephemeral)?; + let testdir = testdir()?.with_config(default_test_config()?)?; + let testdir = &testdir; // unexpected free argument `argument` - let child = get_child(&["version", "argument"], &tempdir)?; + let child = testdir.spawn_child(&["version", "argument"])?; let output = child.wait_with_output()?; output.assert_failure()?; // unrecognized option `-f` - let child = get_child(&["version", "-f"], &tempdir)?; + let child = testdir.spawn_child(&["version", "-f"])?; let output = child.wait_with_output()?; output.assert_failure()?; @@ -427,17 +462,15 @@ fn valid_generated_config_test() -> Result<()> { fn valid_generated_config(command: &str, expected_output: &str) -> Result<()> { zebra_test::init(); - let (tempdir, _guard) = tempdir(ConfigMode::NoConfig)?; + let testdir = testdir()?; + let testdir = &testdir; // Add a config file name to tempdir path - let mut generated_config_path = tempdir.clone(); - generated_config_path.push("zebrad.toml"); + let generated_config_path = testdir.path().join("zebrad.toml"); // Generate configuration in temp dir path - let child = get_child( - &["generate", "-o", generated_config_path.to_str().unwrap()], - &tempdir, - )?; + let child = + testdir.spawn_child(&["generate", "-o", generated_config_path.to_str().unwrap()])?; let output = child.wait_with_output()?; let output = output.assert_success()?; @@ -446,7 +479,7 @@ fn valid_generated_config(command: &str, expected_output: &str) -> Result<()> { assert_with_context!(generated_config_path.exists(), &output); // Run command using temp dir and kill it at 1 second - let mut child = get_child(&[command], &tempdir)?; + let mut child = testdir.spawn_child(&[command])?; std::thread::sleep(Duration::from_secs(1)); child.kill()?; @@ -459,7 +492,7 @@ fn valid_generated_config(command: &str, expected_output: &str) -> Result<()> { output.assert_was_killed().wrap_err("Possible port or cache conflict. Are there other acceptance test, zebrad, or zcashd processes running?")?; // Check if the temp dir still exists - assert_with_context!(tempdir.exists(), &output); + assert_with_context!(testdir.path().exists(), &output); // Check if the created config file still exists assert_with_context!(generated_config_path.exists(), &output); @@ -467,6 +500,22 @@ fn valid_generated_config(command: &str, expected_output: &str) -> Result<()> { Ok(()) } +#[test] +#[ignore] +fn sync_one_checkpoint() -> Result<()> { + zebra_test::init(); + + let mut child = testdir()? + .with_config(persistent_test_config()?)? + .spawn_child(&["start"])? + .with_timeout(Duration::from_secs(20)); + + child.expect_stdout("verified checkpoint range")?; + child.kill()?; + + Ok(()) +} + #[tokio::test] async fn metrics_endpoint() -> Result<()> { use hyper::{Client, Uri}; @@ -485,9 +534,7 @@ async fn metrics_endpoint() -> Result<()> { fs::File::create(dir.path().join("zebrad.toml"))? .write_all(toml::to_string(&config)?.as_bytes())?; - let tempdir = dir.path().to_path_buf(); - - let mut child = get_child(&["start"], &tempdir)?; + let mut child = dir.spawn_child(&["start"])?; // Run the program for a second before testing the endpoint std::thread::sleep(Duration::from_secs(1)); @@ -539,9 +586,7 @@ async fn tracing_endpoint() -> Result<()> { fs::File::create(dir.path().join("zebrad.toml"))? .write_all(toml::to_string(&config)?.as_bytes())?; - let tempdir = dir.path().to_path_buf(); - - let mut child = get_child(&["start"], &tempdir)?; + let mut child = dir.spawn_child(&["start"])?; // Run the program for a second before testing the endpoint std::thread::sleep(Duration::from_secs(1));