pinakes/crates/pinakes-server/tests/webhooks.rs
NotAShelf f1eacc8484
pinakes-server: add more route tests
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ief16a2b3181bfa50193fb69a5ad4a9166a6a6964
2026-03-22 22:05:04 +03:00

136 lines
3.6 KiB
Rust

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;
// GET /api/v1/webhooks (viewer)
#[tokio::test]
async fn list_webhooks_requires_auth() {
let (app, ..) = setup_app_with_auth().await;
let response = app.oneshot(get("/api/v1/webhooks")).await.unwrap();
assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
}
#[tokio::test]
async fn list_webhooks_viewer_ok() {
let (app, _, _, viewer_token) = setup_app_with_auth().await;
let response = app
.oneshot(get_authed("/api/v1/webhooks", &viewer_token))
.await
.unwrap();
let status = response.status();
let body = response_body(response).await;
assert_eq!(status, StatusCode::OK);
// No webhooks configured in test config: empty array
assert!(body.is_array(), "expected array, got: {body}");
assert_eq!(body.as_array().unwrap().len(), 0);
}
#[tokio::test]
async fn list_webhooks_no_auth_disabled_ok() {
// Auth disabled (setup_app): viewer-level route still accessible
let app = setup_app().await;
let response = app.oneshot(get("/api/v1/webhooks")).await.unwrap();
assert_eq!(response.status(), StatusCode::OK);
}
// POST /api/v1/webhooks/test (editor)
#[tokio::test]
async fn test_webhook_requires_editor() {
let (app, _, _, viewer_token) = setup_app_with_auth().await;
let response = app
.oneshot(post_json_authed(
"/api/v1/webhooks/test",
"{}",
&viewer_token,
))
.await
.unwrap();
assert_eq!(response.status(), StatusCode::FORBIDDEN);
}
#[tokio::test]
async fn test_webhook_no_dispatcher_returns_ok() {
// No webhook dispatcher in test setup; route should return 200 with
// "no webhooks configured" message rather than erroring.
let (app, _, editor_token, _) = setup_app_with_auth().await;
let response = app
.oneshot(post_json_authed(
"/api/v1/webhooks/test",
"{}",
&editor_token,
))
.await
.unwrap();
// Either OK or the route returns a structured response about no webhooks
assert!(
response.status() == StatusCode::OK
|| response.status() == StatusCode::BAD_REQUEST
);
}
#[tokio::test]
async fn test_webhook_requires_auth() {
let (app, ..) = setup_app_with_auth().await;
let response = app
.oneshot(post_json_authed("/api/v1/webhooks/test", "{}", "badtoken"))
.await
.unwrap();
assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
}
// RBAC enforcement for editor-level HTTP methods
#[tokio::test]
async fn delete_playlist_requires_editor() {
let (app, _, _, viewer_token) = setup_app_with_auth().await;
let response = app
.oneshot(delete_authed(
"/api/v1/playlists/00000000-0000-0000-0000-000000000000",
&viewer_token,
))
.await
.unwrap();
assert_eq!(response.status(), StatusCode::FORBIDDEN);
}
#[tokio::test]
async fn update_playlist_requires_editor() {
let (app, _, _, viewer_token) = setup_app_with_auth().await;
let response = app
.oneshot(patch_json_authed(
"/api/v1/playlists/00000000-0000-0000-0000-000000000000",
r#"{"name":"updated"}"#,
&viewer_token,
))
.await
.unwrap();
assert_eq!(response.status(), StatusCode::FORBIDDEN);
}
#[tokio::test]
async fn update_sync_device_requires_editor() {
let (app, _, _, viewer_token) = setup_app_with_auth().await;
let response = app
.oneshot(put_json_authed(
"/api/v1/sync/devices/00000000-0000-0000-0000-000000000000",
r#"{"name":"device"}"#,
&viewer_token,
))
.await
.unwrap();
assert_eq!(response.status(), StatusCode::FORBIDDEN);
}