Skip to main content

rivven_client/
error.rs

1use thiserror::Error;
2
3#[derive(Error, Debug)]
4pub enum Error {
5    #[error("Connection error: {0}")]
6    ConnectionError(String),
7
8    #[error("Configuration error: {0}")]
9    ConfigError(String),
10
11    #[error("IO error: {0}")]
12    IoError(String),
13
14    #[error("Serialization error: {0}")]
15    SerializationError(#[from] postcard::Error),
16
17    #[error("Protocol error: {0}")]
18    ProtocolError(#[from] rivven_protocol::ProtocolError),
19
20    #[error("Server error: {0}")]
21    ServerError(String),
22
23    #[error("Authentication failed: {0}")]
24    AuthenticationFailed(String),
25
26    #[error("Invalid response")]
27    InvalidResponse,
28
29    #[error("Response too large: {0} bytes (max: {1})")]
30    ResponseTooLarge(usize, usize),
31
32    #[error("Circuit breaker open for server: {0}")]
33    CircuitBreakerOpen(String),
34
35    #[error("Connection pool exhausted: {0}")]
36    PoolExhausted(String),
37
38    #[error("All servers unavailable")]
39    AllServersUnavailable,
40
41    #[error("Request timeout")]
42    Timeout,
43
44    #[error("Timeout: {0}")]
45    TimeoutWithMessage(String),
46
47    #[error("{0}")]
48    Other(String),
49}
50
51impl From<std::io::Error> for Error {
52    fn from(err: std::io::Error) -> Self {
53        Error::IoError(err.to_string())
54    }
55}
56
57pub type Result<T> = std::result::Result<T, Error>;
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    #[test]
64    fn test_error_display() {
65        assert_eq!(
66            Error::ConnectionError("refused".to_string()).to_string(),
67            "Connection error: refused"
68        );
69        assert_eq!(
70            Error::ServerError("internal error".to_string()).to_string(),
71            "Server error: internal error"
72        );
73        assert_eq!(
74            Error::AuthenticationFailed("bad password".to_string()).to_string(),
75            "Authentication failed: bad password"
76        );
77        assert_eq!(Error::InvalidResponse.to_string(), "Invalid response");
78        assert_eq!(
79            Error::ResponseTooLarge(1000, 500).to_string(),
80            "Response too large: 1000 bytes (max: 500)"
81        );
82        assert_eq!(
83            Error::CircuitBreakerOpen("server1".to_string()).to_string(),
84            "Circuit breaker open for server: server1"
85        );
86        assert_eq!(
87            Error::PoolExhausted("max connections".to_string()).to_string(),
88            "Connection pool exhausted: max connections"
89        );
90        assert_eq!(
91            Error::AllServersUnavailable.to_string(),
92            "All servers unavailable"
93        );
94        assert_eq!(Error::Timeout.to_string(), "Request timeout");
95        assert_eq!(
96            Error::TimeoutWithMessage("connect".to_string()).to_string(),
97            "Timeout: connect"
98        );
99        assert_eq!(
100            Error::Other("custom error".to_string()).to_string(),
101            "custom error"
102        );
103    }
104
105    #[test]
106    fn test_error_debug() {
107        let err = Error::ConnectionError("test".to_string());
108        let debug = format!("{:?}", err);
109        assert!(debug.contains("ConnectionError"));
110        assert!(debug.contains("test"));
111    }
112
113    #[test]
114    fn test_io_error_from() {
115        let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
116        let err: Error = io_err.into();
117        assert!(matches!(err, Error::IoError(_)));
118        assert!(err.to_string().contains("file not found"));
119    }
120
121    #[test]
122    fn test_postcard_error_from() {
123        // Create a postcard deserialization error by trying to deserialize invalid data
124        let invalid_data: &[u8] = &[];
125        let result: std::result::Result<String, postcard::Error> =
126            postcard::from_bytes(invalid_data);
127        assert!(result.is_err());
128        let postcard_err = result.unwrap_err();
129        let err: Error = postcard_err.into();
130        assert!(matches!(err, Error::SerializationError(_)));
131    }
132
133    #[test]
134    fn test_result_type() {
135        fn returns_ok() -> Result<i32> {
136            Ok(42)
137        }
138
139        fn returns_err() -> Result<i32> {
140            Err(Error::InvalidResponse)
141        }
142
143        assert!(returns_ok().is_ok());
144        assert_eq!(returns_ok().unwrap(), 42);
145        assert!(returns_err().is_err());
146    }
147}