Skip to content

Commit

Permalink
fix(test): make the full sync tests cache state at /zebrad-cache (#…
Browse files Browse the repository at this point in the history
…4308)

* Rewrite the full sync tests to cache at /zebrad-cache

* Improve error reporting from cached state tests
  • Loading branch information
teor2345 authored May 5, 2022
1 parent 7cc8f7e commit d720ab0
Showing 1 changed file with 77 additions and 72 deletions.
149 changes: 77 additions & 72 deletions zebrad/tests/acceptance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
//! or you have poor network connectivity,
//! skip all the network tests by setting the `ZEBRA_SKIP_NETWORK_TESTS` environmental variable.
use std::{collections::HashSet, convert::TryInto, env, path::PathBuf, time::Duration};
use std::{collections::HashSet, convert::TryInto, env, path::PathBuf};

use color_eyre::{
eyre::{eyre, Result, WrapErr},
Expand Down Expand Up @@ -634,74 +634,14 @@ fn sync_large_checkpoints_mempool_mainnet() -> Result<()> {
.map(|_tempdir| ())
}

/// Test if `zebrad` can fully sync the chain on mainnet.
///
/// This test takes a long time to run, so we don't run it by default. This test is only executed
/// if there is an environment variable named `FULL_SYNC_MAINNET_TIMEOUT_MINUTES` set with the number
/// of minutes to wait for synchronization to complete before considering that the test failed.
#[test]
#[ignore]
fn full_sync_mainnet() {
// TODO: add "ZEBRA" at the start of this env var, to avoid clashes
full_sync_test(Mainnet, "FULL_SYNC_MAINNET_TIMEOUT_MINUTES").expect("unexpected test failure");
}

/// Test if `zebrad` can fully sync the chain on testnet.
///
/// This test takes a long time to run, so we don't run it by default. This test is only executed
/// if there is an environment variable named `FULL_SYNC_TESTNET_TIMEOUT_MINUTES` set with the number
/// of minutes to wait for synchronization to complete before considering that the test failed.
#[test]
#[ignore]
fn full_sync_testnet() {
// TODO: add "ZEBRA" at the start of this env var, to avoid clashes
full_sync_test(Testnet, "FULL_SYNC_TESTNET_TIMEOUT_MINUTES").expect("unexpected test failure");
}

/// Sync `network` until the chain tip is reached, or a timeout elapses.
///
/// The timeout is specified using an environment variable, with the name configured by the
/// `timeout_argument_name` parameter. The value of the environment variable must the number of
/// minutes specified as an integer.
fn full_sync_test(network: Network, timeout_argument_name: &str) -> Result<()> {
let timeout_argument: Option<u64> = env::var(timeout_argument_name)
.ok()
.and_then(|timeout_string| timeout_string.parse().ok());

if let Some(timeout_minutes) = timeout_argument {
sync_until(
block::Height::MAX,
network,
SYNC_FINISHED_REGEX,
Duration::from_secs(60 * timeout_minutes),
None,
MempoolBehavior::ShouldAutomaticallyActivate,
// Use checkpoints to increase full sync performance, and test default Zebra behaviour.
// (After the changes to the default config in #2368.)
//
// TODO: if full validation performance improves, do another test with checkpoint_sync off
true,
true,
)?;
} else {
tracing::info!(
?network,
"skipped full sync test, \
set the {:?} environmental variable to run the test",
timeout_argument_name,
);
}

Ok(())
}

fn create_cached_database(network: Network) -> Result<()> {
let height = network.mandatory_checkpoint_height();
let checkpoint_stop_regex = format!("{}.*CommitFinalized request", STOP_AT_HEIGHT_REGEX);

create_cached_database_height(
network,
height,
// We don't need the ZK parameters, we're only using checkpoints
true,
// Use checkpoints to increase sync performance while caching the database
true,
Expand All @@ -718,36 +658,77 @@ fn sync_past_mandatory_checkpoint(network: Network) -> Result<()> {
create_cached_database_height(
network,
height.unwrap(),
// We need the ZK parameters for full validation
false,
// Test full validation by turning checkpoints off
false,
// Check that we're doing full validation when we finish the cached sync
&full_validation_stop_regex,
)
}

/// Sync `network` until the chain tip is reached, or a timeout elapses.
///
/// The timeout is specified using an environment variable, with the name configured by the
/// `timeout_argument_name` parameter. The value of the environment variable must the number of
/// minutes specified as an integer.
fn full_sync_test(network: Network, timeout_argument_name: &str) -> Result<()> {
let timeout_argument: Option<u64> = env::var(timeout_argument_name)
.ok()
.and_then(|timeout_string| timeout_string.parse().ok());

// # TODO
//
// Replace hard-coded values in create_cached_database_height with:
// - the timeout in the environmental variable
// - the path from ZEBRA_CACHED_STATE_DIR
if let Some(_timeout_minutes) = timeout_argument {
create_cached_database_height(
network,
// Just keep going until we reach the chain tip
block::Height::MAX,
// We need the ZK parameters for full validation
false,
// Use the checkpoints to sync quickly, then do full validation until the chain tip
true,
// Finish when we reach the chain tip
SYNC_FINISHED_REGEX,
)
} else {
tracing::info!(
?network,
"skipped full sync test, \
set the {:?} environmental variable to run the test",
timeout_argument_name,
);

Ok(())
}
}

// These tests are ignored because they're too long running to run during our
// traditional CI, and they depend on persistent state that cannot be made
// available in github actions or google cloud build. Instead we run these tests
// directly in a vm we spin up on google compute engine, where we can mount
// drives populated by the first two tests, snapshot those drives, and then use
// those to more quickly run the second two tests.
// drives populated by the sync_to_mandatory_checkpoint tests, snapshot those drives,
// and then use them to more quickly run the sync_past_mandatory_checkpoint tests.

/// Sync up to the mandatory checkpoint height on mainnet and stop.
#[allow(dead_code)]
#[cfg_attr(feature = "test_sync_to_mandatory_checkpoint_mainnet", test)]
fn sync_to_mandatory_checkpoint_mainnet() {
fn sync_to_mandatory_checkpoint_mainnet() -> Result<()> {
zebra_test::init();
let network = Mainnet;
create_cached_database(network).unwrap();
create_cached_database(network)
}

/// Sync to the mandatory checkpoint height testnet and stop.
#[allow(dead_code)]
#[cfg_attr(feature = "test_sync_to_mandatory_checkpoint_testnet", test)]
fn sync_to_mandatory_checkpoint_testnet() {
fn sync_to_mandatory_checkpoint_testnet() -> Result<()> {
zebra_test::init();
let network = Testnet;
create_cached_database(network).unwrap();
create_cached_database(network)
}

/// Test syncing 1200 blocks (3 checkpoints) past the mandatory checkpoint on mainnet.
Expand All @@ -757,10 +738,10 @@ fn sync_to_mandatory_checkpoint_testnet() {
/// activation by 1200 blocks, it will fail.
#[allow(dead_code)]
#[cfg_attr(feature = "test_sync_past_mandatory_checkpoint_mainnet", test)]
fn sync_past_mandatory_checkpoint_mainnet() {
fn sync_past_mandatory_checkpoint_mainnet() -> Result<()> {
zebra_test::init();
let network = Mainnet;
sync_past_mandatory_checkpoint(network).unwrap();
sync_past_mandatory_checkpoint(network)
}

/// Test syncing 1200 blocks (3 checkpoints) past the mandatory checkpoint on testnet.
Expand All @@ -770,10 +751,34 @@ fn sync_past_mandatory_checkpoint_mainnet() {
/// activation by 1200 blocks, it will fail.
#[allow(dead_code)]
#[cfg_attr(feature = "test_sync_past_mandatory_checkpoint_testnet", test)]
fn sync_past_mandatory_checkpoint_testnet() {
fn sync_past_mandatory_checkpoint_testnet() -> Result<()> {
zebra_test::init();
let network = Testnet;
sync_past_mandatory_checkpoint(network).unwrap();
sync_past_mandatory_checkpoint(network)
}

/// Test if `zebrad` can fully sync the chain on mainnet.
///
/// This test takes a long time to run, so we don't run it by default. This test is only executed
/// if there is an environment variable named `FULL_SYNC_MAINNET_TIMEOUT_MINUTES` set with the number
/// of minutes to wait for synchronization to complete before considering that the test failed.
#[test]
#[ignore]
fn full_sync_mainnet() -> Result<()> {
// TODO: add "ZEBRA" at the start of this env var, to avoid clashes
full_sync_test(Mainnet, "FULL_SYNC_MAINNET_TIMEOUT_MINUTES")
}

/// Test if `zebrad` can fully sync the chain on testnet.
///
/// This test takes a long time to run, so we don't run it by default. This test is only executed
/// if there is an environment variable named `FULL_SYNC_TESTNET_TIMEOUT_MINUTES` set with the number
/// of minutes to wait for synchronization to complete before considering that the test failed.
#[test]
#[ignore]
fn full_sync_testnet() -> Result<()> {
// TODO: add "ZEBRA" at the start of this env var, to avoid clashes
full_sync_test(Testnet, "FULL_SYNC_TESTNET_TIMEOUT_MINUTES")
}

#[tokio::test]
Expand Down

0 comments on commit d720ab0

Please sign in to comment.