656 lines
14 KiB
Rust
656 lines
14 KiB
Rust
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);
|
|
}
|