use db_logger::{Connection, Handle};
use gethostname::gethostname;
use log::*;
use std::env;
use std::time::Duration;
fn make_log_line(test_name: &str, level: u8, line: u32, message: &str) -> String {
let hostname =
gethostname().into_string().unwrap_or_else(|_e| String::from("invalid-hostname"));
format!(
"SSSS.uuuu {} {} {}::common tests/common/mod.rs:{} {}",
hostname, level, test_name, line, message
)
}
fn make_deterministic(lines: Vec<String>) -> Vec<String> {
let mut new_lines = Vec::with_capacity(lines.len());
let timestamp_re = regex::Regex::new("^[0-9]+.[0-9]+").unwrap();
for line in lines {
let line = timestamp_re.replace(&line, "SSSS.uuuu");
new_lines.push(line.to_string());
}
new_lines
}
async fn test_all_levels(test_name: &str, handle: &Handle, exp_logs: &mut Vec<String>) {
log::set_max_level(Level::Trace.to_level_filter());
let base_line = line!();
error!("An error message");
warn!("A warning message");
info!("An info message");
debug!("A debug message");
trace!("A trace message");
log::logger().flush();
exp_logs.push(make_log_line(test_name, 1, base_line + 1, "An error message"));
exp_logs.push(make_log_line(test_name, 2, base_line + 2, "A warning message"));
exp_logs.push(make_log_line(test_name, 3, base_line + 3, "An info message"));
exp_logs.push(make_log_line(test_name, 4, base_line + 4, "A debug message"));
exp_logs.push(make_log_line(test_name, 5, base_line + 5, "A trace message"));
let entries = handle.get_log_entries().await.unwrap();
assert_eq!(exp_logs, &make_deterministic(entries));
}
async fn test_level_filtering(test_name: &str, handle: &Handle, exp_logs: &mut Vec<String>) {
log::set_max_level(Level::Warn.to_level_filter());
let base_line = line!();
error!("An error message");
warn!("A warning message");
info!("An info message");
debug!("A debug message");
trace!("A trace message");
log::logger().flush();
exp_logs.push(make_log_line(test_name, 1, base_line + 1, "An error message"));
exp_logs.push(make_log_line(test_name, 2, base_line + 2, "A warning message"));
let entries = handle.get_log_entries().await.unwrap();
assert_eq!(exp_logs, &make_deterministic(entries));
}
async fn test_auto_flush(test_name: &str, handle: &Handle, exp_logs: &mut Vec<String>) {
log::set_max_level(Level::Info.to_level_filter());
let base_line = line!();
info!("Another message");
exp_logs.push(make_log_line(test_name, 3, base_line + 1, "Another message"));
let mut retries = 30;
while retries > 0 {
let entries = make_deterministic(handle.get_log_entries().await.unwrap());
if exp_logs == &entries {
break;
} else if retries == 0 {
assert_eq!(exp_logs, &entries);
panic!("Previous assertion should have failed");
}
tokio::time::sleep(Duration::new(0, 100)).await;
retries -= 1;
}
}
async fn test_flood(test_name: &str, handle: &Handle, exp_logs: &mut Vec<String>) {
log::set_max_level(Level::Info.to_level_filter());
for i in 0..10240 {
let base_line = line!();
info!("Message with index {}", i);
exp_logs.push(make_log_line(
test_name,
3,
base_line + 1,
&format!("Message with index {}", i),
));
}
log::logger().flush();
let entries = handle.get_log_entries().await.unwrap();
assert_eq!(exp_logs, &make_deterministic(entries));
}
pub(crate) fn do_test_everything(test_name: &str, db: Connection) {
#[tokio::main(flavor = "multi_thread", worker_threads = 2)]
async fn run_tests(test_name: &str, db: Connection) {
env::set_var("RUST_LOG", "trace");
let handle = db_logger::init(db).await;
let mut logs_accumulator = vec![];
test_all_levels(test_name, &handle, &mut logs_accumulator).await;
test_level_filtering(test_name, &handle, &mut logs_accumulator).await;
test_auto_flush(test_name, &handle, &mut logs_accumulator).await;
test_flood(test_name, &handle, &mut logs_accumulator).await;
}
run_tests(test_name, db);
}