this repo has no description
1mod common;
2mod helpers;
3
4use common::*;
5use reqwest::{StatusCode, header};
6use serde_json::{Value, json};
7
8#[tokio::test]
9async fn test_list_backups_empty() {
10 let client = client();
11 let (token, _did) = create_account_and_login(&client).await;
12
13 let res = client
14 .get(format!("{}/xrpc/_backup.listBackups", base_url().await))
15 .bearer_auth(&token)
16 .send()
17 .await
18 .expect("listBackups request failed");
19
20 assert_eq!(res.status(), StatusCode::OK);
21 let body: Value = res.json().await.expect("Invalid JSON");
22 assert!(body["backups"].is_array());
23 assert_eq!(body["backups"].as_array().unwrap().len(), 0);
24 assert!(body["backupEnabled"].as_bool().unwrap_or(false));
25}
26
27#[tokio::test]
28async fn test_create_and_list_backup() {
29 let client = client();
30 let (token, _did) = create_account_and_login(&client).await;
31
32 let create_res = client
33 .post(format!("{}/xrpc/_backup.createBackup", base_url().await))
34 .bearer_auth(&token)
35 .send()
36 .await
37 .expect("createBackup request failed");
38
39 assert_eq!(create_res.status(), StatusCode::OK, "createBackup failed");
40 let create_body: Value = create_res.json().await.expect("Invalid JSON");
41 assert!(create_body["id"].is_string());
42 assert!(create_body["repoRev"].is_string());
43 assert!(create_body["sizeBytes"].is_i64());
44 assert!(create_body["blockCount"].is_i64());
45
46 let list_res = client
47 .get(format!("{}/xrpc/_backup.listBackups", base_url().await))
48 .bearer_auth(&token)
49 .send()
50 .await
51 .expect("listBackups request failed");
52
53 assert_eq!(list_res.status(), StatusCode::OK);
54 let list_body: Value = list_res.json().await.expect("Invalid JSON");
55 let backups = list_body["backups"].as_array().unwrap();
56 assert!(!backups.is_empty());
57}
58
59#[tokio::test]
60async fn test_download_backup() {
61 let client = client();
62 let (token, _did) = create_account_and_login(&client).await;
63
64 let create_res = client
65 .post(format!("{}/xrpc/_backup.createBackup", base_url().await))
66 .bearer_auth(&token)
67 .send()
68 .await
69 .expect("createBackup request failed");
70
71 assert_eq!(create_res.status(), StatusCode::OK);
72 let create_body: Value = create_res.json().await.expect("Invalid JSON");
73 let backup_id = create_body["id"].as_str().unwrap();
74
75 let get_res = client
76 .get(format!(
77 "{}/xrpc/_backup.getBackup?id={}",
78 base_url().await,
79 backup_id
80 ))
81 .bearer_auth(&token)
82 .send()
83 .await
84 .expect("getBackup request failed");
85
86 assert_eq!(get_res.status(), StatusCode::OK);
87 let content_type = get_res.headers().get(header::CONTENT_TYPE).unwrap();
88 assert_eq!(content_type, "application/vnd.ipld.car");
89
90 let bytes = get_res.bytes().await.expect("Failed to read body");
91 assert!(bytes.len() > 100, "CAR file should have content");
92 assert_eq!(
93 bytes[1], 0xa2,
94 "CAR file should have valid header structure"
95 );
96}
97
98#[tokio::test]
99async fn test_delete_backup() {
100 let client = client();
101 let (token, _did) = create_account_and_login(&client).await;
102
103 let create_res = client
104 .post(format!("{}/xrpc/_backup.createBackup", base_url().await))
105 .bearer_auth(&token)
106 .send()
107 .await
108 .expect("createBackup request failed");
109
110 assert_eq!(create_res.status(), StatusCode::OK);
111 let create_body: Value = create_res.json().await.expect("Invalid JSON");
112 let backup_id = create_body["id"].as_str().unwrap();
113
114 let delete_res = client
115 .post(format!(
116 "{}/xrpc/_backup.deleteBackup?id={}",
117 base_url().await,
118 backup_id
119 ))
120 .bearer_auth(&token)
121 .send()
122 .await
123 .expect("deleteBackup request failed");
124
125 assert_eq!(delete_res.status(), StatusCode::OK);
126
127 let get_res = client
128 .get(format!(
129 "{}/xrpc/_backup.getBackup?id={}",
130 base_url().await,
131 backup_id
132 ))
133 .bearer_auth(&token)
134 .send()
135 .await
136 .expect("getBackup request failed");
137
138 assert_eq!(get_res.status(), StatusCode::NOT_FOUND);
139}
140
141#[tokio::test]
142async fn test_toggle_backup_enabled() {
143 let client = client();
144 let (token, _did) = create_account_and_login(&client).await;
145
146 let list_res = client
147 .get(format!("{}/xrpc/_backup.listBackups", base_url().await))
148 .bearer_auth(&token)
149 .send()
150 .await
151 .expect("listBackups request failed");
152
153 assert_eq!(list_res.status(), StatusCode::OK);
154 let list_body: Value = list_res.json().await.expect("Invalid JSON");
155 assert!(list_body["backupEnabled"].as_bool().unwrap());
156
157 let disable_res = client
158 .post(format!("{}/xrpc/_backup.setEnabled", base_url().await))
159 .bearer_auth(&token)
160 .json(&json!({"enabled": false}))
161 .send()
162 .await
163 .expect("setEnabled request failed");
164
165 assert_eq!(disable_res.status(), StatusCode::OK);
166 let disable_body: Value = disable_res.json().await.expect("Invalid JSON");
167 assert!(!disable_body["enabled"].as_bool().unwrap());
168
169 let list_res2 = client
170 .get(format!("{}/xrpc/_backup.listBackups", base_url().await))
171 .bearer_auth(&token)
172 .send()
173 .await
174 .expect("listBackups request failed");
175
176 let list_body2: Value = list_res2.json().await.expect("Invalid JSON");
177 assert!(!list_body2["backupEnabled"].as_bool().unwrap());
178
179 let enable_res = client
180 .post(format!("{}/xrpc/_backup.setEnabled", base_url().await))
181 .bearer_auth(&token)
182 .json(&json!({"enabled": true}))
183 .send()
184 .await
185 .expect("setEnabled request failed");
186
187 assert_eq!(enable_res.status(), StatusCode::OK);
188}
189
190#[tokio::test]
191async fn test_backup_includes_blobs() {
192 let client = client();
193 let (token, did) = create_account_and_login(&client).await;
194
195 let blob_data = b"Hello, this is test blob data for backup testing!";
196 let upload_res = client
197 .post(format!(
198 "{}/xrpc/com.atproto.repo.uploadBlob",
199 base_url().await
200 ))
201 .header(header::CONTENT_TYPE, "text/plain")
202 .bearer_auth(&token)
203 .body(blob_data.to_vec())
204 .send()
205 .await
206 .expect("uploadBlob request failed");
207
208 assert_eq!(upload_res.status(), StatusCode::OK);
209 let upload_body: Value = upload_res.json().await.expect("Invalid JSON");
210 let blob = &upload_body["blob"];
211
212 let record = json!({
213 "$type": "app.bsky.feed.post",
214 "text": "Test post with blob",
215 "createdAt": chrono::Utc::now().to_rfc3339(),
216 "embed": {
217 "$type": "app.bsky.embed.images",
218 "images": [{
219 "alt": "test image",
220 "image": blob
221 }]
222 }
223 });
224
225 let create_record_res = client
226 .post(format!(
227 "{}/xrpc/com.atproto.repo.createRecord",
228 base_url().await
229 ))
230 .bearer_auth(&token)
231 .json(&json!({
232 "repo": did,
233 "collection": "app.bsky.feed.post",
234 "record": record
235 }))
236 .send()
237 .await
238 .expect("createRecord request failed");
239
240 assert_eq!(create_record_res.status(), StatusCode::OK);
241
242 let create_backup_res = client
243 .post(format!("{}/xrpc/_backup.createBackup", base_url().await))
244 .bearer_auth(&token)
245 .send()
246 .await
247 .expect("createBackup request failed");
248
249 assert_eq!(create_backup_res.status(), StatusCode::OK);
250 let backup_body: Value = create_backup_res.json().await.expect("Invalid JSON");
251 let backup_id = backup_body["id"].as_str().unwrap();
252
253 let get_backup_res = client
254 .get(format!(
255 "{}/xrpc/_backup.getBackup?id={}",
256 base_url().await,
257 backup_id
258 ))
259 .bearer_auth(&token)
260 .send()
261 .await
262 .expect("getBackup request failed");
263
264 assert_eq!(get_backup_res.status(), StatusCode::OK);
265 let car_bytes = get_backup_res.bytes().await.expect("Failed to read body");
266
267 let blob_cid = blob["ref"]["$link"].as_str().unwrap();
268 let blob_found = String::from_utf8_lossy(&car_bytes).contains("Hello, this is test blob data");
269 assert!(
270 blob_found || car_bytes.len() > 500,
271 "Backup should contain blob data (cid: {})",
272 blob_cid
273 );
274}
275
276#[tokio::test]
277async fn test_backup_unauthorized() {
278 let client = client();
279
280 let res = client
281 .get(format!("{}/xrpc/_backup.listBackups", base_url().await))
282 .send()
283 .await
284 .expect("listBackups request failed");
285
286 assert_eq!(res.status(), StatusCode::UNAUTHORIZED);
287}
288
289#[tokio::test]
290async fn test_get_nonexistent_backup() {
291 let client = client();
292 let (token, _did) = create_account_and_login(&client).await;
293
294 let fake_id = uuid::Uuid::new_v4();
295 let res = client
296 .get(format!(
297 "{}/xrpc/_backup.getBackup?id={}",
298 base_url().await,
299 fake_id
300 ))
301 .bearer_auth(&token)
302 .send()
303 .await
304 .expect("getBackup request failed");
305
306 assert_eq!(res.status(), StatusCode::NOT_FOUND);
307}
308
309#[tokio::test]
310async fn test_backup_invalid_id() {
311 let client = client();
312 let (token, _did) = create_account_and_login(&client).await;
313
314 let res = client
315 .get(format!(
316 "{}/xrpc/_backup.getBackup?id=not-a-uuid",
317 base_url().await
318 ))
319 .bearer_auth(&token)
320 .send()
321 .await
322 .expect("getBackup request failed");
323
324 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
325}