slim_controller/
config.rs1use std::sync::Arc;
5
6use serde::Deserialize;
7
8use slim_config::client::ClientConfig;
9use slim_config::component::configuration::Configuration;
10use slim_config::component::id::ID;
11use slim_config::server::ServerConfig;
12use slim_datapath::message_processing::MessageProcessor;
13
14use crate::errors::ControllerError;
15use crate::service::{ControlPlane, ControlPlaneSettings, from_server_config};
16
17#[derive(Debug, Clone, Deserialize, Default, PartialEq)]
19#[serde(deny_unknown_fields)]
20pub struct Config {
21 #[serde(default)]
23 pub servers: Vec<ServerConfig>,
24
25 #[serde(default)]
27 pub clients: Vec<ClientConfig>,
28
29 #[serde(default)]
33 pub recovery_ttl: Option<duration_string::DurationString>,
34}
35
36impl Config {
37 pub fn new() -> Self {
39 Self::default()
40 }
41
42 pub fn is_default(&self) -> bool {
43 self == &Self::default()
44 }
45
46 pub fn with_servers(self, servers: Vec<ServerConfig>) -> Self {
48 Self { servers, ..self }
49 }
50
51 pub fn with_clients(self, clients: Vec<ClientConfig>) -> Self {
53 Self { clients, ..self }
54 }
55
56 pub fn servers(&self) -> &[ServerConfig] {
58 &self.servers
59 }
60
61 pub fn clients(&self) -> &[ClientConfig] {
63 &self.clients
64 }
65
66 pub fn into_service(
68 &self,
69 id: ID,
70 group_name: Option<String>,
71 message_processor: Arc<MessageProcessor>,
72 dataplane_servers: &[ServerConfig],
76 ) -> ControlPlane {
77 let connection_details = dataplane_servers.iter().map(from_server_config).collect();
78
79 ControlPlane::new(ControlPlaneSettings {
80 id,
81 group_name,
82 servers: self.servers.clone(),
83 clients: self.clients.clone(),
84 message_processor,
85 connection_details,
86 })
87 }
88}
89
90impl Configuration for Config {
91 type Error = ControllerError;
92
93 fn validate(&self) -> Result<(), Self::Error> {
94 for server in self.servers.iter() {
96 server.validate()?;
97 }
98
99 for client in &self.clients {
100 client.validate()?;
101 }
102
103 Ok(())
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110 use slim_config::component::id::{ID, Kind};
111 use slim_config::server::ServerConfig;
112 use slim_datapath::message_processing::MessageProcessor;
113 use std::sync::Arc;
114
115 fn create_test_server_config() -> ServerConfig {
116 ServerConfig::with_endpoint("127.0.0.1:50051")
117 .with_tls_settings(slim_config::tls::server::TlsServerConfig::insecure())
118 }
119
120 fn create_test_client_config() -> ClientConfig {
121 ClientConfig::with_endpoint("http://127.0.0.1:50051")
122 .with_tls_setting(slim_config::tls::client::TlsClientConfig::insecure())
123 }
124
125 #[test]
126 fn test_config_new() {
127 let config = Config::new();
128 assert!(config.servers.is_empty());
129 assert!(config.clients.is_empty());
130 }
131
132 #[test]
133 fn test_config_default() {
134 let config = Config::default();
135 assert!(config.servers.is_empty());
136 assert!(config.clients.is_empty());
137 }
138
139 #[test]
140 fn test_config_with_servers() {
141 let server_config = create_test_server_config();
142 let config = Config::new().with_servers(vec![server_config.clone()]);
143
144 assert_eq!(config.servers.len(), 1);
145 assert_eq!(config.servers[0], server_config);
146 assert!(config.clients.is_empty());
147 }
148
149 #[test]
150 fn test_config_with_clients() {
151 let client_config = create_test_client_config();
152 let config = Config::new().with_clients(vec![client_config.clone()]);
153
154 assert_eq!(config.clients.len(), 1);
155 assert_eq!(config.clients[0], client_config);
156 assert!(config.servers.is_empty());
157 }
158
159 #[test]
160 fn test_config_servers_getter() {
161 let server_config = create_test_server_config();
162 let config = Config::new().with_servers(vec![server_config.clone()]);
163
164 let servers = config.servers();
165 assert_eq!(servers.len(), 1);
166 assert_eq!(servers[0], server_config);
167 }
168
169 #[test]
170 fn test_config_clients_getter() {
171 let client_config = create_test_client_config();
172 let config = Config::new().with_clients(vec![client_config.clone()]);
173
174 let clients = config.clients();
175 assert_eq!(clients.len(), 1);
176 assert_eq!(clients[0], client_config);
177 }
178
179 #[test]
180 fn test_config_chaining() {
181 let server_config = create_test_server_config();
182 let client_config = create_test_client_config();
183
184 let config = Config::new()
185 .with_servers(vec![server_config.clone()])
186 .with_clients(vec![client_config.clone()]);
187
188 assert_eq!(config.servers.len(), 1);
189 assert_eq!(config.clients.len(), 1);
190 }
191
192 #[test]
193 fn test_config_validate_empty() {
194 let config = Config::new();
195 assert!(config.validate().is_ok());
196 }
197
198 #[test]
199 fn test_config_validate_with_valid_servers_and_clients() {
200 let server_config = create_test_server_config();
201 let client_config = create_test_client_config();
202 let config = Config::new()
203 .with_servers(vec![server_config])
204 .with_clients(vec![client_config]);
205
206 assert!(config.validate().is_ok());
207 }
208
209 #[test]
210 fn test_config_clone() {
211 let server_config = create_test_server_config();
212 let client_config = create_test_client_config();
213
214 let config1 = Config::new()
215 .with_servers(vec![server_config])
216 .with_clients(vec![client_config]);
217
218 let config2 = config1.clone();
219
220 assert_eq!(config1.servers, config2.servers);
221 assert_eq!(config1.clients, config2.clients);
222 }
223
224 #[tokio::test]
225 async fn test_config_into_service() {
226 let server_config = create_test_server_config();
227 let client_config = create_test_client_config();
228
229 let config = Config::new()
230 .with_servers(vec![server_config.clone()])
231 .with_clients(vec![client_config]);
232
233 let id = ID::new_with_name(Kind::new("slim").unwrap(), "test-instance").unwrap();
234 let group_name = Some("test-group".to_string());
235 let message_processor = Arc::new(MessageProcessor::new());
236
237 let _control_plane =
238 config.into_service(id, group_name, message_processor, &[server_config]);
239 }
240
241 #[test]
242 fn test_config_debug_trait() {
243 let config = Config::new();
244 let debug_str = format!("{:?}", config);
245 assert!(debug_str.contains("Config"));
246 assert!(debug_str.contains("servers"));
247 assert!(debug_str.contains("clients"));
248 }
249
250 #[test]
251 fn test_config_validate_with_multiple_servers() {
252 let server1 = create_test_server_config();
253 let server2 = ServerConfig::with_endpoint("127.0.0.1:50052")
254 .with_tls_settings(slim_config::tls::server::TlsServerConfig::insecure());
255
256 let config = Config::new().with_servers(vec![server1, server2]);
257 assert!(config.validate().is_ok());
258 }
259
260 #[test]
261 fn test_config_validate_with_multiple_clients() {
262 let client1 = create_test_client_config();
263 let client2 = ClientConfig::with_endpoint("http://127.0.0.1:50052")
264 .with_tls_setting(slim_config::tls::client::TlsClientConfig::insecure());
265
266 let config = Config::new().with_clients(vec![client1, client2]);
267 assert!(config.validate().is_ok());
268 }
269
270 #[test]
271 fn test_config_partial_eq() {
272 let config1 = Config::new();
273 let config2 = Config::new();
274
275 assert_eq!(config1, config2);
276
277 let server_config = create_test_server_config();
278 let config3 = config1.clone().with_servers(vec![server_config]);
279
280 assert_ne!(config1, config3);
281 }
282
283 #[test]
284 fn test_config_builder_pattern_reuse() {
285 let base_config = Config::new();
286
287 let config1 = base_config
288 .clone()
289 .with_servers(vec![create_test_server_config()]);
290 let config2 = base_config
291 .clone()
292 .with_clients(vec![create_test_client_config()]);
293
294 assert!(base_config.servers.is_empty());
295 assert!(base_config.clients.is_empty());
296
297 assert_eq!(config1.servers.len(), 1);
298 assert!(config1.clients.is_empty());
299
300 assert!(config2.servers.is_empty());
301 assert_eq!(config2.clients.len(), 1);
302 }
303
304 #[test]
305 fn test_config_overwrite_behavior() {
306 let server1 = create_test_server_config();
307 let server2 = ServerConfig::with_endpoint("127.0.0.1:50052")
308 .with_tls_settings(slim_config::tls::server::TlsServerConfig::insecure());
309
310 let config = Config::new()
311 .with_servers(vec![server1])
312 .with_servers(vec![server2.clone()]);
313
314 assert_eq!(config.servers.len(), 1);
315 assert_eq!(config.servers[0], server2);
316 }
317}