this repo has no description
1mod common; 2use common::*; 3use reqwest::StatusCode; 4use serde_json::{Value, json}; 5use wiremock::matchers::{method, path}; 6use wiremock::{Mock, MockServer, ResponseTemplate}; 7#[tokio::test] 8async fn test_resolve_handle_success() { 9 let client = client(); 10 let handle = format!("resolvetest_{}", uuid::Uuid::new_v4()); 11 let payload = json!({ 12 "handle": handle, 13 "email": format!("{}@example.com", handle), 14 "password": "password" 15 }); 16 let res = client 17 .post(format!( 18 "{}/xrpc/com.atproto.server.createAccount", 19 base_url().await 20 )) 21 .json(&payload) 22 .send() 23 .await 24 .expect("Failed to create account"); 25 assert_eq!(res.status(), StatusCode::OK); 26 let body: Value = res.json().await.expect("Invalid JSON"); 27 let did = body["did"].as_str().expect("No DID").to_string(); 28 let params = [("handle", handle.as_str())]; 29 let res = client 30 .get(format!( 31 "{}/xrpc/com.atproto.identity.resolveHandle", 32 base_url().await 33 )) 34 .query(&params) 35 .send() 36 .await 37 .expect("Failed to send request"); 38 assert_eq!(res.status(), StatusCode::OK); 39 let body: Value = res.json().await.expect("Response was not valid JSON"); 40 assert_eq!(body["did"], did); 41} 42#[tokio::test] 43async fn test_resolve_handle_not_found() { 44 let client = client(); 45 let params = [("handle", "nonexistent_handle_12345")]; 46 let res = client 47 .get(format!( 48 "{}/xrpc/com.atproto.identity.resolveHandle", 49 base_url().await 50 )) 51 .query(&params) 52 .send() 53 .await 54 .expect("Failed to send request"); 55 assert_eq!(res.status(), StatusCode::NOT_FOUND); 56 let body: Value = res.json().await.expect("Response was not valid JSON"); 57 assert_eq!(body["error"], "HandleNotFound"); 58} 59#[tokio::test] 60async fn test_resolve_handle_missing_param() { 61 let client = client(); 62 let res = client 63 .get(format!( 64 "{}/xrpc/com.atproto.identity.resolveHandle", 65 base_url().await 66 )) 67 .send() 68 .await 69 .expect("Failed to send request"); 70 assert_eq!(res.status(), StatusCode::BAD_REQUEST); 71} 72#[tokio::test] 73async fn test_well_known_did() { 74 let client = client(); 75 let res = client 76 .get(format!("{}/.well-known/did.json", base_url().await)) 77 .send() 78 .await 79 .expect("Failed to send request"); 80 assert_eq!(res.status(), StatusCode::OK); 81 let body: Value = res.json().await.expect("Response was not valid JSON"); 82 assert!(body["id"].as_str().unwrap().starts_with("did:web:")); 83 assert_eq!(body["service"][0]["type"], "AtprotoPersonalDataServer"); 84} 85#[tokio::test] 86async fn test_create_did_web_account_and_resolve() { 87 let client = client(); 88 let mock_server = MockServer::start().await; 89 let mock_uri = mock_server.uri(); 90 let mock_addr = mock_uri.trim_start_matches("http://"); 91 let did = format!("did:web:{}", mock_addr.replace(":", "%3A")); 92 let handle = format!("webuser_{}", uuid::Uuid::new_v4()); 93 let pds_endpoint = base_url().await.replace("http://", "https://"); 94 let did_doc = json!({ 95 "@context": ["https://www.w3.org/ns/did/v1"], 96 "id": did, 97 "service": [{ 98 "id": "#atproto_pds", 99 "type": "AtprotoPersonalDataServer", 100 "serviceEndpoint": pds_endpoint 101 }] 102 }); 103 Mock::given(method("GET")) 104 .and(path("/.well-known/did.json")) 105 .respond_with(ResponseTemplate::new(200).set_body_json(did_doc)) 106 .mount(&mock_server) 107 .await; 108 let payload = json!({ 109 "handle": handle, 110 "email": format!("{}@example.com", handle), 111 "password": "password", 112 "did": did 113 }); 114 let res = client 115 .post(format!( 116 "{}/xrpc/com.atproto.server.createAccount", 117 base_url().await 118 )) 119 .json(&payload) 120 .send() 121 .await 122 .expect("Failed to send request"); 123 if res.status() != StatusCode::OK { 124 let status = res.status(); 125 let body: Value = res 126 .json() 127 .await 128 .unwrap_or(json!({"error": "could not parse body"})); 129 panic!("createAccount failed with status {}: {:?}", status, body); 130 } 131 let body: Value = res 132 .json() 133 .await 134 .expect("createAccount response was not JSON"); 135 assert_eq!(body["did"], did); 136 let res = client 137 .get(format!("{}/u/{}/did.json", base_url().await, handle)) 138 .send() 139 .await 140 .expect("Failed to fetch DID doc"); 141 assert_eq!(res.status(), StatusCode::OK); 142 let doc: Value = res.json().await.expect("DID doc was not JSON"); 143 assert_eq!(doc["id"], did); 144 assert_eq!(doc["alsoKnownAs"][0], format!("at://{}", handle)); 145 assert_eq!(doc["verificationMethod"][0]["controller"], did); 146 assert!(doc["verificationMethod"][0]["publicKeyJwk"].is_object()); 147} 148#[tokio::test] 149async fn test_create_account_duplicate_handle() { 150 let client = client(); 151 let handle = format!("dupe_{}", uuid::Uuid::new_v4()); 152 let email = format!("{}@example.com", handle); 153 let payload = json!({ 154 "handle": handle, 155 "email": email, 156 "password": "password" 157 }); 158 let res = client 159 .post(format!( 160 "{}/xrpc/com.atproto.server.createAccount", 161 base_url().await 162 )) 163 .json(&payload) 164 .send() 165 .await 166 .expect("Failed to send request"); 167 assert_eq!(res.status(), StatusCode::OK); 168 let res = client 169 .post(format!( 170 "{}/xrpc/com.atproto.server.createAccount", 171 base_url().await 172 )) 173 .json(&payload) 174 .send() 175 .await 176 .expect("Failed to send request"); 177 assert_eq!(res.status(), StatusCode::BAD_REQUEST); 178 let body: Value = res.json().await.expect("Response was not JSON"); 179 assert_eq!(body["error"], "HandleTaken"); 180} 181#[tokio::test] 182async fn test_did_web_lifecycle() { 183 let client = client(); 184 let mock_server = MockServer::start().await; 185 let mock_uri = mock_server.uri(); 186 let mock_addr = mock_uri.trim_start_matches("http://"); 187 let handle = format!("lifecycle_{}", uuid::Uuid::new_v4()); 188 let did = format!("did:web:{}:u:{}", mock_addr.replace(":", "%3A"), handle); 189 let email = format!("{}@test.com", handle); 190 let pds_endpoint = base_url().await.replace("http://", "https://"); 191 let did_doc = json!({ 192 "@context": ["https://www.w3.org/ns/did/v1"], 193 "id": did, 194 "service": [{ 195 "id": "#atproto_pds", 196 "type": "AtprotoPersonalDataServer", 197 "serviceEndpoint": pds_endpoint 198 }] 199 }); 200 Mock::given(method("GET")) 201 .and(path(format!("/u/{}/did.json", handle))) 202 .respond_with(ResponseTemplate::new(200).set_body_json(did_doc)) 203 .mount(&mock_server) 204 .await; 205 let create_payload = json!({ 206 "handle": handle, 207 "email": email, 208 "password": "password", 209 "did": did 210 }); 211 let res = client 212 .post(format!( 213 "{}/xrpc/com.atproto.server.createAccount", 214 base_url().await 215 )) 216 .json(&create_payload) 217 .send() 218 .await 219 .expect("Failed createAccount"); 220 if res.status() != StatusCode::OK { 221 let body: Value = res.json().await.unwrap(); 222 println!("createAccount failed: {:?}", body); 223 panic!("createAccount returned non-200"); 224 } 225 assert_eq!(res.status(), StatusCode::OK); 226 let create_body: Value = res.json().await.expect("Not JSON"); 227 assert_eq!(create_body["did"], did); 228 let _jwt = verify_new_account(&client, &did).await; 229 /* 230 let profile_payload = json!({ 231 "repo": did, 232 "collection": "app.bsky.actor.profile", 233 "rkey": "self", 234 "record": { 235 "$type": "app.bsky.actor.profile", 236 "displayName": "DID Web User", 237 "description": "Testing lifecycle" 238 } 239 }); 240 let res = client.post(format!("{}/xrpc/com.atproto.repo.putRecord", base_url().await)) 241 .bearer_auth(_jwt) 242 .json(&profile_payload) 243 .send() 244 .await 245 .expect("Failed putRecord"); 246 if res.status() != StatusCode::OK { 247 let body: Value = res.json().await.unwrap(); 248 println!("putRecord failed: {:?}", body); 249 panic!("putRecord returned non-200"); 250 } 251 assert_eq!(res.status(), StatusCode::OK); 252 let res = client.get(format!("{}/xrpc/com.atproto.repo.getRecord", base_url().await)) 253 .query(&[ 254 ("repo", &handle), 255 ("collection", &"app.bsky.actor.profile".to_string()), 256 ("rkey", &"self".to_string()) 257 ]) 258 .send() 259 .await 260 .expect("Failed getRecord"); 261 if res.status() != StatusCode::OK { 262 let body: Value = res.json().await.unwrap(); 263 println!("getRecord failed: {:?}", body); 264 panic!("getRecord returned non-200"); 265 } 266 let record_body: Value = res.json().await.expect("Not JSON"); 267 assert_eq!(record_body["value"]["displayName"], "DID Web User"); 268 */ 269} 270#[tokio::test] 271async fn test_get_recommended_did_credentials_success() { 272 let client = client(); 273 let (access_jwt, _) = create_account_and_login(&client).await; 274 let res = client 275 .get(format!( 276 "{}/xrpc/com.atproto.identity.getRecommendedDidCredentials", 277 base_url().await 278 )) 279 .bearer_auth(&access_jwt) 280 .send() 281 .await 282 .expect("Failed to send request"); 283 assert_eq!(res.status(), StatusCode::OK); 284 let body: Value = res.json().await.expect("Response was not valid JSON"); 285 assert!(body["rotationKeys"].is_array()); 286 assert!(body["alsoKnownAs"].is_array()); 287 assert!(body["verificationMethods"].is_object()); 288 assert!(body["services"].is_object()); 289 let rotation_keys = body["rotationKeys"].as_array().unwrap(); 290 assert!(!rotation_keys.is_empty()); 291 assert!(rotation_keys[0].as_str().unwrap().starts_with("did:key:")); 292 let also_known_as = body["alsoKnownAs"].as_array().unwrap(); 293 assert!(!also_known_as.is_empty()); 294 assert!(also_known_as[0].as_str().unwrap().starts_with("at://")); 295 assert!(body["verificationMethods"]["atproto"].is_string()); 296 assert_eq!(body["services"]["atprotoPds"]["type"], "AtprotoPersonalDataServer"); 297 assert!(body["services"]["atprotoPds"]["endpoint"].is_string()); 298} 299#[tokio::test] 300async fn test_get_recommended_did_credentials_no_auth() { 301 let client = client(); 302 let res = client 303 .get(format!( 304 "{}/xrpc/com.atproto.identity.getRecommendedDidCredentials", 305 base_url().await 306 )) 307 .send() 308 .await 309 .expect("Failed to send request"); 310 assert_eq!(res.status(), StatusCode::UNAUTHORIZED); 311 let body: Value = res.json().await.expect("Response was not valid JSON"); 312 assert_eq!(body["error"], "AuthenticationRequired"); 313}