use slotgate::execution::slot_pool::SlotPool;
use std::time::Duration;
use tokio::time::timeout;
#[tokio::test]
async fn a_held_guard_keeps_its_slot_out_of_circulation() {
let pool = SlotPool::new(1);
let guard = pool.acquire().await;
let while_held = timeout(Duration::from_millis(200), pool.acquire()).await;
assert!(
while_held.is_err(),
"the only slot is held, so a second acquire must block"
);
drop(guard);
assert!(
timeout(Duration::from_millis(500), pool.acquire())
.await
.is_ok(),
"the slot must become available once the guard drops"
);
}
#[tokio::test]
async fn drop_returns_the_guards_own_slot_and_not_merely_some_slot() {
let pool = SlotPool::new(3);
let first = pool.acquire().await;
let middle = pool.acquire().await;
let last = pool.acquire().await;
let middle_slot = middle.slot_index();
drop(middle);
let replacement = timeout(Duration::from_millis(500), pool.acquire())
.await
.expect("the released slot should be immediately available");
assert_eq!(replacement.slot_index(), middle_slot);
assert_ne!(replacement.slot_index(), first.slot_index());
assert_ne!(replacement.slot_index(), last.slot_index());
}
#[tokio::test]
async fn guards_dropped_out_of_order_each_return_their_own_slot() {
let pool = SlotPool::new(3);
let first = pool.acquire().await;
let middle = pool.acquire().await;
let last = pool.acquire().await;
let (first_slot, middle_slot, last_slot) =
(first.slot_index(), middle.slot_index(), last.slot_index());
drop(last);
drop(first);
drop(middle);
let a = pool.acquire().await;
let b = pool.acquire().await;
let c = pool.acquire().await;
let mut returned = [a.slot_index(), b.slot_index(), c.slot_index()];
returned.sort_unstable();
let mut expected = [first_slot, middle_slot, last_slot];
expected.sort_unstable();
assert_eq!(returned, expected);
}
#[tokio::test]
async fn slot_index_reports_the_same_slot_on_every_call() {
let pool = SlotPool::new(4);
let guard = pool.acquire().await;
let first_read = guard.slot_index();
let second_read = guard.slot_index();
assert_eq!(first_read, second_read);
}