1use 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#[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}