Skip to content

Instantly share code, notes, and snippets.

@eval-exec
Last active December 27, 2022 10:28
Show Gist options
  • Save eval-exec/177bffa02bdb0302e1d59c94266508d9 to your computer and use it in GitHub Desktop.
Save eval-exec/177bffa02bdb0302e1d59c94266508d9 to your computer and use it in GitHub Desktop.
faketime issue
use serial_test::serial;
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
// Store faketime timestamp here
#[cfg(test)]
static FAKETIME: AtomicU64 = AtomicU64::new(0);
// Indicate whether faketime is enabled
#[cfg(test)]
static ENABLE_FAKETIME: AtomicBool = AtomicBool::new(false);
// Get real system's timestamp in millis
fn system_time_as_millis() -> u64 {
let duration = std::time::SystemTime::now()
.duration_since(std::time::SystemTime::UNIX_EPOCH)
.expect("SystemTime before UNIX EPOCH!");
duration.as_secs() * 1000 + u64::from(duration.subsec_millis())
}
/// SystemTime provide methods to get system's timestamp in millis
///
/// If use it in test module, it provide FaketimeGuard to enable/disable/set faketime
pub struct SystemTime {}
impl SystemTime {
#[cfg(not(test))]
pub fn unix_time_as_millis() -> u64 {
system_time_as_millis()
}
#[cfg(test)]
pub fn faketime() -> FaketimeGuard {
FaketimeGuard {}
}
#[cfg(test)]
pub fn unix_time_as_millis() -> u64 {
if ENABLE_FAKETIME.load(Ordering::SeqCst) {
return FAKETIME.load(Ordering::SeqCst);
}
system_time_as_millis()
}
}
#[cfg(test)]
pub struct FaketimeGuard {}
#[cfg(test)]
impl FaketimeGuard {
#[cfg(test)]
fn set_faketime(&self, time: u64) {
FAKETIME.store(time, Ordering::Relaxed);
ENABLE_FAKETIME.store(true, Ordering::SeqCst);
}
#[cfg(test)]
fn disable_faketime(&self) {
ENABLE_FAKETIME.store(false, Ordering::Relaxed);
}
}
#[cfg(test)]
impl Drop for FaketimeGuard {
fn drop(&mut self) {
self.disable_faketime()
}
}
///////////// main ///////////////////
fn main() {
dbg!(SystemTime::unix_time_as_millis());
// bellow line won't compile,
// because SystemTime::faketime() only exists in the test module
// let x = SystemTime::faketime();
}
///////////// test ///////////////////
#[serial]
#[test]
fn test0() {
let faketime_guard = SystemTime::faketime();
faketime_guard.set_faketime(123);
assert!(SystemTime::unix_time_as_millis() == 123);
faketime_guard.set_faketime(100);
assert!(SystemTime::unix_time_as_millis() == 100);
faketime_guard.disable_faketime();
let now = system_time_as_millis();
assert!(SystemTime::unix_time_as_millis() >= now);
// The faketime_guard was dropped at the end of the scope,
// then ENABLE_FAKETIME will be set to false
}
#[serial]
#[test]
fn test1() {
let now = system_time_as_millis();
assert!(SystemTime::unix_time_as_millis() >= now);
}
#[serial]
#[test]
fn test2() {
let now = system_time_as_millis();
{
let faketime_guard = SystemTime::faketime();
faketime_guard.set_faketime(1);
assert!(SystemTime::unix_time_as_millis() == 1);
}
assert!(SystemTime::unix_time_as_millis() >= now);
{
let faketime_guard = SystemTime::faketime();
faketime_guard.set_faketime(2);
assert!(SystemTime::unix_time_as_millis() == 2);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment