//! Database integration tests use fc_common::config::DatabaseConfig; use fc_common::*; use sqlx::PgPool; #[tokio::test] async fn test_database_connection() -> anyhow::Result<()> { let config = DatabaseConfig { url: "postgresql://postgres:password@localhost/test".to_string(), max_connections: 5, min_connections: 1, connect_timeout: 5, // Short timeout for test idle_timeout: 600, max_lifetime: 1800, }; // Try to connect, skip test if database is not available let db = match Database::new(config).await { Ok(db) => db, Err(e) => { println!("Skipping test_database_connection: no PostgreSQL instance available - {}", e); return Ok(()); } }; // Test health check Database::health_check(db.pool()).await?; // Test connection info let info = db.get_connection_info().await?; assert!(!info.database.is_empty()); assert!(!info.user.is_empty()); assert!(!info.version.is_empty()); // Test pool stats let stats = db.get_pool_stats().await; assert!(stats.size >= 1); db.close().await; Ok(()) } #[tokio::test] async fn test_database_health_check() -> anyhow::Result<()> { // Try to connect, skip test if database is not available let pool = match PgPool::connect("postgresql://postgres:password@localhost/test").await { Ok(pool) => pool, Err(e) => { println!("Skipping test_database_health_check: no PostgreSQL instance available - {}", e); return Ok(()); } }; // Should succeed Database::health_check(&pool).await?; pool.close().await; Ok(()) } #[tokio::test] async fn test_connection_info() -> anyhow::Result<()> { // Try to connect, skip test if database is not available let pool = match PgPool::connect("postgresql://postgres:password@localhost/test").await { Ok(pool) => pool, Err(e) => { println!("Skipping test_connection_info: no PostgreSQL instance available - {}", e); return Ok(()); } }; let db = match Database::new(DatabaseConfig { url: "postgresql://postgres:password@localhost/test".to_string(), max_connections: 5, min_connections: 1, connect_timeout: 5, // Short timeout for test idle_timeout: 600, max_lifetime: 1800, }) .await { Ok(db) => db, Err(e) => { println!("Skipping test_connection_info: database connection failed - {}", e); pool.close().await; return Ok(()); } }; let info = db.get_connection_info().await?; assert!(!info.database.is_empty()); assert!(!info.user.is_empty()); assert!(!info.version.is_empty()); assert!(info.version.contains("PostgreSQL")); db.close().await; pool.close().await; Ok(()) } #[tokio::test] async fn test_pool_stats() -> anyhow::Result<()> { let db = match Database::new(DatabaseConfig { url: "postgresql://postgres:password@localhost/test".to_string(), max_connections: 5, min_connections: 1, connect_timeout: 5, // Short timeout for test idle_timeout: 600, max_lifetime: 1800, }) .await { Ok(db) => db, Err(e) => { println!("Skipping test_pool_stats: no PostgreSQL instance available - {}", e); return Ok(()); } }; let stats = db.get_pool_stats().await; assert!(stats.size >= 1); assert!(stats.idle >= 1); assert_eq!(stats.size, stats.idle + stats.active); db.close().await; Ok(()) } #[sqlx::test] async fn test_database_config_validation() -> anyhow::Result<()> { // Valid config let config = DatabaseConfig { url: "postgresql://user:pass@localhost/db".to_string(), max_connections: 10, min_connections: 2, connect_timeout: 30, idle_timeout: 600, max_lifetime: 1800, }; assert!(config.validate().is_ok()); // Invalid URL let mut config = config.clone(); config.url = "invalid://url".to_string(); assert!(config.validate().is_err()); // Empty URL config.url = "".to_string(); assert!(config.validate().is_err()); // Zero max connections config = DatabaseConfig { url: "postgresql://user:pass@localhost/db".to_string(), max_connections: 0, min_connections: 1, connect_timeout: 30, idle_timeout: 600, max_lifetime: 1800, }; assert!(config.validate().is_err()); // Min > max config = DatabaseConfig { url: "postgresql://user:pass@localhost/db".to_string(), max_connections: 5, min_connections: 10, connect_timeout: 30, idle_timeout: 600, max_lifetime: 1800, }; assert!(config.validate().is_err()); Ok(()) }