use do_memory_storage_turso::{ConnectionPool, PoolConfig};
use std::sync::Arc;
use std::time::{Duration, Instant};
use tempfile::TempDir;
async fn create_test_pool() -> anyhow::Result<(Arc<ConnectionPool>, TempDir)> {
let dir = TempDir::new()?;
let db_path = dir.path().join("test.db");
let db = libsql::Builder::new_local(&db_path).build().await?;
let config = PoolConfig {
max_connections: 10,
connection_timeout: Duration::from_secs(5),
enable_health_check: true,
health_check_timeout: Duration::from_secs(2),
};
let pool = ConnectionPool::new(Arc::new(db), config).await?;
Ok((Arc::new(pool), dir))
}
#[cfg_attr(target_os = "windows", ignore)]
#[tokio::test]
async fn test_pool_performance_concurrent_operations() -> Result<(), Box<dyn std::error::Error>> {
let (pool, _dir) = create_test_pool().await?;
let start = Instant::now();
let mut handles = vec![];
for _ in 0..100 {
let pool_clone = Arc::clone(&pool);
let handle = tokio::spawn(async move {
let conn = pool_clone.get().await?;
let result = conn
.connection()
.ok_or_else(|| anyhow::anyhow!("Failed to get connection"))?
.query("SELECT 1", ())
.await;
assert!(result.is_ok());
tokio::time::sleep(Duration::from_millis(5)).await;
anyhow::Ok(())
});
handles.push(handle);
}
for handle in handles {
handle.await??;
}
let elapsed = start.elapsed();
tokio::time::sleep(Duration::from_millis(100)).await;
let stats = pool.statistics().await;
println!("100 concurrent operations completed in: {:?}", elapsed);
println!("Total checkouts: {}", stats.total_checkouts);
println!("Total created connections: {}", stats.total_created);
println!("Avg wait time: {}ms", stats.avg_wait_time_ms);
assert_eq!(stats.total_checkouts, 100);
assert_eq!(stats.total_created, 100); assert!(elapsed.as_millis() < 5000);
assert!(stats.active_connections == 0);
let _ = pool.shutdown().await;
tokio::time::sleep(Duration::from_millis(50)).await;
Ok(())
}
#[cfg_attr(target_os = "windows", ignore)]
#[tokio::test]
async fn test_pool_with_turso_storage() -> Result<(), Box<dyn std::error::Error>> {
let dir = TempDir::new()?;
let db_path = dir.path().join("test.db");
let db = libsql::Builder::new_local(&db_path).build().await?;
let config = PoolConfig {
max_connections: 5,
connection_timeout: Duration::from_secs(5),
enable_health_check: true,
health_check_timeout: Duration::from_secs(2),
};
let pool = ConnectionPool::new(Arc::new(db), config).await?;
for i in 0..10 {
let conn = pool.get().await?;
let result = conn
.connection()
.ok_or_else(|| anyhow::anyhow!("Failed to get connection"))?
.query("SELECT 1", ())
.await;
assert!(result.is_ok(), "Query {} failed", i);
}
let stats = pool.statistics().await;
assert_eq!(stats.total_checkouts, 10);
let _ = pool.shutdown().await;
tokio::time::sleep(Duration::from_millis(50)).await;
Ok(())
}
#[cfg_attr(target_os = "windows", ignore)]
#[tokio::test]
async fn test_pool_utilization_tracking() -> Result<(), Box<dyn std::error::Error>> {
let (pool, _dir) = create_test_pool().await?;
assert_eq!(pool.utilization().await, 0.0);
let _conn1 = pool.get().await?;
assert!(pool.utilization().await > 0.0);
let _conn2 = pool.get().await?;
assert!(pool.utilization().await > 0.1);
drop(_conn1);
drop(_conn2);
tokio::time::sleep(Duration::from_millis(50)).await;
assert_eq!(pool.utilization().await, 0.0);
let _ = pool.shutdown().await;
tokio::time::sleep(Duration::from_millis(50)).await;
Ok(())
}
#[cfg_attr(target_os = "windows", ignore)]
#[tokio::test]
async fn test_pool_health_checks() -> Result<(), Box<dyn std::error::Error>> {
let (pool, _dir) = create_test_pool().await?;
for _ in 0..5 {
let _conn = pool.get().await?;
}
let stats = pool.statistics().await;
assert_eq!(stats.total_health_checks_passed, 5);
assert_eq!(stats.total_health_checks_failed, 0);
let _ = pool.shutdown().await;
tokio::time::sleep(Duration::from_millis(50)).await;
Ok(())
}
#[cfg_attr(target_os = "windows", ignore)]
#[tokio::test]
async fn test_pool_graceful_shutdown() -> Result<(), Box<dyn std::error::Error>> {
let (pool, _dir) = create_test_pool().await?;
{
let _conn1 = pool.get().await?;
let _conn2 = pool.get().await?;
}
tokio::time::sleep(Duration::from_millis(100)).await;
let result = pool.shutdown().await;
assert!(result.is_ok());
tokio::time::sleep(Duration::from_millis(50)).await;
Ok(())
}
#[cfg_attr(target_os = "windows", ignore)]
#[tokio::test]
async fn test_pool_statistics_accuracy() -> Result<(), Box<dyn std::error::Error>> {
let (pool, _dir) = create_test_pool().await?;
for _ in 0..3 {
let conn = pool.get().await?;
let _result = conn
.connection()
.ok_or_else(|| anyhow::anyhow!("Failed to get connection"))?
.query("SELECT 1", ())
.await?;
drop(conn);
}
tokio::time::sleep(Duration::from_millis(50)).await;
let stats = pool.statistics().await;
assert_eq!(stats.total_checkouts, 3);
assert!(stats.total_created >= 3);
assert_eq!(stats.total_health_checks_passed, 3);
assert_eq!(stats.active_connections, 0);
let _ = pool.shutdown().await;
tokio::time::sleep(Duration::from_millis(50)).await;
Ok(())
}