test(auth): deflake login rate-limit burst test under CPU load #10
@@ -659,7 +659,8 @@ async fn login_no_user_branch_runs_argon2_for_timing_equalisation(pool: PgPool)
|
|||||||
async fn login_rate_limited_under_burst_pressure(pool: PgPool) {
|
async fn login_rate_limited_under_burst_pressure(pool: PgPool) {
|
||||||
let h = common::harness_with_auth_rate_limit(pool, 1, 3);
|
let h = common::harness_with_auth_rate_limit(pool, 1, 3);
|
||||||
|
|
||||||
// Register a victim so the wrong-password branch is real work.
|
// One register hit first — register and login share the one bucket,
|
||||||
|
// so this exercises the cross-endpoint limit (and consumes a token).
|
||||||
let _ = h
|
let _ = h
|
||||||
.app
|
.app
|
||||||
.clone()
|
.clone()
|
||||||
@@ -667,9 +668,18 @@ async fn login_rate_limited_under_burst_pressure(pool: PgPool) {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Register consumed one token from the burst-3 bucket. Fire 30
|
// Fire 30 logins back-to-back; at least one must come back 429.
|
||||||
// wrong-password logins back-to-back; with per_sec=1 the refill
|
//
|
||||||
// is too slow to keep up and at least one must come back 429.
|
// We send an EMPTY password on purpose. `login` calls the rate
|
||||||
|
// limiter FIRST, then short-circuits empty credentials with a 400
|
||||||
|
// BEFORE any argon2 hash or DB lookup — so each attempt still
|
||||||
|
// consumes a token but is near-instant. That makes the burst drain
|
||||||
|
// the bucket far faster than the per_sec=1 refill regardless of how
|
||||||
|
// loaded the CI box is. (A real wrong-password attempt runs argon2,
|
||||||
|
// ~1s under load, which lets the 1/sec refill keep exact pace with
|
||||||
|
// the loop and the bucket never empties — that was the old flake.
|
||||||
|
// The bucket math itself is covered by rate_limit.rs's unit test;
|
||||||
|
// here we only need to prove the limiter is wired into the route.)
|
||||||
let mut saw_429 = false;
|
let mut saw_429 = false;
|
||||||
for _ in 0..30 {
|
for _ in 0..30 {
|
||||||
let resp = h
|
let resp = h
|
||||||
@@ -677,7 +687,7 @@ async fn login_rate_limited_under_burst_pressure(pool: PgPool) {
|
|||||||
.clone()
|
.clone()
|
||||||
.oneshot(common::post_json(
|
.oneshot(common::post_json(
|
||||||
"/api/v1/auth/login",
|
"/api/v1/auth/login",
|
||||||
json!({ "username": "victim", "password": "wrong" }),
|
json!({ "username": "victim", "password": "" }),
|
||||||
))
|
))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
Reference in New Issue
Block a user