From 87a8d328d53fc4ca27e80610ff3bdea26a580e62 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 22 Jun 2020 21:31:44 -0700 Subject: [PATCH] Rewrite zebra-state tests to use transcripts. This makes adding more tests easier. --- Cargo.lock | 1 + zebra-state/Cargo.toml | 1 + zebra-state/src/lib.rs | 163 +------------------------------------ zebra-state/tests/basic.rs | 96 ++++++++++++++++++++++ 4 files changed, 100 insertions(+), 161 deletions(-) create mode 100644 zebra-state/tests/basic.rs diff --git a/Cargo.lock b/Cargo.lock index 06c63f66..421dc534 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2385,6 +2385,7 @@ dependencies = [ "futures", "hex", "lazy_static", + "once_cell", "serde", "sled", "spandoc", diff --git a/zebra-state/Cargo.toml b/zebra-state/Cargo.toml index 35af8f3e..0e55baaa 100644 --- a/zebra-state/Cargo.toml +++ b/zebra-state/Cargo.toml @@ -26,3 +26,4 @@ tracing-error = "0.1.2" tracing-subscriber = "0.2.6" tempdir = "0.3.7" color-eyre = "0.5" +once_cell = "1.4" diff --git a/zebra-state/src/lib.rs b/zebra-state/src/lib.rs index 8fd565f5..47cea475 100644 --- a/zebra-state/src/lib.rs +++ b/zebra-state/src/lib.rs @@ -42,7 +42,7 @@ impl Default for Config { } } -#[derive(Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] /// A state request, used to manipulate the zebra-state on disk or in memory pub enum Request { // TODO(jlusby): deprecate in the future based on our validation story @@ -65,7 +65,7 @@ pub enum Request { }, } -#[derive(Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] /// A state response pub enum Response { /// The response to a `AddBlock` request indicating a block was successfully @@ -91,162 +91,3 @@ pub enum Response { Option, ), } - -#[cfg(test)] -mod tests { - use super::*; - use color_eyre::eyre::Report; - use color_eyre::eyre::{bail, ensure, eyre}; - use std::sync::Once; - use tower::Service; - use tracing_error::ErrorLayer; - use tracing_subscriber::prelude::*; - use tracing_subscriber::{fmt, EnvFilter}; - use zebra_chain::serialization::ZcashDeserialize; - - static LOGGER_INIT: Once = Once::new(); - - fn install_tracing() { - LOGGER_INIT.call_once(|| { - let fmt_layer = fmt::layer().with_target(false); - let filter_layer = EnvFilter::try_from_default_env() - .or_else(|_| EnvFilter::try_new("info")) - .unwrap(); - - tracing_subscriber::registry() - .with(filter_layer) - .with(fmt_layer) - .with(ErrorLayer::default()) - .init(); - }) - } - - #[tokio::test] - async fn test_round_trip() -> Result<(), Report> { - install_tracing(); - - let service = in_memory::init(); - round_trip(service).await?; - - let mut config = crate::Config::default(); - let tmp_dir = tempdir::TempDir::new("round_trip")?; - config.path = tmp_dir.path().to_owned(); - let service = on_disk::init(config); - get_tip(service).await?; - - Ok(()) - } - - async fn round_trip(mut service: S) -> Result<(), Report> - where - S: Service< - Request, - Error = Box, - Response = Response, - >, - { - let block: Arc<_> = - Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_415000_BYTES[..])?.into(); - let hash = block.as_ref().into(); - - let response = service - .call(Request::AddBlock { - block: block.clone(), - }) - .await - .map_err(|e| eyre!(e))?; - - ensure!( - response == Response::Added { hash }, - "unexpected response kind: {:?}", - response - ); - - let block_response = service - .call(Request::GetBlock { hash }) - .await - .map_err(|e| eyre!(e))?; - - match block_response { - Response::Block { - block: returned_block, - } => assert_eq!(block, returned_block), - _ => bail!("unexpected response kind: {:?}", block_response), - } - - Ok(()) - } - - #[tokio::test] - async fn test_get_tip() -> Result<(), Report> { - install_tracing(); - - let service = in_memory::init(); - get_tip(service).await?; - - let mut config = crate::Config::default(); - let tmp_dir = tempdir::TempDir::new("get_tip")?; - config.path = tmp_dir.path().to_owned(); - let service = on_disk::init(config); - get_tip(service).await?; - - Ok(()) - } - - #[spandoc::spandoc] - async fn get_tip(mut service: S) -> Result<(), Report> - where - S: Service< - Request, - Error = Box, - Response = Response, - >, - { - install_tracing(); - - let block0: Arc<_> = - Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..])?.into(); - let block1: Arc<_> = - Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_1_BYTES[..])?.into(); - - let block0_hash: BlockHeaderHash = block0.as_ref().into(); - let block1_hash: BlockHeaderHash = block1.as_ref().into(); - let expected_hash: BlockHeaderHash = block1_hash; - - /// insert the higher block first - let response = service - .call(Request::AddBlock { block: block1 }) - .await - .map_err(|e| eyre!(e))?; - - ensure!( - response == Response::Added { hash: block1_hash }, - "unexpected response kind: {:?}", - response - ); - - /// genesis block second - let response = service - .call(Request::AddBlock { - block: block0.clone(), - }) - .await - .map_err(|e| eyre!(e))?; - - ensure!( - response == Response::Added { hash: block0_hash }, - "unexpected response kind: {:?}", - response - ); - - let block_response = service.call(Request::GetTip).await.map_err(|e| eyre!(e))?; - - /// assert that the higher block is returned as the tip even tho it was least recently inserted - match block_response { - Response::Tip { hash } => assert_eq!(expected_hash, hash), - _ => bail!("unexpected response kind: {:?}", block_response), - } - - Ok(()) - } -} diff --git a/zebra-state/tests/basic.rs b/zebra-state/tests/basic.rs new file mode 100644 index 00000000..dfe0ecac --- /dev/null +++ b/zebra-state/tests/basic.rs @@ -0,0 +1,96 @@ +use color_eyre::eyre::Report; +use color_eyre::eyre::{bail, ensure, eyre}; +use once_cell::sync::Lazy; +use std::sync::{Arc, Once}; +use tempdir::TempDir; +use tower::Service; +use tracing_error::ErrorLayer; +use tracing_subscriber::prelude::*; +use tracing_subscriber::{fmt, EnvFilter}; +use zebra_chain::{ + block::{Block, BlockHeaderHash}, + serialization::ZcashDeserialize, +}; +use zebra_test::transcript::Transcript; + +use zebra_state::*; + +static LOGGER_INIT: Once = Once::new(); + +fn install_tracing() { + LOGGER_INIT.call_once(|| { + let fmt_layer = fmt::layer().with_target(false); + let filter_layer = EnvFilter::try_from_default_env() + .or_else(|_| EnvFilter::try_new("info")) + .unwrap(); + + tracing_subscriber::registry() + .with(filter_layer) + .with(fmt_layer) + .with(ErrorLayer::default()) + .init(); + }) +} + +static ADD_BLOCK_TRANSCRIPT: Lazy> = Lazy::new(|| { + let block: Arc<_> = + Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_415000_BYTES[..]) + .unwrap() + .into(); + let hash = block.as_ref().into(); + vec![ + ( + Request::AddBlock { + block: block.clone(), + }, + Response::Added { hash }, + ), + (Request::GetBlock { hash }, Response::Block { block }), + ] +}); + +static GET_TIP_TRANSCRIPT: Lazy> = Lazy::new(|| { + let block0: Arc<_> = + Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..]) + .unwrap() + .into(); + let block1: Arc<_> = Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_1_BYTES[..]) + .unwrap() + .into(); + let hash0 = block0.as_ref().into(); + let hash1 = block1.as_ref().into(); + vec![ + // Insert higher block first, lower block second + ( + Request::AddBlock { block: block1 }, + Response::Added { hash: hash1 }, + ), + ( + Request::AddBlock { block: block0 }, + Response::Added { hash: hash0 }, + ), + (Request::GetTip, Response::Tip { hash: hash1 }), + ] +}); + +#[tokio::test] +async fn check_transcripts() -> Result<(), Report> { + install_tracing(); + + for transcript_data in &[&ADD_BLOCK_TRANSCRIPT, &GET_TIP_TRANSCRIPT] { + let service = in_memory::init(); + let transcript = Transcript::from(transcript_data.iter().cloned()); + transcript.check(service).await?; + + let storage_guard = TempDir::new("")?; + let service = on_disk::init(Config { + path: storage_guard.path().to_owned(), + }); + let transcript = Transcript::from(transcript_data.iter().cloned()); + transcript.check(service).await?; + // Delete the contents of the temp directory before going to the next case. + std::mem::drop(storage_guard); + } + + Ok(()) +}