Files
doctate/server/tests/sse_integration.rs
T
Brummel af3377a6bc refactor(tests): migrate remaining batches to tests/common/
Finishes the lift of shared helpers into `tests/common/`. Covered:
- health, web, oneliners_api, upload (31 tests; upload exercises the
  new `multipart_upload_body` helper driven by doctate_common field
  constants)
- sse_integration, sse_cleanup, transcribe, oneliner_heal_decoupled,
  silent_case_empty, failed_only_case_empty_oneliner,
  transient_failure_retries (24 tests)

Also applied cargo fmt across the test tree and fixed one clippy
needless_borrows_for_generic_args warning in analyze_test.

All 387 tests pass; 3 ignored (as before).

Side effect: health_test previously used a hardcoded `/tmp/doctate-test`
data path, which parallel `cargo test` runs could collide on. The
migration replaces it with the common unique-tmpdir pattern, removing
a latent flake.
2026-04-22 10:51:33 +02:00

69 lines
1.9 KiB
Rust

//! 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:?}"
);
}