126 lines
4.2 KiB
Rust
126 lines
4.2 KiB
Rust
//! Integration tests for the admin overview aggregates endpoint
|
|
//! (`GET /api/v1/admin/overview`). Auth gating mirrors the system tab;
|
|
//! the aggregate counts are asserted against seeded data.
|
|
|
|
mod common;
|
|
|
|
use axum::http::StatusCode;
|
|
use axum::Router;
|
|
use serde_json::json;
|
|
use sqlx::PgPool;
|
|
use tower::ServiceExt;
|
|
|
|
use mangalord::repo;
|
|
|
|
async fn seed_admin(pool: &PgPool, app: &Router) -> String {
|
|
let (username, cookie) = common::register_user(app).await;
|
|
let u = repo::user::find_by_username(pool, &username)
|
|
.await
|
|
.unwrap()
|
|
.unwrap();
|
|
repo::user::set_is_admin_unchecked(pool, u.id, true).await.unwrap();
|
|
cookie
|
|
}
|
|
|
|
/// Seed a manga → chapter with `n` pages; mark the first `analyzed` of
|
|
/// them as a `done` page_analysis. Returns the page ids.
|
|
async fn seed_manga_pages(pool: &PgPool, title: &str, n: i32, analyzed: i32) -> Vec<uuid::Uuid> {
|
|
let manga_id: uuid::Uuid =
|
|
sqlx::query_scalar("INSERT INTO mangas (title) VALUES ($1) RETURNING id")
|
|
.bind(title)
|
|
.fetch_one(pool)
|
|
.await
|
|
.unwrap();
|
|
let chapter_id: uuid::Uuid =
|
|
sqlx::query_scalar("INSERT INTO chapters (manga_id, number) VALUES ($1, 1) RETURNING id")
|
|
.bind(manga_id)
|
|
.fetch_one(pool)
|
|
.await
|
|
.unwrap();
|
|
let mut ids = Vec::new();
|
|
for i in 1..=n {
|
|
let id: uuid::Uuid = sqlx::query_scalar(
|
|
"INSERT INTO pages (chapter_id, page_number, storage_key, content_type) \
|
|
VALUES ($1, $2, $3, 'image/png') RETURNING id",
|
|
)
|
|
.bind(chapter_id)
|
|
.bind(i)
|
|
.bind(format!("k/{manga_id}/{i}.png"))
|
|
.fetch_one(pool)
|
|
.await
|
|
.unwrap();
|
|
if i <= analyzed {
|
|
sqlx::query("INSERT INTO page_analysis (page_id, status) VALUES ($1, 'done')")
|
|
.bind(id)
|
|
.execute(pool)
|
|
.await
|
|
.unwrap();
|
|
}
|
|
ids.push(id);
|
|
}
|
|
ids
|
|
}
|
|
|
|
#[sqlx::test(migrations = "./migrations")]
|
|
async fn requires_admin(pool: PgPool) {
|
|
let h = common::harness(pool);
|
|
let (_u, cookie) = common::register_user(&h.app).await;
|
|
let resp = h
|
|
.app
|
|
.oneshot(common::get_with_cookie("/api/v1/admin/overview", &cookie))
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(resp.status(), StatusCode::FORBIDDEN);
|
|
}
|
|
|
|
#[sqlx::test(migrations = "./migrations")]
|
|
async fn unauthenticated_request_is_rejected(pool: PgPool) {
|
|
let h = common::harness(pool);
|
|
let resp = h
|
|
.app
|
|
.oneshot(common::get("/api/v1/admin/overview"))
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(resp.status(), StatusCode::UNAUTHORIZED);
|
|
}
|
|
|
|
#[sqlx::test(migrations = "./migrations")]
|
|
async fn aggregates_users_mangas_and_coverage(pool: PgPool) {
|
|
let h = common::harness(pool.clone());
|
|
// seed_admin registers one user and promotes it; register a second
|
|
// (non-admin) user so the counts have a known split.
|
|
let cookie = seed_admin(&pool, &h.app).await;
|
|
let _ = common::register_user(&h.app).await;
|
|
|
|
// Two mangas: 3 pages with 2 analyzed, and 2 pages with 0 analyzed.
|
|
seed_manga_pages(&pool, "Alpha", 3, 2).await;
|
|
seed_manga_pages(&pool, "Beta", 2, 0).await;
|
|
|
|
let resp = h
|
|
.app
|
|
.oneshot(common::get_with_cookie("/api/v1/admin/overview", &cookie))
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(resp.status(), StatusCode::OK);
|
|
let body = common::body_json(resp).await;
|
|
|
|
let users = body.get("users").expect("users key");
|
|
assert_eq!(users["total"], json!(2));
|
|
assert_eq!(users["admins"], json!(1));
|
|
assert!(users["newest_username"].is_string());
|
|
|
|
let mangas = body.get("mangas").expect("mangas key");
|
|
assert_eq!(mangas["total"], json!(2));
|
|
// Uploaded mangas (no manga_sources) classify as synced.
|
|
assert_eq!(mangas["synced"], json!(2));
|
|
assert_eq!(mangas["in_progress"], json!(0));
|
|
assert_eq!(mangas["dropped"], json!(0));
|
|
assert_eq!(mangas["total_chapters"], json!(2));
|
|
assert_eq!(mangas["total_pages"], json!(5));
|
|
assert!(mangas["newest_title"].is_string());
|
|
|
|
let analysis = body.get("analysis").expect("analysis key");
|
|
assert_eq!(analysis["total_pages"], json!(5));
|
|
assert_eq!(analysis["analyzed_pages"], json!(2));
|
|
}
|