Skip to main content

rocketmq_error/unified/
network.rs

1// Copyright 2023 The RocketMQ Rust Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Network-related errors for RocketMQ operations
16
17use thiserror::Error;
18
19/// Network operation errors
20#[derive(Debug, Error)]
21pub enum NetworkError {
22    /// Connection to remote address failed
23    #[error("Connection failed to {addr}: {reason}")]
24    ConnectionFailed { addr: String, reason: String },
25
26    /// Connection timeout
27    #[error("Connection timeout to {addr} after {timeout_ms}ms")]
28    ConnectionTimeout { addr: String, timeout_ms: u64 },
29
30    /// Connection was closed unexpectedly
31    #[error("Connection closed: {addr}")]
32    ConnectionClosed { addr: String },
33
34    /// Failed to send data
35    #[error("Send failed to {addr}: {reason}")]
36    SendFailed { addr: String, reason: String },
37
38    /// Failed to receive data
39    #[error("Receive failed from {addr}: {reason}")]
40    ReceiveFailed { addr: String, reason: String },
41
42    /// Invalid address format
43    #[error("Invalid address format: {addr}")]
44    InvalidAddress { addr: String },
45
46    /// DNS resolution failed
47    #[error("DNS resolution failed for {host}: {reason}")]
48    DnsResolutionFailed { host: String, reason: String },
49
50    /// Too many requests (backpressure)
51    #[error("Too many requests to {addr}, limit: {limit}")]
52    TooManyRequests { addr: String, limit: usize },
53
54    /// Request timeout
55    #[error("Request timeout to {addr} after {timeout_ms}ms")]
56    RequestTimeout { addr: String, timeout_ms: u64 },
57}
58
59impl NetworkError {
60    /// Create a connection failed error
61    #[inline]
62    pub fn connection_failed(addr: impl Into<String>, reason: impl Into<String>) -> Self {
63        Self::ConnectionFailed {
64            addr: addr.into(),
65            reason: reason.into(),
66        }
67    }
68
69    /// Create a connection timeout error
70    #[inline]
71    pub fn connection_timeout(addr: impl Into<String>, timeout_ms: u64) -> Self {
72        Self::ConnectionTimeout {
73            addr: addr.into(),
74            timeout_ms,
75        }
76    }
77
78    /// Create a send failed error
79    #[inline]
80    pub fn send_failed(addr: impl Into<String>, reason: impl Into<String>) -> Self {
81        Self::SendFailed {
82            addr: addr.into(),
83            reason: reason.into(),
84        }
85    }
86
87    /// Create a request timeout error
88    #[inline]
89    pub fn request_timeout(addr: impl Into<String>, timeout_ms: u64) -> Self {
90        Self::RequestTimeout {
91            addr: addr.into(),
92            timeout_ms,
93        }
94    }
95
96    /// Get the associated address if available
97    pub fn addr(&self) -> &str {
98        match self {
99            Self::ConnectionFailed { addr, .. }
100            | Self::ConnectionTimeout { addr, .. }
101            | Self::ConnectionClosed { addr }
102            | Self::SendFailed { addr, .. }
103            | Self::ReceiveFailed { addr, .. }
104            | Self::InvalidAddress { addr }
105            | Self::TooManyRequests { addr, .. }
106            | Self::RequestTimeout { addr, .. } => addr,
107            Self::DnsResolutionFailed { host, .. } => host,
108        }
109    }
110}
111
112#[cfg(test)]
113mod tests {
114    use super::*;
115
116    #[test]
117    fn test_network_error_creation() {
118        let err = NetworkError::connection_failed("127.0.0.1:9876", "timeout");
119        assert_eq!(err.addr(), "127.0.0.1:9876");
120        assert!(err.to_string().contains("Connection failed"));
121    }
122
123    #[test]
124    fn test_network_error_display() {
125        let err = NetworkError::ConnectionTimeout {
126            addr: "localhost:10911".to_string(),
127            timeout_ms: 3000,
128        };
129        assert_eq!(err.to_string(), "Connection timeout to localhost:10911 after 3000ms");
130    }
131
132    #[test]
133    fn test_network_error_connection_closed() {
134        let err = NetworkError::ConnectionClosed {
135            addr: "localhost:10911".to_string(),
136        };
137        assert_eq!(err.to_string(), "Connection closed: localhost:10911");
138    }
139
140    #[test]
141    fn test_network_error_send_failed() {
142        let err = NetworkError::SendFailed {
143            addr: "localhost:10911".to_string(),
144            reason: "internal error".to_string(),
145        };
146        assert_eq!(err.to_string(), "Send failed to localhost:10911: internal error");
147    }
148
149    #[test]
150    fn test_network_error_receive_failed() {
151        let err = NetworkError::ReceiveFailed {
152            addr: "localhost:10911".to_string(),
153            reason: "internal error".to_string(),
154        };
155        assert_eq!(err.to_string(), "Receive failed from localhost:10911: internal error");
156    }
157
158    #[test]
159    fn test_network_error_invalid_address() {
160        let err = NetworkError::InvalidAddress {
161            addr: "localhost:10911".to_string(),
162        };
163        assert_eq!(err.to_string(), "Invalid address format: localhost:10911");
164    }
165
166    #[test]
167    fn test_network_error_too_many_requests() {
168        let err = NetworkError::TooManyRequests {
169            addr: "localhost:10911".to_string(),
170            limit: 5,
171        };
172        assert_eq!(err.to_string(), "Too many requests to localhost:10911, limit: 5");
173    }
174
175    #[test]
176    fn test_network_error_request_timeout() {
177        let err = NetworkError::RequestTimeout {
178            addr: "localhost:10911".to_string(),
179            timeout_ms: 100,
180        };
181        assert_eq!(err.to_string(), "Request timeout to localhost:10911 after 100ms");
182    }
183
184    #[test]
185    fn test_network_error_dns_resolution_failed() {
186        let err = NetworkError::DnsResolutionFailed {
187            host: "example.com".to_string(),
188            reason: "host not found".to_string(),
189        };
190        assert_eq!(err.to_string(), "DNS resolution failed for example.com: host not found");
191    }
192}