use mcp_gmailcal::{
config::Config,
token_cache::{TokenCache, TokenCacheConfig},
errors::GmailApiError,
};
use std::{env, fs, path::PathBuf, time::{Duration, SystemTime}};
use tempfile::tempdir;
use tokio::test;
fn test_encryption_key() -> Vec<u8> {
vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]
}
#[test]
async fn test_token_cache_save_load() {
let temp_dir = tempdir().unwrap();
let cache_file_path = temp_dir.path().join("token_cache_test.json");
let config = TokenCacheConfig {
enabled: true,
cache_file_path: cache_file_path.clone(),
encryption_key: test_encryption_key(),
};
let token_cache = TokenCache::new(config).unwrap();
let access_token = "test_access_token";
let refresh_token = "test_refresh_token";
let expiry = SystemTime::now().checked_add(Duration::from_secs(3600)).unwrap();
token_cache.save_token(access_token, refresh_token, expiry).unwrap();
assert!(cache_file_path.exists());
let loaded_token = token_cache.load_token().unwrap().unwrap();
assert_eq!(loaded_token.access_token, access_token);
assert_eq!(loaded_token.refresh_token, refresh_token);
temp_dir.close().unwrap();
}
#[test]
async fn test_token_cache_encryption() {
let temp_dir = tempdir().unwrap();
let cache_file_path = temp_dir.path().join("token_cache_encryption_test.json");
let config = TokenCacheConfig {
enabled: true,
cache_file_path: cache_file_path.clone(),
encryption_key: test_encryption_key(),
};
let access_token = "secret_access_token";
let refresh_token = "secret_refresh_token";
let expiry = SystemTime::now().checked_add(Duration::from_secs(3600)).unwrap();
let token_cache = TokenCache::new(config.clone()).unwrap();
token_cache.save_token(access_token, refresh_token, expiry).unwrap();
let file_content = fs::read_to_string(&cache_file_path).unwrap();
assert!(!file_content.contains("secret_access_token"));
assert!(!file_content.contains("secret_refresh_token"));
let result = token_cache.load_token().unwrap();
assert!(result.is_some());
let loaded_token = result.unwrap();
assert_eq!(loaded_token.access_token, access_token);
let wrong_key = vec![32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1];
let config_wrong_key = TokenCacheConfig {
enabled: true,
cache_file_path: cache_file_path.clone(),
encryption_key: wrong_key,
};
let wrong_key_cache = TokenCache::new(config_wrong_key).unwrap();
let result = wrong_key_cache.load_token();
assert!(result.is_ok());
assert!(result.unwrap().is_none());
temp_dir.close().unwrap();
}
#[test]
async fn test_token_cache_disabled() {
let temp_dir = tempdir().unwrap();
let cache_file_path = temp_dir.path().join("disabled_cache_test.json");
let config = TokenCacheConfig {
enabled: false,
cache_file_path: cache_file_path.clone(),
encryption_key: test_encryption_key(),
};
let token_cache = TokenCache::new(config).unwrap();
token_cache.save_token("test_token", "test_refresh",
SystemTime::now().checked_add(Duration::from_secs(3600)).unwrap()).unwrap();
assert!(!cache_file_path.exists());
let result = token_cache.load_token();
assert!(result.is_ok());
assert!(result.unwrap().is_none());
temp_dir.close().unwrap();
}
#[test]
async fn test_token_cache_file_io_errors() {
if !cfg!(unix) {
return;
}
let invalid_path = PathBuf::from("/proc/invalid_dir/token_cache.json");
let config = TokenCacheConfig {
enabled: true,
cache_file_path: invalid_path,
encryption_key: test_encryption_key(),
};
let result = TokenCache::new(config);
if result.is_err() {
assert!(matches!(result, Err(GmailApiError::CacheError(_))));
return;
}
let token_cache = result.unwrap();
let save_result = token_cache.save_token("test", "test", SystemTime::now());
assert!(matches!(save_result, Err(GmailApiError::CacheError(_))));
}
#[test]
async fn test_token_cache_invalid_key() {
let temp_dir = tempdir().unwrap();
let cache_file_path = temp_dir.path().join("invalid_key_test.json");
let config = TokenCacheConfig {
enabled: true,
cache_file_path,
encryption_key: vec![1, 2, 3], };
let result = TokenCache::new(config);
assert!(result.is_err());
assert!(matches!(result, Err(GmailApiError::CacheError(_))));
temp_dir.close().unwrap();
}
#[test]
async fn test_token_manager_integration_with_cache() {
let temp_dir = tempdir().unwrap();
let cache_file_path = temp_dir.path().join("token_manager_test.json");
let cache_path_str = cache_file_path.to_str().unwrap();
env::set_var("TOKEN_CACHE_ENABLED", "true");
env::set_var("TOKEN_CACHE_FILE", cache_path_str);
env::set_var("TOKEN_CACHE_ENCRYPTION_KEY", "12345678901234567890123456789012");
let config = Config {
client_id: "test_client_id".to_string(),
client_secret: "test_client_secret".to_string(),
refresh_token: "test_refresh_token".to_string(),
access_token: Some("test_access_token".to_string()),
token_refresh_threshold: 300,
token_expiry_buffer: 60,
};
let cache_config = TokenCacheConfig::from_env().unwrap();
let token_cache = TokenCache::new(cache_config).unwrap();
token_cache.save_token(
&config.access_token.clone().unwrap_or_default(),
&config.refresh_token,
SystemTime::now() + Duration::from_secs(3600)
).unwrap();
assert!(cache_file_path.exists(), "Cache file should exist at {}", cache_path_str);
env::remove_var("TOKEN_CACHE_ENABLED");
env::remove_var("TOKEN_CACHE_FILE");
env::remove_var("TOKEN_CACHE_ENCRYPTION_KEY");
temp_dir.close().unwrap();
}
#[test]
async fn test_token_cache_from_env() {
}