2020-07-31 23:15:26 -07:00
//! Acceptance test: runs zebrad as a subprocess and asserts its
2019-08-29 14:46:54 -07:00
//! output for given argument combinations matches what is expected.
2020-07-31 23:15:26 -07:00
#![ warn(warnings, missing_docs, trivial_casts, unused_qualifications) ]
2019-08-29 14:46:54 -07:00
#![ forbid(unsafe_code) ]
2020-07-31 23:15:26 -07:00
use color_eyre ::eyre ::Result ;
2020-08-22 16:45:03 -07:00
use std ::{ fs , io ::Write , path ::PathBuf , time ::Duration } ;
use tempdir ::TempDir ;
2020-07-31 23:15:26 -07:00
use zebra_test ::prelude ::* ;
2020-08-22 16:45:03 -07:00
use zebrad ::config ::ZebradConfig ;
2020-08-31 12:43:43 -07:00
fn default_test_config ( ) -> Result < ZebradConfig > {
let mut config = ZebradConfig ::default ( ) ;
2020-09-01 12:39:04 -07:00
config . state = zebra_state ::Config ::ephemeral ( ) ;
2020-08-31 12:43:43 -07:00
config . state . memory_cache_bytes = 256000000 ;
config . network . listen_addr = " 127.0.0.1:0 " . parse ( ) ? ;
Ok ( config )
}
2020-08-31 01:32:55 -07:00
#[ derive(PartialEq) ]
enum ConfigMode {
NoConfig ,
Ephemeral ,
Persistent ,
}
2020-08-22 16:45:03 -07:00
2020-08-31 01:32:55 -07:00
fn tempdir ( config_mode : ConfigMode ) -> Result < ( PathBuf , impl Drop ) > {
let dir = TempDir ::new ( " zebrad_tests " ) ? ;
2020-08-22 16:45:03 -07:00
2020-08-31 01:32:55 -07:00
if config_mode ! = ConfigMode ::NoConfig {
2020-08-31 12:43:43 -07:00
let mut config = default_test_config ( ) ? ;
if config_mode = = ConfigMode ::Persistent {
2020-08-31 01:32:55 -07:00
let cache_dir = dir . path ( ) . join ( " state " ) ;
fs ::create_dir ( & cache_dir ) ? ;
config . state . cache_dir = cache_dir ;
2020-08-31 12:43:43 -07:00
config . state . ephemeral = false ;
2020-08-31 01:32:55 -07:00
}
2020-08-22 16:45:03 -07:00
fs ::File ::create ( dir . path ( ) . join ( " zebrad.toml " ) ) ?
. write_all ( toml ::to_string ( & config ) ? . as_bytes ( ) ) ? ;
}
Ok ( ( dir . path ( ) . to_path_buf ( ) , dir ) )
}
2020-07-31 23:15:26 -07:00
2020-08-13 13:31:13 -07:00
pub fn get_child ( args : & [ & str ] , tempdir : & PathBuf ) -> Result < TestChild > {
let mut cmd = test_cmd ( env! ( " CARGO_BIN_EXE_zebrad " ) , & tempdir ) ? ;
Ok ( cmd
. args ( args )
. stdout ( Stdio ::piped ( ) )
. stderr ( Stdio ::piped ( ) )
. spawn2 ( )
. unwrap ( ) )
2020-07-31 23:15:26 -07:00
}
#[ test ]
fn generate_no_args ( ) -> Result < ( ) > {
zebra_test ::init ( ) ;
2020-08-31 01:32:55 -07:00
let ( tempdir , _guard ) = tempdir ( ConfigMode ::Ephemeral ) ? ;
2020-07-31 23:15:26 -07:00
2020-08-13 13:31:13 -07:00
let child = get_child ( & [ " generate " ] , & tempdir ) ? ;
2020-07-31 23:15:26 -07:00
let output = child . wait_with_output ( ) ? ;
let output = output . assert_success ( ) ? ;
2020-08-10 12:50:48 -07:00
// First line
2020-07-31 23:15:26 -07:00
output . stdout_contains ( r "# Default configuration for zebrad." ) ? ;
Ok ( ( ) )
}
2020-09-01 12:39:04 -07:00
macro_rules ! assert_with_context {
( $pred :expr , $source :expr ) = > {
if ! $pred {
use color_eyre ::Section as _ ;
use color_eyre ::SectionExt as _ ;
use zebra_test ::command ::ContextFrom as _ ;
let report = color_eyre ::eyre ::eyre! ( " failed assertion " )
. section ( stringify! ( $pred ) . header ( " Predicate: " ) )
. context_from ( $source ) ;
panic! ( " Error: {:?} " , report ) ;
}
} ;
}
2020-07-31 23:15:26 -07:00
#[ test ]
fn generate_args ( ) -> Result < ( ) > {
zebra_test ::init ( ) ;
2020-08-31 01:32:55 -07:00
let ( tempdir , _guard ) = tempdir ( ConfigMode ::NoConfig ) ? ;
2020-07-31 23:15:26 -07:00
// unexpected free argument `argument`
2020-08-13 13:31:13 -07:00
let child = get_child ( & [ " generate " , " argument " ] , & tempdir ) ? ;
2020-07-31 23:15:26 -07:00
let output = child . wait_with_output ( ) ? ;
output . assert_failure ( ) ? ;
// unrecognized option `-f`
2020-08-13 13:31:13 -07:00
let child = get_child ( & [ " generate " , " -f " ] , & tempdir ) ? ;
2020-07-31 23:15:26 -07:00
let output = child . wait_with_output ( ) ? ;
output . assert_failure ( ) ? ;
// missing argument to option `-o`
2020-08-13 13:31:13 -07:00
let child = get_child ( & [ " generate " , " -o " ] , & tempdir ) ? ;
2020-07-31 23:15:26 -07:00
let output = child . wait_with_output ( ) ? ;
output . assert_failure ( ) ? ;
2020-08-13 13:31:13 -07:00
// Add a config file name to tempdir path
let mut generated_config_path = tempdir . clone ( ) ;
generated_config_path . push ( " zebrad.toml " ) ;
2020-07-31 23:15:26 -07:00
// Valid
2020-08-13 13:31:13 -07:00
let child = get_child (
& [ " generate " , " -o " , generated_config_path . to_str ( ) . unwrap ( ) ] ,
2020-08-14 16:38:32 -07:00
& tempdir ,
2020-08-13 13:31:13 -07:00
) ? ;
2020-07-31 23:15:26 -07:00
let output = child . wait_with_output ( ) ? ;
2020-09-01 12:39:04 -07:00
let output = output . assert_success ( ) ? ;
2019-08-29 14:46:54 -07:00
2020-08-13 13:31:13 -07:00
// Check if the temp dir still exist
2020-09-01 12:39:04 -07:00
assert_with_context! ( tempdir . exists ( ) , & output ) ;
2020-08-13 13:31:13 -07:00
// Check if the file was created
2020-09-01 12:39:04 -07:00
assert_with_context! ( generated_config_path . exists ( ) , & output ) ;
2020-07-31 23:15:26 -07:00
Ok ( ( ) )
}
#[ test ]
fn help_no_args ( ) -> Result < ( ) > {
zebra_test ::init ( ) ;
2020-08-31 01:32:55 -07:00
let ( tempdir , _guard ) = tempdir ( ConfigMode ::Ephemeral ) ? ;
2020-07-31 23:15:26 -07:00
2020-08-13 13:31:13 -07:00
let child = get_child ( & [ " help " ] , & tempdir ) ? ;
2020-07-31 23:15:26 -07:00
let output = child . wait_with_output ( ) ? ;
let output = output . assert_success ( ) ? ;
2020-08-10 12:50:48 -07:00
// First line haves the version
output . stdout_contains ( r "zebrad [0-9].[0-9].[0-9]" ) ? ;
// Make sure we are in help by looking usage string
2020-07-31 23:15:26 -07:00
output . stdout_contains ( r "USAGE:" ) ? ;
Ok ( ( ) )
}
#[ test ]
fn help_args ( ) -> Result < ( ) > {
zebra_test ::init ( ) ;
2020-08-31 01:32:55 -07:00
let ( tempdir , _guard ) = tempdir ( ConfigMode ::Ephemeral ) ? ;
2020-07-31 23:15:26 -07:00
// The subcommand "argument" wasn't recognized.
2020-08-13 13:31:13 -07:00
let child = get_child ( & [ " help " , " argument " ] , & tempdir ) ? ;
2020-07-31 23:15:26 -07:00
let output = child . wait_with_output ( ) ? ;
output . assert_failure ( ) ? ;
// option `-f` does not accept an argument
2020-08-13 13:31:13 -07:00
let child = get_child ( & [ " help " , " -f " ] , & tempdir ) ? ;
2020-07-31 23:15:26 -07:00
let output = child . wait_with_output ( ) ? ;
output . assert_failure ( ) ? ;
Ok ( ( ) )
}
2019-08-29 14:46:54 -07:00
#[ test ]
2020-07-31 23:15:26 -07:00
fn revhex_args ( ) -> Result < ( ) > {
zebra_test ::init ( ) ;
2020-08-31 01:32:55 -07:00
let ( tempdir , _guard ) = tempdir ( ConfigMode ::Ephemeral ) ? ;
2020-07-31 23:15:26 -07:00
// Valid
2020-08-13 13:31:13 -07:00
let child = get_child ( & [ " revhex " , " 33eeff55 " ] , & tempdir ) ? ;
2020-07-31 23:15:26 -07:00
let output = child . wait_with_output ( ) ? ;
let output = output . assert_success ( ) ? ;
2020-08-10 12:50:48 -07:00
output . stdout_equals ( " 55ffee33 \n " ) ? ;
2020-07-31 23:15:26 -07:00
Ok ( ( ) )
}
2020-08-19 14:48:22 -07:00
#[ test ]
2020-07-31 23:15:26 -07:00
fn seed_no_args ( ) -> Result < ( ) > {
zebra_test ::init ( ) ;
2020-08-31 01:32:55 -07:00
let ( tempdir , _guard ) = tempdir ( ConfigMode ::Ephemeral ) ? ;
2020-07-31 23:15:26 -07:00
2020-08-13 13:31:13 -07:00
let mut child = get_child ( & [ " -v " , " seed " ] , & tempdir ) ? ;
2020-07-31 23:15:26 -07:00
// Run the program and kill it at 1 second
std ::thread ::sleep ( Duration ::from_secs ( 1 ) ) ;
child . kill ( ) ? ;
let output = child . wait_with_output ( ) ? ;
let output = output . assert_failure ( ) ? ;
output . stdout_contains ( r "Starting zebrad in seed mode" ) ? ;
2020-08-04 13:38:39 -07:00
// Make sure the command was killed
2020-09-01 12:39:04 -07:00
output . assert_was_killed ( ) ? ;
2020-08-04 13:38:39 -07:00
2020-07-31 23:15:26 -07:00
Ok ( ( ) )
}
#[ test ]
fn seed_args ( ) -> Result < ( ) > {
zebra_test ::init ( ) ;
2020-08-31 01:32:55 -07:00
let ( tempdir , _guard ) = tempdir ( ConfigMode ::Ephemeral ) ? ;
2020-07-31 23:15:26 -07:00
// unexpected free argument `argument`
2020-08-13 13:31:13 -07:00
let child = get_child ( & [ " seed " , " argument " ] , & tempdir ) ? ;
2020-07-31 23:15:26 -07:00
let output = child . wait_with_output ( ) ? ;
output . assert_failure ( ) ? ;
// unrecognized option `-f`
2020-08-13 13:31:13 -07:00
let child = get_child ( & [ " seed " , " -f " ] , & tempdir ) ? ;
2020-07-31 23:15:26 -07:00
let output = child . wait_with_output ( ) ? ;
output . assert_failure ( ) ? ;
// unexpected free argument `start`
2020-08-13 13:31:13 -07:00
let child = get_child ( & [ " seed " , " start " ] , & tempdir ) ? ;
2020-07-31 23:15:26 -07:00
let output = child . wait_with_output ( ) ? ;
output . assert_failure ( ) ? ;
Ok ( ( ) )
}
2020-08-19 14:48:22 -07:00
#[ test ]
2020-07-31 23:15:26 -07:00
fn start_no_args ( ) -> Result < ( ) > {
zebra_test ::init ( ) ;
2020-08-31 01:32:55 -07:00
// start caches state, so run one of the start tests with persistent state
let ( tempdir , _guard ) = tempdir ( ConfigMode ::Persistent ) ? ;
2020-07-31 23:15:26 -07:00
2020-08-13 13:31:13 -07:00
let mut child = get_child ( & [ " -v " , " start " ] , & tempdir ) ? ;
2020-07-31 23:15:26 -07:00
// Run the program and kill it at 1 second
std ::thread ::sleep ( Duration ::from_secs ( 1 ) ) ;
child . kill ( ) ? ;
let output = child . wait_with_output ( ) ? ;
let output = output . assert_failure ( ) ? ;
2020-08-20 03:52:15 -07:00
// start is the default mode, so we check for end of line, to distinguish it
// from seed
output . stdout_contains ( r "Starting zebrad$" ) ? ;
2020-07-31 23:15:26 -07:00
2020-08-04 13:38:39 -07:00
// Make sure the command was killed
2020-09-01 12:39:04 -07:00
output . assert_was_killed ( ) ? ;
2020-08-04 13:38:39 -07:00
2020-07-31 23:15:26 -07:00
Ok ( ( ) )
}
2020-08-19 14:48:22 -07:00
#[ test ]
2020-07-31 23:15:26 -07:00
fn start_args ( ) -> Result < ( ) > {
zebra_test ::init ( ) ;
2020-08-31 01:32:55 -07:00
let ( tempdir , _guard ) = tempdir ( ConfigMode ::Ephemeral ) ? ;
2020-07-31 23:15:26 -07:00
// Any free argument is valid
2020-08-13 13:31:13 -07:00
let mut child = get_child ( & [ " start " , " argument " ] , & tempdir ) ? ;
2020-07-31 23:15:26 -07:00
// Run the program and kill it at 1 second
std ::thread ::sleep ( Duration ::from_secs ( 1 ) ) ;
child . kill ( ) ? ;
let output = child . wait_with_output ( ) ? ;
2020-08-04 13:38:39 -07:00
// Make sure the command was killed
2020-09-01 12:39:04 -07:00
output . assert_was_killed ( ) ? ;
2020-08-04 13:38:39 -07:00
2020-07-31 23:15:26 -07:00
output . assert_failure ( ) ? ;
// unrecognized option `-f`
2020-08-13 13:31:13 -07:00
let child = get_child ( & [ " start " , " -f " ] , & tempdir ) ? ;
2020-07-31 23:15:26 -07:00
let output = child . wait_with_output ( ) ? ;
output . assert_failure ( ) ? ;
Ok ( ( ) )
}
2020-08-31 01:32:55 -07:00
#[ test ]
fn persistent_mode ( ) -> Result < ( ) > {
zebra_test ::init ( ) ;
let ( tempdir , _guard ) = tempdir ( ConfigMode ::Persistent ) ? ;
let mut child = get_child ( & [ " -v " , " start " ] , & tempdir ) ? ;
// Run the program and kill it at 1 second
std ::thread ::sleep ( Duration ::from_secs ( 1 ) ) ;
child . kill ( ) ? ;
let output = child . wait_with_output ( ) ? ;
// Make sure the command was killed
2020-09-01 12:39:04 -07:00
output . assert_was_killed ( ) ? ;
2020-08-31 01:32:55 -07:00
// Check that we have persistent sled database
let cache_dir = tempdir . join ( " state " ) ;
2020-09-01 12:39:04 -07:00
assert_with_context! ( cache_dir . read_dir ( ) ? . count ( ) > 0 , & output ) ;
2020-08-31 01:32:55 -07:00
Ok ( ( ) )
}
#[ test ]
fn ephemeral_mode ( ) -> Result < ( ) > {
zebra_test ::init ( ) ;
let ( tempdir , _guard ) = tempdir ( ConfigMode ::Ephemeral ) ? ;
// Any free argument is valid
let mut child = get_child ( & [ " start " , " argument " ] , & tempdir ) ? ;
// Run the program and kill it at 1 second
std ::thread ::sleep ( Duration ::from_secs ( 1 ) ) ;
child . kill ( ) ? ;
let output = child . wait_with_output ( ) ? ;
// Make sure the command was killed
2020-09-01 12:39:04 -07:00
output . assert_was_killed ( ) ? ;
2020-08-31 01:32:55 -07:00
let cache_dir = tempdir . join ( " state " ) ;
2020-09-01 12:39:04 -07:00
assert_with_context! ( ! cache_dir . exists ( ) , & output ) ;
2020-08-31 01:32:55 -07:00
Ok ( ( ) )
}
#[ test ]
fn misconfigured_ephemeral_mode ( ) -> Result < ( ) > {
zebra_test ::init ( ) ;
let dir = TempDir ::new ( " zebrad_tests " ) ? ;
let cache_dir = dir . path ( ) . join ( " state " ) ;
2020-08-31 12:43:43 -07:00
fs ::create_dir ( & cache_dir ) ? ;
2020-08-31 01:32:55 -07:00
// Write a configuration that has both cache_dir and ephemeral options set
2020-08-31 12:43:43 -07:00
let mut config = default_test_config ( ) ? ;
2020-08-31 01:32:55 -07:00
// Although cache_dir has a default value, we set it a new temp directory
// to test that it is empty later.
config . state . cache_dir = cache_dir . clone ( ) ;
2020-08-31 12:43:43 -07:00
2020-08-31 01:32:55 -07:00
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 ) ? ;
// Run the program and kill it at 1 second
std ::thread ::sleep ( Duration ::from_secs ( 1 ) ) ;
child . kill ( ) ? ;
let output = child . wait_with_output ( ) ? ;
// Make sure the command was killed
2020-09-01 12:39:04 -07:00
output . assert_was_killed ( ) ? ;
2020-08-31 01:32:55 -07:00
// Check that ephemeral takes precedence over cache_dir
2020-09-01 12:39:04 -07:00
assert_with_context! ( cache_dir . read_dir ( ) ? . count ( ) = = 0 , & output ) ;
2020-08-31 01:32:55 -07:00
Ok ( ( ) )
}
2020-07-31 23:15:26 -07:00
#[ test ]
fn app_no_args ( ) -> Result < ( ) > {
zebra_test ::init ( ) ;
2020-08-31 01:32:55 -07:00
let ( tempdir , _guard ) = tempdir ( ConfigMode ::Ephemeral ) ? ;
2020-07-31 23:15:26 -07:00
2020-08-13 13:31:13 -07:00
let child = get_child ( & [ ] , & tempdir ) ? ;
2020-07-31 23:15:26 -07:00
let output = child . wait_with_output ( ) ? ;
let output = output . assert_success ( ) ? ;
output . stdout_contains ( r "USAGE:" ) ? ;
Ok ( ( ) )
}
#[ test ]
fn version_no_args ( ) -> Result < ( ) > {
zebra_test ::init ( ) ;
2020-08-31 01:32:55 -07:00
let ( tempdir , _guard ) = tempdir ( ConfigMode ::Ephemeral ) ? ;
2020-07-31 23:15:26 -07:00
2020-08-13 13:31:13 -07:00
let child = get_child ( & [ " version " ] , & tempdir ) ? ;
2020-07-31 23:15:26 -07:00
let output = child . wait_with_output ( ) ? ;
let output = output . assert_success ( ) ? ;
2020-08-10 12:50:48 -07:00
output . stdout_matches ( r "^zebrad [0-9].[0-9].[0-9]-[A-Za-z]*.[0-9]\n$" ) ? ;
2020-07-31 23:15:26 -07:00
Ok ( ( ) )
}
#[ test ]
fn version_args ( ) -> Result < ( ) > {
zebra_test ::init ( ) ;
2020-08-31 01:32:55 -07:00
let ( tempdir , _guard ) = tempdir ( ConfigMode ::Ephemeral ) ? ;
2020-07-31 23:15:26 -07:00
// unexpected free argument `argument`
2020-08-13 13:31:13 -07:00
let child = get_child ( & [ " version " , " argument " ] , & tempdir ) ? ;
2020-07-31 23:15:26 -07:00
let output = child . wait_with_output ( ) ? ;
output . assert_failure ( ) ? ;
// unrecognized option `-f`
2020-08-13 13:31:13 -07:00
let child = get_child ( & [ " version " , " -f " ] , & tempdir ) ? ;
2020-07-31 23:15:26 -07:00
let output = child . wait_with_output ( ) ? ;
output . assert_failure ( ) ? ;
Ok ( ( ) )
}
#[ test ]
2020-08-20 03:49:38 -07:00
fn valid_generated_config_test ( ) -> Result < ( ) > {
// Unlike the other tests, these tests can not be run in parallel, because
// they use the generated config. So parallel execution can cause port and
// cache conflicts.
2020-08-20 03:52:15 -07:00
valid_generated_config ( " start " , r "Starting zebrad$" ) ? ;
2020-08-20 03:49:38 -07:00
valid_generated_config ( " seed " , r "Starting zebrad in seed mode" ) ? ;
Ok ( ( ) )
}
fn valid_generated_config ( command : & str , expected_output : & str ) -> Result < ( ) > {
2020-08-13 13:31:13 -07:00
zebra_test ::init ( ) ;
2020-08-31 01:32:55 -07:00
let ( tempdir , _guard ) = tempdir ( ConfigMode ::NoConfig ) ? ;
2020-08-13 13:31:13 -07:00
// Add a config file name to tempdir path
let mut generated_config_path = tempdir . clone ( ) ;
generated_config_path . push ( " zebrad.toml " ) ;
// Generate configuration in temp dir path
let child = get_child (
& [ " generate " , " -o " , generated_config_path . to_str ( ) . unwrap ( ) ] ,
2020-08-14 16:38:32 -07:00
& tempdir ,
2020-08-13 13:31:13 -07:00
) ? ;
let output = child . wait_with_output ( ) ? ;
2020-09-01 12:39:04 -07:00
let output = output . assert_success ( ) ? ;
2020-08-13 13:31:13 -07:00
// Check if the file was created
2020-09-01 12:39:04 -07:00
assert_with_context! ( generated_config_path . exists ( ) , & output ) ;
2020-08-13 13:31:13 -07:00
2020-08-20 03:49:38 -07:00
// Run command using temp dir and kill it at 1 second
2020-08-13 13:31:13 -07:00
let mut child = get_child (
2020-08-20 03:49:38 -07:00
& [ " -c " , generated_config_path . to_str ( ) . unwrap ( ) , command ] ,
2020-08-14 16:38:32 -07:00
& tempdir ,
2020-08-13 13:31:13 -07:00
) ? ;
std ::thread ::sleep ( Duration ::from_secs ( 1 ) ) ;
child . kill ( ) ? ;
let output = child . wait_with_output ( ) ? ;
let output = output . assert_failure ( ) ? ;
2020-08-20 03:49:38 -07:00
output . stdout_contains ( expected_output ) ? ;
2020-08-13 13:31:13 -07:00
2020-08-20 03:39:10 -07:00
// If the test child has a cache or port conflict with another test, or a
// running zebrad or zcashd, then it will panic. But the acceptance tests
// expect it to run until it is killed.
//
// If these conflicts cause test failures:
// - run the tests in an isolated environment,
// - run zebrad on a custom cache path and port,
// - run zcashd on a custom port.
2020-09-01 12:39:04 -07:00
output . assert_was_killed ( ) . expect ( " Expected zebrad with generated config to succeed. Are there other acceptance test, zebrad, or zcashd processes running? " ) ;
2020-08-13 13:31:13 -07:00
2020-08-20 03:49:38 -07:00
// Check if the temp dir still exists
2020-09-01 12:39:04 -07:00
assert_with_context! ( tempdir . exists ( ) , & output ) ;
2020-08-13 13:31:13 -07:00
2020-08-20 03:49:38 -07:00
// Check if the created config file still exists
2020-09-01 12:39:04 -07:00
assert_with_context! ( generated_config_path . exists ( ) , & output ) ;
2020-07-31 23:15:26 -07:00
Ok ( ( ) )
2019-08-29 14:46:54 -07:00
}