rocketmq_error/unified/
tools.rs

1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18//! Tools and Admin operation specific errors
19//!
20//! This module contains error types specific to RocketMQ admin tools and CLI operations.
21
22use thiserror::Error;
23
24/// Tools-specific errors for admin operations
25#[derive(Debug, Error)]
26pub enum ToolsError {
27    // ============================================================================
28    // Topic Management Errors
29    // ============================================================================
30    /// Topic not found
31    #[error("Topic '{topic}' not found")]
32    TopicNotFound { topic: String },
33
34    /// Topic already exists
35    #[error("Topic '{topic}' already exists")]
36    TopicAlreadyExists { topic: String },
37
38    /// Invalid topic configuration
39    #[error("Invalid topic configuration: {reason}")]
40    TopicInvalid { reason: String },
41
42    // ============================================================================
43    // Cluster Management Errors
44    // ============================================================================
45    /// Cluster not found
46    #[error("Cluster '{cluster}' not found")]
47    ClusterNotFound { cluster: String },
48
49    /// Invalid cluster configuration
50    #[error("Invalid cluster configuration: {reason}")]
51    ClusterInvalid { reason: String },
52
53    // ============================================================================
54    // Broker Management Errors
55    // ============================================================================
56    /// Broker not found
57    #[error("Broker '{broker}' not found")]
58    BrokerNotFound { broker: String },
59
60    /// Broker offline
61    #[error("Broker '{broker}' is offline")]
62    BrokerOffline { broker: String },
63
64    // ============================================================================
65    // Consumer Management Errors
66    // ============================================================================
67    /// Consumer group not found
68    #[error("Consumer group '{group}' not found")]
69    ConsumerGroupNotFound { group: String },
70
71    /// Consumer offline
72    #[error("Consumer '{consumer}' is offline")]
73    ConsumerOffline { consumer: String },
74
75    // ============================================================================
76    // NameServer Management Errors
77    // ============================================================================
78    /// NameServer unreachable
79    #[error("NameServer '{addr}' is unreachable")]
80    NameServerUnreachable { addr: String },
81
82    /// NameServer configuration invalid
83    #[error("Invalid NameServer configuration: {reason}")]
84    NameServerConfigInvalid { reason: String },
85
86    // ============================================================================
87    // Configuration Errors
88    // ============================================================================
89    /// Invalid configuration field
90    #[error("Invalid configuration for '{field}': {reason}")]
91    InvalidConfiguration { field: String, reason: String },
92
93    /// Missing required field
94    #[error("Missing required field: '{field}'")]
95    MissingRequiredField { field: String },
96
97    // ============================================================================
98    // Validation Errors
99    // ============================================================================
100    /// Input validation failed
101    #[error("Validation failed for '{field}': {reason}")]
102    ValidationError { field: String, reason: String },
103
104    /// Generic validation error
105    #[error("Validation error: {message}")]
106    ValidationFailed { message: String },
107
108    // ============================================================================
109    // Permission Errors
110    // ============================================================================
111    /// Permission denied for operation
112    #[error("Permission denied for operation: {operation}")]
113    PermissionDenied { operation: String },
114
115    /// Invalid permission value
116    #[error("Invalid permission value: {value}, allowed values: {}", .allowed.iter().map(|v| v.to_string()).collect::<Vec<_>>().join(", "))]
117    InvalidPermission { value: i32, allowed: Vec<i32> },
118
119    // ============================================================================
120    // Operation Errors
121    // ============================================================================
122    /// Operation timeout
123    #[error("Operation '{operation}' timed out after {duration_ms}ms")]
124    OperationTimeout { operation: String, duration_ms: u64 },
125
126    /// Generic internal error
127    #[error("Internal error: {message}")]
128    Internal { message: String },
129}
130
131impl ToolsError {
132    // ============================================================================
133    // Convenience Constructors
134    // ============================================================================
135
136    /// Create a topic not found error
137    #[inline]
138    pub fn topic_not_found(topic: impl Into<String>) -> Self {
139        Self::TopicNotFound {
140            topic: topic.into(),
141        }
142    }
143
144    /// Create a topic already exists error
145    #[inline]
146    pub fn topic_already_exists(topic: impl Into<String>) -> Self {
147        Self::TopicAlreadyExists {
148            topic: topic.into(),
149        }
150    }
151
152    /// Create a cluster not found error
153    #[inline]
154    pub fn cluster_not_found(cluster: impl Into<String>) -> Self {
155        Self::ClusterNotFound {
156            cluster: cluster.into(),
157        }
158    }
159
160    /// Create a broker not found error
161    #[inline]
162    pub fn broker_not_found(broker: impl Into<String>) -> Self {
163        Self::BrokerNotFound {
164            broker: broker.into(),
165        }
166    }
167
168    /// Create a validation error
169    #[inline]
170    pub fn validation_error(field: impl Into<String>, reason: impl Into<String>) -> Self {
171        Self::ValidationError {
172            field: field.into(),
173            reason: reason.into(),
174        }
175    }
176
177    /// Create a nameserver unreachable error
178    #[inline]
179    pub fn nameserver_unreachable(addr: impl Into<String>) -> Self {
180        Self::NameServerUnreachable { addr: addr.into() }
181    }
182
183    /// Create a nameserver config invalid error
184    #[inline]
185    pub fn nameserver_config_invalid(reason: impl Into<String>) -> Self {
186        Self::NameServerConfigInvalid {
187            reason: reason.into(),
188        }
189    }
190
191    /// Create an internal error
192    #[inline]
193    pub fn internal(message: impl Into<String>) -> Self {
194        Self::Internal {
195            message: message.into(),
196        }
197    }
198}
199
200#[cfg(test)]
201mod tests {
202    use super::*;
203
204    #[test]
205    fn test_topic_not_found() {
206        let err = ToolsError::topic_not_found("TestTopic");
207        assert_eq!(err.to_string(), "Topic 'TestTopic' not found");
208    }
209
210    #[test]
211    fn test_validation_error() {
212        let err = ToolsError::validation_error("topic_name", "name too long");
213        assert_eq!(
214            err.to_string(),
215            "Validation failed for 'topic_name': name too long"
216        );
217    }
218
219    #[test]
220    fn test_broker_offline() {
221        let err = ToolsError::BrokerOffline {
222            broker: "broker-a".to_string(),
223        };
224        assert_eq!(err.to_string(), "Broker 'broker-a' is offline");
225    }
226}