open_lark/core/
token_manager.rs

1use log::warn;
2use serde::{Deserialize, Serialize};
3use std::{
4    sync::{
5        atomic::{AtomicU64, Ordering},
6        Arc,
7    },
8    time::{Duration, Instant},
9};
10use tokio::{
11    sync::{Mutex, RwLock},
12    time::interval,
13};
14use tracing::{info_span, Instrument};
15
16use crate::core::{
17    api_resp::{ApiResponseTrait, RawResponse, ResponseFormat},
18    app_ticket_manager::AppTicketManager,
19    cache::QuickCache,
20    config::Config,
21    constants::{
22        AppType, APP_ACCESS_TOKEN_INTERNAL_URL_PATH, APP_ACCESS_TOKEN_KEY_PREFIX,
23        APP_ACCESS_TOKEN_URL_PATH, EXPIRY_DELTA, TENANT_ACCESS_TOKEN_INTERNAL_URL_PATH,
24        TENANT_ACCESS_TOKEN_URL_PATH,
25    },
26    error::LarkAPIError,
27    SDKResult,
28};
29
30/// Token预热配置
31#[derive(Debug, Clone)]
32pub struct PreheatingConfig {
33    /// 检查间隔(秒)
34    pub check_interval_seconds: u64,
35    /// 预热阈值(秒)- 当token剩余时间少于此值时开始预热
36    pub preheat_threshold_seconds: u64,
37    /// 是否启用tenant token预热
38    pub enable_tenant_preheating: bool,
39    /// 最大并发预热任务数
40    pub max_concurrent_preheat: usize,
41}
42
43impl Default for PreheatingConfig {
44    fn default() -> Self {
45        Self {
46            check_interval_seconds: 1800,   // 30分钟
47            preheat_threshold_seconds: 900, // 15分钟
48            enable_tenant_preheating: true,
49            max_concurrent_preheat: 3,
50        }
51    }
52}
53
54/// Token管理器性能监控指标
55#[derive(Debug, Default)]
56pub struct TokenMetrics {
57    /// App token缓存命中次数
58    pub app_cache_hits: AtomicU64,
59    /// App token缓存未命中次数
60    pub app_cache_misses: AtomicU64,
61    /// Tenant token缓存命中次数
62    pub tenant_cache_hits: AtomicU64,
63    /// Tenant token缓存未命中次数
64    pub tenant_cache_misses: AtomicU64,
65    /// Token刷新成功次数
66    pub refresh_success: AtomicU64,
67    /// Token刷新失败次数
68    pub refresh_failures: AtomicU64,
69    /// 总的读锁获取次数
70    pub read_lock_acquisitions: AtomicU64,
71    /// 总的写锁获取次数
72    pub write_lock_acquisitions: AtomicU64,
73}
74
75impl TokenMetrics {
76    pub fn new() -> Self {
77        Self::default()
78    }
79
80    /// 获取app token缓存命中率 (0.0-1.0)
81    pub fn app_cache_hit_rate(&self) -> f64 {
82        let hits = self.app_cache_hits.load(Ordering::Relaxed) as f64;
83        let misses = self.app_cache_misses.load(Ordering::Relaxed) as f64;
84        let total = hits + misses;
85        if total > 0.0 {
86            hits / total
87        } else {
88            0.0
89        }
90    }
91
92    /// 获取tenant token缓存命中率 (0.0-1.0)
93    pub fn tenant_cache_hit_rate(&self) -> f64 {
94        let hits = self.tenant_cache_hits.load(Ordering::Relaxed) as f64;
95        let misses = self.tenant_cache_misses.load(Ordering::Relaxed) as f64;
96        let total = hits + misses;
97        if total > 0.0 {
98            hits / total
99        } else {
100            0.0
101        }
102    }
103
104    /// 获取token刷新成功率 (0.0-1.0)
105    pub fn refresh_success_rate(&self) -> f64 {
106        let success = self.refresh_success.load(Ordering::Relaxed) as f64;
107        let failures = self.refresh_failures.load(Ordering::Relaxed) as f64;
108        let total = success + failures;
109        if total > 0.0 {
110            success / total
111        } else {
112            0.0
113        }
114    }
115
116    /// 生成性能报告
117    pub fn performance_report(&self) -> String {
118        format!(
119            "TokenManager Performance Metrics:\n\
120             - App Cache Hit Rate: {:.2}%\n\
121             - Tenant Cache Hit Rate: {:.2}%\n\
122             - Refresh Success Rate: {:.2}%\n\
123             - Total Read Locks: {}\n\
124             - Total Write Locks: {}\n\
125             - App Cache: {} hits, {} misses\n\
126             - Tenant Cache: {} hits, {} misses\n\
127             - Refreshes: {} success, {} failures",
128            self.app_cache_hit_rate() * 100.0,
129            self.tenant_cache_hit_rate() * 100.0,
130            self.refresh_success_rate() * 100.0,
131            self.read_lock_acquisitions.load(Ordering::Relaxed),
132            self.write_lock_acquisitions.load(Ordering::Relaxed),
133            self.app_cache_hits.load(Ordering::Relaxed),
134            self.app_cache_misses.load(Ordering::Relaxed),
135            self.tenant_cache_hits.load(Ordering::Relaxed),
136            self.tenant_cache_misses.load(Ordering::Relaxed),
137            self.refresh_success.load(Ordering::Relaxed),
138            self.refresh_failures.load(Ordering::Relaxed)
139        )
140    }
141}
142
143#[derive(Debug)]
144pub struct TokenManager {
145    cache: Arc<RwLock<QuickCache<String>>>,
146    metrics: Arc<TokenMetrics>,
147    /// 后台预热任务句柄
148    preheating_handle: Option<tokio::task::JoinHandle<()>>,
149}
150
151impl Default for TokenManager {
152    fn default() -> Self {
153        Self::new()
154    }
155}
156
157impl TokenManager {
158    pub fn new() -> Self {
159        Self {
160            cache: Arc::new(RwLock::new(QuickCache::new())),
161            metrics: Arc::new(TokenMetrics::new()),
162            preheating_handle: None,
163        }
164    }
165
166    /// 获取性能指标的只读引用
167    pub fn metrics(&self) -> &Arc<TokenMetrics> {
168        &self.metrics
169    }
170
171    /// 获取缓存的克隆引用(用于预热功能)
172    pub fn get_cache(&self) -> Arc<RwLock<QuickCache<String>>> {
173        self.cache.clone()
174    }
175
176    /// 获取性能指标的克隆引用(用于预热功能)
177    pub fn get_metrics(&self) -> Arc<TokenMetrics> {
178        self.metrics.clone()
179    }
180
181    /// 打印性能报告到日志
182    pub fn log_performance_metrics(&self) {
183        log::info!("{}", self.metrics.performance_report());
184    }
185
186    /// 启动后台token预热机制
187    ///
188    /// 这个方法会启动一个后台任务,定期检查即将过期的token并预先刷新它们
189    ///
190    /// # 参数
191    /// - `config`: 应用配置,用于token刷新
192    /// - `app_ticket_manager`: App ticket管理器的引用
193    pub fn start_background_preheating(
194        &mut self,
195        config: Config,
196        app_ticket_manager: Arc<Mutex<AppTicketManager>>,
197    ) {
198        self.start_background_preheating_with_config(
199            config,
200            app_ticket_manager,
201            PreheatingConfig::default(),
202        )
203    }
204
205    /// 启动带自定义配置的后台token预热机制
206    pub fn start_background_preheating_with_config(
207        &mut self,
208        config: Config,
209        app_ticket_manager: Arc<Mutex<AppTicketManager>>,
210        preheat_config: PreheatingConfig,
211    ) {
212        // 如果已有预热任务在运行,先停止它
213        if self.preheating_handle.is_some() {
214            log::info!("🔄 停止现有预热任务,启动新配置的预热任务");
215            self.stop_background_preheating();
216        }
217
218        let cache = self.cache.clone();
219        let metrics = self.metrics.clone();
220
221        let handle = tokio::spawn(async move {
222            let mut interval = interval(Duration::from_secs(preheat_config.check_interval_seconds));
223            log::info!(
224                "🔄 Token后台预热机制已启动,检查间隔: {}分钟,预热阈值: {}分钟",
225                preheat_config.check_interval_seconds / 60,
226                preheat_config.preheat_threshold_seconds / 60
227            );
228
229            loop {
230                interval.tick().await;
231
232                if let Err(e) = Self::preheat_tokens_if_needed_with_config(
233                    &cache,
234                    &metrics,
235                    &config,
236                    &app_ticket_manager,
237                    &preheat_config,
238                )
239                .await
240                {
241                    log::warn!("⚠️ Token预热过程中发生错误: {e:?}");
242                    // 记录错误但继续运行
243                }
244            }
245        });
246
247        self.preheating_handle = Some(handle);
248        log::info!("✅ Token后台预热任务已启动并注册到TokenManager");
249    }
250
251    /// 检查并预热即将过期的token(使用默认配置)
252    #[allow(dead_code)]
253    async fn preheat_tokens_if_needed(
254        cache: &Arc<RwLock<QuickCache<String>>>,
255        metrics: &Arc<TokenMetrics>,
256        config: &Config,
257        app_ticket_manager: &Arc<Mutex<AppTicketManager>>,
258    ) -> SDKResult<()> {
259        Self::preheat_tokens_if_needed_with_config(
260            cache,
261            metrics,
262            config,
263            app_ticket_manager,
264            &PreheatingConfig::default(),
265        )
266        .await
267    }
268
269    /// 检查并预热即将过期的token(使用自定义配置)
270    async fn preheat_tokens_if_needed_with_config(
271        cache: &Arc<RwLock<QuickCache<String>>>,
272        metrics: &Arc<TokenMetrics>,
273        config: &Config,
274        app_ticket_manager: &Arc<Mutex<AppTicketManager>>,
275        preheat_config: &PreheatingConfig,
276    ) -> SDKResult<()> {
277        log::debug!("🔍 检查需要预热的token...");
278
279        let mut preheated_count = 0;
280
281        // 检查app access token是否需要预热
282        let app_key = app_access_token_key(&config.app_id);
283        if Self::should_preheat_token_with_threshold(
284            cache,
285            &app_key,
286            preheat_config.preheat_threshold_seconds,
287        )
288        .await
289        {
290            log::info!("🔄 开始预热 app access token");
291            if let Err(e) = Self::preheat_app_token(cache, config, app_ticket_manager).await {
292                log::warn!("❌ App token预热失败: {e:?}");
293                metrics.refresh_failures.fetch_add(1, Ordering::Relaxed);
294            } else {
295                log::info!("✅ App token预热成功");
296                metrics.refresh_success.fetch_add(1, Ordering::Relaxed);
297                preheated_count += 1;
298            }
299        }
300
301        // 预热tenant token(如果启用)
302        if preheat_config.enable_tenant_preheating {
303            let tenant_keys = Self::get_cached_tenant_keys(cache, &config.app_id).await;
304            for tenant_key in tenant_keys
305                .into_iter()
306                .take(preheat_config.max_concurrent_preheat)
307            {
308                let tenant_cache_key = tenant_access_token_key(&config.app_id, &tenant_key);
309                if Self::should_preheat_token_with_threshold(
310                    cache,
311                    &tenant_cache_key,
312                    preheat_config.preheat_threshold_seconds,
313                )
314                .await
315                {
316                    log::info!("🔄 开始预热 tenant access token: {tenant_key}");
317                    if let Err(e) =
318                        Self::preheat_tenant_token(cache, config, &tenant_key, app_ticket_manager)
319                            .await
320                    {
321                        log::warn!("❌ Tenant token预热失败 ({tenant_key}): {e:?}");
322                        metrics.refresh_failures.fetch_add(1, Ordering::Relaxed);
323                    } else {
324                        log::info!("✅ Tenant token预热成功: {tenant_key}");
325                        metrics.refresh_success.fetch_add(1, Ordering::Relaxed);
326                        preheated_count += 1;
327                    }
328                }
329            }
330        }
331
332        if preheated_count > 0 {
333            log::info!("🎯 本轮预热完成,共刷新了 {preheated_count} 个token");
334        } else {
335            log::debug!("✨ 所有token状态良好,无需预热");
336        }
337
338        Ok(())
339    }
340
341    /// 判断指定的token是否需要预热(使用默认15分钟阈值)
342    #[allow(dead_code)]
343    async fn should_preheat_token(cache: &Arc<RwLock<QuickCache<String>>>, key: &str) -> bool {
344        Self::should_preheat_token_with_threshold(cache, key, 900).await
345    }
346
347    /// 判断指定的token是否需要预热(自定义阈值)
348    ///
349    /// 如果token不存在或即将在指定时间内过期,则需要预热
350    async fn should_preheat_token_with_threshold(
351        cache: &Arc<RwLock<QuickCache<String>>>,
352        key: &str,
353        threshold_seconds: u64,
354    ) -> bool {
355        let cache_read = cache.read().await;
356
357        // 如果token不存在,需要预热
358        if cache_read.get(key).is_none_or(|token| token.is_empty()) {
359            log::debug!("🔍 Token {key} 不存在,需要预热");
360            return true;
361        }
362
363        // 检查是否即将过期
364        if let Some(expiry_info) = cache_read.get_with_expiry(key) {
365            let remaining_seconds = expiry_info.expiry_seconds();
366            // 如果剩余时间少于阈值,需要预热
367            if remaining_seconds < threshold_seconds {
368                log::debug!(
369                    "🔍 Token {key} 将在{remaining_seconds}秒后过期,阈值{threshold_seconds}秒,需要预热"
370                );
371                return true;
372            }
373        }
374
375        false
376    }
377
378    /// 获取缓存中所有的tenant keys
379    async fn get_cached_tenant_keys(
380        _cache: &Arc<RwLock<QuickCache<String>>>,
381        _app_id: &str,
382    ) -> Vec<String> {
383        // 注意:这里需要QuickCache提供遍历功能,目前简化为空列表
384        // 在实际实现中,可以维护一个单独的tenant_keys集合
385        // 或者在QuickCache中添加keys()方法来遍历所有键
386        vec![]
387    }
388
389    /// 预热app access token (直接更新主缓存)
390    async fn preheat_app_token(
391        cache: &Arc<RwLock<QuickCache<String>>>,
392        config: &Config,
393        app_ticket_manager: &Arc<Mutex<AppTicketManager>>,
394    ) -> SDKResult<String> {
395        // 直接使用主缓存实例进行预热
396        let temp_manager = TokenManager {
397            cache: cache.clone(),
398            metrics: Arc::new(TokenMetrics::new()), // 临时指标,只用于API调用
399            preheating_handle: None,
400        };
401
402        match config.app_type {
403            AppType::SelfBuild => {
404                temp_manager
405                    .get_custom_app_access_token_then_cache(config)
406                    .await
407            }
408            _ => {
409                temp_manager
410                    .get_marketplace_app_access_token_then_cache(config, "", app_ticket_manager)
411                    .await
412            }
413        }
414    }
415
416    /// 预热tenant access token (直接更新主缓存)
417    async fn preheat_tenant_token(
418        cache: &Arc<RwLock<QuickCache<String>>>,
419        config: &Config,
420        tenant_key: &str,
421        app_ticket_manager: &Arc<Mutex<AppTicketManager>>,
422    ) -> SDKResult<String> {
423        // 直接使用主缓存实例进行预热
424        let temp_manager = TokenManager {
425            cache: cache.clone(),
426            metrics: Arc::new(TokenMetrics::new()), // 临时指标,只用于API调用
427            preheating_handle: None,
428        };
429
430        if config.app_type == AppType::SelfBuild {
431            temp_manager
432                .get_custom_tenant_access_token_then_cache(config, tenant_key)
433                .await
434        } else {
435            temp_manager
436                .get_marketplace_tenant_access_token_then_cache(
437                    config,
438                    tenant_key,
439                    "",
440                    app_ticket_manager,
441                )
442                .await
443        }
444    }
445
446    /// 停止后台预热任务
447    pub fn stop_background_preheating(&mut self) {
448        if let Some(handle) = self.preheating_handle.take() {
449            handle.abort();
450            log::info!("🛑 Token后台预热机制已停止");
451        }
452    }
453
454    /// 检查预热任务是否正在运行 (用于测试)
455    pub fn is_preheating_active(&self) -> bool {
456        self.preheating_handle.is_some()
457    }
458    pub async fn get_app_access_token(
459        &self,
460        config: &Config,
461        app_ticket: &str,
462        app_ticket_manager: &Arc<Mutex<AppTicketManager>>,
463    ) -> SDKResult<String> {
464        let span = info_span!(
465            "token_get_app",
466            app_id = %config.app_id,
467            app_type = ?config.app_type,
468            cache_hit = tracing::field::Empty,
469            duration_ms = tracing::field::Empty,
470        );
471
472        async move {
473            let start_time = Instant::now();
474            let key = app_access_token_key(&config.app_id);
475
476            // 快速路径:使用读锁尝试获取缓存的token
477            {
478                self.metrics
479                    .read_lock_acquisitions
480                    .fetch_add(1, Ordering::Relaxed);
481                let cache = self.cache.read().await;
482                if let Some(token) = cache.get(&key) {
483                    if !token.is_empty() {
484                        self.metrics.app_cache_hits.fetch_add(1, Ordering::Relaxed);
485                        let current_span = tracing::Span::current();
486                        current_span.record("cache_hit", true);
487                        current_span.record("duration_ms", start_time.elapsed().as_millis() as u64);
488                        log::debug!("App token cache hit in {:?}", start_time.elapsed());
489                        return Ok(token);
490                    }
491                }
492            }
493
494            // 记录缓存未命中
495            tracing::Span::current().record("cache_hit", false);
496            self.metrics
497                .app_cache_misses
498                .fetch_add(1, Ordering::Relaxed);
499
500            // 慢速路径:需要刷新token,使用写锁
501            self.metrics
502                .write_lock_acquisitions
503                .fetch_add(1, Ordering::Relaxed);
504            let cache = self.cache.write().await;
505
506            // 双重检查:可能其他线程已经刷新了token
507            if let Some(token) = cache.get(&key) {
508                if !token.is_empty() {
509                    // 双重检查命中,更新为缓存命中统计
510                    self.metrics
511                        .app_cache_misses
512                        .fetch_sub(1, Ordering::Relaxed);
513                    self.metrics.app_cache_hits.fetch_add(1, Ordering::Relaxed);
514                    log::debug!("App token double-check hit in {:?}", start_time.elapsed());
515                    return Ok(token);
516                }
517            }
518
519            // 实际执行token刷新
520            drop(cache); // 释放写锁,避免在HTTP请求期间持有锁
521            log::debug!("App token cache miss, refreshing token");
522
523            let app_type = config.app_type;
524            let result = if app_type == AppType::SelfBuild {
525                self.get_custom_app_access_token_then_cache(config).await
526            } else {
527                self.get_marketplace_app_access_token_then_cache(
528                    config,
529                    app_ticket,
530                    app_ticket_manager,
531                )
532                .await
533            };
534
535            // 记录刷新结果
536            match &result {
537                Ok(_) => {
538                    self.metrics.refresh_success.fetch_add(1, Ordering::Relaxed);
539                    log::debug!("App token refresh succeeded in {:?}", start_time.elapsed());
540                }
541                Err(e) => {
542                    self.metrics
543                        .refresh_failures
544                        .fetch_add(1, Ordering::Relaxed);
545                    log::warn!(
546                        "App token refresh failed in {:?}: {:?}",
547                        start_time.elapsed(),
548                        e
549                    );
550                }
551            }
552
553            tracing::Span::current().record("duration_ms", start_time.elapsed().as_millis() as u64);
554            result
555        }
556        .instrument(span)
557        .await
558    }
559
560    async fn get_custom_app_access_token_then_cache(&self, config: &Config) -> SDKResult<String> {
561        let url = format!("{}{}", config.base_url, APP_ACCESS_TOKEN_INTERNAL_URL_PATH);
562
563        let body = SelfBuiltAppAccessTokenReq {
564            app_id: config.app_id.clone(),
565            app_secret: config.app_secret.clone(),
566        };
567
568        let response = config.http_client.post(&url).json(&body).send().await?;
569
570        let resp: AppAccessTokenResp = response.json().await?;
571        self.handle_app_access_token_response(resp, &config.app_id)
572            .await
573    }
574
575    /// 通用的app access token响应处理逻辑
576    async fn handle_app_access_token_response(
577        &self,
578        resp: AppAccessTokenResp,
579        app_id: &str,
580    ) -> SDKResult<String> {
581        if resp.raw_response.code == 0 {
582            let expire = resp.expire - EXPIRY_DELTA;
583            {
584                let mut cache = self.cache.write().await;
585                cache.set(
586                    &app_access_token_key(app_id),
587                    resp.app_access_token.clone(),
588                    expire,
589                );
590            }
591            Ok(resp.app_access_token)
592        } else {
593            warn!("app access token response error: {:#?}", resp.raw_response);
594            Err(LarkAPIError::illegal_param(resp.raw_response.msg.clone()))
595        }
596    }
597    async fn get_marketplace_app_access_token_then_cache(
598        &self,
599        config: &Config,
600        app_ticket: &str,
601        app_ticket_manager: &Arc<Mutex<AppTicketManager>>,
602    ) -> SDKResult<String> {
603        let mut app_ticket = app_ticket.to_string();
604        if app_ticket.is_empty() {
605            match app_ticket_manager.lock().await.get(config).await {
606                None => return Err(LarkAPIError::illegal_param("App ticket is empty")),
607                Some(ticket) => {
608                    app_ticket = ticket;
609                }
610            }
611        }
612
613        let url = format!("{}{}", config.base_url, APP_ACCESS_TOKEN_URL_PATH);
614
615        let body = MarketplaceAppAccessTokenReq {
616            app_id: config.app_id.clone(),
617            app_secret: config.app_secret.clone(),
618            app_ticket,
619        };
620
621        let response = config.http_client.post(&url).json(&body).send().await?;
622
623        let resp: AppAccessTokenResp = response.json().await?;
624        self.handle_app_access_token_response(resp, &config.app_id)
625            .await
626    }
627
628    pub async fn get_tenant_access_token(
629        &self,
630        config: &Config,
631        tenant_key: &str,
632        app_ticket: &str,
633        app_ticket_manager: &Arc<Mutex<AppTicketManager>>,
634    ) -> SDKResult<String> {
635        let start_time = Instant::now();
636        let key = tenant_access_token_key(&config.app_id, tenant_key);
637
638        // 快速路径:使用读锁尝试获取缓存的token
639        {
640            self.metrics
641                .read_lock_acquisitions
642                .fetch_add(1, Ordering::Relaxed);
643            let cache = self.cache.read().await;
644            if let Some(token) = cache.get(&key) {
645                if !token.is_empty() {
646                    self.metrics
647                        .tenant_cache_hits
648                        .fetch_add(1, Ordering::Relaxed);
649                    log::debug!("Tenant token cache hit in {:?}", start_time.elapsed());
650                    return Ok(token);
651                }
652            }
653        }
654
655        // 记录缓存未命中
656        self.metrics
657            .tenant_cache_misses
658            .fetch_add(1, Ordering::Relaxed);
659
660        // 慢速路径:需要刷新token,使用写锁
661        self.metrics
662            .write_lock_acquisitions
663            .fetch_add(1, Ordering::Relaxed);
664        let cache = self.cache.write().await;
665
666        // 双重检查:可能其他线程已经刷新了token
667        if let Some(token) = cache.get(&key) {
668            if !token.is_empty() {
669                // 双重检查命中,更新为缓存命中统计
670                self.metrics
671                    .tenant_cache_misses
672                    .fetch_sub(1, Ordering::Relaxed);
673                self.metrics
674                    .tenant_cache_hits
675                    .fetch_add(1, Ordering::Relaxed);
676                log::debug!(
677                    "Tenant token double-check hit in {:?}",
678                    start_time.elapsed()
679                );
680                return Ok(token);
681            }
682        }
683
684        // 实际执行token刷新
685        drop(cache); // 释放写锁,避免在HTTP请求期间持有锁
686        log::debug!("Tenant token cache miss, refreshing token");
687
688        let result = if config.app_type == AppType::SelfBuild {
689            self.get_custom_tenant_access_token_then_cache(config, tenant_key)
690                .await
691        } else {
692            self.get_marketplace_tenant_access_token_then_cache(
693                config,
694                tenant_key,
695                app_ticket,
696                app_ticket_manager,
697            )
698            .await
699        };
700
701        // 记录刷新结果
702        match &result {
703            Ok(_) => {
704                self.metrics.refresh_success.fetch_add(1, Ordering::Relaxed);
705                log::debug!(
706                    "Tenant token refresh succeeded in {:?}",
707                    start_time.elapsed()
708                );
709            }
710            Err(e) => {
711                self.metrics
712                    .refresh_failures
713                    .fetch_add(1, Ordering::Relaxed);
714                log::warn!(
715                    "Tenant token refresh failed in {:?}: {:?}",
716                    start_time.elapsed(),
717                    e
718                );
719            }
720        }
721
722        result
723    }
724
725    async fn get_custom_tenant_access_token_then_cache(
726        &self,
727        config: &Config,
728        tenant_key: &str,
729    ) -> SDKResult<String> {
730        let url = format!(
731            "{}{}",
732            config.base_url, TENANT_ACCESS_TOKEN_INTERNAL_URL_PATH
733        );
734
735        let body = SelfBuiltTenantAccessTokenReq {
736            app_id: config.app_id.clone(),
737            app_secret: config.app_secret.clone(),
738        };
739
740        let response = config.http_client.post(&url).json(&body).send().await?;
741
742        let resp: TenantAccessTokenResp = response.json().await?;
743        self.handle_tenant_access_token_response(resp, &config.app_id, tenant_key)
744            .await
745    }
746
747    /// 通用的tenant access token响应处理逻辑
748    async fn handle_tenant_access_token_response(
749        &self,
750        resp: TenantAccessTokenResp,
751        app_id: &str,
752        tenant_key: &str,
753    ) -> SDKResult<String> {
754        if resp.raw_response.code == 0 {
755            let expire = resp.expire - EXPIRY_DELTA;
756            {
757                let mut cache = self.cache.write().await;
758                cache.set(
759                    &tenant_access_token_key(app_id, tenant_key),
760                    resp.tenant_access_token.clone(),
761                    expire,
762                );
763            }
764            Ok(resp.tenant_access_token)
765        } else {
766            warn!(
767                "tenant access token response error: {:#?}",
768                resp.raw_response
769            );
770            Err(LarkAPIError::illegal_param(resp.raw_response.msg.clone()))
771        }
772    }
773
774    async fn get_marketplace_tenant_access_token_then_cache(
775        &self,
776        config: &Config,
777        tenant_key: &str,
778        app_ticket: &str,
779        app_ticket_manager: &Arc<Mutex<AppTicketManager>>,
780    ) -> SDKResult<String> {
781        let app_access_token = self
782            .get_marketplace_app_access_token_then_cache(config, app_ticket, app_ticket_manager)
783            .await?;
784
785        let url = format!("{}{}", config.base_url, TENANT_ACCESS_TOKEN_URL_PATH);
786
787        let body = MarketplaceTenantAccessTokenReq {
788            app_access_token,
789            tenant_key: tenant_key.to_string(),
790        };
791
792        let response = config
793            .http_client
794            .post(&url)
795            .json(&body)
796            .header(
797                "Authorization",
798                &format!("Bearer {}", &body.app_access_token),
799            )
800            .send()
801            .await?;
802
803        let resp: TenantAccessTokenResp = response.json().await?;
804        self.handle_tenant_access_token_response(resp, &config.app_id, tenant_key)
805            .await
806    }
807}
808
809fn app_access_token_key(app_id: &str) -> String {
810    format!("{APP_ACCESS_TOKEN_KEY_PREFIX}-{app_id}")
811}
812
813fn tenant_access_token_key(app_id: &str, tenant_key: &str) -> String {
814    format!("{APP_ACCESS_TOKEN_KEY_PREFIX}-{app_id}-{tenant_key}")
815}
816
817#[derive(Debug, Serialize, Deserialize)]
818struct SelfBuiltAppAccessTokenReq {
819    app_id: String,
820    app_secret: String,
821}
822
823#[derive(Debug, Serialize, Deserialize)]
824struct SelfBuiltTenantAccessTokenReq {
825    app_id: String,
826    app_secret: String,
827}
828
829#[derive(Serialize, Deserialize, Debug)]
830struct AppAccessTokenResp {
831    #[serde(flatten)]
832    raw_response: RawResponse,
833    expire: i32,
834    app_access_token: String,
835}
836
837impl ApiResponseTrait for AppAccessTokenResp {
838    fn data_format() -> ResponseFormat {
839        ResponseFormat::Flatten
840    }
841}
842
843#[derive(Serialize, Deserialize)]
844struct MarketplaceAppAccessTokenReq {
845    app_id: String,
846    app_secret: String,
847    app_ticket: String,
848}
849
850#[derive(Serialize, Deserialize)]
851struct MarketplaceTenantAccessTokenReq {
852    app_access_token: String,
853    tenant_key: String,
854}
855
856#[derive(Serialize, Deserialize, Debug)]
857struct TenantAccessTokenResp {
858    #[serde(flatten)]
859    raw_response: RawResponse,
860    expire: i32,
861    tenant_access_token: String,
862}
863
864impl ApiResponseTrait for TenantAccessTokenResp {
865    fn data_format() -> ResponseFormat {
866        ResponseFormat::Flatten
867    }
868}
869
870#[cfg(test)]
871mod tests {
872    use super::*;
873    use crate::core::{config::Config, constants::AppType};
874    use std::{sync::Arc, time::Duration};
875    use tokio::sync::Mutex;
876
877    #[test]
878    fn test_token_manager_creation() {
879        let manager = TokenManager::new();
880        // 测试创建TokenManager不会panic
881        // 注意:QuickCache没有len方法,我们只测试创建不panic
882        let _cache = &manager.cache;
883    }
884
885    #[test]
886    fn test_app_access_token_key_generation() {
887        let app_id = "test_app_id";
888        let key = app_access_token_key(app_id);
889        assert_eq!(key, format!("{APP_ACCESS_TOKEN_KEY_PREFIX}-{app_id}"));
890    }
891
892    #[test]
893    fn test_tenant_access_token_key_generation() {
894        let app_id = "test_app_id";
895        let tenant_key = "test_tenant";
896        let key = tenant_access_token_key(app_id, tenant_key);
897        assert_eq!(
898            key,
899            format!("{APP_ACCESS_TOKEN_KEY_PREFIX}-{app_id}-{tenant_key}")
900        );
901    }
902
903    #[tokio::test]
904    async fn test_cache_miss_returns_empty_string() {
905        let manager = TokenManager::new();
906        let key = "non_existent_key";
907
908        // 验证缓存miss时返回空字符串而不是panic
909        let cache = manager.cache.read().await;
910        let result = cache.get(key).unwrap_or_default();
911        assert_eq!(result, String::new());
912    }
913
914    #[tokio::test]
915    async fn test_get_app_access_token_cache_miss_does_not_error() {
916        let manager = TokenManager::new();
917        let config = Config::builder()
918            .app_id("test_app")
919            .app_secret("test_secret")
920            .app_type(AppType::SelfBuild)
921            .base_url("https://open.feishu.cn")
922            .enable_token_cache(true)
923            .req_timeout(Duration::from_secs(30))
924            .build();
925
926        let app_ticket_manager = Arc::new(Mutex::new(
927            crate::core::app_ticket_manager::AppTicketManager::new(),
928        ));
929
930        // 测试缓存miss时不会立即返回错误,而是尝试获取新token
931        // 注意:此测试会因为实际API调用失败而失败,但不应该因为缓存逻辑失败
932        let result = manager
933            .get_app_access_token(&config, "", &app_ticket_manager)
934            .await;
935
936        // 这里我们期望的是网络错误或API错误,而不是"cache error"
937        if let Err(error) = result {
938            let error_msg = format!("{error:?}");
939            assert!(
940                !error_msg.contains("cache error"),
941                "应该不再出现'cache error',而是实际的API调用错误: {error_msg}"
942            );
943        }
944    }
945
946    #[test]
947    fn test_token_metrics_creation() {
948        let metrics = TokenMetrics::new();
949
950        // 测试初始状态
951        assert_eq!(metrics.app_cache_hit_rate(), 0.0);
952        assert_eq!(metrics.tenant_cache_hit_rate(), 0.0);
953        assert_eq!(metrics.refresh_success_rate(), 0.0);
954    }
955
956    #[test]
957    fn test_token_metrics_cache_hit_rate_calculation() {
958        let metrics = TokenMetrics::new();
959
960        // 模拟一些缓存命中和未命中
961        metrics.app_cache_hits.store(8, Ordering::Relaxed);
962        metrics.app_cache_misses.store(2, Ordering::Relaxed);
963
964        assert_eq!(metrics.app_cache_hit_rate(), 0.8); // 8/(8+2) = 0.8
965
966        // 测试tenant缓存
967        metrics.tenant_cache_hits.store(9, Ordering::Relaxed);
968        metrics.tenant_cache_misses.store(1, Ordering::Relaxed);
969
970        assert_eq!(metrics.tenant_cache_hit_rate(), 0.9); // 9/(9+1) = 0.9
971    }
972
973    #[test]
974    fn test_token_metrics_refresh_success_rate() {
975        let metrics = TokenMetrics::new();
976
977        // 模拟刷新成功和失败
978        metrics.refresh_success.store(19, Ordering::Relaxed);
979        metrics.refresh_failures.store(1, Ordering::Relaxed);
980
981        assert_eq!(metrics.refresh_success_rate(), 0.95); // 19/(19+1) = 0.95
982    }
983
984    #[test]
985    fn test_token_metrics_performance_report() {
986        let metrics = TokenMetrics::new();
987
988        // 设置一些测试数据
989        metrics.app_cache_hits.store(80, Ordering::Relaxed);
990        metrics.app_cache_misses.store(20, Ordering::Relaxed);
991        metrics.refresh_success.store(95, Ordering::Relaxed);
992        metrics.refresh_failures.store(5, Ordering::Relaxed);
993
994        let report = metrics.performance_report();
995
996        // 验证报告包含关键信息
997        assert!(report.contains("80.00%")); // App cache hit rate
998        assert!(report.contains("95.00%")); // Refresh success rate
999        assert!(report.contains("80 hits, 20 misses")); // Cache statistics
1000    }
1001
1002    #[tokio::test]
1003    async fn test_token_manager_metrics_integration() {
1004        let manager = TokenManager::new();
1005
1006        // 验证metrics可以正常访问
1007        let metrics = manager.metrics();
1008        assert_eq!(metrics.read_lock_acquisitions.load(Ordering::Relaxed), 0);
1009
1010        // 验证性能报告功能
1011        manager.log_performance_metrics(); // 应该不会panic
1012    }
1013
1014    #[tokio::test]
1015    async fn test_preheating_config_default_values() {
1016        let config = PreheatingConfig::default();
1017        assert_eq!(config.check_interval_seconds, 1800); // 30分钟
1018        assert_eq!(config.preheat_threshold_seconds, 900); // 15分钟
1019        assert!(config.enable_tenant_preheating);
1020        assert_eq!(config.max_concurrent_preheat, 3);
1021    }
1022
1023    #[tokio::test]
1024    async fn test_should_preheat_token_with_custom_threshold() {
1025        let manager = TokenManager::new();
1026        let key = "test_token_key";
1027
1028        // 测试不存在的token应该需要预热
1029        assert!(TokenManager::should_preheat_token_with_threshold(&manager.cache, key, 600).await);
1030
1031        // 添加一个token到缓存(模拟刚刷新的token)
1032        {
1033            let mut cache = manager.cache.write().await;
1034            cache.set(key, "test_token_value".to_string(), 3600); // 1小时后过期
1035        }
1036
1037        // 测试长阈值应该不需要预热
1038        assert!(!TokenManager::should_preheat_token_with_threshold(&manager.cache, key, 600).await);
1039
1040        // 测试短阈值应该需要预热
1041        assert!(TokenManager::should_preheat_token_with_threshold(&manager.cache, key, 3700).await);
1042    }
1043
1044    #[tokio::test]
1045    async fn test_get_cached_tenant_keys() {
1046        let manager = TokenManager::new();
1047
1048        // 测试空缓存时返回空列表
1049        let tenant_keys = TokenManager::get_cached_tenant_keys(&manager.cache, "test_app").await;
1050        assert!(tenant_keys.is_empty());
1051    }
1052
1053    #[test]
1054    fn test_cache_entry_expiry_calculations() {
1055        use crate::core::cache::CacheEntry;
1056        use std::time::Duration;
1057        use tokio::time::Instant;
1058
1059        let now = Instant::now();
1060        let expires_in_10_mins = now + Duration::from_secs(600);
1061
1062        let entry = CacheEntry {
1063            value: "test_value".to_string(),
1064            expires_at: expires_in_10_mins,
1065            current_time: now,
1066        };
1067
1068        // 测试过期时间计算
1069        assert_eq!(entry.expiry_seconds(), 600);
1070
1071        // 测试即将过期判断
1072        assert!(entry.expires_within(700)); // 10分钟 < 700秒
1073        assert!(!entry.expires_within(500)); // 10分钟 > 500秒
1074    }
1075
1076    #[test]
1077    fn test_preheating_config_custom_values() {
1078        let config = PreheatingConfig {
1079            check_interval_seconds: 900,
1080            preheat_threshold_seconds: 300,
1081            enable_tenant_preheating: false,
1082            max_concurrent_preheat: 5,
1083        };
1084
1085        assert_eq!(config.check_interval_seconds, 900);
1086        assert_eq!(config.preheat_threshold_seconds, 300);
1087        assert!(!config.enable_tenant_preheating);
1088        assert_eq!(config.max_concurrent_preheat, 5);
1089    }
1090
1091    #[test]
1092    fn test_preheating_config_clone() {
1093        let config = PreheatingConfig::default();
1094        let cloned = config.clone();
1095
1096        assert_eq!(config.check_interval_seconds, cloned.check_interval_seconds);
1097        assert_eq!(
1098            config.preheat_threshold_seconds,
1099            cloned.preheat_threshold_seconds
1100        );
1101        assert_eq!(
1102            config.enable_tenant_preheating,
1103            cloned.enable_tenant_preheating
1104        );
1105        assert_eq!(config.max_concurrent_preheat, cloned.max_concurrent_preheat);
1106    }
1107
1108    #[test]
1109    fn test_preheating_config_debug() {
1110        let config = PreheatingConfig::default();
1111        let debug_str = format!("{:?}", config);
1112
1113        assert!(debug_str.contains("PreheatingConfig"));
1114        assert!(debug_str.contains("1800"));
1115        assert!(debug_str.contains("900"));
1116    }
1117
1118    #[test]
1119    fn test_token_metrics_zero_division_safety() {
1120        let metrics = TokenMetrics::new();
1121
1122        // 测试零除法安全性 - 当没有统计数据时应该返回0.0
1123        assert_eq!(metrics.app_cache_hit_rate(), 0.0);
1124        assert_eq!(metrics.tenant_cache_hit_rate(), 0.0);
1125        assert_eq!(metrics.refresh_success_rate(), 0.0);
1126    }
1127
1128    #[test]
1129    fn test_token_metrics_edge_cases() {
1130        let metrics = TokenMetrics::new();
1131
1132        // 测试只有缓存命中,没有未命中的情况
1133        metrics.app_cache_hits.store(100, Ordering::Relaxed);
1134        assert_eq!(metrics.app_cache_hit_rate(), 1.0);
1135
1136        // 测试只有缓存未命中,没有命中的情况
1137        metrics.app_cache_hits.store(0, Ordering::Relaxed);
1138        metrics.app_cache_misses.store(50, Ordering::Relaxed);
1139        assert_eq!(metrics.app_cache_hit_rate(), 0.0);
1140    }
1141
1142    #[test]
1143    fn test_token_metrics_debug() {
1144        let metrics = TokenMetrics::new();
1145        let debug_str = format!("{:?}", metrics);
1146
1147        assert!(debug_str.contains("TokenMetrics"));
1148        assert!(debug_str.contains("app_cache_hits"));
1149        assert!(debug_str.contains("refresh_success"));
1150    }
1151
1152    #[test]
1153    fn test_token_metrics_all_rates_with_data() {
1154        let metrics = TokenMetrics::new();
1155
1156        // 设置各种统计数据
1157        metrics.app_cache_hits.store(75, Ordering::Relaxed);
1158        metrics.app_cache_misses.store(25, Ordering::Relaxed);
1159        metrics.tenant_cache_hits.store(60, Ordering::Relaxed);
1160        metrics.tenant_cache_misses.store(40, Ordering::Relaxed);
1161        metrics.refresh_success.store(90, Ordering::Relaxed);
1162        metrics.refresh_failures.store(10, Ordering::Relaxed);
1163        metrics.read_lock_acquisitions.store(200, Ordering::Relaxed);
1164        metrics.write_lock_acquisitions.store(50, Ordering::Relaxed);
1165
1166        assert_eq!(metrics.app_cache_hit_rate(), 0.75);
1167        assert_eq!(metrics.tenant_cache_hit_rate(), 0.6);
1168        assert_eq!(metrics.refresh_success_rate(), 0.9);
1169        assert_eq!(metrics.read_lock_acquisitions.load(Ordering::Relaxed), 200);
1170        assert_eq!(metrics.write_lock_acquisitions.load(Ordering::Relaxed), 50);
1171    }
1172
1173    #[test]
1174    fn test_token_request_structs_serialization() {
1175        let self_built_req = SelfBuiltAppAccessTokenReq {
1176            app_id: "test_app".to_string(),
1177            app_secret: "test_secret".to_string(),
1178        };
1179
1180        let json = serde_json::to_string(&self_built_req).unwrap();
1181        assert!(json.contains("test_app"));
1182        assert!(json.contains("test_secret"));
1183
1184        let deserialized: SelfBuiltAppAccessTokenReq = serde_json::from_str(&json).unwrap();
1185        assert_eq!(deserialized.app_id, "test_app");
1186        assert_eq!(deserialized.app_secret, "test_secret");
1187    }
1188
1189    #[test]
1190    fn test_marketplace_token_request_serialization() {
1191        let marketplace_req = MarketplaceAppAccessTokenReq {
1192            app_id: "marketplace_app".to_string(),
1193            app_secret: "marketplace_secret".to_string(),
1194            app_ticket: "test_ticket".to_string(),
1195        };
1196
1197        let json = serde_json::to_string(&marketplace_req).unwrap();
1198        assert!(json.contains("marketplace_app"));
1199        assert!(json.contains("marketplace_secret"));
1200        assert!(json.contains("test_ticket"));
1201
1202        let deserialized: MarketplaceAppAccessTokenReq = serde_json::from_str(&json).unwrap();
1203        assert_eq!(deserialized.app_id, "marketplace_app");
1204        assert_eq!(deserialized.app_ticket, "test_ticket");
1205    }
1206
1207    #[test]
1208    fn test_tenant_token_request_serialization() {
1209        let tenant_req = MarketplaceTenantAccessTokenReq {
1210            app_access_token: "app_token_123".to_string(),
1211            tenant_key: "tenant_abc".to_string(),
1212        };
1213
1214        let json = serde_json::to_string(&tenant_req).unwrap();
1215        assert!(json.contains("app_token_123"));
1216        assert!(json.contains("tenant_abc"));
1217
1218        let deserialized: MarketplaceTenantAccessTokenReq = serde_json::from_str(&json).unwrap();
1219        assert_eq!(deserialized.app_access_token, "app_token_123");
1220        assert_eq!(deserialized.tenant_key, "tenant_abc");
1221    }
1222
1223    #[test]
1224    fn test_app_access_token_response() {
1225        use crate::core::api_resp::{RawResponse, ResponseFormat};
1226
1227        // 测试ResponseFormat
1228        assert!(matches!(
1229            AppAccessTokenResp::data_format(),
1230            ResponseFormat::Flatten
1231        ));
1232
1233        // 测试响应结构
1234        let raw_resp = RawResponse {
1235            code: 0,
1236            msg: "success".to_string(),
1237            err: None,
1238        };
1239
1240        let resp = AppAccessTokenResp {
1241            raw_response: raw_resp,
1242            expire: 3600,
1243            app_access_token: "test_token_123".to_string(),
1244        };
1245
1246        assert_eq!(resp.expire, 3600);
1247        assert_eq!(resp.app_access_token, "test_token_123");
1248        assert_eq!(resp.raw_response.code, 0);
1249    }
1250
1251    #[test]
1252    fn test_tenant_access_token_response() {
1253        use crate::core::api_resp::{RawResponse, ResponseFormat};
1254
1255        // 测试ResponseFormat
1256        assert!(matches!(
1257            TenantAccessTokenResp::data_format(),
1258            ResponseFormat::Flatten
1259        ));
1260
1261        // 测试响应结构
1262        let raw_resp = RawResponse {
1263            code: 0,
1264            msg: "success".to_string(),
1265            err: None,
1266        };
1267
1268        let resp = TenantAccessTokenResp {
1269            raw_response: raw_resp,
1270            expire: 7200,
1271            tenant_access_token: "tenant_token_456".to_string(),
1272        };
1273
1274        assert_eq!(resp.expire, 7200);
1275        assert_eq!(resp.tenant_access_token, "tenant_token_456");
1276        assert_eq!(resp.raw_response.code, 0);
1277    }
1278
1279    #[tokio::test]
1280    async fn test_token_manager_stop_preheating() {
1281        let mut manager = TokenManager::new();
1282
1283        // 确保初始状态下没有预热任务
1284        assert!(!manager.is_preheating_active());
1285
1286        // 停止不存在的预热任务应该不会panic
1287        manager.stop_background_preheating();
1288        assert!(!manager.is_preheating_active());
1289    }
1290
1291    #[tokio::test]
1292    async fn test_token_manager_concurrent_access() {
1293        let manager = Arc::new(TokenManager::new());
1294        let manager_clone = manager.clone();
1295
1296        // 测试并发访问不会导致死锁
1297        let handle1 = tokio::spawn(async move {
1298            let cache = manager_clone.cache.read().await;
1299            cache.get("test_key")
1300        });
1301
1302        let handle2 = tokio::spawn(async move {
1303            let cache = manager.cache.read().await;
1304            cache.get("another_key")
1305        });
1306
1307        let (result1, result2) = tokio::join!(handle1, handle2);
1308        assert!(result1.is_ok());
1309        assert!(result2.is_ok());
1310    }
1311
1312    #[test]
1313    fn test_key_generation_with_special_characters() {
1314        let app_id_with_special = "app-id_with.special@chars";
1315        let tenant_with_special = "tenant.key-with_special@chars";
1316
1317        let app_key = app_access_token_key(app_id_with_special);
1318        let tenant_key = tenant_access_token_key(app_id_with_special, tenant_with_special);
1319
1320        assert!(app_key.contains(app_id_with_special));
1321        assert!(tenant_key.contains(app_id_with_special));
1322        assert!(tenant_key.contains(tenant_with_special));
1323    }
1324
1325    #[test]
1326    fn test_key_generation_with_unicode() {
1327        let app_id = "应用标识符";
1328        let tenant_key = "租户标识符";
1329
1330        let app_key = app_access_token_key(app_id);
1331        let tenant_access_key = tenant_access_token_key(app_id, tenant_key);
1332
1333        assert!(app_key.contains(app_id));
1334        assert!(tenant_access_key.contains(app_id));
1335        assert!(tenant_access_key.contains(tenant_key));
1336    }
1337
1338    #[tokio::test]
1339    async fn test_token_metrics_atomic_operations() {
1340        let metrics = Arc::new(TokenMetrics::new());
1341        let metrics_clone = metrics.clone();
1342
1343        // 测试并发修改指标
1344        let handle = tokio::spawn(async move {
1345            for _ in 0..100 {
1346                metrics_clone.app_cache_hits.fetch_add(1, Ordering::Relaxed);
1347                metrics_clone
1348                    .app_cache_misses
1349                    .fetch_add(1, Ordering::Relaxed);
1350            }
1351        });
1352
1353        for _ in 0..50 {
1354            metrics.refresh_success.fetch_add(1, Ordering::Relaxed);
1355            metrics.refresh_failures.fetch_add(1, Ordering::Relaxed);
1356        }
1357
1358        handle.await.unwrap();
1359
1360        assert_eq!(metrics.app_cache_hits.load(Ordering::Relaxed), 100);
1361        assert_eq!(metrics.app_cache_misses.load(Ordering::Relaxed), 100);
1362        assert_eq!(metrics.refresh_success.load(Ordering::Relaxed), 50);
1363        assert_eq!(metrics.refresh_failures.load(Ordering::Relaxed), 50);
1364    }
1365
1366    #[test]
1367    fn test_self_built_tenant_access_token_req() {
1368        let req = SelfBuiltTenantAccessTokenReq {
1369            app_id: "self_built_app".to_string(),
1370            app_secret: "self_built_secret".to_string(),
1371        };
1372
1373        let json = serde_json::to_string(&req).unwrap();
1374        assert!(json.contains("self_built_app"));
1375        assert!(json.contains("self_built_secret"));
1376
1377        let deserialized: SelfBuiltTenantAccessTokenReq = serde_json::from_str(&json).unwrap();
1378        assert_eq!(deserialized.app_id, "self_built_app");
1379        assert_eq!(deserialized.app_secret, "self_built_secret");
1380    }
1381
1382    #[test]
1383    fn test_token_response_debug() {
1384        use crate::core::api_resp::RawResponse;
1385
1386        let raw_resp = RawResponse {
1387            code: 0,
1388            msg: "success".to_string(),
1389            err: None,
1390        };
1391
1392        let app_resp = AppAccessTokenResp {
1393            raw_response: raw_resp.clone(),
1394            expire: 3600,
1395            app_access_token: "debug_token".to_string(),
1396        };
1397
1398        let debug_str = format!("{:?}", app_resp);
1399        assert!(debug_str.contains("AppAccessTokenResp"));
1400        assert!(debug_str.contains("debug_token"));
1401        assert!(debug_str.contains("3600"));
1402
1403        let tenant_resp = TenantAccessTokenResp {
1404            raw_response: raw_resp,
1405            expire: 7200,
1406            tenant_access_token: "tenant_debug_token".to_string(),
1407        };
1408
1409        let debug_str = format!("{:?}", tenant_resp);
1410        assert!(debug_str.contains("TenantAccessTokenResp"));
1411        assert!(debug_str.contains("tenant_debug_token"));
1412        assert!(debug_str.contains("7200"));
1413    }
1414
1415    #[test]
1416    fn test_token_manager_memory_efficiency() {
1417        // 测试创建多个TokenManager实例不会消耗过多内存
1418        let managers: Vec<TokenManager> = (0..50).map(|_| TokenManager::new()).collect();
1419
1420        assert_eq!(managers.len(), 50);
1421
1422        // 验证每个manager都有独立的缓存和指标
1423        for manager in &managers {
1424            assert!(manager.cache.try_read().is_ok());
1425        }
1426    }
1427
1428    #[test]
1429    fn test_token_manager_default_implementation() {
1430        let manager1 = TokenManager::new();
1431        let manager2 = TokenManager::default();
1432
1433        // 验证new()和default()创建的实例结构相同
1434        assert!(!manager1.is_preheating_active());
1435        assert!(!manager2.is_preheating_active());
1436
1437        // 验证都创建了独立的缓存和指标
1438        assert!(manager1.metrics().app_cache_hit_rate() == manager2.metrics().app_cache_hit_rate());
1439    }
1440
1441    #[test]
1442    fn test_token_manager_get_cache_and_metrics() {
1443        let manager = TokenManager::new();
1444
1445        // 测试获取缓存引用
1446        let cache_ref = manager.get_cache();
1447        assert!(cache_ref.try_read().is_ok());
1448
1449        // 测试获取指标引用
1450        let metrics_ref = manager.get_metrics();
1451        assert_eq!(metrics_ref.app_cache_hit_rate(), 0.0);
1452    }
1453
1454    #[tokio::test]
1455    async fn test_handle_app_access_token_response_success() {
1456        let manager = TokenManager::new();
1457
1458        let successful_resp = AppAccessTokenResp {
1459            raw_response: crate::core::api_resp::RawResponse {
1460                code: 0,
1461                msg: "success".to_string(),
1462                err: None,
1463            },
1464            expire: 3600,
1465            app_access_token: "test_success_token".to_string(),
1466        };
1467
1468        let result = manager
1469            .handle_app_access_token_response(successful_resp, "test_app")
1470            .await;
1471        assert!(result.is_ok());
1472        assert_eq!(result.unwrap(), "test_success_token");
1473
1474        // 验证token已缓存
1475        let cache = manager.cache.read().await;
1476        let cached_token = cache.get(&app_access_token_key("test_app"));
1477        assert_eq!(cached_token, Some("test_success_token".to_string()));
1478    }
1479
1480    #[tokio::test]
1481    async fn test_handle_app_access_token_response_error() {
1482        let manager = TokenManager::new();
1483
1484        let error_resp = AppAccessTokenResp {
1485            raw_response: crate::core::api_resp::RawResponse {
1486                code: 40001,
1487                msg: "invalid app_id".to_string(),
1488                err: None,
1489            },
1490            expire: 0,
1491            app_access_token: "".to_string(),
1492        };
1493
1494        let result = manager
1495            .handle_app_access_token_response(error_resp, "invalid_app")
1496            .await;
1497        assert!(result.is_err());
1498
1499        // 验证错误包含原始错误信息
1500        let error_msg = format!("{:?}", result.unwrap_err());
1501        assert!(error_msg.contains("invalid app_id"));
1502    }
1503
1504    #[tokio::test]
1505    async fn test_handle_tenant_access_token_response_success() {
1506        let manager = TokenManager::new();
1507
1508        let successful_resp = TenantAccessTokenResp {
1509            raw_response: crate::core::api_resp::RawResponse {
1510                code: 0,
1511                msg: "success".to_string(),
1512                err: None,
1513            },
1514            expire: 7200,
1515            tenant_access_token: "test_tenant_token".to_string(),
1516        };
1517
1518        let result = manager
1519            .handle_tenant_access_token_response(successful_resp, "test_app", "test_tenant")
1520            .await;
1521        assert!(result.is_ok());
1522        assert_eq!(result.unwrap(), "test_tenant_token");
1523
1524        // 验证token已缓存
1525        let cache = manager.cache.read().await;
1526        let cached_token = cache.get(&tenant_access_token_key("test_app", "test_tenant"));
1527        assert_eq!(cached_token, Some("test_tenant_token".to_string()));
1528    }
1529
1530    #[tokio::test]
1531    async fn test_handle_tenant_access_token_response_error() {
1532        let manager = TokenManager::new();
1533
1534        let error_resp = TenantAccessTokenResp {
1535            raw_response: crate::core::api_resp::RawResponse {
1536                code: 40002,
1537                msg: "invalid tenant_key".to_string(),
1538                err: None,
1539            },
1540            expire: 0,
1541            tenant_access_token: "".to_string(),
1542        };
1543
1544        let result = manager
1545            .handle_tenant_access_token_response(error_resp, "test_app", "invalid_tenant")
1546            .await;
1547        assert!(result.is_err());
1548
1549        // 验证错误包含原始错误信息
1550        let error_msg = format!("{:?}", result.unwrap_err());
1551        assert!(error_msg.contains("invalid tenant_key"));
1552    }
1553
1554    #[tokio::test]
1555    async fn test_tenant_token_double_check_hit() {
1556        let manager = Arc::new(TokenManager::new());
1557        let config = Config::builder()
1558            .app_id("test_app")
1559            .app_secret("test_secret")
1560            .app_type(AppType::SelfBuild)
1561            .base_url("https://open.feishu.cn")
1562            .build();
1563
1564        let app_ticket_manager = Arc::new(Mutex::new(
1565            crate::core::app_ticket_manager::AppTicketManager::new(),
1566        ));
1567
1568        // 预先在缓存中设置一个token
1569        {
1570            let mut cache = manager.cache.write().await;
1571            cache.set(
1572                &tenant_access_token_key("test_app", "test_tenant"),
1573                "cached_token".to_string(),
1574                3600,
1575            );
1576        }
1577
1578        // 同时启动多个请求,测试双重检查逻辑
1579        let manager_clone = manager.clone();
1580        let config_clone = config.clone();
1581        let app_ticket_manager_clone = app_ticket_manager.clone();
1582
1583        let handle1 = tokio::spawn(async move {
1584            manager_clone
1585                .get_tenant_access_token(
1586                    &config_clone,
1587                    "test_tenant",
1588                    "",
1589                    &app_ticket_manager_clone,
1590                )
1591                .await
1592        });
1593
1594        let handle2 = tokio::spawn(async move {
1595            manager
1596                .get_tenant_access_token(&config, "test_tenant", "", &app_ticket_manager)
1597                .await
1598        });
1599
1600        let (result1, result2) = tokio::join!(handle1, handle2);
1601
1602        // 两个请求都应该成功且返回相同的缓存token
1603        if let (Ok(Ok(token1)), Ok(Ok(token2))) = (result1, result2) {
1604            assert_eq!(token1, "cached_token");
1605            assert_eq!(token2, "cached_token");
1606        }
1607    }
1608
1609    #[tokio::test]
1610    async fn test_app_token_double_check_hit() {
1611        let manager = Arc::new(TokenManager::new());
1612        let config = Config::builder()
1613            .app_id("test_app")
1614            .app_secret("test_secret")
1615            .app_type(AppType::SelfBuild)
1616            .base_url("https://open.feishu.cn")
1617            .build();
1618
1619        let app_ticket_manager = Arc::new(Mutex::new(
1620            crate::core::app_ticket_manager::AppTicketManager::new(),
1621        ));
1622
1623        // 预先在缓存中设置一个token
1624        {
1625            let mut cache = manager.cache.write().await;
1626            cache.set(
1627                &app_access_token_key("test_app"),
1628                "cached_app_token".to_string(),
1629                3600,
1630            );
1631        }
1632
1633        // 同时启动多个请求,测试双重检查逻辑
1634        let manager_clone = manager.clone();
1635        let config_clone = config.clone();
1636        let app_ticket_manager_clone = app_ticket_manager.clone();
1637
1638        let handle1 = tokio::spawn(async move {
1639            manager_clone
1640                .get_app_access_token(&config_clone, "", &app_ticket_manager_clone)
1641                .await
1642        });
1643
1644        let handle2 = tokio::spawn(async move {
1645            manager
1646                .get_app_access_token(&config, "", &app_ticket_manager)
1647                .await
1648        });
1649
1650        let (result1, result2) = tokio::join!(handle1, handle2);
1651
1652        // 两个请求都应该成功且返回相同的缓存token
1653        if let (Ok(Ok(token1)), Ok(Ok(token2))) = (result1, result2) {
1654            assert_eq!(token1, "cached_app_token");
1655            assert_eq!(token2, "cached_app_token");
1656        }
1657    }
1658
1659    #[tokio::test]
1660    async fn test_metrics_record_correctly_during_operations() {
1661        let manager = TokenManager::new();
1662        let config = Config::builder()
1663            .app_id("metrics_test_app")
1664            .app_secret("test_secret")
1665            .build();
1666
1667        let app_ticket_manager = Arc::new(Mutex::new(
1668            crate::core::app_ticket_manager::AppTicketManager::new(),
1669        ));
1670
1671        // 初始指标应该为0
1672        assert_eq!(manager.metrics().app_cache_hits.load(Ordering::Relaxed), 0);
1673        assert_eq!(
1674            manager.metrics().app_cache_misses.load(Ordering::Relaxed),
1675            0
1676        );
1677
1678        // 尝试获取不存在的token(会增加cache miss)
1679        let _result = manager
1680            .get_app_access_token(&config, "", &app_ticket_manager)
1681            .await;
1682
1683        // 验证cache miss被记录
1684        assert!(manager.metrics().app_cache_misses.load(Ordering::Relaxed) > 0);
1685    }
1686
1687    #[tokio::test]
1688    async fn test_empty_string_token_handling() {
1689        let manager = TokenManager::new();
1690
1691        // 设置一个空字符串token到缓存
1692        {
1693            let mut cache = manager.cache.write().await;
1694            cache.set(&app_access_token_key("empty_app"), "".to_string(), 3600);
1695        }
1696
1697        let config = Config::builder()
1698            .app_id("empty_app")
1699            .app_secret("test_secret")
1700            .build();
1701
1702        let app_ticket_manager = Arc::new(Mutex::new(
1703            crate::core::app_ticket_manager::AppTicketManager::new(),
1704        ));
1705
1706        // 空字符串token应该被视为无效,触发刷新
1707        let _result = manager
1708            .get_app_access_token(&config, "", &app_ticket_manager)
1709            .await;
1710
1711        // 验证cache miss被记录(因为空字符串被视为无效)
1712        assert!(manager.metrics().app_cache_misses.load(Ordering::Relaxed) > 0);
1713    }
1714
1715    #[tokio::test]
1716    async fn test_concurrent_cache_access_with_writes() {
1717        let manager = Arc::new(TokenManager::new());
1718        let mut handles = vec![];
1719
1720        // 启动多个并发读操作
1721        for i in 0..10 {
1722            let manager_clone = manager.clone();
1723            let handle = tokio::spawn(async move {
1724                let cache = manager_clone.cache.read().await;
1725                cache.get(&format!("test_key_{}", i))
1726            });
1727            handles.push(handle);
1728        }
1729
1730        // 启动一个写操作
1731        let manager_write = manager.clone();
1732        let write_handle = tokio::spawn(async move {
1733            let mut cache = manager_write.cache.write().await;
1734            cache.set("write_key", "write_value".to_string(), 3600);
1735        });
1736
1737        // 等待所有操作完成
1738        for handle in handles {
1739            assert!(handle.await.is_ok());
1740        }
1741        assert!(write_handle.await.is_ok());
1742
1743        // 验证写操作成功
1744        let cache = manager.cache.read().await;
1745        assert_eq!(cache.get("write_key"), Some("write_value".to_string()));
1746    }
1747
1748    #[tokio::test]
1749    async fn test_preheat_app_token_direct() {
1750        let manager = TokenManager::new();
1751        let cache = manager.get_cache();
1752        let config = Config::builder()
1753            .app_id("preheat_app")
1754            .app_secret("preheat_secret")
1755            .app_type(AppType::SelfBuild)
1756            .base_url("https://open.feishu.cn")
1757            .build();
1758
1759        let app_ticket_manager = Arc::new(Mutex::new(
1760            crate::core::app_ticket_manager::AppTicketManager::new(),
1761        ));
1762
1763        // 测试预热功能(预期会因为网络请求失败)
1764        let result = TokenManager::preheat_app_token(&cache, &config, &app_ticket_manager).await;
1765
1766        // 应该返回网络错误或API错误,而不是缓存错误
1767        if let Err(error) = result {
1768            let error_msg = format!("{:?}", error);
1769            assert!(!error_msg.contains("cache error"));
1770        }
1771    }
1772
1773    #[tokio::test]
1774    async fn test_preheat_tenant_token_direct() {
1775        let manager = TokenManager::new();
1776        let cache = manager.get_cache();
1777        let config = Config::builder()
1778            .app_id("preheat_app")
1779            .app_secret("preheat_secret")
1780            .app_type(AppType::SelfBuild)
1781            .base_url("https://open.feishu.cn")
1782            .build();
1783
1784        let app_ticket_manager = Arc::new(Mutex::new(
1785            crate::core::app_ticket_manager::AppTicketManager::new(),
1786        ));
1787
1788        // 测试预热功能(预期会因为网络请求失败)
1789        let result =
1790            TokenManager::preheat_tenant_token(&cache, &config, "test_tenant", &app_ticket_manager)
1791                .await;
1792
1793        // 应该返回网络错误或API错误,而不是缓存错误
1794        if let Err(error) = result {
1795            let error_msg = format!("{:?}", error);
1796            assert!(!error_msg.contains("cache error"));
1797        }
1798    }
1799
1800    #[tokio::test]
1801    async fn test_should_preheat_token_with_different_thresholds() {
1802        let manager = TokenManager::new();
1803        let key = "threshold_test_key";
1804
1805        // 添加一个token,1小时后过期
1806        {
1807            let mut cache = manager.cache.write().await;
1808            cache.set(key, "test_value".to_string(), 3600);
1809        }
1810
1811        // 测试不同阈值
1812        assert!(!TokenManager::should_preheat_token_with_threshold(&manager.cache, key, 600).await); // 10分钟阈值
1813        assert!(
1814            !TokenManager::should_preheat_token_with_threshold(&manager.cache, key, 1800).await
1815        ); // 30分钟阈值
1816        assert!(
1817            !TokenManager::should_preheat_token_with_threshold(&manager.cache, key, 3000).await
1818        ); // 50分钟阈值
1819        assert!(TokenManager::should_preheat_token_with_threshold(&manager.cache, key, 3700).await);
1820        // 61分钟阈值(大于1小时)
1821    }
1822
1823    #[tokio::test]
1824    async fn test_should_preheat_token_default_threshold() {
1825        let manager = TokenManager::new();
1826        let key = "default_threshold_key";
1827
1828        // 测试不存在的token
1829        assert!(TokenManager::should_preheat_token(&manager.cache, key).await);
1830
1831        // 添加一个token,20分钟后过期
1832        {
1833            let mut cache = manager.cache.write().await;
1834            cache.set(key, "test_value".to_string(), 1200);
1835        }
1836
1837        // 默认阈值是15分钟(900秒),20分钟的token不需要预热
1838        assert!(!TokenManager::should_preheat_token(&manager.cache, key).await);
1839
1840        // 添加一个token,10分钟后过期
1841        {
1842            let mut cache = manager.cache.write().await;
1843            cache.set(key, "test_value2".to_string(), 600);
1844        }
1845
1846        // 10分钟的token需要预热(小于15分钟阈值)
1847        assert!(TokenManager::should_preheat_token(&manager.cache, key).await);
1848    }
1849
1850    #[tokio::test]
1851    async fn test_preheat_tokens_if_needed_default() {
1852        let manager = TokenManager::new();
1853        let cache = manager.get_cache();
1854        let metrics = manager.get_metrics();
1855        let config = Config::builder()
1856            .app_id("preheat_test_app")
1857            .app_secret("test_secret")
1858            .app_type(AppType::SelfBuild)
1859            .base_url("https://open.feishu.cn")
1860            .build();
1861
1862        let app_ticket_manager = Arc::new(Mutex::new(
1863            crate::core::app_ticket_manager::AppTicketManager::new(),
1864        ));
1865
1866        // 测试默认配置的预热功能
1867        let result =
1868            TokenManager::preheat_tokens_if_needed(&cache, &metrics, &config, &app_ticket_manager)
1869                .await;
1870
1871        // 函数应该正常执行,不会panic
1872        // 由于没有可预热的token,或者网络请求失败,结果可能是Ok或Error
1873        match result {
1874            Ok(_) => {
1875                // 成功或者没有需要预热的token
1876                println!("预热检查完成,无需预热或预热成功");
1877            }
1878            Err(e) => {
1879                // 网络错误或API错误,这是预期的
1880                println!("预热过程中发生网络/API错误(预期): {:?}", e);
1881            }
1882        }
1883    }
1884
1885    #[tokio::test]
1886    async fn test_preheat_tokens_with_custom_config() {
1887        let manager = TokenManager::new();
1888        let cache = manager.get_cache();
1889        let metrics = manager.get_metrics();
1890        let config = Config::builder()
1891            .app_id("custom_preheat_app")
1892            .app_secret("test_secret")
1893            .app_type(AppType::SelfBuild)
1894            .base_url("https://open.feishu.cn")
1895            .build();
1896
1897        let app_ticket_manager = Arc::new(Mutex::new(
1898            crate::core::app_ticket_manager::AppTicketManager::new(),
1899        ));
1900
1901        let custom_config = PreheatingConfig {
1902            check_interval_seconds: 300,     // 5分钟
1903            preheat_threshold_seconds: 600,  // 10分钟
1904            enable_tenant_preheating: false, // 禁用tenant预热
1905            max_concurrent_preheat: 1,
1906        };
1907
1908        // 测试自定义配置的预热功能
1909        let result = TokenManager::preheat_tokens_if_needed_with_config(
1910            &cache,
1911            &metrics,
1912            &config,
1913            &app_ticket_manager,
1914            &custom_config,
1915        )
1916        .await;
1917
1918        // 函数应该正常执行
1919        match result {
1920            Ok(_) => {
1921                println!("自定义配置预热检查完成");
1922            }
1923            Err(e) => {
1924                println!("自定义配置预热过程中发生错误(可能是网络错误): {:?}", e);
1925            }
1926        }
1927    }
1928
1929    #[tokio::test]
1930    async fn test_start_background_preheating_basic() {
1931        let mut manager = TokenManager::new();
1932        let config = Config::builder()
1933            .app_id("background_app")
1934            .app_secret("test_secret")
1935            .build();
1936
1937        let app_ticket_manager = Arc::new(Mutex::new(
1938            crate::core::app_ticket_manager::AppTicketManager::new(),
1939        ));
1940
1941        // 启动默认配置的后台预热
1942        manager.start_background_preheating(config, app_ticket_manager);
1943
1944        // 验证预热任务已启动
1945        assert!(manager.is_preheating_active());
1946
1947        // 停止预热任务
1948        manager.stop_background_preheating();
1949        assert!(!manager.is_preheating_active());
1950    }
1951
1952    #[tokio::test]
1953    async fn test_start_background_preheating_with_custom_config() {
1954        let mut manager = TokenManager::new();
1955        let config = Config::builder()
1956            .app_id("custom_background_app")
1957            .app_secret("test_secret")
1958            .build();
1959
1960        let app_ticket_manager = Arc::new(Mutex::new(
1961            crate::core::app_ticket_manager::AppTicketManager::new(),
1962        ));
1963
1964        let custom_config = PreheatingConfig {
1965            check_interval_seconds: 120,    // 2分钟
1966            preheat_threshold_seconds: 300, // 5分钟
1967            enable_tenant_preheating: true,
1968            max_concurrent_preheat: 2,
1969        };
1970
1971        // 启动自定义配置的后台预热
1972        manager.start_background_preheating_with_config(config, app_ticket_manager, custom_config);
1973
1974        // 验证预热任务已启动
1975        assert!(manager.is_preheating_active());
1976
1977        // 停止预热任务
1978        manager.stop_background_preheating();
1979        assert!(!manager.is_preheating_active());
1980    }
1981
1982    #[tokio::test]
1983    async fn test_restart_background_preheating() {
1984        let mut manager = TokenManager::new();
1985        let config = Config::builder()
1986            .app_id("restart_app")
1987            .app_secret("test_secret")
1988            .build();
1989
1990        let app_ticket_manager = Arc::new(Mutex::new(
1991            crate::core::app_ticket_manager::AppTicketManager::new(),
1992        ));
1993
1994        // 首次启动
1995        manager.start_background_preheating(config.clone(), app_ticket_manager.clone());
1996        assert!(manager.is_preheating_active());
1997
1998        // 重新启动(应该先停止现有任务)
1999        let new_config = PreheatingConfig {
2000            check_interval_seconds: 60,
2001            preheat_threshold_seconds: 180,
2002            enable_tenant_preheating: false,
2003            max_concurrent_preheat: 1,
2004        };
2005
2006        manager.start_background_preheating_with_config(config, app_ticket_manager, new_config);
2007        assert!(manager.is_preheating_active());
2008
2009        // 最终停止
2010        manager.stop_background_preheating();
2011        assert!(!manager.is_preheating_active());
2012    }
2013
2014    #[test]
2015    fn test_token_metrics_performance_report_format() {
2016        let metrics = TokenMetrics::new();
2017
2018        // 设置一些测试数据
2019        metrics.app_cache_hits.store(85, Ordering::Relaxed);
2020        metrics.app_cache_misses.store(15, Ordering::Relaxed);
2021        metrics.tenant_cache_hits.store(70, Ordering::Relaxed);
2022        metrics.tenant_cache_misses.store(30, Ordering::Relaxed);
2023        metrics.refresh_success.store(92, Ordering::Relaxed);
2024        metrics.refresh_failures.store(8, Ordering::Relaxed);
2025        metrics.read_lock_acquisitions.store(500, Ordering::Relaxed);
2026        metrics
2027            .write_lock_acquisitions
2028            .store(100, Ordering::Relaxed);
2029
2030        let report = metrics.performance_report();
2031
2032        // 验证报告格式和内容
2033        assert!(report.contains("TokenManager Performance Metrics"));
2034        assert!(report.contains("85.00%")); // App cache hit rate
2035        assert!(report.contains("70.00%")); // Tenant cache hit rate
2036        assert!(report.contains("92.00%")); // Refresh success rate
2037        assert!(report.contains("500")); // Read locks
2038        assert!(report.contains("100")); // Write locks
2039        assert!(report.contains("85 hits, 15 misses")); // App cache stats
2040        assert!(report.contains("70 hits, 30 misses")); // Tenant cache stats
2041        assert!(report.contains("92 success, 8 failures")); // Refresh stats
2042    }
2043
2044    #[test]
2045    fn test_request_structs_debug_trait() {
2046        let self_built_req = SelfBuiltAppAccessTokenReq {
2047            app_id: "debug_app".to_string(),
2048            app_secret: "debug_secret".to_string(),
2049        };
2050
2051        let debug_str = format!("{:?}", self_built_req);
2052        assert!(debug_str.contains("SelfBuiltAppAccessTokenReq"));
2053        assert!(debug_str.contains("debug_app"));
2054
2055        let tenant_req = SelfBuiltTenantAccessTokenReq {
2056            app_id: "tenant_debug_app".to_string(),
2057            app_secret: "tenant_debug_secret".to_string(),
2058        };
2059
2060        let debug_str = format!("{:?}", tenant_req);
2061        assert!(debug_str.contains("SelfBuiltTenantAccessTokenReq"));
2062        assert!(debug_str.contains("tenant_debug_app"));
2063    }
2064
2065    #[tokio::test]
2066    async fn test_marketplace_vs_selfbuild_app_type_handling() {
2067        let manager = TokenManager::new();
2068
2069        // 测试自建应用配置
2070        let self_build_config = Config::builder()
2071            .app_id("self_build_app")
2072            .app_secret("self_build_secret")
2073            .app_type(AppType::SelfBuild)
2074            .base_url("https://open.feishu.cn")
2075            .build();
2076
2077        // 测试应用商店应用配置
2078        let marketplace_config = Config::builder()
2079            .app_id("marketplace_app")
2080            .app_secret("marketplace_secret")
2081            .app_type(AppType::Marketplace)
2082            .base_url("https://open.feishu.cn")
2083            .build();
2084
2085        let app_ticket_manager = Arc::new(Mutex::new(
2086            crate::core::app_ticket_manager::AppTicketManager::new(),
2087        ));
2088
2089        // 测试两种类型的应用都能正确处理(虽然会因网络问题失败)
2090        let self_build_result = manager
2091            .get_app_access_token(&self_build_config, "", &app_ticket_manager)
2092            .await;
2093        let marketplace_result = manager
2094            .get_app_access_token(&marketplace_config, "test_ticket", &app_ticket_manager)
2095            .await;
2096
2097        // 验证都是网络/API错误,而不是配置错误
2098        if let Err(e) = self_build_result {
2099            let error_msg = format!("{:?}", e);
2100            assert!(!error_msg.contains("config error"));
2101        }
2102
2103        if let Err(e) = marketplace_result {
2104            let error_msg = format!("{:?}", e);
2105            assert!(!error_msg.contains("config error"));
2106        }
2107    }
2108
2109    #[tokio::test]
2110    async fn test_token_key_generation_edge_cases() {
2111        // 测试空字符串
2112        let empty_app_key = app_access_token_key("");
2113        assert!(empty_app_key.contains(APP_ACCESS_TOKEN_KEY_PREFIX));
2114
2115        let empty_tenant_key = tenant_access_token_key("", "");
2116        assert!(empty_tenant_key.contains(APP_ACCESS_TOKEN_KEY_PREFIX));
2117
2118        // 测试非常长的字符串
2119        let long_app_id = "a".repeat(1000);
2120        let long_tenant_key = "b".repeat(1000);
2121
2122        let long_app_key = app_access_token_key(&long_app_id);
2123        let long_tenant_cache_key = tenant_access_token_key(&long_app_id, &long_tenant_key);
2124
2125        assert!(long_app_key.len() > 1000);
2126        assert!(long_tenant_cache_key.len() > 2000);
2127        assert!(long_app_key.contains(&long_app_id));
2128        assert!(long_tenant_cache_key.contains(&long_tenant_key));
2129    }
2130
2131    #[tokio::test]
2132    async fn test_metrics_counter_overflow_safety() {
2133        let metrics = TokenMetrics::new();
2134
2135        // 测试接近u64最大值的计数器
2136        metrics
2137            .app_cache_hits
2138            .store(u64::MAX - 1, Ordering::Relaxed);
2139        metrics.app_cache_misses.store(1, Ordering::Relaxed);
2140
2141        // 验证hit rate计算在极值情况下不会panic
2142        let hit_rate = metrics.app_cache_hit_rate();
2143        assert!((0.0..=1.0).contains(&hit_rate));
2144
2145        // 测试fetch_add操作的溢出行为
2146        let old_value = metrics.app_cache_hits.fetch_add(1, Ordering::Relaxed);
2147        assert_eq!(old_value, u64::MAX - 1);
2148
2149        // 验证fetch_add操作完成(不验证具体溢出行为,因为实现依赖)
2150        let new_value = metrics.app_cache_hits.load(Ordering::Relaxed);
2151        assert!(new_value == u64::MAX || new_value == 0); // 允许饱和或wrapping行为
2152    }
2153
2154    #[tokio::test]
2155    async fn test_cache_token_with_special_expiry_values() {
2156        let manager = TokenManager::new();
2157
2158        // 测试使用EXPIRY_DELTA的正确性
2159        let successful_resp = AppAccessTokenResp {
2160            raw_response: crate::core::api_resp::RawResponse {
2161                code: 0,
2162                msg: "success".to_string(),
2163                err: None,
2164            },
2165            expire: 3600,
2166            app_access_token: "expiry_test_token".to_string(),
2167        };
2168
2169        let result = manager
2170            .handle_app_access_token_response(successful_resp, "expiry_app")
2171            .await;
2172        assert!(result.is_ok());
2173
2174        // 验证缓存中的token过期时间已经减去了EXPIRY_DELTA
2175        let cache = manager.cache.read().await;
2176        if let Some(entry) = cache.get_with_expiry(&app_access_token_key("expiry_app")) {
2177            // 过期时间应该是 3600 - EXPIRY_DELTA
2178            let expected_expiry = 3600 - EXPIRY_DELTA;
2179            assert!(entry.expiry_seconds() <= expected_expiry as u64);
2180        }
2181    }
2182}