v0.1.4-pre.015-fix.002

This commit is contained in:
2026-08-16 18:20:32 +02:00
parent 05c65a12f4
commit 9ad61b40e1
25 changed files with 776 additions and 210 deletions

View File

@@ -1,76 +1,145 @@
// file: crates/ksp-config-lib/unit_tests/logging.rs
// version: 2
// version: 3
#[test]
fn committed_logging_profile_maps_complete_runtime_contract() {
let engine = committed_engine();
fn fixture_logging_profile_maps_complete_runtime_contract() {
let engine = fixture_engine();
let engine = match engine {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let environment = crate::ConfigEnvironment::from_maps(std::collections::BTreeMap::new(), std::collections::BTreeMap::new());
let resolved = engine.load_resolved_logging_config(std::option::Option::None, &environment);
assert!(resolved.is_ok(), "committed Logging Config should map");
assert!(resolved.is_ok(), "fixture Logging Config should map");
let resolved = match resolved {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
assert_eq!(resolved.file_id().as_str(), crate::FILE_ID_STD_LOGGING);
assert_eq!(resolved.profile_id(), "local_dev");
assert_eq!(resolved.selection_source(), crate::ConfigProfileSelectionSource::DefaultProfile);
assert_eq!(resolved.logs_directory(), current_directory().join("logs").as_path());
assert_eq!(resolved.effective().value()["logs_directory"], serde_json::Value::String("logs".to_owned()));
let effective = resolved.effective().value();
let effective_logs_directory = effective.get("logs_directory").and_then(serde_json::Value::as_str);
assert!(effective_logs_directory.is_some(), "effective Logging Config should expose logs_directory");
if let std::option::Option::Some(effective_logs_directory) = effective_logs_directory {
let source_path = std::path::Path::new(effective_logs_directory);
let expected = if source_path.is_absolute() { source_path.to_path_buf() } else { current_directory().join(source_path) };
assert_eq!(resolved.logs_directory(), expected.as_path());
}
let settings = resolved.settings();
assert_eq!(settings.default_filter(), ksp_logging_lib::LogFilterLevel::Warn);
assert_eq!(settings.span_events(), ksp_logging_lib::SpanEvents::NewAndClose);
assert_eq!(settings.target_filters().len(), 3);
assert_eq!(settings.target_filters()[0].target_prefix(), "ksp-config-lib");
assert_eq!(settings.target_filters()[0].level(), ksp_logging_lib::LogFilterLevel::Trace);
assert_eq!(settings.target_filters()[1].target_prefix(), "ksp-logging-lib");
assert_eq!(settings.target_filters()[1].level(), ksp_logging_lib::LogFilterLevel::Debug);
assert_eq!(settings.target_filters()[2].target_prefix(), "ksp-app-config-desk");
assert_eq!(settings.target_filters()[2].level(), ksp_logging_lib::LogFilterLevel::Debug);
let default_filter = effective.get("default_filter").and_then(serde_json::Value::as_str);
let span_events = effective.get("span_events").and_then(serde_json::Value::as_str);
assert_eq!(default_filter.and_then(test_level), std::option::Option::Some(settings.default_filter()));
assert_eq!(span_events.and_then(test_span_events), std::option::Option::Some(settings.span_events()));
let source_target_filters = effective.get("target_filters").and_then(serde_json::Value::as_array);
assert!(source_target_filters.is_some(), "effective Logging Config should expose target_filters");
if let std::option::Option::Some(source_target_filters) = source_target_filters {
assert_eq!(settings.target_filters().len(), source_target_filters.len());
for (runtime, source) in settings.target_filters().iter().zip(source_target_filters) {
assert_eq!(source.get("target_prefix").and_then(serde_json::Value::as_str), std::option::Option::Some(runtime.target_prefix()));
assert_eq!(source.get("level").and_then(serde_json::Value::as_str).and_then(test_level), std::option::Option::Some(runtime.level()));
}
}
let console = settings.console();
assert!(console.is_some(), "committed Logging Config declares console settings");
let console = match console {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
let source_console = effective.get("console");
assert!(console.is_some(), "effective Logging Config declares console settings");
assert!(source_console.is_some(), "effective Logging Config should expose console settings");
if let (std::option::Option::Some(console), std::option::Option::Some(source_console)) = (console, source_console) {
assert_eq!(source_console.get("enabled").and_then(serde_json::Value::as_bool), std::option::Option::Some(console.enabled()));
assert_eq!(source_console.get("ansi").and_then(serde_json::Value::as_bool), std::option::Option::Some(console.ansi()));
assert_eq!(source_console.get("output").and_then(serde_json::Value::as_str).and_then(test_console_output), std::option::Option::Some(console.output()));
assert_eq!(source_console.get("format").and_then(serde_json::Value::as_str).and_then(test_format), std::option::Option::Some(console.format()));
let filter = source_console.get("filter");
assert!(filter.is_some(), "effective console should expose filter");
if let std::option::Option::Some(filter) = filter {
assert_eq!(filter.get("level").and_then(serde_json::Value::as_str).and_then(test_level), std::option::Option::Some(console.filter().level()));
assert_eq!(json_string_array(filter.get("targets")), console.filter().targets().to_vec());
assert_eq!(json_string_array(filter.get("domains")), console.filter().domains().to_vec());
}
}
let source_files = effective.get("files").and_then(serde_json::Value::as_array);
assert!(source_files.is_some(), "effective Logging Config should expose files");
if let std::option::Option::Some(source_files) = source_files {
assert_eq!(settings.files().len(), source_files.len());
for (runtime, source) in settings.files().iter().zip(source_files) {
assert_eq!(source.get("output_id").and_then(serde_json::Value::as_str), std::option::Option::Some(runtime.output_id()));
assert_eq!(source.get("enabled").and_then(serde_json::Value::as_bool), std::option::Option::Some(runtime.enabled()));
assert_eq!(source.get("rotation").and_then(serde_json::Value::as_str).and_then(test_rotation), std::option::Option::Some(runtime.rotation()));
assert_eq!(source.get("format").and_then(serde_json::Value::as_str).and_then(test_format), std::option::Option::Some(runtime.format()));
assert_eq!(source.get("ansi").and_then(serde_json::Value::as_bool), std::option::Option::Some(runtime.ansi()));
let filter = source.get("filter");
assert!(filter.is_some(), "effective file should expose filter");
if let std::option::Option::Some(filter) = filter {
assert_eq!(filter.get("level").and_then(serde_json::Value::as_str).and_then(test_level), std::option::Option::Some(runtime.filter().level()));
assert_eq!(json_string_array(filter.get("targets")), runtime.filter().targets().to_vec());
assert_eq!(json_string_array(filter.get("domains")), runtime.filter().domains().to_vec());
}
}
}
}
fn test_level(value: &str) -> std::option::Option<ksp_logging_lib::LogFilterLevel> {
return match value {
"off" => std::option::Option::Some(ksp_logging_lib::LogFilterLevel::Off),
"error" => std::option::Option::Some(ksp_logging_lib::LogFilterLevel::Error),
"warn" => std::option::Option::Some(ksp_logging_lib::LogFilterLevel::Warn),
"info" => std::option::Option::Some(ksp_logging_lib::LogFilterLevel::Info),
"debug" => std::option::Option::Some(ksp_logging_lib::LogFilterLevel::Debug),
"trace" => std::option::Option::Some(ksp_logging_lib::LogFilterLevel::Trace),
_ => std::option::Option::None,
};
assert!(console.enabled());
assert_eq!(console.output(), ksp_logging_lib::ConsoleOutput::Stderr);
assert!(console.ansi());
assert_eq!(console.format(), ksp_logging_lib::LogFormat::Compact);
assert_eq!(console.filter().level(), ksp_logging_lib::LogFilterLevel::Debug);
assert_eq!(console.filter().targets(), &["*".to_owned()]);
assert_eq!(console.filter().domains(), &["*".to_owned()]);
assert_eq!(settings.files().len(), 2);
assert_file(
&settings.files()[0],
"file.all.debug",
current_directory().join("logs/debug").as_path(),
"ksp-debug.log",
ksp_logging_lib::FileRotation::Daily,
ksp_logging_lib::LogFormat::Human,
ksp_logging_lib::LogFilterLevel::Debug,
&["*"],
&["*"],
);
assert_file(
&settings.files()[1],
"file.config.error",
current_directory().join("logs/config").as_path(),
"ksp-config-errors.jsonl",
ksp_logging_lib::FileRotation::Daily,
ksp_logging_lib::LogFormat::Json,
ksp_logging_lib::LogFilterLevel::Error,
&["ksp-config-lib"],
&["config"],
);
}
fn test_span_events(value: &str) -> std::option::Option<ksp_logging_lib::SpanEvents> {
return match value {
"off" => std::option::Option::Some(ksp_logging_lib::SpanEvents::Off),
"new_and_close" => std::option::Option::Some(ksp_logging_lib::SpanEvents::NewAndClose),
"full" => std::option::Option::Some(ksp_logging_lib::SpanEvents::Full),
_ => std::option::Option::None,
};
}
fn test_console_output(value: &str) -> std::option::Option<ksp_logging_lib::ConsoleOutput> {
return match value {
"stdout" => std::option::Option::Some(ksp_logging_lib::ConsoleOutput::Stdout),
"stderr" => std::option::Option::Some(ksp_logging_lib::ConsoleOutput::Stderr),
_ => std::option::Option::None,
};
}
fn test_format(value: &str) -> std::option::Option<ksp_logging_lib::LogFormat> {
return match value {
"human" => std::option::Option::Some(ksp_logging_lib::LogFormat::Human),
"compact" => std::option::Option::Some(ksp_logging_lib::LogFormat::Compact),
"pretty" => std::option::Option::Some(ksp_logging_lib::LogFormat::Pretty),
"json" => std::option::Option::Some(ksp_logging_lib::LogFormat::Json),
_ => std::option::Option::None,
};
}
fn test_rotation(value: &str) -> std::option::Option<ksp_logging_lib::FileRotation> {
return match value {
"never" => std::option::Option::Some(ksp_logging_lib::FileRotation::Never),
"hourly" => std::option::Option::Some(ksp_logging_lib::FileRotation::Hourly),
"daily" => std::option::Option::Some(ksp_logging_lib::FileRotation::Daily),
_ => std::option::Option::None,
};
}
fn json_string_array(value: std::option::Option<&serde_json::Value>) -> std::vec::Vec<String> {
let mut result = std::vec::Vec::<String>::new();
if let std::option::Option::Some(values) = value.and_then(serde_json::Value::as_array) {
for value in values {
if let std::option::Option::Some(value) = value.as_str() {
result.push(value.to_owned());
}
}
}
return result;
}
#[test]
fn relative_logs_directory_is_anchored_to_process_current_directory() {
let engine = committed_engine();
let engine = fixture_engine();
let engine = match engine {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
@@ -86,7 +155,7 @@ fn relative_logs_directory_is_anchored_to_process_current_directory() {
#[test]
fn absolute_logs_directory_is_preserved() {
let engine = committed_engine();
let engine = fixture_engine();
let engine = match engine {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
@@ -111,7 +180,7 @@ fn effective_file_paths_cannot_escape_logging_root() {
#[test]
fn explicit_empty_logs_directory_is_invalid_instead_of_using_fallback() {
let engine = committed_engine();
let engine = fixture_engine();
let engine = match engine {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
@@ -130,7 +199,7 @@ fn explicit_empty_logs_directory_is_invalid_instead_of_using_fallback() {
#[test]
fn existing_non_directory_logging_root_is_rejected_without_secret_leak() {
let engine = committed_engine();
let engine = fixture_engine();
let engine = match engine {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
@@ -139,7 +208,7 @@ fn existing_non_directory_logging_root_is_rejected_without_secret_leak() {
let path = std::env::temp_dir().join(secret.as_str());
let write = std::fs::write(path.as_path(), b"not a directory");
assert!(write.is_ok(), "secret canary file should be created");
let profile = load_committed_profile(&engine);
let profile = load_fixture_profile(&engine);
let profile = match profile {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => {
@@ -161,12 +230,12 @@ fn existing_non_directory_logging_root_is_rejected_without_secret_leak() {
#[test]
fn logging_adapter_rejects_secret_effective_values_without_exposing_canary() {
let engine = committed_engine();
let engine = fixture_engine();
let engine = match engine {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let profile = load_committed_profile(&engine);
let profile = load_fixture_profile(&engine);
let profile = match profile {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
@@ -193,7 +262,7 @@ fn logging_adapter_rejects_secret_effective_values_without_exposing_canary() {
#[test]
fn mapped_logging_settings_can_initialize_and_reinitialize_runtime() {
let engine = committed_engine();
let engine = fixture_engine();
let engine = match engine {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
@@ -231,7 +300,7 @@ fn mapped_logging_settings_can_initialize_and_reinitialize_runtime() {
#[test]
fn resolved_logging_debug_uses_safe_effective_view() {
let engine = committed_engine();
let engine = fixture_engine();
let engine = match engine {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
@@ -270,9 +339,10 @@ fn assert_file(
assert_eq!(file.filter().domains().iter().map(String::as_str).collect::<std::vec::Vec<&str>>(), domains.to_vec());
}
fn committed_engine() -> ksp_core_lib::Result<crate::ConfigDocumentEngine> {
fn fixture_engine() -> ksp_core_lib::Result<crate::ConfigDocumentEngine> {
let workspace = workspace_root();
let bootstrap = crate::ConfigBootstrapOptions::from_paths(workspace.join("config"), workspace.join("config/schemas"));
let fixture_root = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("unit_tests/fixtures");
let bootstrap = crate::ConfigBootstrapOptions::from_paths(fixture_root, workspace.join("config/schemas"));
let bootstrap = match bootstrap {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
@@ -285,7 +355,7 @@ fn committed_engine() -> ksp_core_lib::Result<crate::ConfigDocumentEngine> {
return std::result::Result::Ok(crate::ConfigDocumentEngine::new(bootstrap, registry));
}
fn load_committed_profile(engine: &crate::ConfigDocumentEngine) -> ksp_core_lib::Result<crate::ResolvedConfigProfile> {
fn load_fixture_profile(engine: &crate::ConfigDocumentEngine) -> ksp_core_lib::Result<crate::ResolvedConfigProfile> {
let file_id = crate::ConfigFileId::new(crate::FILE_ID_STD_LOGGING);
let file_id = match file_id {
std::result::Result::Ok(value) => value,