Skip to content

Commit

Permalink
test(time): add test case of time trigger.
Browse files Browse the repository at this point in the history
  • Loading branch information
Dirreke committed Dec 22, 2023
1 parent 5362e3e commit c0b07b5
Show file tree
Hide file tree
Showing 4 changed files with 231 additions and 16 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ lazy_static = "1.4"
streaming-stats = "0.2.3"
humantime = "2.1"
tempfile = "3.8"
mock_instant = "0.3"

[[example]]
name = "json_logger"
Expand Down
4 changes: 2 additions & 2 deletions src/append/rolling_file/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,8 +390,8 @@ appenders:
path: {0}/foo.log
policy:
trigger:
kind: size
limit: 1024
kind: time
limit: 2 minutes
roller:
kind: delete
bar:
Expand Down
11 changes: 11 additions & 0 deletions src/append/rolling_file/policy/compound/trigger/size.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,14 @@ impl Deserialize for SizeTriggerDeserializer {
Ok(Box::new(SizeTrigger::new(config.limit)))
}
}

#[cfg(test)]
mod test {
use super::*;

#[test]
fn pre_process() {
let trigger = SizeTrigger::new(2048);
assert!(!trigger.is_pre_process());
}
}
231 changes: 217 additions & 14 deletions src/append/rolling_file/policy/compound/trigger/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
//! Requires the `time_trigger` feature.
use chrono::{DateTime, Datelike, Duration, Local, TimeZone, Timelike};
#[cfg(test)]
use chrono::{NaiveDateTime, Utc};
#[cfg(test)]
use mock_instant::{SystemTime, UNIX_EPOCH};
#[cfg(feature = "config_parsing")]
use serde::de;
#[cfg(feature = "config_parsing")]
Expand Down Expand Up @@ -145,16 +149,30 @@ impl TimeTrigger {
/// Returns a new trigger which rolls the log once it has passed the
/// specified time.
pub fn new(limit: TimeTriggerLimit) -> TimeTrigger {
#[cfg(test)]
let time = {
let now: std::time::Duration = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("system time before Unix epoch");
let naive = NaiveDateTime::from_timestamp_opt(now.as_secs() as i64, now.subsec_nanos())
.unwrap();
Utc.from_utc_datetime(&naive).with_timezone(&Local)
};

#[cfg(not(test))]
let time = Local::now();
let year = time.year();
let month = time.month();
let day = time.day();
let weekday = time.weekday();
let hour = time.hour();
let min = time.minute();
let sec = time.second();

let time_new = match limit {
TimeTriggerLimit::Second(_) => time,
TimeTriggerLimit::Second(_) => Local
.with_ymd_and_hms(year, month, day, hour, min, sec)
.unwrap(),
TimeTriggerLimit::Minute(_) => Local
.with_ymd_and_hms(year, month, day, hour, min, 0)
.unwrap(),
Expand All @@ -179,7 +197,21 @@ impl TimeTrigger {

impl Trigger for TimeTrigger {
fn trigger(&self, _file: &LogFile) -> anyhow::Result<bool> {
let time_now = Local::now();
#[cfg(test)]
let time_now = {
let now: std::time::Duration = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("system time before Unix epoch");
let naive = NaiveDateTime::from_timestamp_opt(now.as_secs() as i64, now.subsec_nanos())
.unwrap();
let t = Utc.from_utc_datetime(&naive).with_timezone(&Local);
println!("{:?}", t);
println!("{:?}", t.weekday());
t
};

#[cfg(not(test))]
let time_now: DateTime<Local> = Local::now();
let mut time_start = self.time_start.write().unwrap();
let duration = time_now.signed_duration_since(*time_start);
let is_triger = match self.limit {
Expand Down Expand Up @@ -250,25 +282,196 @@ impl Deserialize for TimeTriggerDeserializer {
#[cfg(test)]
mod test {
use super::*;
use mock_instant::MockClock;
use std::time::Duration;

#[test]
fn trigger() {
fn test_mock_instant() {
let now = std::time::SystemTime::now();
println!("{:?}", now);
MockClock::advance_system_time(Duration::from_secs(15));
MockClock::advance_system_time(Duration::from_secs(2));
let now = SystemTime::now();
println!("{:?}", now);
}

fn trigger_with_time(limit: TimeTriggerLimit, millis: u64) -> (bool, bool) {
let file = tempfile::tempdir().unwrap();
let logfile = LogFile {
writer: &mut None,
path: file.path(),
len: 0,
};
let trigger = TimeTrigger::new(TimeTriggerLimit::Second(10));
let result = trigger.trigger(&logfile).unwrap();
assert_eq!(false, result);
std::thread::sleep(std::time::Duration::from_secs(12));
let result = trigger.trigger(&logfile).unwrap();
assert_eq!(true, result);
let result = trigger.trigger(&logfile).unwrap();
assert_eq!(false, result);
std::thread::sleep(std::time::Duration::from_secs(12));
let result = trigger.trigger(&logfile).unwrap();
assert_eq!(true, result);

let trigger = TimeTrigger::new(limit);

MockClock::advance_system_time(Duration::from_millis(millis / 2));
let result1 = trigger.trigger(&logfile).unwrap();

MockClock::advance_system_time(Duration::from_millis(millis / 2));
let result2 = trigger.trigger(&logfile).unwrap();

(result1, result2)
}

#[test]
fn trigger() {
// This test may fail if it runs in the following timezones (UTC+12, UTC-12)
// Second
MockClock::set_system_time(Duration::from_millis(0));
assert_eq!(
trigger_with_time(TimeTriggerLimit::Second(1), 1000),
(false, true)
);
// Minute
MockClock::set_system_time(Duration::from_millis(0));
assert_eq!(
trigger_with_time(TimeTriggerLimit::Minute(1), 60 * 1000),
(false, true)
);
// Hour
MockClock::set_system_time(Duration::from_millis(0));
assert_eq!(
trigger_with_time(TimeTriggerLimit::Hour(1), 60 * 60 * 1000),
(false, true)
);
// Day
MockClock::set_system_time(Duration::from_millis(0));
assert_eq!(
trigger_with_time(TimeTriggerLimit::Day(1), 24 * 60 * 60 * 1000),
(false, true)
);
// Week
MockClock::set_system_time(Duration::from_millis(4 * 24 * 60 * 60 * 1000)); // Monday
assert_eq!(
trigger_with_time(TimeTriggerLimit::Week(1), 7 * 24 * 60 * 60 * 1000),
(false, true)
);
// Month
MockClock::set_system_time(Duration::from_millis(0));
assert_eq!(
trigger_with_time(TimeTriggerLimit::Month(1), 31 * 24 * 60 * 60 * 1000),
(false, true)
);
// Year
MockClock::set_system_time(Duration::from_millis(0));
assert_eq!(
trigger_with_time(TimeTriggerLimit::Year(1), 366 * 24 * 60 * 60 * 1000),
(false, true)
);
}

#[test]
fn trigger2() {
// This test may fail if it runs in the following timezones (UTC+12, UTC-12)
// Second
MockClock::set_system_time(Duration::from_millis(1000 / 2));
assert_eq!(
trigger_with_time(TimeTriggerLimit::Second(1), 1000),
(true, false)
);
// Minute
MockClock::set_system_time(Duration::from_millis(60 * 1000 / 2));
assert_eq!(
trigger_with_time(TimeTriggerLimit::Minute(1), 60 * 1000),
(true, false)
);
// Hour
MockClock::set_system_time(Duration::from_millis(60 * 60 * 1000 / 2));
assert_eq!(
trigger_with_time(TimeTriggerLimit::Hour(1), 60 * 60 * 1000),
(true, false)
);
// Day
MockClock::set_system_time(Duration::from_millis(24 * 60 * 60 * 1000 / 2));
assert_eq!(
trigger_with_time(TimeTriggerLimit::Day(1), 24 * 60 * 60 * 1000),
(true, false)
);
// Week
MockClock::set_system_time(Duration::from_millis(
4 * 24 * 60 * 60 * 1000 + 7 * 24 * 60 * 60 * 1000 / 2,
)); // Monday
assert_eq!(
trigger_with_time(TimeTriggerLimit::Week(1), 7 * 24 * 60 * 60 * 1000),
(true, false)
);
// Month
MockClock::set_system_time(Duration::from_millis(31 * 24 * 60 * 60 * 1000 / 2));
assert_eq!(
trigger_with_time(TimeTriggerLimit::Month(1), 31 * 24 * 60 * 60 * 1000),
(true, false)
);
// Year
MockClock::set_system_time(Duration::from_millis(366 * 24 * 60 * 60 * 1000 / 2));
assert_eq!(
trigger_with_time(TimeTriggerLimit::Year(1), 366 * 24 * 60 * 60 * 1000),
(true, false)
);
}

#[test]
#[cfg(feature = "yaml_format")]
fn test_serde() {
// str none
let limit = format!("limit: abc",);
let error = ::serde_yaml::from_str::<TimeTriggerConfig>(&limit);
assert!(error.is_err());

// none
let limit = format!("limit: ",);
let error = ::serde_yaml::from_str::<TimeTriggerConfig>(&limit);
assert!(error.is_err());

// i64
let limit = format!("limit: -1",);
let error = ::serde_yaml::from_str::<TimeTriggerConfig>(&limit);
assert!(error.is_err());

// u64
let limit = format!("limit: 1",);
let limit = ::serde_yaml::from_str::<TimeTriggerConfig>(&limit).unwrap();
assert_eq!(limit.limit, TimeTriggerLimit::Second(1));

// str second
let limit = format!("limit: 1 second",);
let limit = ::serde_yaml::from_str::<TimeTriggerConfig>(&limit).unwrap();
assert_eq!(limit.limit, TimeTriggerLimit::Second(1));

// str minute
let limit = format!("limit: 1 minute",);
let limit = ::serde_yaml::from_str::<TimeTriggerConfig>(&limit).unwrap();
assert_eq!(limit.limit, TimeTriggerLimit::Minute(1));

// str hour
let limit = format!("limit: 1 hour",);
let limit = ::serde_yaml::from_str::<TimeTriggerConfig>(&limit).unwrap();
assert_eq!(limit.limit, TimeTriggerLimit::Hour(1));

// str day
let limit = format!("limit: 1 day",);
let limit = ::serde_yaml::from_str::<TimeTriggerConfig>(&limit).unwrap();
assert_eq!(limit.limit, TimeTriggerLimit::Day(1));

// str week
let limit = format!("limit: 1 week",);
let limit = ::serde_yaml::from_str::<TimeTriggerConfig>(&limit).unwrap();
assert_eq!(limit.limit, TimeTriggerLimit::Week(1));

// str month
let limit = format!("limit: 1 month",);
let limit = ::serde_yaml::from_str::<TimeTriggerConfig>(&limit).unwrap();
assert_eq!(limit.limit, TimeTriggerLimit::Month(1));

// str year
let limit = format!("limit: 1 year",);
let limit = ::serde_yaml::from_str::<TimeTriggerConfig>(&limit).unwrap();
assert_eq!(limit.limit, TimeTriggerLimit::Year(1));
}

#[test]
fn pre_process() {
let trigger = TimeTrigger::new(TimeTriggerLimit::Minute(2));
assert!(trigger.is_pre_process());
}
}

0 comments on commit c0b07b5

Please sign in to comment.