diff --git a/api/documentation/libs.mdc b/api/documentation/libs.mdc index 04601e93a..e4e9cd200 100644 --- a/api/documentation/libs.mdc +++ b/api/documentation/libs.mdc @@ -109,6 +109,50 @@ pub enum Error { - Keep library-specific test helpers in the library - Use workspace-defined test macros if available +#### Database Integration Tests +For tests that require database access, the preferred approach is to use automatic pool initialization: + +```rust +// In tests/mod.rs +use database::pool::init_pools; +use lazy_static::lazy_static; + +lazy_static! { + // Initialize test environment once across all tests + static ref TEST_ENV: () = { + let rt = tokio::runtime::Runtime::new().unwrap(); + if let Err(e) = rt.block_on(init_pools()) { + panic!("Failed to initialize test pools: {}", e); + } + println!("✅ Test environment initialized"); + }; +} + +#[ctor::ctor] +fn init_test_env() { + lazy_static::initialize(&TEST_ENV); +} +``` + +Then write normal tests without explicit initialization: + +```rust +// In your test file +#[tokio::test] +async fn test_database_functionality() -> Result<()> { + // Pool is already initialized - just get it + let pool = database::pool::get_pg_pool(); + + // Your test code here + Ok(()) +} +``` + +This pattern ensures: +- Database pools are initialized exactly once at test startup +- All tests can access the same pool without manual initialization +- Test code remains clean without initialization boilerplate + ### 5. Documentation - Follow workspace documentation style - Link to related workspace documentation diff --git a/api/libs/database/Cargo.toml b/api/libs/database/Cargo.toml index c3e1ff866..66441df2c 100644 --- a/api/libs/database/Cargo.toml +++ b/api/libs/database/Cargo.toml @@ -30,5 +30,4 @@ reqwest = { workspace = true } [dev-dependencies] -tokio-test = { workspace = true } -testkit = { path = "../../testkit" } \ No newline at end of file +tokio-test = { workspace = true } \ No newline at end of file diff --git a/api/libs/database/tests/connection_test.rs b/api/libs/database/tests/connection_test.rs deleted file mode 100644 index d8820d4e8..000000000 --- a/api/libs/database/tests/connection_test.rs +++ /dev/null @@ -1,45 +0,0 @@ -use anyhow::Result; - -#[tokio::test] -async fn test_database_connection() -> Result<()> { - // Get the database pool from testkit - let pool = testkit::get_pg_pool(); - - // Test the connection by getting a connection from the pool - let conn = pool.get().await?; - - // If we got here without errors, the connection is working - Ok(()) -} - -#[tokio::test] -async fn test_with_isolation() -> Result<()> { - // Get a unique test ID for data isolation - let test_id = testkit::test_id(); - - // Get database pool - let pool = testkit::get_pg_pool(); - - // Get a DB connection - let mut conn = pool.get().await?; - - // Here you would create test data with test_id for isolation - // For example: - // diesel::sql_query("INSERT INTO users (id, email, test_id) VALUES ($1, $2, $3)") - // .bind::(uuid::Uuid::new_v4()) - // .bind::("test@example.com") - // .bind::(&test_id) - // .execute(&mut conn) - // .await?; - - // Run assertions on the test data - - // Clean up after the test - // For example: - // diesel::sql_query("DELETE FROM users WHERE test_id = $1") - // .bind::(&test_id) - // .execute(&mut conn) - // .await?; - - Ok(()) -} \ No newline at end of file diff --git a/api/libs/handlers/CLAUDE.md b/api/libs/handlers/CLAUDE.md index 49546e1fa..585614ed3 100644 --- a/api/libs/handlers/CLAUDE.md +++ b/api/libs/handlers/CLAUDE.md @@ -120,4 +120,33 @@ async fn example_handler(req: PostChatRequest, user: AuthenticatedUser) -> Resul - Test the full request-response cycle for integration tests - Use test fixtures for consistent test data - Run tests with: `cargo test -p handlers` -- Create tests for each handler in the corresponding `tests/` directory \ No newline at end of file +- Create tests for each handler in the corresponding `tests/` directory + +### Automatic Test Environment Setup + +Integration tests in this library use an automatic database pool initialization system. The environment is set up once when the test module is loaded, eliminating the need for explicit initialization in each test. + +Key components: +- `tests/mod.rs` contains the initialization code using `lazy_static` and `ctor` +- Database pools are initialized only once for all tests +- Tests can directly use `get_pg_pool()` without any setup code + +Example test: +```rust +use anyhow::Result; +use database::pool::get_pg_pool; + +#[tokio::test] +async fn test_handler_functionality() -> Result<()> { + // Database pool is already initialized + let pool = get_pg_pool(); + + // Test code here using the pool + Ok(()) +} +``` + +To add new test modules, simply: +1. Create a new module in the `tests/` directory +2. Add it to the module declarations in `tests/mod.rs` +3. Write standard async tests using `#[tokio::test]` \ No newline at end of file diff --git a/api/libs/handlers/Cargo.toml b/api/libs/handlers/Cargo.toml index 5c6f2e5b8..f9ef9d30e 100644 --- a/api/libs/handlers/Cargo.toml +++ b/api/libs/handlers/Cargo.toml @@ -39,4 +39,6 @@ dashmap = "5.5.3" [dev-dependencies] tokio-test = { workspace = true } mockall = { workspace = true } -dotenv = { workspace = true } \ No newline at end of file +dotenv = { workspace = true } +lazy_static.workspace = true +ctor = "0.4.1" diff --git a/api/libs/handlers/tests/dashboards/list_sharing_test.rs b/api/libs/handlers/tests/dashboards/list_sharing_test.rs index d056041d0..860f50610 100644 --- a/api/libs/handlers/tests/dashboards/list_sharing_test.rs +++ b/api/libs/handlers/tests/dashboards/list_sharing_test.rs @@ -1,8 +1,22 @@ use anyhow::Result; +use database::pool::get_pg_pool; +// Just a regular tokio test - environment is initialized automatically #[tokio::test] async fn test_placeholder() -> Result<()> { - // This is a placeholder test + // Verify we can access the database pool without explicit initialization + let _pool = get_pg_pool(); + + assert!(true); + Ok(()) +} + +// Another test - will share the same initialized environment +#[tokio::test] +async fn test_another_test() -> Result<()> { + // Uses the same pool that was initialized once for all tests + let _pool = get_pg_pool(); + assert!(true); Ok(()) } diff --git a/api/libs/handlers/tests/mod.rs b/api/libs/handlers/tests/mod.rs index 3e4f08aa5..91cbbe103 100644 --- a/api/libs/handlers/tests/mod.rs +++ b/api/libs/handlers/tests/mod.rs @@ -1,2 +1,27 @@ +use database::pool::init_pools; +use lazy_static::lazy_static; + +lazy_static! { + // Initialize test environment once across all tests + static ref TEST_ENV: () = { + // Create a runtime for initialization + let rt = tokio::runtime::Runtime::new().unwrap(); + + // Initialize pools + if let Err(e) = rt.block_on(init_pools()) { + panic!("Failed to initialize test pools: {}", e); + } + + println!("✅ Test environment initialized"); + }; +} + +// This constructor runs when the test binary loads +#[ctor::ctor] +fn init_test_env() { + // Force lazy_static initialization + lazy_static::initialize(&TEST_ENV); +} + // Test modules pub mod dashboards;