use crate::harness::{SiteBuilder, TestServer, test_config_with_site, test_config_with_sites}; #[tokio::test] async fn rate_limit_exceeded_returns_429() { let dir = tempfile::tempdir().unwrap().keep(); let site = SiteBuilder::new("my-site", "https://example.com/repo.git", "secret-token").build(); let config = test_config_with_site(dir, site); // Rate limit of 2 per minute let server = TestServer::start_with_rate_limit(config, 2).await; // First request — accepted (or 202) let resp1 = TestServer::client() .post(server.url("/my-site")) .header("Authorization", "Bearer secret-token") .send() .await .unwrap(); let status1 = resp1.status().as_u16(); assert!( status1 == 202 || status1 == 409, "expected 202 or 409, got {status1}" ); // Second request let resp2 = TestServer::client() .post(server.url("/my-site")) .header("Authorization", "Bearer secret-token") .send() .await .unwrap(); let status2 = resp2.status().as_u16(); assert!( status2 == 202 || status2 == 409, "expected 202 or 409, got {status2}" ); // Third request should hit rate limit let resp3 = TestServer::client() .post(server.url("/my-site")) .header("Authorization", "Bearer secret-token") .send() .await .unwrap(); assert_eq!(resp3.status().as_u16(), 429); let body = resp3.text().await.unwrap(); let json: serde_json::Value = serde_json::from_str(&body).unwrap(); assert_eq!(json["error"], "rate_limit_exceeded"); } #[tokio::test] async fn rate_limit_different_tokens_independent() { let dir = tempfile::tempdir().unwrap().keep(); let sites = vec![ SiteBuilder::new("site-one", "https://example.com/one.git", "token-one").build(), SiteBuilder::new("site-two", "https://example.com/two.git", "token-two").build(), ]; let config = test_config_with_sites(dir, sites); // Rate limit of 1 per minute let server = TestServer::start_with_rate_limit(config, 1).await; // token-one: first request succeeds let resp1 = TestServer::client() .post(server.url("/site-one")) .header("Authorization", "Bearer token-one") .send() .await .unwrap(); assert_eq!(resp1.status().as_u16(), 202); // token-one: second request hits rate limit let resp2 = TestServer::client() .post(server.url("/site-one")) .header("Authorization", "Bearer token-one") .send() .await .unwrap(); assert_eq!(resp2.status().as_u16(), 429); // token-two: still has its own budget let resp3 = TestServer::client() .post(server.url("/site-two")) .header("Authorization", "Bearer token-two") .send() .await .unwrap(); assert_eq!(resp3.status().as_u16(), 202); } #[tokio::test] async fn rate_limit_checked_after_auth() { let dir = tempfile::tempdir().unwrap().keep(); let site = SiteBuilder::new("my-site", "https://example.com/repo.git", "secret-token").build(); let config = test_config_with_site(dir, site); let server = TestServer::start_with_rate_limit(config, 1).await; // Exhaust rate limit let _ = TestServer::client() .post(server.url("/my-site")) .header("Authorization", "Bearer secret-token") .send() .await .unwrap(); // Wrong token should get 401, not 429 let resp = TestServer::client() .post(server.url("/my-site")) .header("Authorization", "Bearer wrong-token") .send() .await .unwrap(); assert_eq!(resp.status().as_u16(), 401); }