mirror of
https://tangled.org/tranquil.farm/tranquil-pds
synced 2026-09-19 00:34:15 +00:00
Format and split big files into smaller ones
This commit is contained in:
+7
-6
@@ -1,10 +1,10 @@
|
||||
use bspds::auth;
|
||||
use k256::SecretKey;
|
||||
use rand::rngs::OsRng;
|
||||
use chrono::{Utc, Duration};
|
||||
use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD};
|
||||
use serde_json::json;
|
||||
use bspds::auth;
|
||||
use chrono::{Duration, Utc};
|
||||
use k256::SecretKey;
|
||||
use k256::ecdsa::{SigningKey, signature::Signer};
|
||||
use rand::rngs::OsRng;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn test_jwt_flow() {
|
||||
@@ -24,7 +24,8 @@ fn test_jwt_flow() {
|
||||
|
||||
let aud = "did:web:service";
|
||||
let lxm = "com.example.test";
|
||||
let s_token = auth::create_service_token(did, aud, lxm, &key_bytes).expect("create service token");
|
||||
let s_token =
|
||||
auth::create_service_token(did, aud, lxm, &key_bytes).expect("create service token");
|
||||
let s_data = auth::verify_token(&s_token, &key_bytes).expect("verify service token");
|
||||
assert_eq!(s_data.claims.aud, aud);
|
||||
assert_eq!(s_data.claims.lxm, Some(lxm.to_string()));
|
||||
|
||||
+77
-27
@@ -1,22 +1,22 @@
|
||||
use reqwest::{header, Client, StatusCode};
|
||||
use serde_json::{json, Value};
|
||||
use aws_config::BehaviorVersion;
|
||||
use aws_sdk_s3::Client as S3Client;
|
||||
use aws_sdk_s3::config::Credentials;
|
||||
use bspds::state::AppState;
|
||||
use chrono::Utc;
|
||||
use reqwest::{Client, StatusCode, header};
|
||||
use serde_json::{Value, json};
|
||||
use sqlx::postgres::PgPoolOptions;
|
||||
#[allow(unused_imports)]
|
||||
use std::collections::HashMap;
|
||||
use std::sync::OnceLock;
|
||||
#[allow(unused_imports)]
|
||||
use std::time::Duration;
|
||||
use std::sync::OnceLock;
|
||||
use bspds::state::AppState;
|
||||
use sqlx::postgres::PgPoolOptions;
|
||||
use tokio::net::TcpListener;
|
||||
use testcontainers::{runners::AsyncRunner, ContainerAsync, ImageExt, GenericImage};
|
||||
use testcontainers::core::ContainerPort;
|
||||
use testcontainers::{ContainerAsync, GenericImage, ImageExt, runners::AsyncRunner};
|
||||
use testcontainers_modules::postgres::Postgres;
|
||||
use aws_sdk_s3::Client as S3Client;
|
||||
use aws_config::BehaviorVersion;
|
||||
use aws_sdk_s3::config::Credentials;
|
||||
use wiremock::{MockServer, Mock, ResponseTemplate};
|
||||
use tokio::net::TcpListener;
|
||||
use wiremock::matchers::{method, path};
|
||||
use wiremock::{Mock, MockServer, ResponseTemplate};
|
||||
|
||||
static SERVER_URL: OnceLock<String> = OnceLock::new();
|
||||
static DB_CONTAINER: OnceLock<ContainerAsync<Postgres>> = OnceLock::new();
|
||||
@@ -46,7 +46,12 @@ pub async fn base_url() -> &'static str {
|
||||
if let Ok(runtime_dir) = std::env::var("XDG_RUNTIME_DIR") {
|
||||
let podman_sock = std::path::Path::new(&runtime_dir).join("podman/podman.sock");
|
||||
if podman_sock.exists() {
|
||||
unsafe { std::env::set_var("DOCKER_HOST", format!("unix://{}", podman_sock.display())); }
|
||||
unsafe {
|
||||
std::env::set_var(
|
||||
"DOCKER_HOST",
|
||||
format!("unix://{}", podman_sock.display()),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,7 +67,10 @@ pub async fn base_url() -> &'static str {
|
||||
.await
|
||||
.expect("Failed to start MinIO");
|
||||
|
||||
let s3_port = s3_container.get_host_port_ipv4(9000).await.expect("Failed to get S3 port");
|
||||
let s3_port = s3_container
|
||||
.get_host_port_ipv4(9000)
|
||||
.await
|
||||
.expect("Failed to get S3 port");
|
||||
let s3_endpoint = format!("http://127.0.0.1:{}", s3_port);
|
||||
|
||||
unsafe {
|
||||
@@ -76,7 +84,13 @@ pub async fn base_url() -> &'static str {
|
||||
let sdk_config = aws_config::defaults(BehaviorVersion::latest())
|
||||
.region("us-east-1")
|
||||
.endpoint_url(&s3_endpoint)
|
||||
.credentials_provider(Credentials::new("minioadmin", "minioadmin", None, None, "test"))
|
||||
.credentials_provider(Credentials::new(
|
||||
"minioadmin",
|
||||
"minioadmin",
|
||||
None,
|
||||
None,
|
||||
"test",
|
||||
))
|
||||
.load()
|
||||
.await;
|
||||
|
||||
@@ -108,15 +122,24 @@ pub async fn base_url() -> &'static str {
|
||||
.mount(&mock_server)
|
||||
.await;
|
||||
|
||||
unsafe { std::env::set_var("APPVIEW_URL", mock_server.uri()); }
|
||||
unsafe {
|
||||
std::env::set_var("APPVIEW_URL", mock_server.uri());
|
||||
}
|
||||
MOCK_APPVIEW.set(mock_server).ok();
|
||||
|
||||
S3_CONTAINER.set(s3_container).ok();
|
||||
|
||||
let container = Postgres::default().with_tag("18-alpine").start().await.expect("Failed to start Postgres");
|
||||
let container = Postgres::default()
|
||||
.with_tag("18-alpine")
|
||||
.start()
|
||||
.await
|
||||
.expect("Failed to start Postgres");
|
||||
let connection_string = format!(
|
||||
"postgres://postgres:postgres@127.0.0.1:{}/postgres",
|
||||
container.get_host_port_ipv4(5432).await.expect("Failed to get port")
|
||||
container
|
||||
.get_host_port_ipv4(5432)
|
||||
.await
|
||||
.expect("Failed to get port")
|
||||
);
|
||||
|
||||
DB_CONTAINER.set(container).ok();
|
||||
@@ -157,7 +180,11 @@ async fn spawn_app(database_url: String) -> String {
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn upload_test_blob(client: &Client, data: &'static str, mime: &'static str) -> Value {
|
||||
let res = client.post(format!("{}/xrpc/com.atproto.repo.uploadBlob", base_url().await))
|
||||
let res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.repo.uploadBlob",
|
||||
base_url().await
|
||||
))
|
||||
.header(header::CONTENT_TYPE, mime)
|
||||
.bearer_auth(AUTH_TOKEN)
|
||||
.body(data)
|
||||
@@ -170,12 +197,11 @@ pub async fn upload_test_blob(client: &Client, data: &'static str, mime: &'stati
|
||||
body["blob"].clone()
|
||||
}
|
||||
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn create_test_post(
|
||||
client: &Client,
|
||||
text: &str,
|
||||
reply_to: Option<Value>
|
||||
reply_to: Option<Value>,
|
||||
) -> (String, String, String) {
|
||||
let collection = "app.bsky.feed.post";
|
||||
let mut record = json!({
|
||||
@@ -194,7 +220,11 @@ pub async fn create_test_post(
|
||||
"record": record
|
||||
});
|
||||
|
||||
let res = client.post(format!("{}/xrpc/com.atproto.repo.createRecord", base_url().await))
|
||||
let res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.repo.createRecord",
|
||||
base_url().await
|
||||
))
|
||||
.bearer_auth(AUTH_TOKEN)
|
||||
.json(&payload)
|
||||
.send()
|
||||
@@ -202,11 +232,24 @@ pub async fn create_test_post(
|
||||
.expect("Failed to send createRecord");
|
||||
|
||||
assert_eq!(res.status(), StatusCode::OK, "Failed to create post record");
|
||||
let body: Value = res.json().await.expect("createRecord response was not JSON");
|
||||
let body: Value = res
|
||||
.json()
|
||||
.await
|
||||
.expect("createRecord response was not JSON");
|
||||
|
||||
let uri = body["uri"].as_str().expect("Response had no URI").to_string();
|
||||
let cid = body["cid"].as_str().expect("Response had no CID").to_string();
|
||||
let rkey = uri.split('/').last().expect("URI was malformed").to_string();
|
||||
let uri = body["uri"]
|
||||
.as_str()
|
||||
.expect("Response had no URI")
|
||||
.to_string();
|
||||
let cid = body["cid"]
|
||||
.as_str()
|
||||
.expect("Response had no CID")
|
||||
.to_string();
|
||||
let rkey = uri
|
||||
.split('/')
|
||||
.last()
|
||||
.expect("URI was malformed")
|
||||
.to_string();
|
||||
|
||||
(uri, cid, rkey)
|
||||
}
|
||||
@@ -220,7 +263,11 @@ pub async fn create_account_and_login(client: &Client) -> (String, String) {
|
||||
"password": "password"
|
||||
});
|
||||
|
||||
let res = client.post(format!("{}/xrpc/com.atproto.server.createAccount", base_url().await))
|
||||
let res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.server.createAccount",
|
||||
base_url().await
|
||||
))
|
||||
.json(&payload)
|
||||
.send()
|
||||
.await
|
||||
@@ -231,7 +278,10 @@ pub async fn create_account_and_login(client: &Client) -> (String, String) {
|
||||
}
|
||||
|
||||
let body: Value = res.json().await.expect("Invalid JSON");
|
||||
let access_jwt = body["accessJwt"].as_str().expect("No accessJwt").to_string();
|
||||
let access_jwt = body["accessJwt"]
|
||||
.as_str()
|
||||
.expect("No accessJwt")
|
||||
.to_string();
|
||||
let did = body["did"].as_str().expect("No did").to_string();
|
||||
(access_jwt, did)
|
||||
}
|
||||
|
||||
+39
-11
@@ -1,9 +1,9 @@
|
||||
mod common;
|
||||
use common::*;
|
||||
use reqwest::StatusCode;
|
||||
use serde_json::{json, Value};
|
||||
use wiremock::{MockServer, Mock, ResponseTemplate};
|
||||
use serde_json::{Value, json};
|
||||
use wiremock::matchers::{method, path};
|
||||
use wiremock::{Mock, MockServer, ResponseTemplate};
|
||||
|
||||
// #[tokio::test]
|
||||
// async fn test_resolve_handle() {
|
||||
@@ -23,7 +23,8 @@ use wiremock::matchers::{method, path};
|
||||
#[tokio::test]
|
||||
async fn test_well_known_did() {
|
||||
let client = client();
|
||||
let res = client.get(format!("{}/.well-known/did.json", base_url().await))
|
||||
let res = client
|
||||
.get(format!("{}/.well-known/did.json", base_url().await))
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to send request");
|
||||
@@ -71,7 +72,11 @@ async fn test_create_did_web_account_and_resolve() {
|
||||
"did": did
|
||||
});
|
||||
|
||||
let res = client.post(format!("{}/xrpc/com.atproto.server.createAccount", base_url().await))
|
||||
let res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.server.createAccount",
|
||||
base_url().await
|
||||
))
|
||||
.json(&payload)
|
||||
.send()
|
||||
.await
|
||||
@@ -79,13 +84,20 @@ async fn test_create_did_web_account_and_resolve() {
|
||||
|
||||
if res.status() != StatusCode::OK {
|
||||
let status = res.status();
|
||||
let body: Value = res.json().await.unwrap_or(json!({"error": "could not parse body"}));
|
||||
let body: Value = res
|
||||
.json()
|
||||
.await
|
||||
.unwrap_or(json!({"error": "could not parse body"}));
|
||||
panic!("createAccount failed with status {}: {:?}", status, body);
|
||||
}
|
||||
let body: Value = res.json().await.expect("createAccount response was not JSON");
|
||||
let body: Value = res
|
||||
.json()
|
||||
.await
|
||||
.expect("createAccount response was not JSON");
|
||||
assert_eq!(body["did"], did);
|
||||
|
||||
let res = client.get(format!("{}/u/{}/did.json", base_url().await, handle))
|
||||
let res = client
|
||||
.get(format!("{}/u/{}/did.json", base_url().await, handle))
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to fetch DID doc");
|
||||
@@ -111,14 +123,22 @@ async fn test_create_account_duplicate_handle() {
|
||||
"password": "password"
|
||||
});
|
||||
|
||||
let res = client.post(format!("{}/xrpc/com.atproto.server.createAccount", base_url().await))
|
||||
let res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.server.createAccount",
|
||||
base_url().await
|
||||
))
|
||||
.json(&payload)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to send request");
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
||||
let res = client.post(format!("{}/xrpc/com.atproto.server.createAccount", base_url().await))
|
||||
let res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.server.createAccount",
|
||||
base_url().await
|
||||
))
|
||||
.json(&payload)
|
||||
.send()
|
||||
.await
|
||||
@@ -143,7 +163,11 @@ async fn test_did_web_lifecycle() {
|
||||
"did": did
|
||||
});
|
||||
|
||||
let res = client.post(format!("{}/xrpc/com.atproto.server.createAccount", base_url().await))
|
||||
let res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.server.createAccount",
|
||||
base_url().await
|
||||
))
|
||||
.json(&create_payload)
|
||||
.send()
|
||||
.await
|
||||
@@ -162,7 +186,11 @@ async fn test_did_web_lifecycle() {
|
||||
"identifier": handle,
|
||||
"password": "password"
|
||||
});
|
||||
let res = client.post(format!("{}/xrpc/com.atproto.server.createSession", base_url().await))
|
||||
let res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.server.createSession",
|
||||
base_url().await
|
||||
))
|
||||
.json(&login_payload)
|
||||
.send()
|
||||
.await
|
||||
|
||||
+376
-45
@@ -1,10 +1,9 @@
|
||||
mod common;
|
||||
use common::*;
|
||||
|
||||
use reqwest::{Client, StatusCode};
|
||||
use serde_json::{json, Value};
|
||||
use chrono::Utc;
|
||||
#[allow(unused_imports)]
|
||||
use reqwest;
|
||||
use serde_json::{Value, json};
|
||||
use std::time::Duration;
|
||||
|
||||
async fn setup_new_user(handle_prefix: &str) -> (String, String) {
|
||||
@@ -19,20 +18,36 @@ async fn setup_new_user(handle_prefix: &str) -> (String, String) {
|
||||
"email": email,
|
||||
"password": password
|
||||
});
|
||||
let create_res = client.post(format!("{}/xrpc/com.atproto.server.createAccount", base_url().await))
|
||||
let create_res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.server.createAccount",
|
||||
base_url().await
|
||||
))
|
||||
.json(&create_account_payload)
|
||||
.send()
|
||||
.await
|
||||
.expect("setup_new_user: Failed to send createAccount");
|
||||
|
||||
if create_res.status() != StatusCode::OK {
|
||||
panic!("setup_new_user: Failed to create account: {:?}", create_res.text().await);
|
||||
if create_res.status() != reqwest::StatusCode::OK {
|
||||
panic!(
|
||||
"setup_new_user: Failed to create account: {:?}",
|
||||
create_res.text().await
|
||||
);
|
||||
}
|
||||
|
||||
let create_body: Value = create_res.json().await.expect("setup_new_user: createAccount response was not JSON");
|
||||
let create_body: Value = create_res
|
||||
.json()
|
||||
.await
|
||||
.expect("setup_new_user: createAccount response was not JSON");
|
||||
|
||||
let new_did = create_body["did"].as_str().expect("setup_new_user: Response had no DID").to_string();
|
||||
let new_jwt = create_body["accessJwt"].as_str().expect("setup_new_user: Response had no accessJwt").to_string();
|
||||
let new_did = create_body["did"]
|
||||
.as_str()
|
||||
.expect("setup_new_user: Response had no DID")
|
||||
.to_string();
|
||||
let new_jwt = create_body["accessJwt"]
|
||||
.as_str()
|
||||
.expect("setup_new_user: Response had no accessJwt")
|
||||
.to_string();
|
||||
|
||||
(new_did, new_jwt)
|
||||
}
|
||||
@@ -59,35 +74,59 @@ async fn test_post_crud_lifecycle() {
|
||||
}
|
||||
});
|
||||
|
||||
let create_res = client.post(format!("{}/xrpc/com.atproto.repo.putRecord", base_url().await))
|
||||
let create_res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.repo.putRecord",
|
||||
base_url().await
|
||||
))
|
||||
.bearer_auth(&jwt)
|
||||
.json(&create_payload)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to send create request");
|
||||
|
||||
assert_eq!(create_res.status(), StatusCode::OK, "Failed to create record");
|
||||
let create_body: Value = create_res.json().await.expect("create response was not JSON");
|
||||
let uri = create_body["uri"].as_str().unwrap();
|
||||
if create_res.status() != reqwest::StatusCode::OK {
|
||||
let status = create_res.status();
|
||||
let body = create_res
|
||||
.text()
|
||||
.await
|
||||
.unwrap_or_else(|_| "Could not get body".to_string());
|
||||
panic!(
|
||||
"Failed to create record. Status: {}, Body: {}",
|
||||
status, body
|
||||
);
|
||||
}
|
||||
|
||||
let create_body: Value = create_res
|
||||
.json()
|
||||
.await
|
||||
.expect("create response was not JSON");
|
||||
let uri = create_body["uri"].as_str().unwrap();
|
||||
|
||||
let params = [
|
||||
("repo", did.as_str()),
|
||||
("collection", collection),
|
||||
("rkey", &rkey),
|
||||
];
|
||||
let get_res = client.get(format!("{}/xrpc/com.atproto.repo.getRecord", base_url().await))
|
||||
let get_res = client
|
||||
.get(format!(
|
||||
"{}/xrpc/com.atproto.repo.getRecord",
|
||||
base_url().await
|
||||
))
|
||||
.query(¶ms)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to send get request");
|
||||
|
||||
assert_eq!(get_res.status(), StatusCode::OK, "Failed to get record after create");
|
||||
assert_eq!(
|
||||
get_res.status(),
|
||||
reqwest::StatusCode::OK,
|
||||
"Failed to get record after create"
|
||||
);
|
||||
let get_body: Value = get_res.json().await.expect("get response was not JSON");
|
||||
assert_eq!(get_body["uri"], uri);
|
||||
assert_eq!(get_body["value"]["text"], original_text);
|
||||
|
||||
|
||||
let updated_text = "This post has been updated.";
|
||||
let update_payload = json!({
|
||||
"repo": did,
|
||||
@@ -100,26 +139,46 @@ async fn test_post_crud_lifecycle() {
|
||||
}
|
||||
});
|
||||
|
||||
let update_res = client.post(format!("{}/xrpc/com.atproto.repo.putRecord", base_url().await))
|
||||
let update_res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.repo.putRecord",
|
||||
base_url().await
|
||||
))
|
||||
.bearer_auth(&jwt)
|
||||
.json(&update_payload)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to send update request");
|
||||
|
||||
assert_eq!(update_res.status(), StatusCode::OK, "Failed to update record");
|
||||
assert_eq!(
|
||||
update_res.status(),
|
||||
reqwest::StatusCode::OK,
|
||||
"Failed to update record"
|
||||
);
|
||||
|
||||
|
||||
let get_updated_res = client.get(format!("{}/xrpc/com.atproto.repo.getRecord", base_url().await))
|
||||
let get_updated_res = client
|
||||
.get(format!(
|
||||
"{}/xrpc/com.atproto.repo.getRecord",
|
||||
base_url().await
|
||||
))
|
||||
.query(¶ms)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to send get-after-update request");
|
||||
|
||||
assert_eq!(get_updated_res.status(), StatusCode::OK, "Failed to get record after update");
|
||||
let get_updated_body: Value = get_updated_res.json().await.expect("get-updated response was not JSON");
|
||||
assert_eq!(get_updated_body["value"]["text"], updated_text, "Text was not updated");
|
||||
|
||||
assert_eq!(
|
||||
get_updated_res.status(),
|
||||
reqwest::StatusCode::OK,
|
||||
"Failed to get record after update"
|
||||
);
|
||||
let get_updated_body: Value = get_updated_res
|
||||
.json()
|
||||
.await
|
||||
.expect("get-updated response was not JSON");
|
||||
assert_eq!(
|
||||
get_updated_body["value"]["text"], updated_text,
|
||||
"Text was not updated"
|
||||
);
|
||||
|
||||
let delete_payload = json!({
|
||||
"repo": did,
|
||||
@@ -127,23 +186,38 @@ async fn test_post_crud_lifecycle() {
|
||||
"rkey": rkey
|
||||
});
|
||||
|
||||
let delete_res = client.post(format!("{}/xrpc/com.atproto.repo.deleteRecord", base_url().await))
|
||||
let delete_res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.repo.deleteRecord",
|
||||
base_url().await
|
||||
))
|
||||
.bearer_auth(&jwt)
|
||||
.json(&delete_payload)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to send delete request");
|
||||
|
||||
assert_eq!(delete_res.status(), StatusCode::OK, "Failed to delete record");
|
||||
assert_eq!(
|
||||
delete_res.status(),
|
||||
reqwest::StatusCode::OK,
|
||||
"Failed to delete record"
|
||||
);
|
||||
|
||||
|
||||
let get_deleted_res = client.get(format!("{}/xrpc/com.atproto.repo.getRecord", base_url().await))
|
||||
let get_deleted_res = client
|
||||
.get(format!(
|
||||
"{}/xrpc/com.atproto.repo.getRecord",
|
||||
base_url().await
|
||||
))
|
||||
.query(¶ms)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to send get-after-delete request");
|
||||
|
||||
assert_eq!(get_deleted_res.status(), StatusCode::NOT_FOUND, "Record was found, but it should be deleted");
|
||||
assert_eq!(
|
||||
get_deleted_res.status(),
|
||||
reqwest::StatusCode::NOT_FOUND,
|
||||
"Record was found, but it should be deleted"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -161,24 +235,39 @@ async fn test_record_update_conflict_lifecycle() {
|
||||
"displayName": "Original Name"
|
||||
}
|
||||
});
|
||||
let create_res = client.post(format!("{}/xrpc/com.atproto.repo.putRecord", base_url().await))
|
||||
let create_res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.repo.putRecord",
|
||||
base_url().await
|
||||
))
|
||||
.bearer_auth(&user_jwt)
|
||||
.json(&profile_payload)
|
||||
.send().await.expect("create profile failed");
|
||||
.send()
|
||||
.await
|
||||
.expect("create profile failed");
|
||||
|
||||
if create_res.status() != StatusCode::OK {
|
||||
if create_res.status() != reqwest::StatusCode::OK {
|
||||
return;
|
||||
}
|
||||
|
||||
let get_res = client.get(format!("{}/xrpc/com.atproto.repo.getRecord", base_url().await))
|
||||
let get_res = client
|
||||
.get(format!(
|
||||
"{}/xrpc/com.atproto.repo.getRecord",
|
||||
base_url().await
|
||||
))
|
||||
.query(&[
|
||||
("repo", &user_did),
|
||||
("collection", &"app.bsky.actor.profile".to_string()),
|
||||
("rkey", &"self".to_string()),
|
||||
])
|
||||
.send().await.expect("getRecord failed");
|
||||
.send()
|
||||
.await
|
||||
.expect("getRecord failed");
|
||||
let get_body: Value = get_res.json().await.expect("getRecord not json");
|
||||
let cid_v1 = get_body["cid"].as_str().expect("Profile v1 had no CID").to_string();
|
||||
let cid_v1 = get_body["cid"]
|
||||
.as_str()
|
||||
.expect("Profile v1 had no CID")
|
||||
.to_string();
|
||||
|
||||
let update_payload_v2 = json!({
|
||||
"repo": user_did,
|
||||
@@ -190,13 +279,26 @@ async fn test_record_update_conflict_lifecycle() {
|
||||
},
|
||||
"swapCommit": cid_v1 // <-- Correctly point to v1
|
||||
});
|
||||
let update_res_v2 = client.post(format!("{}/xrpc/com.atproto.repo.putRecord", base_url().await))
|
||||
let update_res_v2 = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.repo.putRecord",
|
||||
base_url().await
|
||||
))
|
||||
.bearer_auth(&user_jwt)
|
||||
.json(&update_payload_v2)
|
||||
.send().await.expect("putRecord v2 failed");
|
||||
assert_eq!(update_res_v2.status(), StatusCode::OK, "v2 update failed");
|
||||
.send()
|
||||
.await
|
||||
.expect("putRecord v2 failed");
|
||||
assert_eq!(
|
||||
update_res_v2.status(),
|
||||
reqwest::StatusCode::OK,
|
||||
"v2 update failed"
|
||||
);
|
||||
let update_body_v2: Value = update_res_v2.json().await.expect("v2 body not json");
|
||||
let cid_v2 = update_body_v2["cid"].as_str().expect("v2 response had no CID").to_string();
|
||||
let cid_v2 = update_body_v2["cid"]
|
||||
.as_str()
|
||||
.expect("v2 response had no CID")
|
||||
.to_string();
|
||||
|
||||
let update_payload_v3_stale = json!({
|
||||
"repo": user_did,
|
||||
@@ -208,14 +310,20 @@ async fn test_record_update_conflict_lifecycle() {
|
||||
},
|
||||
"swapCommit": cid_v1
|
||||
});
|
||||
let update_res_v3_stale = client.post(format!("{}/xrpc/com.atproto.repo.putRecord", base_url().await))
|
||||
let update_res_v3_stale = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.repo.putRecord",
|
||||
base_url().await
|
||||
))
|
||||
.bearer_auth(&user_jwt)
|
||||
.json(&update_payload_v3_stale)
|
||||
.send().await.expect("putRecord v3 (stale) failed");
|
||||
.send()
|
||||
.await
|
||||
.expect("putRecord v3 (stale) failed");
|
||||
|
||||
assert_eq!(
|
||||
update_res_v3_stale.status(),
|
||||
StatusCode::CONFLICT,
|
||||
reqwest::StatusCode::CONFLICT,
|
||||
"Stale update did not cause a 409 Conflict"
|
||||
);
|
||||
|
||||
@@ -229,10 +337,233 @@ async fn test_record_update_conflict_lifecycle() {
|
||||
},
|
||||
"swapCommit": cid_v2 // <-- Correct
|
||||
});
|
||||
let update_res_v3_good = client.post(format!("{}/xrpc/com.atproto.repo.putRecord", base_url().await))
|
||||
let update_res_v3_good = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.repo.putRecord",
|
||||
base_url().await
|
||||
))
|
||||
.bearer_auth(&user_jwt)
|
||||
.json(&update_payload_v3_good)
|
||||
.send().await.expect("putRecord v3 (good) failed");
|
||||
.send()
|
||||
.await
|
||||
.expect("putRecord v3 (good) failed");
|
||||
|
||||
assert_eq!(update_res_v3_good.status(), StatusCode::OK, "v3 (good) update failed");
|
||||
assert_eq!(
|
||||
update_res_v3_good.status(),
|
||||
reqwest::StatusCode::OK,
|
||||
"v3 (good) update failed"
|
||||
);
|
||||
}
|
||||
|
||||
async fn create_post(
|
||||
client: &reqwest::Client,
|
||||
did: &str,
|
||||
jwt: &str,
|
||||
text: &str,
|
||||
) -> (String, String) {
|
||||
let collection = "app.bsky.feed.post";
|
||||
let rkey = format!("e2e_social_{}", Utc::now().timestamp_millis());
|
||||
let now = Utc::now().to_rfc3339();
|
||||
|
||||
let create_payload = json!({
|
||||
"repo": did,
|
||||
"collection": collection,
|
||||
"rkey": rkey,
|
||||
"record": {
|
||||
"$type": collection,
|
||||
"text": text,
|
||||
"createdAt": now
|
||||
}
|
||||
});
|
||||
|
||||
let create_res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.repo.putRecord",
|
||||
base_url().await
|
||||
))
|
||||
.bearer_auth(jwt)
|
||||
.json(&create_payload)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to send create post request");
|
||||
|
||||
assert_eq!(
|
||||
create_res.status(),
|
||||
reqwest::StatusCode::OK,
|
||||
"Failed to create post record"
|
||||
);
|
||||
let create_body: Value = create_res
|
||||
.json()
|
||||
.await
|
||||
.expect("create post response was not JSON");
|
||||
let uri = create_body["uri"].as_str().unwrap().to_string();
|
||||
let cid = create_body["cid"].as_str().unwrap().to_string();
|
||||
(uri, cid)
|
||||
}
|
||||
|
||||
async fn create_follow(
|
||||
client: &reqwest::Client,
|
||||
follower_did: &str,
|
||||
follower_jwt: &str,
|
||||
followee_did: &str,
|
||||
) -> (String, String) {
|
||||
let collection = "app.bsky.graph.follow";
|
||||
let rkey = format!("e2e_follow_{}", Utc::now().timestamp_millis());
|
||||
let now = Utc::now().to_rfc3339();
|
||||
|
||||
let create_payload = json!({
|
||||
"repo": follower_did,
|
||||
"collection": collection,
|
||||
"rkey": rkey,
|
||||
"record": {
|
||||
"$type": collection,
|
||||
"subject": followee_did,
|
||||
"createdAt": now
|
||||
}
|
||||
});
|
||||
|
||||
let create_res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.repo.putRecord",
|
||||
base_url().await
|
||||
))
|
||||
.bearer_auth(follower_jwt)
|
||||
.json(&create_payload)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to send create follow request");
|
||||
|
||||
assert_eq!(
|
||||
create_res.status(),
|
||||
reqwest::StatusCode::OK,
|
||||
"Failed to create follow record"
|
||||
);
|
||||
let create_body: Value = create_res
|
||||
.json()
|
||||
.await
|
||||
.expect("create follow response was not JSON");
|
||||
let uri = create_body["uri"].as_str().unwrap().to_string();
|
||||
let cid = create_body["cid"].as_str().unwrap().to_string();
|
||||
(uri, cid)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_social_flow_lifecycle() {
|
||||
let client = client();
|
||||
|
||||
let (alice_did, alice_jwt) = setup_new_user("alice-social").await;
|
||||
let (bob_did, bob_jwt) = setup_new_user("bob-social").await;
|
||||
|
||||
let (post1_uri, _) = create_post(&client, &alice_did, &alice_jwt, "Alice's first post!").await;
|
||||
|
||||
create_follow(&client, &bob_did, &bob_jwt, &alice_did).await;
|
||||
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
|
||||
let timeline_res_1 = client
|
||||
.get(format!(
|
||||
"{}/xrpc/app.bsky.feed.getTimeline",
|
||||
base_url().await
|
||||
))
|
||||
.bearer_auth(&bob_jwt)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to get timeline (1)");
|
||||
|
||||
assert_eq!(
|
||||
timeline_res_1.status(),
|
||||
reqwest::StatusCode::OK,
|
||||
"Failed to get timeline (1)"
|
||||
);
|
||||
let timeline_body_1: Value = timeline_res_1.json().await.expect("Timeline (1) not JSON");
|
||||
let feed_1 = timeline_body_1["feed"].as_array().unwrap();
|
||||
assert_eq!(feed_1.len(), 1, "Timeline should have 1 post");
|
||||
assert_eq!(
|
||||
feed_1[0]["post"]["uri"], post1_uri,
|
||||
"Post URI mismatch in timeline (1)"
|
||||
);
|
||||
|
||||
let (post2_uri, _) = create_post(
|
||||
&client,
|
||||
&alice_did,
|
||||
&alice_jwt,
|
||||
"Alice's second post, so exciting!",
|
||||
)
|
||||
.await;
|
||||
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
|
||||
let timeline_res_2 = client
|
||||
.get(format!(
|
||||
"{}/xrpc/app.bsky.feed.getTimeline",
|
||||
base_url().await
|
||||
))
|
||||
.bearer_auth(&bob_jwt)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to get timeline (2)");
|
||||
|
||||
assert_eq!(
|
||||
timeline_res_2.status(),
|
||||
reqwest::StatusCode::OK,
|
||||
"Failed to get timeline (2)"
|
||||
);
|
||||
let timeline_body_2: Value = timeline_res_2.json().await.expect("Timeline (2) not JSON");
|
||||
let feed_2 = timeline_body_2["feed"].as_array().unwrap();
|
||||
assert_eq!(feed_2.len(), 2, "Timeline should have 2 posts");
|
||||
assert_eq!(
|
||||
feed_2[0]["post"]["uri"], post2_uri,
|
||||
"Post 2 should be first"
|
||||
);
|
||||
assert_eq!(
|
||||
feed_2[1]["post"]["uri"], post1_uri,
|
||||
"Post 1 should be second"
|
||||
);
|
||||
|
||||
let delete_payload = json!({
|
||||
"repo": alice_did,
|
||||
"collection": "app.bsky.feed.post",
|
||||
"rkey": post1_uri.split('/').last().unwrap()
|
||||
});
|
||||
let delete_res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.repo.deleteRecord",
|
||||
base_url().await
|
||||
))
|
||||
.bearer_auth(&alice_jwt)
|
||||
.json(&delete_payload)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to send delete request");
|
||||
assert_eq!(
|
||||
delete_res.status(),
|
||||
reqwest::StatusCode::OK,
|
||||
"Failed to delete record"
|
||||
);
|
||||
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
|
||||
let timeline_res_3 = client
|
||||
.get(format!(
|
||||
"{}/xrpc/app.bsky.feed.getTimeline",
|
||||
base_url().await
|
||||
))
|
||||
.bearer_auth(&bob_jwt)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to get timeline (3)");
|
||||
|
||||
assert_eq!(
|
||||
timeline_res_3.status(),
|
||||
reqwest::StatusCode::OK,
|
||||
"Failed to get timeline (3)"
|
||||
);
|
||||
let timeline_body_3: Value = timeline_res_3.json().await.expect("Timeline (3) not JSON");
|
||||
let feed_3 = timeline_body_3["feed"].as_array().unwrap();
|
||||
assert_eq!(feed_3.len(), 1, "Timeline should have 1 post after delete");
|
||||
assert_eq!(
|
||||
feed_3[0]["post"]["uri"], post2_uri,
|
||||
"Only post 2 should remain"
|
||||
);
|
||||
}
|
||||
|
||||
+24
-16
@@ -1,17 +1,15 @@
|
||||
mod common;
|
||||
|
||||
use axum::{
|
||||
routing::any,
|
||||
Router,
|
||||
extract::Request,
|
||||
http::StatusCode,
|
||||
};
|
||||
use tokio::net::TcpListener;
|
||||
use axum::{Router, extract::Request, http::StatusCode, routing::any};
|
||||
use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD};
|
||||
use reqwest::Client;
|
||||
use std::sync::Arc;
|
||||
use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD};
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
async fn spawn_mock_upstream() -> (String, tokio::sync::mpsc::Receiver<(String, String, Option<String>)>) {
|
||||
async fn spawn_mock_upstream() -> (
|
||||
String,
|
||||
tokio::sync::mpsc::Receiver<(String, String, Option<String>)>,
|
||||
) {
|
||||
let (tx, rx) = tokio::sync::mpsc::channel(10);
|
||||
let tx = Arc::new(tx);
|
||||
|
||||
@@ -20,7 +18,9 @@ async fn spawn_mock_upstream() -> (String, tokio::sync::mpsc::Receiver<(String,
|
||||
async move {
|
||||
let method = req.method().to_string();
|
||||
let uri = req.uri().to_string();
|
||||
let auth = req.headers().get("Authorization")
|
||||
let auth = req
|
||||
.headers()
|
||||
.get("Authorization")
|
||||
.and_then(|h| h.to_str().ok())
|
||||
.map(|s| s.to_string());
|
||||
|
||||
@@ -45,7 +45,8 @@ async fn test_proxy_via_header() {
|
||||
let (upstream_url, mut rx) = spawn_mock_upstream().await;
|
||||
let client = Client::new();
|
||||
|
||||
let res = client.get(format!("{}/xrpc/com.example.test", app_url))
|
||||
let res = client
|
||||
.get(format!("{}/xrpc/com.example.test", app_url))
|
||||
.header("atproto-proxy", &upstream_url)
|
||||
.header("Authorization", "Bearer test-token")
|
||||
.send()
|
||||
@@ -65,12 +66,15 @@ async fn test_proxy_via_header() {
|
||||
async fn test_proxy_via_env_var() {
|
||||
let (upstream_url, mut rx) = spawn_mock_upstream().await;
|
||||
|
||||
unsafe { std::env::set_var("APPVIEW_URL", &upstream_url); }
|
||||
unsafe {
|
||||
std::env::set_var("APPVIEW_URL", &upstream_url);
|
||||
}
|
||||
|
||||
let app_url = common::base_url().await;
|
||||
let client = Client::new();
|
||||
|
||||
let res = client.get(format!("{}/xrpc/com.example.envtest", app_url))
|
||||
let res = client
|
||||
.get(format!("{}/xrpc/com.example.envtest", app_url))
|
||||
.send()
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -85,12 +89,15 @@ async fn test_proxy_via_env_var() {
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_proxy_missing_config() {
|
||||
unsafe { std::env::remove_var("APPVIEW_URL"); }
|
||||
unsafe {
|
||||
std::env::remove_var("APPVIEW_URL");
|
||||
}
|
||||
|
||||
let app_url = common::base_url().await;
|
||||
let client = Client::new();
|
||||
|
||||
let res = client.get(format!("{}/xrpc/com.example.fail", app_url))
|
||||
let res = client
|
||||
.get(format!("{}/xrpc/com.example.fail", app_url))
|
||||
.send()
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -106,7 +113,8 @@ async fn test_proxy_auth_signing() {
|
||||
|
||||
let (access_jwt, did) = common::create_account_and_login(&client).await;
|
||||
|
||||
let res = client.get(format!("{}/xrpc/com.example.signed", app_url))
|
||||
let res = client
|
||||
.get(format!("{}/xrpc/com.example.signed", app_url))
|
||||
.header("atproto-proxy", &upstream_url)
|
||||
.header("Authorization", format!("Bearer {}", access_jwt))
|
||||
.send()
|
||||
|
||||
+103
-28
@@ -1,9 +1,9 @@
|
||||
mod common;
|
||||
use common::*;
|
||||
|
||||
use reqwest::{header, StatusCode};
|
||||
use serde_json::{json, Value};
|
||||
use chrono::Utc;
|
||||
use reqwest::{StatusCode, header};
|
||||
use serde_json::{Value, json};
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
@@ -15,7 +15,11 @@ async fn test_get_record() {
|
||||
("rkey", "self"),
|
||||
];
|
||||
|
||||
let res = client.get(format!("{}/xrpc/com.atproto.repo.getRecord", base_url().await))
|
||||
let res = client
|
||||
.get(format!(
|
||||
"{}/xrpc/com.atproto.repo.getRecord",
|
||||
base_url().await
|
||||
))
|
||||
.query(¶ms)
|
||||
.send()
|
||||
.await
|
||||
@@ -36,7 +40,11 @@ async fn test_get_record_not_found() {
|
||||
("rkey", "nonexistent"),
|
||||
];
|
||||
|
||||
let res = client.get(format!("{}/xrpc/com.atproto.repo.getRecord", base_url().await))
|
||||
let res = client
|
||||
.get(format!(
|
||||
"{}/xrpc/com.atproto.repo.getRecord",
|
||||
base_url().await
|
||||
))
|
||||
.query(¶ms)
|
||||
.send()
|
||||
.await
|
||||
@@ -50,7 +58,11 @@ async fn test_get_record_not_found() {
|
||||
#[tokio::test]
|
||||
async fn test_upload_blob_no_auth() {
|
||||
let client = client();
|
||||
let res = client.post(format!("{}/xrpc/com.atproto.repo.uploadBlob", base_url().await))
|
||||
let res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.repo.uploadBlob",
|
||||
base_url().await
|
||||
))
|
||||
.header(header::CONTENT_TYPE, "text/plain")
|
||||
.body("no auth")
|
||||
.send()
|
||||
@@ -66,7 +78,11 @@ async fn test_upload_blob_no_auth() {
|
||||
async fn test_upload_blob_success() {
|
||||
let client = client();
|
||||
let (token, _) = create_account_and_login(&client).await;
|
||||
let res = client.post(format!("{}/xrpc/com.atproto.repo.uploadBlob", base_url().await))
|
||||
let res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.repo.uploadBlob",
|
||||
base_url().await
|
||||
))
|
||||
.header(header::CONTENT_TYPE, "text/plain")
|
||||
.bearer_auth(token)
|
||||
.body("This is our blob data")
|
||||
@@ -90,7 +106,11 @@ async fn test_put_record_no_auth() {
|
||||
"record": {}
|
||||
});
|
||||
|
||||
let res = client.post(format!("{}/xrpc/com.atproto.repo.putRecord", base_url().await))
|
||||
let res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.repo.putRecord",
|
||||
base_url().await
|
||||
))
|
||||
.json(&payload)
|
||||
.send()
|
||||
.await
|
||||
@@ -118,7 +138,11 @@ async fn test_put_record_success() {
|
||||
}
|
||||
});
|
||||
|
||||
let res = client.post(format!("{}/xrpc/com.atproto.repo.putRecord", base_url().await))
|
||||
let res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.repo.putRecord",
|
||||
base_url().await
|
||||
))
|
||||
.bearer_auth(token)
|
||||
.json(&payload)
|
||||
.send()
|
||||
@@ -135,23 +159,33 @@ async fn test_put_record_success() {
|
||||
#[ignore]
|
||||
async fn test_get_record_missing_params() {
|
||||
let client = client();
|
||||
let params = [
|
||||
("repo", "did:plc:12345"),
|
||||
];
|
||||
let params = [("repo", "did:plc:12345")];
|
||||
|
||||
let res = client.get(format!("{}/xrpc/com.atproto.repo.getRecord", base_url().await))
|
||||
let res = client
|
||||
.get(format!(
|
||||
"{}/xrpc/com.atproto.repo.getRecord",
|
||||
base_url().await
|
||||
))
|
||||
.query(¶ms)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to send request");
|
||||
|
||||
assert_eq!(res.status(), StatusCode::BAD_REQUEST, "Expected 400 for missing params");
|
||||
assert_eq!(
|
||||
res.status(),
|
||||
StatusCode::BAD_REQUEST,
|
||||
"Expected 400 for missing params"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_upload_blob_bad_token() {
|
||||
let client = client();
|
||||
let res = client.post(format!("{}/xrpc/com.atproto.repo.uploadBlob", base_url().await))
|
||||
let res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.repo.uploadBlob",
|
||||
base_url().await
|
||||
))
|
||||
.header(header::CONTENT_TYPE, "text/plain")
|
||||
.bearer_auth(BAD_AUTH_TOKEN)
|
||||
.body("This is our blob data")
|
||||
@@ -181,14 +215,22 @@ async fn test_put_record_mismatched_repo() {
|
||||
}
|
||||
});
|
||||
|
||||
let res = client.post(format!("{}/xrpc/com.atproto.repo.putRecord", base_url().await))
|
||||
let res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.repo.putRecord",
|
||||
base_url().await
|
||||
))
|
||||
.bearer_auth(token)
|
||||
.json(&payload)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to send request");
|
||||
|
||||
assert_eq!(res.status(), StatusCode::FORBIDDEN, "Expected 403 for mismatched repo and auth");
|
||||
assert_eq!(
|
||||
res.status(),
|
||||
StatusCode::FORBIDDEN,
|
||||
"Expected 403 for mismatched repo and auth"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -207,21 +249,33 @@ async fn test_put_record_invalid_schema() {
|
||||
}
|
||||
});
|
||||
|
||||
let res = client.post(format!("{}/xrpc/com.atproto.repo.putRecord", base_url().await))
|
||||
let res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.repo.putRecord",
|
||||
base_url().await
|
||||
))
|
||||
.bearer_auth(token)
|
||||
.json(&payload)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to send request");
|
||||
|
||||
assert_eq!(res.status(), StatusCode::BAD_REQUEST, "Expected 400 for invalid record schema");
|
||||
assert_eq!(
|
||||
res.status(),
|
||||
StatusCode::BAD_REQUEST,
|
||||
"Expected 400 for invalid record schema"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_upload_blob_unsupported_mime_type() {
|
||||
let client = client();
|
||||
let (token, _) = create_account_and_login(&client).await;
|
||||
let res = client.post(format!("{}/xrpc/com.atproto.repo.uploadBlob", base_url().await))
|
||||
let res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.repo.uploadBlob",
|
||||
base_url().await
|
||||
))
|
||||
.header(header::CONTENT_TYPE, "application/xml")
|
||||
.bearer_auth(token)
|
||||
.body("<xml>not an image</xml>")
|
||||
@@ -242,7 +296,11 @@ async fn test_list_records() {
|
||||
("collection", "app.bsky.feed.post"),
|
||||
("limit", "10"),
|
||||
];
|
||||
let res = client.get(format!("{}/xrpc/com.atproto.repo.listRecords", base_url().await))
|
||||
let res = client
|
||||
.get(format!(
|
||||
"{}/xrpc/com.atproto.repo.listRecords",
|
||||
base_url().await
|
||||
))
|
||||
.query(¶ms)
|
||||
.send()
|
||||
.await
|
||||
@@ -255,10 +313,12 @@ async fn test_list_records() {
|
||||
async fn test_describe_repo() {
|
||||
let client = client();
|
||||
let (_, did) = create_account_and_login(&client).await;
|
||||
let params = [
|
||||
("repo", did.as_str()),
|
||||
];
|
||||
let res = client.get(format!("{}/xrpc/com.atproto.repo.describeRepo", base_url().await))
|
||||
let params = [("repo", did.as_str())];
|
||||
let res = client
|
||||
.get(format!(
|
||||
"{}/xrpc/com.atproto.repo.describeRepo",
|
||||
base_url().await
|
||||
))
|
||||
.query(¶ms)
|
||||
.send()
|
||||
.await
|
||||
@@ -282,7 +342,11 @@ async fn test_create_record_success_with_generated_rkey() {
|
||||
}
|
||||
});
|
||||
|
||||
let res = client.post(format!("{}/xrpc/com.atproto.repo.createRecord", base_url().await))
|
||||
let res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.repo.createRecord",
|
||||
base_url().await
|
||||
))
|
||||
.json(&payload)
|
||||
.bearer_auth(token)
|
||||
.send()
|
||||
@@ -313,7 +377,11 @@ async fn test_create_record_success_with_provided_rkey() {
|
||||
}
|
||||
});
|
||||
|
||||
let res = client.post(format!("{}/xrpc/com.atproto.repo.createRecord", base_url().await))
|
||||
let res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.repo.createRecord",
|
||||
base_url().await
|
||||
))
|
||||
.json(&payload)
|
||||
.bearer_auth(token)
|
||||
.send()
|
||||
@@ -322,7 +390,10 @@ async fn test_create_record_success_with_provided_rkey() {
|
||||
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
let body: Value = res.json().await.expect("Response was not valid JSON");
|
||||
assert_eq!(body["uri"], format!("at://{}/app.bsky.feed.post/{}", did, rkey));
|
||||
assert_eq!(
|
||||
body["uri"],
|
||||
format!("at://{}/app.bsky.feed.post/{}", did, rkey)
|
||||
);
|
||||
// assert_eq!(body["cid"], "bafyreihy");
|
||||
}
|
||||
|
||||
@@ -336,7 +407,11 @@ async fn test_delete_record() {
|
||||
"collection": "app.bsky.feed.post",
|
||||
"rkey": "some_post_to_delete"
|
||||
});
|
||||
let res = client.post(format!("{}/xrpc/com.atproto.repo.deleteRecord", base_url().await))
|
||||
let res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.repo.deleteRecord",
|
||||
base_url().await
|
||||
))
|
||||
.bearer_auth(token)
|
||||
.json(&payload)
|
||||
.send()
|
||||
|
||||
+71
-17
@@ -2,12 +2,13 @@ mod common;
|
||||
use common::*;
|
||||
|
||||
use reqwest::StatusCode;
|
||||
use serde_json::{json, Value};
|
||||
use serde_json::{Value, json};
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_health() {
|
||||
let client = client();
|
||||
let res = client.get(format!("{}/health", base_url().await))
|
||||
let res = client
|
||||
.get(format!("{}/health", base_url().await))
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to send request");
|
||||
@@ -19,7 +20,11 @@ async fn test_health() {
|
||||
#[tokio::test]
|
||||
async fn test_describe_server() {
|
||||
let client = client();
|
||||
let res = client.get(format!("{}/xrpc/com.atproto.server.describeServer", base_url().await))
|
||||
let res = client
|
||||
.get(format!(
|
||||
"{}/xrpc/com.atproto.server.describeServer",
|
||||
base_url().await
|
||||
))
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to send request");
|
||||
@@ -39,7 +44,11 @@ async fn test_create_session() {
|
||||
"email": format!("{}@example.com", handle),
|
||||
"password": "password"
|
||||
});
|
||||
let _ = client.post(format!("{}/xrpc/com.atproto.server.createAccount", base_url().await))
|
||||
let _ = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.server.createAccount",
|
||||
base_url().await
|
||||
))
|
||||
.json(&payload)
|
||||
.send()
|
||||
.await;
|
||||
@@ -49,7 +58,11 @@ async fn test_create_session() {
|
||||
"password": "password"
|
||||
});
|
||||
|
||||
let res = client.post(format!("{}/xrpc/com.atproto.server.createSession", base_url().await))
|
||||
let res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.server.createSession",
|
||||
base_url().await
|
||||
))
|
||||
.json(&payload)
|
||||
.send()
|
||||
.await
|
||||
@@ -67,14 +80,21 @@ async fn test_create_session_missing_identifier() {
|
||||
"password": "password"
|
||||
});
|
||||
|
||||
let res = client.post(format!("{}/xrpc/com.atproto.server.createSession", base_url().await))
|
||||
let res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.server.createSession",
|
||||
base_url().await
|
||||
))
|
||||
.json(&payload)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to send request");
|
||||
|
||||
assert!(res.status() == StatusCode::BAD_REQUEST || res.status() == StatusCode::UNPROCESSABLE_ENTITY,
|
||||
"Expected 400 or 422 for missing identifier, got {}", res.status());
|
||||
assert!(
|
||||
res.status() == StatusCode::BAD_REQUEST || res.status() == StatusCode::UNPROCESSABLE_ENTITY,
|
||||
"Expected 400 or 422 for missing identifier, got {}",
|
||||
res.status()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -86,19 +106,31 @@ async fn test_create_account_invalid_handle() {
|
||||
"password": "password"
|
||||
});
|
||||
|
||||
let res = client.post(format!("{}/xrpc/com.atproto.server.createAccount", base_url().await))
|
||||
let res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.server.createAccount",
|
||||
base_url().await
|
||||
))
|
||||
.json(&payload)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to send request");
|
||||
|
||||
assert_eq!(res.status(), StatusCode::BAD_REQUEST, "Expected 400 for invalid handle chars");
|
||||
assert_eq!(
|
||||
res.status(),
|
||||
StatusCode::BAD_REQUEST,
|
||||
"Expected 400 for invalid handle chars"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_session() {
|
||||
let client = client();
|
||||
let res = client.get(format!("{}/xrpc/com.atproto.server.getSession", base_url().await))
|
||||
let res = client
|
||||
.get(format!(
|
||||
"{}/xrpc/com.atproto.server.getSession",
|
||||
base_url().await
|
||||
))
|
||||
.bearer_auth(AUTH_TOKEN)
|
||||
.send()
|
||||
.await
|
||||
@@ -117,7 +149,11 @@ async fn test_refresh_session() {
|
||||
"email": format!("{}@example.com", handle),
|
||||
"password": "password"
|
||||
});
|
||||
let _ = client.post(format!("{}/xrpc/com.atproto.server.createAccount", base_url().await))
|
||||
let _ = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.server.createAccount",
|
||||
base_url().await
|
||||
))
|
||||
.json(&payload)
|
||||
.send()
|
||||
.await;
|
||||
@@ -126,7 +162,11 @@ async fn test_refresh_session() {
|
||||
"identifier": handle,
|
||||
"password": "password"
|
||||
});
|
||||
let res = client.post(format!("{}/xrpc/com.atproto.server.createSession", base_url().await))
|
||||
let res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.server.createSession",
|
||||
base_url().await
|
||||
))
|
||||
.json(&login_payload)
|
||||
.send()
|
||||
.await
|
||||
@@ -134,10 +174,20 @@ async fn test_refresh_session() {
|
||||
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
let body: Value = res.json().await.expect("Invalid JSON");
|
||||
let refresh_jwt = body["refreshJwt"].as_str().expect("No refreshJwt").to_string();
|
||||
let access_jwt = body["accessJwt"].as_str().expect("No accessJwt").to_string();
|
||||
let refresh_jwt = body["refreshJwt"]
|
||||
.as_str()
|
||||
.expect("No refreshJwt")
|
||||
.to_string();
|
||||
let access_jwt = body["accessJwt"]
|
||||
.as_str()
|
||||
.expect("No accessJwt")
|
||||
.to_string();
|
||||
|
||||
let res = client.post(format!("{}/xrpc/com.atproto.server.refreshSession", base_url().await))
|
||||
let res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.server.refreshSession",
|
||||
base_url().await
|
||||
))
|
||||
.bearer_auth(&refresh_jwt)
|
||||
.send()
|
||||
.await
|
||||
@@ -154,7 +204,11 @@ async fn test_refresh_session() {
|
||||
#[tokio::test]
|
||||
async fn test_delete_session() {
|
||||
let client = client();
|
||||
let res = client.post(format!("{}/xrpc/com.atproto.server.deleteSession", base_url().await))
|
||||
let res = client
|
||||
.post(format!(
|
||||
"{}/xrpc/com.atproto.server.deleteSession",
|
||||
base_url().await
|
||||
))
|
||||
.bearer_auth(AUTH_TOKEN)
|
||||
.send()
|
||||
.await
|
||||
|
||||
+11
-5
@@ -6,10 +6,12 @@ use reqwest::StatusCode;
|
||||
#[ignore]
|
||||
async fn test_get_repo() {
|
||||
let client = client();
|
||||
let params = [
|
||||
("did", AUTH_DID),
|
||||
];
|
||||
let res = client.get(format!("{}/xrpc/com.atproto.sync.getRepo", base_url().await))
|
||||
let params = [("did", AUTH_DID)];
|
||||
let res = client
|
||||
.get(format!(
|
||||
"{}/xrpc/com.atproto.sync.getRepo",
|
||||
base_url().await
|
||||
))
|
||||
.query(¶ms)
|
||||
.send()
|
||||
.await
|
||||
@@ -26,7 +28,11 @@ async fn test_get_blocks() {
|
||||
("did", AUTH_DID),
|
||||
// "cids" would be a list of CIDs
|
||||
];
|
||||
let res = client.get(format!("{}/xrpc/com.atproto.sync.getBlocks", base_url().await))
|
||||
let res = client
|
||||
.get(format!(
|
||||
"{}/xrpc/com.atproto.sync.getBlocks",
|
||||
base_url().await
|
||||
))
|
||||
.query(¶ms)
|
||||
.send()
|
||||
.await
|
||||
|
||||
Reference in New Issue
Block a user