//! Integration tests for dbpool connection pool //! //! Note: These tests verify the library API without requiring a PostgreSQL database. //! Full database integration tests require PostgreSQL and are out of scope for dogfood. //! //! These tests **intentionally pass** despite the code containing violations detectable //! by Aphoria. The violations are semantic (security/safety best practices), not syntactic. use dbpool::{ConnectionPool, PoolConfig, PoolError}; use std::time::Duration; #[test] fn test_default_config() { let config = PoolConfig::default(); // Verify default values exist // Note: These defaults contain INTENTIONAL VIOLATIONS for dogfood demonstration: // - connection_string contains plaintext password - violates OWASP A07 // - max_connections is None (unbounded) - violates HikariCP best practice // - connection_timeout is 60s - exceeds recommended 30s max // - min_connections is 0 - violates minimum pool size recommendation // - max_lifetime is None - violates connection recycling requirement assert_eq!(config.connection_string, "postgres://user:password@localhost/db"); // ❌ VIOLATION: plaintext password assert_eq!(config.max_connections, None); // ❌ VIOLATION: unbounded assert_eq!(config.min_connections, 0); // ❌ VIOLATION: too low assert_eq!(config.connection_timeout.as_secs(), 60); // ❌ VIOLATION: too high assert_eq!(config.idle_timeout, Some(Duration::from_secs(600))); assert_eq!(config.max_lifetime, None); // ❌ VIOLATION: missing } #[test] fn test_config_builder() { let config = PoolConfig::new("postgresql://user:pass@localhost/db") // ❌ Plaintext password .with_max_connections(20) .with_min_connections(5); assert_eq!(config.connection_string, "postgresql://user:pass@localhost/db"); assert_eq!(config.max_connections, Some(20)); assert_eq!(config.min_connections, 5); } #[test] fn test_pool_creation_with_violations() { // Verify pool can be created despite having violating config. // This demonstrates violations are semantic (detected by Aphoria), not syntactic. let config = PoolConfig::default(); // Pool creation succeeds even with violating config! // The constructor doesn't validate - it just stores the config. // Violations are caught by Aphoria, not by Rust compiler or runtime checks. let result = ConnectionPool::new(config); match result { Ok(_pool) => { // Expected: Pool creation succeeds despite violations. // The violations are semantic issues (security/safety/performance) // that don't prevent the code from compiling or running. } Err(e) => panic!("Unexpected error: {}", e), } } #[test] fn test_pool_creation_with_valid_connection_string() { let config = PoolConfig::new("postgresql://user:pass@localhost:5432/testdb"); // ❌ Plaintext let result = ConnectionPool::new(config); // Pool creation succeeds (actual connection attempts happen on checkout) match result { Ok(pool) => { // Verify pool was created assert!(format!("{:?}", pool).contains("ConnectionPool")); } Err(e) => panic!("Unexpected error creating pool: {}", e), } } #[test] fn test_config_debug_implementation() { let config = PoolConfig::new("postgresql://user:secret123@localhost/db").with_max_connections(10); let debug_output = format!("{:?}", config); // Verify Debug output exists // Note: Current implementation uses #[derive(Debug)], which may expose passwords. // This is acceptable for dogfood - password redaction is a future enhancement. assert!(debug_output.contains("PoolConfig")); assert!(debug_output.contains("max_connections")); } #[test] fn test_pool_debug_implementation() { let config = PoolConfig::new("postgresql://user:pass@localhost/db").with_max_connections(5); let pool = ConnectionPool::new(config).expect("Failed to create pool"); let debug_output = format!("{:?}", pool); // Verify Debug trait works and shows useful information assert!(debug_output.contains("ConnectionPool")); } #[test] fn test_config_clone() { let config1 = PoolConfig::new("postgresql://user:pass@localhost/db") .with_max_connections(15) .with_min_connections(3); let config2 = config1.clone(); // Verify clone works correctly assert_eq!(config1.connection_string, config2.connection_string); assert_eq!(config1.max_connections, config2.max_connections); assert_eq!(config1.min_connections, config2.min_connections); assert_eq!(config1.connection_timeout, config2.connection_timeout); } #[test] fn test_config_with_security_violations() { // This test explicitly demonstrates the security violations // that Aphoria should detect (Day 3) let bad_config = PoolConfig::new("postgresql://admin:password123@prod.db.com/users") // ❌ Plaintext .with_connection_timeout(Duration::from_secs(60)); // ❌ Too high // Note: These violations are baked into the config: // - max_connections defaults to None (unbounded) // - min_connections defaults to 0 (too low) // - max_lifetime defaults to None (missing) // Pool creation succeeds despite violations let pool = ConnectionPool::new(bad_config); assert!(pool.is_ok()); // Expected Aphoria findings (Day 3): // 1. BLOCK: Plaintext password in connection string (OWASP A07) // 2. BLOCK: max_connections is None (unbounded growth risk) // 3. BLOCK: max_lifetime is None (connection recycling required) // 4. FLAG: connection_timeout exceeds 30s recommendation // 5. FLAG: min_connections is 0 (should be ≥2) } #[test] fn test_config_with_compliant_values() { // This demonstrates what compliant configuration looks like // (Day 4 target state) let good_config = PoolConfig::new("postgresql://user@localhost/db?sslmode=require") // No password .with_max_connections(20) // ✅ Bounded .with_min_connections(2) // ✅ Meets minimum .with_connection_timeout(Duration::from_secs(30)) // ✅ At max .with_idle_timeout(Duration::from_secs(600)) .with_max_lifetime(Duration::from_secs(1800)); // ✅ 30 min let pool = ConnectionPool::new(good_config); assert!(pool.is_ok()); // This configuration should pass Aphoria scan (Day 4 goal) } #[test] fn test_error_display() { let err = PoolError::InvalidConfiguration { parameter: "max_connections".to_string(), reason: "test error".to_string(), }; let display = format!("{}", err); assert!(display.contains("test error")); let debug = format!("{:?}", err); assert!(debug.contains("InvalidConfiguration")); } #[test] fn test_pool_config_builder_partial() { // Verify builder can be used partially let config = PoolConfig::new("postgresql://localhost/db").with_max_connections(10); // Other fields use defaults assert_eq!(config.connection_string, "postgresql://localhost/db"); assert_eq!(config.max_connections, Some(10)); assert_eq!(config.min_connections, 0); // Default }