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