forked from
lewis.moe/bspds-sandbox
PDS software with bells & whistles you didn’t even know you needed. will move this to its own account when ready.
1mod common;
2use common::*;
3use reqwest::StatusCode;
4use serde_json::{Value, json};
5
6#[tokio::test]
7async fn test_create_invite_code_success() {
8 let client = client();
9 let (access_jwt, _did) = create_admin_account_and_login(&client).await;
10 let payload = json!({
11 "useCount": 5
12 });
13 let res = client
14 .post(format!(
15 "{}/xrpc/com.atproto.server.createInviteCode",
16 base_url().await
17 ))
18 .bearer_auth(&access_jwt)
19 .json(&payload)
20 .send()
21 .await
22 .expect("Failed to send request");
23 assert_eq!(res.status(), StatusCode::OK);
24 let body: Value = res.json().await.expect("Response was not valid JSON");
25 assert!(body["code"].is_string());
26 let code = body["code"].as_str().unwrap();
27 assert!(!code.is_empty());
28 assert!(
29 code.contains('-'),
30 "Code should be in hostname-xxxxx-xxxxx format"
31 );
32 let parts: Vec<&str> = code.split('-').collect();
33 assert!(
34 parts.len() >= 3,
35 "Code should have at least 3 parts (hostname + 2 random parts)"
36 );
37}
38
39#[tokio::test]
40async fn test_create_invite_code_no_auth() {
41 let client = client();
42 let payload = json!({
43 "useCount": 5
44 });
45 let res = client
46 .post(format!(
47 "{}/xrpc/com.atproto.server.createInviteCode",
48 base_url().await
49 ))
50 .json(&payload)
51 .send()
52 .await
53 .expect("Failed to send request");
54 assert_eq!(res.status(), StatusCode::UNAUTHORIZED);
55 let body: Value = res.json().await.expect("Response was not valid JSON");
56 assert_eq!(body["error"], "AuthenticationRequired");
57}
58
59#[tokio::test]
60async fn test_create_invite_code_non_admin() {
61 let client = client();
62 let _ = create_admin_account_and_login(&client).await;
63 let (access_jwt, _did) = create_account_and_login(&client).await;
64 let payload = json!({
65 "useCount": 5
66 });
67 let res = client
68 .post(format!(
69 "{}/xrpc/com.atproto.server.createInviteCode",
70 base_url().await
71 ))
72 .bearer_auth(&access_jwt)
73 .json(&payload)
74 .send()
75 .await
76 .expect("Failed to send request");
77 assert_eq!(res.status(), StatusCode::FORBIDDEN);
78 let body: Value = res.json().await.expect("Response was not valid JSON");
79 assert_eq!(body["error"], "AdminRequired");
80}
81
82#[tokio::test]
83async fn test_create_invite_code_invalid_use_count() {
84 let client = client();
85 let (access_jwt, _did) = create_admin_account_and_login(&client).await;
86 let payload = json!({
87 "useCount": 0
88 });
89 let res = client
90 .post(format!(
91 "{}/xrpc/com.atproto.server.createInviteCode",
92 base_url().await
93 ))
94 .bearer_auth(&access_jwt)
95 .json(&payload)
96 .send()
97 .await
98 .expect("Failed to send request");
99 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
100 let body: Value = res.json().await.expect("Response was not valid JSON");
101 assert_eq!(body["error"], "InvalidRequest");
102}
103
104#[tokio::test]
105async fn test_create_invite_code_for_another_account() {
106 let client = client();
107 let (access_jwt1, _did1) = create_admin_account_and_login(&client).await;
108 let (_access_jwt2, did2) = create_account_and_login(&client).await;
109 let payload = json!({
110 "useCount": 3,
111 "forAccount": did2
112 });
113 let res = client
114 .post(format!(
115 "{}/xrpc/com.atproto.server.createInviteCode",
116 base_url().await
117 ))
118 .bearer_auth(&access_jwt1)
119 .json(&payload)
120 .send()
121 .await
122 .expect("Failed to send request");
123 assert_eq!(res.status(), StatusCode::OK);
124 let body: Value = res.json().await.expect("Response was not valid JSON");
125 assert!(body["code"].is_string());
126}
127
128#[tokio::test]
129async fn test_create_invite_codes_success() {
130 let client = client();
131 let (access_jwt, did) = create_admin_account_and_login(&client).await;
132 let payload = json!({
133 "useCount": 2,
134 "codeCount": 3
135 });
136 let res = client
137 .post(format!(
138 "{}/xrpc/com.atproto.server.createInviteCodes",
139 base_url().await
140 ))
141 .bearer_auth(&access_jwt)
142 .json(&payload)
143 .send()
144 .await
145 .expect("Failed to send request");
146 assert_eq!(res.status(), StatusCode::OK);
147 let body: Value = res.json().await.expect("Response was not valid JSON");
148 assert!(body["codes"].is_array());
149 let codes = body["codes"].as_array().unwrap();
150 assert_eq!(codes.len(), 1);
151 assert_eq!(codes[0]["account"], did);
152 assert_eq!(codes[0]["codes"].as_array().unwrap().len(), 3);
153}
154
155#[tokio::test]
156async fn test_create_invite_codes_for_multiple_accounts() {
157 let client = client();
158 let (access_jwt1, did1) = create_admin_account_and_login(&client).await;
159 let (_access_jwt2, did2) = create_account_and_login(&client).await;
160 let payload = json!({
161 "useCount": 1,
162 "codeCount": 2,
163 "forAccounts": [did1, did2]
164 });
165 let res = client
166 .post(format!(
167 "{}/xrpc/com.atproto.server.createInviteCodes",
168 base_url().await
169 ))
170 .bearer_auth(&access_jwt1)
171 .json(&payload)
172 .send()
173 .await
174 .expect("Failed to send request");
175 assert_eq!(res.status(), StatusCode::OK);
176 let body: Value = res.json().await.expect("Response was not valid JSON");
177 let codes = body["codes"].as_array().unwrap();
178 assert_eq!(codes.len(), 2);
179 for code_obj in codes {
180 assert!(code_obj["account"].is_string());
181 assert_eq!(code_obj["codes"].as_array().unwrap().len(), 2);
182 }
183}
184
185#[tokio::test]
186async fn test_create_invite_codes_no_auth() {
187 let client = client();
188 let payload = json!({
189 "useCount": 2
190 });
191 let res = client
192 .post(format!(
193 "{}/xrpc/com.atproto.server.createInviteCodes",
194 base_url().await
195 ))
196 .json(&payload)
197 .send()
198 .await
199 .expect("Failed to send request");
200 assert_eq!(res.status(), StatusCode::UNAUTHORIZED);
201}
202
203#[tokio::test]
204async fn test_create_invite_codes_non_admin() {
205 let client = client();
206 let (access_jwt, _did) = create_account_and_login(&client).await;
207 let payload = json!({
208 "useCount": 2
209 });
210 let res = client
211 .post(format!(
212 "{}/xrpc/com.atproto.server.createInviteCodes",
213 base_url().await
214 ))
215 .bearer_auth(&access_jwt)
216 .json(&payload)
217 .send()
218 .await
219 .expect("Failed to send request");
220 assert_eq!(res.status(), StatusCode::FORBIDDEN);
221 let body: Value = res.json().await.expect("Response was not valid JSON");
222 assert_eq!(body["error"], "AdminRequired");
223}
224
225#[tokio::test]
226async fn test_get_account_invite_codes_success() {
227 let client = client();
228 let (admin_jwt, _admin_did) = create_admin_account_and_login(&client).await;
229 let (user_jwt, user_did) = create_account_and_login(&client).await;
230
231 let create_payload = json!({
232 "useCount": 5,
233 "forAccount": user_did
234 });
235 let _ = client
236 .post(format!(
237 "{}/xrpc/com.atproto.server.createInviteCode",
238 base_url().await
239 ))
240 .bearer_auth(&admin_jwt)
241 .json(&create_payload)
242 .send()
243 .await
244 .expect("Failed to create invite code");
245
246 let res = client
247 .get(format!(
248 "{}/xrpc/com.atproto.server.getAccountInviteCodes",
249 base_url().await
250 ))
251 .bearer_auth(&user_jwt)
252 .send()
253 .await
254 .expect("Failed to send request");
255 assert_eq!(res.status(), StatusCode::OK);
256 let body: Value = res.json().await.expect("Response was not valid JSON");
257 assert!(body["codes"].is_array());
258 let codes = body["codes"].as_array().unwrap();
259 assert!(!codes.is_empty());
260 let code = &codes[0];
261 assert!(code["code"].is_string());
262 assert!(code["available"].is_number());
263 assert!(code["disabled"].is_boolean());
264 assert!(code["createdAt"].is_string());
265 assert!(code["uses"].is_array());
266 assert_eq!(code["forAccount"], user_did);
267 assert_eq!(code["createdBy"], "admin");
268}
269
270#[tokio::test]
271async fn test_get_account_invite_codes_no_auth() {
272 let client = client();
273 let res = client
274 .get(format!(
275 "{}/xrpc/com.atproto.server.getAccountInviteCodes",
276 base_url().await
277 ))
278 .send()
279 .await
280 .expect("Failed to send request");
281 assert_eq!(res.status(), StatusCode::UNAUTHORIZED);
282}
283
284#[tokio::test]
285async fn test_get_account_invite_codes_include_used_filter() {
286 let client = client();
287 let (admin_jwt, _admin_did) = create_admin_account_and_login(&client).await;
288 let (user_jwt, user_did) = create_account_and_login(&client).await;
289
290 let create_payload = json!({
291 "useCount": 5,
292 "forAccount": user_did
293 });
294 let _ = client
295 .post(format!(
296 "{}/xrpc/com.atproto.server.createInviteCode",
297 base_url().await
298 ))
299 .bearer_auth(&admin_jwt)
300 .json(&create_payload)
301 .send()
302 .await
303 .expect("Failed to create invite code");
304
305 let res = client
306 .get(format!(
307 "{}/xrpc/com.atproto.server.getAccountInviteCodes",
308 base_url().await
309 ))
310 .bearer_auth(&user_jwt)
311 .query(&[("includeUsed", "false")])
312 .send()
313 .await
314 .expect("Failed to send request");
315 assert_eq!(res.status(), StatusCode::OK);
316 let body: Value = res.json().await.expect("Response was not valid JSON");
317 assert!(body["codes"].is_array());
318 for code in body["codes"].as_array().unwrap() {
319 assert!(code["available"].as_i64().unwrap() > 0);
320 }
321}
322
323#[tokio::test]
324async fn test_get_account_invite_codes_filters_disabled() {
325 let client = client();
326 let (admin_jwt, admin_did) = create_admin_account_and_login(&client).await;
327
328 let create_payload = json!({
329 "useCount": 5,
330 "forAccount": admin_did
331 });
332 let create_res = client
333 .post(format!(
334 "{}/xrpc/com.atproto.server.createInviteCode",
335 base_url().await
336 ))
337 .bearer_auth(&admin_jwt)
338 .json(&create_payload)
339 .send()
340 .await
341 .expect("Failed to create invite code");
342 let create_body: Value = create_res.json().await.unwrap();
343 let code = create_body["code"].as_str().unwrap();
344
345 let disable_payload = json!({
346 "codes": [code]
347 });
348 let _ = client
349 .post(format!(
350 "{}/xrpc/com.atproto.admin.disableInviteCodes",
351 base_url().await
352 ))
353 .bearer_auth(&admin_jwt)
354 .json(&disable_payload)
355 .send()
356 .await
357 .expect("Failed to disable invite code");
358
359 let res = client
360 .get(format!(
361 "{}/xrpc/com.atproto.server.getAccountInviteCodes",
362 base_url().await
363 ))
364 .bearer_auth(&admin_jwt)
365 .send()
366 .await
367 .expect("Failed to send request");
368 assert_eq!(res.status(), StatusCode::OK);
369 let body: Value = res.json().await.expect("Response was not valid JSON");
370 let codes = body["codes"].as_array().unwrap();
371 for c in codes {
372 assert_ne!(
373 c["code"].as_str().unwrap(),
374 code,
375 "Disabled code should be filtered out"
376 );
377 }
378}