From 0f84515ebb55e2284410553518141e26ffc27249 Mon Sep 17 00:00:00 2001 From: bconn98 Date: Fri, 16 Feb 2024 11:17:50 -0500 Subject: [PATCH] test: serde deserialization and triggering on size trigger, cleanup, MSRV bump, cleanup color ctrl test --- Cargo.toml | 7 +- README.md | 4 +- docs/Configuration.md | 2 +- examples/color_control.rs | 25 ++ .../policy/compound/trigger/size.rs | 297 ++++++++++++++++++ .../policy/compound/trigger/time.rs | 6 +- tests/color_control.rs | 32 +- 7 files changed, 364 insertions(+), 9 deletions(-) create mode 100644 examples/color_control.rs diff --git a/Cargo.toml b/Cargo.toml index ff9c9fd3..577abc36 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ repository = "https://github.com/estk/log4rs" readme = "README.md" keywords = ["log", "logger", "logging", "log4"] edition = "2018" -rust-version = "1.69" +rust-version = "1.70" [features] default = ["all_components", "config_parsing", "yaml_format"] @@ -88,6 +88,7 @@ streaming-stats = "0.2.3" humantime = "2.1" tempfile = "3.8" mock_instant = "0.3" +serde_test = "1.0.176" [[example]] name = "json_logger" @@ -108,3 +109,7 @@ required-features = ["file_appender", "rolling_file_appender", "size_trigger"] [[example]] name = "multi_logger_config" required-features = ["yaml_format", "config_parsing"] + +[[example]] +name = "color_control" +required-features = ["yaml_format", "config_parsing"] diff --git a/README.md b/README.md index 056d1e4d..b3c36ff2 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![crates.io](https://img.shields.io/crates/v/log4rs.svg)](https://crates.io/crates/log4rs) [![License: MIT OR Apache-2.0](https://img.shields.io/crates/l/clippy.svg)](#license) ![CI](https://github.com/estk/log4rs/workflows/CI/badge.svg) -[![Minimum rustc version](https://img.shields.io/badge/rustc-1.69+-green.svg)](https://github.com/estk/log4rs#rust-version-requirements) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.70+-green.svg)](https://github.com/estk/log4rs#rust-version-requirements) log4rs is a highly configurable logging framework modeled after Java's Logback and log4j libraries. @@ -71,7 +71,7 @@ fn main() { ## Rust Version Requirements -1.69 +1.70 ## Building for Dev diff --git a/docs/Configuration.md b/docs/Configuration.md index 5ec2ce65..e69be5d8 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -174,7 +174,7 @@ other components, the default (and only supported) policy is `kind: compound`. The _trigger_ field is used to dictate when the log file should be rolled. It supports two types: `size`, and `time`. -For `size`, it require a _limit_ field. The _limit_ field is a string which defines the maximum file size +For `size`, it requires a _limit_ field. The _limit_ field is a string which defines the maximum file size prior to a rolling of the file. The limit field requires one of the following units in bytes, case does not matter: diff --git a/examples/color_control.rs b/examples/color_control.rs new file mode 100644 index 00000000..dbc73c9d --- /dev/null +++ b/examples/color_control.rs @@ -0,0 +1,25 @@ +use log::{error, info}; +use log4rs; +use serde_yaml; +use std::env; + +fn main() { + let config_str = include_str!("sample_config.yml"); + let config = serde_yaml::from_str(config_str).unwrap(); + log4rs::init_raw_config(config).unwrap(); + + let no_color = match env::var("NO_COLOR") { + Ok(no_color) => no_color, + Err(_) => "0".to_string(), + }; + let clicolor_force = match env::var("CLICOLOR_FORCE") { + Ok(clicolor_force) => clicolor_force, + Err(_) => "0".to_string(), + }; + let cli_color = match env::var("CLICOLOR") { + Ok(cli_color) => cli_color, + Err(_) => "0".to_string(), + }; + info!("NO_COLOR: {}, CLICOLOR_FORCE: {}, CLICOLOR: {}", no_color, clicolor_force, cli_color); + error!("NO_COLOR: {}, CLICOLOR_FORCE: {}, CLICOLOR: {}", no_color, clicolor_force, cli_color); +} diff --git a/src/append/rolling_file/policy/compound/trigger/size.rs b/src/append/rolling_file/policy/compound/trigger/size.rs index d399cb2f..41c3e8ee 100644 --- a/src/append/rolling_file/policy/compound/trigger/size.rs +++ b/src/append/rolling_file/policy/compound/trigger/size.rs @@ -157,10 +157,307 @@ impl Deserialize for SizeTriggerDeserializer { #[cfg(test)] mod test { use super::*; + use serde_test::{assert_de_tokens, assert_de_tokens_error, Token}; + + static BYTE_MULTIPLIER: u64 = 1024; #[test] fn pre_process() { let trigger = SizeTrigger::new(2048); assert!(!trigger.is_pre_process()); } + + #[test] + fn test_trigger() { + let file = tempfile::tempdir().unwrap(); + let mut logfile = LogFile { + writer: &mut None, + path: file.path(), + len: 0, + }; + + let trigger_bytes = 5; + let trigger = SizeTrigger::new(trigger_bytes); + + // Logfile size is < trigger size, should never trigger + for size in 0..trigger_bytes { + logfile.len = size; + assert!(!trigger.trigger(&logfile).unwrap()); + } + + // Logfile size is == trigger size, should not trigger + logfile.len = trigger_bytes; + assert!(!trigger.trigger(&logfile).unwrap()); + + // Logfile size is >= trigger size, should trigger + logfile.len = trigger_bytes + 1; + assert!(trigger.trigger(&logfile).unwrap()); + } + + #[test] + #[cfg(feature = "config_parsing")] + fn test_u64_deserialize() { + let trigger = SizeTriggerConfig{ limit: BYTE_MULTIPLIER }; + assert_de_tokens( + &trigger, + &[ + Token::Struct { name: "SizeTriggerConfig", len: 1 }, + Token::Str("limit"), + Token::U64(1024), + Token::StructEnd, + ], + ); + } + + #[test] + #[cfg(feature = "config_parsing")] + fn test_i64_deserialize() { + let trigger = SizeTriggerConfig{ limit: BYTE_MULTIPLIER }; + assert_de_tokens( + &trigger, + &[ + Token::Struct { name: "SizeTriggerConfig", len: 1 }, + Token::Str("limit"), + Token::I64(1024), + Token::StructEnd, + ], + ); + + assert_de_tokens_error::( + &[ + Token::Struct { name: "SizeTriggerConfig", len: 1 }, + Token::Str("limit"), + Token::I64(-1024), + Token::StructEnd, + ], + "invalid value: integer `-1024`, expected a non-negative number", + ); + } + + #[test] + #[cfg(feature = "config_parsing")] + fn test_str_deserialize() { + // Test no unit (aka value in Bytes) + let trigger = SizeTriggerConfig{ limit: BYTE_MULTIPLIER }; + assert_de_tokens( + &trigger, + &[ + Token::Struct { name: "SizeTriggerConfig", len: 1 }, + Token::Str("limit"), + Token::Str("1024"), + Token::StructEnd, + ], + ); + + // Test not an unsigned number + assert_de_tokens_error::( + &[ + Token::Struct { name: "SizeTriggerConfig", len: 1 }, + Token::Str("limit"), + Token::Str("-1024"), + Token::StructEnd, + ], + "invalid value: string \"\", expected a number", + ); + } + + #[test] + #[cfg(feature = "config_parsing")] + fn byte_deserialize() { + let trigger = SizeTriggerConfig{ limit: BYTE_MULTIPLIER }; + + // Test spacing & b vs B + assert_de_tokens( + &trigger, + &[ + Token::Struct { name: "SizeTriggerConfig", len: 1 }, + Token::Str("limit"), + Token::Str("1024b"), + Token::StructEnd, + ], + ); + assert_de_tokens( + &trigger, + &[ + Token::Struct { name: "SizeTriggerConfig", len: 1 }, + Token::Str("limit"), + Token::Str("1024 B"), + Token::StructEnd, + ], + ); + } + + #[test] + #[cfg(feature = "config_parsing")] + fn kilobyte_deserialize() { + let trigger = SizeTriggerConfig{ limit: BYTE_MULTIPLIER }; + + // Test kb unit + assert_de_tokens( + &trigger, + &[ + Token::Struct { name: "SizeTriggerConfig", len: 1 }, + Token::Str("limit"), + Token::Str("1 kb"), + Token::StructEnd, + ], + ); + assert_de_tokens( + &trigger, + &[ + Token::Struct { name: "SizeTriggerConfig", len: 1 }, + Token::Str("limit"), + Token::Str("1 KB"), + Token::StructEnd, + ], + ); + assert_de_tokens( + &trigger, + &[ + Token::Struct { name: "SizeTriggerConfig", len: 1 }, + Token::Str("limit"), + Token::Str("1 kB"), + Token::StructEnd, + ], + ); + assert_de_tokens( + &trigger, + &[ + Token::Struct { name: "SizeTriggerConfig", len: 1 }, + Token::Str("limit"), + Token::Str("1 Kb"), + Token::StructEnd, + ], + ); + } + + #[test] + #[cfg(feature = "config_parsing")] + fn megabyte_deserialize() { + // Test mb unit + let trigger = SizeTriggerConfig{ limit: BYTE_MULTIPLIER.pow(2) }; + assert_de_tokens( + &trigger, + &[ + Token::Struct { name: "SizeTriggerConfig", len: 1 }, + Token::Str("limit"), + Token::Str("1 mb"), + Token::StructEnd, + ], + ); + assert_de_tokens( + &trigger, + &[ + Token::Struct { name: "SizeTriggerConfig", len: 1 }, + Token::Str("limit"), + Token::Str("1 MB"), + Token::StructEnd, + ], + ); + assert_de_tokens( + &trigger, + &[ + Token::Struct { name: "SizeTriggerConfig", len: 1 }, + Token::Str("limit"), + Token::Str("1 mB"), + Token::StructEnd, + ], + ); + assert_de_tokens( + &trigger, + &[ + Token::Struct { name: "SizeTriggerConfig", len: 1 }, + Token::Str("limit"), + Token::Str("1 Mb"), + Token::StructEnd, + ], + ); + } + + #[test] + #[cfg(feature = "config_parsing")] + fn gigabyte_deserialize() { + // Test gb unit + let trigger = SizeTriggerConfig{ limit: BYTE_MULTIPLIER.pow(3) }; + assert_de_tokens( + &trigger, + &[ + Token::Struct { name: "SizeTriggerConfig", len: 1 }, + Token::Str("limit"), + Token::Str("1 gb"), + Token::StructEnd, + ], + ); + assert_de_tokens( + &trigger, + &[ + Token::Struct { name: "SizeTriggerConfig", len: 1 }, + Token::Str("limit"), + Token::Str("1 GB"), + Token::StructEnd, + ], + ); + assert_de_tokens( + &trigger, + &[ + Token::Struct { name: "SizeTriggerConfig", len: 1 }, + Token::Str("limit"), + Token::Str("1 gB"), + Token::StructEnd, + ], + ); + assert_de_tokens( + &trigger, + &[ + Token::Struct { name: "SizeTriggerConfig", len: 1 }, + Token::Str("limit"), + Token::Str("1 Gb"), + Token::StructEnd, + ], + ); + } + + #[test] + #[cfg(feature = "config_parsing")] + fn terabyte_deserialize() { + // Test tb unit + let trigger = SizeTriggerConfig{ limit: BYTE_MULTIPLIER.pow(4) }; + assert_de_tokens( + &trigger, + &[ + Token::Struct { name: "SizeTriggerConfig", len: 1 }, + Token::Str("limit"), + Token::Str("1 tb"), + Token::StructEnd, + ], + ); + assert_de_tokens( + &trigger, + &[ + Token::Struct { name: "SizeTriggerConfig", len: 1 }, + Token::Str("limit"), + Token::Str("1 TB"), + Token::StructEnd, + ], + ); + assert_de_tokens( + &trigger, + &[ + Token::Struct { name: "SizeTriggerConfig", len: 1 }, + Token::Str("limit"), + Token::Str("1 tB"), + Token::StructEnd, + ], + ); + assert_de_tokens( + &trigger, + &[ + Token::Struct { name: "SizeTriggerConfig", len: 1 }, + Token::Str("limit"), + Token::Str("1 Tb"), + Token::StructEnd, + ], + ); + } + } diff --git a/src/append/rolling_file/policy/compound/trigger/time.rs b/src/append/rolling_file/policy/compound/trigger/time.rs index 4568a524..c760c7d4 100644 --- a/src/append/rolling_file/policy/compound/trigger/time.rs +++ b/src/append/rolling_file/policy/compound/trigger/time.rs @@ -433,11 +433,11 @@ mod test { #[cfg(feature = "yaml_format")] fn test_serde() { let test_error = vec![ - "abc", // // str none none + "abc", // str "", // none "5 das", // bad unit - "-1", // inegative integar - "2.0", //flaot + "-1", // negative integar + "2.0", // float ]; for interval in test_error.iter() { diff --git a/tests/color_control.rs b/tests/color_control.rs index 344f032f..ab785e6b 100644 --- a/tests/color_control.rs +++ b/tests/color_control.rs @@ -2,7 +2,7 @@ use std::process::Command; fn execute_test(env_key: &str, env_val: &str) { let mut child_proc = Command::new("cargo") - .args(&["run", "--example", "compile_time_config"]) + .args(&["run", "--example", "color_control"]) .env(env_key, env_val) .spawn() .expect("Cargo command failed to start"); @@ -14,7 +14,7 @@ fn execute_test(env_key: &str, env_val: &str) { // Maintaining as a single test to avoid blocking calls to the package cache #[test] -fn test_no_color() { +fn test_single_var() { let keys = vec!["NO_COLOR", "CLICOLOR_FORCE", "CLICOLOR"]; for key in keys { @@ -22,3 +22,31 @@ fn test_no_color() { execute_test(key, "0"); } } + +#[test] +fn test_no_color_vs_force() { + let mut child_proc = Command::new("cargo") + .args(&["run", "--example", "color_control"]) + .env("NO_COLOR", "1") + .env("CLICOLOR_FORCE", "1") + .spawn() + .expect("Cargo command failed to start"); + + let ecode = child_proc.wait().expect("failed to wait on child"); + + assert!(ecode.success()); +} + +#[test] +fn test_no_color_vs_regular() { + let mut child_proc = Command::new("cargo") + .args(&["run", "--example", "color_control"]) + .env("NO_COLOR", "1") + .env("CLICOLOR", "1") + .spawn() + .expect("Cargo command failed to start"); + + let ecode = child_proc.wait().expect("failed to wait on child"); + + assert!(ecode.success()); +}