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