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 Jan 24, 2024
1 parent 13590a7 commit 1753fe8
Show file tree
Hide file tree
Showing 4 changed files with 274 additions and 20 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,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());
}
}
278 changes: 260 additions & 18 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,31 @@ 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_time =
NaiveDateTime::from_timestamp_opt(now.as_secs() as i64, now.subsec_nanos())
.unwrap();
Utc.from_utc_datetime(&naive_time)
};

#[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 +198,19 @@ 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 = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("system time before Unix epoch");
let naive_time =
NaiveDateTime::from_timestamp_opt(now.as_secs() as i64, now.subsec_nanos())
.unwrap();
Utc.from_utc_datetime(&naive_time)
};

#[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 @@ -223,9 +254,9 @@ impl Trigger for TimeTrigger {
/// ```yaml
/// kind: time
///
/// # The time limit in second. The following units are supported (case insensitive):
/// # "second", "seconds", "minute", "minutes", "hour", "hours", "day", "days", "week", "weeks", "month", "months", "year", "years". The unit defaults to
/// # second if not specified. Required.
/// # The time limit in seconds. The following units are supported (case insensitive):
/// # "second(s)", "minute(s)", "hour(s)", "day(s)", "week(s)", "month(s)", "year(s)". The unit defaults to
/// # second if not specified.
/// limit: 7 day
/// ```
#[cfg(feature = "config_parsing")]
Expand All @@ -250,25 +281,236 @@ impl Deserialize for TimeTriggerDeserializer {
#[cfg(test)]
mod test {
use super::*;
use mock_instant::MockClock;
use std::time::Duration;

#[test]
fn trigger() {
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() {
// Second
let second_in_milli = 1000;
let minute_in_milli = second_in_milli * 60;
let hour_in_milli = minute_in_milli * 60;
let day_in_milli = hour_in_milli * 24;
let week_in_milli = day_in_milli * 7;
let month_in_milli = day_in_milli * 31;
let year_in_milli = day_in_milli * 365;
MockClock::set_system_time(Duration::from_millis(0));
assert_eq!(
trigger_with_time(TimeTriggerLimit::Second(1), second_in_milli),
(false, true)
);
// Minute
MockClock::set_system_time(Duration::from_millis(0));
assert_eq!(
trigger_with_time(TimeTriggerLimit::Minute(1), minute_in_milli),
(false, true)
);
// Hour
MockClock::set_system_time(Duration::from_millis(0));
assert_eq!(
trigger_with_time(TimeTriggerLimit::Hour(1), hour_in_milli),
(false, true)
);
// Day
MockClock::set_system_time(Duration::from_millis(0));
assert_eq!(
trigger_with_time(TimeTriggerLimit::Day(1), day_in_milli),
(false, true)
);
// Week
MockClock::set_system_time(Duration::from_millis(4 * day_in_milli)); // Monday
assert_eq!(
trigger_with_time(TimeTriggerLimit::Week(1), week_in_milli),
(false, true)
);
// Month
MockClock::set_system_time(Duration::from_millis(0));
assert_eq!(
trigger_with_time(TimeTriggerLimit::Month(1), month_in_milli),
(false, true)
);
// Year
MockClock::set_system_time(Duration::from_millis(0));
assert_eq!(
trigger_with_time(TimeTriggerLimit::Year(1), year_in_milli),
(false, true)
);
}

#[test]
fn trigger2() {
// This test may fail if it runs in the following timezones (UTC+12, UTC-12)
// Second
let second_in_milli = 1000;
let minute_in_milli = second_in_milli * 60;
let hour_in_milli = minute_in_milli * 60;
let day_in_milli = hour_in_milli * 24;
let week_in_milli = day_in_milli * 7;
let month_in_milli = day_in_milli * 31;
let year_in_milli = day_in_milli * 365;
MockClock::set_system_time(Duration::from_millis(second_in_milli / 2));
assert_eq!(
trigger_with_time(TimeTriggerLimit::Second(1), second_in_milli),
(true, false)
);
// Minute
MockClock::set_system_time(Duration::from_millis(minute_in_milli / 2));
assert_eq!(
trigger_with_time(TimeTriggerLimit::Minute(1), minute_in_milli),
(true, false)
);
// Hour
MockClock::set_system_time(Duration::from_millis(hour_in_milli / 2));
assert_eq!(
trigger_with_time(TimeTriggerLimit::Hour(1), hour_in_milli),
(true, false)
);
// Day
MockClock::set_system_time(Duration::from_millis(day_in_milli / 2));
assert_eq!(
trigger_with_time(TimeTriggerLimit::Day(1), day_in_milli),
(true, false)
);
// Week
MockClock::set_system_time(Duration::from_millis(4 * day_in_milli + week_in_milli / 2)); // Monday
assert_eq!(
trigger_with_time(TimeTriggerLimit::Week(1), week_in_milli),
(true, false)
);
// Month
MockClock::set_system_time(Duration::from_millis(month_in_milli / 2));
assert_eq!(
trigger_with_time(TimeTriggerLimit::Month(1), month_in_milli),
(true, false)
);
// Year
MockClock::set_system_time(Duration::from_millis(year_in_milli / 2));
assert_eq!(
trigger_with_time(TimeTriggerLimit::Year(1), year_in_milli),
(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());

// bad unit
let limit = format!("limit: 5 das",);
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));

let limit = format!("limit: 1 seconds",);
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));

let limit = format!("limit: 1 minutes",);
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));

let limit = format!("limit: 1 hours",);
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));

let limit = format!("limit: 1 days",);
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));

let limit = format!("limit: 1 weeks",);
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));

let limit = format!("limit: 1 months",);
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));

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

#[test]
fn test_time_trigger_limit_default() {
let limit = TimeTriggerLimit::default();
assert_eq!(limit, TimeTriggerLimit::Week(1));
}

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

0 comments on commit 1753fe8

Please sign in to comment.