use thiserror::Error;
#[derive(Debug, Error)]
pub enum ToolsError {
#[error("Topic '{topic}' not found")]
TopicNotFound { topic: String },
#[error("Topic '{topic}' already exists")]
TopicAlreadyExists { topic: String },
#[error("Invalid topic configuration: {reason}")]
TopicInvalid { reason: String },
#[error("Cluster '{cluster}' not found")]
ClusterNotFound { cluster: String },
#[error("Invalid cluster configuration: {reason}")]
ClusterInvalid { reason: String },
#[error("Broker '{broker}' not found")]
BrokerNotFound { broker: String },
#[error("Broker '{broker}' is offline")]
BrokerOffline { broker: String },
#[error("Consumer group '{group}' not found")]
ConsumerGroupNotFound { group: String },
#[error("Consumer '{consumer}' is offline")]
ConsumerOffline { consumer: String },
#[error("NameServer '{addr}' is unreachable")]
NameServerUnreachable { addr: String },
#[error("Invalid NameServer configuration: {reason}")]
NameServerConfigInvalid { reason: String },
#[error("Invalid configuration for '{field}': {reason}")]
InvalidConfiguration { field: String, reason: String },
#[error("Missing required field: '{field}'")]
MissingRequiredField { field: String },
#[error("Validation failed for '{field}': {reason}")]
ValidationError { field: String, reason: String },
#[error("Validation error: {message}")]
ValidationFailed { message: String },
#[error("Permission denied for operation: {operation}")]
PermissionDenied { operation: String },
#[error("Invalid permission value: {value}, allowed values: {}", .allowed.iter().map(|v| v.to_string()).collect::<Vec<_>>().join(", "))]
InvalidPermission { value: i32, allowed: Vec<i32> },
#[error("Operation '{operation}' timed out after {duration_ms}ms")]
OperationTimeout { operation: String, duration_ms: u64 },
#[error("Internal error: {message}")]
Internal { message: String },
}
impl ToolsError {
#[inline]
pub fn topic_not_found(topic: impl Into<String>) -> Self {
Self::TopicNotFound { topic: topic.into() }
}
#[inline]
pub fn topic_already_exists(topic: impl Into<String>) -> Self {
Self::TopicAlreadyExists { topic: topic.into() }
}
#[inline]
pub fn cluster_not_found(cluster: impl Into<String>) -> Self {
Self::ClusterNotFound {
cluster: cluster.into(),
}
}
#[inline]
pub fn broker_not_found(broker: impl Into<String>) -> Self {
Self::BrokerNotFound { broker: broker.into() }
}
#[inline]
pub fn validation_error(field: impl Into<String>, reason: impl Into<String>) -> Self {
Self::ValidationError {
field: field.into(),
reason: reason.into(),
}
}
#[inline]
pub fn nameserver_unreachable(addr: impl Into<String>) -> Self {
Self::NameServerUnreachable { addr: addr.into() }
}
#[inline]
pub fn nameserver_config_invalid(reason: impl Into<String>) -> Self {
Self::NameServerConfigInvalid { reason: reason.into() }
}
#[inline]
pub fn internal(message: impl Into<String>) -> Self {
Self::Internal {
message: message.into(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_topic_management_errors() {
let err = ToolsError::topic_not_found("TestTopic");
assert_eq!(err.to_string(), "Topic 'TestTopic' not found");
let err = ToolsError::topic_already_exists("TestTopic");
assert_eq!(err.to_string(), "Topic 'TestTopic' already exists");
let err = ToolsError::TopicInvalid {
reason: "invalid partitions".to_string(),
};
assert_eq!(err.to_string(), "Invalid topic configuration: invalid partitions");
}
#[test]
fn test_cluster_management_errors() {
let err = ToolsError::cluster_not_found("TestCluster");
assert_eq!(err.to_string(), "Cluster 'TestCluster' not found");
let err = ToolsError::ClusterInvalid {
reason: "missing brokers".to_string(),
};
assert_eq!(err.to_string(), "Invalid cluster configuration: missing brokers");
}
#[test]
fn test_broker_management_errors() {
let err = ToolsError::broker_not_found("broker-a");
assert_eq!(err.to_string(), "Broker 'broker-a' not found");
let err = ToolsError::BrokerOffline {
broker: "broker-a".to_string(),
};
assert_eq!(err.to_string(), "Broker 'broker-a' is offline");
}
#[test]
fn test_consumer_management_errors() {
let err = ToolsError::ConsumerGroupNotFound {
group: "test-group".to_string(),
};
assert_eq!(err.to_string(), "Consumer group 'test-group' not found");
let err = ToolsError::ConsumerOffline {
consumer: "consumer-1".to_string(),
};
assert_eq!(err.to_string(), "Consumer 'consumer-1' is offline");
}
#[test]
fn test_nameserver_management_errors() {
let err = ToolsError::nameserver_unreachable("127.0.0.1:9876");
assert_eq!(err.to_string(), "NameServer '127.0.0.1:9876' is unreachable");
let err = ToolsError::nameserver_config_invalid("missing nameserver");
assert_eq!(err.to_string(), "Invalid NameServer configuration: missing nameserver");
}
#[test]
fn test_configuration_errors() {
let err = ToolsError::InvalidConfiguration {
field: "name_server".to_string(),
reason: "missing nameserver".to_string(),
};
assert_eq!(
err.to_string(),
"Invalid configuration for 'name_server': missing nameserver"
);
let err = ToolsError::MissingRequiredField {
field: "topic".to_string(),
};
assert_eq!(err.to_string(), "Missing required field: 'topic'");
}
#[test]
fn test_validation_errors() {
let err = ToolsError::validation_error("topic_name", "name too long");
assert_eq!(err.to_string(), "Validation failed for 'topic_name': name too long");
let err = ToolsError::ValidationFailed {
message: "generic validation error".to_string(),
};
assert_eq!(err.to_string(), "Validation error: generic validation error");
}
#[test]
fn test_permission_errors() {
let err = ToolsError::PermissionDenied {
operation: "createTopic".to_string(),
};
assert_eq!(err.to_string(), "Permission denied for operation: createTopic");
let err = ToolsError::InvalidPermission {
value: 1,
allowed: vec![2, 4, 6],
};
assert!(err.to_string().contains("Invalid permission value: 1"));
assert!(err.to_string().contains("2, 4, 6"));
}
#[test]
fn test_operation_errors() {
let err = ToolsError::OperationTimeout {
operation: "createTopic".to_string(),
duration_ms: 5000,
};
assert!(err
.to_string()
.contains("Operation 'createTopic' timed out after 5000ms"));
let err = ToolsError::internal("unexpected error");
assert!(err.to_string().contains("Internal error: unexpected error"));
}
}