#![recursion_limit = "256"]
#![doc(
html_logo_url = "https://github.com/maidsafe/QA/raw/master/Images/maidsafe_logo.png",
html_favicon_url = "https://maidsafe.net/img/favicon.ico",
test(attr(deny(warnings)))
)]
#![forbid(
arithmetic_overflow,
mutable_transmutes,
no_mangle_const_items,
unknown_crate_types,
unsafe_code
)]
#![warn(
missing_debug_implementations,
missing_docs,
trivial_casts,
trivial_numeric_casts,
unreachable_pub,
unused_extern_crates,
unused_import_braces,
unused_qualifications,
unused_results,
clippy::unicode_not_nfc
)]
#[macro_use]
extern crate tracing;
pub mod client;
mod dbs;
#[cfg(test)]
mod testnet_grep;
pub use sn_interface::network_knowledge::elder_count;
pub use dbs::UsedSpace;
pub mod node;
mod utils;
use tracing_core::{Event, Subscriber};
use tracing_subscriber::{
fmt::{
format::Writer,
time::{FormatTime, SystemTime},
FmtContext, FormatEvent, FormatFields, FormattedFields,
},
registry::LookupSpan,
};
pub(crate) const DEFAULT_DATA_COPY_COUNT: usize = 4;
const SN_DATA_COPY_COUNT: &str = "SN_DATA_COPY_COUNT";
pub(crate) fn max_num_faulty_elders() -> usize {
elder_count() / 3
}
pub(crate) fn at_least_one_correct_elder() -> usize {
max_num_faulty_elders() + 1
}
pub(crate) fn data_copy_count() -> usize {
match std::env::var(SN_DATA_COPY_COUNT) {
Ok(count) => match count.parse() {
Ok(count) => {
warn!(
"data_copy_count countout set from env var SN_DATA_COPY_COUNT: {:?}",
SN_DATA_COPY_COUNT
);
count
}
Err(error) => {
warn!("There was an error parsing {:?} env var. DEFAULT_DATA_COPY_COUNT will be used: {:?}", SN_DATA_COPY_COUNT, error);
DEFAULT_DATA_COPY_COUNT
}
},
Err(_) => DEFAULT_DATA_COPY_COUNT,
}
}
#[cfg(any(test, feature = "test-utils"))]
use std::sync::Once;
#[cfg(test)]
#[ctor::ctor]
fn test_setup() {
color_eyre::install().expect("color_eyre::install can only be called once");
}
#[derive(Default, Debug)]
pub struct LogFormatter;
impl<S, N> FormatEvent<S, N> for LogFormatter
where
S: Subscriber + for<'a> LookupSpan<'a>,
N: for<'a> FormatFields<'a> + 'static,
{
fn format_event(
&self,
ctx: &FmtContext<'_, S, N>,
mut writer: Writer,
event: &Event<'_>,
) -> std::fmt::Result {
let level = *event.metadata().level();
let target = event.metadata().file().unwrap_or("No target file known.");
let span_separation_string = "\t ➤ ";
let time = SystemTime::default();
write!(writer, " {} ", level)?;
time.format_time(&mut writer)?;
writeln!(
writer,
" [{}:L{}]:",
target,
event.metadata().line().unwrap_or(0),
)?;
write!(writer, "{}", span_separation_string)?;
ctx.visit_spans(|span| {
write!(writer, "{} ", span.name())?;
let ext = span.extensions();
let fields = &ext
.get::<FormattedFields<N>>()
.expect("will never be `None`");
if !fields.is_empty() {
write!(writer, "{{{}}}", fields)?;
}
write!(writer, "\n{}", span_separation_string)?;
Ok(())
})?;
ctx.field_format().format_fields(writer.by_ref(), event)?;
writeln!(writer)
}
}
#[cfg(any(test, feature = "test-utils"))]
static INIT: Once = Once::new();
#[cfg(any(test, feature = "test-utils"))]
pub fn init_test_logger() {
INIT.call_once(|| {
tracing_subscriber::fmt::fmt()
.with_thread_names(true)
.with_ansi(false)
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
.with_target(false)
.event_format(LogFormatter::default())
.try_init().unwrap_or_else(|_| println!("Error initializing logger"));
});
}
#[cfg(test)]
mod tests {
use crate::elder_count;
use crate::testnet_grep::search_testnet_results_per_node;
use eyre::Result;
use sn_interface::types::log_markers::LogMarker;
#[tokio::test(flavor = "multi_thread")]
#[ignore = "Testnet network_assert_ tests should be excluded from normal tests runs, they need to be run in sequence to ensure validity of checks"]
async fn split_network_assert_health_check() -> Result<()> {
let promoted_to_elder_nodes =
search_testnet_results_per_node(LogMarker::PromotedToElder.to_string())?.len();
let prefix1_prior_elder_nodes = search_testnet_results_per_node(format!(
r"{}: Prefix\(1\)",
LogMarker::StillElderAfterSplit
))?
.len();
let prefix1_new_elder_nodes = search_testnet_results_per_node(format!(
r"{}: Prefix\(1\)",
LogMarker::PromotedToElder
))?
.len();
let prefix0_prior_elder_nodes = search_testnet_results_per_node(format!(
r"{}: Prefix\(0\)",
LogMarker::StillElderAfterSplit
))?
.len();
let prefix0_new_elder_nodes = search_testnet_results_per_node(format!(
r"{}: Prefix\(0\)",
LogMarker::PromotedToElder
))?
.len();
let split_count =
search_testnet_results_per_node(LogMarker::SplitSuccess.to_string())?.len();
let desired_elder_count = elder_count();
println!("Found splits: {:?}", split_count);
println!(
"Desired elder_count() per section: {:?}",
desired_elder_count
);
println!("Promoted to elder so far: {:?}", promoted_to_elder_nodes);
let total_elders = prefix0_prior_elder_nodes
+ prefix0_new_elder_nodes
+ prefix1_new_elder_nodes
+ prefix1_prior_elder_nodes;
println!("Found elders: {:?}", total_elders);
println!(
"Found prefix_0_prior_elders: {:?}",
prefix0_prior_elder_nodes
);
println!("Found prefix_0_new_elders: {:?}", prefix0_new_elder_nodes);
println!(
"Found prefix_1_prior_elders: {:?}",
prefix1_prior_elder_nodes
);
println!("Found prefix_1_new_elders: {:?}", prefix1_new_elder_nodes);
assert!(split_count >= desired_elder_count);
Ok(())
}
}