125 lines
3.5 KiB
Rust
125 lines
3.5 KiB
Rust
use backend::Database;
|
|
use lazy_static::lazy_static;
|
|
use std::sync::atomic::{AtomicU64, Ordering};
|
|
use testcontainers::ContainerAsync;
|
|
use testcontainers_modules::{postgres::Postgres, redis::Redis};
|
|
use uuid::Uuid;
|
|
|
|
use super::setup;
|
|
|
|
struct TestState {
|
|
_postgres: ContainerAsync<Postgres>,
|
|
_redis: ContainerAsync<Redis>,
|
|
database: Database,
|
|
}
|
|
|
|
lazy_static! {
|
|
static ref TEST_STATE: tokio::sync::OnceCell<TestState> = tokio::sync::OnceCell::new();
|
|
}
|
|
|
|
pub async fn get_database() -> &'static Database {
|
|
let state = TEST_STATE
|
|
.get_or_init(|| async {
|
|
let (postgres, redis, database) = setup().await;
|
|
TestState {
|
|
_postgres: postgres,
|
|
_redis: redis,
|
|
database,
|
|
}
|
|
})
|
|
.await;
|
|
|
|
&state.database
|
|
}
|
|
|
|
static TEST_COUNTER: AtomicU64 = AtomicU64::new(1);
|
|
|
|
pub fn get_unique_test_id() -> String {
|
|
let counter = TEST_COUNTER.fetch_add(1, Ordering::SeqCst);
|
|
let timestamp = std::time::SystemTime::now()
|
|
.duration_since(std::time::UNIX_EPOCH)
|
|
.unwrap()
|
|
.as_millis();
|
|
format!("test_{}_{}", timestamp, counter)
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|
|
|
|
pub struct TestContext {
|
|
pub test_id: String,
|
|
pub created_users: std::sync::Arc<std::sync::Mutex<Vec<uuid::Uuid>>>,
|
|
pub created_projects: std::sync::Arc<std::sync::Mutex<Vec<uuid::Uuid>>>,
|
|
}
|
|
|
|
impl TestContext {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
test_id: get_unique_test_id(),
|
|
created_users: std::sync::Arc::new(std::sync::Mutex::new(Vec::new())),
|
|
created_projects: std::sync::Arc::new(std::sync::Mutex::new(Vec::new())),
|
|
}
|
|
}
|
|
|
|
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) {
|
|
self.cleanup_projects(db).await;
|
|
self.cleanup_users(db).await;
|
|
}
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! create_test_app {
|
|
() => {{
|
|
let db = $crate::common::test_helpers::get_database().await;
|
|
|
|
actix_web::test::init_service(
|
|
actix_web::App::new()
|
|
.app_data(actix_web::web::Data::new(db.clone()))
|
|
.service(
|
|
actix_web::web::scope("/api/v1")
|
|
.configure(backend::controller::register_controllers),
|
|
),
|
|
)
|
|
.await
|
|
}};
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! with_test_context {
|
|
($test_fn:expr) => {{
|
|
let ctx = $crate::common::test_helpers::TestContext::new();
|
|
let db = $crate::common::test_helpers::get_database().await;
|
|
|
|
let result = $test_fn(ctx.clone(), db).await;
|
|
|
|
ctx.cleanup_all(db).await;
|
|
|
|
result
|
|
}};
|
|
}
|