Skip to main content

litellm_rs/utils/error/gateway_error/
helpers.rs

1//! Helper functions for creating specific error types
2
3use super::types::GatewayError;
4
5/// Helper functions for creating specific errors
6impl GatewayError {
7    pub fn auth<S: Into<String>>(message: S) -> Self {
8        Self::Auth(message.into())
9    }
10
11    pub fn authorization<S: Into<String>>(message: S) -> Self {
12        Self::Forbidden(message.into())
13    }
14
15    pub fn bad_request<S: Into<String>>(message: S) -> Self {
16        Self::BadRequest(message.into())
17    }
18
19    pub fn not_found<S: Into<String>>(message: S) -> Self {
20        Self::NotFound(message.into())
21    }
22
23    pub fn conflict<S: Into<String>>(message: S) -> Self {
24        Self::Conflict(message.into())
25    }
26
27    pub fn internal<S: Into<String>>(message: S) -> Self {
28        Self::Internal(message.into())
29    }
30
31    pub fn validation<S: Into<String>>(message: S) -> Self {
32        Self::Validation(message.into())
33    }
34
35    pub fn rate_limit<S: Into<String>>(message: S) -> Self {
36        Self::RateLimit {
37            message: message.into(),
38            retry_after: None,
39            rpm_limit: None,
40            tpm_limit: None,
41        }
42    }
43
44    pub fn timeout<S: Into<String>>(message: S) -> Self {
45        Self::Timeout(message.into())
46    }
47
48    pub fn service_unavailable<S: Into<String>>(message: S) -> Self {
49        Self::Unavailable(message.into())
50    }
51
52    pub fn server<S: Into<String>>(message: S) -> Self {
53        Self::Internal(message.into())
54    }
55
56    pub fn network<S: Into<String>>(message: S) -> Self {
57        Self::Network(message.into())
58    }
59
60    pub fn external_service<S: Into<String>>(message: S) -> Self {
61        Self::Internal(message.into())
62    }
63
64    pub fn invalid_request<S: Into<String>>(message: S) -> Self {
65        Self::BadRequest(message.into())
66    }
67
68    pub fn parsing<S: Into<String>>(message: S) -> Self {
69        Self::Validation(message.into())
70    }
71
72    pub fn alert<S: Into<String>>(message: S) -> Self {
73        Self::Internal(message.into())
74    }
75
76    pub fn not_implemented<S: Into<String>>(message: S) -> Self {
77        Self::NotImplemented(message.into())
78    }
79
80    pub fn unauthorized<S: Into<String>>(message: S) -> Self {
81        Self::Auth(message.into())
82    }
83
84    pub fn forbidden<S: Into<String>>(message: S) -> Self {
85        Self::Forbidden(message.into())
86    }
87
88    pub fn external<S: Into<String>>(message: S) -> Self {
89        Self::Network(message.into())
90    }
91
92    pub fn invalid_request_error<S: Into<String>>(message: S) -> Self {
93        Self::BadRequest(message.into())
94    }
95
96    pub fn no_providers_available<S: Into<String>>(message: S) -> Self {
97        Self::Unavailable(message.into())
98    }
99
100    pub fn provider_not_found<S: Into<String>>(message: S) -> Self {
101        Self::NotFound(message.into())
102    }
103
104    pub fn no_providers_for_model<S: Into<String>>(message: S) -> Self {
105        Self::BadRequest(message.into())
106    }
107
108    pub fn no_healthy_providers<S: Into<String>>(message: S) -> Self {
109        Self::Unavailable(message.into())
110    }
111}
112
113impl GatewayError {
114    pub fn api_error<S: Into<String>>(_status_code: u16, message: S, _provider: S) -> Self {
115        // ApiError doesn't exist in unified ProviderError, map to Internal in GatewayError
116        Self::Internal(message.into())
117    }
118
119    pub fn unavailable<S: Into<String>>(message: S) -> Self {
120        Self::Unavailable(message.into())
121    }
122}
123
124#[cfg(test)]
125mod tests {
126    use super::*;
127
128    // ==================== Auth Error Tests ====================
129
130    #[test]
131    fn test_auth_error_from_string() {
132        let error = GatewayError::auth("Invalid API key");
133        assert!(matches!(error, GatewayError::Auth(msg) if msg == "Invalid API key"));
134    }
135
136    #[test]
137    fn test_auth_error_from_str() {
138        let error = GatewayError::auth("Token expired");
139        assert!(matches!(error, GatewayError::Auth(_)));
140    }
141
142    #[test]
143    fn test_authorization_error() {
144        let error = GatewayError::authorization("Insufficient permissions");
145        assert!(matches!(error, GatewayError::Forbidden(msg) if msg == "Insufficient permissions"));
146    }
147
148    // ==================== Request Error Tests ====================
149
150    #[test]
151    fn test_bad_request_error() {
152        let error = GatewayError::bad_request("Missing required field");
153        assert!(matches!(error, GatewayError::BadRequest(msg) if msg == "Missing required field"));
154    }
155
156    #[test]
157    fn test_not_found_error() {
158        let error = GatewayError::not_found("Resource not found");
159        assert!(matches!(error, GatewayError::NotFound(msg) if msg == "Resource not found"));
160    }
161
162    #[test]
163    fn test_conflict_error() {
164        let error = GatewayError::conflict("Resource already exists");
165        assert!(matches!(error, GatewayError::Conflict(msg) if msg == "Resource already exists"));
166    }
167
168    #[test]
169    fn test_validation_error() {
170        let error = GatewayError::validation("Invalid input format");
171        assert!(matches!(error, GatewayError::Validation(msg) if msg == "Invalid input format"));
172    }
173
174    #[test]
175    fn test_invalid_request_error() {
176        let error = GatewayError::invalid_request("Malformed JSON");
177        assert!(matches!(error, GatewayError::BadRequest(msg) if msg == "Malformed JSON"));
178    }
179
180    #[test]
181    fn test_invalid_request_error_method() {
182        let error = GatewayError::invalid_request_error("Invalid format");
183        assert!(matches!(error, GatewayError::BadRequest(msg) if msg == "Invalid format"));
184    }
185
186    // ==================== Server Error Tests ====================
187
188    #[test]
189    fn test_internal_error() {
190        let error = GatewayError::internal("Internal server error");
191        assert!(matches!(error, GatewayError::Internal(msg) if msg == "Internal server error"));
192    }
193
194    #[test]
195    fn test_server_error_maps_to_internal() {
196        let error = GatewayError::server("Server failure");
197        assert!(matches!(error, GatewayError::Internal(msg) if msg == "Server failure"));
198    }
199
200    #[test]
201    fn test_external_service_maps_to_internal() {
202        let error = GatewayError::external_service("External API failed");
203        assert!(matches!(error, GatewayError::Internal(msg) if msg == "External API failed"));
204    }
205
206    #[test]
207    fn test_api_error_maps_to_internal() {
208        let error = GatewayError::api_error(500, "Server error", "openai");
209        assert!(matches!(error, GatewayError::Internal(msg) if msg == "Server error"));
210    }
211
212    // ==================== Rate Limiting Tests ====================
213
214    #[test]
215    fn test_rate_limit_error() {
216        let error = GatewayError::rate_limit("Rate limit exceeded");
217        assert!(
218            matches!(error, GatewayError::RateLimit { ref message, .. } if message == "Rate limit exceeded")
219        );
220    }
221
222    #[test]
223    fn test_timeout_error() {
224        let error = GatewayError::timeout("Request timed out after 30s");
225        assert!(
226            matches!(error, GatewayError::Timeout(msg) if msg == "Request timed out after 30s")
227        );
228    }
229
230    // ==================== Provider Error Tests ====================
231
232    #[test]
233    fn test_service_unavailable_error() {
234        let error = GatewayError::service_unavailable("Service under maintenance");
235        assert!(
236            matches!(error, GatewayError::Unavailable(msg) if msg == "Service under maintenance")
237        );
238    }
239
240    #[test]
241    fn test_unavailable_error() {
242        let error = GatewayError::unavailable("Provider unavailable");
243        assert!(matches!(error, GatewayError::Unavailable(msg) if msg == "Provider unavailable"));
244    }
245
246    #[test]
247    fn test_no_providers_available() {
248        let error = GatewayError::no_providers_available("No providers configured");
249        assert!(
250            matches!(error, GatewayError::Unavailable(msg) if msg == "No providers configured")
251        );
252    }
253
254    #[test]
255    fn test_provider_not_found() {
256        let error = GatewayError::provider_not_found("openai");
257        assert!(matches!(error, GatewayError::NotFound(msg) if msg == "openai"));
258    }
259
260    #[test]
261    fn test_no_providers_for_model() {
262        let error = GatewayError::no_providers_for_model("gpt-5");
263        assert!(matches!(error, GatewayError::BadRequest(msg) if msg == "gpt-5"));
264    }
265
266    #[test]
267    fn test_no_healthy_providers() {
268        let error = GatewayError::no_healthy_providers("All providers are down");
269        assert!(matches!(error, GatewayError::Unavailable(msg) if msg == "All providers are down"));
270    }
271
272    // ==================== Network Error Tests ====================
273
274    #[test]
275    fn test_network_error() {
276        let error = GatewayError::network("Connection refused");
277        assert!(matches!(error, GatewayError::Network(msg) if msg == "Connection refused"));
278    }
279
280    // ==================== Parsing Error Tests ====================
281
282    #[test]
283    fn test_parsing_error() {
284        let error = GatewayError::parsing("Invalid JSON syntax");
285        assert!(matches!(error, GatewayError::Validation(msg) if msg == "Invalid JSON syntax"));
286    }
287
288    // ==================== Alert Error Tests ====================
289
290    #[test]
291    fn test_alert_error() {
292        let error = GatewayError::alert("Critical threshold exceeded");
293        assert!(
294            matches!(error, GatewayError::Internal(msg) if msg == "Critical threshold exceeded")
295        );
296    }
297
298    // ==================== Not Implemented Error Tests ====================
299
300    #[test]
301    fn test_not_implemented_error() {
302        let error = GatewayError::not_implemented("Feature not yet available");
303        assert!(
304            matches!(error, GatewayError::NotImplemented(msg) if msg == "Feature not yet available")
305        );
306    }
307
308    // ==================== Authorization Error Tests ====================
309
310    #[test]
311    fn test_unauthorized_error() {
312        let error = GatewayError::unauthorized("Invalid credentials");
313        assert!(matches!(error, GatewayError::Auth(msg) if msg == "Invalid credentials"));
314    }
315
316    #[test]
317    fn test_forbidden_error() {
318        let error = GatewayError::forbidden("Access denied");
319        assert!(matches!(error, GatewayError::Forbidden(msg) if msg == "Access denied"));
320    }
321
322    // ==================== External Error Tests ====================
323
324    #[test]
325    fn test_external_error() {
326        let error = GatewayError::external("Third-party service error");
327        assert!(matches!(error, GatewayError::Network(msg) if msg == "Third-party service error"));
328    }
329
330    // ==================== String Conversion Tests ====================
331
332    #[test]
333    fn test_error_from_owned_string() {
334        let message = String::from("Dynamic error message");
335        let error = GatewayError::auth(message);
336        assert!(matches!(error, GatewayError::Auth(msg) if msg == "Dynamic error message"));
337    }
338
339    #[test]
340    fn test_error_from_string_slice() {
341        let error = GatewayError::auth("Static error message");
342        assert!(matches!(error, GatewayError::Auth(msg) if msg == "Static error message"));
343    }
344
345    #[test]
346    fn test_error_with_format_string() {
347        let model = "gpt-4";
348        let error = GatewayError::no_providers_for_model(format!("No provider supports {}", model));
349        assert!(matches!(error, GatewayError::BadRequest(msg) if msg.contains("gpt-4")));
350    }
351
352    // ==================== Edge Case Tests ====================
353
354    #[test]
355    fn test_error_with_empty_string() {
356        let error = GatewayError::auth("");
357        assert!(matches!(error, GatewayError::Auth(msg) if msg.is_empty()));
358    }
359
360    #[test]
361    fn test_error_with_unicode() {
362        let error = GatewayError::auth("认证失败 - Authentication failed");
363        assert!(matches!(error, GatewayError::Auth(msg) if msg.contains("认证失败")));
364    }
365
366    #[test]
367    fn test_error_with_special_characters() {
368        let error = GatewayError::parsing("JSON error at line 5: unexpected '}'");
369        assert!(matches!(error, GatewayError::Validation(msg) if msg.contains("unexpected '}'")));
370    }
371
372    #[test]
373    fn test_error_with_newlines() {
374        let error = GatewayError::internal("Error details:\n- Issue 1\n- Issue 2");
375        assert!(matches!(error, GatewayError::Internal(msg) if msg.contains('\n')));
376    }
377
378    // ==================== Consistency Tests ====================
379
380    #[test]
381    fn test_service_unavailable_matches_unavailable() {
382        let error1 = GatewayError::service_unavailable("test");
383        let error2 = GatewayError::unavailable("test");
384
385        // Both should produce ProviderUnavailable
386        assert!(matches!(error1, GatewayError::Unavailable(_)));
387        assert!(matches!(error2, GatewayError::Unavailable(_)));
388    }
389
390    #[test]
391    fn test_server_matches_internal() {
392        let error1 = GatewayError::server("test");
393        let error2 = GatewayError::internal("test");
394
395        // Both should produce Internal
396        assert!(matches!(error1, GatewayError::Internal(_)));
397        assert!(matches!(error2, GatewayError::Internal(_)));
398    }
399
400    #[test]
401    fn test_invalid_request_matches_bad_request() {
402        let error1 = GatewayError::invalid_request("test");
403        let error2 = GatewayError::bad_request("test");
404
405        // Both should produce BadRequest
406        assert!(matches!(error1, GatewayError::BadRequest(_)));
407        assert!(matches!(error2, GatewayError::BadRequest(_)));
408    }
409
410    // ==================== All Helper Methods Coverage ====================
411
412    #[test]
413    fn test_all_helper_methods_exist() {
414        // This test ensures all helper methods are callable
415        let _ = GatewayError::auth("test");
416        let _ = GatewayError::authorization("test");
417        let _ = GatewayError::bad_request("test");
418        let _ = GatewayError::not_found("test");
419        let _ = GatewayError::conflict("test");
420        let _ = GatewayError::internal("test");
421        let _ = GatewayError::validation("test");
422        let _ = GatewayError::rate_limit("test");
423        let _ = GatewayError::timeout("test");
424        let _ = GatewayError::service_unavailable("test");
425        let _ = GatewayError::server("test");
426        let _ = GatewayError::network("test");
427        let _ = GatewayError::external_service("test");
428        let _ = GatewayError::invalid_request("test");
429        let _ = GatewayError::parsing("test");
430        let _ = GatewayError::alert("test");
431        let _ = GatewayError::not_implemented("test");
432        let _ = GatewayError::unauthorized("test");
433        let _ = GatewayError::forbidden("test");
434        let _ = GatewayError::external("test");
435        let _ = GatewayError::invalid_request_error("test");
436        let _ = GatewayError::no_providers_available("test");
437        let _ = GatewayError::provider_not_found("test");
438        let _ = GatewayError::no_providers_for_model("test");
439        let _ = GatewayError::no_healthy_providers("test");
440        let _ = GatewayError::api_error(500, "test", "provider");
441        let _ = GatewayError::unavailable("test");
442    }
443}