use super::*;
fn peer(n: u32) -> CanonicalPeer {
CanonicalPeer::direct(&n.to_be_bytes())
}
fn taken(log: &ReceivedEventLog, source: &CanonicalPeer, now: Instant, count: u32) -> u32 {
(0..count).filter(|_| log.admit(source, now)).count() as u32
}
#[test]
fn each_source_gets_its_rate_in_each_window() {
let log = ReceivedEventLog::default();
let start = runtime_clock::now();
assert_eq!(taken(&log, &peer(1), start, 8), RECEIVED_EVENT_LOG_RATE);
assert_eq!(taken(&log, &peer(2), start, 8), RECEIVED_EVENT_LOG_RATE);
let late = start + WINDOW - Duration::from_millis(1);
assert_eq!(taken(&log, &peer(1), late, 1), 0);
assert_eq!(
taken(&log, &peer(1), start + WINDOW, 8),
RECEIVED_EVENT_LOG_RATE
);
}
#[test]
fn a_flood_of_sources_shares_one_allowance_past_the_table() {
let log = ReceivedEventLog::default();
let now = runtime_clock::now();
let tracked = RECEIVED_EVENT_LOG_SOURCES as u32;
let mut total = 0;
for n in 0..tracked {
total += taken(&log, &peer(n), now, 8);
}
assert_eq!(total, tracked * RECEIVED_EVENT_LOG_RATE);
let mut untracked = 0;
for n in tracked..tracked + 1000 {
untracked += taken(&log, &peer(n), now, 8);
}
assert_eq!(untracked, RECEIVED_EVENT_LOG_RATE);
assert_eq!(
log.0.lock().unwrap().sources.len(),
RECEIVED_EVENT_LOG_SOURCES
);
assert_eq!(taken(&log, &peer(0), now, 1), 0);
}
#[test]
fn a_new_source_takes_the_place_of_one_silent_for_a_window() {
let log = ReceivedEventLog::default();
let start = runtime_clock::now();
let tracked = RECEIVED_EVENT_LOG_SOURCES as u32;
for n in 0..tracked {
assert_eq!(taken(&log, &peer(n), start, 1), 1);
}
let later = start + WINDOW;
for n in 1..tracked {
assert_eq!(taken(&log, &peer(n), later, 1), 1);
}
let newcomer = peer(tracked);
assert_eq!(taken(&log, &newcomer, later, 8), RECEIVED_EVENT_LOG_RATE);
let allowances = log.0.lock().unwrap();
assert!(allowances.sources.iter().any(|(p, _)| *p == newcomer));
assert!(allowances.sources.iter().all(|(p, _)| *p != peer(0)));
assert_eq!(allowances.shared.taken, 0);
}
#[test]
fn the_ceiling_holds_window_after_window() {
let log = ReceivedEventLog::default();
let start = runtime_clock::now();
let ceiling = (RECEIVED_EVENT_LOG_SOURCES as u32 + 1) * RECEIVED_EVENT_LOG_RATE;
let mut next = 0;
for window in 0..5 {
let now = start + WINDOW * window;
let mut total = 0;
for _ in 0..500 {
total += taken(&log, &peer(next), now, 3);
next += 1;
}
assert!(total <= ceiling, "window {window}: {total}");
assert!(total > 0);
}
}
#[test]
fn a_source_that_sent_late_in_its_window_keeps_its_place() {
let log = ReceivedEventLog::default();
let start = runtime_clock::now();
let late = start + Duration::from_millis(900);
let tracked = RECEIVED_EVENT_LOG_SOURCES as u32;
for n in 0..tracked {
assert_eq!(taken(&log, &peer(n), start, 1), 1);
assert_eq!(taken(&log, &peer(n), late, 1), 1);
}
let newcomer = peer(tracked);
assert_eq!(taken(&log, &newcomer, start + WINDOW, 1), 1);
{
let allowances = log.0.lock().unwrap();
assert!(allowances.sources.iter().all(|(p, _)| *p != newcomer));
assert!(allowances.sources.iter().any(|(p, _)| *p == peer(0)));
assert_eq!(allowances.shared.taken, 1);
}
assert_eq!(taken(&log, &newcomer, late + WINDOW, 1), 1);
let allowances = log.0.lock().unwrap();
assert!(allowances.sources.iter().any(|(p, _)| *p == newcomer));
assert_eq!(allowances.sources.len(), RECEIVED_EVENT_LOG_SOURCES);
}