test: add auth and session unit tests (20 test cases)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-10 23:54:14 +00:00
co-authored by Claude Opus 4.6
parent 05ed3b7bcf
commit 615ce4f939
3 changed files with 195 additions and 1 deletions
+114
View File
@@ -179,3 +179,117 @@ impl LoginRateLimiter {
entry.push(Instant::now());
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_session_create_and_validate() {
let store = SessionStore::new();
let token = store.create().await;
assert!(store.validate(&token).await);
}
#[tokio::test]
async fn test_session_invalid_token() {
let store = SessionStore::new();
assert!(!store.validate("nonexistent_token").await);
}
#[tokio::test]
async fn test_session_remove() {
let store = SessionStore::new();
let token = store.create().await;
assert!(store.validate(&token).await);
store.remove(&token).await;
assert!(!store.validate(&token).await);
}
#[tokio::test]
async fn test_pending_session_upgrade() {
let store = SessionStore::new();
let secret = vec![1, 2, 3, 4];
let token = store.create_pending(secret.clone()).await;
// Pending session should not validate as full
assert!(!store.validate(&token).await);
// Can get the TOTP secret
let got = store.get_pending_secret(&token).await;
assert_eq!(got, Some(secret));
// Upgrade to full
store.upgrade_to_full(&token).await;
assert!(store.validate(&token).await);
}
#[tokio::test]
async fn test_pending_session_max_attempts() {
let store = SessionStore::new();
let secret = vec![1, 2, 3];
let token = store.create_pending(secret).await;
// Exhaust MAX_TOTP_ATTEMPTS (5) + 1 to trigger removal
for _ in 0..MAX_TOTP_ATTEMPTS {
assert!(store.get_pending_secret(&token).await.is_some());
}
// 6th attempt should fail (session removed)
assert!(store.get_pending_secret(&token).await.is_none());
}
#[tokio::test]
async fn test_extract_session_cookie() {
let mut headers = hyper::HeaderMap::new();
headers.insert("cookie", "session=abc123; other=xyz".parse().unwrap());
assert_eq!(extract_session_cookie(&headers), Some("abc123".to_string()));
}
#[tokio::test]
async fn test_extract_session_cookie_missing() {
let headers = hyper::HeaderMap::new();
assert_eq!(extract_session_cookie(&headers), None);
}
#[tokio::test]
async fn test_rate_limiter_allows_under_limit() {
let limiter = LoginRateLimiter::new();
let ip: IpAddr = "127.0.0.1".parse().unwrap();
for _ in 0..MAX_ATTEMPTS {
assert!(limiter.check(ip).await);
limiter.record_failure(ip).await;
}
}
#[tokio::test]
async fn test_rate_limiter_blocks_over_limit() {
let limiter = LoginRateLimiter::new();
let ip: IpAddr = "127.0.0.1".parse().unwrap();
for _ in 0..MAX_ATTEMPTS {
limiter.record_failure(ip).await;
}
assert!(!limiter.check(ip).await);
}
#[tokio::test]
async fn test_rate_limiter_different_ips() {
let limiter = LoginRateLimiter::new();
let ip1: IpAddr = "127.0.0.1".parse().unwrap();
let ip2: IpAddr = "192.168.1.1".parse().unwrap();
for _ in 0..MAX_ATTEMPTS {
limiter.record_failure(ip1).await;
}
// ip1 should be blocked
assert!(!limiter.check(ip1).await);
// ip2 should still be allowed
assert!(limiter.check(ip2).await);
}
}