mod common;
use common::{DefaultsManager, LocalManager, cfg};
use compio_pool::Pool;
#[compio::test]
async fn a_guard_derefs_to_the_connection() {
let pool = Pool::new(LocalManager::new(), cfg().max_size(2));
let mut conn = pool.acquire().await.unwrap();
assert_eq!(conn.id, 0, "shared access goes through Deref");
conn.id = 99;
assert_eq!(conn.id, 99, "and mutable access through DerefMut");
}
#[compio::test]
async fn metadata_starts_fresh_and_counts_completed_checkouts() {
let pool = Pool::new(LocalManager::new(), cfg().max_size(2));
{
let conn = pool.acquire().await.unwrap();
let meta = conn.meta();
assert_eq!(meta.uses, 0, "a brand new connection has no history");
assert_eq!(meta.generation, 0);
assert_eq!(meta.created_at, meta.last_used);
}
let conn = pool.acquire().await.unwrap();
assert_eq!(conn.meta().uses, 1);
assert!(conn.meta().last_used >= conn.meta().created_at);
assert!(conn.meta().age() >= conn.meta().idle_for());
}
#[compio::test]
async fn a_guard_starts_unpoisoned() {
let pool = Pool::new(LocalManager::new(), cfg().max_size(2));
let conn = pool.acquire().await.unwrap();
assert!(!conn.is_poisoned());
}
#[compio::test]
async fn poisoning_by_hand_closes_the_connection_on_drop() {
let manager = LocalManager::new();
let counts = manager.counts();
let pool = Pool::new(manager, cfg().max_size(2));
{
let conn = pool.acquire().await.unwrap();
conn.poison();
assert!(conn.is_poisoned());
}
assert_eq!(counts.disconnected(), 1);
assert_eq!(
pool.local_idle(),
0,
"a poisoned connection is never pooled"
);
assert_eq!(pool.local_size(), 0, "and its budget is freed");
assert_eq!(pool.metrics().poisoned, 1);
}
#[compio::test]
async fn poisoning_twice_counts_once() {
let pool = Pool::new(LocalManager::new(), cfg().max_size(2));
{
let conn = pool.acquire().await.unwrap();
conn.poison();
conn.poison();
}
assert_eq!(
pool.metrics().poisoned,
1,
"poison is a flag, not a counter"
);
}
#[compio::test]
async fn a_completed_op_guard_leaves_the_connection_reusable() {
let manager = LocalManager::new();
let counts = manager.counts();
let pool = Pool::new(manager, cfg().max_size(2));
{
let conn = pool.acquire().await.unwrap();
let op = conn.begin_op();
op.complete_op();
assert!(!conn.is_poisoned());
}
assert_eq!(pool.local_idle(), 1);
assert_eq!(counts.disconnected(), 0);
assert_eq!(pool.metrics().poisoned, 0);
}
#[compio::test]
async fn an_op_guard_does_not_borrow_the_connection() {
let pool = Pool::new(LocalManager::new(), cfg().max_size(2));
let mut conn = pool.acquire().await.unwrap();
let op = conn.begin_op();
conn.id += 1; assert_eq!(conn.id, 1);
op.complete_op();
}
#[compio::test]
async fn one_dropped_guard_among_several_still_poisons() {
let pool = Pool::new(LocalManager::new(), cfg().max_size(2));
let conn = pool.acquire().await.unwrap();
let first = conn.begin_op();
let second = conn.begin_op();
first.complete_op();
assert!(!conn.is_poisoned());
drop(second);
assert!(conn.is_poisoned());
}
#[compio::test]
async fn completing_an_op_never_clears_an_existing_poison() {
let pool = Pool::new(LocalManager::new(), cfg().max_size(2));
let conn = pool.acquire().await.unwrap();
conn.poison();
conn.begin_op().complete_op();
assert!(conn.is_poisoned(), "poisoning is one-way");
}
#[compio::test]
async fn take_hands_the_connection_over_and_frees_the_slot() {
let manager = LocalManager::new();
let counts = manager.counts();
let pool = Pool::new(manager, cfg().max_size(1));
let conn = pool.acquire().await.unwrap();
let taken = conn.take();
assert_eq!(taken.id, 0, "the caller owns the connection now");
let m = pool.metrics();
assert_eq!(m.live, 0, "the pool no longer counts it");
assert_eq!(m.closed, 0, "but it was not closed either");
assert_eq!(counts.disconnected(), 0);
assert_eq!(pool.local_size(), 0);
assert_eq!(pool.local_idle(), 0);
let replacement = pool.acquire().await.unwrap();
assert_ne!(replacement.id, taken.id);
assert_eq!(counts.connected(), 2);
}
#[compio::test]
async fn a_taken_connection_is_not_returned_when_it_is_dropped() {
let pool = Pool::new(LocalManager::new(), cfg().max_size(2));
drop(pool.acquire().await.unwrap().take());
assert_eq!(pool.local_idle(), 0);
assert_eq!(pool.metrics().live, 0);
}
#[compio::test]
async fn the_guards_debug_output_shows_poison_state_and_metadata() {
let pool = Pool::new(LocalManager::new(), cfg().max_size(2));
let conn = pool.acquire().await.unwrap();
let s = format!("{conn:?}");
assert!(s.contains("poisoned: false"), "got {s}");
assert!(s.contains("meta"), "got {s}");
conn.poison();
assert!(format!("{conn:?}").contains("poisoned: true"));
let op = conn.begin_op();
assert!(format!("{op:?}").contains("armed: true"));
op.complete_op();
}
#[compio::test]
async fn a_manager_using_the_default_disconnect_still_balances_the_counters() {
let pool = Pool::new(DefaultsManager, cfg().max_size(1));
let conn = pool.acquire().await.unwrap();
conn.poison();
drop(conn);
let m = pool.metrics();
assert_eq!((m.live, m.created, m.closed), (0, 1, 1));
}