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.
This commit is contained in:
@@ -11,88 +11,31 @@
|
||||
//! channel through an HTTP test would require reading a never-ending
|
||||
//! body, which these tests deliberately avoid.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
mod common;
|
||||
|
||||
use axum::body::Body;
|
||||
use axum::http::{Request, StatusCode, header};
|
||||
use tower::util::ServiceExt;
|
||||
|
||||
use doctate_server::config::{Config, User};
|
||||
use common::{TestConfig, get_with_cookie, header_opt, paths, test_user};
|
||||
|
||||
fn unique_data_path() -> PathBuf {
|
||||
std::env::temp_dir().join(format!(
|
||||
"doctate-sse-test-{}-{}",
|
||||
std::process::id(),
|
||||
uuid::Uuid::new_v4()
|
||||
))
|
||||
}
|
||||
|
||||
fn make_user(slug: &str) -> User {
|
||||
User {
|
||||
slug: slug.into(),
|
||||
api_key: format!("key-{slug}"),
|
||||
// Password "s" — matches the login helper below.
|
||||
web_password: bcrypt::hash("s", 4).unwrap(),
|
||||
role: "doctor".into(),
|
||||
whisper: Default::default(),
|
||||
retention: Default::default(),
|
||||
window_hours: 72,
|
||||
preview_lines: 2,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_config(data_path: PathBuf) -> Arc<Config> {
|
||||
let users = vec![make_user("alice")];
|
||||
let api_keys: HashMap<String, String> = users
|
||||
.iter()
|
||||
.map(|u| (u.api_key.clone(), u.slug.clone()))
|
||||
.collect();
|
||||
Arc::new(Config {
|
||||
data_path,
|
||||
users,
|
||||
api_keys,
|
||||
..Config::test_default()
|
||||
})
|
||||
}
|
||||
|
||||
/// Log in via POST /web/login and return the resulting `session=…` cookie
|
||||
/// header value. Mirrors the helper in the other integration tests.
|
||||
async fn login(app: axum::Router, slug: &str) -> String {
|
||||
let body = format!("slug={slug}&password=s");
|
||||
let resp = app
|
||||
.oneshot(
|
||||
Request::builder()
|
||||
.method("POST")
|
||||
.uri("/web/login")
|
||||
.header(header::CONTENT_TYPE, "application/x-www-form-urlencoded")
|
||||
.body(Body::from(body))
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
for v in resp.headers().get_all(header::SET_COOKIE).iter() {
|
||||
let s = v.to_str().unwrap();
|
||||
if let Some(pair) = s.split(';').next()
|
||||
&& pair.starts_with("session=")
|
||||
{
|
||||
return pair.to_string();
|
||||
}
|
||||
}
|
||||
panic!("no session cookie after login");
|
||||
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 config = build_config(unique_data_path());
|
||||
let app = doctate_server::create_router(config);
|
||||
let app = test_app();
|
||||
|
||||
let resp = app
|
||||
.oneshot(
|
||||
Request::builder()
|
||||
.method("GET")
|
||||
.uri("/web/events")
|
||||
.uri(paths::EVENTS)
|
||||
.body(Body::empty())
|
||||
.unwrap(),
|
||||
)
|
||||
@@ -100,38 +43,24 @@ async fn events_without_session_redirects_to_login() {
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(resp.status(), StatusCode::FOUND);
|
||||
let location = resp
|
||||
.headers()
|
||||
.get(header::LOCATION)
|
||||
.and_then(|v| v.to_str().ok())
|
||||
.unwrap_or("");
|
||||
assert_eq!(location, "/web/login");
|
||||
assert_eq!(
|
||||
header_opt(&resp, header::LOCATION.as_str()),
|
||||
Some(paths::LOGIN)
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn events_with_session_returns_sse_content_type() {
|
||||
let config = build_config(unique_data_path());
|
||||
let app = doctate_server::create_router(config);
|
||||
let cookie = login(app.clone(), "alice").await;
|
||||
let app = test_app();
|
||||
let cookie = common::login(&app, "alice", "s").await;
|
||||
|
||||
let resp = app
|
||||
.oneshot(
|
||||
Request::builder()
|
||||
.method("GET")
|
||||
.uri("/web/events")
|
||||
.header(header::COOKIE, cookie)
|
||||
.body(Body::empty())
|
||||
.unwrap(),
|
||||
)
|
||||
.oneshot(get_with_cookie(paths::EVENTS, &cookie))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
let ct = resp
|
||||
.headers()
|
||||
.get(header::CONTENT_TYPE)
|
||||
.and_then(|v| v.to_str().ok())
|
||||
.unwrap_or("");
|
||||
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:?}"
|
||||
|
||||
Reference in New Issue
Block a user