1use std::collections::HashMap;
194use std::sync::{Arc, OnceLock};
195use std::time::{Duration, Instant};
196
197use parking_lot::{Mutex, RwLock};
198use serde::de::DeserializeOwned;
199use serde::Serialize;
200
201use sz_rust_orm_facade::{Cache as InnerCache, CacheError, MemoryCache};
202
203mod memcached;
205pub use memcached::{
206 MemcachedBackend, MemcachedCacheDriver, MemcachedConfig, MockMemcachedBackend,
207};
208
209static GLOBAL_CACHE: OnceLock<Cache> = OnceLock::new();
219
220pub fn default_cache() -> &'static Cache {
238 GLOBAL_CACHE.get_or_init(Cache::new)
239}
240
241pub fn init_default_cache(driver: MemoryCacheDriver) {
254 let cache = default_cache();
255 cache.register_default(driver);
256}
257
258#[derive(Debug, Clone, PartialEq)]
273pub enum CacheValue {
274 Number(String),
278 Json(String),
282}
283
284impl CacheValue {
285 pub fn to_bytes(&self) -> Vec<u8> {
289 match self {
290 CacheValue::Number(s) => s.as_bytes().to_vec(),
291 CacheValue::Json(s) => s.as_bytes().to_vec(),
292 }
293 }
294
295 pub fn from_bytes(bytes: &[u8]) -> Result<CacheValue, CacheError> {
301 let s = std::str::from_utf8(bytes)
302 .map_err(|e| CacheError::DeserializationError(e.to_string()))?;
303 if php_is_numeric(s) {
304 Ok(CacheValue::Number(s.to_string()))
305 } else {
306 Ok(CacheValue::Json(s.to_string()))
307 }
308 }
309
310 pub fn is_number(&self) -> bool {
312 matches!(self, CacheValue::Number(_))
313 }
314}
315
316pub fn php_is_numeric(s: &str) -> bool {
347 if s.is_empty() {
348 return false;
349 }
350 if s.parse::<i64>().is_ok() {
352 return true;
353 }
354 if s.parse::<f64>().is_ok() {
356 return true;
357 }
358 false
361}
362
363pub fn php_serialize<T: Serialize>(value: &T) -> Result<CacheValue, CacheError> {
377 let json =
380 serde_json::to_string(value).map_err(|e| CacheError::SerializationError(e.to_string()))?;
381
382 if php_is_numeric(&json) {
386 Ok(CacheValue::Number(json))
387 } else {
388 Ok(CacheValue::Json(json))
389 }
390}
391
392pub fn php_unserialize<T: DeserializeOwned>(value: &CacheValue) -> Result<Option<T>, CacheError> {
406 match value {
407 CacheValue::Number(s) => {
408 serde_json::from_str::<T>(&format!("\"{}\"", s))
411 .map(Some)
412 .map_err(|e| CacheError::DeserializationError(e.to_string()))
413 }
414 CacheValue::Json(s) => serde_json::from_str::<T>(s)
415 .map(Some)
416 .map_err(|e| CacheError::DeserializationError(e.to_string())),
417 }
418}
419
420pub trait CacheDriver: Send + Sync {
441 fn get_raw(&self, key: &str) -> Result<Option<Vec<u8>>, CacheError>;
443
444 fn set_raw(&self, key: &str, value: Vec<u8>, ttl: Option<Duration>) -> Result<(), CacheError>;
446
447 fn delete(&self, key: &str) -> Result<(), CacheError>;
449
450 fn has(&self, key: &str) -> Result<bool, CacheError>;
452
453 fn inc(&self, key: &str, step: i64) -> Result<i64, CacheError> {
464 let current = match self.get_raw(key)? {
465 Some(bytes) => {
466 let s = std::str::from_utf8(&bytes)
467 .map_err(|e| CacheError::DeserializationError(e.to_string()))?;
468 s.parse::<i64>().map_err(|e| {
469 CacheError::DeserializationError(format!("inc: parse {} failed: {}", s, e))
470 })?
471 }
472 None => 0,
473 };
474 let new_value = current + step;
475 self.set_raw(key, new_value.to_string().into_bytes(), None)?;
476 Ok(new_value)
477 }
478
479 fn dec(&self, key: &str, step: i64) -> Result<i64, CacheError> {
483 self.inc(key, -step)
484 }
485
486 fn clear(&self) -> Result<(), CacheError>;
488
489 fn get_cache_key(&self, name: &str) -> String {
503 name.to_string()
504 }
505
506 fn get_tag_key(&self, tag: &str) -> String {
515 format!("tag:{}", compute_md5(tag))
516 }
517
518 fn tag_append(&self, tag_key: &str, cache_key: &str) -> Result<(), CacheError> {
555 let storage_key = self.get_cache_key(tag_key);
556 let mut items: Vec<String> = match self.get_raw(&storage_key)? {
558 Some(bytes) => serde_json::from_slice(&bytes)
559 .map_err(|e| CacheError::DeserializationError(format!("tag_append: {}", e)))?,
560 None => Vec::new(),
561 };
562 items.push(cache_key.to_string());
564 while items.len() > 1000 {
566 items.remove(0);
567 }
568 let mut seen = HashSet::new();
570 items.retain(|item| seen.insert(item.clone()));
571 let serialized = serde_json::to_vec(&items)
573 .map_err(|e| CacheError::SerializationError(e.to_string()))?;
574 self.set_raw(&storage_key, serialized, None)
575 }
576
577 fn tag_items(&self, tag: &str) -> Result<Vec<String>, CacheError> {
596 let tag_key = self.get_tag_key(tag);
597 let storage_key = self.get_cache_key(&tag_key);
598 match self.get_raw(&storage_key)? {
599 Some(bytes) => {
600 let items: Vec<String> = serde_json::from_slice(&bytes)
601 .map_err(|e| CacheError::DeserializationError(format!("tag_items: {}", e)))?;
602 Ok(items)
603 }
604 None => Ok(Vec::new()),
605 }
606 }
607
608 fn tag_clear(&self, keys: &[String]) -> Result<(), CacheError> {
626 for key in keys {
627 let _ = self.delete(key);
628 }
629 Ok(())
630 }
631}
632
633pub struct MemoryCacheDriver {
652 inner: MemoryCache,
653}
654
655impl MemoryCacheDriver {
656 pub fn new() -> Self {
658 Self {
659 inner: MemoryCache::new(),
660 }
661 }
662
663 pub fn with_default_ttl(ttl: Duration) -> Self {
665 Self {
666 inner: MemoryCache::with_ttl(ttl),
667 }
668 }
669}
670
671impl Default for MemoryCacheDriver {
672 fn default() -> Self {
673 Self::new()
674 }
675}
676
677impl CacheDriver for MemoryCacheDriver {
678 fn get_raw(&self, key: &str) -> Result<Option<Vec<u8>>, CacheError> {
679 InnerCache::get(&self.inner, key)
680 }
681
682 fn set_raw(&self, key: &str, value: Vec<u8>, ttl: Option<Duration>) -> Result<(), CacheError> {
683 InnerCache::set(&self.inner, key, value, ttl)
684 }
685
686 fn delete(&self, key: &str) -> Result<(), CacheError> {
687 InnerCache::delete(&self.inner, key)
688 }
689
690 fn has(&self, key: &str) -> Result<bool, CacheError> {
691 InnerCache::exists(&self.inner, key)
692 }
693
694 fn clear(&self) -> Result<(), CacheError> {
695 InnerCache::clear(&self.inner)
696 }
697}
698
699pub struct CacheManager {
719 default: String,
721 stores: HashMap<String, Box<dyn CacheDriver>>,
723}
724
725impl CacheManager {
726 pub fn new() -> Self {
728 Self {
729 default: String::new(),
730 stores: HashMap::new(),
731 }
732 }
733
734 pub fn register_store(&mut self, name: impl Into<String>, driver: Box<dyn CacheDriver>) {
743 let name = name.into();
744 if self.default.is_empty() {
745 self.default = name.clone();
746 }
747 self.stores.insert(name, driver);
748 }
749
750 pub fn set_default(&mut self, name: impl Into<String>) -> Result<(), CacheError> {
754 let name = name.into();
755 if !self.stores.contains_key(&name) {
756 return Err(CacheError::NotFound(format!(
757 "cache store '{}' not registered",
758 name
759 )));
760 }
761 self.default = name;
762 Ok(())
763 }
764
765 pub fn store(&self, name: &str) -> Result<&dyn CacheDriver, CacheError> {
769 self.stores
770 .get(name)
771 .map(|d| d.as_ref())
772 .ok_or_else(|| CacheError::NotFound(format!("cache store '{}' not found", name)))
773 }
774
775 pub fn default_store(&self) -> Result<&dyn CacheDriver, CacheError> {
779 if self.default.is_empty() {
780 return Err(CacheError::NotFound(
781 "no default cache store registered".to_string(),
782 ));
783 }
784 self.store(&self.default)
785 }
786}
787
788impl Default for CacheManager {
789 fn default() -> Self {
790 Self::new()
791 }
792}
793
794pub struct Cache {
823 manager: RwLock<CacheManager>,
824 remember_lock_poll_interval: Duration,
826 remember_lock_timeout: Duration,
827 inflight: Mutex<HashMap<String, Arc<Mutex<()>>>>,
830}
831
832impl Cache {
833 pub fn new() -> Self {
835 Self {
836 manager: RwLock::new(CacheManager::new()),
837 remember_lock_poll_interval: Duration::from_millis(200),
838 remember_lock_timeout: Duration::from_secs(5),
839 inflight: Mutex::new(HashMap::new()),
840 }
841 }
842
843 pub fn register_default(&self, driver: MemoryCacheDriver) {
847 let mut mgr = self.manager.write();
848 mgr.register_store("default", Box::new(driver));
849 }
850
851 pub fn register_store(&self, name: impl Into<String>, driver: Box<dyn CacheDriver>) {
853 let mut mgr = self.manager.write();
854 mgr.register_store(name, driver);
855 }
856
857 pub fn set_default_store(&self, name: impl Into<String>) -> Result<(), CacheError> {
859 let mut mgr = self.manager.write();
860 mgr.set_default(name)
861 }
862
863 #[tracing::instrument(skip(self, value))]
889 pub fn set<T: Serialize>(
890 &self,
891 key: &str,
892 value: T,
893 ttl: Option<Duration>,
894 ) -> Result<(), CacheError> {
895 let cache_value = php_serialize(&value)?;
896 let bytes = cache_value.to_bytes();
897 let mgr = self.manager.read();
898 let driver = mgr.default_store()?;
899 driver.set_raw(key, bytes, ttl)
900 }
901
902 #[tracing::instrument(skip(self))]
938 pub fn get<T: DeserializeOwned>(&self, key: &str) -> Result<Option<T>, CacheError> {
939 let mgr = self.manager.read();
940 let driver = mgr.default_store()?;
941 match driver.get_raw(key)? {
942 None => Ok(None),
943 Some(bytes) => {
944 let cache_value = CacheValue::from_bytes(&bytes)?;
945 php_unserialize(&cache_value)
946 }
947 }
948 }
949
950 pub fn get_or<T: DeserializeOwned>(&self, key: &str, default: T) -> Result<T, CacheError> {
952 match self.get::<T>(key)? {
953 Some(v) => Ok(v),
954 None => Ok(default),
955 }
956 }
957
958 fn get_weak<T: DeserializeOwned>(&self, key: &str) -> Result<Option<T>, CacheError> {
976 match self.get::<T>(key) {
977 Ok(v) => Ok(v),
978 Err(CacheError::DeserializationError(_)) => {
979 match self.get::<String>(key) {
982 Ok(Some(s)) => serde_json::from_str::<T>(&s)
983 .map(Some)
984 .map_err(|e| CacheError::DeserializationError(e.to_string())),
985 Ok(None) => Ok(None),
986 Err(e) => Err(e),
987 }
988 }
989 Err(e) => Err(e),
990 }
991 }
992
993 #[tracing::instrument(skip(self))]
995 pub fn delete(&self, key: &str) -> Result<(), CacheError> {
996 let mgr = self.manager.read();
997 let driver = mgr.default_store()?;
998 driver.delete(key)
999 }
1000
1001 pub fn has(&self, key: &str) -> Result<bool, CacheError> {
1016 let mgr = self.manager.read();
1017 let driver = mgr.default_store()?;
1018 driver.has(key)
1019 }
1020
1021 pub fn inc(&self, key: &str, step: i64) -> Result<i64, CacheError> {
1031 let mgr = self.manager.read();
1032 let driver = mgr.default_store()?;
1033 driver.inc(key, step)
1034 }
1035
1036 pub fn dec(&self, key: &str, step: i64) -> Result<i64, CacheError> {
1038 let mgr = self.manager.read();
1039 let driver = mgr.default_store()?;
1040 driver.dec(key, step)
1041 }
1042
1043 pub fn increment(&self, key: &str) -> Result<i64, CacheError> {
1045 self.inc(key, 1)
1046 }
1047
1048 pub fn decrement(&self, key: &str) -> Result<i64, CacheError> {
1050 self.dec(key, 1)
1051 }
1052
1053 pub fn pull<T: DeserializeOwned>(&self, key: &str) -> Result<Option<T>, CacheError> {
1066 let value = self.get::<T>(key)?;
1067 if value.is_some() {
1068 self.delete(key)?;
1069 }
1070 Ok(value)
1071 }
1072
1073 pub fn push<T: Serialize + DeserializeOwned + PartialEq + Clone>(
1102 &self,
1103 key: &str,
1104 value: T,
1105 ttl: Option<Duration>,
1106 ) -> Result<(), CacheError> {
1107 let mut data: Vec<T> = match self.get::<Vec<T>>(key) {
1110 Ok(Some(v)) => v,
1111 Ok(None) => Vec::new(),
1112 Err(_) => Vec::new(),
1113 };
1114 data.push(value);
1115
1116 while data.len() > 1000 {
1118 data.remove(0);
1119 }
1120
1121 let mut seen = std::collections::HashSet::new();
1123 data.retain(|item| seen.insert(item.hashable_string()));
1124
1125 self.set(key, data, ttl)
1126 }
1127
1128 #[tracing::instrument(skip(self, callback))]
1167 pub async fn remember<T, F>(
1168 &self,
1169 key: &str,
1170 ttl: Option<Duration>,
1171 callback: F,
1172 ) -> Result<T, CacheError>
1173 where
1174 T: Serialize + DeserializeOwned,
1175 F: FnOnce() -> T,
1176 {
1177 if let Some(cached) = self.get_weak::<T>(key)? {
1179 return Ok(cached);
1180 }
1181
1182 let lock_key = format!("{}_lock", key);
1184
1185 if self.has(&lock_key)? {
1187 let start = Instant::now();
1189 while self.has(&lock_key)? {
1190 if start.elapsed() >= self.remember_lock_timeout {
1191 return Ok(callback());
1193 }
1194 tokio::time::sleep(self.remember_lock_poll_interval).await;
1195 }
1196
1197 if let Some(cached) = self.get_weak::<T>(key)? {
1199 return Ok(cached);
1200 }
1201 }
1202
1203 self.set(&lock_key, 1i64, None)?;
1205
1206 let result = callback();
1208 let _ = self.set(key, &result, ttl);
1209
1210 let _ = self.delete(&lock_key);
1212
1213 Ok(result)
1214 }
1215
1216 pub async fn remember_async<T, F, Fut>(
1245 &self,
1246 key: &str,
1247 ttl: Option<Duration>,
1248 callback: F,
1249 ) -> Result<T, CacheError>
1250 where
1251 T: Serialize + DeserializeOwned + Clone,
1252 F: FnOnce() -> Fut,
1253 Fut: std::future::Future<Output = T>,
1254 {
1255 if let Some(cached) = self.get_weak::<T>(key)? {
1257 return Ok(cached);
1258 }
1259
1260 let lock_key = format!("{}_lock", key);
1262
1263 if self.has(&lock_key)? {
1265 let start = Instant::now();
1267 while self.has(&lock_key)? {
1268 if start.elapsed() >= self.remember_lock_timeout {
1269 let result = callback().await;
1271 let _ = self.set(key, &result, ttl);
1272 return Ok(result);
1273 }
1274 tokio::time::sleep(self.remember_lock_poll_interval).await;
1275 }
1276
1277 if let Some(cached) = self.get_weak::<T>(key)? {
1279 return Ok(cached);
1280 }
1281 }
1282
1283 self.set(&lock_key, 1i64, None)?;
1285
1286 let result = callback().await;
1288 let _ = self.set(key, &result, ttl);
1289
1290 let _ = self.delete(&lock_key);
1292
1293 Ok(result)
1294 }
1295
1296 #[tracing::instrument(skip(self))]
1298 pub fn clear(&self) -> Result<(), CacheError> {
1299 let mgr = self.manager.read();
1300 let driver = mgr.default_store()?;
1301 driver.clear()
1302 }
1303
1304 pub fn delete_many(&self, keys: &[&str]) -> Result<(), CacheError> {
1349 let mgr = self.manager.read();
1350 let driver = mgr.default_store()?;
1351 for key in keys {
1352 driver.delete(key)?;
1354 }
1355 Ok(())
1356 }
1357
1358 pub fn invalidate_after_write(&self, keys: &[&str]) -> Result<(), CacheError> {
1393 self.delete_many(keys)
1394 }
1395
1396 pub fn refresh<T, F>(
1433 &self,
1434 key: &str,
1435 ttl: Option<Duration>,
1436 fetcher: F,
1437 ) -> Result<T, CacheError>
1438 where
1439 T: Serialize + DeserializeOwned,
1440 F: FnOnce() -> Result<T, CacheError>,
1441 {
1442 self.delete(key)?;
1444
1445 let value = fetcher()?;
1447
1448 self.set(key, &value, ttl)?;
1450
1451 Ok(value)
1452 }
1453
1454 #[tracing::instrument(skip(self, fetcher))]
1490 pub fn fetch_singleflight<T, F>(
1491 &self,
1492 key: &str,
1493 ttl: Option<Duration>,
1494 fetcher: F,
1495 ) -> Result<T, CacheError>
1496 where
1497 T: Serialize + DeserializeOwned,
1498 F: FnOnce() -> Result<T, CacheError>,
1499 {
1500 if let Some(cached) = self.get::<T>(key)? {
1502 return Ok(cached);
1503 }
1504
1505 let mutex = {
1508 let mut inflight = self.inflight.lock();
1509 inflight
1510 .entry(key.to_string())
1511 .or_insert_with(|| Arc::new(Mutex::new(())))
1512 .clone()
1513 };
1514
1515 let _guard = mutex.lock();
1517
1518 if let Some(cached) = self.get::<T>(key)? {
1520 return Ok(cached);
1521 }
1522
1523 let value = fetcher()?;
1525 self.set(key, &value, ttl)?;
1526
1527 Ok(value)
1528 }
1529
1530 pub fn set_with_jitter<T>(
1549 &self,
1550 key: &str,
1551 value: &T,
1552 ttl: Option<Duration>,
1553 jitter: Duration,
1554 ) -> Result<(), CacheError>
1555 where
1556 T: Serialize + ?Sized,
1557 {
1558 let actual_ttl = match ttl {
1559 Some(t) if !jitter.is_zero() => {
1560 use rand::Rng;
1562 let jitter_nanos = jitter.as_nanos() as u64;
1563 let random_jitter =
1564 Duration::from_nanos(rand::thread_rng().gen_range(0..jitter_nanos));
1565 Some(t + random_jitter)
1566 }
1567 Some(t) => Some(t),
1568 None => None,
1569 };
1570 self.set(key, value, actual_ttl)
1571 }
1572
1573 #[tracing::instrument(skip(self, fetcher))]
1589 pub fn fetch_with_protection<T, F>(
1590 &self,
1591 key: &str,
1592 ttl: Option<Duration>,
1593 jitter: Duration,
1594 fetcher: F,
1595 ) -> Result<T, CacheError>
1596 where
1597 T: Serialize + DeserializeOwned,
1598 F: FnOnce() -> Result<T, CacheError>,
1599 {
1600 if let Some(cached) = self.get::<T>(key)? {
1602 return Ok(cached);
1603 }
1604
1605 let mutex = {
1607 let mut inflight = self.inflight.lock();
1608 inflight
1609 .entry(key.to_string())
1610 .or_insert_with(|| Arc::new(Mutex::new(())))
1611 .clone()
1612 };
1613
1614 let _guard = mutex.lock();
1616
1617 if let Some(cached) = self.get::<T>(key)? {
1619 return Ok(cached);
1620 }
1621
1622 let value = fetcher()?;
1624 self.set_with_jitter(key, &value, ttl, jitter)?;
1625
1626 Ok(value)
1627 }
1628
1629 pub fn with_store<R, F>(&self, name: &str, f: F) -> Result<R, CacheError>
1645 where
1646 F: FnOnce(&dyn CacheDriver) -> Result<R, CacheError>,
1647 {
1648 let mgr = self.manager.read();
1649 let driver = mgr.store(name)?;
1650 f(driver)
1651 }
1652
1653 pub fn tag(&self, name: &str) -> TagSet<'_> {
1685 TagSet {
1686 tags: vec![name.to_string()],
1687 cache: self,
1688 }
1689 }
1690
1691 pub fn tag_many(&self, names: &[&str]) -> TagSet<'_> {
1703 TagSet {
1704 tags: names.iter().map(|s| s.to_string()).collect(),
1705 cache: self,
1706 }
1707 }
1708}
1709
1710impl Default for Cache {
1711 fn default() -> Self {
1712 Self::new()
1713 }
1714}
1715
1716trait CloneHashable: Clone {
1725 fn hashable_string(&self) -> String;
1726}
1727
1728impl<T> CloneHashable for T
1729where
1730 T: Serialize + Clone,
1731{
1732 fn hashable_string(&self) -> String {
1733 serde_json::to_string(self).unwrap_or_default()
1734 }
1735}
1736
1737use md5::{Digest, Md5};
1761use std::collections::HashSet;
1762
1763#[derive(Clone)]
1782pub struct RedisConfig {
1783 pub host: String,
1785 pub port: u16,
1787 pub password: String,
1789 pub select: u32,
1791 pub timeout: Duration,
1793 pub expire: Option<Duration>,
1795 pub persistent: bool,
1797 pub prefix: String,
1799 pub tag_prefix: String,
1801 pub enable_tls: bool,
1803 pub tls_ca_cert_path: Option<String>,
1805}
1806
1807impl std::fmt::Debug for RedisConfig {
1808 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1809 f.debug_struct("RedisConfig")
1810 .field("host", &self.host)
1811 .field("port", &self.port)
1812 .field("password", &"[REDACTED]")
1813 .field("select", &self.select)
1814 .field("timeout", &self.timeout)
1815 .field("expire", &self.expire)
1816 .field("persistent", &self.persistent)
1817 .field("prefix", &self.prefix)
1818 .field("tag_prefix", &self.tag_prefix)
1819 .field("enable_tls", &self.enable_tls)
1820 .field("tls_ca_cert_path", &self.tls_ca_cert_path)
1821 .finish()
1822 }
1823}
1824
1825impl Default for RedisConfig {
1826 fn default() -> Self {
1827 Self {
1828 host: "127.0.0.1".to_string(),
1829 port: 6379,
1830 password: String::new(),
1831 select: 0,
1832 timeout: Duration::ZERO,
1833 expire: None,
1834 persistent: false,
1835 prefix: String::new(),
1836 tag_prefix: "tag:".to_string(),
1837 enable_tls: false,
1838 tls_ca_cert_path: None,
1839 }
1840 }
1841}
1842
1843impl RedisConfig {
1844 pub fn with_prefix(prefix: impl Into<String>) -> Self {
1846 Self {
1847 prefix: prefix.into(),
1848 ..Default::default()
1849 }
1850 }
1851
1852 pub fn with_expire(expire: Duration) -> Self {
1854 Self {
1855 expire: Some(expire),
1856 ..Default::default()
1857 }
1858 }
1859
1860 pub fn is_tls_enabled(&self) -> bool {
1862 self.enable_tls
1863 }
1864
1865 pub fn validate_production_tls(&self, env: &str) -> Result<(), String> {
1869 if env != "production" {
1870 return Ok(());
1871 }
1872 if !self.is_tls_enabled() {
1873 return Err("生产环境要求 Redis TLS 连接".to_string());
1874 }
1875 Ok(())
1876 }
1877}
1878
1879pub trait RedisBackend: Send + Sync {
1904 fn get(&self, key: &str) -> Result<Option<Vec<u8>>, CacheError>;
1906 fn set(&self, key: &str, value: Vec<u8>) -> Result<(), CacheError>;
1908 fn set_ex(&self, key: &str, value: Vec<u8>, ttl: Duration) -> Result<(), CacheError>;
1910 fn del(&self, key: &str) -> Result<i64, CacheError>;
1912 fn del_many(&self, keys: &[&str]) -> Result<i64, CacheError>;
1914 fn exists(&self, key: &str) -> Result<bool, CacheError>;
1916 fn incr_by(&self, key: &str, step: i64) -> Result<i64, CacheError>;
1918 fn decr_by(&self, key: &str, step: i64) -> Result<i64, CacheError>;
1920 fn flush_db(&self) -> Result<(), CacheError>;
1922 fn sadd(&self, key: &str, member: &str) -> Result<i64, CacheError>;
1924 fn smembers(&self, key: &str) -> Result<Vec<String>, CacheError>;
1926}
1927
1928pub struct MockRedisBackend {
1939 kv: parking_lot::RwLock<MockRedisKv>,
1941 sets: parking_lot::RwLock<MockRedisSets>,
1943}
1944
1945type MockRedisKv = HashMap<String, (Vec<u8>, Option<Instant>)>;
1947
1948type MockRedisSets = HashMap<String, HashSet<String>>;
1950
1951impl Default for MockRedisBackend {
1952 fn default() -> Self {
1953 Self::new()
1954 }
1955}
1956
1957impl MockRedisBackend {
1958 pub fn new() -> Self {
1960 Self {
1961 kv: parking_lot::RwLock::new(HashMap::new()),
1962 sets: parking_lot::RwLock::new(HashMap::new()),
1963 }
1964 }
1965
1966 fn is_expired(kv: &MockRedisKv, key: &str) -> bool {
1968 if let Some((_, Some(expires_at))) = kv.get(key) {
1969 return *expires_at <= Instant::now();
1970 }
1971 false
1972 }
1973}
1974
1975impl RedisBackend for MockRedisBackend {
1976 fn get(&self, key: &str) -> Result<Option<Vec<u8>>, CacheError> {
1977 let kv = self.kv.read();
1978 if Self::is_expired(&kv, key) {
1979 return Ok(None);
1980 }
1981 Ok(kv.get(key).map(|(v, _)| v.clone()))
1982 }
1983
1984 fn set(&self, key: &str, value: Vec<u8>) -> Result<(), CacheError> {
1985 let mut kv = self.kv.write();
1986 kv.insert(key.to_string(), (value, None));
1987 Ok(())
1988 }
1989
1990 fn set_ex(&self, key: &str, value: Vec<u8>, ttl: Duration) -> Result<(), CacheError> {
1991 let mut kv = self.kv.write();
1992 let expires_at = Some(Instant::now() + ttl);
1993 kv.insert(key.to_string(), (value, expires_at));
1994 Ok(())
1995 }
1996
1997 fn del(&self, key: &str) -> Result<i64, CacheError> {
1998 let mut kv = self.kv.write();
1999 let removed = kv.remove(key).is_some() as i64;
2000 let mut sets = self.sets.write();
2002 if sets.remove(key).is_some() && removed == 0 {
2003 return Ok(1);
2004 }
2005 Ok(removed)
2006 }
2007
2008 fn del_many(&self, keys: &[&str]) -> Result<i64, CacheError> {
2009 let mut count = 0i64;
2010 for key in keys {
2011 count += self.del(key)?;
2012 }
2013 Ok(count)
2014 }
2015
2016 fn exists(&self, key: &str) -> Result<bool, CacheError> {
2017 let kv = self.kv.read();
2018 if Self::is_expired(&kv, key) {
2019 return Ok(false);
2020 }
2021 if kv.contains_key(key) {
2022 return Ok(true);
2023 }
2024 let sets = self.sets.read();
2025 Ok(sets.contains_key(key))
2026 }
2027
2028 fn incr_by(&self, key: &str, step: i64) -> Result<i64, CacheError> {
2029 let mut kv = self.kv.write();
2030 if Self::is_expired(&kv, key) {
2032 kv.remove(key);
2033 }
2034 let current = match kv.get(key) {
2035 Some((bytes, _)) => {
2036 let s = std::str::from_utf8(bytes)
2037 .map_err(|e| CacheError::DeserializationError(e.to_string()))?;
2038 s.parse::<i64>().map_err(|e| {
2039 CacheError::Internal(format!("INCRBY failed: '{}' is not an integer: {}", s, e))
2040 })?
2041 }
2042 None => 0, };
2044 let new_value = current + step;
2045 kv.insert(key.to_string(), (new_value.to_string().into_bytes(), None));
2046 Ok(new_value)
2047 }
2048
2049 fn decr_by(&self, key: &str, step: i64) -> Result<i64, CacheError> {
2050 self.incr_by(key, -step)
2052 }
2053
2054 fn flush_db(&self) -> Result<(), CacheError> {
2055 let mut kv = self.kv.write();
2056 kv.clear();
2057 let mut sets = self.sets.write();
2058 sets.clear();
2059 Ok(())
2060 }
2061
2062 fn sadd(&self, key: &str, member: &str) -> Result<i64, CacheError> {
2063 let mut sets = self.sets.write();
2064 let set = sets.entry(key.to_string()).or_default();
2065 let added = set.insert(member.to_string()) as i64;
2066 Ok(added)
2067 }
2068
2069 fn smembers(&self, key: &str) -> Result<Vec<String>, CacheError> {
2070 let sets = self.sets.read();
2071 Ok(sets
2072 .get(key)
2073 .map(|s| s.iter().cloned().collect())
2074 .unwrap_or_default())
2075 }
2076}
2077
2078pub struct RedisCacheDriver {
2130 backend: Box<dyn RedisBackend>,
2131 config: RedisConfig,
2132}
2133
2134impl RedisCacheDriver {
2135 pub fn new(config: RedisConfig) -> Self {
2139 Self::with_backend(config, Box::new(MockRedisBackend::new()))
2140 }
2141
2142 pub fn with_backend(config: RedisConfig, backend: Box<dyn RedisBackend>) -> Self {
2146 Self { backend, config }
2147 }
2148
2149 pub fn config(&self) -> &RedisConfig {
2151 &self.config
2152 }
2153
2154 pub fn backend(&self) -> &dyn RedisBackend {
2156 self.backend.as_ref()
2157 }
2158
2159 pub fn append(&self, name: &str, value: &str) -> Result<(), CacheError> {
2173 let key = self.get_cache_key(name);
2174 self.backend.sadd(&key, value)?;
2175 Ok(())
2176 }
2177
2178 pub fn get_tag_items(&self, tag: &str) -> Result<Vec<String>, CacheError> {
2190 let name = self.get_tag_key(tag);
2191 let key = self.get_cache_key(&name);
2192 self.backend.smembers(&key)
2193 }
2194
2195 pub fn clear_tag(&self, keys: &[&str]) -> Result<(), CacheError> {
2205 self.backend.del_many(keys)?;
2206 Ok(())
2207 }
2208
2209 pub fn tag_key(&self, tag: &str) -> String {
2211 self.get_tag_key(tag)
2212 }
2213
2214 pub fn cache_key(&self, name: &str) -> String {
2216 self.get_cache_key(name)
2217 }
2218}
2219
2220impl CacheDriver for RedisCacheDriver {
2221 fn get_raw(&self, key: &str) -> Result<Option<Vec<u8>>, CacheError> {
2222 let cache_key = self.get_cache_key(key);
2223 self.backend.get(&cache_key)
2224 }
2225
2226 fn set_raw(&self, key: &str, value: Vec<u8>, ttl: Option<Duration>) -> Result<(), CacheError> {
2227 let cache_key = self.get_cache_key(key);
2228 let effective_ttl = ttl.or(self.config.expire);
2230 match effective_ttl {
2232 Some(t) if t > Duration::ZERO => self.backend.set_ex(&cache_key, value, t),
2233 _ => self.backend.set(&cache_key, value),
2234 }
2235 }
2236
2237 fn delete(&self, key: &str) -> Result<(), CacheError> {
2238 let cache_key = self.get_cache_key(key);
2239 self.backend.del(&cache_key)?;
2241 Ok(())
2242 }
2243
2244 fn has(&self, key: &str) -> Result<bool, CacheError> {
2245 let cache_key = self.get_cache_key(key);
2246 self.backend.exists(&cache_key)
2248 }
2249
2250 fn inc(&self, key: &str, step: i64) -> Result<i64, CacheError> {
2266 let cache_key = self.get_cache_key(key);
2267 self.backend.incr_by(&cache_key, step)
2268 }
2269
2270 fn dec(&self, key: &str, step: i64) -> Result<i64, CacheError> {
2272 let cache_key = self.get_cache_key(key);
2273 self.backend.decr_by(&cache_key, step)
2274 }
2275
2276 fn clear(&self) -> Result<(), CacheError> {
2277 self.backend.flush_db()
2279 }
2280
2281 fn get_cache_key(&self, name: &str) -> String {
2289 format!("{}{}", self.config.prefix, name)
2290 }
2291
2292 fn get_tag_key(&self, tag: &str) -> String {
2296 let md5_hex = compute_md5(tag);
2297 format!("{}{}", self.config.tag_prefix, md5_hex)
2298 }
2299
2300 fn tag_append(&self, tag_key: &str, cache_key: &str) -> Result<(), CacheError> {
2314 let key = self.get_cache_key(tag_key);
2315 self.backend.sadd(&key, cache_key)?;
2316 Ok(())
2317 }
2318
2319 fn tag_items(&self, tag: &str) -> Result<Vec<String>, CacheError> {
2331 let name = self.get_tag_key(tag);
2332 let key = self.get_cache_key(&name);
2333 self.backend.smembers(&key)
2334 }
2335
2336 fn tag_clear(&self, keys: &[String]) -> Result<(), CacheError> {
2349 let key_refs: Vec<&str> = keys.iter().map(|s| s.as_str()).collect();
2350 self.backend.del_many(&key_refs)?;
2351 Ok(())
2352 }
2353}
2354
2355pub(crate) fn compute_md5(s: &str) -> String {
2359 let mut hasher = Md5::new();
2360 hasher.update(s.as_bytes());
2361 let result = hasher.finalize();
2362 hex::encode(result)
2363}
2364
2365pub struct MultiLevelCacheDriver {
2395 inner: sz_rust_orm_facade::MultiLevelCache,
2396}
2397
2398impl Default for MultiLevelCacheDriver {
2399 fn default() -> Self {
2400 Self::new()
2401 }
2402}
2403
2404impl MultiLevelCacheDriver {
2405 pub fn new() -> Self {
2407 Self {
2408 inner: sz_rust_orm_facade::MultiLevelCache::new(),
2409 }
2410 }
2411
2412 pub fn add_level(mut self, cache: Box<dyn InnerCache>) -> Self {
2416 self.inner = self.inner.add_cache(cache);
2417 self
2418 }
2419
2420 pub fn inner(&self) -> &sz_rust_orm_facade::MultiLevelCache {
2422 &self.inner
2423 }
2424}
2425
2426impl CacheDriver for MultiLevelCacheDriver {
2427 fn get_raw(&self, key: &str) -> Result<Option<Vec<u8>>, CacheError> {
2428 self.inner.get(key)
2429 }
2430
2431 fn set_raw(&self, key: &str, value: Vec<u8>, ttl: Option<Duration>) -> Result<(), CacheError> {
2432 self.inner.set(key, value, ttl)
2433 }
2434
2435 fn delete(&self, key: &str) -> Result<(), CacheError> {
2436 self.inner.delete(key)
2437 }
2438
2439 fn has(&self, key: &str) -> Result<bool, CacheError> {
2440 self.inner.exists(key)
2441 }
2442
2443 fn inc(&self, key: &str, step: i64) -> Result<i64, CacheError> {
2444 let current = match self.inner.get(key)? {
2447 Some(bytes) => String::from_utf8(bytes)
2448 .map_err(|e| CacheError::DeserializationError(e.to_string()))?
2449 .parse::<i64>()
2450 .unwrap_or(0),
2451 None => 0,
2452 };
2453 let new_value = current + step;
2454 let new_bytes = new_value.to_string().into_bytes();
2455 let ttl = self.inner.ttl(key).ok().flatten();
2457 self.inner.set(key, new_bytes, ttl)?;
2458 Ok(new_value)
2459 }
2460
2461 fn dec(&self, key: &str, step: i64) -> Result<i64, CacheError> {
2462 let current = match self.inner.get(key)? {
2464 Some(bytes) => String::from_utf8(bytes)
2465 .map_err(|e| CacheError::DeserializationError(e.to_string()))?
2466 .parse::<i64>()
2467 .unwrap_or(0),
2468 None => 0,
2469 };
2470 let new_value = current - step;
2471 let new_bytes = new_value.to_string().into_bytes();
2472 let ttl = self.inner.ttl(key).ok().flatten();
2473 self.inner.set(key, new_bytes, ttl)?;
2474 Ok(new_value)
2475 }
2476
2477 fn clear(&self) -> Result<(), CacheError> {
2478 self.inner.clear()
2479 }
2480}
2481
2482pub struct TagSet<'a> {
2537 tags: Vec<String>,
2539 cache: &'a Cache,
2541}
2542
2543impl<'a> TagSet<'a> {
2544 pub fn set<T: Serialize>(
2556 &self,
2557 key: &str,
2558 value: T,
2559 ttl: Option<Duration>,
2560 ) -> Result<(), CacheError> {
2561 self.cache.set(key, value, ttl)?;
2563 self.append(key)
2565 }
2566
2567 pub fn append(&self, key: &str) -> Result<(), CacheError> {
2583 let mgr = self.cache.manager.read();
2584 let driver = mgr.default_store()?;
2585 let cache_key = driver.get_cache_key(key);
2587 for tag in &self.tags {
2589 let tag_key = driver.get_tag_key(tag);
2591 driver.tag_append(&tag_key, &cache_key)?;
2593 }
2594 Ok(())
2595 }
2596
2597 pub fn clear(&self) -> Result<(), CacheError> {
2616 let mgr = self.cache.manager.read();
2617 let driver = mgr.default_store()?;
2618 for tag in &self.tags {
2619 let items = driver.tag_items(tag)?;
2621 driver.tag_clear(&items)?;
2623 let tag_key = driver.get_tag_key(tag);
2625 driver.delete(&tag_key)?;
2627 }
2628 Ok(())
2629 }
2630
2631 pub fn tags(&self) -> &[String] {
2633 &self.tags
2634 }
2635}
2636
2637#[cfg(test)]
2642mod tests {
2643 use crate::*;
2644 use serde::Deserialize;
2645 use std::sync::Barrier;
2646
2647 fn make_cache() -> Cache {
2649 let cache = Cache::new();
2650 cache.register_default(MemoryCacheDriver::new());
2651 cache
2652 }
2653
2654 #[test]
2659 fn test_php_is_numeric_integer() {
2660 assert!(php_is_numeric("42"));
2662 assert!(php_is_numeric("-42"));
2663 assert!(php_is_numeric("+42"));
2664 assert!(php_is_numeric("0"));
2665 }
2666
2667 #[test]
2668 fn test_php_is_numeric_float() {
2669 assert!(php_is_numeric("3.14"));
2671 assert!(php_is_numeric("-3.14"));
2672 assert!(php_is_numeric("+3.14"));
2673 assert!(php_is_numeric("0.0"));
2674 }
2675
2676 #[test]
2677 fn test_php_is_numeric_scientific_notation() {
2678 assert!(php_is_numeric("1e10"));
2680 assert!(php_is_numeric("1.5E-3"));
2681 }
2682
2683 #[test]
2684 fn test_php_is_numeric_non_numeric() {
2685 assert!(!php_is_numeric("abc"));
2687 assert!(!php_is_numeric("12abc"));
2688 assert!(!php_is_numeric(""));
2689 assert!(!php_is_numeric("0x1A")); assert!(!php_is_numeric("null"));
2691 assert!(!php_is_numeric("true"));
2692 }
2693
2694 #[test]
2699 fn test_php_serialize_integer_to_number() {
2700 let v = php_serialize(&42i64).unwrap();
2702 assert!(matches!(v, CacheValue::Number(_)));
2703 if let CacheValue::Number(s) = v {
2704 assert_eq!(s, "42");
2705 }
2706 }
2707
2708 #[test]
2709 fn test_php_serialize_float_to_number() {
2710 let v = php_serialize(&2.5f64).unwrap();
2713 assert!(matches!(v, CacheValue::Number(_)));
2714 if let CacheValue::Number(s) = v {
2715 assert_eq!(s, "2.5");
2716 }
2717 }
2718
2719 #[test]
2720 fn test_php_serialize_string_to_json() {
2721 let v = php_serialize(&"Alice".to_string()).unwrap();
2724 assert!(matches!(v, CacheValue::Json(_)));
2725 if let CacheValue::Json(s) = v {
2726 assert_eq!(s, "\"Alice\"");
2727 }
2728 }
2729
2730 #[test]
2731 fn test_php_serialize_numeric_string_to_number() {
2732 let v = php_serialize(&"42".to_string()).unwrap();
2741 assert!(matches!(v, CacheValue::Json(_))); }
2743
2744 #[test]
2745 fn test_php_serialize_array_to_json() {
2746 let v = php_serialize(&vec![1, 2, 3]).unwrap();
2748 assert!(matches!(v, CacheValue::Json(_)));
2749 if let CacheValue::Json(s) = v {
2750 assert_eq!(s, "[1,2,3]");
2751 }
2752 }
2753
2754 #[test]
2755 fn test_php_unserialize_number_returns_string() {
2756 let v = CacheValue::Number("42".to_string());
2759 let result: Option<String> = php_unserialize(&v).unwrap();
2760 assert_eq!(result, Some("42".to_string()));
2761 }
2762
2763 #[test]
2764 fn test_php_unserialize_json_returns_struct() {
2765 let v = CacheValue::Json("\"Alice\"".to_string());
2767 let result: Option<String> = php_unserialize(&v).unwrap();
2768 assert_eq!(result, Some("Alice".to_string()));
2769
2770 let v = CacheValue::Json("[1,2,3]".to_string());
2771 let result: Option<Vec<i64>> = php_unserialize(&v).unwrap();
2772 assert_eq!(result, Some(vec![1, 2, 3]));
2773 }
2774
2775 #[test]
2776 fn test_php_unserialize_number_to_int_via_parse() {
2777 let v = CacheValue::Number("42".to_string());
2780 let s: String = php_unserialize(&v).unwrap().unwrap();
2781 let n: i64 = s.parse().unwrap();
2782 assert_eq!(n, 42);
2783 }
2784
2785 #[test]
2790 fn test_cache_value_number_roundtrip() {
2791 let v = CacheValue::Number("42".to_string());
2792 let bytes = v.to_bytes();
2793 let restored = CacheValue::from_bytes(&bytes).unwrap();
2794 assert_eq!(v, restored);
2795 }
2796
2797 #[test]
2798 fn test_cache_value_json_roundtrip() {
2799 let v = CacheValue::Json("\"Alice\"".to_string());
2800 let bytes = v.to_bytes();
2801 let restored = CacheValue::from_bytes(&bytes).unwrap();
2802 assert_eq!(v, restored);
2803 }
2804
2805 #[test]
2806 fn test_cache_value_array_roundtrip() {
2807 let v = CacheValue::Json("[1,2,3]".to_string());
2808 let bytes = v.to_bytes();
2809 let restored = CacheValue::from_bytes(&bytes).unwrap();
2810 assert_eq!(v, restored);
2811 }
2812
2813 #[test]
2814 fn test_cache_value_from_bytes_numeric_string_becomes_number() {
2815 let bytes = b"42".to_vec();
2817 let v = CacheValue::from_bytes(&bytes).unwrap();
2818 assert!(matches!(v, CacheValue::Number(_)));
2819 }
2820
2821 #[test]
2822 fn test_cache_value_from_bytes_json_string_becomes_json() {
2823 let bytes = b"\"Alice\"".to_vec();
2825 let v = CacheValue::from_bytes(&bytes).unwrap();
2826 assert!(matches!(v, CacheValue::Json(_)));
2827 }
2828
2829 #[test]
2834 fn test_memory_driver_set_get_raw() {
2835 let driver = MemoryCacheDriver::new();
2836 driver.set_raw("key", b"value".to_vec(), None).unwrap();
2837 let val = driver.get_raw("key").unwrap();
2838 assert_eq!(val, Some(b"value".to_vec()));
2839 }
2840
2841 #[test]
2842 fn test_memory_driver_delete() {
2843 let driver = MemoryCacheDriver::new();
2844 driver.set_raw("key", b"value".to_vec(), None).unwrap();
2845 driver.delete("key").unwrap();
2846 let val = driver.get_raw("key").unwrap();
2847 assert_eq!(val, None);
2848 }
2849
2850 #[test]
2851 fn test_memory_driver_has() {
2852 let driver = MemoryCacheDriver::new();
2853 driver.set_raw("key", b"value".to_vec(), None).unwrap();
2854 assert!(driver.has("key").unwrap());
2855 assert!(!driver.has("nonexistent").unwrap());
2856 }
2857
2858 #[test]
2859 fn test_memory_driver_clear() {
2860 let driver = MemoryCacheDriver::new();
2861 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
2862 driver.set_raw("key2", b"value2".to_vec(), None).unwrap();
2863 driver.clear().unwrap();
2864 assert!(!driver.has("key1").unwrap());
2865 assert!(!driver.has("key2").unwrap());
2866 }
2867
2868 #[test]
2869 fn test_memory_driver_ttl_expiration() {
2870 let driver = MemoryCacheDriver::new();
2871 driver
2872 .set_raw("key", b"value".to_vec(), Some(Duration::from_millis(50)))
2873 .unwrap();
2874 assert!(driver.get_raw("key").unwrap().is_some());
2875 std::thread::sleep(Duration::from_millis(100));
2876 assert!(driver.get_raw("key").unwrap().is_none());
2877 }
2878
2879 #[test]
2880 fn test_memory_driver_inc_default_implementation() {
2881 let driver = MemoryCacheDriver::new();
2883
2884 let v = driver.inc("counter", 5).unwrap();
2886 assert_eq!(v, 5);
2887
2888 let v = driver.inc("counter", 3).unwrap();
2890 assert_eq!(v, 8);
2891 }
2892
2893 #[test]
2894 fn test_memory_driver_dec_default_implementation() {
2895 let driver = MemoryCacheDriver::new();
2896
2897 let v = driver.dec("counter", 3).unwrap();
2899 assert_eq!(v, -3);
2900
2901 let v = driver.dec("counter", 2).unwrap();
2903 assert_eq!(v, -5);
2904 }
2905
2906 #[test]
2911 fn test_cache_manager_register_and_get_default() {
2912 let mut mgr = CacheManager::new();
2913 mgr.register_store("default", Box::new(MemoryCacheDriver::new()));
2914
2915 let driver = mgr.default_store().unwrap();
2916 driver.set_raw("key", b"value".to_vec(), None).unwrap();
2917 assert_eq!(driver.get_raw("key").unwrap(), Some(b"value".to_vec()));
2918 }
2919
2920 #[test]
2921 fn test_cache_manager_multiple_stores_isolation() {
2922 let mut mgr = CacheManager::new();
2923 mgr.register_store("file", Box::new(MemoryCacheDriver::new()));
2924 mgr.register_store("redis", Box::new(MemoryCacheDriver::new()));
2925
2926 let file_driver = mgr.store("file").unwrap();
2927 let redis_driver = mgr.store("redis").unwrap();
2928
2929 file_driver
2930 .set_raw("key", b"file_value".to_vec(), None)
2931 .unwrap();
2932 redis_driver
2933 .set_raw("key", b"redis_value".to_vec(), None)
2934 .unwrap();
2935
2936 assert_eq!(
2938 file_driver.get_raw("key").unwrap(),
2939 Some(b"file_value".to_vec())
2940 );
2941 assert_eq!(
2942 redis_driver.get_raw("key").unwrap(),
2943 Some(b"redis_value".to_vec())
2944 );
2945 }
2946
2947 #[test]
2948 fn test_cache_manager_set_default() {
2949 let mut mgr = CacheManager::new();
2950 mgr.register_store("file", Box::new(MemoryCacheDriver::new()));
2951 mgr.register_store("redis", Box::new(MemoryCacheDriver::new()));
2952
2953 let driver = mgr.default_store().unwrap();
2955 driver.set_raw("file_key", b"file".to_vec(), None).unwrap();
2956 assert_eq!(driver.get_raw("file_key").unwrap(), Some(b"file".to_vec()));
2957
2958 mgr.set_default("redis").unwrap();
2960 let driver = mgr.default_store().unwrap();
2961 driver
2962 .set_raw("redis_key", b"redis".to_vec(), None)
2963 .unwrap();
2964 assert_eq!(
2965 driver.get_raw("redis_key").unwrap(),
2966 Some(b"redis".to_vec())
2967 );
2968 }
2969
2970 #[test]
2971 fn test_cache_manager_default_store_not_registered_error() {
2972 let mgr = CacheManager::new();
2973 let result = mgr.default_store();
2974 assert!(matches!(result, Err(CacheError::NotFound(_))));
2975 }
2976
2977 #[test]
2978 fn test_cache_manager_store_not_found_error() {
2979 let mgr = CacheManager::new();
2980 let result = mgr.store("nonexistent");
2981 assert!(matches!(result, Err(CacheError::NotFound(_))));
2982 }
2983
2984 #[test]
2989 fn test_cache_set_get_string() {
2990 let cache = make_cache();
2991 cache.set("name", "Alice", None).unwrap();
2992 let val: Option<String> = cache.get("name").unwrap();
2993 assert_eq!(val, Some("Alice".to_string()));
2994 }
2995
2996 #[test]
2997 fn test_cache_set_get_int_as_string_php_bug() {
2998 let cache = make_cache();
3001 cache.set("count", 42i64, None).unwrap();
3002
3003 let s: Option<String> = cache.get("count").unwrap();
3006 assert_eq!(s, Some("42".to_string()));
3007
3008 let n: i64 = s.unwrap().parse().unwrap();
3009 assert_eq!(n, 42);
3010 }
3011
3012 #[test]
3013 fn test_cache_set_get_struct() {
3014 #[derive(Serialize, Deserialize, PartialEq, Debug)]
3015 struct User {
3016 name: String,
3017 age: u32,
3018 }
3019
3020 let cache = make_cache();
3021 let user = User {
3022 name: "Alice".to_string(),
3023 age: 30,
3024 };
3025 cache.set("user:1", &user, None).unwrap();
3026
3027 let val: Option<User> = cache.get("user:1").unwrap();
3028 assert_eq!(val, Some(user));
3029 }
3030
3031 #[test]
3032 fn test_cache_set_get_vec() {
3033 let cache = make_cache();
3034 let list = vec![1, 2, 3];
3035 cache.set("list", &list, None).unwrap();
3036
3037 let val: Option<Vec<i64>> = cache.get("list").unwrap();
3038 assert_eq!(val, Some(vec![1, 2, 3]));
3039 }
3040
3041 #[test]
3042 fn test_cache_get_miss_returns_none() {
3043 let cache = make_cache();
3044 let val: Option<String> = cache.get("nonexistent").unwrap();
3045 assert_eq!(val, None);
3046 }
3047
3048 #[test]
3049 fn test_cache_get_or_default_value() {
3050 let cache = make_cache();
3051 let val: String = cache.get_or("nonexistent", "default".to_string()).unwrap();
3052 assert_eq!(val, "default");
3053 }
3054
3055 #[test]
3056 fn test_cache_set_with_ttl_expires() {
3057 let cache = make_cache();
3058 cache
3059 .set("key", "value", Some(Duration::from_millis(50)))
3060 .unwrap();
3061 assert!(cache.get::<String>("key").unwrap().is_some());
3062 std::thread::sleep(Duration::from_millis(100));
3063 assert!(cache.get::<String>("key").unwrap().is_none());
3064 }
3065
3066 #[test]
3071 fn test_cache_delete() {
3072 let cache = make_cache();
3073 cache.set("key", "value", None).unwrap();
3074 assert!(cache.has("key").unwrap());
3075
3076 cache.delete("key").unwrap();
3077 assert!(!cache.has("key").unwrap());
3078
3079 cache.delete("nonexistent").unwrap();
3081 }
3082
3083 #[test]
3084 fn test_cache_has_checks_ttl() {
3085 let cache = make_cache();
3086 cache
3087 .set("key", "value", Some(Duration::from_millis(50)))
3088 .unwrap();
3089 assert!(cache.has("key").unwrap());
3090
3091 std::thread::sleep(Duration::from_millis(100));
3092 assert!(!cache.has("key").unwrap());
3094 }
3095
3096 #[test]
3097 fn test_cache_clear() {
3098 let cache = make_cache();
3099 cache.set("key1", "value1", None).unwrap();
3100 cache.set("key2", "value2", None).unwrap();
3101
3102 cache.clear().unwrap();
3103
3104 assert!(!cache.has("key1").unwrap());
3105 assert!(!cache.has("key2").unwrap());
3106 }
3107
3108 #[test]
3113 fn test_cache_inc_initial_value() {
3114 let cache = make_cache();
3116 let v = cache.inc("counter", 5).unwrap();
3117 assert_eq!(v, 5);
3118
3119 let s: String = cache.get("counter").unwrap().unwrap();
3121 assert_eq!(s, "5");
3122 }
3123
3124 #[test]
3125 fn test_cache_inc_accumulate() {
3126 let cache = make_cache();
3127 cache.inc("counter", 5).unwrap();
3128 cache.inc("counter", 3).unwrap();
3129 let v = cache.inc("counter", 2).unwrap();
3130 assert_eq!(v, 10);
3131 }
3132
3133 #[test]
3134 fn test_cache_dec_initial_value() {
3135 let cache = make_cache();
3137 let v = cache.dec("counter", 3).unwrap();
3138 assert_eq!(v, -3);
3139 }
3140
3141 #[test]
3142 fn test_cache_dec_accumulate() {
3143 let cache = make_cache();
3144 cache.set("counter", 100i64, None).unwrap();
3145 cache.dec("counter", 30).unwrap();
3146 let v = cache.dec("counter", 20).unwrap();
3147 assert_eq!(v, 50);
3148 }
3149
3150 #[test]
3151 fn test_cache_increment_default_step_1() {
3152 let cache = make_cache();
3153 let v = cache.increment("counter").unwrap();
3154 assert_eq!(v, 1);
3155 let v = cache.increment("counter").unwrap();
3156 assert_eq!(v, 2);
3157 }
3158
3159 #[test]
3160 fn test_cache_decrement_default_step_1() {
3161 let cache = make_cache();
3162 let v = cache.decrement("counter").unwrap();
3163 assert_eq!(v, -1);
3164 let v = cache.decrement("counter").unwrap();
3165 assert_eq!(v, -2);
3166 }
3167
3168 #[test]
3173 fn test_cache_pull_existing_key() {
3174 let cache = make_cache();
3176 cache.set("key", "value", None).unwrap();
3177
3178 let val: Option<String> = cache.pull("key").unwrap();
3179 assert_eq!(val, Some("value".to_string()));
3180
3181 assert!(!cache.has("key").unwrap());
3183 }
3184
3185 #[test]
3186 fn test_cache_pull_missing_key_returns_none() {
3187 let cache = make_cache();
3188 let val: Option<String> = cache.pull("nonexistent").unwrap();
3189 assert_eq!(val, None);
3190 }
3191
3192 #[test]
3197 fn test_cache_push_initial_array() {
3198 let cache = make_cache();
3199 cache.push("list", "a".to_string(), None).unwrap();
3200
3201 let val: Option<Vec<String>> = cache.get("list").unwrap();
3202 assert_eq!(val, Some(vec!["a".to_string()]));
3203 }
3204
3205 #[test]
3206 fn test_cache_push_appends() {
3207 let cache = make_cache();
3208 cache.push("list", "a".to_string(), None).unwrap();
3209 cache.push("list", "b".to_string(), None).unwrap();
3210 cache.push("list", "c".to_string(), None).unwrap();
3211
3212 let val: Option<Vec<String>> = cache.get("list").unwrap();
3213 assert_eq!(
3214 val,
3215 Some(vec!["a".to_string(), "b".to_string(), "c".to_string()])
3216 );
3217 }
3218
3219 #[test]
3220 fn test_cache_push_deduplication() {
3221 let cache = make_cache();
3223 cache.push("list", "a".to_string(), None).unwrap();
3224 cache.push("list", "b".to_string(), None).unwrap();
3225 cache.push("list", "a".to_string(), None).unwrap(); cache.push("list", "c".to_string(), None).unwrap();
3227 cache.push("list", "b".to_string(), None).unwrap(); let val: Option<Vec<String>> = cache.get("list").unwrap();
3230 assert_eq!(
3231 val,
3232 Some(vec!["a".to_string(), "b".to_string(), "c".to_string()])
3233 );
3234 }
3235
3236 #[test]
3237 fn test_cache_push_max_1000_fifo() {
3238 let cache = make_cache();
3240
3241 for i in 0..1001i64 {
3243 cache.push("list", i, None).unwrap();
3244 }
3245
3246 let val: Option<Vec<i64>> = cache.get("list").unwrap();
3247 let list = val.unwrap();
3248
3249 assert_eq!(list.len(), 1000);
3251 assert_eq!(list[0], 1);
3253 assert_eq!(list[999], 1000);
3255 }
3256
3257 #[test]
3258 fn test_cache_push_non_array_becomes_array() {
3259 let cache = make_cache();
3261
3262 cache.set("key", "not_an_array".to_string(), None).unwrap();
3264
3265 cache.push("key", "first".to_string(), None).unwrap();
3267
3268 let val: Option<Vec<String>> = cache.get("key").unwrap();
3269 assert_eq!(val, Some(vec!["first".to_string()]));
3270 }
3271
3272 #[tokio::test]
3277 async fn test_cache_remember_cache_miss() {
3278 let cache = make_cache();
3280 let counter = std::sync::Arc::new(std::sync::atomic::AtomicU32::new(0));
3281 let counter_clone = counter.clone();
3282
3283 let val: i64 = cache
3284 .remember("expensive", None, || {
3285 counter_clone.fetch_add(1, std::sync::atomic::Ordering::SeqCst) as i64 + 100
3286 })
3287 .await
3288 .unwrap();
3289 assert_eq!(val, 100);
3290
3291 let val: i64 = cache
3293 .remember("expensive", None, || {
3294 counter_clone.fetch_add(1, std::sync::atomic::Ordering::SeqCst) as i64 + 200
3295 })
3296 .await
3297 .unwrap();
3298 assert_eq!(val, 100); assert_eq!(counter.load(std::sync::atomic::Ordering::SeqCst), 1);
3302 }
3303
3304 #[tokio::test]
3305 async fn test_cache_remember_cache_hit_returns_cached() {
3306 let cache = make_cache();
3307 cache.set("predefined", 42i64, None).unwrap();
3308
3309 let val: i64 = cache
3311 .remember("predefined", None, || {
3312 panic!("callback should not be called on cache hit");
3313 })
3314 .await
3315 .unwrap();
3316 assert_eq!(val, 42);
3317 }
3318
3319 #[tokio::test]
3320 async fn test_cache_remember_writes_with_ttl() {
3321 let cache = make_cache();
3322 cache
3323 .remember("key", Some(Duration::from_millis(50)), || 42i64)
3324 .await
3325 .unwrap();
3326
3327 assert_eq!(cache.get::<String>("key").unwrap(), Some("42".to_string()));
3329
3330 tokio::time::sleep(Duration::from_millis(100)).await;
3332 assert!(cache.get::<String>("key").unwrap().is_none());
3333 }
3334
3335 #[tokio::test]
3336 async fn test_cache_remember_releases_lock_on_success() {
3337 let cache = make_cache();
3339 cache.remember("key", None, || 42i64).await.unwrap();
3340
3341 assert!(!cache.has("key_lock").unwrap());
3343 }
3344
3345 #[tokio::test]
3346 async fn test_cache_remember_releases_lock_on_panic() {
3347 let cache = make_cache();
3353 let _ = cache.remember("key", None, || 42i64).await;
3354 assert!(!cache.has("key_lock").unwrap());
3355 }
3356
3357 #[tokio::test]
3358 async fn test_cache_remember_lock_has_no_ttl_php_bug() {
3359 let cache = make_cache();
3366 cache.remember("key", None, || 42i64).await.unwrap();
3367 assert!(!cache.has("key_lock").unwrap());
3368 }
3369
3370 #[tokio::test]
3371 async fn test_cache_remember_async_cache_miss() {
3372 let cache = make_cache();
3374 let counter = std::sync::Arc::new(std::sync::atomic::AtomicU32::new(0));
3375 let counter_clone = counter.clone();
3376
3377 let val: i64 = cache
3378 .remember_async("expensive_async", None, || {
3379 let counter_clone = counter_clone.clone();
3380 async move {
3381 counter_clone.fetch_add(1, std::sync::atomic::Ordering::SeqCst) as i64 + 100
3382 }
3383 })
3384 .await
3385 .unwrap();
3386 assert_eq!(val, 100);
3387
3388 let val: i64 = cache
3390 .remember_async("expensive_async", None, || {
3391 let counter_clone = counter_clone.clone();
3392 async move {
3393 counter_clone.fetch_add(1, std::sync::atomic::Ordering::SeqCst) as i64 + 200
3394 }
3395 })
3396 .await
3397 .unwrap();
3398 assert_eq!(val, 100);
3399
3400 assert_eq!(counter.load(std::sync::atomic::Ordering::SeqCst), 1);
3401 }
3402
3403 #[tokio::test]
3404 async fn test_cache_remember_async_cache_hit_returns_cached() {
3405 let cache = make_cache();
3406 cache.set("predefined_async", 42i64, None).unwrap();
3407
3408 let val: i64 = cache
3409 .remember_async("predefined_async", None, || async {
3410 panic!("callback should not be called on cache hit");
3411 })
3412 .await
3413 .unwrap();
3414 assert_eq!(val, 42);
3415 }
3416
3417 #[tokio::test]
3418 async fn test_cache_remember_async_writes_with_ttl() {
3419 let cache = make_cache();
3420 cache
3421 .remember_async("key_async", Some(Duration::from_millis(50)), || async {
3422 42i64
3423 })
3424 .await
3425 .unwrap();
3426
3427 assert_eq!(
3428 cache.get::<String>("key_async").unwrap(),
3429 Some("42".to_string())
3430 );
3431
3432 tokio::time::sleep(Duration::from_millis(100)).await;
3433 assert!(cache.get::<String>("key_async").unwrap().is_none());
3434 }
3435
3436 #[tokio::test]
3437 async fn test_cache_remember_async_releases_lock_on_success() {
3438 let cache = make_cache();
3439 cache
3440 .remember_async("key_async", None, || async { 42i64 })
3441 .await
3442 .unwrap();
3443 assert!(!cache.has("key_async_lock").unwrap());
3444 }
3445
3446 #[tokio::test]
3447 async fn test_cache_remember_async_lock_has_no_ttl_php_bug() {
3448 let cache = make_cache();
3449 cache
3450 .remember_async("key_async", None, || async { 42i64 })
3451 .await
3452 .unwrap();
3453 assert!(!cache.has("key_async_lock").unwrap());
3454 }
3455
3456 #[test]
3461 fn test_cache_with_store() {
3462 let cache = Cache::new();
3463 cache.register_store("redis", Box::new(MemoryCacheDriver::new()));
3464
3465 let result = cache
3466 .with_store("redis", |driver| {
3467 driver.set_raw("key", b"value".to_vec(), None)?;
3468 driver.get_raw("key")
3469 })
3470 .unwrap();
3471
3472 assert_eq!(result, Some(b"value".to_vec()));
3473 }
3474
3475 #[test]
3476 fn test_cache_with_store_not_found() {
3477 let cache = Cache::new();
3478 let result: Result<Option<Vec<u8>>, CacheError> =
3479 cache.with_store("nonexistent", |driver| driver.get_raw("key"));
3480 assert!(matches!(result, Err(CacheError::NotFound(_))));
3481 }
3482
3483 #[test]
3488 fn test_default_cache_singleton() {
3489 let c1 = default_cache();
3490 let c2 = default_cache();
3491 assert!(std::ptr::eq(c1, c2));
3493 }
3494
3495 #[test]
3503 fn test_r5_php_set_get_basic_alignment() {
3504 let cache = make_cache();
3509 cache.set("name", "Alice", None).unwrap();
3510 let val: String = cache.get("name").unwrap().unwrap();
3511 assert_eq!(val, "Alice");
3512 }
3513
3514 #[test]
3515 fn test_r5_php_is_numeric_short_circuit() {
3516 let cache = make_cache();
3521 cache.set("count", 42i64, None).unwrap();
3522
3523 let s: String = cache.get("count").unwrap().unwrap();
3525 assert_eq!(s, "42");
3526 }
3527
3528 #[test]
3529 fn test_r5_php_inc_no_serialize() {
3530 let cache = make_cache();
3533 cache.set("counter", 100i64, None).unwrap();
3534 let new_val = cache.inc("counter", 50).unwrap();
3535 assert_eq!(new_val, 150);
3536
3537 let s: String = cache.get("counter").unwrap().unwrap();
3539 assert_eq!(s, "150");
3540 }
3541
3542 #[test]
3543 fn test_r5_php_dec_no_serialize() {
3544 let cache = make_cache();
3546 cache.set("counter", 100i64, None).unwrap();
3547 let new_val = cache.dec("counter", 30).unwrap();
3548 assert_eq!(new_val, 70);
3549 }
3550
3551 #[tokio::test]
3552 async fn test_r5_php_remember_lock_mechanism() {
3553 let cache = make_cache();
3556 let val: i64 = cache.remember("key", None, || 42).await.unwrap();
3557 assert_eq!(val, 42);
3558 assert_eq!(cache.get::<String>("key").unwrap(), Some("42".to_string()));
3559 assert!(!cache.has("key_lock").unwrap());
3561 }
3562
3563 #[test]
3564 fn test_r5_php_push_max_1000_array_shift() {
3565 let cache = make_cache();
3567 for i in 0..1001i64 {
3568 cache.push("list", i, None).unwrap();
3569 }
3570 let list: Vec<i64> = cache.get("list").unwrap().unwrap();
3571 assert_eq!(list.len(), 1000);
3572 assert_eq!(list[0], 1); assert_eq!(list[999], 1000);
3574 }
3575
3576 #[test]
3577 fn test_r5_php_push_array_unique() {
3578 let cache = make_cache();
3580 cache.push("list", "a".to_string(), None).unwrap();
3581 cache.push("list", "a".to_string(), None).unwrap();
3582 cache.push("list", "b".to_string(), None).unwrap();
3583 cache.push("list", "a".to_string(), None).unwrap();
3584
3585 let list: Vec<String> = cache.get("list").unwrap().unwrap();
3586 assert_eq!(list, vec!["a".to_string(), "b".to_string()]);
3587 }
3588
3589 #[test]
3590 fn test_r5_php_pull_get_then_delete() {
3591 let cache = make_cache();
3593 cache.set("key", "value", None).unwrap();
3594
3595 let val: Option<String> = cache.pull("key").unwrap();
3596 assert_eq!(val, Some("value".to_string()));
3597 assert!(!cache.has("key").unwrap());
3598 }
3599
3600 #[test]
3601 fn test_r5_php_delete_nonexistent_no_error() {
3602 let cache = make_cache();
3604 let result = cache.delete("nonexistent");
3605 assert!(result.is_ok());
3606 }
3607
3608 #[test]
3609 fn test_r5_php_has_ttl_expiration() {
3610 let cache = make_cache();
3612 cache
3613 .set("key", "value", Some(Duration::from_millis(50)))
3614 .unwrap();
3615 assert!(cache.has("key").unwrap());
3616
3617 std::thread::sleep(Duration::from_millis(100));
3618 assert!(!cache.has("key").unwrap());
3619 }
3620
3621 #[test]
3622 fn test_r5_php_clear_all_keys() {
3623 let cache = make_cache();
3625 cache.set("key1", "value1", None).unwrap();
3626 cache.set("key2", "value2", None).unwrap();
3627 cache.set("key3", "value3", None).unwrap();
3628
3629 cache.clear().unwrap();
3630
3631 assert!(!cache.has("key1").unwrap());
3632 assert!(!cache.has("key2").unwrap());
3633 assert!(!cache.has("key3").unwrap());
3634 }
3635
3636 #[test]
3641 fn test_php_bug_unserialize_numeric_returns_string() {
3642 let cache = make_cache();
3655
3656 cache.set("count", 42i64, None).unwrap();
3658
3659 let s: String = cache.get("count").unwrap().unwrap();
3661 assert_eq!(s, "42");
3662
3663 let n: i64 = s.parse().unwrap();
3665 assert_eq!(n, 42);
3666 }
3667
3668 #[tokio::test]
3669 async fn test_php_bug_remember_lock_no_ttl() {
3670 let cache = make_cache();
3678 cache.remember("key", None, || 42i64).await.unwrap();
3679 assert!(!cache.has("key_lock").unwrap());
3681 }
3682
3683 #[tokio::test]
3684 async fn test_php_bug_remember_has_get_double_check() {
3685 let cache = make_cache();
3702 let val: i64 = cache.remember("key", None, || 42).await.unwrap();
3703 assert_eq!(val, 42);
3704 }
3705
3706 #[test]
3707 fn test_php_behavior_set_overwrite() {
3708 let cache = make_cache();
3710 cache.set("key", "first", None).unwrap();
3711 cache.set("key", "second", None).unwrap();
3712
3713 let val: String = cache.get("key").unwrap().unwrap();
3714 assert_eq!(val, "second");
3715 }
3716
3717 #[test]
3718 fn test_php_behavior_ttl_permanent() {
3719 let cache = make_cache();
3721 cache.set("key", "value", None).unwrap();
3722
3723 assert!(cache.has("key").unwrap());
3725
3726 std::thread::sleep(Duration::from_millis(50));
3728 assert!(cache.has("key").unwrap());
3729 }
3730
3731 #[test]
3736 fn test_redis_config_default() {
3737 let config = RedisConfig::default();
3739 assert_eq!(config.host, "127.0.0.1");
3740 assert_eq!(config.port, 6379);
3741 assert_eq!(config.password, "");
3742 assert_eq!(config.select, 0);
3743 assert_eq!(config.timeout, Duration::ZERO);
3744 assert_eq!(config.expire, None);
3745 assert!(!config.persistent);
3746 assert_eq!(config.prefix, "");
3747 assert_eq!(config.tag_prefix, "tag:");
3748 }
3749
3750 #[test]
3751 fn test_redis_config_with_prefix() {
3752 let config = RedisConfig::with_prefix("myapp:");
3753 assert_eq!(config.prefix, "myapp:");
3754 assert_eq!(config.host, "127.0.0.1");
3755 assert_eq!(config.tag_prefix, "tag:");
3756 }
3757
3758 #[test]
3759 fn test_redis_config_with_expire() {
3760 let config = RedisConfig::with_expire(Duration::from_secs(3600));
3761 assert_eq!(config.expire, Some(Duration::from_secs(3600)));
3762 assert_eq!(config.prefix, "");
3763 }
3764
3765 #[test]
3770 fn test_mock_redis_set_get_roundtrip() {
3771 let backend = MockRedisBackend::new();
3772 backend.set("key1", b"value1".to_vec()).unwrap();
3773 let val = backend.get("key1").unwrap();
3774 assert_eq!(val, Some(b"value1".to_vec()));
3775 }
3776
3777 #[test]
3778 fn test_mock_redis_del() {
3779 let backend = MockRedisBackend::new();
3780 backend.set("key1", b"value1".to_vec()).unwrap();
3781 let removed = backend.del("key1").unwrap();
3782 assert_eq!(removed, 1);
3783 assert_eq!(backend.get("key1").unwrap(), None);
3784 assert_eq!(backend.del("key1").unwrap(), 0);
3786 }
3787
3788 #[test]
3789 fn test_mock_redis_exists() {
3790 let backend = MockRedisBackend::new();
3791 assert!(!backend.exists("key1").unwrap());
3792 backend.set("key1", b"value1".to_vec()).unwrap();
3793 assert!(backend.exists("key1").unwrap());
3794 }
3795
3796 #[test]
3797 fn test_mock_redis_incr_by_new_key() {
3798 let backend = MockRedisBackend::new();
3800 let result = backend.incr_by("counter", 5).unwrap();
3801 assert_eq!(result, 5);
3802 let val = backend.get("counter").unwrap();
3804 assert_eq!(val, Some(b"5".to_vec()));
3805 }
3806
3807 #[test]
3808 fn test_mock_redis_incr_by_existing_key() {
3809 let backend = MockRedisBackend::new();
3810 backend.set("counter", b"10".to_vec()).unwrap();
3811 let result = backend.incr_by("counter", 5).unwrap();
3812 assert_eq!(result, 15);
3813 let val = backend.get("counter").unwrap();
3814 assert_eq!(val, Some(b"15".to_vec()));
3815 }
3816
3817 #[test]
3818 fn test_mock_redis_incr_by_non_integer_error() {
3819 let backend = MockRedisBackend::new();
3821 backend.set("key", b"not_a_number".to_vec()).unwrap();
3822 let result = backend.incr_by("key", 1);
3823 assert!(result.is_err());
3824 }
3825
3826 #[test]
3827 fn test_mock_redis_decr_by() {
3828 let backend = MockRedisBackend::new();
3829 let result = backend.decr_by("counter", 3).unwrap();
3830 assert_eq!(result, -3);
3831 }
3832
3833 #[test]
3838 fn test_mock_redis_set_ex_and_expire() {
3839 let backend = MockRedisBackend::new();
3840 backend
3841 .set_ex("key1", b"value1".to_vec(), Duration::from_millis(50))
3842 .unwrap();
3843 assert!(backend.get("key1").unwrap().is_some());
3844 std::thread::sleep(Duration::from_millis(80));
3845 assert_eq!(backend.get("key1").unwrap(), None);
3846 }
3847
3848 #[test]
3849 fn test_mock_redis_expired_key_exists_false() {
3850 let backend = MockRedisBackend::new();
3851 backend
3852 .set_ex("key1", b"value1".to_vec(), Duration::from_millis(50))
3853 .unwrap();
3854 assert!(backend.exists("key1").unwrap());
3855 std::thread::sleep(Duration::from_millis(80));
3856 assert!(!backend.exists("key1").unwrap());
3857 }
3858
3859 #[test]
3864 fn test_mock_redis_sadd_smembers() {
3865 let backend = MockRedisBackend::new();
3866 backend.sadd("tag:users", "user:1").unwrap();
3867 backend.sadd("tag:users", "user:2").unwrap();
3868 backend.sadd("tag:users", "user:3").unwrap();
3869 let members = backend.smembers("tag:users").unwrap();
3870 assert_eq!(members.len(), 3);
3871 assert!(members.contains(&"user:1".to_string()));
3872 assert!(members.contains(&"user:2".to_string()));
3873 assert!(members.contains(&"user:3".to_string()));
3874 }
3875
3876 #[test]
3877 fn test_mock_redis_sadd_dedup() {
3878 let backend = MockRedisBackend::new();
3880 let added1 = backend.sadd("tag:users", "user:1").unwrap();
3881 assert_eq!(added1, 1);
3882 let added2 = backend.sadd("tag:users", "user:1").unwrap();
3883 assert_eq!(added2, 0);
3884 let members = backend.smembers("tag:users").unwrap();
3885 assert_eq!(members.len(), 1);
3886 }
3887
3888 #[test]
3889 fn test_mock_redis_smembers_nonexistent_key() {
3890 let backend = MockRedisBackend::new();
3892 let members = backend.smembers("nonexistent").unwrap();
3893 assert!(members.is_empty());
3894 }
3895
3896 #[test]
3901 fn test_mock_redis_flush_db() {
3902 let backend = MockRedisBackend::new();
3903 backend.set("key1", b"v1".to_vec()).unwrap();
3904 backend.set("key2", b"v2".to_vec()).unwrap();
3905 backend.sadd("tag:1", "m1").unwrap();
3906 backend.flush_db().unwrap();
3907 assert_eq!(backend.get("key1").unwrap(), None);
3908 assert_eq!(backend.get("key2").unwrap(), None);
3909 assert!(backend.smembers("tag:1").unwrap().is_empty());
3910 }
3911
3912 #[test]
3913 fn test_mock_redis_del_many() {
3914 let backend = MockRedisBackend::new();
3915 backend.set("key1", b"v1".to_vec()).unwrap();
3916 backend.set("key2", b"v2".to_vec()).unwrap();
3917 backend.set("key3", b"v3".to_vec()).unwrap();
3918 let removed = backend.del_many(&["key1", "key2", "nonexistent"]).unwrap();
3919 assert_eq!(removed, 2);
3920 assert_eq!(backend.get("key1").unwrap(), None);
3921 assert_eq!(backend.get("key2").unwrap(), None);
3922 assert!(backend.get("key3").unwrap().is_some());
3923 }
3924
3925 fn make_redis_driver() -> RedisCacheDriver {
3931 RedisCacheDriver::new(RedisConfig::default())
3932 }
3933
3934 #[test]
3935 fn test_redis_driver_set_get_roundtrip() {
3936 let driver = make_redis_driver();
3937 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
3938 let val = driver.get_raw("key1").unwrap();
3939 assert_eq!(val, Some(b"value1".to_vec()));
3940 }
3941
3942 #[test]
3943 fn test_redis_driver_delete() {
3944 let driver = make_redis_driver();
3945 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
3946 driver.delete("key1").unwrap();
3947 assert_eq!(driver.get_raw("key1").unwrap(), None);
3948 }
3949
3950 #[test]
3951 fn test_redis_driver_has() {
3952 let driver = make_redis_driver();
3953 assert!(!driver.has("key1").unwrap());
3954 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
3955 assert!(driver.has("key1").unwrap());
3956 }
3957
3958 #[test]
3959 fn test_redis_driver_clear() {
3960 let driver = make_redis_driver();
3961 driver.set_raw("key1", b"v1".to_vec(), None).unwrap();
3962 driver.set_raw("key2", b"v2".to_vec(), None).unwrap();
3963 driver.clear().unwrap();
3964 assert_eq!(driver.get_raw("key1").unwrap(), None);
3965 assert_eq!(driver.get_raw("key2").unwrap(), None);
3966 }
3967
3968 #[test]
3969 fn test_redis_driver_inc_dec() {
3970 let driver = make_redis_driver();
3971 let result = driver.inc("counter", 5).unwrap();
3973 assert_eq!(result, 5);
3974 let result = driver.inc("counter", 3).unwrap();
3975 assert_eq!(result, 8);
3976 let result = driver.dec("counter", 2).unwrap();
3977 assert_eq!(result, 6);
3978 }
3979
3980 #[test]
3985 fn test_redis_driver_cache_key_with_prefix() {
3986 let driver = RedisCacheDriver::new(RedisConfig::with_prefix("myapp:"));
3988 assert_eq!(driver.cache_key("user:1"), "myapp:user:1");
3989 }
3990
3991 #[test]
3992 fn test_redis_driver_cache_key_no_prefix() {
3993 let driver = RedisCacheDriver::new(RedisConfig::default());
3994 assert_eq!(driver.cache_key("user:1"), "user:1");
3995 }
3996
3997 #[test]
3998 fn test_redis_driver_tag_key_md5() {
3999 let driver = RedisCacheDriver::new(RedisConfig::default());
4001 let tag_key = driver.tag_key("users");
4002 let expected_md5 = compute_md5("users");
4003 assert_eq!(tag_key, format!("tag:{}", expected_md5));
4004 }
4005
4006 #[test]
4007 fn test_redis_driver_tag_key_custom_prefix() {
4008 let config = RedisConfig {
4009 tag_prefix: "t:".to_string(),
4010 ..RedisConfig::default()
4011 };
4012 let driver = RedisCacheDriver::new(config);
4013 let tag_key = driver.tag_key("users");
4014 let expected_md5 = compute_md5("users");
4015 assert_eq!(tag_key, format!("t:{}", expected_md5));
4016 }
4017
4018 #[test]
4023 fn test_redis_driver_prefix_applied_to_set() {
4024 let driver = RedisCacheDriver::new(RedisConfig::with_prefix("myapp:"));
4026 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
4027 let val = driver.backend().get("myapp:key1").unwrap();
4029 assert_eq!(val, Some(b"value1".to_vec()));
4030 assert_eq!(driver.backend().get("key1").unwrap(), None);
4032 }
4033
4034 #[test]
4035 fn test_redis_driver_prefix_applied_to_get() {
4036 let driver = RedisCacheDriver::new(RedisConfig::with_prefix("myapp:"));
4037 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
4038 let val = driver.get_raw("key1").unwrap();
4039 assert_eq!(val, Some(b"value1".to_vec()));
4040 }
4041
4042 #[test]
4043 fn test_redis_driver_prefix_applied_to_delete() {
4044 let driver = RedisCacheDriver::new(RedisConfig::with_prefix("myapp:"));
4045 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
4046 driver.delete("key1").unwrap();
4047 assert_eq!(driver.backend().get("myapp:key1").unwrap(), None);
4048 }
4049
4050 #[test]
4051 fn test_redis_driver_prefix_applied_to_has() {
4052 let driver = RedisCacheDriver::new(RedisConfig::with_prefix("myapp:"));
4053 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
4054 assert!(driver.has("key1").unwrap());
4055 assert!(driver.backend().exists("myapp:key1").unwrap());
4056 }
4057
4058 #[test]
4059 fn test_redis_driver_prefix_applied_to_inc() {
4060 let driver = RedisCacheDriver::new(RedisConfig::with_prefix("myapp:"));
4061 let result = driver.inc("counter", 5).unwrap();
4062 assert_eq!(result, 5);
4063 let val = driver.backend().get("myapp:counter").unwrap();
4064 assert_eq!(val, Some(b"5".to_vec()));
4065 }
4066
4067 #[test]
4072 fn test_redis_driver_append_and_get_tag_items() {
4073 let driver = make_redis_driver();
4075 driver.append("tag:users", "user:1").unwrap();
4076 driver.append("tag:users", "user:2").unwrap();
4077 driver.append("tag:users", "user:3").unwrap();
4078 let members = driver.backend().smembers("tag:users").unwrap();
4079 assert_eq!(members.len(), 3);
4080 }
4081
4082 #[test]
4083 fn test_redis_driver_get_tag_items_with_tag_key() {
4084 let driver = make_redis_driver();
4086 let tag_name = driver.tag_key("users");
4087 driver.append(&tag_name, "user:1").unwrap();
4088 driver.append(&tag_name, "user:2").unwrap();
4089 let members = driver.get_tag_items("users").unwrap();
4090 assert_eq!(members.len(), 2);
4091 assert!(members.contains(&"user:1".to_string()));
4092 assert!(members.contains(&"user:2".to_string()));
4093 }
4094
4095 #[test]
4096 fn test_redis_driver_clear_tag() {
4097 let driver = make_redis_driver();
4098 driver.set_raw("key1", b"v1".to_vec(), None).unwrap();
4099 driver.set_raw("key2", b"v2".to_vec(), None).unwrap();
4100 driver.clear_tag(&["key1", "key2"]).unwrap();
4101 assert_eq!(driver.get_raw("key1").unwrap(), None);
4102 assert_eq!(driver.get_raw("key2").unwrap(), None);
4103 }
4104
4105 #[test]
4110 fn test_redis_driver_set_with_ttl_uses_setex() {
4111 let driver = make_redis_driver();
4113 driver
4114 .set_raw("key1", b"value1".to_vec(), Some(Duration::from_millis(100)))
4115 .unwrap();
4116 assert!(driver.get_raw("key1").unwrap().is_some());
4117 std::thread::sleep(Duration::from_millis(150));
4118 assert_eq!(driver.get_raw("key1").unwrap(), None);
4119 }
4120
4121 #[test]
4122 fn test_redis_driver_set_without_ttl_uses_set() {
4123 let driver = make_redis_driver();
4125 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
4126 std::thread::sleep(Duration::from_millis(50));
4127 assert!(driver.get_raw("key1").unwrap().is_some());
4128 }
4129
4130 #[test]
4131 fn test_redis_driver_set_with_config_expire() {
4132 let config = RedisConfig::with_expire(Duration::from_millis(100));
4134 let driver = RedisCacheDriver::new(config);
4135 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
4136 assert!(driver.get_raw("key1").unwrap().is_some());
4137 std::thread::sleep(Duration::from_millis(150));
4138 assert_eq!(driver.get_raw("key1").unwrap(), None);
4139 }
4140
4141 #[test]
4142 fn test_redis_driver_set_ttl_overrides_config_expire() {
4143 let config = RedisConfig::with_expire(Duration::from_secs(3600));
4145 let driver = RedisCacheDriver::new(config);
4146 driver
4147 .set_raw("key1", b"value1".to_vec(), Some(Duration::from_millis(50)))
4148 .unwrap();
4149 std::thread::sleep(Duration::from_millis(80));
4150 assert_eq!(driver.get_raw("key1").unwrap(), None);
4151 }
4152
4153 #[test]
4158 fn test_redis_driver_with_cache_facade() {
4159 let cache = Cache::new();
4161 let driver = RedisCacheDriver::new(RedisConfig::default());
4162 cache.register_store("redis", Box::new(driver));
4163 cache.set_default_store("redis").unwrap();
4164 cache.set("key", "value", None).unwrap();
4165 let val: String = cache.get("key").unwrap().unwrap();
4166 assert_eq!(val, "value");
4167 }
4168
4169 #[test]
4170 fn test_redis_driver_with_cache_facade_inc() {
4171 let cache = Cache::new();
4173 let driver = RedisCacheDriver::new(RedisConfig::default());
4174 cache.register_store("redis", Box::new(driver));
4175 cache.set_default_store("redis").unwrap();
4176 let result = cache.inc("counter", 5).unwrap();
4177 assert_eq!(result, 5);
4178 let result = cache.inc("counter", 3).unwrap();
4179 assert_eq!(result, 8);
4180 }
4181
4182 #[test]
4187 fn test_php_redis_inc_not_through_serialize() {
4188 let driver = make_redis_driver();
4193 driver.inc("counter", 5).unwrap();
4194 let val = driver.backend().get(&driver.cache_key("counter")).unwrap();
4195 assert_eq!(val, Some(b"5".to_vec())); assert_ne!(val, Some(b"i:5;".to_vec())); }
4198
4199 #[test]
4200 fn test_php_redis_set_with_ttl_expires() {
4201 let driver = make_redis_driver();
4203 driver
4204 .set_raw("key", b"value".to_vec(), Some(Duration::from_millis(50)))
4205 .unwrap();
4206 assert!(driver.get_raw("key").unwrap().is_some());
4207 std::thread::sleep(Duration::from_millis(80));
4208 assert_eq!(driver.get_raw("key").unwrap(), None);
4209 }
4210
4211 #[test]
4212 fn test_php_redis_set_without_ttl_permanent() {
4213 let driver = make_redis_driver();
4215 driver.set_raw("key", b"value".to_vec(), None).unwrap();
4216 std::thread::sleep(Duration::from_millis(50));
4217 assert!(driver.get_raw("key").unwrap().is_some());
4218 }
4219
4220 #[test]
4221 fn test_php_redis_tag_key_format() {
4222 let driver = make_redis_driver();
4224 let tag_key = driver.tag_key("users");
4225 let expected = format!("tag:{}", compute_md5("users"));
4226 assert_eq!(tag_key, expected);
4227 assert_eq!(compute_md5("users").len(), 32);
4228 }
4229
4230 #[test]
4231 fn test_php_redis_clear_uses_flushdb() {
4232 let driver = make_redis_driver();
4234 driver.set_raw("key1", b"v1".to_vec(), None).unwrap();
4235 driver.set_raw("key2", b"v2".to_vec(), None).unwrap();
4236 driver.append("tag:1", "m1").unwrap();
4237 driver.clear().unwrap();
4238 assert_eq!(driver.get_raw("key1").unwrap(), None);
4239 assert_eq!(driver.get_raw("key2").unwrap(), None);
4240 assert!(driver.backend().smembers("tag:1").unwrap().is_empty());
4241 }
4242
4243 #[test]
4244 fn test_php_redis_inc_returns_new_value() {
4245 let driver = make_redis_driver();
4247 let r1 = driver.inc("c", 1).unwrap();
4248 assert_eq!(r1, 1);
4249 let r2 = driver.inc("c", 1).unwrap();
4250 assert_eq!(r2, 2);
4251 let r3 = driver.inc("c", 10).unwrap();
4252 assert_eq!(r3, 12);
4253 let r4 = driver.dec("c", 5).unwrap();
4254 assert_eq!(r4, 7);
4255 }
4256
4257 #[test]
4258 fn test_php_redis_delete_nonexistent_returns_ok() {
4259 let driver = make_redis_driver();
4261 driver.delete("nonexistent").unwrap();
4262 }
4263
4264 #[test]
4265 fn test_php_redis_md5_alignment() {
4266 assert_eq!(compute_md5("hello"), "5d41402abc4b2a76b9719d911017c592");
4269 assert_eq!(compute_md5(""), "d41d8cd98f00b204e9800998ecf8427e");
4271 assert_eq!(compute_md5("users").len(), 32);
4272 }
4273
4274 #[test]
4275 fn test_php_redis_append_uses_sadd() {
4276 let driver = make_redis_driver();
4279 driver.append("tag:1", "m1").unwrap();
4280 driver.append("tag:1", "m1").unwrap(); driver.append("tag:1", "m2").unwrap();
4282 let members = driver.backend().smembers("tag:1").unwrap();
4283 assert_eq!(members.len(), 2);
4285 }
4286
4287 #[test]
4288 fn test_php_redis_config_precedence_ttl() {
4289 let config = RedisConfig::with_expire(Duration::from_secs(3600));
4292 let driver = RedisCacheDriver::new(config);
4293 driver
4294 .set_raw("key1", b"v1".to_vec(), Some(Duration::from_millis(50)))
4295 .unwrap();
4296 std::thread::sleep(Duration::from_millis(80));
4297 assert_eq!(driver.get_raw("key1").unwrap(), None); let config = RedisConfig::with_expire(Duration::from_millis(50));
4301 let driver = RedisCacheDriver::new(config);
4302 driver.set_raw("key2", b"v2".to_vec(), None).unwrap();
4303 std::thread::sleep(Duration::from_millis(80));
4304 assert_eq!(driver.get_raw("key2").unwrap(), None); let driver = make_redis_driver();
4308 driver.set_raw("key3", b"v3".to_vec(), None).unwrap();
4309 std::thread::sleep(Duration::from_millis(50));
4310 assert!(driver.get_raw("key3").unwrap().is_some()); }
4312
4313 #[test]
4318 fn test_multi_level_driver_set_get() {
4319 let l1 = sz_rust_orm_facade::MemoryCache::new();
4320 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4321
4322 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
4323 let val = driver.get_raw("key1").unwrap();
4324 assert_eq!(val, Some(b"value1".to_vec()));
4325 }
4326
4327 #[test]
4328 fn test_multi_level_driver_delete() {
4329 let l1 = sz_rust_orm_facade::MemoryCache::new();
4330 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4331
4332 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
4333 driver.delete("key1").unwrap();
4334 assert_eq!(driver.get_raw("key1").unwrap(), None);
4335 }
4336
4337 #[test]
4338 fn test_multi_level_driver_has() {
4339 let l1 = sz_rust_orm_facade::MemoryCache::new();
4340 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4341
4342 assert!(!driver.has("key1").unwrap());
4343 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
4344 assert!(driver.has("key1").unwrap());
4345 }
4346
4347 #[test]
4348 fn test_multi_level_driver_clear() {
4349 let l1 = sz_rust_orm_facade::MemoryCache::new();
4350 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4351
4352 driver.set_raw("key1", b"v1".to_vec(), None).unwrap();
4353 driver.set_raw("key2", b"v2".to_vec(), None).unwrap();
4354 driver.clear().unwrap();
4355 assert_eq!(driver.get_raw("key1").unwrap(), None);
4356 assert_eq!(driver.get_raw("key2").unwrap(), None);
4357 }
4358
4359 #[test]
4364 fn test_multi_level_two_levels_cascade_get() {
4365 let l1 = sz_rust_orm_facade::MemoryCache::new();
4367 let l2 = sz_rust_orm_facade::MemoryCache::new();
4368
4369 l2.set("key", b"from_l2".to_vec(), None).unwrap();
4371
4372 let driver = MultiLevelCacheDriver::new()
4373 .add_level(Box::new(l1.clone()))
4374 .add_level(Box::new(l2));
4375
4376 let val = driver.get_raw("key").unwrap();
4378 assert_eq!(val, Some(b"from_l2".to_vec()));
4379
4380 let l1_val = l1.get("key").unwrap();
4382 assert_eq!(l1_val, Some(b"from_l2".to_vec()));
4383 }
4384
4385 #[test]
4386 fn test_multi_level_set_writes_all_levels() {
4387 let l1 = sz_rust_orm_facade::MemoryCache::new();
4388 let l2 = sz_rust_orm_facade::MemoryCache::new();
4389
4390 let driver = MultiLevelCacheDriver::new()
4391 .add_level(Box::new(l1.clone()))
4392 .add_level(Box::new(l2.clone()));
4393
4394 driver.set_raw("key", b"value".to_vec(), None).unwrap();
4395
4396 assert_eq!(l1.get("key").unwrap(), Some(b"value".to_vec()));
4398 assert_eq!(l2.get("key").unwrap(), Some(b"value".to_vec()));
4399 }
4400
4401 #[test]
4402 fn test_multi_level_delete_removes_all_levels() {
4403 let l1 = sz_rust_orm_facade::MemoryCache::new();
4404 let l2 = sz_rust_orm_facade::MemoryCache::new();
4405
4406 let driver = MultiLevelCacheDriver::new()
4407 .add_level(Box::new(l1.clone()))
4408 .add_level(Box::new(l2.clone()));
4409
4410 driver.set_raw("key", b"value".to_vec(), None).unwrap();
4411 driver.delete("key").unwrap();
4412
4413 assert_eq!(l1.get("key").unwrap(), None);
4414 assert_eq!(l2.get("key").unwrap(), None);
4415 }
4416
4417 #[test]
4418 fn test_multi_level_l1_hit_skips_l2() {
4419 let l1 = sz_rust_orm_facade::MemoryCache::new();
4421 let l2 = sz_rust_orm_facade::MemoryCache::new();
4422
4423 l1.set("key", b"from_l1".to_vec(), None).unwrap();
4424 l2.set("key", b"from_l2".to_vec(), None).unwrap();
4425
4426 let driver = MultiLevelCacheDriver::new()
4427 .add_level(Box::new(l1))
4428 .add_level(Box::new(l2));
4429
4430 let val = driver.get_raw("key").unwrap();
4431 assert_eq!(val, Some(b"from_l1".to_vec()));
4432 }
4433
4434 #[test]
4439 fn test_multi_level_driver_inc_initial_value() {
4440 let l1 = sz_rust_orm_facade::MemoryCache::new();
4441 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4442
4443 let new_val = driver.inc("counter", 1).unwrap();
4444 assert_eq!(new_val, 1);
4445
4446 let val = driver.get_raw("counter").unwrap();
4447 assert_eq!(val, Some(b"1".to_vec()));
4448 }
4449
4450 #[test]
4451 fn test_multi_level_driver_inc_accumulate() {
4452 let l1 = sz_rust_orm_facade::MemoryCache::new();
4453 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4454
4455 driver.inc("counter", 5).unwrap();
4456 driver.inc("counter", 3).unwrap();
4457 driver.inc("counter", 1).unwrap();
4458
4459 let val = driver.get_raw("counter").unwrap();
4460 assert_eq!(val, Some(b"9".to_vec()));
4461 }
4462
4463 #[test]
4464 fn test_multi_level_driver_dec() {
4465 let l1 = sz_rust_orm_facade::MemoryCache::new();
4466 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4467
4468 driver.set_raw("counter", b"10".to_vec(), None).unwrap();
4469 let new_val = driver.dec("counter", 3).unwrap();
4470 assert_eq!(new_val, 7);
4471
4472 let val = driver.get_raw("counter").unwrap();
4473 assert_eq!(val, Some(b"7".to_vec()));
4474 }
4475
4476 #[test]
4477 fn test_multi_level_driver_inc_preserves_ttl() {
4478 let l1 = sz_rust_orm_facade::MemoryCache::new();
4480 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4481
4482 driver
4483 .set_raw("counter", b"5".to_vec(), Some(Duration::from_millis(200)))
4484 .unwrap();
4485
4486 let ttl_before = driver.inner().ttl("counter").unwrap();
4488 assert!(ttl_before.is_some());
4489
4490 driver.inc("counter", 1).unwrap();
4491
4492 let ttl_after = driver.inner().ttl("counter").unwrap();
4494 assert!(ttl_after.is_some());
4495 }
4496
4497 #[test]
4502 fn test_multi_level_driver_ttl_expiration() {
4503 let l1 = sz_rust_orm_facade::MemoryCache::new();
4504 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4505
4506 driver
4507 .set_raw("key", b"value".to_vec(), Some(Duration::from_millis(50)))
4508 .unwrap();
4509 assert!(driver.get_raw("key").unwrap().is_some());
4510
4511 std::thread::sleep(Duration::from_millis(80));
4512 assert_eq!(driver.get_raw("key").unwrap(), None);
4513 }
4514
4515 #[test]
4516 fn test_multi_level_driver_has_checks_ttl() {
4517 let l1 = sz_rust_orm_facade::MemoryCache::new();
4518 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4519
4520 driver
4521 .set_raw("key", b"value".to_vec(), Some(Duration::from_millis(50)))
4522 .unwrap();
4523 assert!(driver.has("key").unwrap());
4524
4525 std::thread::sleep(Duration::from_millis(80));
4526 assert!(!driver.has("key").unwrap());
4527 }
4528
4529 #[test]
4534 fn test_multi_level_driver_with_cache_facade() {
4535 let l1 = sz_rust_orm_facade::MemoryCache::new();
4536 let l2 = sz_rust_orm_facade::MemoryCache::new();
4537 let driver = MultiLevelCacheDriver::new()
4538 .add_level(Box::new(l1))
4539 .add_level(Box::new(l2));
4540
4541 let cache = Cache::new();
4542 cache.register_store("default", Box::new(driver));
4543
4544 cache.set("user:1", "Alice", None).unwrap();
4545 assert_eq!(
4546 cache.get::<String>("user:1").unwrap(),
4547 Some("Alice".to_string())
4548 );
4549
4550 cache.delete("user:1").unwrap();
4551 assert_eq!(cache.get::<String>("user:1").unwrap(), None);
4552 }
4553
4554 #[test]
4555 fn test_multi_level_driver_with_cache_facade_inc() {
4556 let l1 = sz_rust_orm_facade::MemoryCache::new();
4557 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4558
4559 let cache = Cache::new();
4560 cache.register_store("default", Box::new(driver));
4561
4562 cache.inc("counter", 5).unwrap();
4563 cache.inc("counter", 3).unwrap();
4564
4565 let val = cache.get::<String>("counter").unwrap();
4568 assert_eq!(val, Some("8".to_string()));
4569 }
4570
4571 #[test]
4576 fn test_multi_level_driver_empty_levels_get_returns_none() {
4577 let driver = MultiLevelCacheDriver::new();
4579 assert_eq!(driver.get_raw("key").unwrap(), None);
4580 }
4581
4582 #[test]
4583 fn test_multi_level_driver_empty_levels_has_returns_false() {
4584 let driver = MultiLevelCacheDriver::new();
4585 assert!(!driver.has("key").unwrap());
4586 }
4587
4588 #[test]
4589 fn test_multi_level_driver_inc_non_numeric_value_resets_to_step() {
4590 let l1 = sz_rust_orm_facade::MemoryCache::new();
4592 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4593
4594 driver
4595 .set_raw("counter", b"not_a_number".to_vec(), None)
4596 .unwrap();
4597 let new_val = driver.inc("counter", 5).unwrap();
4598 assert_eq!(new_val, 5);
4599 }
4600
4601 #[test]
4602 fn test_multi_level_driver_default_impl() {
4603 let driver = MultiLevelCacheDriver::default();
4605 assert_eq!(driver.get_raw("key").unwrap(), None);
4606 }
4607
4608 #[test]
4613 fn test_r5_multi_level_get_set_basic() {
4614 let l1 = sz_rust_orm_facade::MemoryCache::new();
4616 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4617
4618 driver.set_raw("key", b"value".to_vec(), None).unwrap();
4619 assert_eq!(driver.get_raw("key").unwrap(), Some(b"value".to_vec()));
4620 }
4621
4622 #[test]
4623 fn test_r5_multi_level_delete_nonexistent_no_error() {
4624 let l1 = sz_rust_orm_facade::MemoryCache::new();
4626 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4627
4628 assert!(driver.delete("nonexistent").is_ok());
4629 }
4630
4631 #[test]
4632 fn test_r5_multi_level_clear_empties_all() {
4633 let l1 = sz_rust_orm_facade::MemoryCache::new();
4635 let l2 = sz_rust_orm_facade::MemoryCache::new();
4636 let driver = MultiLevelCacheDriver::new()
4637 .add_level(Box::new(l1))
4638 .add_level(Box::new(l2));
4639
4640 driver.set_raw("k1", b"v1".to_vec(), None).unwrap();
4641 driver.set_raw("k2", b"v2".to_vec(), None).unwrap();
4642 driver.clear().unwrap();
4643
4644 assert_eq!(driver.get_raw("k1").unwrap(), None);
4645 assert_eq!(driver.get_raw("k2").unwrap(), None);
4646 }
4647
4648 #[test]
4649 fn test_r5_multi_level_cascade_fill_back() {
4650 let l1 = sz_rust_orm_facade::MemoryCache::new();
4652 let l2 = sz_rust_orm_facade::MemoryCache::new();
4653
4654 l2.set("key", b"from_l2".to_vec(), None).unwrap();
4656
4657 let driver = MultiLevelCacheDriver::new()
4658 .add_level(Box::new(l1.clone()))
4659 .add_level(Box::new(l2));
4660
4661 let val = driver.get_raw("key").unwrap();
4663 assert_eq!(val, Some(b"from_l2".to_vec()));
4664
4665 assert_eq!(l1.get("key").unwrap(), Some(b"from_l2".to_vec()));
4667 }
4668
4669 #[test]
4674 fn test_tag_get_cache_key_default_no_prefix() {
4675 let driver = MemoryCacheDriver::new();
4677 assert_eq!(driver.get_cache_key("user:1"), "user:1");
4678 assert_eq!(driver.get_cache_key("hello"), "hello");
4679 }
4680
4681 #[test]
4682 fn test_tag_get_tag_key_default_format() {
4683 let driver = MemoryCacheDriver::new();
4685 let tag_key = driver.get_tag_key("user");
4686 assert_eq!(tag_key, "tag:ee11cbb19052e40b07aac0ca060c23ee");
4688 }
4689
4690 #[test]
4691 fn test_tag_append_creates_new_tag_set() {
4692 let driver = MemoryCacheDriver::new();
4694 driver.tag_append("tag:abc123", "user:1").unwrap();
4695 let storage_key = "tag:abc123"; let raw = driver.get_raw(storage_key).unwrap();
4698 let stored: Vec<String> = serde_json::from_slice(&raw.unwrap()).unwrap();
4699 assert_eq!(stored, vec!["user:1"]);
4700 }
4701
4702 #[test]
4703 fn test_tag_append_appends_to_existing() {
4704 let driver = MemoryCacheDriver::new();
4705 driver.tag_append("tag:abc", "key1").unwrap();
4706 driver.tag_append("tag:abc", "key2").unwrap();
4707 let storage_key = "tag:abc";
4708 let raw = driver.get_raw(storage_key).unwrap();
4709 let stored: Vec<String> = serde_json::from_slice(&raw.unwrap()).unwrap();
4710 assert_eq!(stored, vec!["key1", "key2"]);
4711 }
4712
4713 #[test]
4714 fn test_tag_append_dedup() {
4715 let driver = MemoryCacheDriver::new();
4717 driver.tag_append("tag:abc", "key1").unwrap();
4718 driver.tag_append("tag:abc", "key1").unwrap(); let storage_key = "tag:abc";
4720 let raw = driver.get_raw(storage_key).unwrap();
4721 let stored: Vec<String> = serde_json::from_slice(&raw.unwrap()).unwrap();
4722 assert_eq!(stored, vec!["key1"]);
4723 }
4724
4725 #[test]
4726 fn test_tag_append_max_1000_cap() {
4727 let driver = MemoryCacheDriver::new();
4729 for i in 0..1001i64 {
4730 driver.tag_append("tag:abc", &format!("key{}", i)).unwrap();
4731 }
4732 let storage_key = "tag:abc";
4733 let raw = driver.get_raw(storage_key).unwrap();
4734 let stored: Vec<String> = serde_json::from_slice(&raw.unwrap()).unwrap();
4735 assert_eq!(stored.len(), 1000);
4737 assert!(!stored.contains(&"key0".to_string()));
4738 assert!(stored.contains(&"key1".to_string()));
4739 assert!(stored.contains(&"key1000".to_string()));
4740 }
4741
4742 #[test]
4743 fn test_tag_items_empty_returns_empty() {
4744 let driver = MemoryCacheDriver::new();
4745 let items = driver.tag_items("nonexistent_tag").unwrap();
4746 assert!(items.is_empty());
4747 }
4748
4749 #[test]
4750 fn test_tag_items_returns_stored_keys() {
4751 let driver = MemoryCacheDriver::new();
4752 let tag_key = driver.get_tag_key("mytag");
4754 driver.tag_append(&tag_key, "key1").unwrap();
4755 driver.tag_append(&tag_key, "key2").unwrap();
4756 let items = driver.tag_items("mytag").unwrap();
4757 assert_eq!(items, vec!["key1", "key2"]);
4758 }
4759
4760 #[test]
4761 fn test_tag_clear_deletes_keys() {
4762 let driver = MemoryCacheDriver::new();
4763 driver.set_raw("key1", b"v1".to_vec(), None).unwrap();
4765 driver.set_raw("key2", b"v2".to_vec(), None).unwrap();
4766 driver
4768 .tag_clear(&["key1".to_string(), "key2".to_string()])
4769 .unwrap();
4770 assert!(!driver.has("key1").unwrap());
4771 assert!(!driver.has("key2").unwrap());
4772 }
4773
4774 #[test]
4775 fn test_tag_clear_empty_no_error() {
4776 let driver = MemoryCacheDriver::new();
4777 driver.tag_clear(&[]).unwrap();
4779 }
4780
4781 #[test]
4786 fn test_redis_tag_get_cache_key_with_prefix() {
4787 let config = RedisConfig {
4788 prefix: "myapp:".to_string(),
4789 ..RedisConfig::default()
4790 };
4791 let driver = RedisCacheDriver::new(config);
4792 assert_eq!(driver.get_cache_key("user:1"), "myapp:user:1");
4793 }
4794
4795 #[test]
4796 fn test_redis_tag_get_tag_key_with_tag_prefix() {
4797 let config = RedisConfig {
4798 tag_prefix: "tag:".to_string(),
4799 ..RedisConfig::default()
4800 };
4801 let driver = RedisCacheDriver::new(config);
4802 let tag_key = driver.get_tag_key("user");
4803 assert_eq!(tag_key, "tag:ee11cbb19052e40b07aac0ca060c23ee");
4805 }
4806
4807 #[test]
4808 fn test_redis_tag_get_tag_key_custom_prefix() {
4809 let config = RedisConfig {
4810 tag_prefix: "t:".to_string(),
4811 ..RedisConfig::default()
4812 };
4813 let driver = RedisCacheDriver::new(config);
4814 let tag_key = driver.get_tag_key("user");
4815 assert_eq!(tag_key, "t:ee11cbb19052e40b07aac0ca060c23ee");
4816 }
4817
4818 #[test]
4819 fn test_redis_tag_append_uses_sadd() {
4820 let driver = RedisCacheDriver::new(RedisConfig::default());
4822 let tag_key = driver.get_tag_key("mytag");
4823 driver.tag_append(&tag_key, "key1").unwrap();
4824 driver.tag_append(&tag_key, "key2").unwrap();
4825 driver.tag_append(&tag_key, "key1").unwrap(); let items = driver.tag_items("mytag").unwrap();
4827 assert_eq!(items.len(), 2);
4829 assert!(items.contains(&"key1".to_string()));
4830 assert!(items.contains(&"key2".to_string()));
4831 }
4832
4833 #[test]
4834 fn test_redis_tag_items_uses_smembers() {
4835 let driver = RedisCacheDriver::new(RedisConfig::default());
4836 let tag_key = driver.get_tag_key("mytag");
4837 driver.tag_append(&tag_key, "a").unwrap();
4838 driver.tag_append(&tag_key, "b").unwrap();
4839 driver.tag_append(&tag_key, "c").unwrap();
4840 let items = driver.tag_items("mytag").unwrap();
4841 assert_eq!(items.len(), 3);
4842 }
4843
4844 #[test]
4845 fn test_redis_tag_clear_does_not_double_prefix() {
4846 let config = RedisConfig {
4848 prefix: "app:".to_string(),
4849 ..RedisConfig::default()
4850 };
4851 let driver = RedisCacheDriver::new(config);
4852 driver.set_raw("key1", b"v1".to_vec(), None).unwrap();
4854 let tag_key = driver.get_tag_key("mytag");
4856 driver.tag_append(&tag_key, "app:key1").unwrap();
4857 let items = driver.tag_items("mytag").unwrap();
4858 assert_eq!(items, vec!["app:key1"]);
4859 driver.tag_clear(&items).unwrap();
4861 assert!(!driver.has("key1").unwrap());
4862 }
4863
4864 #[test]
4865 fn test_redis_tag_clear_empty_no_error() {
4866 let driver = RedisCacheDriver::new(RedisConfig::default());
4867 driver.tag_clear(&[]).unwrap();
4868 }
4869
4870 #[test]
4875 fn test_tagset_set_stores_value_and_appends_tag() {
4876 let cache = Cache::new();
4877 cache.register_default(MemoryCacheDriver::new());
4878
4879 cache.tag("user").set("user:1", "Alice", None).unwrap();
4881
4882 assert_eq!(
4884 cache.get::<String>("user:1").unwrap(),
4885 Some("Alice".to_string())
4886 );
4887
4888 let mgr = cache.manager.read();
4890 let driver = mgr.default_store().unwrap();
4891 let items = driver.tag_items("user").unwrap();
4892 assert_eq!(items, vec!["user:1"]);
4893 }
4894
4895 #[test]
4896 fn test_tagset_set_multiple_keys_same_tag() {
4897 let cache = Cache::new();
4898 cache.register_default(MemoryCacheDriver::new());
4899
4900 cache.tag("user").set("user:1", "Alice", None).unwrap();
4901 cache.tag("user").set("user:2", "Bob", None).unwrap();
4902 cache.tag("user").set("user:3", "Carol", None).unwrap();
4903
4904 let mgr = cache.manager.read();
4905 let driver = mgr.default_store().unwrap();
4906 let items = driver.tag_items("user").unwrap();
4907 assert_eq!(items, vec!["user:1", "user:2", "user:3"]);
4908 }
4909
4910 #[test]
4911 fn test_tagset_clear_deletes_all_tagged_keys() {
4912 let cache = Cache::new();
4913 cache.register_default(MemoryCacheDriver::new());
4914
4915 cache.tag("user").set("user:1", "Alice", None).unwrap();
4916 cache.tag("user").set("user:2", "Bob", None).unwrap();
4917 cache.tag("user").set("user:3", "Carol", None).unwrap();
4918
4919 cache.tag("user").clear().unwrap();
4921
4922 assert!(cache.get::<String>("user:1").unwrap().is_none());
4923 assert!(cache.get::<String>("user:2").unwrap().is_none());
4924 assert!(cache.get::<String>("user:3").unwrap().is_none());
4925 }
4926
4927 #[test]
4928 fn test_tagset_clear_deletes_tag_key() {
4929 let cache = Cache::new();
4930 cache.register_default(MemoryCacheDriver::new());
4931
4932 cache.tag("user").set("user:1", "Alice", None).unwrap();
4933
4934 let mgr = cache.manager.read();
4936 let driver = mgr.default_store().unwrap();
4937 let tag_key = driver.get_tag_key("user");
4938 assert!(driver.has(&tag_key).unwrap());
4939 drop(mgr);
4940
4941 cache.tag("user").clear().unwrap();
4942
4943 let mgr = cache.manager.read();
4945 let driver = mgr.default_store().unwrap();
4946 assert!(!driver.has(&tag_key).unwrap());
4947 }
4948
4949 #[test]
4950 fn test_tagset_clear_empty_tag_no_error() {
4951 let cache = Cache::new();
4952 cache.register_default(MemoryCacheDriver::new());
4953
4954 cache.tag("empty").clear().unwrap();
4956 }
4957
4958 #[test]
4959 fn test_tagset_append_adds_key_to_tag() {
4960 let cache = Cache::new();
4961 cache.register_default(MemoryCacheDriver::new());
4962
4963 cache.set("user:1", "Alice", None).unwrap();
4965 cache.tag("user").append("user:1").unwrap();
4967
4968 let mgr = cache.manager.read();
4969 let driver = mgr.default_store().unwrap();
4970 let items = driver.tag_items("user").unwrap();
4971 assert_eq!(items, vec!["user:1"]);
4972 }
4973
4974 #[test]
4975 fn test_tagset_many_tags_single_key() {
4976 let cache = Cache::new();
4977 cache.register_default(MemoryCacheDriver::new());
4978
4979 cache
4981 .tag_many(&["user", "admin"])
4982 .set("key1", "val", None)
4983 .unwrap();
4984
4985 let mgr = cache.manager.read();
4987 let driver = mgr.default_store().unwrap();
4988 let user_items = driver.tag_items("user").unwrap();
4989 let admin_items = driver.tag_items("admin").unwrap();
4990 assert_eq!(user_items, vec!["key1"]);
4991 assert_eq!(admin_items, vec!["key1"]);
4992 }
4993
4994 #[test]
4995 fn test_tagset_many_tags_clear_one() {
4996 let cache = Cache::new();
4997 cache.register_default(MemoryCacheDriver::new());
4998
4999 cache
5000 .tag_many(&["user", "admin"])
5001 .set("key1", "val", None)
5002 .unwrap();
5003
5004 cache.tag("user").clear().unwrap();
5006
5007 assert!(cache.get::<String>("key1").unwrap().is_none());
5009
5010 let mgr = cache.manager.read();
5013 let driver = mgr.default_store().unwrap();
5014 let admin_items = driver.tag_items("admin").unwrap();
5015 assert_eq!(admin_items, vec!["key1"]); let user_tag_key = driver.get_tag_key("user");
5018 assert!(!driver.has(&user_tag_key).unwrap());
5019 }
5020
5021 #[test]
5022 fn test_tagset_tags_getter() {
5023 let cache = Cache::new();
5024 let ts = cache.tag_many(&["a", "b", "c"]);
5025 assert_eq!(ts.tags(), &["a", "b", "c"]);
5026 }
5027
5028 #[test]
5033 fn test_redis_tagset_set_stores_value_and_appends_tag() {
5034 let cache = Cache::new();
5035 let driver = RedisCacheDriver::new(RedisConfig::default());
5036 cache.register_store("redis", Box::new(driver));
5037
5038 cache.tag("user").set("user:1", "Alice", None).unwrap();
5039
5040 assert_eq!(
5042 cache.get::<String>("user:1").unwrap(),
5043 Some("Alice".to_string())
5044 );
5045
5046 let mgr = cache.manager.read();
5048 let driver = mgr.default_store().unwrap();
5049 let items = driver.tag_items("user").unwrap();
5050 assert_eq!(items, vec!["user:1"]);
5051 }
5052
5053 #[test]
5054 fn test_redis_tagset_set_with_prefix() {
5055 let cache = Cache::new();
5056 let config = RedisConfig {
5057 prefix: "app:".to_string(),
5058 ..RedisConfig::default()
5059 };
5060 let driver = RedisCacheDriver::new(config);
5061 cache.register_store("redis", Box::new(driver));
5062
5063 cache.tag("user").set("user:1", "Alice", None).unwrap();
5064
5065 let mgr = cache.manager.read();
5067 let driver = mgr.default_store().unwrap();
5068 let items = driver.tag_items("user").unwrap();
5069 assert_eq!(items, vec!["app:user:1"]);
5070 }
5071
5072 #[test]
5073 fn test_redis_tagset_clear_deletes_all_tagged_keys() {
5074 let cache = Cache::new();
5075 let driver = RedisCacheDriver::new(RedisConfig::default());
5076 cache.register_store("redis", Box::new(driver));
5077
5078 cache.tag("user").set("user:1", "Alice", None).unwrap();
5079 cache.tag("user").set("user:2", "Bob", None).unwrap();
5080 cache.tag("user").set("user:3", "Carol", None).unwrap();
5081
5082 cache.tag("user").clear().unwrap();
5083
5084 assert!(cache.get::<String>("user:1").unwrap().is_none());
5085 assert!(cache.get::<String>("user:2").unwrap().is_none());
5086 assert!(cache.get::<String>("user:3").unwrap().is_none());
5087 }
5088
5089 #[test]
5090 fn test_redis_tagset_clear_deletes_tag_key() {
5091 let cache = Cache::new();
5092 let driver = RedisCacheDriver::new(RedisConfig::default());
5093 cache.register_store("redis", Box::new(driver));
5094
5095 cache.tag("user").set("user:1", "Alice", None).unwrap();
5096
5097 let mgr = cache.manager.read();
5098 let driver = mgr.default_store().unwrap();
5099 let tag_key = driver.get_tag_key("user");
5100 assert!(driver.has(&tag_key).unwrap());
5102 drop(mgr);
5103
5104 cache.tag("user").clear().unwrap();
5105
5106 let mgr = cache.manager.read();
5107 let driver = mgr.default_store().unwrap();
5108 assert!(!driver.has(&tag_key).unwrap());
5109 }
5110
5111 #[test]
5112 fn test_redis_tagset_many_tags() {
5113 let cache = Cache::new();
5114 let driver = RedisCacheDriver::new(RedisConfig::default());
5115 cache.register_store("redis", Box::new(driver));
5116
5117 cache
5118 .tag_many(&["user", "admin"])
5119 .set("key1", "val", None)
5120 .unwrap();
5121
5122 let mgr = cache.manager.read();
5123 let driver = mgr.default_store().unwrap();
5124 let user_items = driver.tag_items("user").unwrap();
5125 let admin_items = driver.tag_items("admin").unwrap();
5126 assert_eq!(user_items, vec!["key1"]);
5127 assert_eq!(admin_items, vec!["key1"]);
5128 }
5129
5130 #[test]
5135 fn test_r5_php_tag_set_then_clear() {
5136 let cache = Cache::new();
5138 cache.register_default(MemoryCacheDriver::new());
5139
5140 cache.tag("user").set("u1", "Alice", None).unwrap();
5141 cache.tag("user").set("u2", "Bob", None).unwrap();
5142
5143 cache.set("other", "data", None).unwrap();
5145
5146 cache.tag("user").clear().unwrap();
5147
5148 assert!(cache.get::<String>("u1").unwrap().is_none());
5150 assert!(cache.get::<String>("u2").unwrap().is_none());
5151 assert_eq!(
5153 cache.get::<String>("other").unwrap(),
5154 Some("data".to_string())
5155 );
5156 }
5157
5158 #[test]
5159 fn test_r5_php_tag_multiple_tags_clear() {
5160 let cache = Cache::new();
5162 cache.register_default(MemoryCacheDriver::new());
5163
5164 cache
5166 .tag_many(&["user", "admin"])
5167 .set("key1", "v1", None)
5168 .unwrap();
5169 cache.tag("user").set("key2", "v2", None).unwrap();
5171
5172 cache.tag("user").clear().unwrap();
5174
5175 assert!(cache.get::<String>("key1").unwrap().is_none());
5176 assert!(cache.get::<String>("key2").unwrap().is_none());
5177 }
5178
5179 #[test]
5180 fn test_r5_php_tag_get_cache_key_prefix() {
5181 let cache = Cache::new();
5183 cache.register_default(MemoryCacheDriver::new());
5184 let mgr = cache.manager.read();
5185 let driver = mgr.default_store().unwrap();
5186 assert_eq!(driver.get_cache_key("test"), "test");
5187 }
5188
5189 #[test]
5190 fn test_r5_php_tag_get_tag_key_md5() {
5191 let cache = Cache::new();
5193 cache.register_default(MemoryCacheDriver::new());
5194 let mgr = cache.manager.read();
5195 let driver = mgr.default_store().unwrap();
5196 assert_eq!(
5198 driver.get_tag_key("hello"),
5199 "tag:5d41402abc4b2a76b9719d911017c592"
5200 );
5201 }
5202
5203 #[test]
5204 fn test_r5_php_tag_push_max_1000_array_shift() {
5205 let driver = MemoryCacheDriver::new();
5207 for i in 0..1005i64 {
5208 driver.tag_append("tag:test", &format!("key{}", i)).unwrap();
5209 }
5210 let storage_key = "tag:test";
5211 let raw = driver.get_raw(storage_key).unwrap();
5212 let stored: Vec<String> = serde_json::from_slice(&raw.unwrap()).unwrap();
5213 assert_eq!(stored.len(), 1000);
5215 assert!(!stored.contains(&"key0".to_string()));
5217 assert!(!stored.contains(&"key4".to_string()));
5218 assert!(stored.contains(&"key5".to_string()));
5220 assert!(stored.contains(&"key1004".to_string()));
5221 }
5222
5223 #[test]
5224 fn test_r5_php_tag_push_array_unique() {
5225 let driver = MemoryCacheDriver::new();
5227 driver.tag_append("tag:u", "a").unwrap();
5228 driver.tag_append("tag:u", "b").unwrap();
5229 driver.tag_append("tag:u", "a").unwrap(); driver.tag_append("tag:u", "c").unwrap();
5231 driver.tag_append("tag:u", "b").unwrap(); let storage_key = "tag:u";
5234 let raw = driver.get_raw(storage_key).unwrap();
5235 let stored: Vec<String> = serde_json::from_slice(&raw.unwrap()).unwrap();
5236 assert_eq!(stored, vec!["a", "b", "c"]);
5238 }
5239
5240 #[test]
5241 fn test_r5_php_tag_singleton_equivalent() {
5242 let cache = Cache::new();
5244 cache.register_default(MemoryCacheDriver::new());
5245
5246 cache.tag("user").set("u1", "Alice", None).unwrap();
5248 cache.tag("user").set("u2", "Bob", None).unwrap();
5250
5251 let mgr = cache.manager.read();
5253 let driver = mgr.default_store().unwrap();
5254 let items = driver.tag_items("user").unwrap();
5255 assert_eq!(items, vec!["u1", "u2"]);
5256
5257 cache.tag("user").clear().unwrap();
5259 assert!(cache.get::<String>("u1").unwrap().is_none());
5260 assert!(cache.get::<String>("u2").unwrap().is_none());
5261 }
5262
5263 #[test]
5264 fn test_r5_php_tag_clear_then_set_again() {
5265 let cache = Cache::new();
5267 cache.register_default(MemoryCacheDriver::new());
5268
5269 cache.tag("user").set("u1", "Alice", None).unwrap();
5270 cache.tag("user").clear().unwrap();
5271 assert!(cache.get::<String>("u1").unwrap().is_none());
5272
5273 cache.tag("user").set("u1", "Alice2", None).unwrap();
5275 assert_eq!(
5276 cache.get::<String>("u1").unwrap(),
5277 Some("Alice2".to_string())
5278 );
5279
5280 let mgr = cache.manager.read();
5282 let driver = mgr.default_store().unwrap();
5283 let items = driver.tag_items("user").unwrap();
5284 assert_eq!(items, vec!["u1"]);
5285 }
5286
5287 #[test]
5288 fn test_r5_php_tag_redis_set_then_clear() {
5289 let cache = Cache::new();
5291 let driver = RedisCacheDriver::new(RedisConfig::default());
5292 cache.register_store("redis", Box::new(driver));
5293
5294 cache.tag("article").set("a:1", "Hello", None).unwrap();
5295 cache.tag("article").set("a:2", "World", None).unwrap();
5296 cache.set("untagged", "data", None).unwrap();
5297
5298 cache.tag("article").clear().unwrap();
5299
5300 assert!(cache.get::<String>("a:1").unwrap().is_none());
5301 assert!(cache.get::<String>("a:2").unwrap().is_none());
5302 assert_eq!(
5304 cache.get::<String>("untagged").unwrap(),
5305 Some("data".to_string())
5306 );
5307 }
5308
5309 #[test]
5310 fn test_r5_php_tag_redis_with_prefix() {
5311 let cache = Cache::new();
5313 let config = RedisConfig {
5314 prefix: "myapp:".to_string(),
5315 tag_prefix: "tag:".to_string(),
5316 ..RedisConfig::default()
5317 };
5318 let driver = RedisCacheDriver::new(config);
5319 cache.register_store("redis", Box::new(driver));
5320
5321 cache.tag("user").set("u1", "Alice", None).unwrap();
5322
5323 let mgr = cache.manager.read();
5325 let driver = mgr.default_store().unwrap();
5326 let items = driver.tag_items("user").unwrap();
5327 assert_eq!(items, vec!["myapp:u1"]);
5328
5329 drop(mgr);
5331 cache.tag("user").clear().unwrap();
5332 assert!(cache.get::<String>("u1").unwrap().is_none());
5333 }
5334
5335 #[test]
5336 fn test_r5_php_tag_different_tags_isolation() {
5337 let cache = Cache::new();
5339 cache.register_default(MemoryCacheDriver::new());
5340
5341 cache.tag("user").set("u1", "Alice", None).unwrap();
5342 cache.tag("article").set("a1", "Hello", None).unwrap();
5343
5344 cache.tag("user").clear().unwrap();
5346
5347 assert!(cache.get::<String>("u1").unwrap().is_none());
5348 assert_eq!(
5349 cache.get::<String>("a1").unwrap(),
5350 Some("Hello".to_string())
5351 );
5352 }
5353
5354 #[test]
5355 fn test_r5_php_tag_set_with_ttl() {
5356 let cache = Cache::new();
5358 cache.register_default(MemoryCacheDriver::new());
5359
5360 cache
5361 .tag("user")
5362 .set("u1", "Alice", Some(Duration::from_millis(50)))
5363 .unwrap();
5364
5365 assert_eq!(
5366 cache.get::<String>("u1").unwrap(),
5367 Some("Alice".to_string())
5368 );
5369
5370 std::thread::sleep(Duration::from_millis(60));
5371 assert!(cache.get::<String>("u1").unwrap().is_none());
5372 }
5373
5374 #[test]
5379 fn test_delete_many_multiple_keys() {
5380 let cache = Cache::new();
5382 cache.register_default(MemoryCacheDriver::new());
5383 cache.set("k1", "v1", None).unwrap();
5384 cache.set("k2", "v2", None).unwrap();
5385 cache.set("k3", "v3", None).unwrap();
5386
5387 cache.delete_many(&["k1", "k2", "k3"]).unwrap();
5388
5389 assert!(cache.get::<String>("k1").unwrap().is_none());
5390 assert!(cache.get::<String>("k2").unwrap().is_none());
5391 assert!(cache.get::<String>("k3").unwrap().is_none());
5392 }
5393
5394 #[test]
5395 fn test_delete_many_nonexistent_keys_ok() {
5396 let cache = Cache::new();
5398 cache.register_default(MemoryCacheDriver::new());
5399 cache.set("exists", "v", None).unwrap();
5400
5401 let result = cache.delete_many(&["exists", "nonexistent"]);
5403 assert!(result.is_ok());
5404 }
5405
5406 #[test]
5407 fn test_delete_many_empty_slice() {
5408 let cache = Cache::new();
5410 cache.register_default(MemoryCacheDriver::new());
5411 let result = cache.delete_many(&[]);
5412 assert!(result.is_ok());
5413 }
5414
5415 #[test]
5416 fn test_delete_many_partial_delete_before_failure() {
5417 let cache = Cache::new();
5420 cache.register_default(MemoryCacheDriver::new());
5421 cache.set("a", "1", None).unwrap();
5422 cache.set("b", "2", None).unwrap();
5423
5424 cache.delete_many(&["a", "b"]).unwrap();
5425 assert!(cache.get::<String>("a").unwrap().is_none());
5426 assert!(cache.get::<String>("b").unwrap().is_none());
5427 }
5428
5429 #[test]
5434 fn test_invalidate_after_write_basic() {
5435 let cache = Cache::new();
5437 cache.register_default(MemoryCacheDriver::new());
5438 cache.set("user:1", "Alice", None).unwrap();
5439 assert_eq!(
5440 cache.get::<String>("user:1").unwrap(),
5441 Some("Alice".to_string())
5442 );
5443
5444 cache.invalidate_after_write(&["user:1"]).unwrap();
5446 assert!(cache.get::<String>("user:1").unwrap().is_none());
5447 }
5448
5449 #[test]
5450 fn test_invalidate_after_write_multiple_keys() {
5451 let cache = Cache::new();
5453 cache.register_default(MemoryCacheDriver::new());
5454 cache.set("sdp_category_tree", "t1", None).unwrap();
5455 cache.set("sdp_category_select", "s1", None).unwrap();
5456 cache.set("sdp_category_child", "c1", None).unwrap();
5457
5458 cache
5459 .invalidate_after_write(&[
5460 "sdp_category_tree",
5461 "sdp_category_select",
5462 "sdp_category_child",
5463 ])
5464 .unwrap();
5465
5466 assert!(cache.get::<String>("sdp_category_tree").unwrap().is_none());
5467 assert!(cache
5468 .get::<String>("sdp_category_select")
5469 .unwrap()
5470 .is_none());
5471 assert!(cache.get::<String>("sdp_category_child").unwrap().is_none());
5472 }
5473
5474 #[test]
5475 fn test_invalidate_after_write_fire_and_forget() {
5476 let cache = Cache::new();
5478 cache.register_default(MemoryCacheDriver::new());
5479 cache.set("clerk:1", "data", None).unwrap();
5480
5481 let _ = cache.invalidate_after_write(&["clerk:1"]);
5483 assert!(cache.get::<String>("clerk:1").unwrap().is_none());
5484 }
5485
5486 #[test]
5491 fn test_refresh_force_update() {
5492 let cache = Cache::new();
5494 cache.register_default(MemoryCacheDriver::new());
5495 cache.set("store:1", "old_data", None).unwrap();
5496
5497 let result: String = cache
5498 .refresh("store:1", None, || Ok("new_data".to_string()))
5499 .unwrap();
5500
5501 assert_eq!(result, "new_data");
5502 assert_eq!(
5503 cache.get::<String>("store:1").unwrap(),
5504 Some("new_data".to_string())
5505 );
5506 }
5507
5508 #[test]
5509 fn test_refresh_fetcher_error_no_write() {
5510 let cache = Cache::new();
5512 cache.register_default(MemoryCacheDriver::new());
5513 cache.set("key", "original", None).unwrap();
5514
5515 let result: Result<String, CacheError> = cache.refresh("key", None, || {
5517 Err(CacheError::SerializationError("fetch failed".to_string()))
5518 });
5519
5520 assert!(result.is_err());
5521 assert!(cache.get::<String>("key").unwrap().is_none());
5523 }
5524
5525 #[test]
5526 fn test_refresh_ttl_propagation() {
5527 let cache = Cache::new();
5529 cache.register_default(MemoryCacheDriver::new());
5530
5531 let _result: String = cache
5532 .refresh("ttl_key", Some(Duration::from_millis(50)), || {
5533 Ok("value".to_string())
5534 })
5535 .unwrap();
5536
5537 assert_eq!(
5539 cache.get::<String>("ttl_key").unwrap(),
5540 Some("value".to_string())
5541 );
5542
5543 std::thread::sleep(Duration::from_millis(60));
5545 assert!(cache.get::<String>("ttl_key").unwrap().is_none());
5546 }
5547
5548 #[test]
5549 fn test_refresh_returns_fetcher_value() {
5550 let cache = Cache::new();
5553 cache.register_default(MemoryCacheDriver::new());
5554 cache.set("counter", "old_value", None).unwrap();
5555
5556 let result: String = cache
5557 .refresh("counter", None, || Ok("new_value".to_string()))
5558 .unwrap();
5559 assert_eq!(result, "new_value");
5560 assert_eq!(
5561 cache.get::<String>("counter").unwrap(),
5562 Some("new_value".to_string())
5563 );
5564 }
5565
5566 #[test]
5571 fn test_r5_php_delete_multiple_semantics() {
5572 let cache = Cache::new();
5575 cache.register_default(MemoryCacheDriver::new());
5576 cache.set("a", "1", None).unwrap();
5577 cache.set("b", "2", None).unwrap();
5578 cache.set("c", "3", None).unwrap();
5579
5580 let result = cache.delete_many(&["a", "b", "c"]);
5582 assert!(result.is_ok()); assert!(cache.get::<String>("a").unwrap().is_none());
5586 assert!(cache.get::<String>("b").unwrap().is_none());
5587 assert!(cache.get::<String>("c").unwrap().is_none());
5588 }
5589
5590 #[test]
5591 fn test_r5_php_invalidate_after_write_pattern() {
5592 let cache = Cache::new();
5595 cache.register_default(MemoryCacheDriver::new());
5596
5597 cache
5599 .set("foodCashierClerkAll_1", vec!["clerk1"], None)
5600 .unwrap();
5601
5602 let write_success = true;
5604 if write_success {
5605 cache
5606 .invalidate_after_write(&["foodCashierClerkAll_1"])
5607 .unwrap();
5608 }
5609
5610 assert!(cache
5612 .get::<Vec<String>>("foodCashierClerkAll_1")
5613 .unwrap()
5614 .is_none());
5615 }
5616
5617 #[test]
5618 fn test_r5_php_refresh_pattern() {
5619 let cache = Cache::new();
5622 cache.register_default(MemoryCacheDriver::new());
5623
5624 cache
5626 .set("wmall_store_info_1", "old_store_data", None)
5627 .unwrap();
5628
5629 let result: String = cache
5631 .refresh("wmall_store_info_1", None, || {
5632 Ok("fresh_store_data".to_string())
5634 })
5635 .unwrap();
5636
5637 assert_eq!(result, "fresh_store_data");
5638 assert_eq!(
5639 cache.get::<String>("wmall_store_info_1").unwrap(),
5640 Some("fresh_store_data".to_string())
5641 );
5642 }
5643
5644 #[test]
5649 fn test_fetch_singleflight_cache_hit() {
5650 let cache = Cache::new();
5652 cache.register_default(MemoryCacheDriver::new());
5653 cache.set("hot", "cached_value", None).unwrap();
5654
5655 let called = Arc::new(Mutex::new(false));
5656 let called_clone = called.clone();
5657 let result: String = cache
5658 .fetch_singleflight("hot", None, || {
5659 *called_clone.lock() = true;
5660 Ok("fetcher_value".to_string())
5661 })
5662 .unwrap();
5663
5664 assert_eq!(result, "cached_value");
5665 assert!(!*called.lock(), "fetcher 不应被调用(缓存命中)");
5666 }
5667
5668 #[test]
5669 fn test_fetch_singleflight_cache_miss_invokes_fetcher() {
5670 let cache = Cache::new();
5672 cache.register_default(MemoryCacheDriver::new());
5673
5674 let result: String = cache
5675 .fetch_singleflight("miss_key", None, || Ok("fetched".to_string()))
5676 .unwrap();
5677
5678 assert_eq!(result, "fetched");
5679 assert_eq!(
5680 cache.get::<String>("miss_key").unwrap(),
5681 Some("fetched".to_string())
5682 );
5683 }
5684
5685 #[test]
5686 fn test_fetch_singleflight_concurrent_only_one_fetcher_call() {
5687 let cache = Arc::new(Cache::new());
5689 cache.register_default(MemoryCacheDriver::new());
5690
5691 let fetcher_call_count = Arc::new(Mutex::new(0u32));
5692 let barrier = Arc::new(Barrier::new(4));
5693 let results = Arc::new(Mutex::new(Vec::<String>::new()));
5694
5695 let mut handles = Vec::new();
5696 for _ in 0..4 {
5697 let cache_clone = Arc::clone(&cache);
5698 let count_clone = Arc::clone(&fetcher_call_count);
5699 let barrier_clone = Arc::clone(&barrier);
5700 let results_clone = Arc::clone(&results);
5701
5702 handles.push(std::thread::spawn(move || {
5703 barrier_clone.wait();
5705
5706 let value: String = cache_clone
5707 .fetch_singleflight("concurrent_key", None, || {
5708 std::thread::sleep(Duration::from_millis(50));
5710 let mut count = count_clone.lock();
5711 *count += 1;
5712 Ok(format!("fetched_{}", *count))
5713 })
5714 .unwrap();
5715
5716 results_clone.lock().push(value);
5717 }));
5718 }
5719
5720 for handle in handles {
5721 handle.join().unwrap();
5722 }
5723
5724 assert_eq!(
5726 *fetcher_call_count.lock(),
5727 1,
5728 "fetcher 应只调用一次(singleflight)"
5729 );
5730
5731 let results = results.lock();
5733 assert_eq!(results.len(), 4);
5734 for value in results.iter() {
5735 assert_eq!(value, "fetched_1");
5736 }
5737 }
5738
5739 #[test]
5740 fn test_fetch_singleflight_fetcher_error_propagates() {
5741 let cache = Cache::new();
5743 cache.register_default(MemoryCacheDriver::new());
5744
5745 let result: Result<String, CacheError> = cache.fetch_singleflight("err_key", None, || {
5746 Err(CacheError::SerializationError("fetcher failed".to_string()))
5747 });
5748
5749 assert!(result.is_err());
5750 assert!(cache.get::<String>("err_key").unwrap().is_none());
5751 }
5752
5753 #[test]
5758 fn test_set_with_jitter_basic() {
5759 let cache = Cache::new();
5761 cache.register_default(MemoryCacheDriver::new());
5762
5763 cache
5764 .set_with_jitter(
5765 "jitter_key",
5766 "value",
5767 Some(Duration::from_secs(60)),
5768 Duration::from_secs(10),
5769 )
5770 .unwrap();
5771
5772 assert_eq!(
5773 cache.get::<String>("jitter_key").unwrap(),
5774 Some("value".to_string())
5775 );
5776 }
5777
5778 #[test]
5779 fn test_set_with_jitter_zero_jitter_equivalent_to_set() {
5780 let cache = Cache::new();
5782 cache.register_default(MemoryCacheDriver::new());
5783
5784 cache
5785 .set_with_jitter(
5786 "no_jitter",
5787 "value",
5788 Some(Duration::from_secs(60)),
5789 Duration::ZERO,
5790 )
5791 .unwrap();
5792
5793 assert_eq!(
5794 cache.get::<String>("no_jitter").unwrap(),
5795 Some("value".to_string())
5796 );
5797 }
5798
5799 #[test]
5800 fn test_set_with_jitter_none_ttl_no_jitter() {
5801 let cache = Cache::new();
5803 cache.register_default(MemoryCacheDriver::new());
5804
5805 cache
5806 .set_with_jitter("permanent", "value", None, Duration::from_secs(10))
5807 .unwrap();
5808
5809 assert_eq!(
5810 cache.get::<String>("permanent").unwrap(),
5811 Some("value".to_string())
5812 );
5813 }
5814
5815 #[test]
5816 fn test_set_with_jitter_ttl_in_expected_range() {
5817 let cache = Cache::new();
5819 cache.register_default(MemoryCacheDriver::new());
5820
5821 let base_ttl = Duration::from_millis(50);
5822 let jitter = Duration::from_millis(100);
5823
5824 cache
5825 .set_with_jitter("range_key", "value", Some(base_ttl), jitter)
5826 .unwrap();
5827
5828 assert!(cache.get::<String>("range_key").unwrap().is_some());
5830
5831 std::thread::sleep(base_ttl + jitter + Duration::from_millis(20));
5833 assert!(
5834 cache.get::<String>("range_key").unwrap().is_none(),
5835 "TTL 应在 [{:?}, {:?}] 范围内,已过期",
5836 base_ttl,
5837 base_ttl + jitter
5838 );
5839 }
5840
5841 #[test]
5846 fn test_fetch_with_protection_cache_hit() {
5847 let cache = Cache::new();
5849 cache.register_default(MemoryCacheDriver::new());
5850 cache.set("protected", "cached", None).unwrap();
5851
5852 let called = Arc::new(Mutex::new(false));
5853 let called_clone = called.clone();
5854 let result: String = cache
5855 .fetch_with_protection(
5856 "protected",
5857 Some(Duration::from_secs(60)),
5858 Duration::from_secs(10),
5859 || {
5860 *called_clone.lock() = true;
5861 Ok("fetched".to_string())
5862 },
5863 )
5864 .unwrap();
5865
5866 assert_eq!(result, "cached");
5867 assert!(!*called.lock());
5868 }
5869
5870 #[test]
5871 fn test_fetch_with_protection_cache_miss_invokes_fetcher() {
5872 let cache = Cache::new();
5874 cache.register_default(MemoryCacheDriver::new());
5875
5876 let result: String = cache
5877 .fetch_with_protection(
5878 "miss_protected",
5879 Some(Duration::from_secs(60)),
5880 Duration::from_secs(10),
5881 || Ok("fetched_protected".to_string()),
5882 )
5883 .unwrap();
5884
5885 assert_eq!(result, "fetched_protected");
5886 assert_eq!(
5887 cache.get::<String>("miss_protected").unwrap(),
5888 Some("fetched_protected".to_string())
5889 );
5890 }
5891
5892 #[test]
5893 fn test_fetch_with_protection_concurrent_single_flight() {
5894 let cache = Arc::new(Cache::new());
5896 cache.register_default(MemoryCacheDriver::new());
5897
5898 let fetcher_call_count = Arc::new(Mutex::new(0u32));
5899 let barrier = Arc::new(Barrier::new(4));
5900 let results = Arc::new(Mutex::new(Vec::<String>::new()));
5901
5902 let mut handles = Vec::new();
5903 for _ in 0..4 {
5904 let cache_clone = Arc::clone(&cache);
5905 let count_clone = Arc::clone(&fetcher_call_count);
5906 let barrier_clone = Arc::clone(&barrier);
5907 let results_clone = Arc::clone(&results);
5908
5909 handles.push(std::thread::spawn(move || {
5910 barrier_clone.wait();
5911
5912 let value: String = cache_clone
5913 .fetch_with_protection(
5914 "concurrent_protected",
5915 Some(Duration::from_secs(60)),
5916 Duration::from_secs(10),
5917 || {
5918 std::thread::sleep(Duration::from_millis(50));
5919 let mut count = count_clone.lock();
5920 *count += 1;
5921 Ok(format!("value_{}", *count))
5922 },
5923 )
5924 .unwrap();
5925
5926 results_clone.lock().push(value);
5927 }));
5928 }
5929
5930 for handle in handles {
5931 handle.join().unwrap();
5932 }
5933
5934 assert_eq!(*fetcher_call_count.lock(), 1, "fetcher 应只调用一次");
5935
5936 let results = results.lock();
5937 assert_eq!(results.len(), 4);
5938 for value in results.iter() {
5939 assert_eq!(value, "value_1");
5940 }
5941 }
5942
5943 #[test]
5944 fn test_fetch_with_protection_fetcher_error_propagates() {
5945 let cache = Cache::new();
5947 cache.register_default(MemoryCacheDriver::new());
5948
5949 let result: Result<String, CacheError> = cache.fetch_with_protection(
5950 "err_protected",
5951 Some(Duration::from_secs(60)),
5952 Duration::from_secs(10),
5953 || Err(CacheError::SerializationError("failed".to_string())),
5954 );
5955
5956 assert!(result.is_err());
5957 assert!(cache.get::<String>("err_protected").unwrap().is_none());
5958 }
5959
5960 #[test]
5965 fn test_r5_php_remember_lock_vs_rust_singleflight() {
5966 let cache = Arc::new(Cache::new());
5970 cache.register_default(MemoryCacheDriver::new());
5971
5972 let call_count = Arc::new(Mutex::new(0u32));
5973 let barrier = Arc::new(Barrier::new(3));
5974 let results = Arc::new(Mutex::new(Vec::<String>::new()));
5975
5976 let mut handles = Vec::new();
5977 for _ in 0..3 {
5978 let cache_clone = Arc::clone(&cache);
5979 let count_clone = Arc::clone(&call_count);
5980 let barrier_clone = Arc::clone(&barrier);
5981 let results_clone = Arc::clone(&results);
5982
5983 handles.push(std::thread::spawn(move || {
5984 barrier_clone.wait();
5985
5986 let value: String = cache_clone
5987 .fetch_singleflight("r5_compare_key", None, || {
5988 std::thread::sleep(Duration::from_millis(30));
5989 let mut count = count_clone.lock();
5990 *count += 1;
5991 Ok(format!("v_{}", *count))
5992 })
5993 .unwrap();
5994
5995 results_clone.lock().push(value);
5996 }));
5997 }
5998
5999 for handle in handles {
6000 handle.join().unwrap();
6001 }
6002
6003 assert_eq!(
6005 *call_count.lock(),
6006 1,
6007 "Rust singleflight fetcher 应只调用一次"
6008 );
6009
6010 let results = results.lock();
6012 assert_eq!(results.len(), 3);
6013 for value in results.iter() {
6014 assert_eq!(value, "v_1");
6015 }
6016 }
6017
6018 #[test]
6019 fn test_r5_php_no_jitter_vs_rust_jitter() {
6020 let cache = Cache::new();
6024 cache.register_default(MemoryCacheDriver::new());
6025
6026 let mut ttl_samples = Vec::new();
6028 for i in 0..10 {
6029 let key = format!("jitter_sample_{}", i);
6030 cache
6031 .set_with_jitter(
6032 &key,
6033 "value",
6034 Some(Duration::from_secs(60)),
6035 Duration::from_secs(10),
6036 )
6037 .unwrap();
6038
6039 let _ = cache.get::<String>(&key).unwrap();
6042 ttl_samples.push(key);
6043 }
6044
6045 for key in &ttl_samples {
6047 assert_eq!(
6048 cache.get::<String>(key).unwrap(),
6049 Some("value".to_string()),
6050 "所有带抖动 TTL 的 key 都应写入成功"
6051 );
6052 }
6053 }
6054
6055 #[test]
6056 fn test_r5_php_remember_no_double_check_vs_rust_double_check() {
6057 let cache = Cache::new();
6061 cache.register_default(MemoryCacheDriver::new());
6062
6063 cache.set("double_check_key", "pre_cached", None).unwrap();
6065
6066 let called = Arc::new(Mutex::new(false));
6068 let called_clone = called.clone();
6069 let result: String = cache
6070 .fetch_singleflight("double_check_key", None, || {
6071 *called_clone.lock() = true;
6072 Ok("fetched".to_string())
6073 })
6074 .unwrap();
6075
6076 assert_eq!(result, "pre_cached");
6078 assert!(
6079 !*called.lock(),
6080 "double-check 应命中预缓存,fetcher 不被调用"
6081 );
6082 }
6083
6084 #[test]
6096 fn test_cache_thundering_herd_singleflight_collapses() {
6097 let cache = Arc::new(Cache::new());
6098 cache.register_default(MemoryCacheDriver::new());
6099
6100 let call_count = Arc::new(Mutex::new(0u32));
6101 let num_tasks = 50;
6102 let barrier = Arc::new(Barrier::new(num_tasks));
6103 let mut handles = Vec::new();
6104
6105 for _ in 0..num_tasks {
6106 let cache = Arc::clone(&cache);
6107 let cc = Arc::clone(&call_count);
6108 let barrier = Arc::clone(&barrier);
6109 handles.push(std::thread::spawn(move || {
6110 barrier.wait(); let result: String = cache
6112 .fetch_singleflight("herd_key", None, || {
6113 *cc.lock() += 1;
6115 std::thread::sleep(Duration::from_millis(10));
6116 Ok("single_source".to_string())
6117 })
6118 .unwrap();
6119 result
6120 }));
6121 }
6122
6123 let results: Vec<_> = handles.into_iter().map(|h| h.join().unwrap()).collect();
6124
6125 for r in &results {
6127 assert_eq!(r, "single_source");
6128 }
6129
6130 let calls = *call_count.lock();
6132 assert_eq!(
6133 calls, 1,
6134 "P3-CHAOS-01: 50 并发请求应合并为 1 次实际回源,实际 {} 次",
6135 calls
6136 );
6137 }
6138
6139 #[test]
6145 fn test_cache_slow_backend_timeout_degradation() {
6146 let cache = Cache::new();
6147 cache.register_default(MemoryCacheDriver::new());
6148
6149 let (tx, rx) = std::sync::mpsc::channel::<String>();
6150
6151 let handle = std::thread::spawn(move || {
6153 let result: String = cache
6154 .fetch_singleflight("slow_key", None, || {
6155 std::thread::sleep(Duration::from_millis(500));
6156 Ok("slow_value".to_string())
6157 })
6158 .unwrap();
6159 let _ = tx.send(result);
6160 });
6161
6162 let early = rx.recv_timeout(Duration::from_millis(200));
6164 assert!(
6165 early.is_err(),
6166 "P3-CHAOS-02: 慢回源(500ms)在 200ms 内不应完成,调用方应已触发超时降级"
6167 );
6168
6169 handle.join().unwrap();
6171 let final_val = rx.recv_timeout(Duration::from_secs(2)).unwrap();
6172 assert_eq!(
6173 final_val, "slow_value",
6174 "P3-CHAOS-02: 慢回源完成后结果应正确传播"
6175 );
6176 }
6177
6178 #[test]
6185 fn test_cache_ttl_eviction_under_concurrent_load() {
6186 use std::time::Duration;
6187
6188 let cache = Arc::new(Cache::new());
6189 cache.register_default(MemoryCacheDriver::new());
6190
6191 let num_writers = 16;
6192 let writes_per_writer = 100;
6193 let ttl = Duration::from_millis(50);
6194 let barrier = Arc::new(Barrier::new(num_writers));
6195
6196 let mut handles = Vec::new();
6197
6198 for w in 0..num_writers {
6200 let cache = Arc::clone(&cache);
6201 let barrier = Arc::clone(&barrier);
6202 handles.push(std::thread::spawn(move || {
6203 barrier.wait(); for i in 0..writes_per_writer {
6205 let key = format!("ttl_key_{}", i % 20); let val = format!("writer{}_val{}", w, i);
6207 let _ = cache.set(&key, &val, Some(ttl));
6208 }
6209 }));
6210 }
6211
6212 for h in handles {
6213 h.join().unwrap();
6214 }
6215
6216 std::thread::sleep(ttl * 3);
6218
6219 for i in 0..20 {
6221 let key = format!("ttl_key_{}", i);
6222 let val: Option<String> = cache.get(&key).unwrap();
6223 assert!(
6224 val.is_none(),
6225 "P3-CHAOS-03: key={} 应在 TTL 过期后为 None,实际 {:?}",
6226 key,
6227 val
6228 );
6229 }
6230
6231 cache.set("post_eviction_key", "fresh", None).unwrap();
6233 let val: Option<String> = cache.get("post_eviction_key").unwrap();
6234 assert_eq!(val, Some("fresh".to_string()));
6235 }
6236}