use std::time::Duration;
use tokio::time::Instant;
use tokio::time::sleep;
use super::*;
#[tokio::test]
async fn test_election_timer_init_within_range() {
let (min, max) = (100u64, 200u64);
let timer = ElectionTimer::new((min, max));
let now = Instant::now();
let next_deadline = timer.next_deadline();
assert!(next_deadline > now, "Next deadline should be in the future");
let elapsed = next_deadline - now;
let min_duration = Duration::from_millis(min.saturating_sub(1));
let max_duration = Duration::from_millis(max + 1);
assert!(
elapsed >= min_duration,
"Elapsed time {elapsed:?} should be at least {min_duration:?}",
);
assert!(
elapsed <= max_duration,
"Elapsed time {elapsed:?} should be at most {max_duration:?}",
);
}
#[tokio::test]
async fn test_election_timer_shows_randomness() {
let (min, max) = (100u64, 200u64);
let range = (min, max);
let timers: Vec<_> = (0..5).map(|_| ElectionTimer::new(range)).collect();
let deadlines: Vec<_> = timers.iter().map(|t| t.next_deadline()).collect();
let first = deadlines[0];
let all_same = deadlines.iter().all(|&d| d == first);
assert!(
!all_same || deadlines.len() == 1,
"Timers should have different deadlines due to randomness"
);
}
#[tokio::test]
async fn test_election_timer_not_expired_initially() {
let timer = ElectionTimer::new((100u64, 200u64));
assert!(
!timer.is_expired(),
"Timer should not be expired immediately after creation"
);
}
#[tokio::test]
async fn test_election_timer_expired_after_timeout() {
let timer = ElectionTimer::new((10u64, 20u64));
sleep(Duration::from_millis(50)).await;
assert!(
timer.is_expired(),
"Timer should be expired after timeout period"
);
}
#[tokio::test]
async fn test_election_timer_reset() {
let mut timer = ElectionTimer::new((100u64, 200u64));
sleep(Duration::from_millis(150)).await;
let before_reset = Instant::now();
timer.reset();
let new_deadline = timer.next_deadline();
let min_expected = before_reset + Duration::from_millis(100);
assert!(
new_deadline >= min_expected,
"New deadline {new_deadline:?} should be at least 100ms after reset time {before_reset:?}",
);
}
#[tokio::test]
async fn test_election_timer_random_duration_bounds() {
let (min, max) = (50u64, 150u64);
let min_duration = Duration::from_millis(min);
let max_duration = Duration::from_millis(max);
for _ in 0..100 {
let duration = ElectionTimer::random_duration(min, max);
assert!(
duration >= min_duration,
"Duration {duration:?} should be >= {min_duration:?}",
);
assert!(
duration < max_duration,
"Duration {duration:?} should be < {max_duration:?}",
);
}
}
#[tokio::test]
async fn test_election_timer_random_duration_distribution() {
let (min, max) = (100u64, 200u64);
let mut durations = Vec::new();
for _ in 0..100 {
let duration = ElectionTimer::random_duration(min, max);
durations.push(duration.as_millis() as u64);
}
durations.sort();
let q1 = durations[24]; let q3 = durations[74];
assert!(
q3 > q1 + 10,
"Quartiles suggest good distribution: Q1={q1}, Q3={q3}",
);
}
#[tokio::test]
async fn test_replication_timer_init() {
let replication_timeout = 100u64;
let timer = ReplicationTimer::new(replication_timeout);
let now = Instant::now();
let replication_elapsed = timer.replication_deadline() - now;
assert!(
replication_elapsed >= Duration::from_millis(replication_timeout - 5),
"Replication deadline should be close to timeout value"
);
}
#[tokio::test]
async fn test_replication_timer_next_deadline() {
let timer = ReplicationTimer::new(100u64);
let replication = timer.replication_deadline();
let next = timer.next_deadline();
assert_eq!(
next, replication,
"next_deadline should equal replication_deadline"
);
}
#[tokio::test]
async fn test_replication_timer_reset_replication() {
let mut timer = ReplicationTimer::new(100u64);
let old_deadline = timer.replication_deadline();
sleep(Duration::from_millis(10)).await;
timer.reset_replication();
let new_deadline = timer.replication_deadline();
assert!(
new_deadline > old_deadline,
"New replication deadline should be later than old one"
);
}
#[tokio::test]
async fn test_replication_timer_is_expired() {
let timer = ReplicationTimer::new(5u64);
assert!(
!timer.is_expired(),
"Timer should not be expired immediately"
);
sleep(Duration::from_millis(20)).await;
assert!(timer.is_expired(), "Timer should be expired after timeout");
}