this repo has no description
1mod common; 2mod helpers; 3use chrono::Utc; 4use common::*; 5use helpers::*; 6use reqwest::StatusCode; 7use serde_json::{Value, json}; 8 9#[tokio::test] 10async fn test_like_lifecycle() { 11 let client = client(); 12 let (alice_did, alice_jwt) = setup_new_user("alice-like").await; 13 let (bob_did, bob_jwt) = setup_new_user("bob-like").await; 14 let (post_uri, post_cid) = 15 create_post(&client, &alice_did, &alice_jwt, "Like this post!").await; 16 let (like_uri, _) = create_like(&client, &bob_did, &bob_jwt, &post_uri, &post_cid).await; 17 let like_rkey = like_uri.split('/').last().unwrap(); 18 let get_like_res = client 19 .get(format!( 20 "{}/xrpc/com.atproto.repo.getRecord", 21 base_url().await 22 )) 23 .query(&[ 24 ("repo", bob_did.as_str()), 25 ("collection", "app.bsky.feed.like"), 26 ("rkey", like_rkey), 27 ]) 28 .send() 29 .await 30 .expect("Failed to get like"); 31 assert_eq!(get_like_res.status(), StatusCode::OK); 32 let like_body: Value = get_like_res.json().await.unwrap(); 33 assert_eq!(like_body["value"]["subject"]["uri"], post_uri); 34 let delete_payload = json!({ 35 "repo": bob_did, 36 "collection": "app.bsky.feed.like", 37 "rkey": like_rkey 38 }); 39 let delete_res = client 40 .post(format!( 41 "{}/xrpc/com.atproto.repo.deleteRecord", 42 base_url().await 43 )) 44 .bearer_auth(&bob_jwt) 45 .json(&delete_payload) 46 .send() 47 .await 48 .expect("Failed to delete like"); 49 assert_eq!(delete_res.status(), StatusCode::OK, "Failed to delete like"); 50 let get_deleted_res = client 51 .get(format!( 52 "{}/xrpc/com.atproto.repo.getRecord", 53 base_url().await 54 )) 55 .query(&[ 56 ("repo", bob_did.as_str()), 57 ("collection", "app.bsky.feed.like"), 58 ("rkey", like_rkey), 59 ]) 60 .send() 61 .await 62 .expect("Failed to check deleted like"); 63 assert_eq!( 64 get_deleted_res.status(), 65 StatusCode::NOT_FOUND, 66 "Like should be deleted" 67 ); 68} 69 70#[tokio::test] 71async fn test_repost_lifecycle() { 72 let client = client(); 73 let (alice_did, alice_jwt) = setup_new_user("alice-repost").await; 74 let (bob_did, bob_jwt) = setup_new_user("bob-repost").await; 75 let (post_uri, post_cid) = create_post(&client, &alice_did, &alice_jwt, "Repost this!").await; 76 let (repost_uri, _) = create_repost(&client, &bob_did, &bob_jwt, &post_uri, &post_cid).await; 77 let repost_rkey = repost_uri.split('/').last().unwrap(); 78 let get_repost_res = client 79 .get(format!( 80 "{}/xrpc/com.atproto.repo.getRecord", 81 base_url().await 82 )) 83 .query(&[ 84 ("repo", bob_did.as_str()), 85 ("collection", "app.bsky.feed.repost"), 86 ("rkey", repost_rkey), 87 ]) 88 .send() 89 .await 90 .expect("Failed to get repost"); 91 assert_eq!(get_repost_res.status(), StatusCode::OK); 92 let repost_body: Value = get_repost_res.json().await.unwrap(); 93 assert_eq!(repost_body["value"]["subject"]["uri"], post_uri); 94 let delete_payload = json!({ 95 "repo": bob_did, 96 "collection": "app.bsky.feed.repost", 97 "rkey": repost_rkey 98 }); 99 let delete_res = client 100 .post(format!( 101 "{}/xrpc/com.atproto.repo.deleteRecord", 102 base_url().await 103 )) 104 .bearer_auth(&bob_jwt) 105 .json(&delete_payload) 106 .send() 107 .await 108 .expect("Failed to delete repost"); 109 assert_eq!( 110 delete_res.status(), 111 StatusCode::OK, 112 "Failed to delete repost" 113 ); 114} 115 116#[tokio::test] 117async fn test_unfollow_lifecycle() { 118 let client = client(); 119 let (alice_did, _alice_jwt) = setup_new_user("alice-unfollow").await; 120 let (bob_did, bob_jwt) = setup_new_user("bob-unfollow").await; 121 let (follow_uri, _) = create_follow(&client, &bob_did, &bob_jwt, &alice_did).await; 122 let follow_rkey = follow_uri.split('/').last().unwrap(); 123 let get_follow_res = client 124 .get(format!( 125 "{}/xrpc/com.atproto.repo.getRecord", 126 base_url().await 127 )) 128 .query(&[ 129 ("repo", bob_did.as_str()), 130 ("collection", "app.bsky.graph.follow"), 131 ("rkey", follow_rkey), 132 ]) 133 .send() 134 .await 135 .expect("Failed to get follow"); 136 assert_eq!(get_follow_res.status(), StatusCode::OK); 137 let unfollow_payload = json!({ 138 "repo": bob_did, 139 "collection": "app.bsky.graph.follow", 140 "rkey": follow_rkey 141 }); 142 let unfollow_res = client 143 .post(format!( 144 "{}/xrpc/com.atproto.repo.deleteRecord", 145 base_url().await 146 )) 147 .bearer_auth(&bob_jwt) 148 .json(&unfollow_payload) 149 .send() 150 .await 151 .expect("Failed to unfollow"); 152 assert_eq!(unfollow_res.status(), StatusCode::OK, "Failed to unfollow"); 153 let get_deleted_res = client 154 .get(format!( 155 "{}/xrpc/com.atproto.repo.getRecord", 156 base_url().await 157 )) 158 .query(&[ 159 ("repo", bob_did.as_str()), 160 ("collection", "app.bsky.graph.follow"), 161 ("rkey", follow_rkey), 162 ]) 163 .send() 164 .await 165 .expect("Failed to check deleted follow"); 166 assert_eq!( 167 get_deleted_res.status(), 168 StatusCode::NOT_FOUND, 169 "Follow should be deleted" 170 ); 171} 172 173#[tokio::test] 174async fn test_account_to_post_full_lifecycle() { 175 let client = client(); 176 let ts = Utc::now().timestamp_millis(); 177 let handle = format!("fullcycle-{}.test", ts); 178 let email = format!("fullcycle-{}@test.com", ts); 179 let password = "Fullcycle123!"; 180 let create_account_res = client 181 .post(format!( 182 "{}/xrpc/com.atproto.server.createAccount", 183 base_url().await 184 )) 185 .json(&json!({ 186 "handle": handle, 187 "email": email, 188 "password": password 189 })) 190 .send() 191 .await 192 .expect("Failed to create account"); 193 assert_eq!(create_account_res.status(), StatusCode::OK); 194 let account_body: Value = create_account_res.json().await.unwrap(); 195 let did = account_body["did"].as_str().unwrap().to_string(); 196 let handle = account_body["handle"].as_str().unwrap().to_string(); 197 let access_jwt = verify_new_account(&client, &did).await; 198 let get_session_res = client 199 .get(format!( 200 "{}/xrpc/com.atproto.server.getSession", 201 base_url().await 202 )) 203 .bearer_auth(&access_jwt) 204 .send() 205 .await 206 .expect("Failed to get session"); 207 assert_eq!(get_session_res.status(), StatusCode::OK); 208 let session_body: Value = get_session_res.json().await.unwrap(); 209 assert_eq!(session_body["did"], did); 210 let normalized_handle = session_body["handle"].as_str().unwrap().to_string(); 211 assert!( 212 normalized_handle.starts_with(&handle), 213 "Session handle should start with the requested handle" 214 ); 215 let profile_res = client 216 .post(format!( 217 "{}/xrpc/com.atproto.repo.putRecord", 218 base_url().await 219 )) 220 .bearer_auth(&access_jwt) 221 .json(&json!({ 222 "repo": did, 223 "collection": "app.bsky.actor.profile", 224 "rkey": "self", 225 "record": { 226 "$type": "app.bsky.actor.profile", 227 "displayName": "Full Cycle User" 228 } 229 })) 230 .send() 231 .await 232 .expect("Failed to create profile"); 233 assert_eq!(profile_res.status(), StatusCode::OK); 234 let (post_uri, post_cid) = create_post(&client, &did, &access_jwt, "My first post!").await; 235 let get_post_res = client 236 .get(format!( 237 "{}/xrpc/com.atproto.repo.getRecord", 238 base_url().await 239 )) 240 .query(&[ 241 ("repo", did.as_str()), 242 ("collection", "app.bsky.feed.post"), 243 ("rkey", post_uri.split('/').last().unwrap()), 244 ]) 245 .send() 246 .await 247 .expect("Failed to get post"); 248 assert_eq!(get_post_res.status(), StatusCode::OK); 249 create_like(&client, &did, &access_jwt, &post_uri, &post_cid).await; 250 let describe_res = client 251 .get(format!( 252 "{}/xrpc/com.atproto.repo.describeRepo", 253 base_url().await 254 )) 255 .query(&[("repo", did.as_str())]) 256 .send() 257 .await 258 .expect("Failed to describe repo"); 259 assert_eq!(describe_res.status(), StatusCode::OK); 260 let describe_body: Value = describe_res.json().await.unwrap(); 261 assert_eq!(describe_body["did"], did); 262 let describe_handle = describe_body["handle"].as_str().unwrap(); 263 assert!( 264 normalized_handle.starts_with(describe_handle) || describe_handle.starts_with(&handle), 265 "describeRepo handle should be related to the requested handle" 266 ); 267}