use elara_runtime::observability::logging::{
init_logging, LogFormat, LogLevel, LogOutput, LoggingConfig, LoggingError,
};
use std::path::PathBuf;
#[test]
fn test_logging_initialization_idempotency() {
let config = LoggingConfig {
level: LogLevel::Info,
format: LogFormat::Compact,
output: LogOutput::Stderr,
};
let result = init_logging(config);
assert!(
result.is_ok() || matches!(result, Err(LoggingError::AlreadyInitialized)),
"Initialization should either succeed or return AlreadyInitialized"
);
let config2 = LoggingConfig {
level: LogLevel::Debug,
format: LogFormat::Json,
output: LogOutput::Stdout,
};
let result2 = init_logging(config2);
assert!(
matches!(result2, Err(LoggingError::AlreadyInitialized)),
"Second initialization should return AlreadyInitialized error"
);
}
#[test]
fn test_log_level_conversions() {
assert!(LogLevel::Trace < LogLevel::Debug);
assert!(LogLevel::Debug < LogLevel::Info);
assert!(LogLevel::Info < LogLevel::Warn);
assert!(LogLevel::Warn < LogLevel::Error);
}
#[test]
fn test_logging_config_default() {
let config = LoggingConfig::default();
assert_eq!(config.level, LogLevel::Info);
assert_eq!(config.format, LogFormat::Pretty);
assert_eq!(config.output, LogOutput::Stdout);
}
#[test]
fn test_log_output_variants() {
let _stdout = LogOutput::Stdout;
let _stderr = LogOutput::Stderr;
let _file = LogOutput::File(PathBuf::from("/tmp/test.log"));
assert_eq!(LogOutput::Stdout, LogOutput::Stdout);
assert_eq!(LogOutput::Stderr, LogOutput::Stderr);
assert_ne!(LogOutput::Stdout, LogOutput::Stderr);
}
#[test]
fn test_log_format_variants() {
let _pretty = LogFormat::Pretty;
let _json = LogFormat::Json;
let _compact = LogFormat::Compact;
assert_eq!(LogFormat::Pretty, LogFormat::Pretty);
assert_eq!(LogFormat::Json, LogFormat::Json);
assert_eq!(LogFormat::Compact, LogFormat::Compact);
assert_ne!(LogFormat::Pretty, LogFormat::Json);
}
#[test]
fn test_env_filter_respects_rust_log() {
std::env::set_var("RUST_LOG", "info,elara_wire=debug,elara_crypto=trace");
let config = LoggingConfig {
level: LogLevel::Warn, format: LogFormat::Compact,
output: LogOutput::Stderr,
};
let result = init_logging(config);
assert!(
result.is_ok() || matches!(result, Err(LoggingError::AlreadyInitialized)),
"Initialization with RUST_LOG should succeed or return AlreadyInitialized"
);
std::env::remove_var("RUST_LOG");
}
#[test]
fn test_contextual_fields_in_logs() {
use tracing::{info, warn, error};
let config = LoggingConfig {
level: LogLevel::Info,
format: LogFormat::Json,
output: LogOutput::Stderr,
};
let _ = init_logging(config);
info!(
node_id = "node-1",
session_id = "session-abc",
"Node started successfully"
);
warn!(
node_id = "node-1",
peer_id = "peer-xyz",
"Connection attempt failed, retrying"
);
error!(
node_id = "node-1",
session_id = "session-abc",
peer_id = "peer-xyz",
error_code = 500,
"Critical error occurred"
);
}
#[test]
fn test_per_module_log_levels_syntax() {
let test_cases = vec![
"info",
"debug,elara_wire=trace",
"warn,elara_crypto=debug,elara_state=info",
"error,elara_transport=warn",
"trace,elara_runtime::observability=debug",
];
for rust_log_value in test_cases {
std::env::set_var("RUST_LOG", rust_log_value);
let filter_result = tracing_subscriber::EnvFilter::try_from_default_env();
assert!(
filter_result.is_ok(),
"RUST_LOG='{}' should be valid syntax",
rust_log_value
);
std::env::remove_var("RUST_LOG");
}
}
#[test]
fn test_fallback_to_config_level_when_no_rust_log() {
std::env::remove_var("RUST_LOG");
let config = LoggingConfig {
level: LogLevel::Debug,
format: LogFormat::Compact,
output: LogOutput::Stderr,
};
let result = init_logging(config);
assert!(
result.is_ok() || matches!(result, Err(LoggingError::AlreadyInitialized)),
"Initialization should succeed with fallback to config.level or return AlreadyInitialized"
);
}