diff options
| author | Dawid Rycerz <dawid@rycerz.xyz> | 2026-01-22 22:07:32 +0100 |
|---|---|---|
| committer | Dawid Rycerz <dawid@rycerz.xyz> | 2026-02-10 18:44:26 +0100 |
| commit | 064a1d01c5c14f5ecc032fa9b8346a4a88b893f6 (patch) | |
| tree | a2023f9ccd297ed8a41a3a0cc5699c2add09244d /tests/integration/rate_limit.rs | |
witryna 0.1.0 — initial releasev0.1.0
Minimalist Git-based static site deployment orchestrator.
Webhook-triggered builds in Podman/Docker containers with atomic
symlink publishing, SIGHUP hot-reload, and zero-downtime deploys.
See README.md for usage, CHANGELOG.md for details.
Diffstat (limited to 'tests/integration/rate_limit.rs')
| -rw-r--r-- | tests/integration/rate_limit.rs | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/tests/integration/rate_limit.rs b/tests/integration/rate_limit.rs new file mode 100644 index 0000000..81378a2 --- /dev/null +++ b/tests/integration/rate_limit.rs @@ -0,0 +1,114 @@ +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); +} |
