291 lines
10 KiB
Rust
291 lines
10 KiB
Rust
//! `zebra-scanner` binary tests.
|
|
|
|
use std::path::Path;
|
|
|
|
#[cfg(not(target_os = "windows"))]
|
|
use std::io::Write;
|
|
|
|
use tempfile::TempDir;
|
|
|
|
use zebra_test::{
|
|
args,
|
|
command::{Arguments, TestDirExt},
|
|
prelude::*,
|
|
};
|
|
|
|
#[cfg(not(target_os = "windows"))]
|
|
use zebra_grpc::scanner::{scanner_client::ScannerClient, Empty};
|
|
|
|
mod scan_task_commands;
|
|
|
|
/// The extended Sapling viewing key of [ZECpages](https://zecpages.com/boardinfo)
|
|
#[cfg(not(target_os = "windows"))]
|
|
const ZECPAGES_SAPLING_VIEWING_KEY: &str = "zxviews1q0duytgcqqqqpqre26wkl45gvwwwd706xw608hucmvfalr759ejwf7qshjf5r9aa7323zulvz6plhttp5mltqcgs9t039cx2d09mgq05ts63n8u35hyv6h9nc9ctqqtue2u7cer2mqegunuulq2luhq3ywjcz35yyljewa4mgkgjzyfwh6fr6jd0dzd44ghk0nxdv2hnv4j5nxfwv24rwdmgllhe0p8568sgqt9ckt02v2kxf5ahtql6s0ltjpkckw8gtymxtxuu9gcr0swvz";
|
|
|
|
/// Test the scanner binary with the `--help` flag.
|
|
#[test]
|
|
fn scanner_help() -> eyre::Result<()> {
|
|
let _init_guard = zebra_test::init();
|
|
|
|
let testdir = testdir()?;
|
|
|
|
let child = testdir.spawn_scanner_child(args!["--help"])?;
|
|
let output = child.wait_with_output()?;
|
|
let output = output.assert_success()?;
|
|
|
|
output.stdout_line_contains("USAGE:")?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Test that the scanner binary starts the scan task.
|
|
///
|
|
/// This test creates a new zebrad cache dir by using a `zebrad` binary specified in the `CARGO_BIN_EXE_zebrad` env variable.
|
|
///
|
|
/// To run it locally, one way is:
|
|
///
|
|
/// ```
|
|
/// cargo test scan_binary_starts -- --nocapture
|
|
/// ```
|
|
#[tokio::test]
|
|
#[cfg(not(target_os = "windows"))]
|
|
async fn scan_binary_starts() -> Result<()> {
|
|
use std::time::Duration;
|
|
|
|
let _init_guard = zebra_test::init();
|
|
|
|
// Create a directory to dump test data into it.
|
|
let test_dir = testdir()?;
|
|
|
|
// Create a config for zebrad with a cache directory inside the test directory.
|
|
let mut config = zebrad::config::ZebradConfig::default();
|
|
config.state.cache_dir = test_dir.path().join("zebra").to_path_buf();
|
|
let config_file = test_dir.path().join("zebrad.toml");
|
|
std::fs::File::create(config_file.clone())?.write_all(toml::to_string(&config)?.as_bytes())?;
|
|
|
|
// Start the node just to make sure a cache is created.
|
|
let mut zebrad =
|
|
test_dir.spawn_zebrad_child(args!["-c", config_file.clone().to_str().unwrap(), "start"])?;
|
|
zebrad.expect_stdout_line_matches("Opened Zebra state cache at .*")?;
|
|
|
|
// Kill the node now that we have a valid zebra node cache.
|
|
zebrad.kill(false)?;
|
|
let output = zebrad.wait_with_output()?;
|
|
|
|
// Make sure the command was killed
|
|
output.assert_was_killed()?;
|
|
|
|
// Create a new directory for the scanner
|
|
let test_dir = testdir()?;
|
|
|
|
// Create arguments for the scanner
|
|
let key = serde_json::json!({"key": ZECPAGES_SAPLING_VIEWING_KEY}).to_string();
|
|
let listen_addr = "127.0.0.1:8231";
|
|
let rpc_listen_addr = "127.0.0.1:8232";
|
|
let zebrad_cache_dir = config.state.cache_dir.clone();
|
|
let scanning_cache_dir = test_dir.path().join("scanner").to_path_buf();
|
|
let args = args![
|
|
"--zebrad-cache-dir",
|
|
zebrad_cache_dir.to_str().unwrap(),
|
|
"--scanning-cache-dir",
|
|
scanning_cache_dir.to_str().unwrap(),
|
|
"--sapling-keys-to-scan",
|
|
key,
|
|
"--listen-addr",
|
|
listen_addr,
|
|
"--zebra-rpc-listen-addr",
|
|
rpc_listen_addr
|
|
];
|
|
|
|
// Start the scaner using another test directory.
|
|
let mut zebra_scanner = test_dir.spawn_scanner_child(args)?;
|
|
|
|
// Check scanner was started.
|
|
zebra_scanner.expect_stdout_line_matches("loaded Zebra scanner cache")?;
|
|
|
|
// Wait for the scanner's gRPC server to start up
|
|
tokio::time::sleep(Duration::from_secs(1)).await;
|
|
|
|
// Check if the grpc server is up
|
|
let mut client = ScannerClient::connect(format!("http://{listen_addr}")).await?;
|
|
let request = tonic::Request::new(Empty {});
|
|
client.get_info(request).await?;
|
|
|
|
// Look for 2 scanner notices indicating we are below sapling activation.
|
|
zebra_scanner.expect_stdout_line_matches("scanner is waiting for Sapling activation. Current tip: [0-9]{1,4}, Sapling activation: 419200")?;
|
|
zebra_scanner.expect_stdout_line_matches("scanner is waiting for Sapling activation. Current tip: [0-9]{1,4}, Sapling activation: 419200")?;
|
|
|
|
// Kill the scanner.
|
|
zebra_scanner.kill(true)?;
|
|
|
|
// Check that scan task started and the scanning is done.
|
|
let output = zebra_scanner.wait_with_output()?;
|
|
|
|
// Make sure the command was killed
|
|
output.assert_was_killed()?;
|
|
output.assert_failure()?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Test that the scanner can continue scanning where it was left when zebrad restarts.
|
|
///
|
|
/// Needs a cache state close to the tip. A possible way to run it locally is:
|
|
///
|
|
/// export ZEBRA_CACHED_STATE_DIR="/path/to/zebra/state"
|
|
/// cargo test scan_start_where_left -- --ignored --nocapture
|
|
///
|
|
/// The test will run zebrad with a key to scan, scan the first few blocks after sapling and then stops.
|
|
/// Then it will restart zebrad and check that it resumes scanning where it was left.
|
|
#[ignore]
|
|
#[tokio::test]
|
|
#[cfg(not(target_os = "windows"))]
|
|
async fn scan_start_where_left() -> Result<()> {
|
|
use ZECPAGES_SAPLING_VIEWING_KEY;
|
|
|
|
let _init_guard = zebra_test::init();
|
|
|
|
let Ok(zebrad_cachedir) = std::env::var("ZEBRA_CACHED_STATE_DIR") else {
|
|
tracing::info!("skipping scan_start_where_left test due to missing cached state, \
|
|
please set a ZEBRA_CACHED_STATE_DIR env var with a populated and valid path to run this test");
|
|
return Ok(());
|
|
};
|
|
|
|
// Logs the network as zebrad would as part of the metadata when starting up.
|
|
// This is currently needed for the 'Check startup logs' step in CI to pass.
|
|
let network = zebra_chain::parameters::Network::Mainnet;
|
|
tracing::info!("Zcash network: {network}");
|
|
|
|
let scanning_cache_dir = testdir()?.path().join("scanner").to_path_buf();
|
|
|
|
// Create arguments for the scanner
|
|
let key = serde_json::json!({"key": ZECPAGES_SAPLING_VIEWING_KEY}).to_string();
|
|
let listen_addr = "127.0.0.1:18231";
|
|
let rpc_listen_addr = "127.0.0.1:18232";
|
|
let args = args![
|
|
"--zebrad-cache-dir",
|
|
zebrad_cachedir,
|
|
"--scanning-cache-dir",
|
|
scanning_cache_dir.to_str().unwrap(),
|
|
"--sapling-keys-to-scan",
|
|
key,
|
|
"--listen-addr",
|
|
listen_addr,
|
|
"--zebra-rpc-listen-addr",
|
|
rpc_listen_addr
|
|
];
|
|
|
|
// Start the scaner using another test directory.
|
|
let mut zebra_scanner: TestChild<TempDir> = testdir()?.spawn_scanner_child(args.clone())?;
|
|
|
|
// Check scanner was started.
|
|
zebra_scanner.expect_stdout_line_matches("loaded Zebra scanner cache")?;
|
|
|
|
// The first time
|
|
zebra_scanner.expect_stdout_line_matches(
|
|
r"Scanning the blockchain for key 0, started at block 419200, now at block 420000",
|
|
)?;
|
|
|
|
// Make sure scanner scans a few blocks.
|
|
zebra_scanner.expect_stdout_line_matches(
|
|
r"Scanning the blockchain for key 0, started at block 419200, now at block 430000",
|
|
)?;
|
|
zebra_scanner.expect_stdout_line_matches(
|
|
r"Scanning the blockchain for key 0, started at block 419200, now at block 440000",
|
|
)?;
|
|
|
|
// Kill the scanner.
|
|
zebra_scanner.kill(true)?;
|
|
|
|
// Check that scan task started and the first scanning is done.
|
|
let output = zebra_scanner.wait_with_output()?;
|
|
|
|
// Make sure the command was killed
|
|
output.assert_was_killed()?;
|
|
output.assert_failure()?;
|
|
|
|
// Start the node again with the same arguments.
|
|
let mut zebra_scanner: TestChild<TempDir> = testdir()?.spawn_scanner_child(args)?;
|
|
|
|
// Resuming message.
|
|
zebra_scanner.expect_stdout_line_matches(
|
|
"Last scanned height for key number 0 is 439000, resuming at 439001",
|
|
)?;
|
|
zebra_scanner.expect_stdout_line_matches("loaded Zebra scanner cache")?;
|
|
|
|
// Start scanning where it was left.
|
|
zebra_scanner.expect_stdout_line_matches(
|
|
r"Scanning the blockchain for key 0, started at block 439001, now at block 440000",
|
|
)?;
|
|
zebra_scanner.expect_stdout_line_matches(
|
|
r"Scanning the blockchain for key 0, started at block 439001, now at block 450000",
|
|
)?;
|
|
|
|
// Kill the scanner.
|
|
zebra_scanner.kill(true)?;
|
|
|
|
// Check that scan task started and the second scanning is done.
|
|
let output = zebra_scanner.wait_with_output()?;
|
|
|
|
// Make sure the command was killed
|
|
output.assert_was_killed()?;
|
|
output.assert_failure()?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Tests successful:
|
|
/// - Registration of a new key,
|
|
/// - Subscription to scan results of new key, and
|
|
/// - Deletion of keys
|
|
/// in the scan task
|
|
/// See [`common::shielded_scan::scan_task_commands`] for more information.
|
|
///
|
|
/// Example of how to run the scan_task_commands test locally:
|
|
///
|
|
/// ```console
|
|
/// RUST_LOG=info ZEBRA_CACHED_STATE_DIR=/path/to/zebra/state cargo test scan_task_commands -- --include-ignored --nocapture
|
|
/// ```
|
|
#[tokio::test]
|
|
#[ignore]
|
|
async fn scan_task_commands() -> Result<()> {
|
|
scan_task_commands::run().await
|
|
}
|
|
|
|
/// Create a temporary directory for testing `zebra-scanner`.
|
|
pub fn testdir() -> eyre::Result<TempDir> {
|
|
tempfile::Builder::new()
|
|
.prefix("zebra_scanner_tests")
|
|
.tempdir()
|
|
.map_err(Into::into)
|
|
}
|
|
|
|
/// Extension trait for methods on `tempfile::TempDir` for using it as a test
|
|
/// directory for `zebra-scanner`.
|
|
pub trait ScannerTestDirExt
|
|
where
|
|
Self: AsRef<Path> + Sized,
|
|
{
|
|
/// Spawn `zebra-scanner` with `args` as a child process in this test directory.
|
|
fn spawn_scanner_child(self, args: Arguments) -> Result<TestChild<Self>>;
|
|
|
|
/// Spawn `zebrad` with `args` as a child process in this test directory.
|
|
fn spawn_zebrad_child(self, args: Arguments) -> Result<TestChild<Self>>;
|
|
}
|
|
|
|
impl<T> ScannerTestDirExt for T
|
|
where
|
|
Self: TestDirExt + AsRef<Path> + Sized,
|
|
{
|
|
fn spawn_scanner_child(self, extra_args: Arguments) -> Result<TestChild<Self>> {
|
|
let mut args = Arguments::new();
|
|
args.merge_with(extra_args);
|
|
self.spawn_child_with_command(env!("CARGO_BIN_EXE_zebra-scanner"), args)
|
|
}
|
|
fn spawn_zebrad_child(self, extra_args: Arguments) -> Result<TestChild<Self>> {
|
|
let mut args = Arguments::new();
|
|
args.merge_with(extra_args);
|
|
self.spawn_child_with_command(env!("CARGO_BIN_EXE_zebrad-for-scanner"), args)
|
|
}
|
|
}
|