Skip to main content

a3s_event/
error.rs

1//! Error types for a3s-event
2
3use thiserror::Error;
4
5/// Errors that can occur in the event system
6#[derive(Debug, Error)]
7pub enum EventError {
8    /// Provider connection failure
9    #[error("Connection error: {0}")]
10    Connection(String),
11
12    /// Provider-specific backend error (JetStream, Redis, etc.)
13    #[error("Provider error: {0}")]
14    JetStream(String),
15
16    /// Publish failure
17    #[error("Failed to publish event to subject '{subject}': {reason}")]
18    Publish {
19        subject: String,
20        reason: String,
21    },
22
23    /// Subscribe failure
24    #[error("Failed to subscribe to subject '{subject}': {reason}")]
25    Subscribe {
26        subject: String,
27        reason: String,
28    },
29
30    /// Serialization/deserialization failure
31    #[error("Serialization error: {0}")]
32    Serialization(#[from] serde_json::Error),
33
34    /// Event not found
35    #[error("Event not found: {0}")]
36    NotFound(String),
37
38    /// Configuration error
39    #[error("Configuration error: {0}")]
40    Config(String),
41
42    /// Stream/topic creation or management error
43    #[error("Stream error: {0}")]
44    Stream(String),
45
46    /// Consumer/subscription creation or management error
47    #[error("Consumer error: {0}")]
48    Consumer(String),
49
50    /// Acknowledgement failure
51    #[error("Failed to acknowledge message: {0}")]
52    Ack(String),
53
54    /// Timeout
55    #[error("Operation timed out: {0}")]
56    Timeout(String),
57
58    /// Provider not supported or not available
59    #[error("Provider error: {0}")]
60    Provider(String),
61
62    /// Schema validation failure
63    #[error("Schema validation failed for event type '{event_type}' v{version}: {reason}")]
64    SchemaValidation {
65        event_type: String,
66        version: u32,
67        reason: String,
68    },
69
70    /// Sink delivery failure
71    #[error("Sink delivery failed for '{sink}': {reason}")]
72    SinkDelivery {
73        sink: String,
74        reason: String,
75    },
76
77    /// Broker routing failure
78    #[error("Broker routing error: {0}")]
79    BrokerRouting(String),
80
81    /// CloudEvent conversion failure
82    #[error("CloudEvent conversion error: {0}")]
83    CloudEventConversion(String),
84
85    /// Event source error
86    #[error("Event source error: {0}")]
87    Source(String),
88}
89
90/// Result type alias for event operations
91pub type Result<T> = std::result::Result<T, EventError>;
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    #[test]
98    fn test_connection_error_display() {
99        let err = EventError::Connection("refused".to_string());
100        assert_eq!(err.to_string(), "Connection error: refused");
101    }
102
103    #[test]
104    fn test_publish_error_display() {
105        let err = EventError::Publish {
106            subject: "events.test.a".to_string(),
107            reason: "timeout".to_string(),
108        };
109        assert!(err.to_string().contains("events.test.a"));
110        assert!(err.to_string().contains("timeout"));
111    }
112
113    #[test]
114    fn test_subscribe_error_display() {
115        let err = EventError::Subscribe {
116            subject: "events.market.>".to_string(),
117            reason: "consumer limit".to_string(),
118        };
119        assert!(err.to_string().contains("events.market.>"));
120    }
121
122    #[test]
123    fn test_schema_validation_error_display() {
124        let err = EventError::SchemaValidation {
125            event_type: "forex.rate".to_string(),
126            version: 2,
127            reason: "Missing required field 'rate'".to_string(),
128        };
129        let msg = err.to_string();
130        assert!(msg.contains("forex.rate"));
131        assert!(msg.contains("v2"));
132        assert!(msg.contains("rate"));
133    }
134
135    #[test]
136    fn test_not_found_error() {
137        let err = EventError::NotFound("sub-123".to_string());
138        assert!(err.to_string().contains("sub-123"));
139    }
140
141    #[test]
142    fn test_timeout_error() {
143        let err = EventError::Timeout("publish ack".to_string());
144        assert!(err.to_string().contains("publish ack"));
145    }
146
147    #[test]
148    fn test_serialization_error_from() {
149        let json_err = serde_json::from_str::<String>("invalid").unwrap_err();
150        let err: EventError = json_err.into();
151        assert!(matches!(err, EventError::Serialization(_)));
152    }
153
154    #[test]
155    fn test_sink_delivery_error() {
156        let err = EventError::SinkDelivery {
157            sink: "http-sink".to_string(),
158            reason: "connection refused".to_string(),
159        };
160        let msg = err.to_string();
161        assert!(msg.contains("http-sink"));
162        assert!(msg.contains("connection refused"));
163    }
164
165    #[test]
166    fn test_broker_routing_error() {
167        let err = EventError::BrokerRouting("no matching triggers".to_string());
168        assert!(err.to_string().contains("no matching triggers"));
169    }
170
171    #[test]
172    fn test_cloudevent_conversion_error() {
173        let err = EventError::CloudEventConversion("missing required field".to_string());
174        assert!(err.to_string().contains("missing required field"));
175    }
176
177    #[test]
178    fn test_source_error() {
179        let err = EventError::Source("interval too small".to_string());
180        assert!(err.to_string().contains("interval too small"));
181    }
182}