marketdata_core/rest/
error.rs1use crate::errors::MarketDataError;
4
5impl From<ureq::Error> for MarketDataError {
6 fn from(error: ureq::Error) -> Self {
7 match error {
8 ureq::Error::Status(status, response) => {
10 let status_code = status;
11 let message = response
12 .into_string()
13 .unwrap_or_else(|_| format!("HTTP {}", status_code));
14
15 match status_code {
16 401 | 403 => MarketDataError::AuthError { msg: message },
18 429 | 500..=599 => MarketDataError::ApiError {
20 status: status_code,
21 message,
22 },
23 _ => MarketDataError::ApiError {
25 status: status_code,
26 message,
27 },
28 }
29 }
30 ureq::Error::Transport(transport) => {
32 let error_msg = transport.to_string();
33
34 if error_msg.contains("timed out") || error_msg.contains("timeout") {
36 MarketDataError::TimeoutError {
37 operation: error_msg,
38 }
39 } else {
40 MarketDataError::ConnectionError { msg: error_msg }
42 }
43 }
44 }
45 }
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51
52 #[test]
53 fn test_error_is_retryable() {
54 let err = MarketDataError::ConnectionError {
56 msg: "test".to_string(),
57 };
58 assert!(err.is_retryable());
59
60 let err = MarketDataError::TimeoutError {
62 operation: "test".to_string(),
63 };
64 assert!(err.is_retryable());
65
66 let err = MarketDataError::AuthError {
68 msg: "test".to_string(),
69 };
70 assert!(!err.is_retryable());
71
72 let err = MarketDataError::ApiError {
74 status: 400,
75 message: "test".to_string(),
76 };
77 assert!(!err.is_retryable());
78
79 let err = MarketDataError::ApiError {
81 status: 429,
82 message: "rate limit".to_string(),
83 };
84 assert!(err.is_retryable());
85
86 let err = MarketDataError::ApiError {
88 status: 503,
89 message: "service unavailable".to_string(),
90 };
91 assert!(err.is_retryable());
92 }
93
94 #[test]
95 fn test_status_401_converts_to_auth_error() {
96 let err = MarketDataError::AuthError {
98 msg: "HTTP 401".to_string(),
99 };
100 assert!(!err.is_retryable());
101 assert!(matches!(err, MarketDataError::AuthError { .. }));
102 }
103
104 #[test]
105 fn test_status_403_converts_to_auth_error() {
106 let err = MarketDataError::AuthError {
108 msg: "HTTP 403".to_string(),
109 };
110 assert!(!err.is_retryable());
111 assert!(matches!(err, MarketDataError::AuthError { .. }));
112 }
113
114 #[test]
115 fn test_status_429_converts_to_api_error_retryable() {
116 let err = MarketDataError::ApiError {
118 status: 429,
119 message: "Too Many Requests".to_string(),
120 };
121 assert!(err.is_retryable());
122 assert!(matches!(err, MarketDataError::ApiError { status: 429, .. }));
123 }
124
125 #[test]
126 fn test_status_500_converts_to_api_error_retryable() {
127 let err = MarketDataError::ApiError {
129 status: 500,
130 message: "Internal Server Error".to_string(),
131 };
132 assert!(err.is_retryable());
133 assert!(matches!(err, MarketDataError::ApiError { status: 500, .. }));
134 }
135
136 #[test]
137 fn test_timeout_converts_to_timeout_error() {
138 let err = MarketDataError::TimeoutError {
140 operation: "connection timed out".to_string(),
141 };
142 assert!(err.is_retryable());
143 assert!(matches!(err, MarketDataError::TimeoutError { .. }));
144 }
145}