#[cfg(test)]
mod tls_tests {
use crate::{
host::{path::HandlerPath, HostImpl},
tests::{CA_CERT, SERVER_CERT, SERVER_KEY},
tls::TlsFactory,
VetisHosts,
};
use async_lock::RwLock;
use std::sync::Arc;
use vetis::{
errors::VetisError,
host::{handler_fn, HostConfig},
security::SecurityConfig,
Response,
};
fn create_test_hosts() -> VetisHosts<HostImpl> {
let security_config = SecurityConfig::builder()
.cert_from_bytes(SERVER_CERT.to_vec())
.key_from_bytes(SERVER_KEY.to_vec())
.ca_cert_from_bytes(CA_CERT.to_vec())
.build()
.expect("Failed to create security config");
let vhost_config = HostConfig::builder()
.hostname("localhost")
.root_directory("src/tests".into())
.security(security_config)
.build()
.expect("Failed to create virtual host config");
let mut host = HostImpl::new(vhost_config);
let handler_path = HandlerPath::builder()
.uri("/")
.handler(handler_fn(|_req| async move {
Ok::<_, VetisError>(
Response::builder()
.status(http::StatusCode::OK)
.text("Test response"),
)
}))
.build()
.unwrap();
host.add_path(handler_path);
let mut hosts = std::collections::HashMap::new();
hosts.insert(Arc::from("localhost"), host);
Arc::new(RwLock::new(hosts))
}
fn create_test_hosts_no_security() -> VetisHosts<HostImpl> {
let vhost_config = HostConfig::builder()
.hostname("localhost")
.root_directory("src/tests".into())
.build()
.expect("Failed to create virtual host config");
let mut host = HostImpl::new(vhost_config);
let handler_path = HandlerPath::builder()
.uri("/")
.handler(handler_fn(|_req| async move {
Ok::<_, VetisError>(
Response::builder()
.status(http::StatusCode::OK)
.text("Test response"),
)
}))
.build()
.unwrap();
host.add_path(handler_path);
let mut hosts = std::collections::HashMap::new();
hosts.insert(Arc::from("localhost"), host);
Arc::new(RwLock::new(hosts))
}
fn create_test_hosts_invalid_key() -> VetisHosts<HostImpl> {
let security_config = SecurityConfig::builder()
.cert_from_bytes(SERVER_CERT.to_vec())
.key_from_bytes(vec![0x01, 0x02, 0x03]) .build()
.expect("Failed to create security config");
let vhost_config = HostConfig::builder()
.hostname("localhost")
.root_directory("src/tests".into())
.security(security_config)
.build()
.expect("Failed to create virtual host config");
let mut host = HostImpl::new(vhost_config);
let handler_path = HandlerPath::builder()
.uri("/")
.handler(handler_fn(|_req| async move {
Ok::<_, VetisError>(
Response::builder()
.status(http::StatusCode::OK)
.text("Test response"),
)
}))
.build()
.unwrap();
host.add_path(handler_path);
let mut hosts = std::collections::HashMap::new();
hosts.insert(Arc::from("localhost"), host);
Arc::new(RwLock::new(hosts))
}
async fn do_create_tls_config_success() {
let hosts = create_test_hosts();
let alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
let result = TlsFactory::create_tls_config(hosts, alpn_protocols).await;
assert!(result.is_ok(), "TLS config creation should succeed");
let tls_config = result.unwrap();
assert!(tls_config.is_some(), "TLS config should be Some");
let config = tls_config.unwrap();
assert_eq!(config.alpn_protocols, vec![b"h2".to_vec(), b"http/1.1".to_vec()]);
assert_eq!(config.max_early_data_size, u32::MAX);
}
#[compio::test]
async fn test_create_tls_config_success() {
do_create_tls_config_success().await;
}
async fn do_create_tls_config_no_security() {
let hosts = create_test_hosts_no_security();
let alpn_protocols = vec![b"http/1.1".to_vec()];
let result = TlsFactory::create_tls_config(hosts, alpn_protocols).await;
assert!(result.is_ok(), "TLS config creation should succeed even without security");
let tls_config = result.unwrap();
assert!(tls_config.is_some(), "TLS config should be Some");
let config = tls_config.unwrap();
assert_eq!(config.alpn_protocols, vec![b"http/1.1".to_vec()]);
}
#[compio::test]
async fn test_create_tls_config_no_security() {
do_create_tls_config_no_security().await;
}
async fn do_create_tls_config_invalid_private_key() {
let hosts = create_test_hosts_invalid_key();
let alpn_protocols = vec![b"http/1.1".to_vec()];
let result = TlsFactory::create_tls_config(hosts, alpn_protocols).await;
assert!(result.is_err(), "TLS config creation should fail with invalid key");
match result.unwrap_err() {
VetisError::Tls(msg) => {
assert!(msg.contains("Failed to parse private key"));
}
_ => panic!("Expected Tls error"),
}
}
#[compio::test]
async fn test_create_tls_config_invalid_private_key() {
do_create_tls_config_invalid_private_key().await;
}
async fn do_create_tls_config_empty_alpn() {
let hosts = create_test_hosts();
let alpn_protocols = vec![];
let result = TlsFactory::create_tls_config(hosts, alpn_protocols).await;
assert!(result.is_ok(), "TLS config creation should succeed with empty ALPN");
let tls_config = result.unwrap();
assert!(tls_config.is_some(), "TLS config should be Some");
let config = tls_config.unwrap();
assert!(
config
.alpn_protocols
.is_empty(),
"ALPN protocols should be empty"
);
}
#[compio::test]
async fn test_create_tls_config_empty_alpn() {
do_create_tls_config_empty_alpn().await;
}
async fn do_create_tls_config_multiple_hosts() {
let mut hosts = std::collections::HashMap::new();
let security_config1 = SecurityConfig::builder()
.cert_from_bytes(SERVER_CERT.to_vec())
.key_from_bytes(SERVER_KEY.to_vec())
.build()
.expect("Failed to create security config");
let vhost_config1 = HostConfig::builder()
.hostname("localhost")
.root_directory("src/tests".into())
.security(security_config1)
.build()
.expect("Failed to create virtual host config");
let mut host1 = HostImpl::new(vhost_config1);
let handler_path = HandlerPath::builder()
.uri("/")
.handler(handler_fn(|_req| async move {
Ok::<_, VetisError>(
Response::builder()
.status(http::StatusCode::OK)
.text("Test response"),
)
}))
.build()
.unwrap();
host1.add_path(handler_path);
let vhost_config2 = HostConfig::builder()
.hostname("test.com")
.root_directory("src/tests".into())
.build()
.expect("Failed to create virtual host config");
let mut host2 = HostImpl::new(vhost_config2);
let handler_path = HandlerPath::builder()
.uri("/")
.handler(handler_fn(|_req| async move {
Ok::<_, VetisError>(
Response::builder()
.status(http::StatusCode::OK)
.text("Test response"),
)
}))
.build()
.unwrap();
host2.add_path(handler_path);
hosts.insert(Arc::from("localhost"), host1);
hosts.insert(Arc::from("test.com"), host2);
let hosts = Arc::new(RwLock::new(hosts));
let alpn_protocols = vec![b"h2".to_vec()];
let result = TlsFactory::create_tls_config(hosts, alpn_protocols).await;
assert!(result.is_ok(), "TLS config creation should succeed with multiple hosts");
let tls_config = result.unwrap();
assert!(tls_config.is_some(), "TLS config should be Some");
}
#[compio::test]
async fn test_create_tls_config_multiple_hosts() {
do_create_tls_config_multiple_hosts().await;
}
async fn do_create_tls_config_with_ca_cert() {
let hosts = create_test_hosts();
let alpn_protocols = vec![b"http/1.1".to_vec()];
let result = TlsFactory::create_tls_config(hosts, alpn_protocols).await;
assert!(result.is_ok(), "TLS config creation should succeed with CA cert");
let tls_config = result.unwrap();
assert!(tls_config.is_some(), "TLS config should be Some");
let config = tls_config.unwrap();
assert_eq!(config.alpn_protocols, vec![b"http/1.1".to_vec()]);
}
#[compio::test]
async fn test_create_tls_config_with_ca_cert() {
do_create_tls_config_with_ca_cert().await;
}
#[test]
fn test_tls_factory_struct_exists() {
let _factory = TlsFactory {};
}
}