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