227 lines
10 KiB
Rust
227 lines
10 KiB
Rust
// file: crates/ksp-logging-lib/unit_tests/settings.rs
|
|
// version: 3
|
|
|
|
fn unrestricted_file(output_id: &str) -> crate::FileSettings {
|
|
return crate::FileSettings::new(
|
|
output_id,
|
|
true,
|
|
"logs",
|
|
format!("{output_id}.log"),
|
|
crate::FileRotation::Daily,
|
|
crate::LogFormat::Human,
|
|
crate::OutputFilter::unrestricted(),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn level_variants_are_distinct() {
|
|
assert_ne!(crate::LogFilterLevel::Off, crate::LogFilterLevel::Error);
|
|
assert_ne!(crate::LogFilterLevel::Error, crate::LogFilterLevel::Warn);
|
|
assert_ne!(crate::LogFilterLevel::Warn, crate::LogFilterLevel::Info);
|
|
assert_ne!(crate::LogFilterLevel::Info, crate::LogFilterLevel::Debug);
|
|
assert_ne!(crate::LogFilterLevel::Debug, crate::LogFilterLevel::Trace);
|
|
}
|
|
|
|
#[test]
|
|
fn format_variants_are_distinct() {
|
|
assert_ne!(crate::LogFormat::Human, crate::LogFormat::Compact);
|
|
assert_ne!(crate::LogFormat::Compact, crate::LogFormat::Pretty);
|
|
assert_ne!(crate::LogFormat::Pretty, crate::LogFormat::Json);
|
|
}
|
|
|
|
#[test]
|
|
fn target_filter_preserves_prefix_and_level() {
|
|
let filter = crate::TargetFilter::new("ksp-store-lib", crate::LogFilterLevel::Trace);
|
|
assert_eq!(filter.target_prefix(), "ksp-store-lib");
|
|
assert_eq!(filter.level(), crate::LogFilterLevel::Trace);
|
|
}
|
|
|
|
#[test]
|
|
fn output_filter_preserves_level_targets_and_domains() {
|
|
let filter = crate::OutputFilter::new(
|
|
crate::LogFilterLevel::Debug,
|
|
std::vec!["ksp-config-lib".to_string(), "ksp-logging-lib".to_string()],
|
|
std::vec!["config".to_string(), "logging.runtime".to_string()],
|
|
);
|
|
assert_eq!(filter.level(), crate::LogFilterLevel::Debug);
|
|
assert_eq!(filter.targets().len(), 2);
|
|
assert_eq!(filter.targets()[0], "ksp-config-lib");
|
|
assert_eq!(filter.targets()[1], "ksp-logging-lib");
|
|
assert_eq!(filter.domains().len(), 2);
|
|
assert_eq!(filter.domains()[0], "config");
|
|
assert_eq!(filter.domains()[1], "logging.runtime");
|
|
let unrestricted = crate::OutputFilter::unrestricted();
|
|
assert_eq!(unrestricted.level(), crate::LogFilterLevel::Trace);
|
|
assert_eq!(unrestricted.targets(), &["*".to_string()]);
|
|
assert_eq!(unrestricted.domains(), &["*".to_string()]);
|
|
}
|
|
|
|
#[test]
|
|
fn console_settings_preserve_enabled_stream_ansi_format_and_filter() {
|
|
let filter = crate::OutputFilter::new(crate::LogFilterLevel::Debug, std::vec!["*".to_string()], std::vec!["config".to_string()]);
|
|
let settings = crate::ConsoleSettings::new(true, crate::ConsoleOutput::Stderr, true, crate::LogFormat::Compact, filter.clone());
|
|
assert!(settings.enabled());
|
|
assert_eq!(settings.output(), crate::ConsoleOutput::Stderr);
|
|
assert!(settings.ansi());
|
|
assert_eq!(settings.format(), crate::LogFormat::Compact);
|
|
assert_eq!(settings.filter(), &filter);
|
|
}
|
|
|
|
#[test]
|
|
fn compatibility_console_constructors_are_unrestricted_human_and_non_ansi() {
|
|
let stdout = crate::ConsoleSettings::stdout();
|
|
let stderr = crate::ConsoleSettings::stderr();
|
|
assert_eq!(stdout.output(), crate::ConsoleOutput::Stdout);
|
|
assert_eq!(stderr.output(), crate::ConsoleOutput::Stderr);
|
|
assert!(stdout.enabled());
|
|
assert!(!stdout.ansi());
|
|
assert_eq!(stdout.format(), crate::LogFormat::Human);
|
|
assert_eq!(stdout.filter(), &crate::OutputFilter::unrestricted());
|
|
}
|
|
|
|
#[test]
|
|
fn file_settings_preserve_multi_output_contract() {
|
|
let filter = crate::OutputFilter::new(crate::LogFilterLevel::Error, std::vec!["ksp-config-lib".to_string()], std::vec!["config".to_string()]);
|
|
let settings =
|
|
crate::FileSettings::new("file.config.error", true, "logs/config", "error.jsonl", crate::FileRotation::Daily, crate::LogFormat::Json, filter.clone());
|
|
assert_eq!(settings.output_id(), "file.config.error");
|
|
assert!(settings.enabled());
|
|
assert_eq!(settings.directory(), std::path::Path::new("logs/config"));
|
|
assert_eq!(settings.file_name_prefix(), "error.jsonl");
|
|
assert_eq!(settings.rotation(), crate::FileRotation::Daily);
|
|
assert_eq!(settings.format(), crate::LogFormat::Json);
|
|
assert!(!settings.ansi());
|
|
assert_eq!(settings.filter(), &filter);
|
|
}
|
|
|
|
#[test]
|
|
fn logging_settings_represent_multiple_file_outputs() {
|
|
let first = unrestricted_file("file.debug");
|
|
let second = crate::FileSettings::new(
|
|
"file.config.error",
|
|
false,
|
|
"logs/config",
|
|
"error.jsonl",
|
|
crate::FileRotation::Hourly,
|
|
crate::LogFormat::Json,
|
|
crate::OutputFilter::new(crate::LogFilterLevel::Error, std::vec!["ksp-config-lib".to_string()], std::vec!["config".to_string()]),
|
|
);
|
|
let settings = crate::LoggingSettings::new(
|
|
crate::LogFilterLevel::Info,
|
|
crate::SpanEvents::NewAndClose,
|
|
std::option::Option::Some(crate::ConsoleSettings::stdout()),
|
|
std::vec![first, second],
|
|
)
|
|
.with_target_filter(crate::TargetFilter::new("ksp-store-lib", crate::LogFilterLevel::Trace));
|
|
assert_eq!(settings.default_filter(), crate::LogFilterLevel::Info);
|
|
assert_eq!(settings.span_events(), crate::SpanEvents::NewAndClose);
|
|
assert_eq!(settings.target_filters().len(), 1);
|
|
assert_eq!(settings.files().len(), 2);
|
|
assert_eq!(settings.files()[0].output_id(), "file.debug");
|
|
assert_eq!(settings.files()[1].format(), crate::LogFormat::Json);
|
|
assert_eq!(settings.console().map(crate::ConsoleSettings::output), std::option::Option::Some(crate::ConsoleOutput::Stdout));
|
|
assert!(settings.validate().is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn validation_rejects_empty_or_external_global_target_prefix() {
|
|
let empty = crate::LoggingSettings::new(crate::LogFilterLevel::Info, crate::SpanEvents::Off, std::option::Option::None, std::vec::Vec::new())
|
|
.with_target_filter(crate::TargetFilter::new("", crate::LogFilterLevel::Debug));
|
|
let external = crate::LoggingSettings::new(crate::LogFilterLevel::Info, crate::SpanEvents::Off, std::option::Option::None, std::vec::Vec::new())
|
|
.with_target_filter(crate::TargetFilter::new("sqlx", crate::LogFilterLevel::Debug));
|
|
assert!(empty.validate().is_err());
|
|
assert!(external.validate().is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn validation_rejects_invalid_file_identity_and_duplicate_output_ids() {
|
|
let invalid_id =
|
|
crate::LoggingSettings::new(crate::LogFilterLevel::Info, crate::SpanEvents::Off, std::option::Option::None, std::vec![unrestricted_file("File.Debug")]);
|
|
let duplicate_id = crate::LoggingSettings::new(
|
|
crate::LogFilterLevel::Info,
|
|
crate::SpanEvents::Off,
|
|
std::option::Option::None,
|
|
std::vec![unrestricted_file("file.debug"), unrestricted_file("file.debug")],
|
|
);
|
|
assert!(invalid_id.validate().is_err());
|
|
assert!(duplicate_id.validate().is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn validation_rejects_empty_file_paths_and_persistent_ansi() {
|
|
let empty_directory = crate::FileSettings::new(
|
|
"file.empty.dir",
|
|
true,
|
|
"",
|
|
"debug.log",
|
|
crate::FileRotation::Never,
|
|
crate::LogFormat::Human,
|
|
crate::OutputFilter::unrestricted(),
|
|
);
|
|
let empty_prefix = crate::FileSettings::new(
|
|
"file.empty.prefix",
|
|
true,
|
|
"logs",
|
|
"",
|
|
crate::FileRotation::Never,
|
|
crate::LogFormat::Human,
|
|
crate::OutputFilter::unrestricted(),
|
|
);
|
|
let ansi_file = crate::FileSettings::new(
|
|
"file.ansi",
|
|
true,
|
|
"logs",
|
|
"ansi.log",
|
|
crate::FileRotation::Never,
|
|
crate::LogFormat::Human,
|
|
crate::OutputFilter::unrestricted(),
|
|
)
|
|
.with_ansi(true);
|
|
let empty_directory_settings =
|
|
crate::LoggingSettings::new(crate::LogFilterLevel::Info, crate::SpanEvents::Off, std::option::Option::None, std::vec![empty_directory]);
|
|
let empty_prefix_settings =
|
|
crate::LoggingSettings::new(crate::LogFilterLevel::Info, crate::SpanEvents::Off, std::option::Option::None, std::vec![empty_prefix]);
|
|
let ansi_file_settings = crate::LoggingSettings::new(crate::LogFilterLevel::Info, crate::SpanEvents::Off, std::option::Option::None, std::vec![ansi_file]);
|
|
assert!(empty_directory_settings.validate().is_err());
|
|
assert!(empty_prefix_settings.validate().is_err());
|
|
assert!(ansi_file_settings.validate().is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn validation_rejects_ansi_json_console() {
|
|
let console = crate::ConsoleSettings::new(true, crate::ConsoleOutput::Stdout, true, crate::LogFormat::Json, crate::OutputFilter::unrestricted());
|
|
let settings = crate::LoggingSettings::new(crate::LogFilterLevel::Info, crate::SpanEvents::Off, std::option::Option::Some(console), std::vec::Vec::new());
|
|
assert!(settings.validate().is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn validation_rejects_invalid_output_selectors() {
|
|
let external_target = crate::OutputFilter::new(crate::LogFilterLevel::Debug, std::vec!["sqlx".to_string()], std::vec!["*".to_string()]);
|
|
let wildcard_mix =
|
|
crate::OutputFilter::new(crate::LogFilterLevel::Debug, std::vec!["*".to_string(), "ksp-config-lib".to_string()], std::vec!["*".to_string()]);
|
|
let duplicate_domain =
|
|
crate::OutputFilter::new(crate::LogFilterLevel::Debug, std::vec!["*".to_string()], std::vec!["config".to_string(), "config".to_string()]);
|
|
for filter in [external_target, wildcard_mix, duplicate_domain] {
|
|
let console = crate::ConsoleSettings::new(true, crate::ConsoleOutput::Stdout, false, crate::LogFormat::Human, filter);
|
|
let settings =
|
|
crate::LoggingSettings::new(crate::LogFilterLevel::Info, crate::SpanEvents::Off, std::option::Option::Some(console), std::vec::Vec::new());
|
|
assert!(settings.validate().is_err());
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn settings_allow_all_outputs_to_be_disabled() {
|
|
let console = crate::ConsoleSettings::new(false, crate::ConsoleOutput::Stderr, true, crate::LogFormat::Pretty, crate::OutputFilter::unrestricted());
|
|
let file = crate::FileSettings::new(
|
|
"file.disabled",
|
|
false,
|
|
"logs",
|
|
"disabled.jsonl",
|
|
crate::FileRotation::Daily,
|
|
crate::LogFormat::Json,
|
|
crate::OutputFilter::new(crate::LogFilterLevel::Error, std::vec!["ksp-config-lib".to_string()], std::vec!["config".to_string()]),
|
|
);
|
|
let settings = crate::LoggingSettings::new(crate::LogFilterLevel::Off, crate::SpanEvents::Off, std::option::Option::Some(console), std::vec![file]);
|
|
assert!(settings.validate().is_ok());
|
|
}
|