litellm_rs/config/validation/
monitoring_validators.rs1use super::trait_def::Validate;
8use crate::config::models::*;
9use tracing::debug;
10
11impl Validate for MonitoringConfig {
12 fn validate(&self) -> Result<(), String> {
13 debug!("Validating monitoring configuration");
14
15 self.metrics.validate()?;
16 self.tracing.validate()?;
17 self.health.validate()?;
18
19 Ok(())
20 }
21}
22
23impl Validate for MetricsConfig {
24 fn validate(&self) -> Result<(), String> {
25 if self.enabled && self.port == 0 {
26 return Err("Metrics port must be greater than 0 when metrics are enabled".to_string());
27 }
28
29 if self.path.is_empty() {
30 return Err("Metrics path cannot be empty".to_string());
31 }
32
33 if !self.path.starts_with('/') {
34 return Err("Metrics path must start with '/'".to_string());
35 }
36
37 Ok(())
38 }
39}
40
41impl Validate for TracingConfig {
42 fn validate(&self) -> Result<(), String> {
43 if self.enabled && self.endpoint.is_none() {
44 return Err("Tracing endpoint must be specified when tracing is enabled".to_string());
45 }
46
47 if self.service_name.is_empty() {
48 return Err("Service name cannot be empty".to_string());
49 }
50
51 Ok(())
52 }
53}
54
55impl Validate for HealthConfig {
56 fn validate(&self) -> Result<(), String> {
57 if self.path.is_empty() {
58 return Err("Health check path cannot be empty".to_string());
59 }
60
61 if !self.path.starts_with('/') {
62 return Err("Health check path must start with '/'".to_string());
63 }
64
65 Ok(())
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::super::trait_def::Validate;
72 use super::*;
73
74 fn validate_config<T: Validate>(config: &T) -> Result<(), String> {
76 Validate::validate(config)
77 }
78
79 #[test]
82 fn test_metrics_config_valid() {
83 let config = MetricsConfig {
84 enabled: true,
85 port: 9090,
86 path: "/metrics".to_string(),
87 };
88 assert!(validate_config(&config).is_ok());
89 }
90
91 #[test]
92 fn test_metrics_config_disabled_with_zero_port() {
93 let config = MetricsConfig {
94 enabled: false,
95 port: 0,
96 path: "/metrics".to_string(),
97 };
98 assert!(validate_config(&config).is_ok());
99 }
100
101 #[test]
102 fn test_metrics_config_enabled_with_zero_port() {
103 let config = MetricsConfig {
104 enabled: true,
105 port: 0,
106 path: "/metrics".to_string(),
107 };
108 let result = validate_config(&config);
109 assert!(result.is_err());
110 assert!(result.unwrap_err().contains("port must be greater than 0"));
111 }
112
113 #[test]
114 fn test_metrics_config_empty_path() {
115 let config = MetricsConfig {
116 enabled: true,
117 port: 9090,
118 path: "".to_string(),
119 };
120 let result = validate_config(&config);
121 assert!(result.is_err());
122 assert!(result.unwrap_err().contains("path cannot be empty"));
123 }
124
125 #[test]
126 fn test_metrics_config_path_without_leading_slash() {
127 let config = MetricsConfig {
128 enabled: true,
129 port: 9090,
130 path: "metrics".to_string(),
131 };
132 let result = validate_config(&config);
133 assert!(result.is_err());
134 assert!(result.unwrap_err().contains("must start with '/'"));
135 }
136
137 #[test]
138 fn test_metrics_config_custom_path() {
139 let config = MetricsConfig {
140 enabled: true,
141 port: 9090,
142 path: "/custom/metrics/path".to_string(),
143 };
144 assert!(validate_config(&config).is_ok());
145 }
146
147 #[test]
150 fn test_tracing_config_valid() {
151 let config = TracingConfig {
152 enabled: true,
153 endpoint: Some("http://localhost:4317".to_string()),
154 service_name: "gateway".to_string(),
155 };
156 assert!(validate_config(&config).is_ok());
157 }
158
159 #[test]
160 fn test_tracing_config_disabled_no_endpoint() {
161 let config = TracingConfig {
162 enabled: false,
163 endpoint: None,
164 service_name: "gateway".to_string(),
165 };
166 assert!(validate_config(&config).is_ok());
167 }
168
169 #[test]
170 fn test_tracing_config_enabled_no_endpoint() {
171 let config = TracingConfig {
172 enabled: true,
173 endpoint: None,
174 service_name: "gateway".to_string(),
175 };
176 let result = validate_config(&config);
177 assert!(result.is_err());
178 assert!(result.unwrap_err().contains("endpoint must be specified"));
179 }
180
181 #[test]
182 fn test_tracing_config_empty_service_name() {
183 let config = TracingConfig {
184 enabled: false,
185 endpoint: None,
186 service_name: "".to_string(),
187 };
188 let result = validate_config(&config);
189 assert!(result.is_err());
190 assert!(result.unwrap_err().contains("Service name cannot be empty"));
191 }
192
193 #[test]
196 fn test_health_config_valid() {
197 let config = HealthConfig {
198 path: "/health".to_string(),
199 ..Default::default()
200 };
201 assert!(validate_config(&config).is_ok());
202 }
203
204 #[test]
205 fn test_health_config_empty_path() {
206 let config = HealthConfig {
207 path: "".to_string(),
208 ..Default::default()
209 };
210 let result = validate_config(&config);
211 assert!(result.is_err());
212 assert!(result.unwrap_err().contains("path cannot be empty"));
213 }
214
215 #[test]
216 fn test_health_config_path_without_leading_slash() {
217 let config = HealthConfig {
218 path: "health".to_string(),
219 ..Default::default()
220 };
221 let result = validate_config(&config);
222 assert!(result.is_err());
223 assert!(result.unwrap_err().contains("must start with '/'"));
224 }
225
226 #[test]
227 fn test_health_config_custom_path() {
228 let config = HealthConfig {
229 path: "/api/v1/health".to_string(),
230 ..Default::default()
231 };
232 assert!(validate_config(&config).is_ok());
233 }
234
235 #[test]
238 fn test_monitoring_config_valid() {
239 let config = MonitoringConfig::default();
240 assert!(validate_config(&config).is_ok());
241 }
242
243 #[test]
244 fn test_monitoring_config_with_invalid_metrics() {
245 let mut config = MonitoringConfig::default();
246 config.metrics.enabled = true;
247 config.metrics.port = 0;
248
249 let result = validate_config(&config);
250 assert!(result.is_err());
251 }
252
253 #[test]
254 fn test_monitoring_config_with_invalid_tracing() {
255 let mut config = MonitoringConfig::default();
256 config.tracing.enabled = true;
257 config.tracing.endpoint = None;
258
259 let result = validate_config(&config);
260 assert!(result.is_err());
261 }
262
263 #[test]
264 fn test_monitoring_config_with_invalid_health() {
265 let mut config = MonitoringConfig::default();
266 config.health.path = "".to_string();
267
268 let result = validate_config(&config);
269 assert!(result.is_err());
270 }
271}