mod common; use std::process::Command; #[test] fn test_missing_config_file() { let output = Command::new(env!("CARGO_BIN_EXE_pollux")) .arg("--config") .arg("nonexistent.toml") .env("RUST_LOG", "error") .output() .unwrap(); assert!(!output.status.success()); let stderr = String::from_utf8(output.stderr).unwrap(); let stdout = String::from_utf8(output.stdout).unwrap(); assert!(stderr.contains("Config file 'nonexistent.toml' not found")); assert!(stdout.contains("Create the config file with")); } #[test] fn test_nonexistent_root_directory() { let temp_dir = common::setup_test_environment(); let config_path = temp_dir.path().join("config.toml"); let config_content = format!( r#" bind_host = "127.0.0.1" ["example.com"] root = "/definitely/does/not/exist" cert = "{}" key = "{}" "#, temp_dir.path().join("cert.pem").display(), temp_dir.path().join("key.pem").display() ); std::fs::write(&config_path, config_content).unwrap(); let output = Command::new(env!("CARGO_BIN_EXE_pollux")) .arg("--config") .arg(&config_path) .env("RUST_LOG", "error") .output() .unwrap(); assert!(!output.status.success()); let stderr = String::from_utf8(output.stderr).unwrap(); assert!(stderr.contains("Failed to parse config file")); assert!(stderr.contains( "Error for host 'example.com': Root directory '/definitely/does/not/exist' does not exist" )); } #[test] fn test_missing_certificate_file() { let temp_dir = common::setup_test_environment(); let config_path = temp_dir.path().join("config.toml"); let config_content = format!( r#" bind_host = "127.0.0.1" ["example.com"] root = "{}" cert = "/nonexistent/cert.pem" key = "{}" "#, temp_dir.path().join("content").display(), temp_dir.path().join("key.pem").display() ); std::fs::write(&config_path, config_content).unwrap(); let output = Command::new(env!("CARGO_BIN_EXE_pollux")) .arg("--config") .arg(&config_path) .env("RUST_LOG", "error") .output() .unwrap(); assert!(!output.status.success()); let stderr = String::from_utf8(output.stderr).unwrap(); assert!(stderr.contains( "Error for host 'example.com': Certificate file '/nonexistent/cert.pem' does not exist" )); assert!(stderr.contains("Generate or obtain TLS certificates for your domain")); } #[test] fn test_valid_config_startup() { let temp_dir = common::setup_test_environment(); let port = 1967 + (std::process::id() % 1000) as u16; let config_path = temp_dir.path().join("config.toml"); let config_content = format!( r#" bind_host = "127.0.0.1" port = {} ["localhost"] root = "{}" cert = "{}" key = "{}" "#, port, temp_dir.path().join("content").display(), temp_dir.path().join("cert.pem").display(), temp_dir.path().join("key.pem").display() ); std::fs::write(&config_path, config_content).unwrap(); let mut server_process = Command::new(env!("CARGO_BIN_EXE_pollux")) .arg("--config") .arg(&config_path) .spawn() .unwrap(); // Wait for server to start std::thread::sleep(std::time::Duration::from_millis(500)); // Check server is still running (didn't exit with error) assert!( server_process.try_wait().unwrap().is_none(), "Server should still be running with valid config" ); // Kill server server_process.kill().unwrap(); } #[test] fn test_valid_multiple_hosts_startup() { let temp_dir = common::setup_test_environment(); let port = 1965 + (std::process::id() % 1000) as u16; // Create host directories std::fs::create_dir(temp_dir.path().join("host1")).unwrap(); std::fs::create_dir(temp_dir.path().join("host2")).unwrap(); // Generate certificates for both hosts let cert1_path = temp_dir.path().join("host1_cert.pem"); let key1_path = temp_dir.path().join("host1_key.pem"); let cert2_path = temp_dir.path().join("host2_cert.pem"); let key2_path = temp_dir.path().join("host2_key.pem"); // Generate certificate for host1 let cert_result1 = std::process::Command::new("openssl") .args(&[ "req", "-x509", "-newkey", "rsa:2048", "-keyout", &key1_path.to_string_lossy(), "-out", &cert1_path.to_string_lossy(), "-days", "1", "-nodes", "-subj", "/CN=host1.com", ]) .output(); // Generate certificate for host2 let cert_result2 = std::process::Command::new("openssl") .args(&[ "req", "-x509", "-newkey", "rsa:2048", "-keyout", &key2_path.to_string_lossy(), "-out", &cert2_path.to_string_lossy(), "-days", "1", "-nodes", "-subj", "/CN=host2.com", ]) .output(); if cert_result1.is_err() || cert_result2.is_err() { panic!("Failed to generate test certificates for multiple hosts test"); } let config_path = temp_dir.path().join("config.toml"); let config_content = format!( r#" bind_host = "127.0.0.1" port = {} ["host1.com"] root = "{}" cert = "{}" key = "{}" ["host2.com"] root = "{}" cert = "{}" key = "{}" "#, port, temp_dir.path().join("host1").display(), cert1_path.display(), key1_path.display(), temp_dir.path().join("host2").display(), cert2_path.display(), key2_path.display() ); std::fs::write(&config_path, config_content).unwrap(); let mut server_process = Command::new(env!("CARGO_BIN_EXE_pollux")) .arg("--config") .arg(&config_path) .spawn() .unwrap(); // Wait for server to start std::thread::sleep(std::time::Duration::from_millis(500)); // Check server is still running (didn't exit with error) assert!( server_process.try_wait().unwrap().is_none(), "Server should start with valid multiple host config" ); // Kill server server_process.kill().unwrap(); } #[test] fn test_multiple_hosts_missing_certificate() { let temp_dir = common::setup_test_environment(); let config_path = temp_dir.path().join("config.toml"); // Create host directories std::fs::create_dir(temp_dir.path().join("host1")).unwrap(); std::fs::create_dir(temp_dir.path().join("host2")).unwrap(); // Generate certificate for only one host let cert1_path = temp_dir.path().join("host1_cert.pem"); let key1_path = temp_dir.path().join("host1_key.pem"); let cert_result = std::process::Command::new("openssl") .args(&[ "req", "-x509", "-newkey", "rsa:2048", "-keyout", &key1_path.to_string_lossy(), "-out", &cert1_path.to_string_lossy(), "-days", "1", "-nodes", "-subj", "/CN=host1.com", ]) .output(); if cert_result.is_err() { panic!("Failed to generate test certificate"); } let config_content = format!( r#" bind_host = "127.0.0.1" ["host1.com"] root = "{}" cert = "{}" key = "{}" ["host2.com"] root = "{}" cert = "/nonexistent/cert.pem" key = "/nonexistent/key.pem" "#, temp_dir.path().join("host1").display(), cert1_path.display(), key1_path.display(), temp_dir.path().join("host2").display() ); std::fs::write(&config_path, config_content).unwrap(); let output = Command::new(env!("CARGO_BIN_EXE_pollux")) .arg("--config") .arg(&config_path) .env("RUST_LOG", "error") .output() .unwrap(); assert!(!output.status.success()); let stderr = String::from_utf8(output.stderr).unwrap(); assert!(stderr.contains( "Error for host 'host2.com': Certificate file '/nonexistent/cert.pem' does not exist" )); } #[test] fn test_multiple_hosts_invalid_hostname() { let temp_dir = common::setup_test_environment(); let config_path = temp_dir.path().join("config.toml"); // Create host directories std::fs::create_dir(temp_dir.path().join("validhost")).unwrap(); std::fs::create_dir(temp_dir.path().join("invalidhost")).unwrap(); // Generate certificates for both hosts let cert1_path = temp_dir.path().join("valid_cert.pem"); let key1_path = temp_dir.path().join("valid_key.pem"); let cert2_path = temp_dir.path().join("invalid_cert.pem"); let key2_path = temp_dir.path().join("invalid_key.pem"); // Generate certificate for valid host let cert_result1 = std::process::Command::new("openssl") .args(&[ "req", "-x509", "-newkey", "rsa:2048", "-keyout", &key1_path.to_string_lossy(), "-out", &cert1_path.to_string_lossy(), "-days", "1", "-nodes", "-subj", "/CN=valid.com", ]) .output(); // Generate certificate for invalid host (hostname validation happens before cert validation) let cert_result2 = std::process::Command::new("openssl") .args(&[ "req", "-x509", "-newkey", "rsa:2048", "-keyout", &key2_path.to_string_lossy(), "-out", &cert2_path.to_string_lossy(), "-days", "1", "-nodes", "-subj", "/CN=invalid.com", ]) .output(); if cert_result1.is_err() || cert_result2.is_err() { panic!("Failed to generate test certificates"); } let config_content = format!( r#" bind_host = "127.0.0.1" ["valid.com"] root = "{}" cert = "{}" key = "{}" ["bad..host.com"] root = "{}" cert = "{}" key = "{}" "#, temp_dir.path().join("validhost").display(), cert1_path.display(), key1_path.display(), temp_dir.path().join("invalidhost").display(), cert2_path.display(), key2_path.display() ); std::fs::write(&config_path, config_content).unwrap(); let output = Command::new(env!("CARGO_BIN_EXE_pollux")) .arg("--config") .arg(&config_path) .env("RUST_LOG", "error") .output() .unwrap(); assert!(!output.status.success()); let stderr = String::from_utf8(output.stderr).unwrap(); assert!(stderr.contains("Invalid hostname 'bad..host.com'. Hostnames must be valid DNS names.")); }