use crate::logger::{
LogEntry, LOG_ENTRY_MAX_FILENAME_LENGTH, LOG_ENTRY_MAX_HOSTNAME_LENGTH,
LOG_ENTRY_MAX_MESSAGE_LENGTH, LOG_ENTRY_MAX_MODULE_LENGTH,
};
use crate::Db;
use std::convert::TryFrom;
use time::OffsetDateTime;
pub(crate) trait TestContext {
fn db(&self) -> &(dyn Db + Send + Sync);
}
pub(crate) fn test_log_entries_none(mut context: Box<dyn TestContext>) {
#[tokio::main]
async fn run(context: &mut dyn TestContext) {
context.db().put_log_entries(vec![]).await.unwrap();
assert!(context.db().get_log_entries().await.unwrap().is_empty());
}
run(context.as_mut());
}
pub(crate) fn test_log_entries_individual(mut context: Box<dyn TestContext>) {
#[tokio::main]
async fn run(context: &mut dyn TestContext) {
let entry1 = LogEntry {
timestamp: OffsetDateTime::from_unix_timestamp_nanos(1_000_001_001),
hostname: "fake-host1".to_owned(),
level: log::Level::Error,
module: None,
filename: None,
line: None,
message: "Entry without optional fields".to_owned(),
};
context.db().put_log_entries(vec![entry1]).await.unwrap();
let entry2 = LogEntry {
timestamp: OffsetDateTime::from_unix_timestamp_nanos(12_345_000_006_000),
hostname: "fake-host2".to_owned(),
level: log::Level::Info,
module: Some("the-module"),
filename: Some("the-file"),
line: Some(42),
message: "Entry with optional fields".to_owned(),
};
context.db().put_log_entries(vec![entry2]).await.unwrap();
let exp_entries = vec![
"1.2000 fake-host1 1 NO-MODULE NO-FILENAME:-1 Entry without optional fields".to_owned(),
"12345.6000 fake-host2 3 the-module the-file:42 Entry with optional fields".to_owned(),
];
assert_eq!(exp_entries, context.db().get_log_entries().await.unwrap());
}
run(context.as_mut());
}
pub(crate) fn test_log_entries_combined(mut context: Box<dyn TestContext>) {
#[tokio::main]
async fn run(context: &mut dyn TestContext) {
let entry1 = LogEntry {
timestamp: OffsetDateTime::from_unix_timestamp_nanos(1_000_001_500),
hostname: "fake-host1".to_owned(),
level: log::Level::Error,
module: None,
filename: None,
line: None,
message: "Entry without optional fields".to_owned(),
};
let entry2 = LogEntry {
timestamp: OffsetDateTime::from_unix_timestamp_nanos(12_345_000_006_999),
hostname: "fake-host2".to_owned(),
level: log::Level::Info,
module: Some("the-module"),
filename: Some("the-file"),
line: Some(42),
message: "Entry with optional fields".to_owned(),
};
context.db().put_log_entries(vec![entry1, entry2]).await.unwrap();
let exp_entries = vec![
"1.2000 fake-host1 1 NO-MODULE NO-FILENAME:-1 Entry without optional fields".to_owned(),
"12345.7000 fake-host2 3 the-module the-file:42 Entry with optional fields".to_owned(),
];
assert_eq!(exp_entries, context.db().get_log_entries().await.unwrap());
}
run(context.as_mut());
}
pub(crate) fn test_log_entries_long_strings(mut context: Box<dyn TestContext>) {
#[tokio::main]
async fn run(context: &mut dyn TestContext) {
let mut long_string = String::with_capacity(5000);
for i in 0..long_string.capacity() {
long_string.push(char::from(b'0' + u8::try_from(i % 10).unwrap()));
}
let entry = LogEntry {
timestamp: OffsetDateTime::from_unix_timestamp(0),
hostname: long_string.to_owned(),
level: log::Level::Trace,
module: Some(&long_string),
filename: Some(&long_string),
line: None,
message: long_string.to_owned(),
};
context.db().put_log_entries(vec![entry]).await.unwrap();
let truncated_hostname = &long_string[0..LOG_ENTRY_MAX_HOSTNAME_LENGTH];
let truncated_module = &long_string[0..LOG_ENTRY_MAX_MODULE_LENGTH];
let truncated_filename = &long_string[0..LOG_ENTRY_MAX_FILENAME_LENGTH];
let truncated_message = &long_string[0..LOG_ENTRY_MAX_MESSAGE_LENGTH];
let exp_entries = vec![format!(
"0.0 {} 5 {} {}:-1 {}",
truncated_hostname, truncated_module, truncated_filename, truncated_message
)];
assert_eq!(exp_entries, context.db().get_log_entries().await.unwrap());
}
run(context.as_mut());
}