zebra-state: Add support for temporary sled databases (#939)

* Test config with persistent sled database
* Test ephemeral config
* Add misconfigured ephemeral test
This commit is contained in:
Ramana Venkata 2020-08-31 14:02:55 +05:30 committed by GitHub
parent d25cc20319
commit ad0001f7f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 140 additions and 35 deletions

View File

@ -123,33 +123,35 @@ where
}
#[tokio::test]
async fn batch_flushes_on_max_items() {
async fn batch_flushes_on_max_items() -> Result<(), Report> {
use tokio::time::timeout;
zebra_test::init();
// Use a very long max_latency and a short timeout to check that
// flushing is happening based on hitting max_items.
let verifier = Batch::new(Ed25519Verifier::new(), 10, Duration::from_secs(1000));
assert!(
timeout(Duration::from_secs(1), sign_and_verify(verifier, 100, None))
.await
.is_ok()
);
timeout(Duration::from_secs(1), sign_and_verify(verifier, 100, None))
.await
.map_err(|e| eyre!(e))?
.map_err(|e| eyre!(e))?;
Ok(())
}
#[tokio::test]
async fn batch_flushes_on_max_latency() {
async fn batch_flushes_on_max_latency() -> Result<(), Report> {
use tokio::time::timeout;
zebra_test::init();
// Use a very high max_items and a short timeout to check that
// flushing is happening based on hitting max_latency.
let verifier = Batch::new(Ed25519Verifier::new(), 100, Duration::from_millis(500));
assert!(
timeout(Duration::from_secs(1), sign_and_verify(verifier, 10, None))
.await
.is_ok()
);
timeout(Duration::from_secs(1), sign_and_verify(verifier, 10, None))
.await
.map_err(|e| eyre!(e))?
.map_err(|e| eyre!(e))?;
Ok(())
}
#[tokio::test]

View File

@ -69,6 +69,13 @@ pub struct Config {
/// The maximum number of bytes to use caching data in memory.
pub memory_cache_bytes: u64,
/// Whether to use an ephemeral database.
///
/// Ephemeral databases are stored in memory on Linux, and in a temporary directory on other OSes.
///
/// Set to `false` by default. If this is set to `true`, [`cache_dir`] is ignored.
pub ephemeral: bool,
}
impl Config {
@ -79,12 +86,16 @@ impl Config {
Network::Mainnet => "mainnet",
Network::Testnet => "testnet",
};
let path = self.cache_dir.join(net_dir).join("state");
sled::Config::default()
.path(path)
let config = sled::Config::default()
.cache_capacity(self.memory_cache_bytes)
.mode(sled::Mode::LowSpace)
.mode(sled::Mode::LowSpace);
if self.ephemeral {
config.temporary(self.ephemeral)
} else {
let path = self.cache_dir.join(net_dir).join("state");
config.path(path)
}
}
}
@ -96,6 +107,7 @@ impl Default for Config {
Self {
cache_dir,
memory_cache_bytes: 512 * 1024 * 1024,
ephemeral: false,
}
}
}

View File

