tests are robusts running in parallel
This commit is contained in:
@@ -42,3 +42,4 @@ path = "src/lib.rs"
|
||||
tokio = { version = "1.44", features = ["full", "test-util"] }
|
||||
rstest = "0.25.0"
|
||||
lazy_static = "1.5.0"
|
||||
rand = "0.9.1"
|
||||
|
||||
@@ -1,56 +1,75 @@
|
||||
// tests/common/mod.rs
|
||||
use dotenvy;
|
||||
use sqlx::{postgres::PgPoolOptions, PgPool};
|
||||
|
||||
use dotenvy::dotenv;
|
||||
// --- CHANGE 1: Add Alphanumeric to the use statement ---
|
||||
use rand::distr::Alphanumeric;
|
||||
use rand::Rng;
|
||||
use sqlx::{postgres::PgPoolOptions, Connection, Executor, PgConnection, PgPool};
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
|
||||
pub async fn setup_test_db() -> PgPool {
|
||||
// Get path to server directory
|
||||
let manifest_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR must be set");
|
||||
let env_path = Path::new(&manifest_dir).join(".env_test");
|
||||
// (The get_database_url and get_root_connection functions remain the same)
|
||||
fn get_database_url() -> String {
|
||||
dotenv().ok();
|
||||
env::var("TEST_DATABASE_URL").expect("TEST_DATABASE_URL must be set")
|
||||
}
|
||||
async fn get_root_connection() -> PgConnection {
|
||||
PgConnection::connect(&get_database_url())
|
||||
.await
|
||||
.expect("Failed to create root connection to test database")
|
||||
}
|
||||
|
||||
// Load environment variables
|
||||
dotenvy::from_path(env_path).ok();
|
||||
|
||||
// Create connection pool
|
||||
let database_url = env::var("TEST_DATABASE_URL").expect("TEST_DATABASE_URL must be set");
|
||||
/// The primary test setup function.
|
||||
/// Creates a new, unique schema and returns a connection pool that is scoped to that schema.
|
||||
/// This is the key to test isolation.
|
||||
pub async fn setup_isolated_db() -> PgPool {
|
||||
let mut root_conn = get_root_connection().await;
|
||||
|
||||
let schema_name = format!(
|
||||
"test_{}",
|
||||
rand::thread_rng()
|
||||
// --- CHANGE 2: Pass a reference to Alphanumeric directly ---
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(12)
|
||||
.map(char::from)
|
||||
.collect::<String>()
|
||||
.to_lowercase()
|
||||
);
|
||||
|
||||
root_conn
|
||||
.execute(format!("CREATE SCHEMA \"{}\"", schema_name).as_str())
|
||||
.await
|
||||
.unwrap_or_else(|_| panic!("Failed to create schema: {}", schema_name));
|
||||
|
||||
let pool = PgPoolOptions::new()
|
||||
.max_connections(5)
|
||||
.connect(&database_url)
|
||||
.after_connect(move |conn, _meta| {
|
||||
let schema_name = schema_name.clone();
|
||||
Box::pin(async move {
|
||||
conn.execute(format!("SET search_path TO \"{}\"", schema_name).as_str())
|
||||
.await?;
|
||||
Ok(())
|
||||
})
|
||||
})
|
||||
.connect(&get_database_url())
|
||||
.await
|
||||
.expect("Failed to create pool");
|
||||
.expect("Failed to create isolated pool");
|
||||
|
||||
// Run migrations
|
||||
sqlx::migrate!()
|
||||
.run(&pool)
|
||||
.await
|
||||
.expect("Migrations failed");
|
||||
.expect("Migrations failed in isolated schema");
|
||||
|
||||
// Insert default profile if it doesn't exist
|
||||
let profile = sqlx::query!(
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO profiles (name)
|
||||
VALUES ('default')
|
||||
ON CONFLICT (name) DO NOTHING
|
||||
RETURNING id
|
||||
"#
|
||||
)
|
||||
.fetch_optional(&pool)
|
||||
.execute(&pool)
|
||||
.await
|
||||
.expect("Failed to insert test profile");
|
||||
|
||||
let profile_id = if let Some(profile) = profile {
|
||||
profile.id
|
||||
} else {
|
||||
// If the profile already exists, fetch its ID
|
||||
sqlx::query!(
|
||||
"SELECT id FROM profiles WHERE name = 'default'"
|
||||
)
|
||||
.fetch_one(&pool)
|
||||
.await
|
||||
.expect("Failed to fetch default profile ID")
|
||||
.id
|
||||
};
|
||||
.expect("Failed to insert test profile in isolated schema");
|
||||
|
||||
pool
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// tests/table_definition/post_table_definition_test.rs
|
||||
use crate::common::setup_test_db;
|
||||
|
||||
use crate::common::setup_isolated_db;
|
||||
|
||||
use common::proto::multieko2::table_definition::{
|
||||
ColumnDefinition, PostTableDefinitionRequest, TableLink,
|
||||
};
|
||||
@@ -10,9 +12,13 @@ use tonic::Code;
|
||||
|
||||
// ========= Fixtures =========
|
||||
|
||||
/// THIS IS THE KEY CHANGE.
|
||||
/// The `pool` fixture, which most of your tests already use,
|
||||
/// will now provide a completely isolated database schema for every test.
|
||||
#[fixture]
|
||||
async fn pool() -> PgPool {
|
||||
setup_test_db().await
|
||||
// Instead of the old setup, we call the new isolated setup.
|
||||
setup_isolated_db().await
|
||||
}
|
||||
|
||||
#[fixture]
|
||||
@@ -22,8 +28,8 @@ async fn closed_pool(#[future] pool: PgPool) -> PgPool {
|
||||
pool
|
||||
}
|
||||
|
||||
/// A fixture that creates a pre-existing 'customers' table definition,
|
||||
/// so we can test linking to it.
|
||||
/// This fixture now works perfectly and is also isolated,
|
||||
/// because it depends on the `pool` fixture above. No changes needed here!
|
||||
#[fixture]
|
||||
async fn pool_with_preexisting_table(#[future] pool: PgPool) -> PgPool {
|
||||
let pool = pool.await;
|
||||
@@ -43,6 +49,7 @@ async fn pool_with_preexisting_table(#[future] pool: PgPool) -> PgPool {
|
||||
pool
|
||||
}
|
||||
|
||||
|
||||
// ========= Helper Functions =========
|
||||
|
||||
/// Checks the PostgreSQL information_schema to verify a table and its columns exist.
|
||||
|
||||
Reference in New Issue
Block a user