this repo has no description
1mod common; 2use common::*; 3 4use chrono::Utc; 5use reqwest::StatusCode; 6use serde_json::{Value, json}; 7 8#[tokio::test] 9async fn test_apply_writes_create() { 10 let client = client(); 11 let (token, did) = create_account_and_login(&client).await; 12 let now = Utc::now().to_rfc3339(); 13 14 let payload = json!({ 15 "repo": did, 16 "writes": [ 17 { 18 "$type": "com.atproto.repo.applyWrites#create", 19 "collection": "app.bsky.feed.post", 20 "value": { 21 "$type": "app.bsky.feed.post", 22 "text": "Batch created post 1", 23 "createdAt": now 24 } 25 }, 26 { 27 "$type": "com.atproto.repo.applyWrites#create", 28 "collection": "app.bsky.feed.post", 29 "value": { 30 "$type": "app.bsky.feed.post", 31 "text": "Batch created post 2", 32 "createdAt": now 33 } 34 } 35 ] 36 }); 37 38 let res = client 39 .post(format!( 40 "{}/xrpc/com.atproto.repo.applyWrites", 41 base_url().await 42 )) 43 .bearer_auth(&token) 44 .json(&payload) 45 .send() 46 .await 47 .expect("Failed to send request"); 48 49 assert_eq!(res.status(), StatusCode::OK); 50 let body: Value = res.json().await.expect("Response was not valid JSON"); 51 assert!(body["commit"]["cid"].is_string()); 52 assert!(body["results"].is_array()); 53 let results = body["results"].as_array().unwrap(); 54 assert_eq!(results.len(), 2); 55 assert!(results[0]["uri"].is_string()); 56 assert!(results[0]["cid"].is_string()); 57} 58 59#[tokio::test] 60async fn test_apply_writes_update() { 61 let client = client(); 62 let (token, did) = create_account_and_login(&client).await; 63 let now = Utc::now().to_rfc3339(); 64 let rkey = format!("batch_update_{}", Utc::now().timestamp_millis()); 65 66 let create_payload = json!({ 67 "repo": did, 68 "collection": "app.bsky.feed.post", 69 "rkey": rkey, 70 "record": { 71 "$type": "app.bsky.feed.post", 72 "text": "Original post", 73 "createdAt": now 74 } 75 }); 76 let res = client 77 .post(format!( 78 "{}/xrpc/com.atproto.repo.putRecord", 79 base_url().await 80 )) 81 .bearer_auth(&token) 82 .json(&create_payload) 83 .send() 84 .await 85 .expect("Failed to create"); 86 assert_eq!(res.status(), StatusCode::OK); 87 88 let update_payload = json!({ 89 "repo": did, 90 "writes": [ 91 { 92 "$type": "com.atproto.repo.applyWrites#update", 93 "collection": "app.bsky.feed.post", 94 "rkey": rkey, 95 "value": { 96 "$type": "app.bsky.feed.post", 97 "text": "Updated post via applyWrites", 98 "createdAt": now 99 } 100 } 101 ] 102 }); 103 104 let res = client 105 .post(format!( 106 "{}/xrpc/com.atproto.repo.applyWrites", 107 base_url().await 108 )) 109 .bearer_auth(&token) 110 .json(&update_payload) 111 .send() 112 .await 113 .expect("Failed to send request"); 114 115 assert_eq!(res.status(), StatusCode::OK); 116 let body: Value = res.json().await.expect("Response was not valid JSON"); 117 let results = body["results"].as_array().unwrap(); 118 assert_eq!(results.len(), 1); 119 assert!(results[0]["uri"].is_string()); 120} 121 122#[tokio::test] 123async fn test_apply_writes_delete() { 124 let client = client(); 125 let (token, did) = create_account_and_login(&client).await; 126 let now = Utc::now().to_rfc3339(); 127 let rkey = format!("batch_delete_{}", Utc::now().timestamp_millis()); 128 129 let create_payload = json!({ 130 "repo": did, 131 "collection": "app.bsky.feed.post", 132 "rkey": rkey, 133 "record": { 134 "$type": "app.bsky.feed.post", 135 "text": "Post to delete", 136 "createdAt": now 137 } 138 }); 139 let res = client 140 .post(format!( 141 "{}/xrpc/com.atproto.repo.putRecord", 142 base_url().await 143 )) 144 .bearer_auth(&token) 145 .json(&create_payload) 146 .send() 147 .await 148 .expect("Failed to create"); 149 assert_eq!(res.status(), StatusCode::OK); 150 151 let delete_payload = json!({ 152 "repo": did, 153 "writes": [ 154 { 155 "$type": "com.atproto.repo.applyWrites#delete", 156 "collection": "app.bsky.feed.post", 157 "rkey": rkey 158 } 159 ] 160 }); 161 162 let res = client 163 .post(format!( 164 "{}/xrpc/com.atproto.repo.applyWrites", 165 base_url().await 166 )) 167 .bearer_auth(&token) 168 .json(&delete_payload) 169 .send() 170 .await 171 .expect("Failed to send request"); 172 173 assert_eq!(res.status(), StatusCode::OK); 174 175 let get_res = client 176 .get(format!( 177 "{}/xrpc/com.atproto.repo.getRecord", 178 base_url().await 179 )) 180 .query(&[ 181 ("repo", did.as_str()), 182 ("collection", "app.bsky.feed.post"), 183 ("rkey", rkey.as_str()), 184 ]) 185 .send() 186 .await 187 .expect("Failed to verify"); 188 assert_eq!(get_res.status(), StatusCode::NOT_FOUND); 189} 190 191#[tokio::test] 192async fn test_apply_writes_mixed_operations() { 193 let client = client(); 194 let (token, did) = create_account_and_login(&client).await; 195 let now = Utc::now().to_rfc3339(); 196 let rkey_to_delete = format!("mixed_del_{}", Utc::now().timestamp_millis()); 197 let rkey_to_update = format!("mixed_upd_{}", Utc::now().timestamp_millis()); 198 199 let setup_payload = json!({ 200 "repo": did, 201 "writes": [ 202 { 203 "$type": "com.atproto.repo.applyWrites#create", 204 "collection": "app.bsky.feed.post", 205 "rkey": rkey_to_delete, 206 "value": { 207 "$type": "app.bsky.feed.post", 208 "text": "To be deleted", 209 "createdAt": now 210 } 211 }, 212 { 213 "$type": "com.atproto.repo.applyWrites#create", 214 "collection": "app.bsky.feed.post", 215 "rkey": rkey_to_update, 216 "value": { 217 "$type": "app.bsky.feed.post", 218 "text": "To be updated", 219 "createdAt": now 220 } 221 } 222 ] 223 }); 224 let res = client 225 .post(format!( 226 "{}/xrpc/com.atproto.repo.applyWrites", 227 base_url().await 228 )) 229 .bearer_auth(&token) 230 .json(&setup_payload) 231 .send() 232 .await 233 .expect("Failed to setup"); 234 assert_eq!(res.status(), StatusCode::OK); 235 236 let mixed_payload = json!({ 237 "repo": did, 238 "writes": [ 239 { 240 "$type": "com.atproto.repo.applyWrites#create", 241 "collection": "app.bsky.feed.post", 242 "value": { 243 "$type": "app.bsky.feed.post", 244 "text": "New post", 245 "createdAt": now 246 } 247 }, 248 { 249 "$type": "com.atproto.repo.applyWrites#update", 250 "collection": "app.bsky.feed.post", 251 "rkey": rkey_to_update, 252 "value": { 253 "$type": "app.bsky.feed.post", 254 "text": "Updated text", 255 "createdAt": now 256 } 257 }, 258 { 259 "$type": "com.atproto.repo.applyWrites#delete", 260 "collection": "app.bsky.feed.post", 261 "rkey": rkey_to_delete 262 } 263 ] 264 }); 265 266 let res = client 267 .post(format!( 268 "{}/xrpc/com.atproto.repo.applyWrites", 269 base_url().await 270 )) 271 .bearer_auth(&token) 272 .json(&mixed_payload) 273 .send() 274 .await 275 .expect("Failed to send request"); 276 277 assert_eq!(res.status(), StatusCode::OK); 278 let body: Value = res.json().await.expect("Response was not valid JSON"); 279 let results = body["results"].as_array().unwrap(); 280 assert_eq!(results.len(), 3); 281} 282 283#[tokio::test] 284async fn test_apply_writes_no_auth() { 285 let client = client(); 286 287 let payload = json!({ 288 "repo": "did:plc:test", 289 "writes": [ 290 { 291 "$type": "com.atproto.repo.applyWrites#create", 292 "collection": "app.bsky.feed.post", 293 "value": { 294 "$type": "app.bsky.feed.post", 295 "text": "Test", 296 "createdAt": "2025-01-01T00:00:00Z" 297 } 298 } 299 ] 300 }); 301 302 let res = client 303 .post(format!( 304 "{}/xrpc/com.atproto.repo.applyWrites", 305 base_url().await 306 )) 307 .json(&payload) 308 .send() 309 .await 310 .expect("Failed to send request"); 311 312 assert_eq!(res.status(), StatusCode::UNAUTHORIZED); 313} 314 315#[tokio::test] 316async fn test_apply_writes_empty_writes() { 317 let client = client(); 318 let (token, did) = create_account_and_login(&client).await; 319 320 let payload = json!({ 321 "repo": did, 322 "writes": [] 323 }); 324 325 let res = client 326 .post(format!( 327 "{}/xrpc/com.atproto.repo.applyWrites", 328 base_url().await 329 )) 330 .bearer_auth(&token) 331 .json(&payload) 332 .send() 333 .await 334 .expect("Failed to send request"); 335 336 assert_eq!(res.status(), StatusCode::BAD_REQUEST); 337}