pollux/tests/virtual_host_routing.rs
Jeena 55fe47b172 Replace custom logging with tracing crate and RUST_LOG env var
- Remove custom logging module and init_logging function
- Update main.rs to use tracing_subscriber with EnvFilter
- Remove log_level from global config structure
- Update documentation and tests to use RUST_LOG
- Format long lines in config.rs and test files for better readability
2026-01-22 05:25:46 +00:00

236 lines
7 KiB
Rust

mod common;
/// Make a Gemini request over TLS and return the response
fn make_gemini_request(host: &str, port: u16, request: &str) -> String {
// Use the Python client for TLS requests
use std::process::Command;
let url = request.to_string();
let output = Command::new("python3")
.arg("tests/gemini_test_client.py")
.arg(url)
.env("GEMINI_PORT", &port.to_string())
.env("GEMINI_CONNECT_HOST", host)
.output()
.expect("Failed to run test client");
String::from_utf8(output.stdout).unwrap().trim().to_string()
}
// Unit tests for hostname extraction - temporarily disabled due to import issues
// TODO: Fix import path for server functions
/*
#[test]
fn test_extract_hostname_and_path_valid_urls() {
// Test various valid Gemini URLs
let test_cases = vec![
("gemini://example.com/", ("example.com", "/")),
("gemini://example.com/page.gmi", ("example.com", "/page.gmi")),
("gemini://sub.example.com/path/to/file.txt", ("sub.example.com", "/path/to/file.txt")),
("gemini://localhost:1965/", ("localhost", "/")),
("gemini://test.com", ("test.com", "/")),
];
for (url, expected) in test_cases {
let result = pollux::server::extract_hostname_and_path(url);
assert!(result.is_ok(), "Failed to parse: {}", url);
let (hostname, path) = result.unwrap();
assert_eq!(hostname, expected.0, "Hostname mismatch for: {}", url);
assert_eq!(path, expected.1, "Path mismatch for: {}", url);
}
}
#[test]
fn test_extract_hostname_and_path_invalid_urls() {
// Test invalid URLs
let invalid_urls = vec![
"", // empty
"http://example.com/", // wrong scheme
"gemini://", // no hostname
"//example.com/", // no scheme
"gemini://example.com:99999/", // port is handled by path
"gemini://example.com?query", // query params not supported
];
for url in invalid_urls {
let result = pollux::server::extract_hostname_and_path(url);
assert!(result.is_err(), "Should fail for invalid URL: {}", url);
}
}
*/
#[test]
fn test_virtual_host_routing_multiple_hosts() {
let temp_dir = common::setup_test_environment();
let port = 2000 + (std::process::id() % 1000) as u16;
// Create directories for hosts (content already exists from setup_test_environment)
std::fs::create_dir(temp_dir.path().join("site1")).unwrap();
std::fs::create_dir(temp_dir.path().join("site2")).unwrap();
// Create config with two hosts
let config_path = temp_dir.path().join("config.toml");
let content = format!(
r#"
bind_host = "127.0.0.1"
port = {}
["site1.com"]
root = "{}"
cert = "{}"
key = "{}"
["site2.org"]
root = "{}"
cert = "{}"
key = "{}"
"#,
port,
temp_dir.path().join("site1").display(),
temp_dir.path().join("cert.pem").display(),
temp_dir.path().join("key.pem").display(),
temp_dir.path().join("site2").display(),
temp_dir.path().join("cert.pem").display(),
temp_dir.path().join("key.pem").display()
);
std::fs::write(&config_path, content).unwrap();
// Create host-specific content
std::fs::create_dir_all(temp_dir.path().join("site1")).unwrap();
std::fs::create_dir_all(temp_dir.path().join("site2")).unwrap();
std::fs::write(
temp_dir.path().join("site1").join("index.gmi"),
"# Site 1 Content\n",
)
.unwrap();
std::fs::write(
temp_dir.path().join("site2").join("index.gmi"),
"# Site 2 Content\n",
)
.unwrap();
// Use the same certs for both hosts (server uses first cert anyway)
// Start server with TLS
let mut server_process = std::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));
// Test request to site1.com with TLS
let response1 = make_gemini_request("127.0.0.1", port, "gemini://site1.com/index.gmi");
assert!(
response1.starts_with("20"),
"Expected success response for site1.com, got: {}",
response1
);
// Test request to site2.org
let response2 = make_gemini_request("127.0.0.1", port, "gemini://site2.org/index.gmi");
assert!(
response2.starts_with("20"),
"Expected success response for site2.org, got: {}",
response2
);
server_process.kill().unwrap();
}
#[test]
fn test_virtual_host_routing_known_hostname() {
let temp_dir = common::setup_test_environment();
let port = 2100 + (std::process::id() % 1000) as u16;
// Content directory already created by setup_test_environment
// Config with only one host
let config_path = temp_dir.path().join("config.toml");
let content = format!(
r#"
bind_host = "127.0.0.1"
port = {}
["example.com"]
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, content).unwrap();
// Start server with TLS
let mut server_process = std::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));
// Test request to unknown hostname
let response = make_gemini_request("127.0.0.1", port, "gemini://unknown.com/index.gmi");
assert!(
response.starts_with("53"),
"Should return status 53 for unknown hostname, got: {}",
response
);
server_process.kill().unwrap();
}
#[test]
fn test_virtual_host_routing_malformed_url() {
let temp_dir = common::setup_test_environment();
let port = 2200 + (std::process::id() % 1000) as u16;
// Content directory already created by setup_test_environment
// Config with one host
let config_path = temp_dir.path().join("config.toml");
let content = format!(
r#"
bind_host = "127.0.0.1"
port = {}
["example.com"]
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, content).unwrap();
// Start server with TLS
let mut server_process = std::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));
// Test malformed URL (wrong protocol)
let response = make_gemini_request("127.0.0.1", port, "http://example.com/index.gmi");
assert!(
response.starts_with("59"),
"Should return status 59 for malformed URL, got: {}",
response
);
server_process.kill().unwrap();
}