open_lark/core/
error_codes.rs

1use std::fmt::{Display, Formatter};
2
3/// 飞书API错误码的语义化枚举
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5pub enum LarkErrorCode {
6    /// 成功
7    Success = 0,
8
9    // 认证相关错误
10    /// 应用票据无效
11    AppTicketInvalid = 10012,
12    /// 访问令牌无效
13    AccessTokenInvalid = 99991671,
14    /// 应用访问令牌无效
15    AppAccessTokenInvalid = 99991664,
16    /// 租户访问令牌无效
17    TenantAccessTokenInvalid = 99991663,
18
19    // HTTP标准错误码
20    /// 请求参数错误
21    BadRequest = 400,
22    /// 认证失败
23    Unauthorized = 401,
24    /// 权限不足
25    Forbidden = 403,
26    /// 资源不存在
27    NotFound = 404,
28    /// 方法不允许
29    MethodNotAllowed = 405,
30    /// 请求冲突
31    Conflict = 409,
32    /// 请求频率过高
33    TooManyRequests = 429,
34
35    // 服务器错误
36    /// 内部服务器错误
37    InternalServerError = 500,
38    /// 网关错误
39    BadGateway = 502,
40    /// 服务不可用
41    ServiceUnavailable = 503,
42    /// 网关超时
43    GatewayTimeout = 504,
44
45    // 飞书业务错误码
46    /// 应用未安装
47    AppNotInstalled = 10003,
48    /// 应用状态异常
49    AppStatusException = 10013,
50    /// 应用权限不足
51    AppPermissionDenied = 19001,
52    /// 用户不存在
53    UserNotFound = 60001,
54    /// 用户状态异常
55    UserStatusException = 60002,
56    /// 部门不存在
57    DepartmentNotFound = 60003,
58    /// 群组不存在
59    ChatNotFound = 70001,
60    /// 群组类型不支持
61    ChatTypeNotSupported = 70002,
62    /// 消息不存在
63    MessageNotFound = 80001,
64    /// 消息类型不支持
65    MessageTypeNotSupported = 80002,
66    /// 文件不存在
67    FileNotFound = 90001,
68    /// 文件大小超限
69    FileSizeExceeded = 90002,
70    /// 文件类型不支持
71    FileTypeNotSupported = 90003,
72
73    // 日历相关错误
74    /// 日历不存在
75    CalendarNotFound = 110001,
76    /// 日程不存在
77    EventNotFound = 110002,
78    /// 日程冲突
79    EventConflict = 110003,
80
81    // 云文档相关错误
82    /// 文档不存在
83    DocumentNotFound = 120001,
84    /// 文档权限不足
85    DocumentPermissionDenied = 120002,
86    /// 文档已锁定
87    DocumentLocked = 120003,
88    /// 工作表不存在
89    SheetNotFound = 120011,
90    /// 表格不存在
91    TableNotFound = 120021,
92
93    // 应用商店相关错误
94    /// 应用未发布
95    AppNotPublished = 130001,
96    /// 应用版本不兼容
97    AppVersionIncompatible = 130002,
98
99    // 网络和传输错误
100    /// 网络连接超时
101    NetworkTimeout = 999001,
102    /// 网络连接失败
103    NetworkConnectionFailed = 999002,
104    /// DNS解析失败
105    DnsResolutionFailed = 999003,
106    /// SSL证书错误
107    SslCertificateError = 999004,
108}
109
110impl LarkErrorCode {
111    /// 从错误码数值创建枚举
112    pub fn from_code(code: i32) -> Option<Self> {
113        match code {
114            0 => Some(Self::Success),
115            10003 => Some(Self::AppNotInstalled),
116            10012 => Some(Self::AppTicketInvalid),
117            10013 => Some(Self::AppStatusException),
118            19001 => Some(Self::AppPermissionDenied),
119            99991671 => Some(Self::AccessTokenInvalid),
120            99991664 => Some(Self::AppAccessTokenInvalid),
121            99991663 => Some(Self::TenantAccessTokenInvalid),
122            400 => Some(Self::BadRequest),
123            401 => Some(Self::Unauthorized),
124            403 => Some(Self::Forbidden),
125            404 => Some(Self::NotFound),
126            405 => Some(Self::MethodNotAllowed),
127            409 => Some(Self::Conflict),
128            429 => Some(Self::TooManyRequests),
129            500 => Some(Self::InternalServerError),
130            502 => Some(Self::BadGateway),
131            503 => Some(Self::ServiceUnavailable),
132            504 => Some(Self::GatewayTimeout),
133            60001 => Some(Self::UserNotFound),
134            60002 => Some(Self::UserStatusException),
135            60003 => Some(Self::DepartmentNotFound),
136            70001 => Some(Self::ChatNotFound),
137            70002 => Some(Self::ChatTypeNotSupported),
138            80001 => Some(Self::MessageNotFound),
139            80002 => Some(Self::MessageTypeNotSupported),
140            90001 => Some(Self::FileNotFound),
141            90002 => Some(Self::FileSizeExceeded),
142            90003 => Some(Self::FileTypeNotSupported),
143            110001 => Some(Self::CalendarNotFound),
144            110002 => Some(Self::EventNotFound),
145            110003 => Some(Self::EventConflict),
146            120001 => Some(Self::DocumentNotFound),
147            120002 => Some(Self::DocumentPermissionDenied),
148            120003 => Some(Self::DocumentLocked),
149            120011 => Some(Self::SheetNotFound),
150            120021 => Some(Self::TableNotFound),
151            130001 => Some(Self::AppNotPublished),
152            130002 => Some(Self::AppVersionIncompatible),
153            999001 => Some(Self::NetworkTimeout),
154            999002 => Some(Self::NetworkConnectionFailed),
155            999003 => Some(Self::DnsResolutionFailed),
156            999004 => Some(Self::SslCertificateError),
157            _ => None,
158        }
159    }
160
161    /// 获取错误码的中文描述
162    pub fn description(&self) -> &'static str {
163        match self {
164            Self::Success => "操作成功",
165            Self::AppNotInstalled => "应用未安装",
166            Self::AppTicketInvalid => "应用票据无效",
167            Self::AppStatusException => "应用状态异常",
168            Self::AppPermissionDenied => "应用权限不足",
169            Self::AccessTokenInvalid => "访问令牌无效",
170            Self::AppAccessTokenInvalid => "应用访问令牌无效",
171            Self::TenantAccessTokenInvalid => "租户访问令牌无效",
172            Self::BadRequest => "请求参数错误",
173            Self::Unauthorized => "认证失败",
174            Self::Forbidden => "权限不足",
175            Self::NotFound => "资源不存在",
176            Self::MethodNotAllowed => "请求方法不允许",
177            Self::Conflict => "请求冲突",
178            Self::TooManyRequests => "请求频率过高",
179            Self::InternalServerError => "内部服务器错误",
180            Self::BadGateway => "网关错误",
181            Self::ServiceUnavailable => "服务不可用",
182            Self::GatewayTimeout => "网关超时",
183            Self::UserNotFound => "用户不存在",
184            Self::UserStatusException => "用户状态异常",
185            Self::DepartmentNotFound => "部门不存在",
186            Self::ChatNotFound => "群组不存在",
187            Self::ChatTypeNotSupported => "群组类型不支持",
188            Self::MessageNotFound => "消息不存在",
189            Self::MessageTypeNotSupported => "消息类型不支持",
190            Self::FileNotFound => "文件不存在",
191            Self::FileSizeExceeded => "文件大小超限",
192            Self::FileTypeNotSupported => "文件类型不支持",
193            Self::CalendarNotFound => "日历不存在",
194            Self::EventNotFound => "日程不存在",
195            Self::EventConflict => "日程冲突",
196            Self::DocumentNotFound => "文档不存在",
197            Self::DocumentPermissionDenied => "文档权限不足",
198            Self::DocumentLocked => "文档已锁定",
199            Self::SheetNotFound => "工作表不存在",
200            Self::TableNotFound => "表格不存在",
201            Self::AppNotPublished => "应用未发布",
202            Self::AppVersionIncompatible => "应用版本不兼容",
203            Self::NetworkTimeout => "网络连接超时",
204            Self::NetworkConnectionFailed => "网络连接失败",
205            Self::DnsResolutionFailed => "DNS解析失败",
206            Self::SslCertificateError => "SSL证书错误",
207        }
208    }
209
210    /// 获取详细的错误说明
211    pub fn detailed_description(&self) -> &'static str {
212        match self {
213            Self::Success => "请求已成功处理",
214            Self::AppNotInstalled => "应用未安装到当前企业,请先在飞书管理后台安装应用",
215            Self::AppTicketInvalid => "应用票据已失效,SDK会自动重新申请",
216            Self::AppStatusException => "应用状态异常,请检查应用是否正常启用",
217            Self::AppPermissionDenied => "应用缺少执行此操作的权限,请在开发者后台配置相应权限",
218            Self::AccessTokenInvalid => "用户访问令牌已过期,需要重新获取用户授权",
219            Self::AppAccessTokenInvalid => "应用访问令牌无效,请检查应用ID和密钥配置",
220            Self::TenantAccessTokenInvalid => "租户访问令牌无效,请检查应用是否正确安装到企业",
221            Self::BadRequest => "请求参数格式错误或缺少必需参数",
222            Self::Unauthorized => "身份认证失败,请检查访问令牌",
223            Self::Forbidden => "当前用户或应用缺少执行此操作的权限",
224            Self::NotFound => "请求的资源不存在或已被删除",
225            Self::MethodNotAllowed => "当前API不支持此HTTP方法",
226            Self::Conflict => "请求与当前资源状态冲突",
227            Self::TooManyRequests => "请求频率超过限制,请降低请求频率",
228            Self::InternalServerError => "服务器内部错误,请稍后重试",
229            Self::BadGateway => "网关错误,请检查网络连接或稍后重试",
230            Self::ServiceUnavailable => "服务暂时不可用,请稍后重试",
231            Self::GatewayTimeout => "网关超时,请稍后重试",
232            Self::UserNotFound => "指定的用户不存在,请检查用户ID是否正确",
233            Self::UserStatusException => "用户状态异常,可能已被禁用或删除",
234            Self::DepartmentNotFound => "指定的部门不存在,请检查部门ID是否正确",
235            Self::ChatNotFound => "指定的群组不存在或机器人未加入该群组",
236            Self::ChatTypeNotSupported => "当前群组类型不支持此操作",
237            Self::MessageNotFound => "指定的消息不存在或已被删除",
238            Self::MessageTypeNotSupported => "不支持的消息类型",
239            Self::FileNotFound => "指定的文件不存在或已被删除",
240            Self::FileSizeExceeded => "文件大小超出限制,请压缩后重试",
241            Self::FileTypeNotSupported => "不支持的文件类型",
242            Self::CalendarNotFound => "指定的日历不存在",
243            Self::EventNotFound => "指定的日程不存在或已被删除",
244            Self::EventConflict => "日程时间冲突,请选择其他时间",
245            Self::DocumentNotFound => "指定的文档不存在或已被删除",
246            Self::DocumentPermissionDenied => "文档权限不足,请联系文档所有者授权",
247            Self::DocumentLocked => "文档已被其他用户锁定,请稍后再试",
248            Self::SheetNotFound => "指定的工作表不存在",
249            Self::TableNotFound => "指定的表格不存在",
250            Self::AppNotPublished => "应用尚未发布到应用商店",
251            Self::AppVersionIncompatible => "应用版本不兼容,请更新到最新版本",
252            Self::NetworkTimeout => "网络连接超时,请检查网络设置",
253            Self::NetworkConnectionFailed => "网络连接失败,请检查网络设置",
254            Self::DnsResolutionFailed => "DNS解析失败,请检查域名设置",
255            Self::SslCertificateError => "SSL证书验证失败,请检查证书配置",
256        }
257    }
258
259    /// 检查是否为认证相关错误
260    pub fn is_auth_error(&self) -> bool {
261        matches!(
262            self,
263            Self::AppTicketInvalid
264                | Self::AccessTokenInvalid
265                | Self::AppAccessTokenInvalid
266                | Self::TenantAccessTokenInvalid
267                | Self::Unauthorized
268        )
269    }
270
271    /// 检查是否为权限相关错误
272    pub fn is_permission_error(&self) -> bool {
273        matches!(
274            self,
275            Self::Forbidden | Self::AppPermissionDenied | Self::DocumentPermissionDenied
276        )
277    }
278
279    /// 检查是否为客户端错误
280    pub fn is_client_error(&self) -> bool {
281        let code = *self as i32;
282        (400..=499).contains(&code) && code != 429
283    }
284
285    /// 检查是否为服务器错误
286    pub fn is_server_error(&self) -> bool {
287        let code = *self as i32;
288        (500..=599).contains(&code)
289    }
290
291    /// 检查是否可以重试
292    pub fn is_retryable(&self) -> bool {
293        matches!(
294            self,
295            Self::TooManyRequests
296                | Self::InternalServerError
297                | Self::BadGateway
298                | Self::ServiceUnavailable
299                | Self::GatewayTimeout
300                | Self::NetworkTimeout
301                | Self::NetworkConnectionFailed
302                | Self::DnsResolutionFailed
303        )
304    }
305
306    /// 获取建议的重试延迟时间(秒)
307    pub fn suggested_retry_delay(&self) -> Option<u64> {
308        match self {
309            Self::TooManyRequests => Some(60),        // 限流错误建议等待60秒
310            Self::InternalServerError => Some(5),     // 服务器错误建议等待5秒
311            Self::BadGateway => Some(3),              // 网关错误建议等待3秒
312            Self::ServiceUnavailable => Some(10),     // 服务不可用建议等待10秒
313            Self::GatewayTimeout => Some(5),          // 网关超时建议等待5秒
314            Self::NetworkTimeout => Some(3),          // 网络超时建议等待3秒
315            Self::NetworkConnectionFailed => Some(5), // 网络连接失败建议等待5秒
316            Self::DnsResolutionFailed => Some(10),    // DNS解析失败建议等待10秒
317            _ => None,
318        }
319    }
320
321    /// 获取错误的严重程度
322    pub fn severity(&self) -> super::error::ErrorSeverity {
323        match self {
324            Self::Success => super::error::ErrorSeverity::Info,
325            Self::TooManyRequests => super::error::ErrorSeverity::Warning,
326            Self::BadRequest | Self::Unauthorized | Self::Forbidden | Self::NotFound => {
327                super::error::ErrorSeverity::Error
328            }
329            Self::InternalServerError | Self::ServiceUnavailable | Self::GatewayTimeout => {
330                super::error::ErrorSeverity::Critical
331            }
332            _ => super::error::ErrorSeverity::Warning,
333        }
334    }
335
336    /// 获取相关的帮助文档链接
337    pub fn help_url(&self) -> Option<&'static str> {
338        match self {
339            Self::AppTicketInvalid
340            | Self::AccessTokenInvalid
341            | Self::AppAccessTokenInvalid
342            | Self::TenantAccessTokenInvalid => {
343                Some("https://open.feishu.cn/document/server-docs/authentication/access-token")
344            }
345            Self::Forbidden => {
346                Some("https://open.feishu.cn/document/home/introduction-to-scope-and-authorization")
347            }
348            Self::TooManyRequests => {
349                Some("https://open.feishu.cn/document/server-docs/api-call-guide/rate-limiting")
350            }
351            _ => Some("https://open.feishu.cn/document/"),
352        }
353    }
354}
355
356impl Display for LarkErrorCode {
357    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
358        write!(f, "{} ({})", self.description(), *self as i32)
359    }
360}
361
362/// 错误码分类
363#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
364pub enum ErrorCategory {
365    /// 认证错误
366    Authentication,
367    /// 权限错误
368    Permission,
369    /// 参数错误
370    Parameter,
371    /// 资源错误
372    Resource,
373    /// 服务器错误
374    Server,
375    /// 网络错误
376    Network,
377    /// 限流错误
378    RateLimit,
379    /// 其他错误
380    Other,
381}
382
383impl LarkErrorCode {
384    /// 获取错误分类
385    pub fn category(&self) -> ErrorCategory {
386        match self {
387            Self::AppTicketInvalid
388            | Self::AccessTokenInvalid
389            | Self::AppAccessTokenInvalid
390            | Self::TenantAccessTokenInvalid
391            | Self::Unauthorized => ErrorCategory::Authentication,
392
393            Self::Forbidden | Self::AppPermissionDenied | Self::DocumentPermissionDenied => {
394                ErrorCategory::Permission
395            }
396
397            Self::BadRequest
398            | Self::MethodNotAllowed
399            | Self::FileSizeExceeded
400            | Self::FileTypeNotSupported
401            | Self::MessageTypeNotSupported
402            | Self::ChatTypeNotSupported
403            | Self::EventConflict
404            | Self::AppVersionIncompatible => ErrorCategory::Parameter,
405
406            Self::NotFound
407            | Self::UserNotFound
408            | Self::DepartmentNotFound
409            | Self::ChatNotFound
410            | Self::MessageNotFound
411            | Self::FileNotFound
412            | Self::CalendarNotFound
413            | Self::EventNotFound
414            | Self::DocumentNotFound
415            | Self::SheetNotFound
416            | Self::TableNotFound
417            | Self::AppNotInstalled
418            | Self::AppNotPublished
419            | Self::Conflict => ErrorCategory::Resource,
420
421            Self::TooManyRequests => ErrorCategory::RateLimit,
422
423            Self::InternalServerError
424            | Self::BadGateway
425            | Self::ServiceUnavailable
426            | Self::AppStatusException
427            | Self::UserStatusException
428            | Self::DocumentLocked => ErrorCategory::Server,
429
430            Self::GatewayTimeout
431            | Self::NetworkTimeout
432            | Self::NetworkConnectionFailed
433            | Self::DnsResolutionFailed
434            | Self::SslCertificateError => ErrorCategory::Network,
435
436            Self::Success => ErrorCategory::Other,
437        }
438    }
439}
440
441#[cfg(test)]
442mod tests {
443    use super::*;
444
445    #[test]
446    fn test_error_code_from_code() {
447        assert_eq!(LarkErrorCode::from_code(0), Some(LarkErrorCode::Success));
448        assert_eq!(
449            LarkErrorCode::from_code(10012),
450            Some(LarkErrorCode::AppTicketInvalid)
451        );
452        assert_eq!(LarkErrorCode::from_code(404), Some(LarkErrorCode::NotFound));
453        assert_eq!(LarkErrorCode::from_code(999999), None);
454    }
455
456    #[test]
457    fn test_error_classification() {
458        assert!(LarkErrorCode::AccessTokenInvalid.is_auth_error());
459        assert!(LarkErrorCode::Forbidden.is_permission_error());
460        assert!(LarkErrorCode::BadRequest.is_client_error());
461        assert!(LarkErrorCode::InternalServerError.is_server_error());
462        assert!(LarkErrorCode::TooManyRequests.is_retryable());
463    }
464
465    #[test]
466    fn test_retry_delay() {
467        assert_eq!(
468            LarkErrorCode::TooManyRequests.suggested_retry_delay(),
469            Some(60)
470        );
471        assert_eq!(LarkErrorCode::Success.suggested_retry_delay(), None);
472    }
473
474    #[test]
475    fn test_error_category() {
476        // 认证错误
477        assert_eq!(
478            LarkErrorCode::AccessTokenInvalid.category(),
479            ErrorCategory::Authentication
480        );
481        assert_eq!(
482            LarkErrorCode::AppTicketInvalid.category(),
483            ErrorCategory::Authentication
484        );
485        assert_eq!(
486            LarkErrorCode::Unauthorized.category(),
487            ErrorCategory::Authentication
488        );
489
490        // 权限错误
491        assert_eq!(
492            LarkErrorCode::Forbidden.category(),
493            ErrorCategory::Permission
494        );
495        assert_eq!(
496            LarkErrorCode::AppPermissionDenied.category(),
497            ErrorCategory::Permission
498        );
499        assert_eq!(
500            LarkErrorCode::DocumentPermissionDenied.category(),
501            ErrorCategory::Permission
502        );
503
504        // 参数错误
505        assert_eq!(
506            LarkErrorCode::BadRequest.category(),
507            ErrorCategory::Parameter
508        );
509        assert_eq!(
510            LarkErrorCode::FileSizeExceeded.category(),
511            ErrorCategory::Parameter
512        );
513        assert_eq!(
514            LarkErrorCode::EventConflict.category(),
515            ErrorCategory::Parameter
516        );
517
518        // 资源错误
519        assert_eq!(LarkErrorCode::NotFound.category(), ErrorCategory::Resource);
520        assert_eq!(
521            LarkErrorCode::UserNotFound.category(),
522            ErrorCategory::Resource
523        );
524        assert_eq!(
525            LarkErrorCode::DocumentNotFound.category(),
526            ErrorCategory::Resource
527        );
528
529        // 限流错误
530        assert_eq!(
531            LarkErrorCode::TooManyRequests.category(),
532            ErrorCategory::RateLimit
533        );
534
535        // 服务器错误
536        assert_eq!(
537            LarkErrorCode::InternalServerError.category(),
538            ErrorCategory::Server
539        );
540        assert_eq!(
541            LarkErrorCode::DocumentLocked.category(),
542            ErrorCategory::Server
543        );
544
545        // 网络错误
546        assert_eq!(
547            LarkErrorCode::NetworkTimeout.category(),
548            ErrorCategory::Network
549        );
550        assert_eq!(
551            LarkErrorCode::DnsResolutionFailed.category(),
552            ErrorCategory::Network
553        );
554    }
555
556    #[test]
557    fn test_business_error_codes() {
558        // 测试业务特定错误码
559        assert_eq!(
560            LarkErrorCode::from_code(60001),
561            Some(LarkErrorCode::UserNotFound)
562        );
563        assert_eq!(
564            LarkErrorCode::from_code(70001),
565            Some(LarkErrorCode::ChatNotFound)
566        );
567        assert_eq!(
568            LarkErrorCode::from_code(120001),
569            Some(LarkErrorCode::DocumentNotFound)
570        );
571        assert_eq!(
572            LarkErrorCode::from_code(110001),
573            Some(LarkErrorCode::CalendarNotFound)
574        );
575
576        // 测试网络错误码
577        assert_eq!(
578            LarkErrorCode::from_code(999001),
579            Some(LarkErrorCode::NetworkTimeout)
580        );
581        assert_eq!(
582            LarkErrorCode::from_code(999004),
583            Some(LarkErrorCode::SslCertificateError)
584        );
585    }
586
587    #[test]
588    fn test_error_descriptions() {
589        // 测试中文描述
590        assert_eq!(LarkErrorCode::Success.description(), "操作成功");
591        assert_eq!(LarkErrorCode::UserNotFound.description(), "用户不存在");
592        assert_eq!(LarkErrorCode::ChatNotFound.description(), "群组不存在");
593        assert_eq!(LarkErrorCode::DocumentLocked.description(), "文档已锁定");
594        assert_eq!(LarkErrorCode::NetworkTimeout.description(), "网络连接超时");
595
596        // 测试详细描述
597        assert!(LarkErrorCode::UserNotFound
598            .detailed_description()
599            .contains("用户ID"));
600        assert!(LarkErrorCode::TooManyRequests
601            .detailed_description()
602            .contains("请求频率"));
603        assert!(LarkErrorCode::DocumentPermissionDenied
604            .detailed_description()
605            .contains("权限不足"));
606    }
607
608    #[test]
609    fn test_help_urls() {
610        // 测试帮助链接
611        assert!(LarkErrorCode::AccessTokenInvalid.help_url().is_some());
612        assert!(LarkErrorCode::TooManyRequests.help_url().is_some());
613        assert!(LarkErrorCode::Forbidden.help_url().is_some());
614
615        let auth_url = LarkErrorCode::AppAccessTokenInvalid.help_url().unwrap();
616        assert!(auth_url.contains("authentication"));
617
618        let rate_limit_url = LarkErrorCode::TooManyRequests.help_url().unwrap();
619        assert!(rate_limit_url.contains("rate-limiting"));
620    }
621
622    #[test]
623    fn test_severity_levels() {
624        use crate::core::error::ErrorSeverity;
625
626        // 测试不同严重级别
627        assert_eq!(LarkErrorCode::Success.severity(), ErrorSeverity::Info);
628        assert_eq!(
629            LarkErrorCode::TooManyRequests.severity(),
630            ErrorSeverity::Warning
631        );
632        assert_eq!(LarkErrorCode::BadRequest.severity(), ErrorSeverity::Error);
633        assert_eq!(
634            LarkErrorCode::InternalServerError.severity(),
635            ErrorSeverity::Critical
636        );
637    }
638
639    #[test]
640    fn test_comprehensive_error_properties() {
641        // 测试标准HTTP客户端错误
642        let client_error = LarkErrorCode::BadRequest;
643        assert!(!client_error.is_auth_error());
644        assert!(!client_error.is_permission_error());
645        assert!(client_error.is_client_error());
646        assert!(!client_error.is_server_error());
647        assert!(!client_error.is_retryable());
648        assert_eq!(client_error.suggested_retry_delay(), None);
649        assert_eq!(client_error.category(), ErrorCategory::Parameter);
650
651        // 测试业务错误(不在HTTP范围内)
652        let business_error = LarkErrorCode::DocumentNotFound;
653        assert!(!business_error.is_auth_error());
654        assert!(!business_error.is_permission_error());
655        assert!(!business_error.is_client_error()); // 120001 不在400-499范围
656        assert!(!business_error.is_server_error()); // 120001 不在500-599范围
657        assert!(!business_error.is_retryable());
658        assert_eq!(business_error.suggested_retry_delay(), None);
659        assert_eq!(business_error.category(), ErrorCategory::Resource);
660
661        // 测试网络错误的重试特性
662        let network_error = LarkErrorCode::NetworkTimeout;
663        assert!(network_error.is_retryable());
664        assert_eq!(network_error.suggested_retry_delay(), Some(3));
665        assert_eq!(network_error.category(), ErrorCategory::Network);
666
667        // 测试权限错误
668        let permission_error = LarkErrorCode::DocumentPermissionDenied;
669        assert!(!permission_error.is_auth_error());
670        assert!(permission_error.is_permission_error());
671        assert_eq!(permission_error.category(), ErrorCategory::Permission);
672
673        // 测试认证错误
674        let auth_error = LarkErrorCode::AccessTokenInvalid;
675        assert!(auth_error.is_auth_error());
676        assert!(!auth_error.is_permission_error());
677        assert_eq!(auth_error.category(), ErrorCategory::Authentication);
678
679        // 测试服务器错误
680        let server_error = LarkErrorCode::InternalServerError;
681        assert!(!server_error.is_auth_error());
682        assert!(!server_error.is_permission_error());
683        assert!(!server_error.is_client_error());
684        assert!(server_error.is_server_error());
685        assert!(server_error.is_retryable());
686        assert_eq!(server_error.suggested_retry_delay(), Some(5));
687        assert_eq!(server_error.category(), ErrorCategory::Server);
688    }
689}