1use thiserror::Error;
2
3#[derive(Debug, Clone, Error)]
5#[non_exhaustive]
6pub enum CamelError {
7 #[error("Component not found: {0}")]
8 ComponentNotFound(String),
9
10 #[error("Endpoint creation failed: {0}")]
11 EndpointCreationFailed(String),
12
13 #[error("Processor error: {0}")]
14 ProcessorError(String),
15
16 #[error("Type conversion failed: {0}")]
17 TypeConversionFailed(String),
18
19 #[error("Invalid URI: {0}")]
20 InvalidUri(String),
21
22 #[error("Channel closed")]
23 ChannelClosed,
24
25 #[error("Route error: {0}")]
26 RouteError(String),
27
28 #[error("IO error: {0}")]
29 Io(String),
30
31 #[error("Dead letter channel failed: {0}")]
32 DeadLetterChannelFailed(String),
33
34 #[error("Circuit breaker open: {0}")]
35 CircuitOpen(String),
36
37 #[error("HTTP {method} {url} failed: {status_code} {status_text}")]
38 HttpOperationFailed {
39 method: String,
40 url: String,
41 status_code: u16,
42 status_text: String,
43 response_body: Option<String>,
44 },
45
46 #[error("Exchange stopped by Stop EIP")]
47 Stopped,
48
49 #[error("Configuration error: {0}")]
50 Config(String),
51
52 #[error("Body stream has already been consumed")]
53 AlreadyConsumed,
54
55 #[error("Stream size exceeded limit: {0}")]
56 StreamLimitExceeded(usize),
57}
58
59impl From<std::io::Error> for CamelError {
60 fn from(err: std::io::Error) -> Self {
61 CamelError::Io(err.to_string())
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[test]
70 fn test_http_operation_failed_display() {
71 let err = CamelError::HttpOperationFailed {
72 method: "GET".to_string(),
73 url: "https://example.com/test".to_string(),
74 status_code: 404,
75 status_text: "Not Found".to_string(),
76 response_body: Some("page not found".to_string()),
77 };
78 let msg = format!("{err}");
79 assert!(msg.contains("404"));
80 assert!(msg.contains("Not Found"));
81 }
82
83 #[test]
84 fn test_http_operation_failed_clone() {
85 let err = CamelError::HttpOperationFailed {
86 method: "POST".to_string(),
87 url: "https://api.example.com/users".to_string(),
88 status_code: 500,
89 status_text: "Internal Server Error".to_string(),
90 response_body: None,
91 };
92 let cloned = err.clone();
93 assert!(matches!(
94 cloned,
95 CamelError::HttpOperationFailed {
96 status_code: 500,
97 ..
98 }
99 ));
100 }
101
102 #[test]
103 fn test_stopped_variant_exists_and_is_clone() {
104 let err = CamelError::Stopped;
105 let cloned = err.clone();
106 assert!(matches!(cloned, CamelError::Stopped));
107 assert_eq!(format!("{err}"), "Exchange stopped by Stop EIP");
108 }
109}