WIP: moved stuff around
This commit is contained in:
parent
fa18724e32
commit
4893cc9e06
7 changed files with 35 additions and 91 deletions
|
@ -16,6 +16,6 @@ pub fn register_controllers(cfg: &mut ServiceConfig) {
|
||||||
.service(web::scope("/template").configure(template::setup))
|
.service(web::scope("/template").configure(template::setup))
|
||||||
.service(web::scope("/auth").configure(auth::setup))
|
.service(web::scope("/auth").configure(auth::setup))
|
||||||
.service(
|
.service(
|
||||||
web::resource("ok").to(|| async { actix_web::HttpResponse::Ok().body("available") }),
|
web::resource("/ok").to(|| async { actix_web::HttpResponse::Ok().body("available") }),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ pub fn setup(cfg: &mut actix_web::web::ServiceConfig) {
|
||||||
pub struct CreateUser {
|
pub struct CreateUser {
|
||||||
#[validate(length(min = 4))]
|
#[validate(length(min = 4))]
|
||||||
/// Username (minimum 4 characters)
|
/// Username (minimum 4 characters)
|
||||||
|
/// TODO: Don't allow spaces, only alphanumeric characters and underscores
|
||||||
username: String,
|
username: String,
|
||||||
/// Full name of the user
|
/// Full name of the user
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -77,10 +78,12 @@ async fn get_user(
|
||||||
responses(
|
responses(
|
||||||
(status = 200, description = "User created successfully", body = entity::user::Model, content_type = "application/json"),
|
(status = 200, description = "User created successfully", body = entity::user::Model, content_type = "application/json"),
|
||||||
(status = 400, description = "Invalid request data or validation error", body = String, content_type = "application/json"),
|
(status = 400, description = "Invalid request data or validation error", body = String, content_type = "application/json"),
|
||||||
|
(status = 409, description = "User already exists", body = String, content_type = "application/json"),
|
||||||
(status = 500, description = "Internal server error", body = String, content_type = "application/json")
|
(status = 500, description = "Internal server error", body = String, content_type = "application/json")
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
#[post("")]
|
#[post("")]
|
||||||
|
// TODO: if a user with the same username already exists, return 409 Conflict
|
||||||
async fn create_user(
|
async fn create_user(
|
||||||
db: web::Data<Database>,
|
db: web::Data<Database>,
|
||||||
user: web::Json<CreateUser>,
|
user: web::Json<CreateUser>,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/*
|
||||||
use crate::common::test_helpers::TestContext;
|
use crate::common::test_helpers::TestContext;
|
||||||
use backend::{Database, db::entity};
|
use backend::{Database, db::entity};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
@ -119,3 +120,4 @@ impl TestContext {
|
||||||
Ok((user, can_login))
|
Ok((user, can_login))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
|
@ -11,7 +11,7 @@ impl TestContext {
|
||||||
) -> Result<entity::user::Model, backend::error::ApiError> {
|
) -> Result<entity::user::Model, backend::error::ApiError> {
|
||||||
let test_id = &self.test_id;
|
let test_id = &self.test_id;
|
||||||
let username = username.unwrap_or_else(|| format!("user_{}", test_id));
|
let username = username.unwrap_or_else(|| format!("user_{}", test_id));
|
||||||
let name = name.unwrap_or_else(|| format!("Test User {}", test_id));
|
let name = name.unwrap_or_else(|| format!("name_{}", test_id));
|
||||||
let password = "password123".to_string();
|
let password = "password123".to_string();
|
||||||
|
|
||||||
let user = db.create_user(name, username, password).await?;
|
let user = db.create_user(name, username, password).await?;
|
||||||
|
@ -23,26 +23,6 @@ impl TestContext {
|
||||||
Ok(user)
|
Ok(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_user_with_password(
|
|
||||||
&self,
|
|
||||||
db: &Database,
|
|
||||||
username: Option<String>,
|
|
||||||
name: Option<String>,
|
|
||||||
password: String,
|
|
||||||
) -> Result<entity::user::Model, backend::error::ApiError> {
|
|
||||||
let test_id = &self.test_id;
|
|
||||||
let username = username.unwrap_or_else(|| format!("user_{}", test_id));
|
|
||||||
let name = name.unwrap_or_else(|| format!("Test User {}", test_id));
|
|
||||||
|
|
||||||
let user = db.create_user(name, username, password).await?;
|
|
||||||
|
|
||||||
if let Ok(mut users) = self.created_users.lock() {
|
|
||||||
users.push(user.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(user)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn create_multiple_users(
|
pub async fn create_multiple_users(
|
||||||
&self,
|
&self,
|
||||||
db: &Database,
|
db: &Database,
|
||||||
|
@ -52,7 +32,7 @@ impl TestContext {
|
||||||
|
|
||||||
for i in 0..count {
|
for i in 0..count {
|
||||||
let username = format!("user_{}_{}", self.test_id, i);
|
let username = format!("user_{}_{}", self.test_id, i);
|
||||||
let name = format!("Test User {} {}", self.test_id, i);
|
let name = format!("name_{}_{}", self.test_id, i);
|
||||||
let user = self.create_user(db, Some(username), Some(name)).await?;
|
let user = self.create_user(db, Some(username), Some(name)).await?;
|
||||||
users.push(user);
|
users.push(user);
|
||||||
}
|
}
|
||||||
|
@ -76,10 +56,8 @@ impl TestContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn assert_user_exists(&self, db: &Database, id: Uuid) -> bool {
|
pub async fn assert_user_exists(&self, db: &Database, id: Uuid) -> bool {
|
||||||
match self.get_user_by_id(db, id).await {
|
dbg!("Check if user exists with ID: {}", id);
|
||||||
Ok(Some(_)) => true,
|
matches!(self.get_user_by_id(db, id).await, Ok(Some(_)))
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn assert_user_count(&self, db: &Database, expected: usize) -> bool {
|
pub async fn assert_user_count(&self, db: &Database, expected: usize) -> bool {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::{thread, time::Duration};
|
||||||
|
|
||||||
use backend::{Database, build_database_url};
|
use backend::{Database, build_database_url};
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
use migration::{Migrator, MigratorTrait};
|
use migration::{Migrator, MigratorTrait};
|
||||||
|
@ -29,6 +31,8 @@ pub async fn setup() -> (ContainerAsync<Postgres>, ContainerAsync<Redis>, Databa
|
||||||
|
|
||||||
// Wait for PostgreSQL to be ready
|
// Wait for PostgreSQL to be ready
|
||||||
wait_for_postgres_ready(&postgres).await;
|
wait_for_postgres_ready(&postgres).await;
|
||||||
|
dbg!("PostgreSQL is ready - Starting to sleep");
|
||||||
|
thread::sleep(Duration::from_secs(10));
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
std::env::set_var("DB_HOST", "127.0.0.1");
|
std::env::set_var("DB_HOST", "127.0.0.1");
|
||||||
|
@ -45,12 +49,12 @@ pub async fn setup() -> (ContainerAsync<Postgres>, ContainerAsync<Redis>, Databa
|
||||||
|
|
||||||
// Configure connection pool for tests
|
// Configure connection pool for tests
|
||||||
let mut opts = ConnectOptions::new(database_url);
|
let mut opts = ConnectOptions::new(database_url);
|
||||||
opts.max_connections(200)
|
opts.max_connections(10)
|
||||||
.min_connections(5)
|
.min_connections(2)
|
||||||
.connect_timeout(std::time::Duration::from_secs(15))
|
.connect_timeout(std::time::Duration::from_secs(30))
|
||||||
.acquire_timeout(std::time::Duration::from_secs(15))
|
.acquire_timeout(std::time::Duration::from_secs(30))
|
||||||
.idle_timeout(std::time::Duration::from_secs(30))
|
.idle_timeout(std::time::Duration::from_secs(60))
|
||||||
.max_lifetime(std::time::Duration::from_secs(300));
|
.max_lifetime(std::time::Duration::from_secs(600));
|
||||||
|
|
||||||
let database = Database::new(opts).await.unwrap();
|
let database = Database::new(opts).await.unwrap();
|
||||||
|
|
||||||
|
|
|
@ -39,24 +39,7 @@ pub fn get_unique_test_id() -> String {
|
||||||
.duration_since(std::time::UNIX_EPOCH)
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_millis();
|
.as_millis();
|
||||||
format!("test_{}_{}", timestamp, counter)
|
format!("test_{}_{}", counter, timestamp)
|
||||||
}
|
|
||||||
|
|
||||||
pub struct UserFactory;
|
|
||||||
|
|
||||||
impl UserFactory {
|
|
||||||
pub fn create_request(username: Option<String>, name: Option<String>) -> serde_json::Value {
|
|
||||||
let test_id = get_unique_test_id();
|
|
||||||
serde_json::json!({
|
|
||||||
"username": username.unwrap_or_else(|| format!("user_{}", test_id)),
|
|
||||||
"name": name.unwrap_or_else(|| format!("Test User {}", test_id)),
|
|
||||||
"password": "password123"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_unique_request() -> serde_json::Value {
|
|
||||||
Self::create_request(None, None)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -75,18 +58,6 @@ impl TestContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_user_data(
|
|
||||||
&self,
|
|
||||||
username_prefix: Option<&str>,
|
|
||||||
name: Option<&str>,
|
|
||||||
) -> serde_json::Value {
|
|
||||||
let username = username_prefix
|
|
||||||
.map(|prefix| format!("{}_{}", prefix, self.test_id))
|
|
||||||
.unwrap_or_else(|| format!("user_{}", self.test_id));
|
|
||||||
|
|
||||||
UserFactory::create_request(Some(username), name.map(String::from))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn cleanup_all(&self, db: &Database) {
|
pub async fn cleanup_all(&self, db: &Database) {
|
||||||
self.cleanup_projects(db).await;
|
self.cleanup_projects(db).await;
|
||||||
self.cleanup_users(db).await;
|
self.cleanup_users(db).await;
|
||||||
|
@ -109,23 +80,3 @@ macro_rules! create_test_app {
|
||||||
.await
|
.await
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! with_test_context {
|
|
||||||
($test_fn:expr) => {{
|
|
||||||
async {
|
|
||||||
let ctx = $crate::common::test_helpers::TestContext::new();
|
|
||||||
let db = $crate::common::test_helpers::get_database().await;
|
|
||||||
|
|
||||||
let result = {
|
|
||||||
let ctx = &ctx;
|
|
||||||
let db = &*db;
|
|
||||||
$test_fn(ctx.clone(), db).await
|
|
||||||
};
|
|
||||||
|
|
||||||
ctx.cleanup_all(db).await;
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
use actix_web::{http::header, test};
|
use actix_web::{http::header, test};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{common::test_helpers::TestContext, create_test_app};
|
||||||
common::test_helpers::{TestContext, UserFactory},
|
|
||||||
create_test_app,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
@ -19,11 +16,17 @@ mod tests {
|
||||||
|
|
||||||
#[actix_web::test]
|
#[actix_web::test]
|
||||||
async fn test_create_user() {
|
async fn test_create_user() {
|
||||||
let ctx = TestContext::new();
|
let ctx: TestContext = TestContext::new();
|
||||||
let db = crate::common::test_helpers::get_database().await;
|
let db = crate::common::test_helpers::get_database().await;
|
||||||
|
|
||||||
let app = create_test_app!();
|
let app = create_test_app!();
|
||||||
let user_data = UserFactory::create_unique_request();
|
|
||||||
|
// Create JSON payload using TestContext's ID
|
||||||
|
let user_data = serde_json::json!({
|
||||||
|
"username": format!("user_{}", ctx.test_id),
|
||||||
|
"name": format!("Test User {}", ctx.test_id),
|
||||||
|
"password": "password123"
|
||||||
|
});
|
||||||
|
|
||||||
let resp = test::TestRequest::post()
|
let resp = test::TestRequest::post()
|
||||||
.uri("/api/v1/user")
|
.uri("/api/v1/user")
|
||||||
|
@ -32,7 +35,9 @@ mod tests {
|
||||||
.send_request(&app)
|
.send_request(&app)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
dbg!(&resp);
|
||||||
let status = resp.status();
|
let status = resp.status();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
status.is_success(),
|
status.is_success(),
|
||||||
"Expected success status, got: {}",
|
"Expected success status, got: {}",
|
||||||
|
@ -60,10 +65,9 @@ mod tests {
|
||||||
|
|
||||||
let app = create_test_app!();
|
let app = create_test_app!();
|
||||||
|
|
||||||
// Create user using helper
|
|
||||||
let user = ctx.create_user(db, None, None).await.unwrap();
|
let user = ctx.create_user(db, None, None).await.unwrap();
|
||||||
|
|
||||||
// Verify user exists before deletion
|
// Check if user exists before deletion
|
||||||
assert!(ctx.assert_user_exists(db, user.id).await);
|
assert!(ctx.assert_user_exists(db, user.id).await);
|
||||||
|
|
||||||
// Delete the user via API
|
// Delete the user via API
|
||||||
|
@ -73,6 +77,8 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
let delete_status = delete_resp.status();
|
let delete_status = delete_resp.status();
|
||||||
|
|
||||||
|
dbg!(&delete_resp);
|
||||||
|
|
||||||
let delete_message: String = test::read_body_json(delete_resp).await;
|
let delete_message: String = test::read_body_json(delete_resp).await;
|
||||||
assert_eq!(delete_message, format!("User {} deleted", user.id));
|
assert_eq!(delete_message, format!("User {} deleted", user.id));
|
||||||
assert!(
|
assert!(
|
||||||
|
|
Loading…
Add table
Reference in a new issue