@ -11,15 +11,25 @@ use tempdir::TempDir;
use zebra_test::prelude::*;
use zebrad::config::ZebradConfig;
pub fn tempdir(create_config: bool) -> Result<(PathBuf, impl Drop)> {
#[derive(PartialEq)]
enum ConfigMode {
NoConfig,
Ephemeral,
Persistent,
}
fn tempdir(config_mode: ConfigMode) -> Result<(PathBuf, impl Drop)> {
let dir = TempDir::new("zebrad_tests")?;
if create_config {
let cache_dir = dir.path().join("state");
fs::create_dir(&cache_dir)?;
if config_mode != ConfigMode::NoConfig {
let mut config = ZebradConfig::default();
config.state.cache_dir = cache_dir;
if config_mode == ConfigMode::Ephemeral {
config.state.ephemeral = true;
} else {
let cache_dir = dir.path().join("state");
fs::create_dir(&cache_dir)?;
config.state.cache_dir = cache_dir;
}
config.state.memory_cache_bytes = 256000000;
config.network.listen_addr = "127.0.0.1:0".parse()?;
@ -44,7 +54,7 @@ pub fn get_child(args: &[&str], tempdir: &PathBuf) -> Result<TestChild> {
#[test]
fn generate_no_args() -> Result<()> {
zebra_test::init();
let (tempdir, _guard) = tempdir(true)?;
let (tempdir, _guard) = tempdir(ConfigMode::Ephemeral)?;
let child = get_child(&["generate"], &tempdir)?;
let output = child.wait_with_output()?;
@ -59,7 +69,7 @@ fn generate_no_args() -> Result<()> {
#[test]
fn generate_args() -> Result<()> {
zebra_test::init();
let (tempdir, _guard) = tempdir(false)?;
let (tempdir, _guard) = tempdir(ConfigMode::NoConfig)?;
// unexpected free argument `argument`
let child = get_child(&["generate", "argument"], &tempdir)?;
@ -101,7 +111,7 @@ fn generate_args() -> Result<()> {
#[test]
fn help_no_args() -> Result<()> {
zebra_test::init();
let (tempdir, _guard) = tempdir(true)?;
let (tempdir, _guard) = tempdir(ConfigMode::Ephemeral)?;
let child = get_child(&["help"], &tempdir)?;
let output = child.wait_with_output()?;
@ -119,7 +129,7 @@ fn help_no_args() -> Result<()> {
#[test]
fn help_args() -> Result<()> {
zebra_test::init();
let (tempdir, _guard) = tempdir(true)?;
let (tempdir, _guard) = tempdir(ConfigMode::Ephemeral)?;
// The subcommand "argument" wasn't recognized.
let child = get_child(&["help", "argument"], &tempdir)?;
@ -137,7 +147,7 @@ fn help_args() -> Result<()> {
#[test]
fn revhex_args() -> Result<()> {
zebra_test::init();
let (tempdir, _guard) = tempdir(true)?;
let (tempdir, _guard) = tempdir(ConfigMode::Ephemeral)?;
// Valid
let child = get_child(&["revhex", "33eeff55"], &tempdir)?;
@ -152,7 +162,7 @@ fn revhex_args() -> Result<()> {
#[test]
fn seed_no_args() -> Result<()> {
zebra_test::init();
let (tempdir, _guard) = tempdir(true)?;
let (tempdir, _guard) = tempdir(ConfigMode::Ephemeral)?;
let mut child = get_child(&["-v", "seed"], &tempdir)?;
@ -174,7 +184,7 @@ fn seed_no_args() -> Result<()> {
#[test]
fn seed_args() -> Result<()> {
zebra_test::init();
let (tempdir, _guard) = tempdir(true)?;
let (tempdir, _guard) = tempdir(ConfigMode::Ephemeral)?;
// unexpected free argument `argument`
let child = get_child(&["seed", "argument"], &tempdir)?;
@ -197,7 +207,8 @@ fn seed_args() -> Result<()> {
#[test]
fn start_no_args() -> Result<()> {
zebra_test::init();
let (tempdir, _guard) = tempdir(true)?;
// start caches state, so run one of the start tests with persistent state
let (tempdir, _guard) = tempdir(ConfigMode::Persistent)?;
let mut child = get_child(&["-v", "start"], &tempdir)?;
@ -221,7 +232,7 @@ fn start_no_args() -> Result<()> {
#[test]
fn start_args() -> Result<()> {
zebra_test::init();
let (tempdir, _guard) = tempdir(true)?;
let (tempdir, _guard) = tempdir(ConfigMode::Ephemeral)?;
// Any free argument is valid
let mut child = get_child(&["start", "argument"], &tempdir)?;
@ -243,10 +254,90 @@ fn start_args() -> Result<()> {
Ok(())
}
#[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
assert!(output.was_killed());
// Check that we have persistent sled database
let cache_dir = tempdir.join("state");
assert!(cache_dir.read_dir()?.count() > 0);
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
assert!(output.was_killed());
let cache_dir = tempdir.join("state");
assert!(!cache_dir.exists());
Ok(())
}
#[test]
fn misconfigured_ephemeral_mode() -> Result<()> {
zebra_test::init();
let dir = TempDir::new("zebrad_tests")?;
let cache_dir = dir.path().join("state");
// Write a configuration that has both cache_dir and ephemeral options set
let mut config = ZebradConfig::default();
config.state.ephemeral = true;
// Although cache_dir has a default value, we set it a new temp directory
// to test that it is empty later.
fs::create_dir(&cache_dir)?;
config.state.cache_dir = cache_dir.clone();
config.state.memory_cache_bytes = 256000000;
config.network.listen_addr = "127.0.0.1:0".parse()?;
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
assert!(output.was_killed());
// Check that ephemeral takes precedence over cache_dir
assert_eq!(cache_dir.read_dir()?.count(), 0);
Ok(())
}
#[test]
fn app_no_args() -> Result<()> {
zebra_test::init();
let (tempdir, _guard) = tempdir(true)?;
let (tempdir, _guard) = tempdir(ConfigMode::Ephemeral)?;
let child = get_child(&[], &tempdir)?;
let output = child.wait_with_output()?;
@ -260,7 +351,7 @@ fn app_no_args() -> Result<()> {
#[test]
fn version_no_args() -> Result<()> {
zebra_test::init();
let (tempdir, _guard) = tempdir(true)?;
let (tempdir, _guard) = tempdir(ConfigMode::Ephemeral)?;
let child = get_child(&["version"], &tempdir)?;
let output = child.wait_with_output()?;
@ -274,7 +365,7 @@ fn version_no_args() -> Result<()> {
#[test]
fn version_args() -> Result<()> {
zebra_test::init();
let (tempdir, _guard) = tempdir(true)?;
let (tempdir, _guard) = tempdir(ConfigMode::Ephemeral)?;
// unexpected free argument `argument`
let child = get_child(&["version", "argument"], &tempdir)?;
@ -302,7 +393,7 @@ fn valid_generated_config_test() -> Result<()> {
fn valid_generated_config(command: &str, expected_output: &str) -> Result<()> {
zebra_test::init();
let (tempdir, _guard) = tempdir(false)?;
let (tempdir, _guard) = tempdir(ConfigMode::NoConfig)?;
// Add a config file name to tempdir path
let mut generated_config_path = tempdir.clone();