this repo has no description
1mod common; 2mod helpers; 3use common::*; 4use reqwest::StatusCode; 5use serde_json::{Value, json}; 6 7#[tokio::test] 8async fn test_check_account_status_returns_correct_block_count() { 9 let client = client(); 10 let base = base_url().await; 11 let (access_jwt, did) = create_account_and_login(&client).await; 12 13 let status1 = client 14 .get(format!("{}/xrpc/com.atproto.server.checkAccountStatus", base)) 15 .bearer_auth(&access_jwt) 16 .send() 17 .await 18 .unwrap(); 19 assert_eq!(status1.status(), StatusCode::OK); 20 let body1: Value = status1.json().await.unwrap(); 21 let initial_blocks = body1["repoBlocks"].as_i64().unwrap(); 22 assert!(initial_blocks >= 2, "New account should have at least 2 blocks (commit + empty MST)"); 23 24 let create_res = client 25 .post(format!("{}/xrpc/com.atproto.repo.createRecord", base)) 26 .bearer_auth(&access_jwt) 27 .json(&json!({ 28 "repo": did, 29 "collection": "app.bsky.feed.post", 30 "record": { 31 "$type": "app.bsky.feed.post", 32 "text": "Test post for block counting", 33 "createdAt": chrono::Utc::now().to_rfc3339() 34 } 35 })) 36 .send() 37 .await 38 .unwrap(); 39 assert_eq!(create_res.status(), StatusCode::OK); 40 let create_body: Value = create_res.json().await.unwrap(); 41 let rkey = create_body["uri"].as_str().unwrap().split('/').last().unwrap().to_string(); 42 43 let status2 = client 44 .get(format!("{}/xrpc/com.atproto.server.checkAccountStatus", base)) 45 .bearer_auth(&access_jwt) 46 .send() 47 .await 48 .unwrap(); 49 let body2: Value = status2.json().await.unwrap(); 50 let after_create_blocks = body2["repoBlocks"].as_i64().unwrap(); 51 assert!(after_create_blocks > initial_blocks, "Block count should increase after creating a record"); 52 53 let delete_res = client 54 .post(format!("{}/xrpc/com.atproto.repo.deleteRecord", base)) 55 .bearer_auth(&access_jwt) 56 .json(&json!({ 57 "repo": did, 58 "collection": "app.bsky.feed.post", 59 "rkey": rkey 60 })) 61 .send() 62 .await 63 .unwrap(); 64 assert_eq!(delete_res.status(), StatusCode::OK); 65 66 let status3 = client 67 .get(format!("{}/xrpc/com.atproto.server.checkAccountStatus", base)) 68 .bearer_auth(&access_jwt) 69 .send() 70 .await 71 .unwrap(); 72 let body3: Value = status3.json().await.unwrap(); 73 let after_delete_blocks = body3["repoBlocks"].as_i64().unwrap(); 74 assert!( 75 after_delete_blocks >= after_create_blocks, 76 "Block count should not decrease after deleting a record (was {}, now {})", 77 after_create_blocks, 78 after_delete_blocks 79 ); 80} 81 82#[tokio::test] 83async fn test_check_account_status_returns_valid_repo_rev() { 84 let client = client(); 85 let base = base_url().await; 86 let (access_jwt, _) = create_account_and_login(&client).await; 87 88 let status = client 89 .get(format!("{}/xrpc/com.atproto.server.checkAccountStatus", base)) 90 .bearer_auth(&access_jwt) 91 .send() 92 .await 93 .unwrap(); 94 assert_eq!(status.status(), StatusCode::OK); 95 let body: Value = status.json().await.unwrap(); 96 97 let repo_rev = body["repoRev"].as_str().unwrap(); 98 assert!(!repo_rev.is_empty(), "repoRev should not be empty"); 99 assert!(repo_rev.chars().all(|c| c.is_alphanumeric()), "repoRev should be alphanumeric TID"); 100} 101 102#[tokio::test] 103async fn test_check_account_status_valid_did_is_true_for_active_account() { 104 let client = client(); 105 let base = base_url().await; 106 let (access_jwt, _) = create_account_and_login(&client).await; 107 108 let status = client 109 .get(format!("{}/xrpc/com.atproto.server.checkAccountStatus", base)) 110 .bearer_auth(&access_jwt) 111 .send() 112 .await 113 .unwrap(); 114 assert_eq!(status.status(), StatusCode::OK); 115 let body: Value = status.json().await.unwrap(); 116 117 assert_eq!(body["validDid"], true, "validDid should be true for active account with correct DID document"); 118 assert_eq!(body["activated"], true, "activated should be true for active account"); 119} 120 121#[tokio::test] 122async fn test_deactivate_account_with_delete_after() { 123 let client = client(); 124 let base = base_url().await; 125 let (access_jwt, _) = create_account_and_login(&client).await; 126 127 let future_time = chrono::Utc::now() + chrono::Duration::hours(24); 128 let delete_after = future_time.to_rfc3339(); 129 130 let deactivate = client 131 .post(format!("{}/xrpc/com.atproto.server.deactivateAccount", base)) 132 .bearer_auth(&access_jwt) 133 .json(&json!({ 134 "deleteAfter": delete_after 135 })) 136 .send() 137 .await 138 .unwrap(); 139 assert_eq!(deactivate.status(), StatusCode::OK); 140 141 let status = client 142 .get(format!("{}/xrpc/com.atproto.server.checkAccountStatus", base)) 143 .bearer_auth(&access_jwt) 144 .send() 145 .await 146 .unwrap(); 147 assert_eq!(status.status(), StatusCode::OK); 148 let body: Value = status.json().await.unwrap(); 149 assert_eq!(body["activated"], false, "Account should be deactivated"); 150} 151 152#[tokio::test] 153async fn test_create_account_returns_did_doc() { 154 let client = client(); 155 let base = base_url().await; 156 157 let handle = format!("dd{}", &uuid::Uuid::new_v4().simple().to_string()[..12]); 158 let payload = json!({ 159 "handle": handle, 160 "email": format!("{}@example.com", handle), 161 "password": "Testpass123!" 162 }); 163 164 let create_res = client 165 .post(format!("{}/xrpc/com.atproto.server.createAccount", base)) 166 .json(&payload) 167 .send() 168 .await 169 .unwrap(); 170 assert_eq!(create_res.status(), StatusCode::OK); 171 let body: Value = create_res.json().await.unwrap(); 172 173 assert!(body["accessJwt"].is_string(), "accessJwt should always be returned"); 174 assert!(body["refreshJwt"].is_string(), "refreshJwt should always be returned"); 175 assert!(body["did"].is_string(), "did should be returned"); 176 177 if body["didDoc"].is_object() { 178 let did_doc = &body["didDoc"]; 179 assert!(did_doc["id"].is_string(), "didDoc should have id field"); 180 } 181} 182 183#[tokio::test] 184async fn test_create_account_always_returns_tokens() { 185 let client = client(); 186 let base = base_url().await; 187 188 let handle = format!("tt{}", &uuid::Uuid::new_v4().simple().to_string()[..12]); 189 let payload = json!({ 190 "handle": handle, 191 "email": format!("{}@example.com", handle), 192 "password": "Testpass123!" 193 }); 194 195 let create_res = client 196 .post(format!("{}/xrpc/com.atproto.server.createAccount", base)) 197 .json(&payload) 198 .send() 199 .await 200 .unwrap(); 201 assert_eq!(create_res.status(), StatusCode::OK); 202 let body: Value = create_res.json().await.unwrap(); 203 204 let access_jwt = body["accessJwt"].as_str().expect("accessJwt should be present"); 205 let refresh_jwt = body["refreshJwt"].as_str().expect("refreshJwt should be present"); 206 207 assert!(!access_jwt.is_empty(), "accessJwt should not be empty"); 208 assert!(!refresh_jwt.is_empty(), "refreshJwt should not be empty"); 209 210 let parts: Vec<&str> = access_jwt.split('.').collect(); 211 assert_eq!(parts.len(), 3, "accessJwt should be a valid JWT with 3 parts"); 212} 213 214#[tokio::test] 215async fn test_describe_server_has_links_and_contact() { 216 let client = client(); 217 let base = base_url().await; 218 219 let describe = client 220 .get(format!("{}/xrpc/com.atproto.server.describeServer", base)) 221 .send() 222 .await 223 .unwrap(); 224 assert_eq!(describe.status(), StatusCode::OK); 225 let body: Value = describe.json().await.unwrap(); 226 227 assert!(body.get("links").is_some(), "describeServer should include links object"); 228 assert!(body.get("contact").is_some(), "describeServer should include contact object"); 229 230 let links = &body["links"]; 231 assert!(links.get("privacyPolicy").is_some() || links["privacyPolicy"].is_null(), 232 "links should have privacyPolicy field (can be null)"); 233 assert!(links.get("termsOfService").is_some() || links["termsOfService"].is_null(), 234 "links should have termsOfService field (can be null)"); 235 236 let contact = &body["contact"]; 237 assert!(contact.get("email").is_some() || contact["email"].is_null(), 238 "contact should have email field (can be null)"); 239} 240 241#[tokio::test] 242async fn test_delete_account_password_max_length() { 243 let client = client(); 244 let base = base_url().await; 245 246 let handle = format!("pl{}", &uuid::Uuid::new_v4().simple().to_string()[..12]); 247 let payload = json!({ 248 "handle": handle, 249 "email": format!("{}@example.com", handle), 250 "password": "Testpass123!" 251 }); 252 253 let create_res = client 254 .post(format!("{}/xrpc/com.atproto.server.createAccount", base)) 255 .json(&payload) 256 .send() 257 .await 258 .unwrap(); 259 assert_eq!(create_res.status(), StatusCode::OK); 260 let body: Value = create_res.json().await.unwrap(); 261 let did = body["did"].as_str().unwrap(); 262 263 let too_long_password = "a".repeat(600); 264 let delete_res = client 265 .post(format!("{}/xrpc/com.atproto.server.deleteAccount", base)) 266 .json(&json!({ 267 "did": did, 268 "password": too_long_password, 269 "token": "fake-token" 270 })) 271 .send() 272 .await 273 .unwrap(); 274 275 assert_eq!(delete_res.status(), StatusCode::BAD_REQUEST); 276 let error_body: Value = delete_res.json().await.unwrap(); 277 assert!(error_body["message"].as_str().unwrap().contains("password length") 278 || error_body["error"].as_str().unwrap() == "InvalidRequest"); 279}