Rustelo/server/tests/config_integration_test.rs

656 lines
14 KiB
Rust
Raw Normal View History

2025-07-07 23:05:19 +01:00
use server::config::{Config, ConfigError, Environment, Protocol};
use std::fs;
use tempfile::tempdir;
#[tokio::test]
async fn test_config_loading_from_toml_file() {
let dir = tempdir().unwrap();
let config_path = dir.path().join("config.toml");
let config_content = r#"
[server]
protocol = "http"
host = "127.0.0.1"
port = 3030
environment = "development"
log_level = "info"
[database]
url = "postgresql://localhost:5432/test"
max_connections = 10
min_connections = 1
connect_timeout = 30
idle_timeout = 600
max_lifetime = 1800
[session]
secret = "test-secret"
cookie_name = "session_id"
cookie_secure = false
cookie_http_only = true
cookie_same_site = "lax"
max_age = 3600
[cors]
allowed_origins = ["http://localhost:3030"]
allowed_methods = ["GET", "POST"]
allowed_headers = ["Content-Type"]
allow_credentials = true
max_age = 3600
[static]
assets_dir = "public"
site_root = "target/site"
site_pkg_dir = "pkg"
[server_dirs]
public_dir = "public"
uploads_dir = "uploads"
logs_dir = "logs"
temp_dir = "tmp"
cache_dir = "cache"
config_dir = "config"
data_dir = "data"
backup_dir = "backups"
[security]
enable_csrf = true
csrf_token_name = "csrf_token"
rate_limit_requests = 100
rate_limit_window = 60
bcrypt_cost = 12
[oauth]
enabled = false
[email]
enabled = false
provider = "console"
smtp_host = "localhost"
smtp_port = 587
smtp_username = ""
smtp_password = ""
smtp_use_tls = true
smtp_use_starttls = false
sendgrid_api_key = ""
sendgrid_endpoint = "https://api.sendgrid.com/v3/mail/send"
from_email = "test@example.com"
from_name = "Test"
template_dir = "templates/email"
[redis]
enabled = false
url = "redis://localhost:6379"
pool_size = 10
connection_timeout = 5
command_timeout = 5
[app]
name = "Test App"
version = "0.1.0"
debug = true
enable_metrics = false
enable_health_check = true
enable_compression = true
max_request_size = 10485760
[logging]
format = "text"
level = "info"
file_path = "logs/app.log"
max_file_size = 10485760
max_files = 5
enable_console = true
enable_file = false
[content]
enabled = false
content_dir = "content"
cache_enabled = true
cache_ttl = 3600
max_file_size = 5242880
[features]
[features.auth]
enabled = true
jwt = true
oauth = false
two_factor = false
sessions = true
password_reset = true
email_verification = true
account_lockout = true
[features.rbac]
enabled = false
database_access = false
file_access = false
content_access = false
api_access = false
categories = false
tags = false
caching = false
audit_logging = false
toml_config = false
hierarchical_permissions = false
dynamic_rules = false
[features.content]
enabled = true
markdown = true
syntax_highlighting = false
file_uploads = false
versioning = false
scheduling = false
seo = false
[features.security]
csrf = true
security_headers = true
rate_limiting = true
input_sanitization = true
sql_injection_protection = true
xss_protection = true
content_security_policy = true
[features.performance]
response_caching = false
query_caching = false
compression = true
connection_pooling = true
lazy_loading = false
background_tasks = false
[features.custom]
"#;
fs::write(&config_path, config_content).unwrap();
let config = Config::load_from_file(&config_path).unwrap();
// Verify server configuration
assert_eq!(config.server.host, "127.0.0.1");
assert_eq!(config.server.port, 3030);
assert_eq!(config.server.log_level, "info");
assert!(matches!(config.server.protocol, Protocol::Http));
assert!(matches!(
config.server.environment,
Environment::Development
));
// Verify database configuration
assert_eq!(config.database.url, "postgresql://localhost:5432/test");
assert_eq!(config.database.max_connections, 10);
// Verify application configuration
assert_eq!(config.app.name, "Test App");
assert_eq!(config.app.version, "0.1.0");
assert_eq!(config.app.debug, true);
// Verify server directories configuration
assert_eq!(config.server_dirs.public_dir, "public");
assert_eq!(config.server_dirs.uploads_dir, "uploads");
assert_eq!(config.server_dirs.logs_dir, "logs");
assert_eq!(config.server_dirs.cache_dir, "cache");
// Verify helper methods
assert_eq!(config.server_address(), "127.0.0.1:3030");
assert_eq!(config.server_url(), "http://127.0.0.1:3030");
assert_eq!(config.is_development(), true);
assert_eq!(config.is_production(), false);
assert_eq!(config.requires_tls(), false);
}
#[tokio::test]
async fn test_https_configuration_validation() {
let dir = tempdir().unwrap();
let config_path = dir.path().join("config.toml");
// Create a configuration that should fail validation (HTTPS without TLS config)
let config_content = r#"
[server]
protocol = "https"
host = "127.0.0.1"
port = 443
environment = "production"
log_level = "info"
[database]
url = "postgresql://localhost:5432/test"
max_connections = 10
min_connections = 1
connect_timeout = 30
idle_timeout = 600
max_lifetime = 1800
[session]
secret = "test-secret"
cookie_name = "session_id"
cookie_secure = false
cookie_http_only = true
cookie_same_site = "lax"
max_age = 3600
[cors]
allowed_origins = ["http://localhost:3030"]
allowed_methods = ["GET", "POST"]
allowed_headers = ["Content-Type"]
allow_credentials = true
max_age = 3600
[static]
assets_dir = "public"
site_root = "target/site"
site_pkg_dir = "pkg"
[server_dirs]
public_dir = "public"
uploads_dir = "uploads"
logs_dir = "logs"
temp_dir = "tmp"
cache_dir = "cache"
config_dir = "config"
data_dir = "data"
backup_dir = "backups"
[security]
enable_csrf = true
csrf_token_name = "csrf_token"
rate_limit_requests = 100
rate_limit_window = 60
bcrypt_cost = 12
[oauth]
enabled = false
[email]
enabled = false
provider = "console"
smtp_host = "localhost"
smtp_port = 587
smtp_username = ""
smtp_password = ""
smtp_use_tls = true
smtp_use_starttls = false
sendgrid_api_key = ""
sendgrid_endpoint = "https://api.sendgrid.com/v3/mail/send"
from_email = "test@example.com"
from_name = "Test"
template_dir = "templates/email"
[redis]
enabled = false
url = "redis://localhost:6379"
pool_size = 10
connection_timeout = 5
command_timeout = 5
[app]
name = "Test App"
version = "0.1.0"
debug = true
enable_metrics = false
enable_health_check = true
enable_compression = true
max_request_size = 10485760
[logging]
format = "text"
level = "info"
file_path = "logs/app.log"
max_file_size = 10485760
max_files = 5
enable_console = true
enable_file = false
[content]
enabled = false
content_dir = "content"
cache_enabled = true
cache_ttl = 3600
max_file_size = 5242880
[features]
[features.auth]
enabled = true
jwt = true
oauth = false
two_factor = false
sessions = true
password_reset = true
email_verification = true
[features.rbac]
enabled = false
database_access = false
file_access = false
content_access = false
api_access = false
categories = false
tags = false
caching = false
audit_logging = false
toml_config = false
hierarchical_permissions = false
dynamic_rules = false
[features.content]
enabled = true
markdown = true
syntax_highlighting = false
file_uploads = false
versioning = false
scheduling = false
seo = false
[features.security]
csrf = true
security_headers = true
rate_limiting = true
input_sanitization = true
sql_injection_protection = true
xss_protection = true
content_security_policy = true
[features.performance]
response_caching = false
query_caching = false
compression = true
connection_pooling = true
lazy_loading = false
background_tasks = false
[features.custom]
"#;
fs::write(&config_path, config_content).unwrap();
let config = Config::load_from_file(&config_path).unwrap();
// This should fail because HTTPS is enabled but no TLS config is provided
let result = config.validate();
assert!(result.is_err());
match result.unwrap_err() {
ConfigError::ValidationError(msg) => {
assert!(msg.contains("HTTPS protocol requires TLS configuration"));
}
other => {
panic!("Expected ValidationError about HTTPS/TLS, got: {:?}", other);
}
}
}
#[tokio::test]
async fn test_invalid_toml_format() {
let dir = tempdir().unwrap();
let config_path = dir.path().join("config.toml");
// Create an invalid TOML file
let invalid_toml = r#"
[server
protocol = "http"
host = "127.0.0.1"
port = 3030
"#;
fs::write(&config_path, invalid_toml).unwrap();
let result = Config::load_from_file(&config_path);
assert!(result.is_err());
match result.unwrap_err() {
ConfigError::ParseError(_) => {
// Expected error
}
other => {
panic!("Expected ParseError, got: {:?}", other);
}
}
}
#[tokio::test]
async fn test_database_pool_config() {
let dir = tempdir().unwrap();
let config_path = dir.path().join("config.toml");
let config_content = r#"
[server]
protocol = "http"
host = "127.0.0.1"
port = 3030
environment = "development"
log_level = "info"
[database]
url = "postgresql://localhost:5432/test"
max_connections = 15
min_connections = 2
connect_timeout = 45
idle_timeout = 900
max_lifetime = 3600
[session]
secret = "test-secret"
cookie_name = "session_id"
cookie_secure = false
cookie_http_only = true
cookie_same_site = "lax"
max_age = 3600
[cors]
allowed_origins = ["http://localhost:3030"]
allowed_methods = ["GET", "POST"]
allowed_headers = ["Content-Type"]
allow_credentials = true
max_age = 3600
[static]
assets_dir = "public"
site_root = "target/site"
site_pkg_dir = "pkg"
[server_dirs]
public_dir = "public"
uploads_dir = "uploads"
logs_dir = "logs"
temp_dir = "tmp"
cache_dir = "cache"
config_dir = "config"
data_dir = "data"
backup_dir = "backups"
[security]
enable_csrf = true
csrf_token_name = "csrf_token"
rate_limit_requests = 100
rate_limit_window = 60
bcrypt_cost = 12
[oauth]
enabled = false
[email]
enabled = false
provider = "console"
smtp_host = "localhost"
smtp_port = 587
smtp_username = ""
smtp_password = ""
smtp_use_tls = true
smtp_use_starttls = false
sendgrid_api_key = ""
sendgrid_endpoint = "https://api.sendgrid.com/v3/mail/send"
from_email = "test@example.com"
from_name = "Test"
template_dir = "templates/email"
[redis]
enabled = false
url = "redis://localhost:6379"
pool_size = 10
connection_timeout = 5
command_timeout = 5
[app]
name = "Test App"
version = "0.1.0"
debug = true
enable_metrics = false
enable_health_check = true
enable_compression = true
max_request_size = 10485760
[logging]
format = "text"
level = "info"
file_path = "logs/app.log"
max_file_size = 10485760
max_files = 5
enable_console = true
enable_file = false
[content]
enabled = false
content_dir = "content"
cache_enabled = true
cache_ttl = 3600
max_file_size = 5242880
[features]
[features.auth]
enabled = true
jwt = true
oauth = false
two_factor = false
sessions = true
password_reset = true
email_verification = true
[features.rbac]
enabled = false
database_access = false
file_access = false
content_access = false
api_access = false
categories = false
tags = false
caching = false
audit_logging = false
toml_config = false
hierarchical_permissions = false
dynamic_rules = false
[features.content]
enabled = true
markdown = true
syntax_highlighting = false
file_uploads = false
versioning = false
scheduling = false
seo = false
[features.security]
csrf = true
security_headers = true
rate_limiting = true
input_sanitization = true
sql_injection_protection = true
xss_protection = true
content_security_policy = true
[features.performance]
response_caching = false
query_caching = false
compression = true
connection_pooling = true
lazy_loading = false
background_tasks = false
[features.custom]
"#;
fs::write(&config_path, config_content).unwrap();
let config = Config::load_from_file(&config_path).unwrap();
let pool_config = config.database_pool_config();
assert_eq!(pool_config.url, "postgresql://localhost:5432/test");
assert_eq!(pool_config.max_connections, 15);
assert_eq!(pool_config.min_connections, 2);
assert_eq!(
pool_config.connect_timeout,
std::time::Duration::from_secs(45)
);
assert_eq!(
pool_config.idle_timeout,
std::time::Duration::from_secs(900)
);
assert_eq!(
pool_config.max_lifetime,
std::time::Duration::from_secs(3600)
);
}
#[test]
fn test_environment_string_substitution_mock() {
// Test the string substitution function with a mock approach
// This test assumes DB_PASSWORD is already set in environment
let input_without_substitution = "postgresql://user:password@localhost:5432/db";
// Test that strings without substitution pass through unchanged
let result = Config::substitute_env_in_string(input_without_substitution);
assert_eq!(result, "postgresql://user:password@localhost:5432/db");
}
#[test]
fn test_config_defaults() {
let config = Config::default();
// Test default values
assert_eq!(config.server.host, "127.0.0.1");
assert_eq!(config.server.port, 3030);
assert!(matches!(config.server.protocol, Protocol::Http));
assert!(matches!(
config.server.environment,
Environment::Development
));
assert_eq!(config.app.name, "My Rust App");
assert_eq!(config.app.debug, true);
assert_eq!(config.features.auth.enabled, true);
assert_eq!(config.features.security.csrf, true);
// Test server directories defaults
assert_eq!(config.server_dirs.public_dir, "public");
assert_eq!(config.server_dirs.uploads_dir, "uploads");
assert_eq!(config.server_dirs.logs_dir, "logs");
assert_eq!(config.server_dirs.temp_dir, "tmp");
assert_eq!(config.server_dirs.cache_dir, "cache");
assert_eq!(config.server_dirs.config_dir, "config");
assert_eq!(config.server_dirs.data_dir, "data");
assert_eq!(config.server_dirs.backup_dir, "backups");
}
#[test]
fn test_config_helper_methods() {
let mut config = Config::default();
// Test HTTP configuration
assert_eq!(config.server_address(), "127.0.0.1:3030");
assert_eq!(config.server_url(), "http://127.0.0.1:3030");
assert_eq!(config.is_development(), true);
assert_eq!(config.is_production(), false);
assert_eq!(config.requires_tls(), false);
// Test HTTPS configuration
config.server.protocol = Protocol::Https;
config.server.port = 443;
config.server.environment = Environment::Production;
assert_eq!(config.server_address(), "127.0.0.1:443");
assert_eq!(config.server_url(), "https://127.0.0.1:443");
assert_eq!(config.is_development(), false);
assert_eq!(config.is_production(), true);
assert_eq!(config.requires_tls(), true);
}