use super::*;
#[test]
fn nothing_is_allocated_until_something_is_installed() {
let hooks = Hooks::new();
assert!(
hooks.0.is_none(),
"an empty Hooks must hold no boxed inner struct"
);
assert!(!hooks.is_observed());
let mut hooks = hooks;
hooks.install_rate_limiter(Box::new(AllowAll));
assert!(
hooks.0.is_some(),
"installing a seam must allocate the inner struct"
);
assert!(
!hooks.is_observed(),
"is_observed must answer for the EVENT sink specifically"
);
}
#[test]
fn installing_a_second_sink_replaces_the_first() {
let mut hooks = Hooks::new();
hooks.install_event_sink(Box::new(NullSink));
hooks.install_event_sink(Box::new(NullSink));
let installed = hooks.0.as_ref().expect("something is installed");
assert!(installed.events.is_some());
assert!(installed.rate_limiter.is_none());
assert!(installed.secret_verifier.is_none());
}
#[test]
fn an_absent_sink_never_runs_the_event_closure() {
let hooks = Hooks::new();
hooks.emit(|| panic!("the event closure must not run without a sink"));
let mut hooks = Hooks::new();
hooks.install_rate_limiter(Box::new(AllowAll));
hooks.emit(|| panic!("the event closure must not run without a sink"));
}
#[test]
fn an_absent_limiter_allows() {
let hooks = Hooks::new();
assert_eq!(
hooks.check(Attempt::ClientAuthentication { client_id: "c" }),
RateLimitDecision::Allow
);
hooks.record(
Attempt::ClientAuthentication { client_id: "c" },
AttemptOutcome::Succeeded,
);
}
struct NullSink;
impl EventSink for NullSink {
fn on_event(&self, _event: Event<'_>) {}
}
struct AllowAll;
impl RateLimiter for AllowAll {
fn check(&self, _attempt: Attempt<'_>) -> RateLimitDecision {
RateLimitDecision::Allow
}
}