Skip to main content

gog_api/
error.rs

1// gog-api error module
2// API-specific error types ported from internal/googleapi/errors.go
3
4use thiserror::Error;
5
6#[derive(Error, Debug)]
7pub enum ApiError {
8    #[error("auth required for {service} {email}")]
9    AuthRequired {
10        service: String,
11        email: String,
12        client: String,
13    },
14
15    #[error("rate limit exceeded after {retries} retries")]
16    RateLimitExhausted { retries: u32 },
17
18    #[error("circuit breaker open - too many recent failures")]
19    CircuitBreakerOpen,
20
21    #[error("Google API error ({status}): {message}")]
22    GoogleApi { status: u16, message: String },
23
24    #[error(transparent)]
25    Auth(#[from] gog_auth::AuthError),
26
27    #[error(transparent)]
28    Secrets(#[from] gog_secrets::SecretsError),
29
30    #[error(transparent)]
31    Http(#[from] reqwest::Error),
32
33    #[error(transparent)]
34    Config(#[from] gog_core::config::ConfigError),
35}
36
37// ---------------------------------------------------------------------------
38// Tests
39// ---------------------------------------------------------------------------
40
41#[cfg(test)]
42mod tests {
43    use super::*;
44
45    #[test]
46    fn test_auth_required_display() {
47        let err = ApiError::AuthRequired {
48            service: "gmail".to_string(),
49            email: "user@example.com".to_string(),
50            client: "default".to_string(),
51        };
52        let msg = err.to_string();
53        assert!(msg.contains("auth required for"), "got: {msg}");
54        assert!(msg.contains("gmail"), "got: {msg}");
55        assert!(msg.contains("user@example.com"), "got: {msg}");
56    }
57
58    #[test]
59    fn test_rate_limit_display() {
60        let err = ApiError::RateLimitExhausted { retries: 5 };
61        let msg = err.to_string();
62        assert!(msg.contains("rate limit exceeded"), "got: {msg}");
63        assert!(msg.contains("5"), "got: {msg}");
64    }
65
66    #[test]
67    fn test_circuit_breaker_display() {
68        let err = ApiError::CircuitBreakerOpen;
69        let msg = err.to_string();
70        assert!(msg.contains("circuit breaker"), "got: {msg}");
71    }
72
73    #[test]
74    fn test_google_api_display() {
75        let err = ApiError::GoogleApi {
76            status: 403,
77            message: "Forbidden".to_string(),
78        };
79        let msg = err.to_string();
80        assert!(msg.contains("403"), "got: {msg}");
81        assert!(msg.contains("Forbidden"), "got: {msg}");
82    }
83}