delete testkit

This commit is contained in:
dal 2025-04-02 14:28:29 -06:00
parent 2abf522c78
commit 7e982c3653
No known key found for this signature in database
GPG Key ID: 16F4B0E1E9F61122
5 changed files with 0 additions and 363 deletions

View File

@ -9,7 +9,6 @@ members = [
"libs/sharing", "libs/sharing",
"libs/sql_analyzer", "libs/sql_analyzer",
"libs/search", "libs/search",
"testkit",
] ]
resolver = "2" resolver = "2"

View File

@ -1,139 +0,0 @@
# Testkit Library Usage Guide
## Overview
The testkit library initializes database pools during build time and provides utilities for test isolation. The pools themselves are accessed directly from the database library.
## Key Features
- Pre-initialized database connections at build time
- Environment variable management for test-specific configurations
- Test ID generation for test isolation
## Usage
### Basic Usage
```rust
use database::pool::get_pg_pool;
use testkit::test_id;
use anyhow::Result;
#[tokio::test]
async fn test_database_operations() -> Result<()> {
// Create a unique test ID for isolation
let test_id = test_id();
// Pools are already initialized during build time
// Get the pool from the database library
let pool = get_pg_pool();
// Use the pool in your test
let conn = pool.get().await?;
// Perform database operations...
Ok(())
}
```
### Environment Configuration
The testkit automatically loads environment variables from `.env.test` if available, otherwise from `.env` during the build process. Key environment variables include:
- `TEST_DATABASE_URL` - PostgreSQL connection string for tests
- `TEST_POOLER_URL` - Connection string for the SQL pooler
- `TEST_REDIS_URL` - Redis connection string
- `TEST_DATABASE_POOL_SIZE` - Maximum connections in Diesel pool (default: 10)
- `TEST_SQLX_POOL_SIZE` - Maximum connections in SQLx pool (default: 10)
### Accessing Database Pools
Access the pre-initialized database pools directly through the database library:
```rust
// Get the Diesel PostgreSQL pool (AsyncPgConnection)
let pg_pool = database::pool::get_pg_pool();
// Get the SQLx PostgreSQL pool
let sqlx_pool = database::pool::get_sqlx_pool();
// Get the Redis pool
let redis_pool = database::pool::get_redis_pool();
```
### Test ID Generation
For test isolation, you can generate unique IDs to tag test data:
```rust
let test_id = testkit::test_id();
// Use this ID to mark test data for cleanup
diesel::insert_into(users::table)
.values((
users::name.eq("Test User"),
users::email.eq("test@example.com"),
users::test_id.eq(test_id), // Use the test ID for later cleanup
))
.execute(&mut conn)
.await?;
```
## Implementation Details
### Pool Initialization
The testkit initializes pools during the build process using `build.rs`. This ensures pools are always available when your tests run, with no initialization overhead or risk of connection timing issues.
### Error Handling
- Build-time initialization failures are reported as warnings but don't fail the build
- Unit tests that don't need database access will run fine even if pool initialization failed
- Integration tests that need database access will fail fast if the database isn't available
### Database Reset (Optional Feature)
For clearing test data, use the `db_reset` feature:
```rust
// Only available when the `db_reset` feature is enabled
#[cfg(feature = "db_reset")]
testkit::reset_test_database().await?;
```
## Best Practices
1. **Direct Pool Access**: Always use `get_pg_pool()`, `get_sqlx_pool()`, or `get_redis_pool()` directly
2. **Use Test IDs**: Generate and use test IDs for proper test isolation
3. **Cleanup After Tests**: Always clean up test data after tests
4. **Connection Pooling**: Reuse connections from the pool instead of creating new ones
5. **Environment Variables**: Use the `.env.test` file for test-specific configuration
6. **Avoid Database in Unit Tests**: Unit tests should mock database operations
## Example Integration Test Pattern
```rust
#[tokio::test]
async fn test_example() -> Result<()> {
// Generate unique test ID
let test_id = testkit::test_id();
// Get pre-initialized database connection directly from database lib
let pool = database::pool::get_pg_pool();
let mut conn = pool.get().await?;
// Setup test data with test_id for tracking
let test_user = create_test_user(&mut conn, &test_id).await?;
// Run the test against the test data
let result = your_function_under_test(test_user.id).await?;
assert_eq!(result.name, test_user.name);
// Clean up test data using test_id
cleanup_test_data(&mut conn, &test_id).await?;
Ok(())
}
async fn create_test_user(conn: &mut PgConnection, test_id: &str) -> Result<User> {
// Insert user with test_id
// ...
}
async fn cleanup_test_data(conn: &mut PgConnection, test_id: &str) -> Result<()> {
// Delete all data with matching test_id
// ...
}
```

