// cfg(test) only — this whole module is test-only use sqlx::SqlitePool; use axum::Router; use tower::ServiceExt; use axum::http::{Request, StatusCode}; use http_body_util::BodyExt; /// Insert a test tutor (if not exists), return a valid JWT for that tutor. pub async fn make_token(pool: &SqlitePool, email: &str) -> String { let hash = bcrypt::hash("testpass", bcrypt::DEFAULT_COST).unwrap(); sqlx::query("INSERT OR IGNORE INTO tutors (name,email,password_hash) VALUES (?,?,?)") .bind("Test Tutor").bind(email).bind(&hash) .execute(pool).await.unwrap(); let id: (i64,) = sqlx::query_as("SELECT id FROM tutors WHERE email = ?") .bind(email).fetch_one(pool).await.unwrap(); unsafe { std::env::set_var("JWT_SECRET", "testsecret"); } crate::auth::encode_jwt(id.0, email).unwrap() } /// Build the full Axum app wired with the given pool, plus a Bearer auth header value. pub async fn build_test_app(pool: SqlitePool) -> (Router, String) { unsafe { std::env::set_var("JWT_SECRET", "testsecret"); } let token = make_token(&pool, "tutor@test.com").await; let app = crate::routes::build(pool); (app, format!("Bearer {token}")) } /// POST JSON body to the app (one-shot), returns (StatusCode, response body bytes). pub async fn post_json(app: Router, path: &str, auth: &str, body: serde_json::Value) -> (StatusCode, bytes::Bytes) { let req = Request::builder() .method("POST").uri(path) .header("Content-Type", "application/json") .header("Authorization", auth) .body(axum::body::Body::from(body.to_string())) .unwrap(); let res = app.oneshot(req).await.unwrap(); let status = res.status(); let body = res.into_body().collect().await.unwrap().to_bytes(); (status, body) } /// GET from the app (one-shot), returns (StatusCode, response body bytes). pub async fn get(app: Router, path: &str, auth: &str) -> (StatusCode, bytes::Bytes) { let req = Request::builder() .method("GET").uri(path) .header("Authorization", auth) .body(axum::body::Body::empty()) .unwrap(); let res = app.oneshot(req).await.unwrap(); let status = res.status(); let body = res.into_body().collect().await.unwrap().to_bytes(); (status, body) }