Files
biggus-dickus/crates/api/tests/public.rs
T

178 lines
5.3 KiB
Rust

use api::{AppState, build_app};
use axum::body::Body;
use axum::http::{Request, StatusCode};
use db::catalog;
use domain::{AuditActor, ObjectInput, Visibility};
use http_body_util::BodyExt;
use sqlx::PgPool;
use tower::ServiceExt; // for `oneshot`
fn state(pool: PgPool) -> AppState {
AppState {
db: db::Db::from_pool(pool),
app_name: "Test".to_string(),
}
}
fn object(number: &str, name: &str, visibility: Visibility) -> ObjectInput {
ObjectInput {
object_number: number.into(),
object_name: name.into(),
number_of_objects: 1,
brief_description: Some("a description".into()),
current_location: Some("vault B".into()), // never-public; must NOT appear in output
current_owner: Some("the museum".into()), // never-public
recorder: None,
recording_date: None,
visibility,
}
}
async fn body_json(resp: axum::http::Response<Body>) -> serde_json::Value {
let bytes = resp.into_body().collect().await.unwrap().to_bytes();
serde_json::from_slice(&bytes).unwrap()
}
#[sqlx::test(migrations = "../db/migrations")]
async fn list_returns_only_public_as_public_view(pool: PgPool) {
let db = db::Db::from_pool(pool.clone());
let mut tx = db.pool().begin().await.unwrap();
catalog::create_object(
&mut tx,
AuditActor::System,
&object("D-1", "draft vase", Visibility::Draft),
)
.await
.unwrap();
catalog::create_object(
&mut tx,
AuditActor::System,
&object("P-1", "public vase", Visibility::Public),
)
.await
.unwrap();
tx.commit().await.unwrap();
let app = build_app(state(pool));
let resp = app
.oneshot(
Request::builder()
.uri("/api/public/objects")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
let json = body_json(resp).await;
assert_eq!(json["total"], 1);
assert_eq!(json["items"].as_array().unwrap().len(), 1);
let item = &json["items"][0];
assert_eq!(item["object_number"], "P-1");
assert_eq!(item["object_name"], "public vase");
assert_eq!(item["brief_description"], "a description");
assert!(item.get("current_location").is_none());
assert!(item.get("current_owner").is_none());
assert!(item.get("recorder").is_none());
assert!(item.get("visibility").is_none());
}
#[sqlx::test(migrations = "../db/migrations")]
async fn get_public_object_returns_it(pool: PgPool) {
let db = db::Db::from_pool(pool.clone());
let mut tx = db.pool().begin().await.unwrap();
let id = catalog::create_object(
&mut tx,
AuditActor::System,
&object("P-1", "public vase", Visibility::Public),
)
.await
.unwrap();
tx.commit().await.unwrap();
let app = build_app(state(pool));
let resp = app
.oneshot(
Request::builder()
.uri(format!("/api/public/objects/{id}"))
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
let json = body_json(resp).await;
assert_eq!(json["object_number"], "P-1");
assert!(json.get("current_location").is_none());
}
#[sqlx::test(migrations = "../db/migrations")]
async fn non_public_objects_are_404(pool: PgPool) {
let db = db::Db::from_pool(pool.clone());
let mut tx = db.pool().begin().await.unwrap();
let draft = catalog::create_object(
&mut tx,
AuditActor::System,
&object("D-1", "draft vase", Visibility::Draft),
)
.await
.unwrap();
let internal = catalog::create_object(
&mut tx,
AuditActor::System,
&object("I-1", "internal vase", Visibility::Internal),
)
.await
.unwrap();
tx.commit().await.unwrap();
// both non-public states are hidden behind a 404 — not 403 — so existence isn't leaked
let app = build_app(state(pool));
for id in [draft, internal] {
let resp = app
.clone()
.oneshot(
Request::builder()
.uri(format!("/api/public/objects/{id}"))
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
}
}
#[sqlx::test(migrations = "../db/migrations")]
async fn get_missing_object_is_404(pool: PgPool) {
let app = build_app(state(pool));
let resp = app
.oneshot(
Request::builder()
.uri(format!("/api/public/objects/{}", domain::ObjectId::new()))
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
}
#[sqlx::test(migrations = "../db/migrations")]
async fn openapi_lists_the_public_paths(pool: PgPool) {
let app = build_app(state(pool));
let resp = app
.oneshot(
Request::builder()
.uri("/api-docs/openapi.json")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
let json = body_json(resp).await;
assert!(json["paths"]["/api/public/objects"].is_object());
assert!(json["paths"]["/api/public/objects/{id}"].is_object());
}