this repo has no description
1mod common;
2
3use common::{base_url, client};
4use reqwest::StatusCode;
5use serde_json::json;
6
7#[tokio::test]
8#[ignore = "rate limiting is disabled in test environment"]
9async fn test_login_rate_limiting() {
10 let client = client();
11 let url = format!("{}/xrpc/com.atproto.server.createSession", base_url().await);
12
13 let payload = json!({
14 "identifier": "nonexistent_user_for_rate_limit_test",
15 "password": "wrongpassword"
16 });
17
18 let mut rate_limited_count = 0;
19 let mut auth_failed_count = 0;
20
21 for _ in 0..15 {
22 let res = client
23 .post(&url)
24 .json(&payload)
25 .send()
26 .await
27 .expect("Request failed");
28
29 match res.status() {
30 StatusCode::TOO_MANY_REQUESTS => {
31 rate_limited_count += 1;
32 }
33 StatusCode::UNAUTHORIZED => {
34 auth_failed_count += 1;
35 }
36 status => {
37 panic!("Unexpected status: {}", status);
38 }
39 }
40 }
41
42 assert!(
43 rate_limited_count > 0,
44 "Expected at least one rate-limited response after 15 login attempts. Got {} auth failures and {} rate limits.",
45 auth_failed_count,
46 rate_limited_count
47 );
48}
49
50#[tokio::test]
51#[ignore = "rate limiting is disabled in test environment"]
52async fn test_password_reset_rate_limiting() {
53 let client = client();
54 let url = format!(
55 "{}/xrpc/com.atproto.server.requestPasswordReset",
56 base_url().await
57 );
58
59 let mut rate_limited_count = 0;
60 let mut success_count = 0;
61
62 for i in 0..8 {
63 let payload = json!({
64 "email": format!("ratelimit_test_{}@example.com", i)
65 });
66
67 let res = client
68 .post(&url)
69 .json(&payload)
70 .send()
71 .await
72 .expect("Request failed");
73
74 match res.status() {
75 StatusCode::TOO_MANY_REQUESTS => {
76 rate_limited_count += 1;
77 }
78 StatusCode::OK => {
79 success_count += 1;
80 }
81 status => {
82 panic!("Unexpected status: {} - {:?}", status, res.text().await);
83 }
84 }
85 }
86
87 assert!(
88 rate_limited_count > 0,
89 "Expected rate limiting after {} password reset requests. Got {} successes.",
90 success_count + rate_limited_count,
91 success_count
92 );
93}
94
95#[tokio::test]
96#[ignore = "rate limiting is disabled in test environment"]
97async fn test_account_creation_rate_limiting() {
98 let client = client();
99 let url = format!(
100 "{}/xrpc/com.atproto.server.createAccount",
101 base_url().await
102 );
103
104 let mut rate_limited_count = 0;
105 let mut other_count = 0;
106
107 for i in 0..15 {
108 let unique_id = uuid::Uuid::new_v4();
109 let payload = json!({
110 "handle": format!("ratelimit_{}_{}", i, unique_id),
111 "email": format!("ratelimit_{}_{}@example.com", i, unique_id),
112 "password": "testpassword123"
113 });
114
115 let res = client
116 .post(&url)
117 .json(&payload)
118 .send()
119 .await
120 .expect("Request failed");
121
122 match res.status() {
123 StatusCode::TOO_MANY_REQUESTS => {
124 rate_limited_count += 1;
125 }
126 _ => {
127 other_count += 1;
128 }
129 }
130 }
131
132 assert!(
133 rate_limited_count > 0,
134 "Expected rate limiting after account creation attempts. Got {} other responses and {} rate limits.",
135 other_count,
136 rate_limited_count
137 );
138}
139
140#[tokio::test]
141async fn test_valkey_connection() {
142 if std::env::var("VALKEY_URL").is_err() {
143 println!("VALKEY_URL not set, skipping Valkey connection test");
144 return;
145 }
146
147 let valkey_url = std::env::var("VALKEY_URL").unwrap();
148 let client = redis::Client::open(valkey_url.as_str()).expect("Failed to create Redis client");
149 let mut conn = client
150 .get_multiplexed_async_connection()
151 .await
152 .expect("Failed to connect to Valkey");
153
154 let pong: String = redis::cmd("PING")
155 .query_async(&mut conn)
156 .await
157 .expect("PING failed");
158 assert_eq!(pong, "PONG");
159
160 let _: () = redis::cmd("SET")
161 .arg("test_key")
162 .arg("test_value")
163 .arg("EX")
164 .arg(10)
165 .query_async(&mut conn)
166 .await
167 .expect("SET failed");
168
169 let value: String = redis::cmd("GET")
170 .arg("test_key")
171 .query_async(&mut conn)
172 .await
173 .expect("GET failed");
174 assert_eq!(value, "test_value");
175
176 let _: () = redis::cmd("DEL")
177 .arg("test_key")
178 .query_async(&mut conn)
179 .await
180 .expect("DEL failed");
181}
182
183#[tokio::test]
184async fn test_distributed_rate_limiter_directly() {
185 if std::env::var("VALKEY_URL").is_err() {
186 println!("VALKEY_URL not set, skipping distributed rate limiter test");
187 return;
188 }
189
190 use bspds::cache::{DistributedRateLimiter, RedisRateLimiter};
191
192 let valkey_url = std::env::var("VALKEY_URL").unwrap();
193 let client = redis::Client::open(valkey_url.as_str()).expect("Failed to create Redis client");
194 let conn = client
195 .get_connection_manager()
196 .await
197 .expect("Failed to get connection manager");
198
199 let rate_limiter = RedisRateLimiter::new(conn);
200
201 let test_key = format!("test_rate_limit_{}", uuid::Uuid::new_v4());
202 let limit = 5;
203 let window_ms = 60_000;
204
205 for i in 0..limit {
206 let allowed = rate_limiter
207 .check_rate_limit(&test_key, limit, window_ms)
208 .await;
209 assert!(
210 allowed,
211 "Request {} should have been allowed (limit: {})",
212 i + 1,
213 limit
214 );
215 }
216
217 let allowed = rate_limiter
218 .check_rate_limit(&test_key, limit, window_ms)
219 .await;
220 assert!(
221 !allowed,
222 "Request {} should have been rate limited (limit: {})",
223 limit + 1,
224 limit
225 );
226
227 let allowed = rate_limiter
228 .check_rate_limit(&test_key, limit, window_ms)
229 .await;
230 assert!(!allowed, "Subsequent request should also be rate limited");
231}