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 #[serde(default)]
28 pub outbound_clients: Vec<ClientConfig>,
29}
30
31impl Config {
32 pub fn new() -> Self {
34 Self::default()
35 }
36
37 pub fn is_default(&self) -> bool {
38 self == &Self::default()
39 }
40
41 pub fn with_servers(self, servers: Vec<ServerConfig>) -> Self {
43 Self { servers, ..self }
44 }
45
46 pub fn with_clients(self, clients: Vec<ClientConfig>) -> Self {
48 Self { clients, ..self }
49 }
50
51 pub fn servers(&self) -> &[ServerConfig] {
53 &self.servers
54 }
55
56 pub fn clients(&self) -> &[ClientConfig] {
58 &self.clients
59 }
60
61 pub fn into_service(
63 &self,
64 node_id: String,
65 group_name: Option<String>,
66 message_processor: MessageProcessor,
67 dataplane_servers: &[ServerConfig],
71 auth_provider: Option<slim_auth::auth_provider::AuthProvider>,
72 ) -> ControlPlane {
73 let connection_details = dataplane_servers.iter().map(from_server_config).collect();
74
75 ControlPlane::new(ControlPlaneSettings {
76 id: node_id,
77 group_name,
78 servers: self.servers.clone(),
79 clients: self.clients.clone(),
80 outbound_clients: self.outbound_clients.clone(),
81 message_processor,
82 connection_details,
83 auth_provider,
84 })
85 }
86}
87
88impl Configuration for Config {
89 type Error = ControllerError;
90
91 fn validate(&self) -> Result<(), Self::Error> {
92 for server in self.servers.iter() {
94 server.validate()?;
95 }
96
97 for client in &self.clients {
98 client.validate()?;
99 }
100
101 Ok(())
102 }
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108 use slim_config::server::ServerConfig;
109 use slim_datapath::message_processing::MessageProcessor;
110
111 fn create_test_server_config() -> ServerConfig {
112 ServerConfig::with_endpoint("127.0.0.1:50051")
113 .with_tls_settings(slim_config::tls::server::TlsServerConfig::insecure())
114 }
115
116 fn create_test_client_config() -> ClientConfig {
117 ClientConfig::with_endpoint("http://127.0.0.1:50051")
118 .with_tls_setting(slim_config::tls::client::TlsClientConfig::insecure())
119 }
120
121 #[test]
122 fn test_config_new() {
123 let config = Config::new();
124 assert!(config.servers.is_empty());
125 assert!(config.clients.is_empty());
126 }
127
128 #[test]
129 fn test_config_default() {
130 let config = Config::default();
131 assert!(config.servers.is_empty());
132 assert!(config.clients.is_empty());
133 }
134
135 #[test]
136 fn test_config_with_servers() {
137 let server_config = create_test_server_config();
138 let config = Config::new().with_servers(vec![server_config.clone()]);
139
140 assert_eq!(config.servers.len(), 1);
141 assert_eq!(config.servers[0], server_config);
142 assert!(config.clients.is_empty());
143 }
144
145 #[test]
146 fn test_config_with_clients() {
147 let client_config = create_test_client_config();
148 let config = Config::new().with_clients(vec![client_config.clone()]);
149
150 assert_eq!(config.clients.len(), 1);
151 assert_eq!(config.clients[0], client_config);
152 assert!(config.servers.is_empty());
153 }
154
155 #[test]
156 fn test_config_servers_getter() {
157 let server_config = create_test_server_config();
158 let config = Config::new().with_servers(vec![server_config.clone()]);
159
160 let servers = config.servers();
161 assert_eq!(servers.len(), 1);
162 assert_eq!(servers[0], server_config);
163 }
164
165 #[test]
166 fn test_config_clients_getter() {
167 let client_config = create_test_client_config();
168 let config = Config::new().with_clients(vec![client_config.clone()]);
169
170 let clients = config.clients();
171 assert_eq!(clients.len(), 1);
172 assert_eq!(clients[0], client_config);
173 }
174
175 #[test]
176 fn test_config_chaining() {
177 let server_config = create_test_server_config();
178 let client_config = create_test_client_config();
179
180 let config = Config::new()
181 .with_servers(vec![server_config.clone()])
182 .with_clients(vec![client_config.clone()]);
183
184 assert_eq!(config.servers.len(), 1);
185 assert_eq!(config.clients.len(), 1);
186 }
187
188 #[test]
189 fn test_config_validate_empty() {
190 let config = Config::new();
191 assert!(config.validate().is_ok());
192 }
193
194 #[test]
195 fn test_config_validate_with_valid_servers_and_clients() {
196 let server_config = create_test_server_config();
197 let client_config = create_test_client_config();
198 let config = Config::new()
199 .with_servers(vec![server_config])
200 .with_clients(vec![client_config]);
201
202 assert!(config.validate().is_ok());
203 }
204
205 #[test]
206 fn test_config_clone() {
207 let server_config = create_test_server_config();
208 let client_config = create_test_client_config();
209
210 let config1 = Config::new()
211 .with_servers(vec![server_config])
212 .with_clients(vec![client_config]);
213
214 let config2 = config1.clone();
215
216 assert_eq!(config1.servers, config2.servers);
217 assert_eq!(config1.clients, config2.clients);
218 }
219
220 #[tokio::test]
221 async fn test_config_into_service() {
222 let server_config = create_test_server_config();
223 let client_config = create_test_client_config();
224
225 let config = Config::new()
226 .with_servers(vec![server_config.clone()])
227 .with_clients(vec![client_config]);
228
229 let group_name = Some("test-group".to_string());
230 let message_processor = MessageProcessor::new();
231
232 let _control_plane = config.into_service(
233 "test-instance".to_string(),
234 group_name,
235 message_processor,
236 &[server_config],
237 None,
238 );
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}