Something went wrong. Try again.
atproto Thingiverse but good
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346use super::test_support::*;
#[tokio::test]async fn get_part_file_missing_uri_is_bad_request() { let state = state().await; let app = crate::appview::router().with_state(state); let resp = app .oneshot( Request::builder() .uri("/xrpc/space.polymodel.library.getPartFile") .body(Body::empty()) .unwrap(), ) .await .unwrap(); assert_eq!(resp.status(), StatusCode::BAD_REQUEST); let body = axum::body::to_bytes(resp.into_body(), usize::MAX) .await .unwrap(); let json: serde_json::Value = serde_json::from_slice(&body).unwrap(); assert_eq!(json["error"], "InvalidRequest");}
#[tokio::test]async fn get_part_file_malformed_uri_is_bad_request() { let state = state().await; let app = crate::appview::router().with_state(state); let resp = app .oneshot( Request::builder() .uri("/xrpc/space.polymodel.library.getPartFile?uri=notauri") .body(Body::empty()) .unwrap(), ) .await .unwrap(); assert_eq!(resp.status(), StatusCode::BAD_REQUEST);}
#[tokio::test]async fn get_part_file_wrong_collection_is_bad_request() { let state = state().await; let app = crate::appview::router().with_state(state); let resp = app .oneshot( Request::builder() .uri("/xrpc/space.polymodel.library.getPartFile?uri=at%3A%2F%2Fdid%3Aplc%3Ax%2Fspace.polymodel.library.thing%2Ft1") .body(Body::empty()) .unwrap(), ) .await .unwrap(); assert_eq!(resp.status(), StatusCode::BAD_REQUEST); let body = axum::body::to_bytes(resp.into_body(), usize::MAX) .await .unwrap(); let json: serde_json::Value = serde_json::from_slice(&body).unwrap(); assert_eq!(json["error"], "InvalidRequest");}
#[tokio::test]async fn get_part_file_missing_part_is_not_found() { let state = state().await; let app = crate::appview::router().with_state(state); let resp = app .oneshot( Request::builder() .uri("/xrpc/space.polymodel.library.getPartFile?uri=at%3A%2F%2Fdid%3Aplc%3Ax%2Fspace.polymodel.library.part%2Fnone") .body(Body::empty()) .unwrap(), ) .await .unwrap(); assert_eq!(resp.status(), StatusCode::NOT_FOUND); let body = axum::body::to_bytes(resp.into_body(), usize::MAX) .await .unwrap(); let json: serde_json::Value = serde_json::from_slice(&body).unwrap(); assert_eq!(json["error"], "RecordNotFound");}
#[tokio::test]async fn get_part_file_streams_format_matrix_with_exact_download_metadata() { let cases = [ ("stl", "model/stl", "Bracket.stl"), ("obj", "model/obj", "Bracket.obj"), ("gltf", "model/gltf+json", "Bracket.gltf"), ("glb", "model/gltf-binary", "Bracket.glb"), ("3mf", "model/3mf", "Bracket.3mf"), ("ldraw", "application/x-ldraw", "Bracket.dat"), ];
for (format, mime, filename) in cases { let (pds, server) = loopback_pds(false, None).await; let pool = pool().await; let part_uri = format!("at://{DID_A}/space.polymodel.library.part/download-{format}"); let file = json!({ "mimeType": mime, "size": 4, "chunks": [ {"blob": {"$type": "blob", "ref": {"$link": "bafkreibb44q4gwsyep63iux2f6pquyjmot5zklqgsj2itrvspjb3qf562q"}, "mimeType": mime, "size": 2}, "offset": 2, "size": 2}, {"blob": {"$type": "blob", "ref": {"$link": "bafkreih3ryqpylsmh4siyygdtplff46bgrzjro4xpofu2widxbifkyqgam"}, "mimeType": mime, "size": 2}, "offset": 0, "size": 2} ] }); sqlx::query("INSERT INTO parts (did, rkey, uri, cid, name, format, file_json, created_at, indexed_at, record_json) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") .bind(DID_A) .bind(format!("download-{format}")) .bind(&part_uri) .bind("part-cid") .bind(filename) .bind(format) .bind(file.to_string()) .bind(1_i64) .bind(1_i64) .bind(file!()) .execute(&pool) .await .unwrap(); let bootstrap = crate::oauth::bootstrap_oauth(pool.clone(), Some("http://localhost")) .expect("ephemeral OAuth bootstrap for tests"); let state = AppState::new_with_resolver(pool, bootstrap, loopback_resolver(&pds)); let app = crate::appview::router().with_state(state); let resp = app .oneshot( Request::builder() .uri(format!( "/xrpc/space.polymodel.library.getPartFile?uri={}", urlencoding::encode(&part_uri) )) .body(Body::empty()) .unwrap(), ) .await .unwrap(); assert_eq!(resp.status(), StatusCode::OK, "{format}"); assert_eq!(resp.headers()["content-type"], mime, "{format}"); assert_eq!(resp.headers()["content-length"], "4", "{format}"); assert_eq!( resp.headers()["content-disposition"], format!("attachment; filename=\"{filename}\""), "{format}" ); assert_eq!(body_text(resp).await, "abcd", "{format}"); server.abort(); }}
#[tokio::test]async fn get_part_file_returns_500_when_first_blob_fetch_fails() { let (pds, server) = loopback_pds(true, None).await; let pool = pool().await; let part_uri = format!("at://{DID_A}/space.polymodel.library.part/download"); let file = json!({ "mimeType": "model/stl", "size": 2, "chunks": [{"blob": {"$type": "blob", "ref": {"$link": "bafkreih3ryqpylsmh4siyygdtplff46bgrzjro4xpofu2widxbifkyqgam"}, "mimeType": "model/stl", "size": 2}, "offset": 0, "size": 2}] }); sqlx::query("INSERT INTO parts (did, rkey, uri, cid, name, format, file_json, created_at, indexed_at, record_json) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") .bind(DID_A).bind("download").bind(&part_uri).bind("part-cid").bind("Bracket.stl") .bind("stl").bind(file.to_string()).bind(1_i64).bind(1_i64).bind(file!()) .execute(&pool).await.unwrap(); let bootstrap = crate::oauth::bootstrap_oauth(pool.clone(), Some("http://localhost")) .expect("ephemeral OAuth bootstrap for tests"); let state = AppState::new_with_resolver(pool, bootstrap, loopback_resolver(&pds)); let app = crate::appview::router().with_state(state); let resp = app .oneshot( Request::builder() .uri(format!( "/xrpc/space.polymodel.library.getPartFile?uri={}", urlencoding::encode(&part_uri) )) .body(Body::empty()) .unwrap(), ) .await .unwrap(); assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR); let body = body_text(resp).await; let error: serde_json::Value = serde_json::from_str(&body).unwrap(); assert_eq!(error["error"], "InternalServerError"); assert!( error["message"] .as_str() .is_some_and(|message| message.contains("blob fetch")) ); server.abort();}
#[tokio::test]async fn get_part_file_later_blob_failure_truncates_committed_stream() { let failed_cid = "bafkreibb44q4gwsyep63iux2f6pquyjmot5zklqgsj2itrvspjb3qf562q"; let (pds, server) = loopback_pds(false, Some(failed_cid.to_string())).await; let pool = pool().await; let part_uri = format!("at://{DID_A}/space.polymodel.library.part/download"); let file = json!({ "mimeType": "model/stl", "size": 4, "chunks": [ {"blob": {"$type": "blob", "ref": {"$link": failed_cid}, "mimeType": "model/stl", "size": 2}, "offset": 2, "size": 2}, {"blob": {"$type": "blob", "ref": {"$link": "bafkreih3ryqpylsmh4siyygdtplff46bgrzjro4xpofu2widxbifkyqgam"}, "mimeType": "model/stl", "size": 2}, "offset": 0, "size": 2} ] }); sqlx::query("INSERT INTO parts (did, rkey, uri, cid, name, format, file_json, created_at, indexed_at, record_json) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") .bind(DID_A).bind("download").bind(&part_uri).bind("part-cid").bind("Bracket.stl") .bind("stl").bind(file.to_string()).bind(1_i64).bind(1_i64).bind(file!()) .execute(&pool).await.unwrap(); let bootstrap = crate::oauth::bootstrap_oauth(pool.clone(), Some("http://localhost")) .expect("ephemeral OAuth bootstrap for tests"); let state = AppState::new_with_resolver(pool, bootstrap, loopback_resolver(&pds)); let app = crate::appview::router().with_state(state); let resp = app .oneshot( Request::builder() .uri(format!( "/xrpc/space.polymodel.library.getPartFile?uri={}", urlencoding::encode(&part_uri) )) .body(Body::empty()) .unwrap(), ) .await .unwrap(); if resp.status() != StatusCode::OK { let status = resp.status(); let body = body_text(resp).await; panic!("expected successful streaming response, got {status}: {body}"); } assert_eq!(resp.headers()["content-length"], "4"); let mut body = resp.into_body(); let mut bytes = Vec::new(); let mut stream_error = false; while let Some(frame) = body.frame().await { match frame { Ok(frame) => { if let Ok(data) = frame.into_data() { bytes.extend_from_slice(&data); } } Err(_) => { stream_error = true; break; } } } assert!( stream_error, "later PDS failure must surface as a body error" ); assert_eq!(&bytes[..], b"ab"); server.abort();}
#[tokio::test]async fn anonymous_model_bundle_surface_is_present_without_legacy_routes_or_route_rows() { let state = state().await; let pool = state.pool.clone(); let app = crate::appview::router().with_state(state);
let response = app .clone() .oneshot( Request::builder() .method(Method::POST) .uri("/app/model-load-bundle") .header("content-type", "application/json") .body(Body::from( r#"{"uri":"at://did:plc:x/space.polymodel.library.part/main"}"#, )) .unwrap(), ) .await .unwrap(); assert_eq!(response.status(), StatusCode::NOT_FOUND);
for (method, path, body) in [ ( Method::GET, "/app/parts/did:plc:x/abc/download", Body::empty(), ), (Method::GET, "/app/ldraw/did:plc:x/abc", Body::empty()), ( Method::GET, "/xrpc/space.polymodel.library.ldrawResource?uri=at%3A%2F%2Fdid%3Aplc%3Ax%2Fresource%2Fabc", Body::empty(), ), ( Method::GET, "/xrpc/space.polymodel.library.getLdrawResource?uri=at%3A%2F%2Fdid%3Aplc%3Ax%2Fresource%2Fabc", Body::empty(), ), ( Method::POST, "/xrpc/space.polymodel.library.mintLdrawResource", Body::from("{}"), ), ] { let response = app .clone() .oneshot( Request::builder() .method(method.clone()) .uri(path) .body(body) .unwrap(), ) .await .unwrap(); assert_eq!( response.status(), StatusCode::NOT_FOUND, "legacy route must stay absent: {method} {path}" ); }
for table in [ "ldraw_resources", "ldraw_manifest_files", "ldraw_verification", "ldraw_official_snapshots", "ldraw_legacy_resources", ] { let exists: Option<String> = sqlx::query_scalar("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?") .bind(table) .fetch_optional(&pool) .await .unwrap(); assert!( exists.is_some(), "PM-76 projection table must remain: {table}" ); } let routes: Option<String> = sqlx::query_scalar( "SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'ldraw_routes'", ) .fetch_optional(&pool) .await .unwrap(); assert!( routes.is_none(), "public compound routes must remain stateless" );}