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