#![doc(html_favicon_url = "https://zfnd.org/wp-content/uploads/2022/03/zebra-favicon-128.png")]
#![doc(html_logo_url = "https://zfnd.org/wp-content/uploads/2022/03/zebra-icon.png")]
#![doc(html_root_url = "https://docs.rs/zebra_test")]
#![recursion_limit = "512"]
use std::sync::Once;
use color_eyre::section::PanicMessage;
use once_cell::sync::Lazy;
use owo_colors::OwoColorize;
use tracing_error::ErrorLayer;
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
#[allow(missing_docs)]
pub mod command;
pub mod mock_service;
pub mod net;
pub mod network_addr;
pub mod prelude;
pub mod service_extensions;
pub mod transcript;
pub mod vectors;
pub mod zip0143;
pub mod zip0243;
pub mod zip0244;
pub static SINGLE_THREADED_RUNTIME: Lazy<tokio::runtime::Runtime> = Lazy::new(|| {
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("Failed to create Tokio runtime")
});
pub static MULTI_THREADED_RUNTIME: Lazy<tokio::runtime::Runtime> = Lazy::new(|| {
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.expect("Failed to create Tokio runtime")
});
static INIT: Once = Once::new();
#[must_use]
pub fn init() -> impl Drop {
let mut settings = insta::Settings::clone_current();
settings.set_prepend_module_to_snapshot(false);
let drop_guard = settings.bind_to_scope();
INIT.call_once(|| {
let fmt_layer = fmt::layer().with_target(false);
let filter_layer = EnvFilter::try_from_default_env()
.unwrap_or_else(|_| {
EnvFilter::try_new("warn")
.unwrap()
.add_directive("zebra_consensus=error".parse().unwrap())
.add_directive("zebra_network=error".parse().unwrap())
.add_directive("zebra_state=error".parse().unwrap())
.add_directive("zebrad=error".parse().unwrap())
.add_directive("tor_circmgr=error".parse().unwrap())
})
;
tracing_subscriber::registry()
.with(filter_layer)
.with(fmt_layer)
.with(ErrorLayer::default())
.init();
color_eyre::config::HookBuilder::default()
.add_frame_filter(Box::new(|frames| {
let mut displayed = std::collections::HashSet::new();
let filters = &[
"tokio::",
"<futures_util::",
"std::panic",
"test::run_test_in_process",
"core::ops::function::FnOnce::call_once",
"std::thread::local",
"<core::future::",
"<alloc::boxed::Box",
"<std::panic::AssertUnwindSafe",
"core::result::Result",
"<T as futures_util",
"<tracing_futures::Instrumented",
"test::assert_test_result",
"spandoc::",
];
frames.retain(|frame| {
let loc = (frame.lineno, &frame.filename);
let inserted = displayed.insert(loc);
if !inserted {
return false;
}
!filters.iter().any(|f| {
let name = if let Some(name) = frame.name.as_ref() {
name.as_str()
} else {
return true;
};
name.starts_with(f)
})
});
}))
.panic_message(SkipTestReturnedErrPanicMessages)
.install()
.unwrap();
});
drop_guard
}
pub fn init_async() -> (tokio::runtime::Runtime, impl Drop) {
let drop_guard = init();
(
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("Failed to create Tokio runtime"),
drop_guard,
)
}
struct SkipTestReturnedErrPanicMessages;
impl PanicMessage for SkipTestReturnedErrPanicMessages {
fn display(
&self,
pi: &std::panic::PanicHookInfo<'_>,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
let payload = pi
.payload()
.downcast_ref::<String>()
.map(String::as_str)
.or_else(|| pi.payload().downcast_ref::<&str>().cloned())
.unwrap_or("<non string panic payload>");
if payload.contains("the test returned a termination value with a non-zero status code") {
return write!(f, "---- end of test output ----");
}
writeln!(f, "{}", "\nThe application panicked (crashed).".red())?;
write!(f, "Message: ")?;
writeln!(f, "{}", payload.cyan())?;
write!(f, "Location: ")?;
if let Some(loc) = pi.location() {
write!(f, "{}", loc.file().purple())?;
write!(f, ":")?;
write!(f, "{}", loc.line().purple())?;
} else {
write!(f, "<unknown>")?;
}
Ok(())
}
}