this repo has no description
1mod common; 2mod helpers; 3 4use common::*; 5use helpers::*; 6 7use reqwest::StatusCode; 8use serde_json::{Value, json}; 9use std::time::Duration; 10 11#[tokio::test] 12async fn test_social_flow_lifecycle() { 13 let client = client(); 14 15 let (alice_did, alice_jwt) = setup_new_user("alice-social").await; 16 let (bob_did, bob_jwt) = setup_new_user("bob-social").await; 17 18 let (post1_uri, _) = create_post(&client, &alice_did, &alice_jwt, "Alice's first post!").await; 19 20 create_follow(&client, &bob_did, &bob_jwt, &alice_did).await; 21 22 tokio::time::sleep(Duration::from_secs(1)).await; 23 24 let timeline_res_1 = client 25 .get(format!( 26 "{}/xrpc/app.bsky.feed.getTimeline", 27 base_url().await 28 )) 29 .bearer_auth(&bob_jwt) 30 .send() 31 .await 32 .expect("Failed to get timeline (1)"); 33 34 assert_eq!( 35 timeline_res_1.status(), 36 reqwest::StatusCode::OK, 37 "Failed to get timeline (1)" 38 ); 39 let timeline_body_1: Value = timeline_res_1.json().await.expect("Timeline (1) not JSON"); 40 let feed_1 = timeline_body_1["feed"].as_array().unwrap(); 41 assert_eq!(feed_1.len(), 1, "Timeline should have 1 post"); 42 assert_eq!( 43 feed_1[0]["post"]["uri"], post1_uri, 44 "Post URI mismatch in timeline (1)" 45 ); 46 47 let (post2_uri, _) = create_post( 48 &client, 49 &alice_did, 50 &alice_jwt, 51 "Alice's second post, so exciting!", 52 ) 53 .await; 54 55 tokio::time::sleep(Duration::from_secs(1)).await; 56 57 let timeline_res_2 = client 58 .get(format!( 59 "{}/xrpc/app.bsky.feed.getTimeline", 60 base_url().await 61 )) 62 .bearer_auth(&bob_jwt) 63 .send() 64 .await 65 .expect("Failed to get timeline (2)"); 66 67 assert_eq!( 68 timeline_res_2.status(), 69 reqwest::StatusCode::OK, 70 "Failed to get timeline (2)" 71 ); 72 let timeline_body_2: Value = timeline_res_2.json().await.expect("Timeline (2) not JSON"); 73 let feed_2 = timeline_body_2["feed"].as_array().unwrap(); 74 assert_eq!(feed_2.len(), 2, "Timeline should have 2 posts"); 75 assert_eq!( 76 feed_2[0]["post"]["uri"], post2_uri, 77 "Post 2 should be first" 78 ); 79 assert_eq!( 80 feed_2[1]["post"]["uri"], post1_uri, 81 "Post 1 should be second" 82 ); 83 84 let delete_payload = json!({ 85 "repo": alice_did, 86 "collection": "app.bsky.feed.post", 87 "rkey": post1_uri.split('/').last().unwrap() 88 }); 89 let delete_res = client 90 .post(format!( 91 "{}/xrpc/com.atproto.repo.deleteRecord", 92 base_url().await 93 )) 94 .bearer_auth(&alice_jwt) 95 .json(&delete_payload) 96 .send() 97 .await 98 .expect("Failed to send delete request"); 99 assert_eq!( 100 delete_res.status(), 101 reqwest::StatusCode::OK, 102 "Failed to delete record" 103 ); 104 105 tokio::time::sleep(Duration::from_secs(1)).await; 106 107 let timeline_res_3 = client 108 .get(format!( 109 "{}/xrpc/app.bsky.feed.getTimeline", 110 base_url().await 111 )) 112 .bearer_auth(&bob_jwt) 113 .send() 114 .await 115 .expect("Failed to get timeline (3)"); 116 117 assert_eq!( 118 timeline_res_3.status(), 119 reqwest::StatusCode::OK, 120 "Failed to get timeline (3)" 121 ); 122 let timeline_body_3: Value = timeline_res_3.json().await.expect("Timeline (3) not JSON"); 123 let feed_3 = timeline_body_3["feed"].as_array().unwrap(); 124 assert_eq!(feed_3.len(), 1, "Timeline should have 1 post after delete"); 125 assert_eq!( 126 feed_3[0]["post"]["uri"], post2_uri, 127 "Only post 2 should remain" 128 ); 129} 130 131#[tokio::test] 132async fn test_like_lifecycle() { 133 let client = client(); 134 135 let (alice_did, alice_jwt) = setup_new_user("alice-like").await; 136 let (bob_did, bob_jwt) = setup_new_user("bob-like").await; 137 138 let (post_uri, post_cid) = create_post(&client, &alice_did, &alice_jwt, "Like this post!").await; 139 140 let (like_uri, _) = create_like(&client, &bob_did, &bob_jwt, &post_uri, &post_cid).await; 141 142 let like_rkey = like_uri.split('/').last().unwrap(); 143 let get_like_res = client 144 .get(format!( 145 "{}/xrpc/com.atproto.repo.getRecord", 146 base_url().await 147 )) 148 .query(&[ 149 ("repo", bob_did.as_str()), 150 ("collection", "app.bsky.feed.like"), 151 ("rkey", like_rkey), 152 ]) 153 .send() 154 .await 155 .expect("Failed to get like"); 156 157 assert_eq!(get_like_res.status(), StatusCode::OK); 158 let like_body: Value = get_like_res.json().await.unwrap(); 159 assert_eq!(like_body["value"]["subject"]["uri"], post_uri); 160 161 let delete_payload = json!({ 162 "repo": bob_did, 163 "collection": "app.bsky.feed.like", 164 "rkey": like_rkey 165 }); 166 167 let delete_res = client 168 .post(format!( 169 "{}/xrpc/com.atproto.repo.deleteRecord", 170 base_url().await 171 )) 172 .bearer_auth(&bob_jwt) 173 .json(&delete_payload) 174 .send() 175 .await 176 .expect("Failed to delete like"); 177 178 assert_eq!(delete_res.status(), StatusCode::OK, "Failed to delete like"); 179 180 let get_deleted_res = client 181 .get(format!( 182 "{}/xrpc/com.atproto.repo.getRecord", 183 base_url().await 184 )) 185 .query(&[ 186 ("repo", bob_did.as_str()), 187 ("collection", "app.bsky.feed.like"), 188 ("rkey", like_rkey), 189 ]) 190 .send() 191 .await 192 .expect("Failed to check deleted like"); 193 194 assert_eq!(get_deleted_res.status(), StatusCode::NOT_FOUND, "Like should be deleted"); 195} 196 197#[tokio::test] 198async fn test_repost_lifecycle() { 199 let client = client(); 200 201 let (alice_did, alice_jwt) = setup_new_user("alice-repost").await; 202 let (bob_did, bob_jwt) = setup_new_user("bob-repost").await; 203 204 let (post_uri, post_cid) = create_post(&client, &alice_did, &alice_jwt, "Repost this!").await; 205 206 let (repost_uri, _) = create_repost(&client, &bob_did, &bob_jwt, &post_uri, &post_cid).await; 207 208 let repost_rkey = repost_uri.split('/').last().unwrap(); 209 let get_repost_res = client 210 .get(format!( 211 "{}/xrpc/com.atproto.repo.getRecord", 212 base_url().await 213 )) 214 .query(&[ 215 ("repo", bob_did.as_str()), 216 ("collection", "app.bsky.feed.repost"), 217 ("rkey", repost_rkey), 218 ]) 219 .send() 220 .await 221 .expect("Failed to get repost"); 222 223 assert_eq!(get_repost_res.status(), StatusCode::OK); 224 let repost_body: Value = get_repost_res.json().await.unwrap(); 225 assert_eq!(repost_body["value"]["subject"]["uri"], post_uri); 226 227 let delete_payload = json!({ 228 "repo": bob_did, 229 "collection": "app.bsky.feed.repost", 230 "rkey": repost_rkey 231 }); 232 233 let delete_res = client 234 .post(format!( 235 "{}/xrpc/com.atproto.repo.deleteRecord", 236 base_url().await 237 )) 238 .bearer_auth(&bob_jwt) 239 .json(&delete_payload) 240 .send() 241 .await 242 .expect("Failed to delete repost"); 243 244 assert_eq!(delete_res.status(), StatusCode::OK, "Failed to delete repost"); 245} 246 247#[tokio::test] 248async fn test_unfollow_lifecycle() { 249 let client = client(); 250 251 let (alice_did, _alice_jwt) = setup_new_user("alice-unfollow").await; 252 let (bob_did, bob_jwt) = setup_new_user("bob-unfollow").await; 253 254 let (follow_uri, _) = create_follow(&client, &bob_did, &bob_jwt, &alice_did).await; 255 256 let follow_rkey = follow_uri.split('/').last().unwrap(); 257 let get_follow_res = client 258 .get(format!( 259 "{}/xrpc/com.atproto.repo.getRecord", 260 base_url().await 261 )) 262 .query(&[ 263 ("repo", bob_did.as_str()), 264 ("collection", "app.bsky.graph.follow"), 265 ("rkey", follow_rkey), 266 ]) 267 .send() 268 .await 269 .expect("Failed to get follow"); 270 271 assert_eq!(get_follow_res.status(), StatusCode::OK); 272 273 let unfollow_payload = json!({ 274 "repo": bob_did, 275 "collection": "app.bsky.graph.follow", 276 "rkey": follow_rkey 277 }); 278 279 let unfollow_res = client 280 .post(format!( 281 "{}/xrpc/com.atproto.repo.deleteRecord", 282 base_url().await 283 )) 284 .bearer_auth(&bob_jwt) 285 .json(&unfollow_payload) 286 .send() 287 .await 288 .expect("Failed to unfollow"); 289 290 assert_eq!(unfollow_res.status(), StatusCode::OK, "Failed to unfollow"); 291 292 let get_deleted_res = client 293 .get(format!( 294 "{}/xrpc/com.atproto.repo.getRecord", 295 base_url().await 296 )) 297 .query(&[ 298 ("repo", bob_did.as_str()), 299 ("collection", "app.bsky.graph.follow"), 300 ("rkey", follow_rkey), 301 ]) 302 .send() 303 .await 304 .expect("Failed to check deleted follow"); 305 306 assert_eq!(get_deleted_res.status(), StatusCode::NOT_FOUND, "Follow should be deleted"); 307} 308 309#[tokio::test] 310async fn test_timeline_after_unfollow() { 311 let client = client(); 312 313 let (alice_did, alice_jwt) = setup_new_user("alice-tl-unfollow").await; 314 let (bob_did, bob_jwt) = setup_new_user("bob-tl-unfollow").await; 315 316 let (follow_uri, _) = create_follow(&client, &bob_did, &bob_jwt, &alice_did).await; 317 318 create_post(&client, &alice_did, &alice_jwt, "Post while following").await; 319 320 tokio::time::sleep(Duration::from_secs(1)).await; 321 322 let timeline_res = client 323 .get(format!( 324 "{}/xrpc/app.bsky.feed.getTimeline", 325 base_url().await 326 )) 327 .bearer_auth(&bob_jwt) 328 .send() 329 .await 330 .expect("Failed to get timeline"); 331 332 assert_eq!(timeline_res.status(), StatusCode::OK); 333 let timeline_body: Value = timeline_res.json().await.unwrap(); 334 let feed = timeline_body["feed"].as_array().unwrap(); 335 assert_eq!(feed.len(), 1, "Should see 1 post from Alice"); 336 337 let follow_rkey = follow_uri.split('/').last().unwrap(); 338 let unfollow_payload = json!({ 339 "repo": bob_did, 340 "collection": "app.bsky.graph.follow", 341 "rkey": follow_rkey 342 }); 343 client 344 .post(format!( 345 "{}/xrpc/com.atproto.repo.deleteRecord", 346 base_url().await 347 )) 348 .bearer_auth(&bob_jwt) 349 .json(&unfollow_payload) 350 .send() 351 .await 352 .expect("Failed to unfollow"); 353 354 tokio::time::sleep(Duration::from_secs(1)).await; 355 356 let timeline_after_res = client 357 .get(format!( 358 "{}/xrpc/app.bsky.feed.getTimeline", 359 base_url().await 360 )) 361 .bearer_auth(&bob_jwt) 362 .send() 363 .await 364 .expect("Failed to get timeline after unfollow"); 365 366 assert_eq!(timeline_after_res.status(), StatusCode::OK); 367 let timeline_after: Value = timeline_after_res.json().await.unwrap(); 368 let feed_after = timeline_after["feed"].as_array().unwrap(); 369 assert_eq!(feed_after.len(), 0, "Should see 0 posts after unfollowing"); 370} 371 372#[tokio::test] 373async fn test_mutual_follow_lifecycle() { 374 let client = client(); 375 376 let (alice_did, alice_jwt) = setup_new_user("alice-mutual").await; 377 let (bob_did, bob_jwt) = setup_new_user("bob-mutual").await; 378 379 create_follow(&client, &alice_did, &alice_jwt, &bob_did).await; 380 create_follow(&client, &bob_did, &bob_jwt, &alice_did).await; 381 382 create_post(&client, &alice_did, &alice_jwt, "Alice's post for mutual").await; 383 create_post(&client, &bob_did, &bob_jwt, "Bob's post for mutual").await; 384 385 tokio::time::sleep(Duration::from_secs(1)).await; 386 387 let alice_timeline_res = client 388 .get(format!( 389 "{}/xrpc/app.bsky.feed.getTimeline", 390 base_url().await 391 )) 392 .bearer_auth(&alice_jwt) 393 .send() 394 .await 395 .expect("Failed to get Alice's timeline"); 396 397 assert_eq!(alice_timeline_res.status(), StatusCode::OK); 398 let alice_tl: Value = alice_timeline_res.json().await.unwrap(); 399 let alice_feed = alice_tl["feed"].as_array().unwrap(); 400 assert_eq!(alice_feed.len(), 1, "Alice should see Bob's 1 post"); 401 402 let bob_timeline_res = client 403 .get(format!( 404 "{}/xrpc/app.bsky.feed.getTimeline", 405 base_url().await 406 )) 407 .bearer_auth(&bob_jwt) 408 .send() 409 .await 410 .expect("Failed to get Bob's timeline"); 411 412 assert_eq!(bob_timeline_res.status(), StatusCode::OK); 413 let bob_tl: Value = bob_timeline_res.json().await.unwrap(); 414 let bob_feed = bob_tl["feed"].as_array().unwrap(); 415 assert_eq!(bob_feed.len(), 1, "Bob should see Alice's 1 post"); 416}