mod common; use axum::http::StatusCode; use common::{ delete_authed, get, get_authed, patch_json_authed, post_json_authed, put_json_authed, response_body, setup_app, setup_app_with_auth, }; use tower::ServiceExt; #[tokio::test] async fn media_count_empty() { let app = setup_app().await; let resp = app.oneshot(get("/api/v1/media/count")).await.unwrap(); assert_eq!(resp.status(), StatusCode::OK); let body = response_body(resp).await; assert_eq!(body["count"], 0); } #[tokio::test] async fn batch_delete_empty_ids() { let (app, admin, ..) = setup_app_with_auth().await; let resp = app .clone() .oneshot(post_json_authed( "/api/v1/media/batch/delete", r#"{"ids":[]}"#, &admin, )) .await .unwrap(); // Empty ids should be rejected (validation requires 1+ items) assert!( resp.status() == StatusCode::BAD_REQUEST || resp.status() == StatusCode::UNPROCESSABLE_ENTITY ); } #[tokio::test] async fn batch_delete_requires_editor() { let (app, _, _, viewer) = setup_app_with_auth().await; let fake_id = uuid::Uuid::now_v7(); let body = format!(r#"{{"ids":["{fake_id}"]}}"#); let resp = app .clone() .oneshot(post_json_authed( "/api/v1/media/batch/delete", &body, &viewer, )) .await .unwrap(); assert_eq!(resp.status(), StatusCode::FORBIDDEN); } #[tokio::test] async fn list_trash_empty() { let (app, _, editor, _) = setup_app_with_auth().await; let resp = app .clone() .oneshot(get_authed("/api/v1/trash?offset=0&limit=50", &editor)) .await .unwrap(); assert_eq!(resp.status(), StatusCode::OK); let body = response_body(resp).await; assert_eq!(body["total_count"], 0); let items = body["items"].as_array().expect("items array"); assert!(items.is_empty()); } #[tokio::test] async fn batch_tag_requires_editor() { let (app, _, _, viewer) = setup_app_with_auth().await; let resp = app .clone() .oneshot(post_json_authed( "/api/v1/media/batch/tag", r#"{"media_ids":[],"tag_ids":[]}"#, &viewer, )) .await .unwrap(); assert_eq!(resp.status(), StatusCode::FORBIDDEN); } #[tokio::test] async fn list_trash_requires_editor() { let (app, _, _, viewer) = setup_app_with_auth().await; let resp = app .clone() .oneshot(get_authed("/api/v1/trash", &viewer)) .await .unwrap(); assert_eq!(resp.status(), StatusCode::FORBIDDEN); } #[tokio::test] async fn rename_media_requires_editor() { let (app, _, _, viewer) = setup_app_with_auth().await; let fake_id = uuid::Uuid::now_v7(); let resp = app .clone() .oneshot(patch_json_authed( &format!("/api/v1/media/{fake_id}/rename"), r#"{"new_name":"renamed.txt"}"#, &viewer, )) .await .unwrap(); assert_eq!(resp.status(), StatusCode::FORBIDDEN); } #[tokio::test] async fn permanent_delete_requires_editor() { let (app, _, _, viewer) = setup_app_with_auth().await; let fake_id = uuid::Uuid::now_v7(); let resp = app .clone() .oneshot(delete_authed(&format!("/api/v1/media/{fake_id}"), &viewer)) .await .unwrap(); assert_eq!(resp.status(), StatusCode::FORBIDDEN); } #[tokio::test] async fn update_sync_device_requires_editor() { let (app, _, _, viewer) = setup_app_with_auth().await; let fake_id = uuid::Uuid::now_v7(); let resp = app .clone() .oneshot(put_json_authed( &format!("/api/v1/sync/devices/{fake_id}"), r#"{"name":"renamed"}"#, &viewer, )) .await .unwrap(); assert_eq!(resp.status(), StatusCode::FORBIDDEN); }