More endpoints, split out some tests to smaller files

This commit is contained in:
lewis
2025-12-09 23:41:53 +02:00
parent 85eb0108fb
commit 04a70e590c
20 changed files with 4956 additions and 928 deletions
+306
View File
@@ -0,0 +1,306 @@
mod common;
mod helpers;
use common::*;
use helpers::*;
use chrono::Utc;
use reqwest::StatusCode;
use serde_json::{Value, json};
#[tokio::test]
async fn test_session_lifecycle_wrong_password() {
let client = client();
let (_, _) = setup_new_user("session-wrong-pw").await;
let login_payload = json!({
"identifier": format!("session-wrong-pw-{}.test", Utc::now().timestamp_millis()),
"password": "wrong-password"
});
let res = client
.post(format!(
"{}/xrpc/com.atproto.server.createSession",
base_url().await
))
.json(&login_payload)
.send()
.await
.expect("Failed to send request");
assert!(
res.status() == StatusCode::UNAUTHORIZED || res.status() == StatusCode::BAD_REQUEST,
"Expected 401 or 400 for wrong password, got {}",
res.status()
);
}
#[tokio::test]
async fn test_session_lifecycle_multiple_sessions() {
let client = client();
let ts = Utc::now().timestamp_millis();
let handle = format!("multi-session-{}.test", ts);
let email = format!("multi-session-{}@test.com", ts);
let password = "multi-session-pw";
let create_payload = json!({
"handle": handle,
"email": email,
"password": password
});
let create_res = client
.post(format!(
"{}/xrpc/com.atproto.server.createAccount",
base_url().await
))
.json(&create_payload)
.send()
.await
.expect("Failed to create account");
assert_eq!(create_res.status(), StatusCode::OK);
let login_payload = json!({
"identifier": handle,
"password": password
});
let session1_res = client
.post(format!(
"{}/xrpc/com.atproto.server.createSession",
base_url().await
))
.json(&login_payload)
.send()
.await
.expect("Failed session 1");
assert_eq!(session1_res.status(), StatusCode::OK);
let session1: Value = session1_res.json().await.unwrap();
let jwt1 = session1["accessJwt"].as_str().unwrap();
let session2_res = client
.post(format!(
"{}/xrpc/com.atproto.server.createSession",
base_url().await
))
.json(&login_payload)
.send()
.await
.expect("Failed session 2");
assert_eq!(session2_res.status(), StatusCode::OK);
let session2: Value = session2_res.json().await.unwrap();
let jwt2 = session2["accessJwt"].as_str().unwrap();
assert_ne!(jwt1, jwt2, "Sessions should have different tokens");
let get1 = client
.get(format!(
"{}/xrpc/com.atproto.server.getSession",
base_url().await
))
.bearer_auth(jwt1)
.send()
.await
.expect("Failed getSession 1");
assert_eq!(get1.status(), StatusCode::OK);
let get2 = client
.get(format!(
"{}/xrpc/com.atproto.server.getSession",
base_url().await
))
.bearer_auth(jwt2)
.send()
.await
.expect("Failed getSession 2");
assert_eq!(get2.status(), StatusCode::OK);
}
#[tokio::test]
async fn test_session_lifecycle_refresh_invalidates_old() {
let client = client();
let ts = Utc::now().timestamp_millis();
let handle = format!("refresh-inv-{}.test", ts);
let email = format!("refresh-inv-{}@test.com", ts);
let password = "refresh-inv-pw";
let create_payload = json!({
"handle": handle,
"email": email,
"password": password
});
client
.post(format!(
"{}/xrpc/com.atproto.server.createAccount",
base_url().await
))
.json(&create_payload)
.send()
.await
.expect("Failed to create account");
let login_payload = json!({
"identifier": handle,
"password": password
});
let login_res = client
.post(format!(
"{}/xrpc/com.atproto.server.createSession",
base_url().await
))
.json(&login_payload)
.send()
.await
.expect("Failed login");
let login_body: Value = login_res.json().await.unwrap();
let refresh_jwt = login_body["refreshJwt"].as_str().unwrap().to_string();
let refresh_res = client
.post(format!(
"{}/xrpc/com.atproto.server.refreshSession",
base_url().await
))
.bearer_auth(&refresh_jwt)
.send()
.await
.expect("Failed first refresh");
assert_eq!(refresh_res.status(), StatusCode::OK);
let refresh_body: Value = refresh_res.json().await.unwrap();
let new_refresh_jwt = refresh_body["refreshJwt"].as_str().unwrap();
assert_ne!(refresh_jwt, new_refresh_jwt, "Refresh tokens should differ");
let reuse_res = client
.post(format!(
"{}/xrpc/com.atproto.server.refreshSession",
base_url().await
))
.bearer_auth(&refresh_jwt)
.send()
.await
.expect("Failed reuse attempt");
assert!(
reuse_res.status() == StatusCode::UNAUTHORIZED || reuse_res.status() == StatusCode::BAD_REQUEST,
"Old refresh token should be invalid after use"
);
}
#[tokio::test]
async fn test_app_password_lifecycle() {
let client = client();
let ts = Utc::now().timestamp_millis();
let handle = format!("apppass-{}.test", ts);
let email = format!("apppass-{}@test.com", ts);
let password = "apppass-password";
let create_res = client
.post(format!(
"{}/xrpc/com.atproto.server.createAccount",
base_url().await
))
.json(&json!({
"handle": handle,
"email": email,
"password": password
}))
.send()
.await
.expect("Failed to create account");
assert_eq!(create_res.status(), StatusCode::OK);
let account: Value = create_res.json().await.unwrap();
let jwt = account["accessJwt"].as_str().unwrap();
let create_app_pass_res = client
.post(format!(
"{}/xrpc/com.atproto.server.createAppPassword",
base_url().await
))
.bearer_auth(jwt)
.json(&json!({ "name": "Test App" }))
.send()
.await
.expect("Failed to create app password");
assert_eq!(create_app_pass_res.status(), StatusCode::OK);
let app_pass: Value = create_app_pass_res.json().await.unwrap();
let app_password = app_pass["password"].as_str().unwrap().to_string();
assert_eq!(app_pass["name"], "Test App");
let list_res = client
.get(format!(
"{}/xrpc/com.atproto.server.listAppPasswords",
base_url().await
))
.bearer_auth(jwt)
.send()
.await
.expect("Failed to list app passwords");
assert_eq!(list_res.status(), StatusCode::OK);
let list_body: Value = list_res.json().await.unwrap();
let passwords = list_body["passwords"].as_array().unwrap();
assert_eq!(passwords.len(), 1);
assert_eq!(passwords[0]["name"], "Test App");
let login_res = client
.post(format!(
"{}/xrpc/com.atproto.server.createSession",
base_url().await
))
.json(&json!({
"identifier": handle,
"password": app_password
}))
.send()
.await
.expect("Failed to login with app password");
assert_eq!(login_res.status(), StatusCode::OK, "App password login should work");
let revoke_res = client
.post(format!(
"{}/xrpc/com.atproto.server.revokeAppPassword",
base_url().await
))
.bearer_auth(jwt)
.json(&json!({ "name": "Test App" }))
.send()
.await
.expect("Failed to revoke app password");
assert_eq!(revoke_res.status(), StatusCode::OK);
let login_after_revoke = client
.post(format!(
"{}/xrpc/com.atproto.server.createSession",
base_url().await
))
.json(&json!({
"identifier": handle,
"password": app_password
}))
.send()
.await
.expect("Failed to attempt login after revoke");
assert!(
login_after_revoke.status() == StatusCode::UNAUTHORIZED
|| login_after_revoke.status() == StatusCode::BAD_REQUEST,
"Revoked app password should not work"
);
let list_after_revoke = client
.get(format!(
"{}/xrpc/com.atproto.server.listAppPasswords",
base_url().await
))
.bearer_auth(jwt)
.send()
.await
.expect("Failed to list after revoke");
let list_after: Value = list_after_revoke.json().await.unwrap();
let passwords_after = list_after["passwords"].as_array().unwrap();
assert_eq!(passwords_after.len(), 0, "No app passwords should remain");
}