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:
parent
bbd8a069bb
commit
a7b418bfe5
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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"] }
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
Loading…
Reference in New Issue