tests are robusts running in parallel
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -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",
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
Reference in New Issue
Block a user