View File

@ -1,29 +0,0 @@
[package]
name = "testkit"
version = "0.1.0"
edition = "2021"
description = "Test utilities for Buster API database pools"
build = "build.rs"
[dependencies]
anyhow = { workspace = true }
tokio = { workspace = true }
diesel = { workspace = true }
diesel-async = { workspace = true }
sqlx = { workspace = true }
bb8-redis = { workspace = true }
uuid = { workspace = true }
dotenv = { workspace = true }
once_cell = { workspace = true }
futures = { workspace = true }
tracing = { workspace = true }
database = { path = "../libs/database" }
[build-dependencies]
dotenv = { workspace = true }
tokio = { workspace = true, features = ["rt", "macros"] }
database = { path = "../libs/database" }
[features]
default = []
db_reset = [] # Use with caution - allows resetting the test database

View File

@ -1,104 +0,0 @@
use std::env;
use std::fs;
use std::path::Path;
fn main() {
println!("cargo:rerun-if-changed=build.rs");
// Create default .env.test if it doesn't exist
ensure_test_env_exists();
// Load environment variables from .env
load_env_file();
// Try to initialize pools but don't fail the build if it fails
if let Err(e) = try_init_pools() {
println!("cargo:warning=Failed to initialize pools: {}", e);
println!("cargo:warning=This is not a build error - pools will be initialized when tests run");
} else {
println!("cargo:warning=Successfully initialized database pools");
}
}
fn ensure_test_env_exists() {
let test_env_path = Path::new(".env.test");
// Only create if it doesn't exist
if !test_env_path.exists() {
println!("cargo:warning=Creating default .env.test file");
let default_content = r#"
# Test Environment Configuration
TEST_ENV=test
TEST_DATABASE_URL=postgresql://postgres:postgres@127.0.0.1:54322/postgres
TEST_POOLER_URL=postgresql://postgres:postgres@127.0.0.1:54322/postgres
TEST_REDIS_URL=redis://localhost:6379
TEST_DATABASE_POOL_SIZE=10
TEST_SQLX_POOL_SIZE=10
TEST_LOG=true
TEST_LOG_LEVEL=debug
"#.trim();
fs::write(test_env_path, default_content)
.expect("Failed to create default .env.test file");
println!("cargo:warning=Created default .env.test file");
}
}
fn load_env_file() {
// Try loading .env.test first, then fall back to .env
if Path::new(".env.test").exists() {
if let Ok(_) = dotenv::from_filename(".env.test") {
println!("cargo:warning=Loaded environment from .env.test");
}
} else if let Ok(_) = dotenv::dotenv() {
println!("cargo:warning=Loaded environment from .env");
}
// Override DATABASE_URL to use TEST_DATABASE_URL for tests
if let Ok(test_db_url) = env::var("TEST_DATABASE_URL") {
env::set_var("DATABASE_URL", test_db_url);
println!("cargo:warning=Using TEST_DATABASE_URL for DATABASE_URL");
}
// Override POOLER_URL to use TEST_POOLER_URL for tests
if let Ok(test_pooler_url) = env::var("TEST_POOLER_URL") {
env::set_var("POOLER_URL", test_pooler_url);
println!("cargo:warning=Using TEST_POOLER_URL for POOLER_URL");
}
// Override REDIS_URL to use TEST_REDIS_URL for tests
if let Ok(test_redis_url) = env::var("TEST_REDIS_URL") {
env::set_var("REDIS_URL", test_redis_url);
println!("cargo:warning=Using TEST_REDIS_URL for REDIS_URL");
}
// Override pool sizes to prevent excessive connections in test environment
if let Ok(test_pool_size) = env::var("TEST_DATABASE_POOL_SIZE") {
env::set_var("DATABASE_POOL_SIZE", test_pool_size);
}
if let Ok(test_sqlx_pool_size) = env::var("TEST_SQLX_POOL_SIZE") {
env::set_var("SQLX_POOL_SIZE", test_sqlx_pool_size);
}
}
fn try_init_pools() -> Result<(), String> {
// Create a runtime for async operations
let runtime = match tokio::runtime::Builder::new_current_thread()
.enable_all()
.build() {
Ok(rt) => rt,
Err(e) => return Err(e.to_string()),
};
// Try to initialize pools through the testkit's internal function
// This won't fail the build if it can't connect to the database
runtime.block_on(async {
match database::pool::init_pools().await {
Ok(_) => Ok(()),
Err(e) => Err(e.to_string()),
}
})
}

