Skip to content

Commit

Permalink
Rewrite the gRPC and full sync tests for the new APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
teor2345 committed Sep 21, 2022
1 parent 5ac8d47 commit 335099c
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 235 deletions.
187 changes: 80 additions & 107 deletions zebrad/tests/acceptance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,9 @@ use common::{
config::{
config_file_full_path, configs_dir, default_test_config, persistent_test_config, testdir,
},
launch::{
spawn_zebrad_for_rpc, wait_for_zebrad_and_lightwalletd_tip, ZebradTestDirExt,
BETWEEN_NODES_DELAY, LAUNCH_DELAY,
},
launch::{spawn_zebrad_for_rpc, ZebradTestDirExt, BETWEEN_NODES_DELAY, LAUNCH_DELAY},
lightwalletd::{
random_known_rpc_port_config, zebra_skip_lightwalletd_tests, LightWalletdTestDirExt,
can_spawn_lightwalletd_for_rpc, random_known_rpc_port_config, spawn_lightwalletd_for_rpc,
LightwalletdTestType::{self, *},
},
sync::{
Expand Down Expand Up @@ -1403,25 +1400,31 @@ fn zebrad_update_sync() -> Result<()> {

/// Make sure `lightwalletd` can sync from Zebra, in update sync mode.
///
/// This test only runs when the `ZEBRA_TEST_LIGHTWALLETD`,
/// `ZEBRA_CACHED_STATE_DIR`, and `LIGHTWALLETD_DATA_DIR` env vars are set.
/// This test only runs when:
/// - the `ZEBRA_TEST_LIGHTWALLETD`, `ZEBRA_CACHED_STATE_DIR`, and
/// `LIGHTWALLETD_DATA_DIR` env vars are set, and
/// - Zebra is compiled with `--features=lightwalletd-grpc-tests`.
///
/// This test doesn't work on Windows, so it is always skipped on that platform.
#[test]
#[cfg(not(target_os = "windows"))]
#[cfg(feature = "lightwalletd-grpc-tests")]
fn lightwalletd_update_sync() -> Result<()> {
lightwalletd_integration_test(UpdateCachedState)
}

/// Make sure `lightwalletd` can fully sync from genesis using Zebra.
///
/// This test only runs when the `ZEBRA_TEST_LIGHTWALLETD` and
/// `ZEBRA_CACHED_STATE_DIR` env vars are set.
/// This test only runs when:
/// - the `ZEBRA_TEST_LIGHTWALLETD` and `ZEBRA_CACHED_STATE_DIR` env vars are set, and
/// - Zebra is compiled with `--features=lightwalletd-grpc-tests`.
///
///
/// This test doesn't work on Windows, so it is always skipped on that platform.
#[test]
#[ignore]
#[cfg(not(target_os = "windows"))]
#[cfg(feature = "lightwalletd-grpc-tests")]
fn lightwalletd_full_sync() -> Result<()> {
lightwalletd_integration_test(FullSyncFromGenesis {
allow_lightwalletd_cached_state: false,
Expand All @@ -1439,7 +1442,7 @@ fn lightwalletd_full_sync() -> Result<()> {
/// - run a send transaction gRPC test,
/// - run read-only gRPC tests.
///
/// The gRPC tests only run when the `lightwalletd-grpc-tests` is on.
/// The lightwalletd full, update, and gRPC tests only run with `--features=lightwalletd-grpc-tests`.
///
/// These tests don't work on Windows, so they are always skipped on that platform.
#[tokio::test]
Expand Down Expand Up @@ -1485,69 +1488,37 @@ async fn lightwalletd_test_suite() -> Result<()> {
///
/// # Panics
///
/// If the `test_type` is UpdateZebraCachedStateNoRpc
/// If the `test_type` requires `--features=lightwalletd-grpc-tests`,
/// but Zebra was not compiled with that feature.
#[tracing::instrument]
fn lightwalletd_integration_test(test_type: LightwalletdTestType) -> Result<()> {
let _init_guard = zebra_test::init();

if zebra_test::net::zebra_skip_network_tests() {
return Ok(());
}
// We run these sync tests with a network connection, for better test coverage.
let use_internet_connection = true;
let network = Mainnet;
let test_name = "lightwalletd_integration_test";

// Skip the test unless the user specifically asked for it
//
// TODO: pass test_type to zebra_skip_lightwalletd_tests() and check for lightwalletd launch in there
if test_type.launches_lightwalletd() && zebra_skip_lightwalletd_tests() {
if test_type.launches_lightwalletd() && !can_spawn_lightwalletd_for_rpc(test_name, test_type) {
tracing::info!("skipping test due to missing lightwalletd network or cached state");
return Ok(());
}

// TODO: split the zebrad and lightwalletd launches and checks into separate functions?

// Get the zebrad config

// Handle the Zebra state directory based on the test type:
// - LaunchWithEmptyState: ignore the state directory
// - FullSyncFromGenesis, UpdateCachedState, UpdateZebraCachedStateNoRpc:
// skip the test if it is not available, timeout if it is not populated

// Write a configuration that has RPC listen_addr set (if needed).
// If the state path env var is set, use it in the config.
let config = if let Some(config) =
test_type.zebrad_config("lightwalletd_integration_test".to_string())
// Launch zebra with peers and using a predefined zebrad state path.
let (mut zebrad, zebra_rpc_address) = if let Some(zebrad_and_address) =
spawn_zebrad_for_rpc(network, test_name, test_type, use_internet_connection)?
{
config?
tracing::info!(
?test_type,
"running lightwalletd & zebrad integration test, launching zebrad...",
);

zebrad_and_address
} else {
// Skip the test, we don't have the required cached state
return Ok(());
};

// Handle the lightwalletd state directory based on the test type:
// - LaunchWithEmptyState, UpdateZebraCachedStateNoRpc: ignore the state directory
// - FullSyncFromGenesis: use it if available, timeout if it is already populated
// - UpdateCachedState: skip the test if it is not available, timeout if it is not populated
let lightwalletd_state_path =
test_type.lightwalletd_state_path("lightwalletd_integration_test".to_string());

if test_type.needs_lightwalletd_cached_state() && lightwalletd_state_path.is_none() {
return Ok(());
}

tracing::info!(
?test_type,
?config,
?lightwalletd_state_path,
"running lightwalletd & zebrad integration test",
);

// Get the lists of process failure logs
let (zebrad_failure_messages, zebrad_ignore_messages) = test_type.zebrad_failure_messages();

// Launch zebrad
let zdir = testdir()?.with_exact_config(&config)?;
let mut zebrad = zdir
.spawn_child(args!["start"])?
.with_timeout(test_type.zebrad_timeout())
.with_failure_regex_iter(zebrad_failure_messages, zebrad_ignore_messages);

if test_type.needs_zebra_cached_state() {
zebrad
.expect_stdout_line_matches(r"loaded Zebra state cache .*tip.*=.*Height\([0-9]{7}\)")?;
Expand All @@ -1557,32 +1528,21 @@ fn lightwalletd_integration_test(test_type: LightwalletdTestType) -> Result<()>
}

// Launch lightwalletd, if needed
let lightwalletd = if test_type.launches_lightwalletd() {
// Wait until `zebrad` has opened the RPC endpoint
zebrad.expect_stdout_line_matches(regex::escape(
format!("Opened RPC endpoint at {}", config.rpc.listen_addr.unwrap()).as_str(),
))?;

// Write a fake zcashd configuration that has the rpcbind and rpcport options set
let ldir = testdir()?;
let ldir = ldir.with_lightwalletd_config(config.rpc.listen_addr.unwrap())?;

let (lightwalletd_failure_messages, lightwalletd_ignore_messages) =
test_type.lightwalletd_failure_messages();

// Launch the lightwalletd process
let lightwalletd = if test_type == LaunchWithEmptyState {
ldir.spawn_lightwalletd_child(None, args![])?
} else {
ldir.spawn_lightwalletd_child(lightwalletd_state_path, args![])?
};
let lightwalletd_and_port = if test_type.launches_lightwalletd() {
tracing::info!(
?zebra_rpc_address,
"launching lightwalletd connected to zebrad",
);

let mut lightwalletd = lightwalletd
.with_timeout(test_type.lightwalletd_timeout())
.with_failure_regex_iter(lightwalletd_failure_messages, lightwalletd_ignore_messages);
// Launch lightwalletd
let (mut lightwalletd, lightwalletd_rpc_port) =
spawn_lightwalletd_for_rpc(network, test_name, test_type, zebra_rpc_address)?
.expect("already checked for lightwalletd cached state and network");

// Wait until `lightwalletd` has launched
lightwalletd.expect_stdout_line_matches(regex::escape("Starting gRPC server"))?;
tracing::info!(
?lightwalletd_rpc_port,
"spawned lightwalletd connected to zebrad",
);

// Check that `lightwalletd` is calling the expected Zebra RPCs

Expand Down Expand Up @@ -1634,29 +1594,42 @@ fn lightwalletd_integration_test(test_type: LightwalletdTestType) -> Result<()>
}
}

Some(lightwalletd)
Some((lightwalletd, lightwalletd_rpc_port))
} else {
None
};

let (mut zebrad, lightwalletd) = if test_type.needs_zebra_cached_state() {
if let Some(lightwalletd) = lightwalletd {
if let Some((lightwalletd, lightwalletd_rpc_port)) = lightwalletd_and_port {
#[cfg(feature = "lightwalletd-grpc-tests")]
{
let (zebrad, lightwalletd) =
common::lightwalletd::wallet_grpc::wait_for_zebrad_and_lightwalletd_tip(
lightwalletd,
zebrad,
test_type,
)?;
use common::lightwalletd::wallet_grpc::wait_for_zebrad_and_lightwalletd_sync;

tracing::info!(
?lightwalletd_rpc_port,
"waiting for zebrad and lightwalletd to sync...",
);

let (lightwalletd, zebrad) = wait_for_zebrad_and_lightwalletd_sync(
lightwalletd,
lightwalletd_rpc_port,
zebrad,
zebra_rpc_address,
test_type,
// We want to wait for the mempool and network for better coverage
true,
use_internet_connection,
)?;

(zebrad, Some(lightwalletd))
}

#[cfg(not(feature = "lightwalletd-grpc-tests"))]
panic!(
"the {test_type:?} test requires `cargo test --feature lightwalletd-grpc-tests` \n\
zebrad: {zebrad:?} \n\
lightwalletd: {lightwalletd:?}"
"the {test_type:?} test requires `cargo test --feature lightwalletd-grpc-tests`\n\
zebrad: {zebrad:?}\n\
lightwalletd: {lightwalletd:?}\n\
lightwalletd_rpc_port: {lightwalletd_rpc_port:?}"
);
} else {
// We're just syncing Zebra, so there's no lightwalletd to check
Expand All @@ -1666,6 +1639,8 @@ fn lightwalletd_integration_test(test_type: LightwalletdTestType) -> Result<()>
(zebrad, None)
}
} else {
let lightwalletd = lightwalletd_and_port.map(|(lightwalletd, _port)| lightwalletd);

// We don't have a cached state, so we don't do any tip checks for Zebra or lightwalletd
(zebrad, lightwalletd)
};
Expand Down Expand Up @@ -1946,23 +1921,21 @@ async fn fully_synced_rpc_test() -> Result<()> {
let _init_guard = zebra_test::init();

// We're only using cached Zebra state here, so this test type is the most similar
let test_type = LightwalletdTestType::FullSyncFromGenesis {
allow_lightwalletd_cached_state: false,
};
let test_type = LightwalletdTestType::UpdateCachedState;
let network = Network::Mainnet;

// Handle the Zebra state directory
let cached_state_path = test_type.zebrad_state_path("fully_synced_rpc_test".to_string());
let (mut zebrad, zebra_rpc_address) = if let Some(zebrad_and_address) =
spawn_zebrad_for_rpc(network, "fully_synced_rpc_test", test_type, false)?
{
tracing::info!("running fully synced zebrad RPC test");

if cached_state_path.is_none() {
zebrad_and_address
} else {
// Skip the test, we don't have the required cached state
return Ok(());
};

tracing::info!("running fully synced zebrad RPC test");

let network = Network::Mainnet;

let (_zebrad, zebra_rpc_address) =
spawn_zebrad_for_rpc(network, cached_state_path.unwrap(), test_type, true, false)?;
zebrad.expect_stdout_line_matches(&format!("Opened RPC endpoint at {}", zebra_rpc_address))?;

// Make a getblock test that works only on synced node (high block number).
// The block is before the mandatory checkpoint, so the checkpoint cached state can be used
Expand Down
Loading

0 comments on commit 335099c

Please sign in to comment.