use thiserror::Error;
#[derive(Debug, Error)]
pub enum EventError {
#[error("Connection error: {0}")]
Connection(String),
#[error("Provider error: {0}")]
JetStream(String),
#[error("Failed to publish event to subject '{subject}': {reason}")]
Publish {
subject: String,
reason: String,
},
#[error("Failed to subscribe to subject '{subject}': {reason}")]
Subscribe {
subject: String,
reason: String,
},
#[error("Serialization error: {0}")]
Serialization(#[from] serde_json::Error),
#[error("Event not found: {0}")]
NotFound(String),
#[error("Configuration error: {0}")]
Config(String),
#[error("Stream error: {0}")]
Stream(String),
#[error("Consumer error: {0}")]
Consumer(String),
#[error("Failed to acknowledge message: {0}")]
Ack(String),
#[error("Operation timed out: {0}")]
Timeout(String),
#[error("Provider error: {0}")]
Provider(String),
#[error("Schema validation failed for event type '{event_type}' v{version}: {reason}")]
SchemaValidation {
event_type: String,
version: u32,
reason: String,
},
#[error("Sink delivery failed for '{sink}': {reason}")]
SinkDelivery {
sink: String,
reason: String,
},
#[error("Broker routing error: {0}")]
BrokerRouting(String),
#[error("CloudEvent conversion error: {0}")]
CloudEventConversion(String),
#[error("Event source error: {0}")]
Source(String),
}
pub type Result<T> = std::result::Result<T, EventError>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_connection_error_display() {
let err = EventError::Connection("refused".to_string());
assert_eq!(err.to_string(), "Connection error: refused");
}
#[test]
fn test_publish_error_display() {
let err = EventError::Publish {
subject: "events.test.a".to_string(),
reason: "timeout".to_string(),
};
assert!(err.to_string().contains("events.test.a"));
assert!(err.to_string().contains("timeout"));
}
#[test]
fn test_subscribe_error_display() {
let err = EventError::Subscribe {
subject: "events.market.>".to_string(),
reason: "consumer limit".to_string(),
};
assert!(err.to_string().contains("events.market.>"));
}
#[test]
fn test_schema_validation_error_display() {
let err = EventError::SchemaValidation {
event_type: "forex.rate".to_string(),
version: 2,
reason: "Missing required field 'rate'".to_string(),
};
let msg = err.to_string();
assert!(msg.contains("forex.rate"));
assert!(msg.contains("v2"));
assert!(msg.contains("rate"));
}
#[test]
fn test_not_found_error() {
let err = EventError::NotFound("sub-123".to_string());
assert!(err.to_string().contains("sub-123"));
}
#[test]
fn test_timeout_error() {
let err = EventError::Timeout("publish ack".to_string());
assert!(err.to_string().contains("publish ack"));
}
#[test]
fn test_serialization_error_from() {
let json_err = serde_json::from_str::<String>("invalid").unwrap_err();
let err: EventError = json_err.into();
assert!(matches!(err, EventError::Serialization(_)));
}
#[test]
fn test_sink_delivery_error() {
let err = EventError::SinkDelivery {
sink: "http-sink".to_string(),
reason: "connection refused".to_string(),
};
let msg = err.to_string();
assert!(msg.contains("http-sink"));
assert!(msg.contains("connection refused"));
}
#[test]
fn test_broker_routing_error() {
let err = EventError::BrokerRouting("no matching triggers".to_string());
assert!(err.to_string().contains("no matching triggers"));
}
#[test]
fn test_cloudevent_conversion_error() {
let err = EventError::CloudEventConversion("missing required field".to_string());
assert!(err.to_string().contains("missing required field"));
}
#[test]
fn test_source_error() {
let err = EventError::Source("interval too small".to_string());
assert!(err.to_string().contains("interval too small"));
}
}