//! Integration tests for the `/web/events` SSE route. //! //! We test two things end-to-end: //! 1. Without a session cookie, the route redirects to the login page //! (the web-auth extractor's standard rejection). //! 2. With a valid session, the route returns a streaming response with //! `Content-Type: text/event-stream`. //! //! Actual event-filtering logic (per-user scoping, admin sees-all) is //! covered at the unit level in `src/events.rs`; wiring the broadcast //! channel through an HTTP test would require reading a never-ending //! body, which these tests deliberately avoid. mod common; use axum::body::Body; use axum::http::{Request, StatusCode, header}; use tower::util::ServiceExt; use common::{TestConfig, get_with_cookie, header_opt, paths, test_user}; fn test_app() -> axum::Router { let cfg = TestConfig::new() .with_label("sse") .with_user(test_user("alice")) .build(); doctate_server::create_router(cfg) } #[tokio::test] async fn events_without_session_redirects_to_login() { let app = test_app(); let resp = app .oneshot( Request::builder() .method("GET") .uri(paths::EVENTS) .body(Body::empty()) .unwrap(), ) .await .unwrap(); assert_eq!(resp.status(), StatusCode::FOUND); assert_eq!( header_opt(&resp, header::LOCATION.as_str()), Some(paths::LOGIN) ); } #[tokio::test] async fn events_with_session_returns_sse_content_type() { let app = test_app(); let cookie = common::login(&app, "alice", "s").await; let resp = app .oneshot(get_with_cookie(paths::EVENTS, &cookie)) .await .unwrap(); assert_eq!(resp.status(), StatusCode::OK); let ct = header_opt(&resp, header::CONTENT_TYPE.as_str()).unwrap_or(""); assert!( ct.starts_with("text/event-stream"), "expected text/event-stream, got {ct:?}" ); }