mockforge_collab/
config.rs

1//! Configuration for collaboration server
2
3use serde::{Deserialize, Serialize};
4use std::time::Duration;
5
6/// Collaboration server configuration
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct CollabConfig {
9    /// JWT secret for authentication
10    pub jwt_secret: String,
11    /// Database URL (`SQLite` or `PostgreSQL`)
12    pub database_url: String,
13    /// Server bind address
14    pub bind_address: String,
15    /// Maximum connections per workspace
16    pub max_connections_per_workspace: usize,
17    /// Event bus capacity
18    pub event_bus_capacity: usize,
19    /// Enable auto-commit for changes
20    pub auto_commit: bool,
21    /// Session timeout duration
22    pub session_timeout: Duration,
23    /// WebSocket ping interval
24    pub websocket_ping_interval: Duration,
25    /// Maximum message size (bytes)
26    pub max_message_size: usize,
27    /// Directory for workspace storage (for `CoreBridge`)
28    pub workspace_dir: Option<String>,
29    /// Directory for backup storage
30    pub backup_dir: Option<String>,
31}
32
33impl Default for CollabConfig {
34    fn default() -> Self {
35        Self {
36            jwt_secret: "change-me-in-production".to_string(),
37            database_url: "sqlite://mockforge-collab.db".to_string(),
38            bind_address: "127.0.0.1:8080".to_string(),
39            max_connections_per_workspace: 100,
40            event_bus_capacity: 1000,
41            auto_commit: true,
42            session_timeout: Duration::from_secs(24 * 3600), // 24 hours
43            websocket_ping_interval: Duration::from_secs(30),
44            max_message_size: 1024 * 1024, // 1 MB
45            workspace_dir: Some("./workspaces".to_string()),
46            backup_dir: Some("./backups".to_string()),
47        }
48    }
49}
50
51impl CollabConfig {
52    /// Load configuration from environment variables
53    #[must_use]
54    pub fn from_env() -> Self {
55        Self {
56            jwt_secret: std::env::var("MOCKFORGE_JWT_SECRET")
57                .unwrap_or_else(|_| "change-me-in-production".to_string()),
58            database_url: std::env::var("MOCKFORGE_DATABASE_URL")
59                .unwrap_or_else(|_| "sqlite://mockforge-collab.db".to_string()),
60            bind_address: std::env::var("MOCKFORGE_BIND_ADDRESS")
61                .unwrap_or_else(|_| "127.0.0.1:8080".to_string()),
62            ..Default::default()
63        }
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70    use std::sync::Mutex;
71
72    // Mutex to serialize tests that modify environment variables
73    static ENV_MUTEX: Mutex<()> = Mutex::new(());
74
75    #[test]
76    fn test_default_config() {
77        let config = CollabConfig::default();
78
79        assert_eq!(config.jwt_secret, "change-me-in-production");
80        assert_eq!(config.database_url, "sqlite://mockforge-collab.db");
81        assert_eq!(config.bind_address, "127.0.0.1:8080");
82        assert_eq!(config.max_connections_per_workspace, 100);
83        assert_eq!(config.event_bus_capacity, 1000);
84        assert!(config.auto_commit);
85        assert_eq!(config.session_timeout, Duration::from_secs(24 * 3600));
86        assert_eq!(config.websocket_ping_interval, Duration::from_secs(30));
87        assert_eq!(config.max_message_size, 1024 * 1024);
88        assert_eq!(config.workspace_dir, Some("./workspaces".to_string()));
89        assert_eq!(config.backup_dir, Some("./backups".to_string()));
90    }
91
92    #[test]
93    fn test_from_env_defaults() {
94        // Lock mutex to prevent parallel test interference
95        let _guard = ENV_MUTEX.lock().unwrap_or_else(|e| e.into_inner());
96
97        // Clear environment variables
98        std::env::remove_var("MOCKFORGE_JWT_SECRET");
99        std::env::remove_var("MOCKFORGE_DATABASE_URL");
100        std::env::remove_var("MOCKFORGE_BIND_ADDRESS");
101
102        let config = CollabConfig::from_env();
103
104        assert_eq!(config.jwt_secret, "change-me-in-production");
105        assert_eq!(config.database_url, "sqlite://mockforge-collab.db");
106        assert_eq!(config.bind_address, "127.0.0.1:8080");
107    }
108
109    #[test]
110    fn test_from_env_with_values() {
111        // Lock mutex to prevent parallel test interference
112        let _guard = ENV_MUTEX.lock().unwrap_or_else(|e| e.into_inner());
113
114        // Set environment variables
115        std::env::set_var("MOCKFORGE_JWT_SECRET", "test-secret");
116        std::env::set_var("MOCKFORGE_DATABASE_URL", "postgres://localhost/test");
117        std::env::set_var("MOCKFORGE_BIND_ADDRESS", "0.0.0.0:9090");
118
119        let config = CollabConfig::from_env();
120
121        assert_eq!(config.jwt_secret, "test-secret");
122        assert_eq!(config.database_url, "postgres://localhost/test");
123        assert_eq!(config.bind_address, "0.0.0.0:9090");
124
125        // Clean up
126        std::env::remove_var("MOCKFORGE_JWT_SECRET");
127        std::env::remove_var("MOCKFORGE_DATABASE_URL");
128        std::env::remove_var("MOCKFORGE_BIND_ADDRESS");
129    }
130
131    #[test]
132    fn test_config_serialization() {
133        let config = CollabConfig::default();
134        let serialized = serde_json::to_string(&config).unwrap();
135        let deserialized: CollabConfig = serde_json::from_str(&serialized).unwrap();
136
137        assert_eq!(config.jwt_secret, deserialized.jwt_secret);
138        assert_eq!(config.database_url, deserialized.database_url);
139        assert_eq!(config.bind_address, deserialized.bind_address);
140    }
141
142    #[test]
143    fn test_config_clone() {
144        let config = CollabConfig::default();
145        let cloned = config.clone();
146
147        assert_eq!(config.jwt_secret, cloned.jwt_secret);
148        assert_eq!(config.max_connections_per_workspace, cloned.max_connections_per_workspace);
149    }
150
151    #[test]
152    fn test_config_debug() {
153        let config = CollabConfig::default();
154        let debug_str = format!("{:?}", config);
155
156        assert!(debug_str.contains("CollabConfig"));
157        assert!(debug_str.contains("jwt_secret"));
158    }
159}