use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::time::{Duration, Instant};
use gunnar_ssh::admission::DEFAULT_MAX_ANONYMOUS_TRANSFERS;
use gunnar_ssh::config::DEFAULT_MAX_TRANSFERS_PER_PRINCIPAL;
use gunnar_ssh::governor::OpClass;
use gunnar_ssh::gunnar_core::ANONYMOUS_PRINCIPAL_ID;
use gunnar_ssh::{Admission, AdmissionGuard, Refusal, SshConfig};
fn roomy_gate(anonymous: usize) -> Arc<Admission> {
Arc::new(
Admission::new(Some(64), Some(DEFAULT_MAX_TRANSFERS_PER_PRINCIPAL))
.with_anonymous_ceiling(Some(anonymous))
.with_wait(Duration::ZERO),
)
}
#[test]
fn the_anonymous_ceiling_binds_on_an_idle_server() {
let gate = roomy_gate(5);
let mut held: Vec<AdmissionGuard> = Vec::new();
for i in 0..5 {
held.push(
gate.try_admit(ANONYMOUS_PRINCIPAL_ID, "team", OpClass::Clone)
.unwrap_or_else(|refusal| {
panic!("anonymous transfer {i} must be admitted, and was refused: {refusal}")
}),
);
}
let refusal = gate
.try_admit(ANONYMOUS_PRINCIPAL_ID, "team", OpClass::Clone)
.expect_err(
"the sixth anonymous transfer must be refused on an EMPTY server; if it was admitted \
the max-min share is the only ceiling and a stranger's ceiling is the whole box",
);
assert_eq!(
refusal,
Refusal::AnonymousAtCapacity { limit: 5 },
"the refusal must name the anonymous ceiling, not the server-wide limit: an operator who \
reads `at capacity` on a box with 59 free slots raises the wrong number"
);
let stats = gate.stats();
assert_eq!(stats.in_flight, 5, "exactly the ceiling is in flight");
assert_eq!(
stats.peak_in_flight, 5,
"and the HIGH-WATER MARK is the cap"
);
assert_eq!(
stats.refused_anonymous, 1,
"the refusal must be COUNTED under its own reason; folded into \
`refused_per_principal` it is indistinguishable from a keyed client hitting its share"
);
assert_eq!(
stats.refused_per_principal, 0,
"and it must NOT be counted as a per-principal refusal"
);
assert_eq!(
stats.refused(),
1,
"it is a refusal, so the total moves too"
);
drop(held.pop().expect("five were held"));
gate.try_admit(ANONYMOUS_PRINCIPAL_ID, "team", OpClass::Clone)
.expect("a freed anonymous slot is reusable");
assert_eq!(gate.stats().peak_in_flight, 5, "and the peak never moved");
}
#[tokio::test(flavor = "multi_thread", worker_threads = 8)]
async fn two_hundred_anonymous_readers_never_exceed_the_ceiling() {
const CEILING: usize = 5;
let gate = roomy_gate(CEILING);
let inside = Arc::new(AtomicUsize::new(0));
let observed_peak = Arc::new(AtomicUsize::new(0));
let admitted = Arc::new(AtomicUsize::new(0));
let mut tasks = tokio::task::JoinSet::new();
for _ in 0..200 {
let gate = Arc::clone(&gate);
let inside = Arc::clone(&inside);
let observed_peak = Arc::clone(&observed_peak);
let admitted = Arc::clone(&admitted);
tasks.spawn(async move {
for _ in 0..40 {
match gate.try_admit(ANONYMOUS_PRINCIPAL_ID, "team", OpClass::Clone) {
Ok(guard) => {
let now = inside.fetch_add(1, Ordering::SeqCst) + 1;
observed_peak.fetch_max(now, Ordering::SeqCst);
admitted.fetch_add(1, Ordering::SeqCst);
tokio::time::sleep(Duration::from_millis(2)).await;
inside.fetch_sub(1, Ordering::SeqCst);
drop(guard);
return;
}
Err(_) => tokio::time::sleep(Duration::from_millis(1)).await,
}
}
});
}
while tasks.join_next().await.is_some() {}
let peak = observed_peak.load(Ordering::SeqCst);
assert!(
peak > 0 && peak <= CEILING,
"the observed maximum number of anonymous transfers in flight at once was {peak}, and the \
ceiling is {CEILING}; a bound that is exceeded under load is not a bound"
);
assert_eq!(
peak, CEILING,
"the ceiling must actually be REACHED as well as not exceeded; a test that only ever saw \
one transfer at a time would pass the bound above while proving nothing"
);
assert!(
admitted.load(Ordering::SeqCst) > CEILING,
"the gate must keep SERVING anonymous readers as slots free up, not serve five and shut; \
a ceiling that never recycles is an outage with a nicer name"
);
let counter_peak = gate.stats().peak_in_flight as usize;
assert!(
counter_peak <= CEILING + 1,
"the gate's lock-free high-water mark read {counter_peak} against a ceiling of {CEILING}; \
one above is the release/admit interleave described here, more than one is the ceiling \
itself failing"
);
}
#[test]
fn an_authenticated_caller_is_never_held_up_by_an_anonymous_flood() {
let gate = roomy_gate(5);
let _anon: Vec<AdmissionGuard> = (0..5)
.map(|_| {
gate.try_admit(ANONYMOUS_PRINCIPAL_ID, "team", OpClass::Clone)
.expect("anonymous fills its ceiling")
})
.collect();
for _ in 0..50 {
gate.try_admit(ANONYMOUS_PRINCIPAL_ID, "team", OpClass::Clone)
.expect_err("and every further anonymous ask is refused");
}
let mut operator = Vec::new();
for i in 0..DEFAULT_MAX_TRANSFERS_PER_PRINCIPAL {
operator.push(
gate.try_admit("alice", "team", OpClass::Clone)
.unwrap_or_else(|refusal| {
panic!(
"a keyed principal's transfer {i} was refused while anonymous held only 5 of \
64 slots: {refusal}"
)
}),
);
}
assert_eq!(
gate.stats().in_flight,
5 + DEFAULT_MAX_TRANSFERS_PER_PRINCIPAL as u64,
"anonymous kept its five and the operator got its whole floor, at the same time"
);
assert_eq!(
gate.stats().refused_per_principal,
0,
"and the operator was never refused for any reason"
);
}
#[test]
fn a_panicking_anonymous_transfer_gives_its_permit_back() {
let gate = roomy_gate(1);
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe({
let gate = Arc::clone(&gate);
move || {
let _guard = gate
.try_admit(ANONYMOUS_PRINCIPAL_ID, "team", OpClass::Clone)
.expect("the only anonymous slot");
assert_eq!(gate.stats().in_flight, 1);
panic!("a clone that dies mid-pack");
}
}));
assert!(result.is_err(), "the closure must actually have panicked");
assert_eq!(
gate.stats().in_flight,
0,
"the permit must be released by unwinding; a manual decrement on the happy path would \
read 1 here and the ceiling would shrink by one per panic until it was zero"
);
gate.try_admit(ANONYMOUS_PRINCIPAL_ID, "team", OpClass::Clone)
.expect("and the ceiling is whole again after a panic");
}
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn an_anonymous_refusal_is_never_parked() {
let wait = Duration::from_millis(400);
let gate = Arc::new(
Admission::hard_capped(Some(64), Some(2))
.with_anonymous_ceiling(Some(1))
.with_wait(wait),
);
let _anon = gate
.try_admit(ANONYMOUS_PRINCIPAL_ID, "team", OpClass::Clone)
.expect("the only anonymous slot");
let _keyed = [
gate.try_admit("alice", "team", OpClass::Clone)
.expect("first"),
gate.try_admit("alice", "team", OpClass::Clone)
.expect("second"),
];
let started = Instant::now();
let refusal = gate
.admit_within(ANONYMOUS_PRINCIPAL_ID, "team", OpClass::Clone)
.await
.expect_err("anonymous is over its ceiling");
let anonymous_took = started.elapsed();
assert!(
matches!(refusal, Refusal::AnonymousAtCapacity { limit: 1 }),
"refused by the anonymous ceiling, got {refusal:?}"
);
assert!(
anonymous_took < wait / 4,
"an anonymous caller over the ceiling waited {anonymous_took:?} of a {wait:?} bound; it \
must be refused immediately, because parking it is what holds the socket a flood wants"
);
let started = Instant::now();
gate.admit_within("alice", "team", OpClass::Clone)
.await
.expect_err("the keyed principal is over its share too");
let keyed_took = started.elapsed();
assert!(
keyed_took >= wait,
"the keyed refusal waited only {keyed_took:?} of its {wait:?} bound, so the anonymous \
comparison above proves nothing"
);
}
#[test]
fn the_anonymous_default_is_a_decision_and_is_far_below_the_keyed_share() {
assert_eq!(
DEFAULT_MAX_ANONYMOUS_TRANSFERS, 5,
"the number is a decision; change it here and in the doc comment that argues for it"
);
const {
assert!(
DEFAULT_MAX_ANONYMOUS_TRANSFERS < DEFAULT_MAX_TRANSFERS_PER_PRINCIPAL,
"a stranger must never be able to hold as much as a keyed identity is GUARANTEED"
)
}
let config = SshConfig::default();
assert_eq!(
config.max_anonymous_transfers,
Some(DEFAULT_MAX_ANONYMOUS_TRANSFERS),
"the appliance default must HAVE an anonymous ceiling: the door is open by default, so \
the door has to arrive with the limit already on it"
);
assert_eq!(
config.without_anonymous_access().max_anonymous_transfers,
Some(DEFAULT_MAX_ANONYMOUS_TRANSFERS),
"closing the door must not silently clear the ceiling; re-opening it later would then \
re-open it unlimited"
);
}
#[test]
fn the_ceiling_can_be_switched_off_entirely() {
let gate = Arc::new(
Admission::new(Some(64), Some(DEFAULT_MAX_TRANSFERS_PER_PRINCIPAL))
.with_anonymous_ceiling(None)
.with_wait(Duration::ZERO),
);
let held: Vec<AdmissionGuard> = (0..DEFAULT_MAX_TRANSFERS_PER_PRINCIPAL)
.map(|i| {
gate.try_admit(ANONYMOUS_PRINCIPAL_ID, "team", OpClass::Clone)
.unwrap_or_else(|e| panic!("with the ceiling off, anonymous {i} is admitted: {e}"))
})
.collect();
assert_eq!(held.len(), DEFAULT_MAX_TRANSFERS_PER_PRINCIPAL);
assert_eq!(gate.stats().refused_anonymous, 0);
assert_eq!(
gate.max_anonymous(),
None,
"and the gate reports the ceiling it is actually enforcing"
);
}