mod common; use axum::http::StatusCode; use common::{ delete_authed, get, get_authed, patch_json_authed, post_json, post_json_authed, put_json_authed, response_body, setup_app, setup_app_with_auth, }; use tower::ServiceExt; #[tokio::test] async fn list_sync_devices_empty() { let (app, _, _, viewer) = setup_app_with_auth().await; let resp = app .clone() .oneshot(get_authed("/api/v1/sync/devices", &viewer)) .await .unwrap(); assert_eq!(resp.status(), StatusCode::OK); let body = response_body(resp).await; let devices = body.as_array().expect("array response"); assert!(devices.is_empty()); } #[tokio::test] async fn get_changes_sync_disabled() { // Default config has sync.enabled = false; endpoint should reject let (app, _, _, viewer) = setup_app_with_auth().await; let resp = app .clone() .oneshot(get_authed("/api/v1/sync/changes", &viewer)) .await .unwrap(); assert_eq!(resp.status(), StatusCode::BAD_REQUEST); } #[tokio::test] async fn list_conflicts_requires_device_token() { // list_conflicts requires X-Device-Token header; omitting it returns 400 let (app, _, _, viewer) = setup_app_with_auth().await; let resp = app .clone() .oneshot(get_authed("/api/v1/sync/conflicts", &viewer)) .await .unwrap(); assert_eq!(resp.status(), StatusCode::BAD_REQUEST); } #[tokio::test] async fn register_device_requires_auth() { let (app, ..) = setup_app_with_auth().await; let resp = app .clone() .oneshot(post_json( "/api/v1/sync/devices", r#"{"name":"test","device_type":"desktop","client_version":"0.3.0"}"#, )) .await .unwrap(); assert_eq!(resp.status(), StatusCode::UNAUTHORIZED); } #[tokio::test] async fn register_device_requires_editor() { let (app, _, _, viewer) = setup_app_with_auth().await; let resp = app .clone() .oneshot(post_json_authed( "/api/v1/sync/devices", r#"{"name":"test","device_type":"desktop","client_version":"0.3.0"}"#, &viewer, )) .await .unwrap(); assert_eq!(resp.status(), StatusCode::FORBIDDEN); } #[tokio::test] async fn update_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); } #[tokio::test] async fn delete_device_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/sync/devices/{fake_id}"), &viewer, )) .await .unwrap(); assert_eq!(resp.status(), StatusCode::FORBIDDEN); } #[tokio::test] async fn update_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}"), r#"{"title":"new"}"#, &viewer, )) .await .unwrap(); assert_eq!(resp.status(), StatusCode::FORBIDDEN); } #[tokio::test] async fn media_list_no_auth() { let app = setup_app().await; let resp = app.oneshot(get("/api/v1/media")).await.unwrap(); assert_eq!(resp.status(), StatusCode::OK); }