mockforge_test/
config.rs

1//! Configuration for MockForge test servers
2
3use std::path::PathBuf;
4use std::time::Duration;
5
6/// Configuration for a MockForge test server
7#[derive(Debug, Clone)]
8pub struct ServerConfig {
9    /// HTTP server port (default: auto-assigned)
10    pub http_port: u16,
11
12    /// WebSocket server port (optional)
13    pub ws_port: Option<u16>,
14
15    /// gRPC server port (optional)
16    pub grpc_port: Option<u16>,
17
18    /// Admin UI port (optional)
19    pub admin_port: Option<u16>,
20
21    /// Metrics/Prometheus port (optional)
22    pub metrics_port: Option<u16>,
23
24    /// Path to OpenAPI specification file (optional)
25    pub spec_file: Option<PathBuf>,
26
27    /// Path to workspace directory (optional)
28    pub workspace_dir: Option<PathBuf>,
29
30    /// Profile name for configuration (optional)
31    pub profile: Option<String>,
32
33    /// Enable admin UI (default: false)
34    pub enable_admin: bool,
35
36    /// Enable metrics endpoint (default: false)
37    pub enable_metrics: bool,
38
39    /// Additional CLI arguments
40    pub extra_args: Vec<String>,
41
42    /// Health check timeout (default: 30 seconds)
43    pub health_timeout: Duration,
44
45    /// Health check interval (default: 100ms)
46    pub health_interval: Duration,
47
48    /// Working directory for the server process (optional)
49    pub working_dir: Option<PathBuf>,
50
51    /// Environment variables for the server process
52    pub env_vars: Vec<(String, String)>,
53
54    /// Path to mockforge binary (optional, will search PATH if not provided)
55    pub binary_path: Option<PathBuf>,
56}
57
58impl Default for ServerConfig {
59    fn default() -> Self {
60        Self {
61            http_port: 0, // 0 means auto-assign
62            ws_port: None,
63            grpc_port: None,
64            admin_port: None,
65            metrics_port: None,
66            spec_file: None,
67            workspace_dir: None,
68            profile: None,
69            enable_admin: false,
70            enable_metrics: false,
71            extra_args: Vec::new(),
72            health_timeout: Duration::from_secs(30),
73            health_interval: Duration::from_millis(100),
74            working_dir: None,
75            env_vars: Vec::new(),
76            binary_path: None,
77        }
78    }
79}
80
81impl ServerConfig {
82    /// Create a new builder for ServerConfig
83    pub fn builder() -> ServerConfigBuilder {
84        ServerConfigBuilder::default()
85    }
86}
87
88/// Builder for ServerConfig
89#[derive(Debug, Default)]
90pub struct ServerConfigBuilder {
91    config: ServerConfig,
92}
93
94impl ServerConfigBuilder {
95    /// Set HTTP port (0 for auto-assign)
96    pub fn http_port(mut self, port: u16) -> Self {
97        self.config.http_port = port;
98        self
99    }
100
101    /// Set WebSocket port
102    pub fn ws_port(mut self, port: u16) -> Self {
103        self.config.ws_port = Some(port);
104        self
105    }
106
107    /// Set gRPC port
108    pub fn grpc_port(mut self, port: u16) -> Self {
109        self.config.grpc_port = Some(port);
110        self
111    }
112
113    /// Set admin UI port
114    pub fn admin_port(mut self, port: u16) -> Self {
115        self.config.admin_port = Some(port);
116        self
117    }
118
119    /// Set metrics port
120    pub fn metrics_port(mut self, port: u16) -> Self {
121        self.config.metrics_port = Some(port);
122        self
123    }
124
125    /// Set OpenAPI specification file
126    pub fn spec_file<P: Into<PathBuf>>(mut self, path: P) -> Self {
127        self.config.spec_file = Some(path.into());
128        self
129    }
130
131    /// Set workspace directory
132    pub fn workspace_dir<P: Into<PathBuf>>(mut self, path: P) -> Self {
133        self.config.workspace_dir = Some(path.into());
134        self
135    }
136
137    /// Set profile name
138    pub fn profile<S: Into<String>>(mut self, profile: S) -> Self {
139        self.config.profile = Some(profile.into());
140        self
141    }
142
143    /// Enable admin UI
144    pub fn enable_admin(mut self, enable: bool) -> Self {
145        self.config.enable_admin = enable;
146        self
147    }
148
149    /// Enable metrics endpoint
150    pub fn enable_metrics(mut self, enable: bool) -> Self {
151        self.config.enable_metrics = enable;
152        self
153    }
154
155    /// Add extra CLI argument
156    pub fn extra_arg<S: Into<String>>(mut self, arg: S) -> Self {
157        self.config.extra_args.push(arg.into());
158        self
159    }
160
161    /// Add multiple extra CLI arguments
162    pub fn extra_args<I, S>(mut self, args: I) -> Self
163    where
164        I: IntoIterator<Item = S>,
165        S: Into<String>,
166    {
167        self.config.extra_args.extend(args.into_iter().map(Into::into));
168        self
169    }
170
171    /// Set health check timeout
172    pub fn health_timeout(mut self, timeout: Duration) -> Self {
173        self.config.health_timeout = timeout;
174        self
175    }
176
177    /// Set health check interval
178    pub fn health_interval(mut self, interval: Duration) -> Self {
179        self.config.health_interval = interval;
180        self
181    }
182
183    /// Set working directory
184    pub fn working_dir<P: Into<PathBuf>>(mut self, path: P) -> Self {
185        self.config.working_dir = Some(path.into());
186        self
187    }
188
189    /// Add environment variable
190    pub fn env_var<K, V>(mut self, key: K, value: V) -> Self
191    where
192        K: Into<String>,
193        V: Into<String>,
194    {
195        self.config.env_vars.push((key.into(), value.into()));
196        self
197    }
198
199    /// Set path to mockforge binary
200    pub fn binary_path<P: Into<PathBuf>>(mut self, path: P) -> Self {
201        self.config.binary_path = Some(path.into());
202        self
203    }
204
205    /// Build the ServerConfig
206    pub fn build(self) -> ServerConfig {
207        self.config
208    }
209}
210
211#[cfg(test)]
212mod tests {
213    use super::*;
214
215    #[test]
216    fn test_default_config() {
217        let config = ServerConfig::default();
218        assert_eq!(config.http_port, 0);
219        assert!(config.ws_port.is_none());
220        assert!(config.grpc_port.is_none());
221        assert!(config.admin_port.is_none());
222        assert!(config.metrics_port.is_none());
223        assert!(config.spec_file.is_none());
224        assert!(config.workspace_dir.is_none());
225        assert!(config.profile.is_none());
226        assert!(!config.enable_admin);
227        assert!(!config.enable_metrics);
228        assert!(config.extra_args.is_empty());
229        assert_eq!(config.health_timeout, Duration::from_secs(30));
230        assert_eq!(config.health_interval, Duration::from_millis(100));
231        assert!(config.working_dir.is_none());
232        assert!(config.env_vars.is_empty());
233        assert!(config.binary_path.is_none());
234    }
235
236    #[test]
237    fn test_builder() {
238        let config = ServerConfig::builder()
239            .http_port(3000)
240            .ws_port(3001)
241            .grpc_port(3002)
242            .admin_port(3003)
243            .enable_admin(true)
244            .enable_metrics(true)
245            .profile("test")
246            .extra_arg("--verbose")
247            .build();
248
249        assert_eq!(config.http_port, 3000);
250        assert_eq!(config.ws_port, Some(3001));
251        assert_eq!(config.grpc_port, Some(3002));
252        assert_eq!(config.admin_port, Some(3003));
253        assert!(config.enable_admin);
254        assert!(config.enable_metrics);
255        assert_eq!(config.profile, Some("test".to_string()));
256        assert_eq!(config.extra_args, vec!["--verbose"]);
257    }
258
259    #[test]
260    fn test_builder_metrics_port() {
261        let config = ServerConfig::builder().metrics_port(9090).build();
262        assert_eq!(config.metrics_port, Some(9090));
263    }
264
265    #[test]
266    fn test_builder_spec_file() {
267        let config = ServerConfig::builder().spec_file("/path/to/spec.yaml").build();
268        assert_eq!(config.spec_file, Some(PathBuf::from("/path/to/spec.yaml")));
269    }
270
271    #[test]
272    fn test_builder_workspace_dir() {
273        let config = ServerConfig::builder().workspace_dir("/path/to/workspace").build();
274        assert_eq!(config.workspace_dir, Some(PathBuf::from("/path/to/workspace")));
275    }
276
277    #[test]
278    fn test_builder_extra_args() {
279        let config = ServerConfig::builder().extra_args(vec!["--verbose", "--debug"]).build();
280        assert_eq!(config.extra_args, vec!["--verbose", "--debug"]);
281    }
282
283    #[test]
284    fn test_builder_extra_args_combined() {
285        let config = ServerConfig::builder()
286            .extra_arg("--first")
287            .extra_args(vec!["--second", "--third"])
288            .extra_arg("--fourth")
289            .build();
290        assert_eq!(config.extra_args, vec!["--first", "--second", "--third", "--fourth"]);
291    }
292
293    #[test]
294    fn test_builder_health_timeout() {
295        let config = ServerConfig::builder().health_timeout(Duration::from_secs(60)).build();
296        assert_eq!(config.health_timeout, Duration::from_secs(60));
297    }
298
299    #[test]
300    fn test_builder_health_interval() {
301        let config = ServerConfig::builder().health_interval(Duration::from_millis(500)).build();
302        assert_eq!(config.health_interval, Duration::from_millis(500));
303    }
304
305    #[test]
306    fn test_builder_working_dir() {
307        let config = ServerConfig::builder().working_dir("/tmp/test").build();
308        assert_eq!(config.working_dir, Some(PathBuf::from("/tmp/test")));
309    }
310
311    #[test]
312    fn test_builder_env_var() {
313        let config = ServerConfig::builder()
314            .env_var("RUST_LOG", "debug")
315            .env_var("MY_VAR", "value")
316            .build();
317        assert_eq!(config.env_vars.len(), 2);
318        assert!(config.env_vars.contains(&("RUST_LOG".to_string(), "debug".to_string())));
319        assert!(config.env_vars.contains(&("MY_VAR".to_string(), "value".to_string())));
320    }
321
322    #[test]
323    fn test_builder_binary_path() {
324        let config = ServerConfig::builder().binary_path("/usr/local/bin/mockforge").build();
325        assert_eq!(config.binary_path, Some(PathBuf::from("/usr/local/bin/mockforge")));
326    }
327
328    #[test]
329    fn test_config_clone() {
330        let config = ServerConfig::builder().http_port(3000).profile("test").build();
331
332        let cloned = config.clone();
333        assert_eq!(config.http_port, cloned.http_port);
334        assert_eq!(config.profile, cloned.profile);
335    }
336
337    #[test]
338    fn test_config_debug() {
339        let config = ServerConfig::default();
340        let debug = format!("{:?}", config);
341        assert!(debug.contains("ServerConfig"));
342    }
343
344    #[test]
345    fn test_builder_debug() {
346        let builder = ServerConfigBuilder::default();
347        let debug = format!("{:?}", builder);
348        assert!(debug.contains("ServerConfigBuilder"));
349    }
350
351    #[test]
352    fn test_builder_full_chain() {
353        let config = ServerConfig::builder()
354            .http_port(3000)
355            .ws_port(3001)
356            .grpc_port(3002)
357            .admin_port(3003)
358            .metrics_port(9090)
359            .spec_file("/spec.yaml")
360            .workspace_dir("/workspace")
361            .profile("production")
362            .enable_admin(true)
363            .enable_metrics(true)
364            .extra_arg("--verbose")
365            .health_timeout(Duration::from_secs(60))
366            .health_interval(Duration::from_millis(200))
367            .working_dir("/working")
368            .env_var("KEY", "VALUE")
369            .binary_path("/bin/mockforge")
370            .build();
371
372        assert_eq!(config.http_port, 3000);
373        assert_eq!(config.ws_port, Some(3001));
374        assert_eq!(config.grpc_port, Some(3002));
375        assert_eq!(config.admin_port, Some(3003));
376        assert_eq!(config.metrics_port, Some(9090));
377        assert_eq!(config.spec_file, Some(PathBuf::from("/spec.yaml")));
378        assert_eq!(config.workspace_dir, Some(PathBuf::from("/workspace")));
379        assert_eq!(config.profile, Some("production".to_string()));
380        assert!(config.enable_admin);
381        assert!(config.enable_metrics);
382        assert_eq!(config.health_timeout, Duration::from_secs(60));
383        assert_eq!(config.health_interval, Duration::from_millis(200));
384        assert_eq!(config.working_dir, Some(PathBuf::from("/working")));
385        assert_eq!(config.binary_path, Some(PathBuf::from("/bin/mockforge")));
386    }
387
388    #[test]
389    fn test_server_config_builder_method() {
390        let builder = ServerConfig::builder();
391        let config = builder.http_port(8080).build();
392        assert_eq!(config.http_port, 8080);
393    }
394}