View File

@ -1,90 +0,0 @@
use anyhow::Result;
use dotenv::dotenv;
use std::path::Path;
use std::sync::Once;
use once_cell::sync::OnceCell;
static ENV_INIT: Once = Once::new();
static POOL_INIT: OnceCell<()> = OnceCell::new();
/// Initialize the test environment by setting up .env.test
/// This should only be used internally or by build.rs
fn init_test_env() {
ENV_INIT.call_once(|| {
// Try loading .env.test first, then fall back to .env
if Path::new(".env.test").exists() {
dotenv::from_filename(".env.test").ok();
} else {
dotenv().ok();
}
// Override DATABASE_URL to use TEST_DATABASE_URL for tests
if let Ok(test_db_url) = std::env::var("TEST_DATABASE_URL") {
std::env::set_var("DATABASE_URL", test_db_url);
}
// Override POOLER_URL to use TEST_POOLER_URL for tests
if let Ok(test_pooler_url) = std::env::var("TEST_POOLER_URL") {
std::env::set_var("POOLER_URL", test_pooler_url);
}
// Override REDIS_URL to use TEST_REDIS_URL for tests
if let Ok(test_redis_url) = std::env::var("TEST_REDIS_URL") {
std::env::set_var("REDIS_URL", test_redis_url);
}
// Override pool sizes to prevent excessive connections in test environment
if let Ok(test_pool_size) = std::env::var("TEST_DATABASE_POOL_SIZE") {
std::env::set_var("DATABASE_POOL_SIZE", test_pool_size);
}
if let Ok(test_sqlx_pool_size) = std::env::var("TEST_SQLX_POOL_SIZE") {
std::env::set_var("SQLX_POOL_SIZE", test_sqlx_pool_size);
}
});
}
// This function is only for internal use by build.rs - the pools should be
// initialized at build time, not during test runtime
#[doc(hidden)]
pub async fn _internal_init_pools() -> Result<()> {
// Setup the environment first
init_test_env();
// Only initialize pools once
if POOL_INIT.get().is_some() {
return Ok(());
}
// Use the database crate's init_pools function
let result = match database::pool::init_pools().await {
Ok(_) => {
// Success case - cache the result
let _ = POOL_INIT.set(());
Ok(())
},
Err(e) => {
// Log the error but still cache the attempt to prevent repeated tries
tracing::error!("Failed to initialize test pools: {}", e);
let _ = POOL_INIT.set(());
Err(e)
}
};
result
}
// No need for pool accessor functions - users should access pools directly
// through the database library (database::pool::get_pg_pool(), etc.)
/// Generate a unique test ID - useful for creating test resources
pub fn test_id() -> String {
uuid::Uuid::new_v4().to_string()
}
/// Clean up a test database connection - useful in test teardown
pub async fn cleanup_connection() -> Result<()> {
// This is a placeholder for any future cleanup that might be needed
// Currently the pools handle their own cleanup
Ok(())
}