diff --git a/crates/backend/src/controller.rs b/crates/backend/src/controller.rs index 7bb9b1b..ee8e8a5 100644 --- a/crates/backend/src/controller.rs +++ b/crates/backend/src/controller.rs @@ -13,5 +13,8 @@ pub fn register_controllers(cfg: &mut ServiceConfig) { .service(web::scope("/user").configure(user::setup)) .service(web::scope("/class").configure(class::setup)) .service(web::scope("/template").configure(template::setup)) - .service(web::scope("/auth").configure(auth::setup)); + .service(web::scope("/auth").configure(auth::setup)) + .service( + web::resource("ok").to(|| async { actix_web::HttpResponse::Ok().body("available") }), + ); } diff --git a/crates/backend/tests/common/mod.rs b/crates/backend/tests/common/mod.rs index 617e62f..1c3fda3 100644 --- a/crates/backend/tests/common/mod.rs +++ b/crates/backend/tests/common/mod.rs @@ -22,6 +22,12 @@ pub async fn setup() -> (ContainerAsync, ContainerAsync, Databa let postgres_port = postgres.get_host_port_ipv4(5432).await.unwrap(); let redis_port = redis.get_host_port_ipv4(6379).await.unwrap(); + println!("PostgreSQL container started on port: {}", postgres_port); + println!("Redis container started on port: {}", redis_port); + + // Wait for PostgreSQL to be ready + wait_for_postgres_ready(&postgres).await; + unsafe { std::env::set_var("DB_HOST", "127.0.0.1"); std::env::set_var("DB_PORT", postgres_port.to_string()); @@ -32,12 +38,48 @@ pub async fn setup() -> (ContainerAsync, ContainerAsync, Databa std::env::set_var("REDIS_PORT", redis_port.to_string()); } - tokio::time::sleep(tokio::time::Duration::from_secs(2)).await; - let database_url = build_database_url(); + println!("Database URL: {}", database_url); + let database = Database::new(database_url.into()).await.unwrap(); Migrator::up(database.connection(), None).await.unwrap(); (postgres, redis, database) } + +async fn wait_for_postgres_ready(container: &ContainerAsync) { + use sea_orm::{Database as SeaOrmDatabase, DbErr}; + + println!("Waiting for PostgreSQL to be ready..."); + + let postgres_port = container.get_host_port_ipv4(5432).await.unwrap(); + let connection_string = format!( + "postgresql://postgres:postgres@127.0.0.1:{}/test_db", + postgres_port + ); + + for attempt in 1..=30 { + match SeaOrmDatabase::connect(&connection_string).await { + Ok(conn) => match conn.ping().await { + Ok(_) => { + println!("PostgreSQL is ready after {} attempts", attempt); + return; + } + Err(_) => { + println!("Attempt {}: PostgreSQL connection failed ping", attempt); + } + }, + Err(DbErr::Conn(_)) => { + println!("Attempt {}: PostgreSQL connection refused", attempt); + } + Err(_) => { + println!("Attempt {}: PostgreSQL other error", attempt); + } + } + + tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; + } + + panic!("PostgreSQL failed to become ready within 30 seconds"); +} diff --git a/crates/backend/tests/endpoints/auth.rs b/crates/backend/tests/endpoints/auth.rs index a887338..1d72664 100644 --- a/crates/backend/tests/endpoints/auth.rs +++ b/crates/backend/tests/endpoints/auth.rs @@ -1,9 +1,54 @@ -use actix_web::{App, test, web}; +use actix_web::{App, http::header, test, web}; use backend::controller; +use serde::{Deserialize, Serialize}; use crate::common::test_helpers::{get_database, with_transaction}; #[cfg(test)] mod tests { + use serde_json::json; + use super::*; + + #[derive(Deserialize, Serialize, Debug, Clone)] + struct UserLogin { + username: String, + name: String, + password: String, + } + + #[actix_web::test] + async fn test_login() { + let db = get_database().await; + + let app = test::init_service( + App::new() + .app_data(web::Data::new(db.clone())) + .service(web::scope("/api/v1").configure(controller::register_controllers)), + ) + .await; + + let req = test::TestRequest::post() + .uri("/api/v1/user") + .insert_header(header::ContentType::json()) + .set_payload( + json!({ + "username": "testuser", + "name": "Test User", + "password": "password" + }) + .to_string(), + ) + .send_request(&app) + .await; + + let status = req.status(); + let body = test::read_body(req).await; + let body_str = String::from_utf8_lossy(&body); + + println!("Response status: {}", status); + println!("Response body: {}", body_str); + + assert!(status.is_success() || status.is_client_error()); + } } diff --git a/crates/backend/tests/integration_tests.rs b/crates/backend/tests/integration_tests.rs index 996e997..43f5d53 100644 --- a/crates/backend/tests/integration_tests.rs +++ b/crates/backend/tests/integration_tests.rs @@ -20,10 +20,21 @@ mod tests { ) .await; - let req = test::TestRequest::get().uri("/api/v1/user").to_request(); - let resp = test::call_service(&app, req).await; + let resp = test::TestRequest::get() + .uri("/api/v1/ok") + .send_request(&app) + .await; - assert!(resp.status().is_success() || resp.status().is_client_error()); + let resp_status = resp.status(); + + let resp_body = test::read_body(resp).await; + let resp_body_str = String::from_utf8_lossy(&resp_body); + assert!( + resp_body_str.contains("available"), + "Expected 'available' in response body" + ); + + assert!(resp_status.is_success(), "Expected success response"); }) .await; }