//! Entegrasyon testleri için yardımcılar. //! //! Her test kendi geçici veritabanını (`kakeibo_test_`) kullanır ve sonunda siler. //! Gereken: yerel MongoDB çalışıyor olmalı (`npm run db:up`), `.env` içinde `MONGODB_URI`. #![allow(dead_code)] // her test dosyası tüm yardımcıları kullanmaz use axum::{ Router, body::Body, http::{Method, Request, StatusCode, header}, }; use http_body_util::BodyExt; use kakeibo::{ config::{Config, RegistrationMode}, db, routes, state::AppState, }; use mongodb::Database; use serde_json::{Value, json}; use tower::ServiceExt; pub struct TestApp { router: Router, pub db: Database, } /// Oturum açmış bir test kullanıcısı #[derive(Clone)] pub struct Session { pub cookie: String, pub household_id: String, } impl TestApp { /// Kayıt açık (birden fazla hane gerektiren testler için). pub async fn new() -> Self { Self::with_registration(RegistrationMode::Open).await } pub async fn with_registration(registration: RegistrationMode) -> Self { dotenvy::dotenv().ok(); let uri = std::env::var("MONGODB_URI") .expect("MONGODB_URI tanımlı değil (.env dosyasını kontrol edin)"); let base = db::connect(&uri) .await .expect("MongoDB'ye bağlanılamadı — `npm run db:up` çalıştırın"); let name = format!("kakeibo_test_{}", uuid::Uuid::new_v4().simple()); let db = base.client().database(&name); db::prepare(&db).await.expect("test DB hazırlanamadı"); let config = Config { mongodb_uri: uri, jwt_secret: "test-jwt-secret-en-az-32-karakter-olmali!!".into(), app_url: "http://localhost".into(), port: 0, registration, static_dir: None, }; let router = routes::router(AppState::new(db.clone(), config)); Self { router, db } } /// Test sonunda geçici veritabanını siler. pub async fn cleanup(self) { self.db.drop().await.ok(); } /// İstek gönderir; (durum kodu, JSON gövde, set-cookie) döner. pub async fn send( &self, method: Method, path: &str, cookie: Option<&str>, body: Option, ) -> (StatusCode, Value, Option) { let mut req = Request::builder().method(method).uri(format!("/api{path}")); if let Some(c) = cookie { req = req.header(header::COOKIE, c); } let req = match body { Some(b) => req .header(header::CONTENT_TYPE, "application/json") .body(Body::from(b.to_string())), None => req.body(Body::empty()), } .unwrap(); let res = self.router.clone().oneshot(req).await.unwrap(); let status = res.status(); let set_cookie = res .headers() .get(header::SET_COOKIE) .and_then(|v| v.to_str().ok()) .and_then(|v| v.split(';').next()) .map(String::from); let bytes = res.into_body().collect().await.unwrap().to_bytes(); let json = serde_json::from_slice(&bytes).unwrap_or(Value::Null); (status, json, set_cookie) } pub async fn get(&self, path: &str, s: &Session) -> (StatusCode, Value) { let (st, v, _) = self.send(Method::GET, path, Some(&s.cookie), None).await; (st, v) } pub async fn post(&self, path: &str, s: &Session, body: Value) -> (StatusCode, Value) { let (st, v, _) = self .send(Method::POST, path, Some(&s.cookie), Some(body)) .await; (st, v) } pub async fn patch(&self, path: &str, s: &Session, body: Value) -> (StatusCode, Value) { let (st, v, _) = self .send(Method::PATCH, path, Some(&s.cookie), Some(body)) .await; (st, v) } pub async fn put(&self, path: &str, s: &Session, body: Value) -> (StatusCode, Value) { let (st, v, _) = self .send(Method::PUT, path, Some(&s.cookie), Some(body)) .await; (st, v) } pub async fn delete(&self, path: &str, s: &Session) -> (StatusCode, Value) { let (st, v, _) = self.send(Method::DELETE, path, Some(&s.cookie), None).await; (st, v) } /// Yeni kullanıcı kaydeder (davet koduyla veya yeni hane olarak) ve oturumunu döner. pub async fn register(&self, name: &str, invite_code: Option<&str>) -> Session { let email = format!( "{}-{}@test.com", name.to_lowercase(), uuid::Uuid::new_v4().simple() ); let (status, body, cookie) = self .send( Method::POST, "/auth/register", None, Some(json!({ "name": name, "email": email, "password": "test-sifre-123", "invite_code": invite_code, })), ) .await; assert_eq!(status, StatusCode::CREATED, "kayıt başarısız: {body}"); Session { cookie: cookie.expect("kayıtta cookie dönmedi"), household_id: body["household"]["id"].as_str().unwrap().to_string(), } } }