use super::db_setup::start_postgres_container;
use std::env;
use testcontainers::{ContainerAsync, GenericImage};
use tokio::sync::OnceCell;
use tokio_postgres::{Client, NoTls};
pub static ALICE_ID: OnceCell<i32> = OnceCell::const_new();
pub static BOB_ID: OnceCell<i32> = OnceCell::const_new();
pub static ADMIN_ID: OnceCell<i32> = OnceCell::const_new();
pub static GROUP_OWNER_ID: OnceCell<i32> = OnceCell::const_new();
pub async fn setup_test_container() -> (ContainerAsync<GenericImage>, Client, String) {
let (node, _) = start_postgres_container().await;
let host = "127.0.0.1";
let port = 5432;
let postgres_url = format!("postgres://postgres:postgres@{}:{}/postgres", host, port);
env::set_var("DB_HOST", host);
env::set_var("DB_PORT", port.to_string());
let (client, connection) = tokio_postgres::connect(&postgres_url, NoTls)
.await
.expect("Failed to connect to Postgres");
tokio::spawn(async move {
if let Err(e) = connection.await {
eprintln!("connection error: {}", e);
}
});
(node, client, postgres_url)
}
pub async fn setup_active_session(client: &Client) {
let row = client.query_one("
INSERT INTO users (first_name, last_name, email, password, phone_number, status, is_archived)
VALUES ('Alice', 'Smith', 'alice@example.com', 'password123', '0102030405', 'active', FALSE)
ON CONFLICT (email) DO UPDATE SET email = EXCLUDED.email
RETURNING id;
", &[]).await.expect("Failed to insert Alice");
let id: i32 = row.get(0);
ALICE_ID.set(id).ok();
client
.execute(
"
INSERT INTO sessions (user_id, user_is_archived, token_hash, ip_address, device_info)
VALUES ($1, FALSE, 'test_token_hash_unique_123', '127.0.0.1', 'Mozilla/5.0 (TestRunner)')
ON CONFLICT DO NOTHING;
",
&[&id],
)
.await
.expect("Failed to setup active session");
}
pub async fn setup_expired_session(client: &Client) {
let id = *ALICE_ID.get().expect("Alice ID not initialized");
client.execute("
INSERT INTO sessions (user_id, user_is_archived, token_hash, ip_address, device_info, expires_at)
VALUES ($1, FALSE, 'test_token_hash_expired', '127.0.0.1', 'Mozilla/5.0', now() - INTERVAL '1 hour');
", &[&id]).await.expect("Failed to setup expired session");
}
pub async fn setup_archived_user_test(client: &Client) {
let row = client.query_one("
INSERT INTO users (first_name, last_name, email, password, phone_number, status, is_archived)
VALUES ('Bob', 'Smith', 'bob@example.com', 'password123', '0102030405', 'active', FALSE)
ON CONFLICT (email) DO UPDATE SET email = EXCLUDED.email
RETURNING id;
", &[]).await.expect("Failed to insert Bob");
let id: i32 = row.get(0);
BOB_ID.set(id).ok();
client
.execute(
"
INSERT INTO sessions (user_id, user_is_archived, token_hash, ip_address, device_info)
VALUES ($1, FALSE, 'test_token_hash_archived_user', '127.0.0.1', 'Mozilla/5.0')
ON CONFLICT DO NOTHING;
",
&[&id],
)
.await
.expect("Failed to setup Bob session");
client
.execute(
"UPDATE users SET is_archived = TRUE, status = 'archived' WHERE id = $1",
&[&id],
)
.await
.expect("Failed to archive Bob");
}
pub async fn setup_access_control_data(client: &Client) {
let alice_id = *ALICE_ID.get().expect("Alice ID missing");
let bob_id = *BOB_ID.get().expect("Bob ID missing");
let admin_row = client
.query_one(
"
INSERT INTO users (first_name, last_name, email, password, status)
VALUES ('Admin', 'User', 'admin@test.com', 'hash', 'active')
ON CONFLICT (email) DO UPDATE SET email = EXCLUDED.email
RETURNING id;
",
&[],
)
.await
.expect("Failed to insert Admin");
let admin_id: i32 = admin_row.get(0);
client
.batch_execute(&format!(
"INSERT INTO user_roles (user_id, role_id) VALUES ({admin_id}, 1) ON CONFLICT DO NOTHING;"
))
.await
.expect("Failed to insert User Role");
ADMIN_ID.set(admin_id).ok();
let owner_row = client
.query_one(
"
INSERT INTO users (first_name, last_name, email, password, status)
VALUES ('Group', 'Owner', 'owner@test.com', 'hash', 'active')
ON CONFLICT (email) DO UPDATE SET email = EXCLUDED.email
RETURNING id;
",
&[],
)
.await
.expect("Failed to insert Group Owner");
let owner_id: i32 = owner_row.get(0);
GROUP_OWNER_ID.set(owner_id).ok();
client
.batch_execute(&format!(
"
INSERT INTO user_roles (user_id, role_id) VALUES ({alice_id}, 1) ON CONFLICT DO NOTHING;
CREATE TABLE IF NOT EXISTS document (id SERIAL PRIMARY KEY, owner_id INT);
INSERT INTO document (owner_id) VALUES ({alice_id});
INSERT INTO groups (owner_id, name, owner_is_archived)
VALUES ({owner_id}, 'Seeded Group', false) ON CONFLICT DO NOTHING;
INSERT INTO access_control (user_id, resource_id, permission_id, resource_instance_id)
VALUES ({bob_id}, 2, 3, 50) ON CONFLICT DO NOTHING;
"
))
.await
.expect("Failed to setup access control data");
}
static SHARED_DB: OnceCell<(ContainerAsync<GenericImage>, String)> = OnceCell::const_new();
pub async fn get_shared_db() -> &'static (ContainerAsync<GenericImage>, String) {
SHARED_DB
.get_or_init(|| async {
println!("🚀 Lancement du setup global UNIQUE...");
let (node, client, url) = setup_test_container().await;
client
.batch_execute(
"
TRUNCATE TABLE
access_control,
user_roles,
groups,
sessions,
users
RESTART IDENTITY CASCADE;
",
)
.await
.expect("Erreur lors du nettoyage des données");
setup_active_session(&client).await;
setup_expired_session(&client).await;
setup_archived_user_test(&client).await;
setup_access_control_data(&client).await;
println!("✅ Données de test injectées avec succès.");
(node, url)
})
.await
}