use std::sync::atomic::{AtomicBool, AtomicI64, AtomicU64, Ordering};
use std::time::Duration;
#[derive(Debug, Default)]
pub struct FaultInjector {
notifier_disabled: AtomicBool,
refresh_delay_ms: AtomicU64,
force_reconnect: AtomicBool,
refresh_should_error: AtomicBool,
notifier_should_panic: AtomicBool,
clock_skew_ms: AtomicI64,
}
impl FaultInjector {
pub fn new() -> Self {
Self::default()
}
pub fn disable_notifier(&self) {
self.notifier_disabled.store(true, Ordering::SeqCst);
}
pub fn is_notifier_disabled(&self) -> bool {
self.notifier_disabled.load(Ordering::SeqCst)
}
pub fn set_notifier_should_panic(&self, should_panic: bool) {
self.notifier_should_panic
.store(should_panic, Ordering::SeqCst);
}
pub fn should_notifier_panic(&self) -> bool {
self.notifier_should_panic.swap(false, Ordering::SeqCst)
}
pub fn set_refresh_delay(&self, delay: Duration) {
self.refresh_delay_ms
.store(delay.as_millis() as u64, Ordering::SeqCst);
}
pub fn get_refresh_delay(&self) -> Duration {
Duration::from_millis(self.refresh_delay_ms.load(Ordering::SeqCst))
}
pub fn set_refresh_should_error(&self, should_error: bool) {
self.refresh_should_error
.store(should_error, Ordering::SeqCst);
}
pub fn should_refresh_error(&self) -> bool {
self.refresh_should_error.swap(false, Ordering::SeqCst)
}
pub fn trigger_reconnect(&self) {
self.force_reconnect.store(true, Ordering::SeqCst);
}
pub fn should_reconnect(&self) -> bool {
self.force_reconnect.swap(false, Ordering::SeqCst)
}
pub fn set_clock_skew(&self, skew: Duration) {
self.clock_skew_ms
.store(skew.as_millis() as i64, Ordering::SeqCst);
}
pub fn set_clock_skew_signed(&self, skew_ms: i64) {
self.clock_skew_ms.store(skew_ms, Ordering::SeqCst);
}
pub fn get_clock_skew_ms(&self) -> i64 {
self.clock_skew_ms.load(Ordering::SeqCst)
}
pub fn clear_clock_skew(&self) {
self.clock_skew_ms.store(0, Ordering::SeqCst);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fault_injector_default() {
let fi = FaultInjector::new();
assert!(!fi.is_notifier_disabled());
assert_eq!(fi.get_refresh_delay(), Duration::ZERO);
assert!(!fi.should_reconnect());
}
#[test]
fn test_disable_notifier() {
let fi = FaultInjector::new();
fi.disable_notifier();
assert!(fi.is_notifier_disabled());
}
#[test]
fn test_refresh_delay() {
let fi = FaultInjector::new();
fi.set_refresh_delay(Duration::from_secs(5));
assert_eq!(fi.get_refresh_delay(), Duration::from_secs(5));
}
#[test]
fn test_reconnect_flag() {
let fi = FaultInjector::new();
assert!(!fi.should_reconnect());
fi.trigger_reconnect();
assert!(fi.should_reconnect());
assert!(!fi.should_reconnect());
}
#[test]
fn test_refresh_error_flag() {
let fi = FaultInjector::new();
assert!(!fi.should_refresh_error());
fi.set_refresh_should_error(true);
assert!(fi.should_refresh_error());
assert!(!fi.should_refresh_error());
}
#[test]
fn test_notifier_panic_flag() {
let fi = FaultInjector::new();
assert!(!fi.should_notifier_panic());
fi.set_notifier_should_panic(true);
assert!(fi.should_notifier_panic());
assert!(!fi.should_notifier_panic());
}
#[test]
fn test_clock_skew() {
let fi = FaultInjector::new();
assert_eq!(fi.get_clock_skew_ms(), 0);
fi.set_clock_skew(Duration::from_millis(500));
assert_eq!(fi.get_clock_skew_ms(), 500);
fi.set_clock_skew_signed(-200);
assert_eq!(fi.get_clock_skew_ms(), -200);
fi.clear_clock_skew();
assert_eq!(fi.get_clock_skew_ms(), 0);
}
}