use std::path::PathBuf;
use std::time::Duration;
#[derive(Debug, Clone)]
pub struct ServerConfig {
pub http_port: u16,
pub ws_port: Option<u16>,
pub grpc_port: Option<u16>,
pub admin_port: Option<u16>,
pub metrics_port: Option<u16>,
pub spec_file: Option<PathBuf>,
pub workspace_dir: Option<PathBuf>,
pub profile: Option<String>,
pub enable_admin: bool,
pub enable_metrics: bool,
pub extra_args: Vec<String>,
pub health_timeout: Duration,
pub health_interval: Duration,
pub working_dir: Option<PathBuf>,
pub env_vars: Vec<(String, String)>,
pub binary_path: Option<PathBuf>,
}
impl Default for ServerConfig {
fn default() -> Self {
Self {
http_port: 0, ws_port: None,
grpc_port: None,
admin_port: None,
metrics_port: None,
spec_file: None,
workspace_dir: None,
profile: None,
enable_admin: false,
enable_metrics: false,
extra_args: Vec::new(),
health_timeout: Duration::from_secs(30),
health_interval: Duration::from_millis(100),
working_dir: None,
env_vars: Vec::new(),
binary_path: None,
}
}
}
impl ServerConfig {
pub fn builder() -> ServerConfigBuilder {
ServerConfigBuilder::default()
}
}
#[derive(Debug, Default)]
pub struct ServerConfigBuilder {
config: ServerConfig,
}
impl ServerConfigBuilder {
pub fn http_port(mut self, port: u16) -> Self {
self.config.http_port = port;
self
}
pub fn ws_port(mut self, port: u16) -> Self {
self.config.ws_port = Some(port);
self
}
pub fn grpc_port(mut self, port: u16) -> Self {
self.config.grpc_port = Some(port);
self
}
pub fn admin_port(mut self, port: u16) -> Self {
self.config.admin_port = Some(port);
self
}
pub fn metrics_port(mut self, port: u16) -> Self {
self.config.metrics_port = Some(port);
self
}
pub fn spec_file<P: Into<PathBuf>>(mut self, path: P) -> Self {
self.config.spec_file = Some(path.into());
self
}
pub fn workspace_dir<P: Into<PathBuf>>(mut self, path: P) -> Self {
self.config.workspace_dir = Some(path.into());
self
}
pub fn profile<S: Into<String>>(mut self, profile: S) -> Self {
self.config.profile = Some(profile.into());
self
}
pub fn enable_admin(mut self, enable: bool) -> Self {
self.config.enable_admin = enable;
self
}
pub fn enable_metrics(mut self, enable: bool) -> Self {
self.config.enable_metrics = enable;
self
}
pub fn extra_arg<S: Into<String>>(mut self, arg: S) -> Self {
self.config.extra_args.push(arg.into());
self
}
pub fn extra_args<I, S>(mut self, args: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
self.config.extra_args.extend(args.into_iter().map(Into::into));
self
}
pub fn health_timeout(mut self, timeout: Duration) -> Self {
self.config.health_timeout = timeout;
self
}
pub fn health_interval(mut self, interval: Duration) -> Self {
self.config.health_interval = interval;
self
}
pub fn working_dir<P: Into<PathBuf>>(mut self, path: P) -> Self {
self.config.working_dir = Some(path.into());
self
}
pub fn env_var<K, V>(mut self, key: K, value: V) -> Self
where
K: Into<String>,
V: Into<String>,
{
self.config.env_vars.push((key.into(), value.into()));
self
}
pub fn binary_path<P: Into<PathBuf>>(mut self, path: P) -> Self {
self.config.binary_path = Some(path.into());
self
}
pub fn build(self) -> ServerConfig {
self.config
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let config = ServerConfig::default();
assert_eq!(config.http_port, 0);
assert!(config.ws_port.is_none());
assert!(config.grpc_port.is_none());
assert!(config.admin_port.is_none());
assert!(config.metrics_port.is_none());
assert!(config.spec_file.is_none());
assert!(config.workspace_dir.is_none());
assert!(config.profile.is_none());
assert!(!config.enable_admin);
assert!(!config.enable_metrics);
assert!(config.extra_args.is_empty());
assert_eq!(config.health_timeout, Duration::from_secs(30));
assert_eq!(config.health_interval, Duration::from_millis(100));
assert!(config.working_dir.is_none());
assert!(config.env_vars.is_empty());
assert!(config.binary_path.is_none());
}
#[test]
fn test_builder() {
let config = ServerConfig::builder()
.http_port(3000)
.ws_port(3001)
.grpc_port(3002)
.admin_port(3003)
.enable_admin(true)
.enable_metrics(true)
.profile("test")
.extra_arg("--verbose")
.build();
assert_eq!(config.http_port, 3000);
assert_eq!(config.ws_port, Some(3001));
assert_eq!(config.grpc_port, Some(3002));
assert_eq!(config.admin_port, Some(3003));
assert!(config.enable_admin);
assert!(config.enable_metrics);
assert_eq!(config.profile, Some("test".to_string()));
assert_eq!(config.extra_args, vec!["--verbose"]);
}
#[test]
fn test_builder_metrics_port() {
let config = ServerConfig::builder().metrics_port(9090).build();
assert_eq!(config.metrics_port, Some(9090));
}
#[test]
fn test_builder_spec_file() {
let config = ServerConfig::builder().spec_file("/path/to/spec.yaml").build();
assert_eq!(config.spec_file, Some(PathBuf::from("/path/to/spec.yaml")));
}
#[test]
fn test_builder_workspace_dir() {
let config = ServerConfig::builder().workspace_dir("/path/to/workspace").build();
assert_eq!(config.workspace_dir, Some(PathBuf::from("/path/to/workspace")));
}
#[test]
fn test_builder_extra_args() {
let config = ServerConfig::builder().extra_args(vec!["--verbose", "--debug"]).build();
assert_eq!(config.extra_args, vec!["--verbose", "--debug"]);
}
#[test]
fn test_builder_extra_args_combined() {
let config = ServerConfig::builder()
.extra_arg("--first")
.extra_args(vec!["--second", "--third"])
.extra_arg("--fourth")
.build();
assert_eq!(config.extra_args, vec!["--first", "--second", "--third", "--fourth"]);
}
#[test]
fn test_builder_health_timeout() {
let config = ServerConfig::builder().health_timeout(Duration::from_secs(60)).build();
assert_eq!(config.health_timeout, Duration::from_secs(60));
}
#[test]
fn test_builder_health_interval() {
let config = ServerConfig::builder().health_interval(Duration::from_millis(500)).build();
assert_eq!(config.health_interval, Duration::from_millis(500));
}
#[test]
fn test_builder_working_dir() {
let config = ServerConfig::builder().working_dir("/tmp/test").build();
assert_eq!(config.working_dir, Some(PathBuf::from("/tmp/test")));
}
#[test]
fn test_builder_env_var() {
let config = ServerConfig::builder()
.env_var("RUST_LOG", "debug")
.env_var("MY_VAR", "value")
.build();
assert_eq!(config.env_vars.len(), 2);
assert!(config.env_vars.contains(&("RUST_LOG".to_string(), "debug".to_string())));
assert!(config.env_vars.contains(&("MY_VAR".to_string(), "value".to_string())));
}
#[test]
fn test_builder_binary_path() {
let config = ServerConfig::builder().binary_path("/usr/local/bin/mockforge").build();
assert_eq!(config.binary_path, Some(PathBuf::from("/usr/local/bin/mockforge")));
}
#[test]
fn test_config_clone() {
let config = ServerConfig::builder().http_port(3000).profile("test").build();
let cloned = config.clone();
assert_eq!(config.http_port, cloned.http_port);
assert_eq!(config.profile, cloned.profile);
}
#[test]
fn test_config_debug() {
let config = ServerConfig::default();
let debug = format!("{:?}", config);
assert!(debug.contains("ServerConfig"));
}
#[test]
fn test_builder_debug() {
let builder = ServerConfigBuilder::default();
let debug = format!("{:?}", builder);
assert!(debug.contains("ServerConfigBuilder"));
}
#[test]
fn test_builder_full_chain() {
let config = ServerConfig::builder()
.http_port(3000)
.ws_port(3001)
.grpc_port(3002)
.admin_port(3003)
.metrics_port(9090)
.spec_file("/spec.yaml")
.workspace_dir("/workspace")
.profile("production")
.enable_admin(true)
.enable_metrics(true)
.extra_arg("--verbose")
.health_timeout(Duration::from_secs(60))
.health_interval(Duration::from_millis(200))
.working_dir("/working")
.env_var("KEY", "VALUE")
.binary_path("/bin/mockforge")
.build();
assert_eq!(config.http_port, 3000);
assert_eq!(config.ws_port, Some(3001));
assert_eq!(config.grpc_port, Some(3002));
assert_eq!(config.admin_port, Some(3003));
assert_eq!(config.metrics_port, Some(9090));
assert_eq!(config.spec_file, Some(PathBuf::from("/spec.yaml")));
assert_eq!(config.workspace_dir, Some(PathBuf::from("/workspace")));
assert_eq!(config.profile, Some("production".to_string()));
assert!(config.enable_admin);
assert!(config.enable_metrics);
assert_eq!(config.health_timeout, Duration::from_secs(60));
assert_eq!(config.health_interval, Duration::from_millis(200));
assert_eq!(config.working_dir, Some(PathBuf::from("/working")));
assert_eq!(config.binary_path, Some(PathBuf::from("/bin/mockforge")));
}
#[test]
fn test_server_config_builder_method() {
let builder = ServerConfig::builder();
let config = builder.http_port(8080).build();
assert_eq!(config.http_port, 8080);
}
}