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 <teor@riseup.net>

* move include out of unix cfg

Co-authored-by: teor <teor@riseup.net>
This commit is contained in:
Jane Lusby 2020-09-11 13:39:39 -07:00 committed by GitHub
parent bbd8a069bb
commit a7b418bfe5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 310 additions and 124 deletions

29
Cargo.lock generated
View File

@ -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",

View File

@ -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"] }

View File

@ -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<Command> {
pub fn test_cmd(command_path: &str, tempdir: &Path) -> Result<Command> {
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<TestOutput, Report>;
fn output2(&mut self) -> Result<TestOutput<NoDir>, Report>;
/// wrapper for `spawn` fn on `Command` that constructs informative error
/// reports
fn spawn2(&mut self) -> Result<TestChild, Report>;
fn spawn2<T>(&mut self, dir: T) -> Result<TestChild<T>, 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<TestOutput, Report> {
fn output2(&mut self) -> Result<TestOutput<NoDir>, 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<TestChild, Report> {
fn spawn2<T>(&mut self, dir: T) -> Result<TestChild<T>, 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<T> {
dir: T,
pub cmd: String,
pub child: Child,
pub stdout: Option<Lines<BufReader<ChildStdout>>>,
pub deadline: Option<Instant>,
}
impl TestChild {
impl<T> TestChild<T> {
#[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<TestOutput> {
pub fn wait_with_output(self) -> Result<TestOutput<T>> {
/// 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<T> {
#[allow(dead_code)]
// this just keeps the test dir around from `TestChild` so it doesnt get
// deleted during `wait_with_output`
dir: Option<T>,
pub cmd: String,
pub output: Output,
}
impl TestOutput {
impl<T> TestOutput<T> {
pub fn assert_success(self) -> Result<Self> {
if !self.output.status.success() {
Err(eyre!("command exited unsuccessfully")).context_from(&self)?;
@ -227,7 +308,7 @@ impl TestOutput {
pub trait ContextFrom<S> {
type Return;
fn context_from(self, source: &S) -> Self::Return;
fn context_from(self, source: S) -> Self::Return;
}
impl<C, T, E> ContextFrom<C> for Result<T, E>
@ -237,13 +318,13 @@ where
{
type Return = Result<T, Report>;
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<TestStatus> for Report {
impl ContextFrom<&TestStatus> for Report {
type Return = Report;
fn context_from(self, source: &TestStatus) -> Self::Return {
@ -253,27 +334,47 @@ impl ContextFrom<TestStatus> for Report {
}
}
impl ContextFrom<TestChild> for Report {
impl<T> ContextFrom<&mut TestChild<T>> 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<T>) -> 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<TestOutput> for Report {
impl<T> ContextFrom<&TestOutput<T>> for Report {
type Return = Report;
fn context_from(self, source: &TestOutput) -> Self::Return {
fn context_from(self, source: &TestOutput<T>) -> Self::Return {
self.with_section(|| source.cmd.clone().header("Command:"))
.context_from(&source.output)
}
}
impl ContextFrom<Output> for Report {
impl ContextFrom<&Output> for Report {
type Return = Report;
fn context_from(self, source: &Output) -> Self::Return {
@ -294,7 +395,7 @@ impl ContextFrom<Output> for Report {
}
}
impl ContextFrom<ExitStatus> for Report {
impl ContextFrom<&ExitStatus> for Report {
type Return = Report;
fn context_from(self, source: &ExitStatus) -> Self::Return {

View File

@ -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();
})

View File

@ -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};

View File

@ -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<ZebradConfig> {
Ok(config)
}
#[derive(PartialEq)]
enum ConfigMode {
NoConfig,
Ephemeral,
Persistent,
fn persistent_test_config() -> Result<ZebradConfig> {
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> {
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<TempDir> + 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<TestChild<Self>>;
/// Add the given config to the test directory and use it for all
/// subsequently spawned processes.
fn with_config(self, config: ZebradConfig) -> Result<Self>;
}
impl<T> TestDirExt for T
where
Self: Borrow<TempDir> + Sized,
{
fn spawn_child(self, args: &[&str]) -> Result<TestChild<Self>> {
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<Self> {
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<TestChild> {
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));