mirror of
https://tangled.org/tranquil.farm/tranquil-pds
synced 2026-02-08 21:30:08 +00:00
369 lines
12 KiB
Rust
369 lines
12 KiB
Rust
mod common;
|
|
mod helpers;
|
|
use common::*;
|
|
use helpers::*;
|
|
use reqwest::StatusCode;
|
|
use serde_json::Value;
|
|
|
|
#[tokio::test]
|
|
async fn test_get_head_comprehensive() {
|
|
let client = client();
|
|
let (did, jwt) = setup_new_user("gethead").await;
|
|
let res = client
|
|
.get(format!(
|
|
"{}/xrpc/com.atproto.sync.getHead",
|
|
base_url().await
|
|
))
|
|
.query(&[("did", did.as_str())])
|
|
.send()
|
|
.await
|
|
.expect("Failed to send request");
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
let body: Value = res.json().await.expect("Response was not valid JSON");
|
|
assert!(body["root"].is_string());
|
|
let root1 = body["root"].as_str().unwrap().to_string();
|
|
assert!(root1.starts_with("bafy"), "Root CID should be a CID");
|
|
let latest_res = client
|
|
.get(format!(
|
|
"{}/xrpc/com.atproto.sync.getLatestCommit",
|
|
base_url().await
|
|
))
|
|
.query(&[("did", did.as_str())])
|
|
.send()
|
|
.await
|
|
.expect("Failed to get latest commit");
|
|
let latest_body: Value = latest_res.json().await.unwrap();
|
|
let latest_cid = latest_body["cid"].as_str().unwrap();
|
|
assert_eq!(
|
|
root1, latest_cid,
|
|
"getHead root should match getLatestCommit cid"
|
|
);
|
|
create_post(&client, &did, &jwt, "Post to change head").await;
|
|
let res2 = client
|
|
.get(format!(
|
|
"{}/xrpc/com.atproto.sync.getHead",
|
|
base_url().await
|
|
))
|
|
.query(&[("did", did.as_str())])
|
|
.send()
|
|
.await
|
|
.expect("Failed to get head after record");
|
|
let body2: Value = res2.json().await.unwrap();
|
|
let root2 = body2["root"].as_str().unwrap().to_string();
|
|
assert_ne!(root1, root2, "Head CID should change after record creation");
|
|
let not_found_res = client
|
|
.get(format!(
|
|
"{}/xrpc/com.atproto.sync.getHead",
|
|
base_url().await
|
|
))
|
|
.query(&[("did", "did:plc:nonexistent12345")])
|
|
.send()
|
|
.await
|
|
.expect("Failed to send request");
|
|
assert_eq!(not_found_res.status(), StatusCode::BAD_REQUEST);
|
|
let error_body: Value = not_found_res.json().await.unwrap();
|
|
assert_eq!(error_body["error"], "RepoNotFound");
|
|
let missing_res = client
|
|
.get(format!(
|
|
"{}/xrpc/com.atproto.sync.getHead",
|
|
base_url().await
|
|
))
|
|
.send()
|
|
.await
|
|
.expect("Failed to send request");
|
|
assert_eq!(missing_res.status(), StatusCode::BAD_REQUEST);
|
|
let empty_res = client
|
|
.get(format!(
|
|
"{}/xrpc/com.atproto.sync.getHead",
|
|
base_url().await
|
|
))
|
|
.query(&[("did", "")])
|
|
.send()
|
|
.await
|
|
.expect("Failed to send request");
|
|
assert_eq!(empty_res.status(), StatusCode::BAD_REQUEST);
|
|
let whitespace_res = client
|
|
.get(format!(
|
|
"{}/xrpc/com.atproto.sync.getHead",
|
|
base_url().await
|
|
))
|
|
.query(&[("did", " ")])
|
|
.send()
|
|
.await
|
|
.expect("Failed to send request");
|
|
assert_eq!(whitespace_res.status(), StatusCode::BAD_REQUEST);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_get_checkout_comprehensive() {
|
|
let client = client();
|
|
let (did, jwt) = setup_new_user("getcheckout").await;
|
|
let empty_res = client
|
|
.get(format!(
|
|
"{}/xrpc/com.atproto.sync.getCheckout",
|
|
base_url().await
|
|
))
|
|
.query(&[("did", did.as_str())])
|
|
.send()
|
|
.await
|
|
.expect("Failed to send request");
|
|
assert_eq!(empty_res.status(), StatusCode::OK);
|
|
let empty_body = empty_res.bytes().await.expect("Failed to get body");
|
|
assert!(
|
|
!empty_body.is_empty(),
|
|
"Even empty repo should return CAR header"
|
|
);
|
|
create_post(&client, &did, &jwt, "Post for checkout test").await;
|
|
let res = client
|
|
.get(format!(
|
|
"{}/xrpc/com.atproto.sync.getCheckout",
|
|
base_url().await
|
|
))
|
|
.query(&[("did", did.as_str())])
|
|
.send()
|
|
.await
|
|
.expect("Failed to send request");
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
assert_eq!(
|
|
res.headers()
|
|
.get("content-type")
|
|
.and_then(|h| h.to_str().ok()),
|
|
Some("application/vnd.ipld.car")
|
|
);
|
|
let body = res.bytes().await.expect("Failed to get body");
|
|
assert!(!body.is_empty(), "CAR file should not be empty");
|
|
assert!(body.len() > 50, "CAR file should contain actual data");
|
|
assert!(
|
|
body.len() >= 2,
|
|
"CAR file should have at least header length"
|
|
);
|
|
for i in 0..4 {
|
|
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
|
create_post(&client, &did, &jwt, &format!("Checkout post {}", i)).await;
|
|
}
|
|
let multi_res = client
|
|
.get(format!(
|
|
"{}/xrpc/com.atproto.sync.getCheckout",
|
|
base_url().await
|
|
))
|
|
.query(&[("did", did.as_str())])
|
|
.send()
|
|
.await
|
|
.expect("Failed to send request");
|
|
assert_eq!(multi_res.status(), StatusCode::OK);
|
|
let multi_body = multi_res.bytes().await.expect("Failed to get body");
|
|
assert!(
|
|
multi_body.len() > 500,
|
|
"CAR file with 5 records should be larger"
|
|
);
|
|
let not_found_res = client
|
|
.get(format!(
|
|
"{}/xrpc/com.atproto.sync.getCheckout",
|
|
base_url().await
|
|
))
|
|
.query(&[("did", "did:plc:nonexistent12345")])
|
|
.send()
|
|
.await
|
|
.expect("Failed to send request");
|
|
assert_eq!(not_found_res.status(), StatusCode::BAD_REQUEST);
|
|
let error_body: Value = not_found_res.json().await.unwrap();
|
|
assert_eq!(error_body["error"], "RepoNotFound");
|
|
let missing_res = client
|
|
.get(format!(
|
|
"{}/xrpc/com.atproto.sync.getCheckout",
|
|
base_url().await
|
|
))
|
|
.send()
|
|
.await
|
|
.expect("Failed to send request");
|
|
assert_eq!(missing_res.status(), StatusCode::BAD_REQUEST);
|
|
let empty_did_res = client
|
|
.get(format!(
|
|
"{}/xrpc/com.atproto.sync.getCheckout",
|
|
base_url().await
|
|
))
|
|
.query(&[("did", "")])
|
|
.send()
|
|
.await
|
|
.expect("Failed to send request");
|
|
assert_eq!(empty_did_res.status(), StatusCode::BAD_REQUEST);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_get_head_deactivated_account_returns_error() {
|
|
let client = client();
|
|
let base = base_url().await;
|
|
let (did, jwt) = setup_new_user("deactheadtest").await;
|
|
let res = client
|
|
.get(format!("{}/xrpc/com.atproto.sync.getHead", base))
|
|
.query(&[("did", did.as_str())])
|
|
.send()
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
client
|
|
.post(format!(
|
|
"{}/xrpc/com.atproto.server.deactivateAccount",
|
|
base
|
|
))
|
|
.bearer_auth(&jwt)
|
|
.json(&serde_json::json!({}))
|
|
.send()
|
|
.await
|
|
.unwrap();
|
|
let deact_res = client
|
|
.get(format!("{}/xrpc/com.atproto.sync.getHead", base))
|
|
.query(&[("did", did.as_str())])
|
|
.send()
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(deact_res.status(), StatusCode::BAD_REQUEST);
|
|
let body: Value = deact_res.json().await.unwrap();
|
|
assert_eq!(body["error"], "RepoDeactivated");
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_get_head_takendown_account_returns_error() {
|
|
let client = client();
|
|
let base = base_url().await;
|
|
let (admin_jwt, _) = create_admin_account_and_login(&client).await;
|
|
let (_, target_did) = create_account_and_login(&client).await;
|
|
let res = client
|
|
.get(format!("{}/xrpc/com.atproto.sync.getHead", base))
|
|
.query(&[("did", target_did.as_str())])
|
|
.send()
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
client
|
|
.post(format!(
|
|
"{}/xrpc/com.atproto.admin.updateSubjectStatus",
|
|
base
|
|
))
|
|
.bearer_auth(&admin_jwt)
|
|
.json(&serde_json::json!({
|
|
"subject": {
|
|
"$type": "com.atproto.admin.defs#repoRef",
|
|
"did": target_did
|
|
},
|
|
"takedown": {
|
|
"applied": true,
|
|
"ref": "test-takedown"
|
|
}
|
|
}))
|
|
.send()
|
|
.await
|
|
.unwrap();
|
|
let takedown_res = client
|
|
.get(format!("{}/xrpc/com.atproto.sync.getHead", base))
|
|
.query(&[("did", target_did.as_str())])
|
|
.send()
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(takedown_res.status(), StatusCode::BAD_REQUEST);
|
|
let body: Value = takedown_res.json().await.unwrap();
|
|
assert_eq!(body["error"], "RepoTakendown");
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_get_head_admin_can_access_deactivated() {
|
|
let client = client();
|
|
let base = base_url().await;
|
|
let (admin_jwt, _) = create_admin_account_and_login(&client).await;
|
|
let (user_jwt, did) = create_account_and_login(&client).await;
|
|
client
|
|
.post(format!(
|
|
"{}/xrpc/com.atproto.server.deactivateAccount",
|
|
base
|
|
))
|
|
.bearer_auth(&user_jwt)
|
|
.json(&serde_json::json!({}))
|
|
.send()
|
|
.await
|
|
.unwrap();
|
|
let res = client
|
|
.get(format!("{}/xrpc/com.atproto.sync.getHead", base))
|
|
.bearer_auth(&admin_jwt)
|
|
.query(&[("did", did.as_str())])
|
|
.send()
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_get_checkout_deactivated_account_returns_error() {
|
|
let client = client();
|
|
let base = base_url().await;
|
|
let (did, jwt) = setup_new_user("deactcheckouttest").await;
|
|
let res = client
|
|
.get(format!("{}/xrpc/com.atproto.sync.getCheckout", base))
|
|
.query(&[("did", did.as_str())])
|
|
.send()
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
client
|
|
.post(format!(
|
|
"{}/xrpc/com.atproto.server.deactivateAccount",
|
|
base
|
|
))
|
|
.bearer_auth(&jwt)
|
|
.json(&serde_json::json!({}))
|
|
.send()
|
|
.await
|
|
.unwrap();
|
|
let deact_res = client
|
|
.get(format!("{}/xrpc/com.atproto.sync.getCheckout", base))
|
|
.query(&[("did", did.as_str())])
|
|
.send()
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(deact_res.status(), StatusCode::BAD_REQUEST);
|
|
let body: Value = deact_res.json().await.unwrap();
|
|
assert_eq!(body["error"], "RepoDeactivated");
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_get_checkout_takendown_account_returns_error() {
|
|
let client = client();
|
|
let base = base_url().await;
|
|
let (admin_jwt, _) = create_admin_account_and_login(&client).await;
|
|
let (_, target_did) = create_account_and_login(&client).await;
|
|
let res = client
|
|
.get(format!("{}/xrpc/com.atproto.sync.getCheckout", base))
|
|
.query(&[("did", target_did.as_str())])
|
|
.send()
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
client
|
|
.post(format!(
|
|
"{}/xrpc/com.atproto.admin.updateSubjectStatus",
|
|
base
|
|
))
|
|
.bearer_auth(&admin_jwt)
|
|
.json(&serde_json::json!({
|
|
"subject": {
|
|
"$type": "com.atproto.admin.defs#repoRef",
|
|
"did": target_did
|
|
},
|
|
"takedown": {
|
|
"applied": true,
|
|
"ref": "test-takedown"
|
|
}
|
|
}))
|
|
.send()
|
|
.await
|
|
.unwrap();
|
|
let takedown_res = client
|
|
.get(format!("{}/xrpc/com.atproto.sync.getCheckout", base))
|
|
.query(&[("did", target_did.as_str())])
|
|
.send()
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(takedown_res.status(), StatusCode::BAD_REQUEST);
|
|
let body: Value = takedown_res.json().await.unwrap();
|
|
assert_eq!(body["error"], "RepoTakendown");
|
|
}
|