From 8445f338f61d0bb12a0f4b881e7f15ceffaade87 Mon Sep 17 00:00:00 2001 From: fabi Date: Tue, 16 Jun 2026 18:04:53 +0000 Subject: [PATCH] test(auth): deflake login rate-limit burst test under CPU load (#10) --- backend/tests/api_auth.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/backend/tests/api_auth.rs b/backend/tests/api_auth.rs index e572b3b..2c8b15e 100644 --- a/backend/tests/api_auth.rs +++ b/backend/tests/api_auth.rs @@ -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) { 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 .app .clone() @@ -667,9 +668,18 @@ async fn login_rate_limited_under_burst_pressure(pool: PgPool) { .await .unwrap(); - // Register consumed one token from the burst-3 bucket. Fire 30 - // 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. + // Fire 30 logins back-to-back; 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; for _ in 0..30 { let resp = h @@ -677,7 +687,7 @@ async fn login_rate_limited_under_burst_pressure(pool: PgPool) { .clone() .oneshot(common::post_json( "/api/v1/auth/login", - json!({ "username": "victim", "password": "wrong" }), + json!({ "username": "victim", "password": "" }), )) .await .unwrap();