tests are robusts running in parallel

This commit is contained in:
filipriec
2025-06-18 22:38:00 +02:00
parent 4843b0778c
commit e25213ed1b
4 changed files with 65 additions and 37 deletions

1
Cargo.lock generated
View File

@@ -2846,6 +2846,7 @@ dependencies = [
"lazy_static", "lazy_static",
"prost", "prost",
"prost-types", "prost-types",
"rand 0.9.1",
"regex", "regex",
"rstest", "rstest",
"rust-stemmers", "rust-stemmers",

View File

@@ -42,3 +42,4 @@ path = "src/lib.rs"
tokio = { version = "1.44", features = ["full", "test-util"] } tokio = { version = "1.44", features = ["full", "test-util"] }
rstest = "0.25.0" rstest = "0.25.0"
lazy_static = "1.5.0" lazy_static = "1.5.0"
rand = "0.9.1"

View File

@@ -1,56 +1,75 @@
// tests/common/mod.rs // 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::env;
use std::path::Path;
pub async fn setup_test_db() -> PgPool { // (The get_database_url and get_root_connection functions remain the same)
// Get path to server directory fn get_database_url() -> String {
let manifest_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR must be set"); dotenv().ok();
let env_path = Path::new(&manifest_dir).join(".env_test"); 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 /// The primary test setup function.
let database_url = env::var("TEST_DATABASE_URL").expect("TEST_DATABASE_URL must be set"); /// 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() let pool = PgPoolOptions::new()
.max_connections(5) .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 .await
.expect("Failed to create pool"); .expect("Failed to create isolated pool");
// Run migrations
sqlx::migrate!() sqlx::migrate!()
.run(&pool) .run(&pool)
.await .await
.expect("Migrations failed"); .expect("Migrations failed in isolated schema");
// Insert default profile if it doesn't exist sqlx::query!(
let profile = sqlx::query!(
r#" r#"
INSERT INTO profiles (name) INSERT INTO profiles (name)
VALUES ('default') VALUES ('default')
ON CONFLICT (name) DO NOTHING ON CONFLICT (name) DO NOTHING
RETURNING id
"# "#
) )
.fetch_optional(&pool) .execute(&pool)
.await .await
.expect("Failed to insert test profile"); .expect("Failed to insert test profile in isolated schema");
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
};
pool pool
} }

View File

@@ -1,5 +1,7 @@
// tests/table_definition/post_table_definition_test.rs // 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::{ use common::proto::multieko2::table_definition::{
ColumnDefinition, PostTableDefinitionRequest, TableLink, ColumnDefinition, PostTableDefinitionRequest, TableLink,
}; };
@@ -10,9 +12,13 @@ use tonic::Code;
// ========= Fixtures ========= // ========= 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] #[fixture]
async fn pool() -> PgPool { async fn pool() -> PgPool {
setup_test_db().await // Instead of the old setup, we call the new isolated setup.
setup_isolated_db().await
} }
#[fixture] #[fixture]
@@ -22,8 +28,8 @@ async fn closed_pool(#[future] pool: PgPool) -> PgPool {
pool pool
} }
/// A fixture that creates a pre-existing 'customers' table definition, /// This fixture now works perfectly and is also isolated,
/// so we can test linking to it. /// because it depends on the `pool` fixture above. No changes needed here!
#[fixture] #[fixture]
async fn pool_with_preexisting_table(#[future] pool: PgPool) -> PgPool { async fn pool_with_preexisting_table(#[future] pool: PgPool) -> PgPool {
let pool = pool.await; let pool = pool.await;
@@ -43,6 +49,7 @@ async fn pool_with_preexisting_table(#[future] pool: PgPool) -> PgPool {
pool pool
} }
// ========= Helper Functions ========= // ========= Helper Functions =========
/// Checks the PostgreSQL information_schema to verify a table and its columns exist. /// Checks the PostgreSQL information_schema to verify a table and its columns exist.