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(Debug, 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}
1802
1803impl Default for RedisConfig {
1804 fn default() -> Self {
1805 Self {
1806 host: "127.0.0.1".to_string(),
1807 port: 6379,
1808 password: String::new(),
1809 select: 0,
1810 timeout: Duration::ZERO,
1811 expire: None,
1812 persistent: false,
1813 prefix: String::new(),
1814 tag_prefix: "tag:".to_string(),
1815 }
1816 }
1817}
1818
1819impl RedisConfig {
1820 pub fn with_prefix(prefix: impl Into<String>) -> Self {
1822 Self {
1823 prefix: prefix.into(),
1824 ..Default::default()
1825 }
1826 }
1827
1828 pub fn with_expire(expire: Duration) -> Self {
1830 Self {
1831 expire: Some(expire),
1832 ..Default::default()
1833 }
1834 }
1835}
1836
1837pub trait RedisBackend: Send + Sync {
1862 fn get(&self, key: &str) -> Result<Option<Vec<u8>>, CacheError>;
1864 fn set(&self, key: &str, value: Vec<u8>) -> Result<(), CacheError>;
1866 fn set_ex(&self, key: &str, value: Vec<u8>, ttl: Duration) -> Result<(), CacheError>;
1868 fn del(&self, key: &str) -> Result<i64, CacheError>;
1870 fn del_many(&self, keys: &[&str]) -> Result<i64, CacheError>;
1872 fn exists(&self, key: &str) -> Result<bool, CacheError>;
1874 fn incr_by(&self, key: &str, step: i64) -> Result<i64, CacheError>;
1876 fn decr_by(&self, key: &str, step: i64) -> Result<i64, CacheError>;
1878 fn flush_db(&self) -> Result<(), CacheError>;
1880 fn sadd(&self, key: &str, member: &str) -> Result<i64, CacheError>;
1882 fn smembers(&self, key: &str) -> Result<Vec<String>, CacheError>;
1884}
1885
1886pub struct MockRedisBackend {
1897 kv: parking_lot::RwLock<MockRedisKv>,
1899 sets: parking_lot::RwLock<MockRedisSets>,
1901}
1902
1903type MockRedisKv = HashMap<String, (Vec<u8>, Option<Instant>)>;
1905
1906type MockRedisSets = HashMap<String, HashSet<String>>;
1908
1909impl Default for MockRedisBackend {
1910 fn default() -> Self {
1911 Self::new()
1912 }
1913}
1914
1915impl MockRedisBackend {
1916 pub fn new() -> Self {
1918 Self {
1919 kv: parking_lot::RwLock::new(HashMap::new()),
1920 sets: parking_lot::RwLock::new(HashMap::new()),
1921 }
1922 }
1923
1924 fn is_expired(kv: &MockRedisKv, key: &str) -> bool {
1926 if let Some((_, Some(expires_at))) = kv.get(key) {
1927 return *expires_at <= Instant::now();
1928 }
1929 false
1930 }
1931}
1932
1933impl RedisBackend for MockRedisBackend {
1934 fn get(&self, key: &str) -> Result<Option<Vec<u8>>, CacheError> {
1935 let kv = self.kv.read();
1936 if Self::is_expired(&kv, key) {
1937 return Ok(None);
1938 }
1939 Ok(kv.get(key).map(|(v, _)| v.clone()))
1940 }
1941
1942 fn set(&self, key: &str, value: Vec<u8>) -> Result<(), CacheError> {
1943 let mut kv = self.kv.write();
1944 kv.insert(key.to_string(), (value, None));
1945 Ok(())
1946 }
1947
1948 fn set_ex(&self, key: &str, value: Vec<u8>, ttl: Duration) -> Result<(), CacheError> {
1949 let mut kv = self.kv.write();
1950 let expires_at = Some(Instant::now() + ttl);
1951 kv.insert(key.to_string(), (value, expires_at));
1952 Ok(())
1953 }
1954
1955 fn del(&self, key: &str) -> Result<i64, CacheError> {
1956 let mut kv = self.kv.write();
1957 let removed = kv.remove(key).is_some() as i64;
1958 let mut sets = self.sets.write();
1960 if sets.remove(key).is_some() && removed == 0 {
1961 return Ok(1);
1962 }
1963 Ok(removed)
1964 }
1965
1966 fn del_many(&self, keys: &[&str]) -> Result<i64, CacheError> {
1967 let mut count = 0i64;
1968 for key in keys {
1969 count += self.del(key)?;
1970 }
1971 Ok(count)
1972 }
1973
1974 fn exists(&self, key: &str) -> Result<bool, CacheError> {
1975 let kv = self.kv.read();
1976 if Self::is_expired(&kv, key) {
1977 return Ok(false);
1978 }
1979 if kv.contains_key(key) {
1980 return Ok(true);
1981 }
1982 let sets = self.sets.read();
1983 Ok(sets.contains_key(key))
1984 }
1985
1986 fn incr_by(&self, key: &str, step: i64) -> Result<i64, CacheError> {
1987 let mut kv = self.kv.write();
1988 if Self::is_expired(&kv, key) {
1990 kv.remove(key);
1991 }
1992 let current = match kv.get(key) {
1993 Some((bytes, _)) => {
1994 let s = std::str::from_utf8(bytes)
1995 .map_err(|e| CacheError::DeserializationError(e.to_string()))?;
1996 s.parse::<i64>().map_err(|e| {
1997 CacheError::Internal(format!("INCRBY failed: '{}' is not an integer: {}", s, e))
1998 })?
1999 }
2000 None => 0, };
2002 let new_value = current + step;
2003 kv.insert(key.to_string(), (new_value.to_string().into_bytes(), None));
2004 Ok(new_value)
2005 }
2006
2007 fn decr_by(&self, key: &str, step: i64) -> Result<i64, CacheError> {
2008 self.incr_by(key, -step)
2010 }
2011
2012 fn flush_db(&self) -> Result<(), CacheError> {
2013 let mut kv = self.kv.write();
2014 kv.clear();
2015 let mut sets = self.sets.write();
2016 sets.clear();
2017 Ok(())
2018 }
2019
2020 fn sadd(&self, key: &str, member: &str) -> Result<i64, CacheError> {
2021 let mut sets = self.sets.write();
2022 let set = sets.entry(key.to_string()).or_default();
2023 let added = set.insert(member.to_string()) as i64;
2024 Ok(added)
2025 }
2026
2027 fn smembers(&self, key: &str) -> Result<Vec<String>, CacheError> {
2028 let sets = self.sets.read();
2029 Ok(sets
2030 .get(key)
2031 .map(|s| s.iter().cloned().collect())
2032 .unwrap_or_default())
2033 }
2034}
2035
2036pub struct RedisCacheDriver {
2088 backend: Box<dyn RedisBackend>,
2089 config: RedisConfig,
2090}
2091
2092impl RedisCacheDriver {
2093 pub fn new(config: RedisConfig) -> Self {
2097 Self::with_backend(config, Box::new(MockRedisBackend::new()))
2098 }
2099
2100 pub fn with_backend(config: RedisConfig, backend: Box<dyn RedisBackend>) -> Self {
2104 Self { backend, config }
2105 }
2106
2107 pub fn config(&self) -> &RedisConfig {
2109 &self.config
2110 }
2111
2112 pub fn backend(&self) -> &dyn RedisBackend {
2114 self.backend.as_ref()
2115 }
2116
2117 pub fn append(&self, name: &str, value: &str) -> Result<(), CacheError> {
2131 let key = self.get_cache_key(name);
2132 self.backend.sadd(&key, value)?;
2133 Ok(())
2134 }
2135
2136 pub fn get_tag_items(&self, tag: &str) -> Result<Vec<String>, CacheError> {
2148 let name = self.get_tag_key(tag);
2149 let key = self.get_cache_key(&name);
2150 self.backend.smembers(&key)
2151 }
2152
2153 pub fn clear_tag(&self, keys: &[&str]) -> Result<(), CacheError> {
2163 self.backend.del_many(keys)?;
2164 Ok(())
2165 }
2166
2167 pub fn tag_key(&self, tag: &str) -> String {
2169 self.get_tag_key(tag)
2170 }
2171
2172 pub fn cache_key(&self, name: &str) -> String {
2174 self.get_cache_key(name)
2175 }
2176}
2177
2178impl CacheDriver for RedisCacheDriver {
2179 fn get_raw(&self, key: &str) -> Result<Option<Vec<u8>>, CacheError> {
2180 let cache_key = self.get_cache_key(key);
2181 self.backend.get(&cache_key)
2182 }
2183
2184 fn set_raw(&self, key: &str, value: Vec<u8>, ttl: Option<Duration>) -> Result<(), CacheError> {
2185 let cache_key = self.get_cache_key(key);
2186 let effective_ttl = ttl.or(self.config.expire);
2188 match effective_ttl {
2190 Some(t) if t > Duration::ZERO => self.backend.set_ex(&cache_key, value, t),
2191 _ => self.backend.set(&cache_key, value),
2192 }
2193 }
2194
2195 fn delete(&self, key: &str) -> Result<(), CacheError> {
2196 let cache_key = self.get_cache_key(key);
2197 self.backend.del(&cache_key)?;
2199 Ok(())
2200 }
2201
2202 fn has(&self, key: &str) -> Result<bool, CacheError> {
2203 let cache_key = self.get_cache_key(key);
2204 self.backend.exists(&cache_key)
2206 }
2207
2208 fn inc(&self, key: &str, step: i64) -> Result<i64, CacheError> {
2224 let cache_key = self.get_cache_key(key);
2225 self.backend.incr_by(&cache_key, step)
2226 }
2227
2228 fn dec(&self, key: &str, step: i64) -> Result<i64, CacheError> {
2230 let cache_key = self.get_cache_key(key);
2231 self.backend.decr_by(&cache_key, step)
2232 }
2233
2234 fn clear(&self) -> Result<(), CacheError> {
2235 self.backend.flush_db()
2237 }
2238
2239 fn get_cache_key(&self, name: &str) -> String {
2247 format!("{}{}", self.config.prefix, name)
2248 }
2249
2250 fn get_tag_key(&self, tag: &str) -> String {
2254 let md5_hex = compute_md5(tag);
2255 format!("{}{}", self.config.tag_prefix, md5_hex)
2256 }
2257
2258 fn tag_append(&self, tag_key: &str, cache_key: &str) -> Result<(), CacheError> {
2272 let key = self.get_cache_key(tag_key);
2273 self.backend.sadd(&key, cache_key)?;
2274 Ok(())
2275 }
2276
2277 fn tag_items(&self, tag: &str) -> Result<Vec<String>, CacheError> {
2289 let name = self.get_tag_key(tag);
2290 let key = self.get_cache_key(&name);
2291 self.backend.smembers(&key)
2292 }
2293
2294 fn tag_clear(&self, keys: &[String]) -> Result<(), CacheError> {
2307 let key_refs: Vec<&str> = keys.iter().map(|s| s.as_str()).collect();
2308 self.backend.del_many(&key_refs)?;
2309 Ok(())
2310 }
2311}
2312
2313pub(crate) fn compute_md5(s: &str) -> String {
2317 let mut hasher = Md5::new();
2318 hasher.update(s.as_bytes());
2319 let result = hasher.finalize();
2320 hex::encode(result)
2321}
2322
2323pub struct MultiLevelCacheDriver {
2353 inner: sz_rust_orm_facade::MultiLevelCache,
2354}
2355
2356impl Default for MultiLevelCacheDriver {
2357 fn default() -> Self {
2358 Self::new()
2359 }
2360}
2361
2362impl MultiLevelCacheDriver {
2363 pub fn new() -> Self {
2365 Self {
2366 inner: sz_rust_orm_facade::MultiLevelCache::new(),
2367 }
2368 }
2369
2370 pub fn add_level(mut self, cache: Box<dyn InnerCache>) -> Self {
2374 self.inner = self.inner.add_cache(cache);
2375 self
2376 }
2377
2378 pub fn inner(&self) -> &sz_rust_orm_facade::MultiLevelCache {
2380 &self.inner
2381 }
2382}
2383
2384impl CacheDriver for MultiLevelCacheDriver {
2385 fn get_raw(&self, key: &str) -> Result<Option<Vec<u8>>, CacheError> {
2386 self.inner.get(key)
2387 }
2388
2389 fn set_raw(&self, key: &str, value: Vec<u8>, ttl: Option<Duration>) -> Result<(), CacheError> {
2390 self.inner.set(key, value, ttl)
2391 }
2392
2393 fn delete(&self, key: &str) -> Result<(), CacheError> {
2394 self.inner.delete(key)
2395 }
2396
2397 fn has(&self, key: &str) -> Result<bool, CacheError> {
2398 self.inner.exists(key)
2399 }
2400
2401 fn inc(&self, key: &str, step: i64) -> Result<i64, CacheError> {
2402 let current = match self.inner.get(key)? {
2405 Some(bytes) => String::from_utf8(bytes)
2406 .map_err(|e| CacheError::DeserializationError(e.to_string()))?
2407 .parse::<i64>()
2408 .unwrap_or(0),
2409 None => 0,
2410 };
2411 let new_value = current + step;
2412 let new_bytes = new_value.to_string().into_bytes();
2413 let ttl = self.inner.ttl(key).ok().flatten();
2415 self.inner.set(key, new_bytes, ttl)?;
2416 Ok(new_value)
2417 }
2418
2419 fn dec(&self, key: &str, step: i64) -> Result<i64, CacheError> {
2420 let current = match self.inner.get(key)? {
2422 Some(bytes) => String::from_utf8(bytes)
2423 .map_err(|e| CacheError::DeserializationError(e.to_string()))?
2424 .parse::<i64>()
2425 .unwrap_or(0),
2426 None => 0,
2427 };
2428 let new_value = current - step;
2429 let new_bytes = new_value.to_string().into_bytes();
2430 let ttl = self.inner.ttl(key).ok().flatten();
2431 self.inner.set(key, new_bytes, ttl)?;
2432 Ok(new_value)
2433 }
2434
2435 fn clear(&self) -> Result<(), CacheError> {
2436 self.inner.clear()
2437 }
2438}
2439
2440pub struct TagSet<'a> {
2495 tags: Vec<String>,
2497 cache: &'a Cache,
2499}
2500
2501impl<'a> TagSet<'a> {
2502 pub fn set<T: Serialize>(
2514 &self,
2515 key: &str,
2516 value: T,
2517 ttl: Option<Duration>,
2518 ) -> Result<(), CacheError> {
2519 self.cache.set(key, value, ttl)?;
2521 self.append(key)
2523 }
2524
2525 pub fn append(&self, key: &str) -> Result<(), CacheError> {
2541 let mgr = self.cache.manager.read();
2542 let driver = mgr.default_store()?;
2543 let cache_key = driver.get_cache_key(key);
2545 for tag in &self.tags {
2547 let tag_key = driver.get_tag_key(tag);
2549 driver.tag_append(&tag_key, &cache_key)?;
2551 }
2552 Ok(())
2553 }
2554
2555 pub fn clear(&self) -> Result<(), CacheError> {
2574 let mgr = self.cache.manager.read();
2575 let driver = mgr.default_store()?;
2576 for tag in &self.tags {
2577 let items = driver.tag_items(tag)?;
2579 driver.tag_clear(&items)?;
2581 let tag_key = driver.get_tag_key(tag);
2583 driver.delete(&tag_key)?;
2585 }
2586 Ok(())
2587 }
2588
2589 pub fn tags(&self) -> &[String] {
2591 &self.tags
2592 }
2593}
2594
2595#[cfg(test)]
2600mod tests {
2601 use crate::*;
2602 use serde::Deserialize;
2603 use std::sync::Barrier;
2604
2605 fn make_cache() -> Cache {
2607 let cache = Cache::new();
2608 cache.register_default(MemoryCacheDriver::new());
2609 cache
2610 }
2611
2612 #[test]
2617 fn test_php_is_numeric_integer() {
2618 assert!(php_is_numeric("42"));
2620 assert!(php_is_numeric("-42"));
2621 assert!(php_is_numeric("+42"));
2622 assert!(php_is_numeric("0"));
2623 }
2624
2625 #[test]
2626 fn test_php_is_numeric_float() {
2627 assert!(php_is_numeric("3.14"));
2629 assert!(php_is_numeric("-3.14"));
2630 assert!(php_is_numeric("+3.14"));
2631 assert!(php_is_numeric("0.0"));
2632 }
2633
2634 #[test]
2635 fn test_php_is_numeric_scientific_notation() {
2636 assert!(php_is_numeric("1e10"));
2638 assert!(php_is_numeric("1.5E-3"));
2639 }
2640
2641 #[test]
2642 fn test_php_is_numeric_non_numeric() {
2643 assert!(!php_is_numeric("abc"));
2645 assert!(!php_is_numeric("12abc"));
2646 assert!(!php_is_numeric(""));
2647 assert!(!php_is_numeric("0x1A")); assert!(!php_is_numeric("null"));
2649 assert!(!php_is_numeric("true"));
2650 }
2651
2652 #[test]
2657 fn test_php_serialize_integer_to_number() {
2658 let v = php_serialize(&42i64).unwrap();
2660 assert!(matches!(v, CacheValue::Number(_)));
2661 if let CacheValue::Number(s) = v {
2662 assert_eq!(s, "42");
2663 }
2664 }
2665
2666 #[test]
2667 fn test_php_serialize_float_to_number() {
2668 let v = php_serialize(&2.5f64).unwrap();
2671 assert!(matches!(v, CacheValue::Number(_)));
2672 if let CacheValue::Number(s) = v {
2673 assert_eq!(s, "2.5");
2674 }
2675 }
2676
2677 #[test]
2678 fn test_php_serialize_string_to_json() {
2679 let v = php_serialize(&"Alice".to_string()).unwrap();
2682 assert!(matches!(v, CacheValue::Json(_)));
2683 if let CacheValue::Json(s) = v {
2684 assert_eq!(s, "\"Alice\"");
2685 }
2686 }
2687
2688 #[test]
2689 fn test_php_serialize_numeric_string_to_number() {
2690 let v = php_serialize(&"42".to_string()).unwrap();
2699 assert!(matches!(v, CacheValue::Json(_))); }
2701
2702 #[test]
2703 fn test_php_serialize_array_to_json() {
2704 let v = php_serialize(&vec![1, 2, 3]).unwrap();
2706 assert!(matches!(v, CacheValue::Json(_)));
2707 if let CacheValue::Json(s) = v {
2708 assert_eq!(s, "[1,2,3]");
2709 }
2710 }
2711
2712 #[test]
2713 fn test_php_unserialize_number_returns_string() {
2714 let v = CacheValue::Number("42".to_string());
2717 let result: Option<String> = php_unserialize(&v).unwrap();
2718 assert_eq!(result, Some("42".to_string()));
2719 }
2720
2721 #[test]
2722 fn test_php_unserialize_json_returns_struct() {
2723 let v = CacheValue::Json("\"Alice\"".to_string());
2725 let result: Option<String> = php_unserialize(&v).unwrap();
2726 assert_eq!(result, Some("Alice".to_string()));
2727
2728 let v = CacheValue::Json("[1,2,3]".to_string());
2729 let result: Option<Vec<i64>> = php_unserialize(&v).unwrap();
2730 assert_eq!(result, Some(vec![1, 2, 3]));
2731 }
2732
2733 #[test]
2734 fn test_php_unserialize_number_to_int_via_parse() {
2735 let v = CacheValue::Number("42".to_string());
2738 let s: String = php_unserialize(&v).unwrap().unwrap();
2739 let n: i64 = s.parse().unwrap();
2740 assert_eq!(n, 42);
2741 }
2742
2743 #[test]
2748 fn test_cache_value_number_roundtrip() {
2749 let v = CacheValue::Number("42".to_string());
2750 let bytes = v.to_bytes();
2751 let restored = CacheValue::from_bytes(&bytes).unwrap();
2752 assert_eq!(v, restored);
2753 }
2754
2755 #[test]
2756 fn test_cache_value_json_roundtrip() {
2757 let v = CacheValue::Json("\"Alice\"".to_string());
2758 let bytes = v.to_bytes();
2759 let restored = CacheValue::from_bytes(&bytes).unwrap();
2760 assert_eq!(v, restored);
2761 }
2762
2763 #[test]
2764 fn test_cache_value_array_roundtrip() {
2765 let v = CacheValue::Json("[1,2,3]".to_string());
2766 let bytes = v.to_bytes();
2767 let restored = CacheValue::from_bytes(&bytes).unwrap();
2768 assert_eq!(v, restored);
2769 }
2770
2771 #[test]
2772 fn test_cache_value_from_bytes_numeric_string_becomes_number() {
2773 let bytes = b"42".to_vec();
2775 let v = CacheValue::from_bytes(&bytes).unwrap();
2776 assert!(matches!(v, CacheValue::Number(_)));
2777 }
2778
2779 #[test]
2780 fn test_cache_value_from_bytes_json_string_becomes_json() {
2781 let bytes = b"\"Alice\"".to_vec();
2783 let v = CacheValue::from_bytes(&bytes).unwrap();
2784 assert!(matches!(v, CacheValue::Json(_)));
2785 }
2786
2787 #[test]
2792 fn test_memory_driver_set_get_raw() {
2793 let driver = MemoryCacheDriver::new();
2794 driver.set_raw("key", b"value".to_vec(), None).unwrap();
2795 let val = driver.get_raw("key").unwrap();
2796 assert_eq!(val, Some(b"value".to_vec()));
2797 }
2798
2799 #[test]
2800 fn test_memory_driver_delete() {
2801 let driver = MemoryCacheDriver::new();
2802 driver.set_raw("key", b"value".to_vec(), None).unwrap();
2803 driver.delete("key").unwrap();
2804 let val = driver.get_raw("key").unwrap();
2805 assert_eq!(val, None);
2806 }
2807
2808 #[test]
2809 fn test_memory_driver_has() {
2810 let driver = MemoryCacheDriver::new();
2811 driver.set_raw("key", b"value".to_vec(), None).unwrap();
2812 assert!(driver.has("key").unwrap());
2813 assert!(!driver.has("nonexistent").unwrap());
2814 }
2815
2816 #[test]
2817 fn test_memory_driver_clear() {
2818 let driver = MemoryCacheDriver::new();
2819 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
2820 driver.set_raw("key2", b"value2".to_vec(), None).unwrap();
2821 driver.clear().unwrap();
2822 assert!(!driver.has("key1").unwrap());
2823 assert!(!driver.has("key2").unwrap());
2824 }
2825
2826 #[test]
2827 fn test_memory_driver_ttl_expiration() {
2828 let driver = MemoryCacheDriver::new();
2829 driver
2830 .set_raw("key", b"value".to_vec(), Some(Duration::from_millis(50)))
2831 .unwrap();
2832 assert!(driver.get_raw("key").unwrap().is_some());
2833 std::thread::sleep(Duration::from_millis(100));
2834 assert!(driver.get_raw("key").unwrap().is_none());
2835 }
2836
2837 #[test]
2838 fn test_memory_driver_inc_default_implementation() {
2839 let driver = MemoryCacheDriver::new();
2841
2842 let v = driver.inc("counter", 5).unwrap();
2844 assert_eq!(v, 5);
2845
2846 let v = driver.inc("counter", 3).unwrap();
2848 assert_eq!(v, 8);
2849 }
2850
2851 #[test]
2852 fn test_memory_driver_dec_default_implementation() {
2853 let driver = MemoryCacheDriver::new();
2854
2855 let v = driver.dec("counter", 3).unwrap();
2857 assert_eq!(v, -3);
2858
2859 let v = driver.dec("counter", 2).unwrap();
2861 assert_eq!(v, -5);
2862 }
2863
2864 #[test]
2869 fn test_cache_manager_register_and_get_default() {
2870 let mut mgr = CacheManager::new();
2871 mgr.register_store("default", Box::new(MemoryCacheDriver::new()));
2872
2873 let driver = mgr.default_store().unwrap();
2874 driver.set_raw("key", b"value".to_vec(), None).unwrap();
2875 assert_eq!(driver.get_raw("key").unwrap(), Some(b"value".to_vec()));
2876 }
2877
2878 #[test]
2879 fn test_cache_manager_multiple_stores_isolation() {
2880 let mut mgr = CacheManager::new();
2881 mgr.register_store("file", Box::new(MemoryCacheDriver::new()));
2882 mgr.register_store("redis", Box::new(MemoryCacheDriver::new()));
2883
2884 let file_driver = mgr.store("file").unwrap();
2885 let redis_driver = mgr.store("redis").unwrap();
2886
2887 file_driver
2888 .set_raw("key", b"file_value".to_vec(), None)
2889 .unwrap();
2890 redis_driver
2891 .set_raw("key", b"redis_value".to_vec(), None)
2892 .unwrap();
2893
2894 assert_eq!(
2896 file_driver.get_raw("key").unwrap(),
2897 Some(b"file_value".to_vec())
2898 );
2899 assert_eq!(
2900 redis_driver.get_raw("key").unwrap(),
2901 Some(b"redis_value".to_vec())
2902 );
2903 }
2904
2905 #[test]
2906 fn test_cache_manager_set_default() {
2907 let mut mgr = CacheManager::new();
2908 mgr.register_store("file", Box::new(MemoryCacheDriver::new()));
2909 mgr.register_store("redis", Box::new(MemoryCacheDriver::new()));
2910
2911 let driver = mgr.default_store().unwrap();
2913 driver.set_raw("file_key", b"file".to_vec(), None).unwrap();
2914 assert_eq!(driver.get_raw("file_key").unwrap(), Some(b"file".to_vec()));
2915
2916 mgr.set_default("redis").unwrap();
2918 let driver = mgr.default_store().unwrap();
2919 driver
2920 .set_raw("redis_key", b"redis".to_vec(), None)
2921 .unwrap();
2922 assert_eq!(
2923 driver.get_raw("redis_key").unwrap(),
2924 Some(b"redis".to_vec())
2925 );
2926 }
2927
2928 #[test]
2929 fn test_cache_manager_default_store_not_registered_error() {
2930 let mgr = CacheManager::new();
2931 let result = mgr.default_store();
2932 assert!(matches!(result, Err(CacheError::NotFound(_))));
2933 }
2934
2935 #[test]
2936 fn test_cache_manager_store_not_found_error() {
2937 let mgr = CacheManager::new();
2938 let result = mgr.store("nonexistent");
2939 assert!(matches!(result, Err(CacheError::NotFound(_))));
2940 }
2941
2942 #[test]
2947 fn test_cache_set_get_string() {
2948 let cache = make_cache();
2949 cache.set("name", "Alice", None).unwrap();
2950 let val: Option<String> = cache.get("name").unwrap();
2951 assert_eq!(val, Some("Alice".to_string()));
2952 }
2953
2954 #[test]
2955 fn test_cache_set_get_int_as_string_php_bug() {
2956 let cache = make_cache();
2959 cache.set("count", 42i64, None).unwrap();
2960
2961 let s: Option<String> = cache.get("count").unwrap();
2964 assert_eq!(s, Some("42".to_string()));
2965
2966 let n: i64 = s.unwrap().parse().unwrap();
2967 assert_eq!(n, 42);
2968 }
2969
2970 #[test]
2971 fn test_cache_set_get_struct() {
2972 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2973 struct User {
2974 name: String,
2975 age: u32,
2976 }
2977
2978 let cache = make_cache();
2979 let user = User {
2980 name: "Alice".to_string(),
2981 age: 30,
2982 };
2983 cache.set("user:1", &user, None).unwrap();
2984
2985 let val: Option<User> = cache.get("user:1").unwrap();
2986 assert_eq!(val, Some(user));
2987 }
2988
2989 #[test]
2990 fn test_cache_set_get_vec() {
2991 let cache = make_cache();
2992 let list = vec![1, 2, 3];
2993 cache.set("list", &list, None).unwrap();
2994
2995 let val: Option<Vec<i64>> = cache.get("list").unwrap();
2996 assert_eq!(val, Some(vec![1, 2, 3]));
2997 }
2998
2999 #[test]
3000 fn test_cache_get_miss_returns_none() {
3001 let cache = make_cache();
3002 let val: Option<String> = cache.get("nonexistent").unwrap();
3003 assert_eq!(val, None);
3004 }
3005
3006 #[test]
3007 fn test_cache_get_or_default_value() {
3008 let cache = make_cache();
3009 let val: String = cache.get_or("nonexistent", "default".to_string()).unwrap();
3010 assert_eq!(val, "default");
3011 }
3012
3013 #[test]
3014 fn test_cache_set_with_ttl_expires() {
3015 let cache = make_cache();
3016 cache
3017 .set("key", "value", Some(Duration::from_millis(50)))
3018 .unwrap();
3019 assert!(cache.get::<String>("key").unwrap().is_some());
3020 std::thread::sleep(Duration::from_millis(100));
3021 assert!(cache.get::<String>("key").unwrap().is_none());
3022 }
3023
3024 #[test]
3029 fn test_cache_delete() {
3030 let cache = make_cache();
3031 cache.set("key", "value", None).unwrap();
3032 assert!(cache.has("key").unwrap());
3033
3034 cache.delete("key").unwrap();
3035 assert!(!cache.has("key").unwrap());
3036
3037 cache.delete("nonexistent").unwrap();
3039 }
3040
3041 #[test]
3042 fn test_cache_has_checks_ttl() {
3043 let cache = make_cache();
3044 cache
3045 .set("key", "value", Some(Duration::from_millis(50)))
3046 .unwrap();
3047 assert!(cache.has("key").unwrap());
3048
3049 std::thread::sleep(Duration::from_millis(100));
3050 assert!(!cache.has("key").unwrap());
3052 }
3053
3054 #[test]
3055 fn test_cache_clear() {
3056 let cache = make_cache();
3057 cache.set("key1", "value1", None).unwrap();
3058 cache.set("key2", "value2", None).unwrap();
3059
3060 cache.clear().unwrap();
3061
3062 assert!(!cache.has("key1").unwrap());
3063 assert!(!cache.has("key2").unwrap());
3064 }
3065
3066 #[test]
3071 fn test_cache_inc_initial_value() {
3072 let cache = make_cache();
3074 let v = cache.inc("counter", 5).unwrap();
3075 assert_eq!(v, 5);
3076
3077 let s: String = cache.get("counter").unwrap().unwrap();
3079 assert_eq!(s, "5");
3080 }
3081
3082 #[test]
3083 fn test_cache_inc_accumulate() {
3084 let cache = make_cache();
3085 cache.inc("counter", 5).unwrap();
3086 cache.inc("counter", 3).unwrap();
3087 let v = cache.inc("counter", 2).unwrap();
3088 assert_eq!(v, 10);
3089 }
3090
3091 #[test]
3092 fn test_cache_dec_initial_value() {
3093 let cache = make_cache();
3095 let v = cache.dec("counter", 3).unwrap();
3096 assert_eq!(v, -3);
3097 }
3098
3099 #[test]
3100 fn test_cache_dec_accumulate() {
3101 let cache = make_cache();
3102 cache.set("counter", 100i64, None).unwrap();
3103 cache.dec("counter", 30).unwrap();
3104 let v = cache.dec("counter", 20).unwrap();
3105 assert_eq!(v, 50);
3106 }
3107
3108 #[test]
3109 fn test_cache_increment_default_step_1() {
3110 let cache = make_cache();
3111 let v = cache.increment("counter").unwrap();
3112 assert_eq!(v, 1);
3113 let v = cache.increment("counter").unwrap();
3114 assert_eq!(v, 2);
3115 }
3116
3117 #[test]
3118 fn test_cache_decrement_default_step_1() {
3119 let cache = make_cache();
3120 let v = cache.decrement("counter").unwrap();
3121 assert_eq!(v, -1);
3122 let v = cache.decrement("counter").unwrap();
3123 assert_eq!(v, -2);
3124 }
3125
3126 #[test]
3131 fn test_cache_pull_existing_key() {
3132 let cache = make_cache();
3134 cache.set("key", "value", None).unwrap();
3135
3136 let val: Option<String> = cache.pull("key").unwrap();
3137 assert_eq!(val, Some("value".to_string()));
3138
3139 assert!(!cache.has("key").unwrap());
3141 }
3142
3143 #[test]
3144 fn test_cache_pull_missing_key_returns_none() {
3145 let cache = make_cache();
3146 let val: Option<String> = cache.pull("nonexistent").unwrap();
3147 assert_eq!(val, None);
3148 }
3149
3150 #[test]
3155 fn test_cache_push_initial_array() {
3156 let cache = make_cache();
3157 cache.push("list", "a".to_string(), None).unwrap();
3158
3159 let val: Option<Vec<String>> = cache.get("list").unwrap();
3160 assert_eq!(val, Some(vec!["a".to_string()]));
3161 }
3162
3163 #[test]
3164 fn test_cache_push_appends() {
3165 let cache = make_cache();
3166 cache.push("list", "a".to_string(), None).unwrap();
3167 cache.push("list", "b".to_string(), None).unwrap();
3168 cache.push("list", "c".to_string(), None).unwrap();
3169
3170 let val: Option<Vec<String>> = cache.get("list").unwrap();
3171 assert_eq!(
3172 val,
3173 Some(vec!["a".to_string(), "b".to_string(), "c".to_string()])
3174 );
3175 }
3176
3177 #[test]
3178 fn test_cache_push_deduplication() {
3179 let cache = make_cache();
3181 cache.push("list", "a".to_string(), None).unwrap();
3182 cache.push("list", "b".to_string(), None).unwrap();
3183 cache.push("list", "a".to_string(), None).unwrap(); cache.push("list", "c".to_string(), None).unwrap();
3185 cache.push("list", "b".to_string(), None).unwrap(); let val: Option<Vec<String>> = cache.get("list").unwrap();
3188 assert_eq!(
3189 val,
3190 Some(vec!["a".to_string(), "b".to_string(), "c".to_string()])
3191 );
3192 }
3193
3194 #[test]
3195 fn test_cache_push_max_1000_fifo() {
3196 let cache = make_cache();
3198
3199 for i in 0..1001i64 {
3201 cache.push("list", i, None).unwrap();
3202 }
3203
3204 let val: Option<Vec<i64>> = cache.get("list").unwrap();
3205 let list = val.unwrap();
3206
3207 assert_eq!(list.len(), 1000);
3209 assert_eq!(list[0], 1);
3211 assert_eq!(list[999], 1000);
3213 }
3214
3215 #[test]
3216 fn test_cache_push_non_array_becomes_array() {
3217 let cache = make_cache();
3219
3220 cache.set("key", "not_an_array".to_string(), None).unwrap();
3222
3223 cache.push("key", "first".to_string(), None).unwrap();
3225
3226 let val: Option<Vec<String>> = cache.get("key").unwrap();
3227 assert_eq!(val, Some(vec!["first".to_string()]));
3228 }
3229
3230 #[tokio::test]
3235 async fn test_cache_remember_cache_miss() {
3236 let cache = make_cache();
3238 let counter = std::sync::Arc::new(std::sync::atomic::AtomicU32::new(0));
3239 let counter_clone = counter.clone();
3240
3241 let val: i64 = cache
3242 .remember("expensive", None, || {
3243 counter_clone.fetch_add(1, std::sync::atomic::Ordering::SeqCst) as i64 + 100
3244 })
3245 .await
3246 .unwrap();
3247 assert_eq!(val, 100);
3248
3249 let val: i64 = cache
3251 .remember("expensive", None, || {
3252 counter_clone.fetch_add(1, std::sync::atomic::Ordering::SeqCst) as i64 + 200
3253 })
3254 .await
3255 .unwrap();
3256 assert_eq!(val, 100); assert_eq!(counter.load(std::sync::atomic::Ordering::SeqCst), 1);
3260 }
3261
3262 #[tokio::test]
3263 async fn test_cache_remember_cache_hit_returns_cached() {
3264 let cache = make_cache();
3265 cache.set("predefined", 42i64, None).unwrap();
3266
3267 let val: i64 = cache
3269 .remember("predefined", None, || {
3270 panic!("callback should not be called on cache hit");
3271 })
3272 .await
3273 .unwrap();
3274 assert_eq!(val, 42);
3275 }
3276
3277 #[tokio::test]
3278 async fn test_cache_remember_writes_with_ttl() {
3279 let cache = make_cache();
3280 cache
3281 .remember("key", Some(Duration::from_millis(50)), || 42i64)
3282 .await
3283 .unwrap();
3284
3285 assert_eq!(cache.get::<String>("key").unwrap(), Some("42".to_string()));
3287
3288 tokio::time::sleep(Duration::from_millis(100)).await;
3290 assert!(cache.get::<String>("key").unwrap().is_none());
3291 }
3292
3293 #[tokio::test]
3294 async fn test_cache_remember_releases_lock_on_success() {
3295 let cache = make_cache();
3297 cache.remember("key", None, || 42i64).await.unwrap();
3298
3299 assert!(!cache.has("key_lock").unwrap());
3301 }
3302
3303 #[tokio::test]
3304 async fn test_cache_remember_releases_lock_on_panic() {
3305 let cache = make_cache();
3311 let _ = cache.remember("key", None, || 42i64).await;
3312 assert!(!cache.has("key_lock").unwrap());
3313 }
3314
3315 #[tokio::test]
3316 async fn test_cache_remember_lock_has_no_ttl_php_bug() {
3317 let cache = make_cache();
3324 cache.remember("key", None, || 42i64).await.unwrap();
3325 assert!(!cache.has("key_lock").unwrap());
3326 }
3327
3328 #[tokio::test]
3329 async fn test_cache_remember_async_cache_miss() {
3330 let cache = make_cache();
3332 let counter = std::sync::Arc::new(std::sync::atomic::AtomicU32::new(0));
3333 let counter_clone = counter.clone();
3334
3335 let val: i64 = cache
3336 .remember_async("expensive_async", None, || {
3337 let counter_clone = counter_clone.clone();
3338 async move {
3339 counter_clone.fetch_add(1, std::sync::atomic::Ordering::SeqCst) as i64 + 100
3340 }
3341 })
3342 .await
3343 .unwrap();
3344 assert_eq!(val, 100);
3345
3346 let val: i64 = cache
3348 .remember_async("expensive_async", None, || {
3349 let counter_clone = counter_clone.clone();
3350 async move {
3351 counter_clone.fetch_add(1, std::sync::atomic::Ordering::SeqCst) as i64 + 200
3352 }
3353 })
3354 .await
3355 .unwrap();
3356 assert_eq!(val, 100);
3357
3358 assert_eq!(counter.load(std::sync::atomic::Ordering::SeqCst), 1);
3359 }
3360
3361 #[tokio::test]
3362 async fn test_cache_remember_async_cache_hit_returns_cached() {
3363 let cache = make_cache();
3364 cache.set("predefined_async", 42i64, None).unwrap();
3365
3366 let val: i64 = cache
3367 .remember_async("predefined_async", None, || async {
3368 panic!("callback should not be called on cache hit");
3369 })
3370 .await
3371 .unwrap();
3372 assert_eq!(val, 42);
3373 }
3374
3375 #[tokio::test]
3376 async fn test_cache_remember_async_writes_with_ttl() {
3377 let cache = make_cache();
3378 cache
3379 .remember_async("key_async", Some(Duration::from_millis(50)), || async {
3380 42i64
3381 })
3382 .await
3383 .unwrap();
3384
3385 assert_eq!(
3386 cache.get::<String>("key_async").unwrap(),
3387 Some("42".to_string())
3388 );
3389
3390 tokio::time::sleep(Duration::from_millis(100)).await;
3391 assert!(cache.get::<String>("key_async").unwrap().is_none());
3392 }
3393
3394 #[tokio::test]
3395 async fn test_cache_remember_async_releases_lock_on_success() {
3396 let cache = make_cache();
3397 cache
3398 .remember_async("key_async", None, || async { 42i64 })
3399 .await
3400 .unwrap();
3401 assert!(!cache.has("key_async_lock").unwrap());
3402 }
3403
3404 #[tokio::test]
3405 async fn test_cache_remember_async_lock_has_no_ttl_php_bug() {
3406 let cache = make_cache();
3407 cache
3408 .remember_async("key_async", None, || async { 42i64 })
3409 .await
3410 .unwrap();
3411 assert!(!cache.has("key_async_lock").unwrap());
3412 }
3413
3414 #[test]
3419 fn test_cache_with_store() {
3420 let cache = Cache::new();
3421 cache.register_store("redis", Box::new(MemoryCacheDriver::new()));
3422
3423 let result = cache
3424 .with_store("redis", |driver| {
3425 driver.set_raw("key", b"value".to_vec(), None)?;
3426 driver.get_raw("key")
3427 })
3428 .unwrap();
3429
3430 assert_eq!(result, Some(b"value".to_vec()));
3431 }
3432
3433 #[test]
3434 fn test_cache_with_store_not_found() {
3435 let cache = Cache::new();
3436 let result: Result<Option<Vec<u8>>, CacheError> =
3437 cache.with_store("nonexistent", |driver| driver.get_raw("key"));
3438 assert!(matches!(result, Err(CacheError::NotFound(_))));
3439 }
3440
3441 #[test]
3446 fn test_default_cache_singleton() {
3447 let c1 = default_cache();
3448 let c2 = default_cache();
3449 assert!(std::ptr::eq(c1, c2));
3451 }
3452
3453 #[test]
3461 fn test_r5_php_set_get_basic_alignment() {
3462 let cache = make_cache();
3467 cache.set("name", "Alice", None).unwrap();
3468 let val: String = cache.get("name").unwrap().unwrap();
3469 assert_eq!(val, "Alice");
3470 }
3471
3472 #[test]
3473 fn test_r5_php_is_numeric_short_circuit() {
3474 let cache = make_cache();
3479 cache.set("count", 42i64, None).unwrap();
3480
3481 let s: String = cache.get("count").unwrap().unwrap();
3483 assert_eq!(s, "42");
3484 }
3485
3486 #[test]
3487 fn test_r5_php_inc_no_serialize() {
3488 let cache = make_cache();
3491 cache.set("counter", 100i64, None).unwrap();
3492 let new_val = cache.inc("counter", 50).unwrap();
3493 assert_eq!(new_val, 150);
3494
3495 let s: String = cache.get("counter").unwrap().unwrap();
3497 assert_eq!(s, "150");
3498 }
3499
3500 #[test]
3501 fn test_r5_php_dec_no_serialize() {
3502 let cache = make_cache();
3504 cache.set("counter", 100i64, None).unwrap();
3505 let new_val = cache.dec("counter", 30).unwrap();
3506 assert_eq!(new_val, 70);
3507 }
3508
3509 #[tokio::test]
3510 async fn test_r5_php_remember_lock_mechanism() {
3511 let cache = make_cache();
3514 let val: i64 = cache.remember("key", None, || 42).await.unwrap();
3515 assert_eq!(val, 42);
3516 assert_eq!(cache.get::<String>("key").unwrap(), Some("42".to_string()));
3517 assert!(!cache.has("key_lock").unwrap());
3519 }
3520
3521 #[test]
3522 fn test_r5_php_push_max_1000_array_shift() {
3523 let cache = make_cache();
3525 for i in 0..1001i64 {
3526 cache.push("list", i, None).unwrap();
3527 }
3528 let list: Vec<i64> = cache.get("list").unwrap().unwrap();
3529 assert_eq!(list.len(), 1000);
3530 assert_eq!(list[0], 1); assert_eq!(list[999], 1000);
3532 }
3533
3534 #[test]
3535 fn test_r5_php_push_array_unique() {
3536 let cache = make_cache();
3538 cache.push("list", "a".to_string(), None).unwrap();
3539 cache.push("list", "a".to_string(), None).unwrap();
3540 cache.push("list", "b".to_string(), None).unwrap();
3541 cache.push("list", "a".to_string(), None).unwrap();
3542
3543 let list: Vec<String> = cache.get("list").unwrap().unwrap();
3544 assert_eq!(list, vec!["a".to_string(), "b".to_string()]);
3545 }
3546
3547 #[test]
3548 fn test_r5_php_pull_get_then_delete() {
3549 let cache = make_cache();
3551 cache.set("key", "value", None).unwrap();
3552
3553 let val: Option<String> = cache.pull("key").unwrap();
3554 assert_eq!(val, Some("value".to_string()));
3555 assert!(!cache.has("key").unwrap());
3556 }
3557
3558 #[test]
3559 fn test_r5_php_delete_nonexistent_no_error() {
3560 let cache = make_cache();
3562 let result = cache.delete("nonexistent");
3563 assert!(result.is_ok());
3564 }
3565
3566 #[test]
3567 fn test_r5_php_has_ttl_expiration() {
3568 let cache = make_cache();
3570 cache
3571 .set("key", "value", Some(Duration::from_millis(50)))
3572 .unwrap();
3573 assert!(cache.has("key").unwrap());
3574
3575 std::thread::sleep(Duration::from_millis(100));
3576 assert!(!cache.has("key").unwrap());
3577 }
3578
3579 #[test]
3580 fn test_r5_php_clear_all_keys() {
3581 let cache = make_cache();
3583 cache.set("key1", "value1", None).unwrap();
3584 cache.set("key2", "value2", None).unwrap();
3585 cache.set("key3", "value3", None).unwrap();
3586
3587 cache.clear().unwrap();
3588
3589 assert!(!cache.has("key1").unwrap());
3590 assert!(!cache.has("key2").unwrap());
3591 assert!(!cache.has("key3").unwrap());
3592 }
3593
3594 #[test]
3599 fn test_php_bug_unserialize_numeric_returns_string() {
3600 let cache = make_cache();
3613
3614 cache.set("count", 42i64, None).unwrap();
3616
3617 let s: String = cache.get("count").unwrap().unwrap();
3619 assert_eq!(s, "42");
3620
3621 let n: i64 = s.parse().unwrap();
3623 assert_eq!(n, 42);
3624 }
3625
3626 #[tokio::test]
3627 async fn test_php_bug_remember_lock_no_ttl() {
3628 let cache = make_cache();
3636 cache.remember("key", None, || 42i64).await.unwrap();
3637 assert!(!cache.has("key_lock").unwrap());
3639 }
3640
3641 #[tokio::test]
3642 async fn test_php_bug_remember_has_get_double_check() {
3643 let cache = make_cache();
3660 let val: i64 = cache.remember("key", None, || 42).await.unwrap();
3661 assert_eq!(val, 42);
3662 }
3663
3664 #[test]
3665 fn test_php_behavior_set_overwrite() {
3666 let cache = make_cache();
3668 cache.set("key", "first", None).unwrap();
3669 cache.set("key", "second", None).unwrap();
3670
3671 let val: String = cache.get("key").unwrap().unwrap();
3672 assert_eq!(val, "second");
3673 }
3674
3675 #[test]
3676 fn test_php_behavior_ttl_permanent() {
3677 let cache = make_cache();
3679 cache.set("key", "value", None).unwrap();
3680
3681 assert!(cache.has("key").unwrap());
3683
3684 std::thread::sleep(Duration::from_millis(50));
3686 assert!(cache.has("key").unwrap());
3687 }
3688
3689 #[test]
3694 fn test_redis_config_default() {
3695 let config = RedisConfig::default();
3697 assert_eq!(config.host, "127.0.0.1");
3698 assert_eq!(config.port, 6379);
3699 assert_eq!(config.password, "");
3700 assert_eq!(config.select, 0);
3701 assert_eq!(config.timeout, Duration::ZERO);
3702 assert_eq!(config.expire, None);
3703 assert!(!config.persistent);
3704 assert_eq!(config.prefix, "");
3705 assert_eq!(config.tag_prefix, "tag:");
3706 }
3707
3708 #[test]
3709 fn test_redis_config_with_prefix() {
3710 let config = RedisConfig::with_prefix("myapp:");
3711 assert_eq!(config.prefix, "myapp:");
3712 assert_eq!(config.host, "127.0.0.1");
3713 assert_eq!(config.tag_prefix, "tag:");
3714 }
3715
3716 #[test]
3717 fn test_redis_config_with_expire() {
3718 let config = RedisConfig::with_expire(Duration::from_secs(3600));
3719 assert_eq!(config.expire, Some(Duration::from_secs(3600)));
3720 assert_eq!(config.prefix, "");
3721 }
3722
3723 #[test]
3728 fn test_mock_redis_set_get_roundtrip() {
3729 let backend = MockRedisBackend::new();
3730 backend.set("key1", b"value1".to_vec()).unwrap();
3731 let val = backend.get("key1").unwrap();
3732 assert_eq!(val, Some(b"value1".to_vec()));
3733 }
3734
3735 #[test]
3736 fn test_mock_redis_del() {
3737 let backend = MockRedisBackend::new();
3738 backend.set("key1", b"value1".to_vec()).unwrap();
3739 let removed = backend.del("key1").unwrap();
3740 assert_eq!(removed, 1);
3741 assert_eq!(backend.get("key1").unwrap(), None);
3742 assert_eq!(backend.del("key1").unwrap(), 0);
3744 }
3745
3746 #[test]
3747 fn test_mock_redis_exists() {
3748 let backend = MockRedisBackend::new();
3749 assert!(!backend.exists("key1").unwrap());
3750 backend.set("key1", b"value1".to_vec()).unwrap();
3751 assert!(backend.exists("key1").unwrap());
3752 }
3753
3754 #[test]
3755 fn test_mock_redis_incr_by_new_key() {
3756 let backend = MockRedisBackend::new();
3758 let result = backend.incr_by("counter", 5).unwrap();
3759 assert_eq!(result, 5);
3760 let val = backend.get("counter").unwrap();
3762 assert_eq!(val, Some(b"5".to_vec()));
3763 }
3764
3765 #[test]
3766 fn test_mock_redis_incr_by_existing_key() {
3767 let backend = MockRedisBackend::new();
3768 backend.set("counter", b"10".to_vec()).unwrap();
3769 let result = backend.incr_by("counter", 5).unwrap();
3770 assert_eq!(result, 15);
3771 let val = backend.get("counter").unwrap();
3772 assert_eq!(val, Some(b"15".to_vec()));
3773 }
3774
3775 #[test]
3776 fn test_mock_redis_incr_by_non_integer_error() {
3777 let backend = MockRedisBackend::new();
3779 backend.set("key", b"not_a_number".to_vec()).unwrap();
3780 let result = backend.incr_by("key", 1);
3781 assert!(result.is_err());
3782 }
3783
3784 #[test]
3785 fn test_mock_redis_decr_by() {
3786 let backend = MockRedisBackend::new();
3787 let result = backend.decr_by("counter", 3).unwrap();
3788 assert_eq!(result, -3);
3789 }
3790
3791 #[test]
3796 fn test_mock_redis_set_ex_and_expire() {
3797 let backend = MockRedisBackend::new();
3798 backend
3799 .set_ex("key1", b"value1".to_vec(), Duration::from_millis(50))
3800 .unwrap();
3801 assert!(backend.get("key1").unwrap().is_some());
3802 std::thread::sleep(Duration::from_millis(80));
3803 assert_eq!(backend.get("key1").unwrap(), None);
3804 }
3805
3806 #[test]
3807 fn test_mock_redis_expired_key_exists_false() {
3808 let backend = MockRedisBackend::new();
3809 backend
3810 .set_ex("key1", b"value1".to_vec(), Duration::from_millis(50))
3811 .unwrap();
3812 assert!(backend.exists("key1").unwrap());
3813 std::thread::sleep(Duration::from_millis(80));
3814 assert!(!backend.exists("key1").unwrap());
3815 }
3816
3817 #[test]
3822 fn test_mock_redis_sadd_smembers() {
3823 let backend = MockRedisBackend::new();
3824 backend.sadd("tag:users", "user:1").unwrap();
3825 backend.sadd("tag:users", "user:2").unwrap();
3826 backend.sadd("tag:users", "user:3").unwrap();
3827 let members = backend.smembers("tag:users").unwrap();
3828 assert_eq!(members.len(), 3);
3829 assert!(members.contains(&"user:1".to_string()));
3830 assert!(members.contains(&"user:2".to_string()));
3831 assert!(members.contains(&"user:3".to_string()));
3832 }
3833
3834 #[test]
3835 fn test_mock_redis_sadd_dedup() {
3836 let backend = MockRedisBackend::new();
3838 let added1 = backend.sadd("tag:users", "user:1").unwrap();
3839 assert_eq!(added1, 1);
3840 let added2 = backend.sadd("tag:users", "user:1").unwrap();
3841 assert_eq!(added2, 0);
3842 let members = backend.smembers("tag:users").unwrap();
3843 assert_eq!(members.len(), 1);
3844 }
3845
3846 #[test]
3847 fn test_mock_redis_smembers_nonexistent_key() {
3848 let backend = MockRedisBackend::new();
3850 let members = backend.smembers("nonexistent").unwrap();
3851 assert!(members.is_empty());
3852 }
3853
3854 #[test]
3859 fn test_mock_redis_flush_db() {
3860 let backend = MockRedisBackend::new();
3861 backend.set("key1", b"v1".to_vec()).unwrap();
3862 backend.set("key2", b"v2".to_vec()).unwrap();
3863 backend.sadd("tag:1", "m1").unwrap();
3864 backend.flush_db().unwrap();
3865 assert_eq!(backend.get("key1").unwrap(), None);
3866 assert_eq!(backend.get("key2").unwrap(), None);
3867 assert!(backend.smembers("tag:1").unwrap().is_empty());
3868 }
3869
3870 #[test]
3871 fn test_mock_redis_del_many() {
3872 let backend = MockRedisBackend::new();
3873 backend.set("key1", b"v1".to_vec()).unwrap();
3874 backend.set("key2", b"v2".to_vec()).unwrap();
3875 backend.set("key3", b"v3".to_vec()).unwrap();
3876 let removed = backend.del_many(&["key1", "key2", "nonexistent"]).unwrap();
3877 assert_eq!(removed, 2);
3878 assert_eq!(backend.get("key1").unwrap(), None);
3879 assert_eq!(backend.get("key2").unwrap(), None);
3880 assert!(backend.get("key3").unwrap().is_some());
3881 }
3882
3883 fn make_redis_driver() -> RedisCacheDriver {
3889 RedisCacheDriver::new(RedisConfig::default())
3890 }
3891
3892 #[test]
3893 fn test_redis_driver_set_get_roundtrip() {
3894 let driver = make_redis_driver();
3895 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
3896 let val = driver.get_raw("key1").unwrap();
3897 assert_eq!(val, Some(b"value1".to_vec()));
3898 }
3899
3900 #[test]
3901 fn test_redis_driver_delete() {
3902 let driver = make_redis_driver();
3903 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
3904 driver.delete("key1").unwrap();
3905 assert_eq!(driver.get_raw("key1").unwrap(), None);
3906 }
3907
3908 #[test]
3909 fn test_redis_driver_has() {
3910 let driver = make_redis_driver();
3911 assert!(!driver.has("key1").unwrap());
3912 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
3913 assert!(driver.has("key1").unwrap());
3914 }
3915
3916 #[test]
3917 fn test_redis_driver_clear() {
3918 let driver = make_redis_driver();
3919 driver.set_raw("key1", b"v1".to_vec(), None).unwrap();
3920 driver.set_raw("key2", b"v2".to_vec(), None).unwrap();
3921 driver.clear().unwrap();
3922 assert_eq!(driver.get_raw("key1").unwrap(), None);
3923 assert_eq!(driver.get_raw("key2").unwrap(), None);
3924 }
3925
3926 #[test]
3927 fn test_redis_driver_inc_dec() {
3928 let driver = make_redis_driver();
3929 let result = driver.inc("counter", 5).unwrap();
3931 assert_eq!(result, 5);
3932 let result = driver.inc("counter", 3).unwrap();
3933 assert_eq!(result, 8);
3934 let result = driver.dec("counter", 2).unwrap();
3935 assert_eq!(result, 6);
3936 }
3937
3938 #[test]
3943 fn test_redis_driver_cache_key_with_prefix() {
3944 let driver = RedisCacheDriver::new(RedisConfig::with_prefix("myapp:"));
3946 assert_eq!(driver.cache_key("user:1"), "myapp:user:1");
3947 }
3948
3949 #[test]
3950 fn test_redis_driver_cache_key_no_prefix() {
3951 let driver = RedisCacheDriver::new(RedisConfig::default());
3952 assert_eq!(driver.cache_key("user:1"), "user:1");
3953 }
3954
3955 #[test]
3956 fn test_redis_driver_tag_key_md5() {
3957 let driver = RedisCacheDriver::new(RedisConfig::default());
3959 let tag_key = driver.tag_key("users");
3960 let expected_md5 = compute_md5("users");
3961 assert_eq!(tag_key, format!("tag:{}", expected_md5));
3962 }
3963
3964 #[test]
3965 fn test_redis_driver_tag_key_custom_prefix() {
3966 let config = RedisConfig {
3967 tag_prefix: "t:".to_string(),
3968 ..RedisConfig::default()
3969 };
3970 let driver = RedisCacheDriver::new(config);
3971 let tag_key = driver.tag_key("users");
3972 let expected_md5 = compute_md5("users");
3973 assert_eq!(tag_key, format!("t:{}", expected_md5));
3974 }
3975
3976 #[test]
3981 fn test_redis_driver_prefix_applied_to_set() {
3982 let driver = RedisCacheDriver::new(RedisConfig::with_prefix("myapp:"));
3984 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
3985 let val = driver.backend().get("myapp:key1").unwrap();
3987 assert_eq!(val, Some(b"value1".to_vec()));
3988 assert_eq!(driver.backend().get("key1").unwrap(), None);
3990 }
3991
3992 #[test]
3993 fn test_redis_driver_prefix_applied_to_get() {
3994 let driver = RedisCacheDriver::new(RedisConfig::with_prefix("myapp:"));
3995 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
3996 let val = driver.get_raw("key1").unwrap();
3997 assert_eq!(val, Some(b"value1".to_vec()));
3998 }
3999
4000 #[test]
4001 fn test_redis_driver_prefix_applied_to_delete() {
4002 let driver = RedisCacheDriver::new(RedisConfig::with_prefix("myapp:"));
4003 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
4004 driver.delete("key1").unwrap();
4005 assert_eq!(driver.backend().get("myapp:key1").unwrap(), None);
4006 }
4007
4008 #[test]
4009 fn test_redis_driver_prefix_applied_to_has() {
4010 let driver = RedisCacheDriver::new(RedisConfig::with_prefix("myapp:"));
4011 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
4012 assert!(driver.has("key1").unwrap());
4013 assert!(driver.backend().exists("myapp:key1").unwrap());
4014 }
4015
4016 #[test]
4017 fn test_redis_driver_prefix_applied_to_inc() {
4018 let driver = RedisCacheDriver::new(RedisConfig::with_prefix("myapp:"));
4019 let result = driver.inc("counter", 5).unwrap();
4020 assert_eq!(result, 5);
4021 let val = driver.backend().get("myapp:counter").unwrap();
4022 assert_eq!(val, Some(b"5".to_vec()));
4023 }
4024
4025 #[test]
4030 fn test_redis_driver_append_and_get_tag_items() {
4031 let driver = make_redis_driver();
4033 driver.append("tag:users", "user:1").unwrap();
4034 driver.append("tag:users", "user:2").unwrap();
4035 driver.append("tag:users", "user:3").unwrap();
4036 let members = driver.backend().smembers("tag:users").unwrap();
4037 assert_eq!(members.len(), 3);
4038 }
4039
4040 #[test]
4041 fn test_redis_driver_get_tag_items_with_tag_key() {
4042 let driver = make_redis_driver();
4044 let tag_name = driver.tag_key("users");
4045 driver.append(&tag_name, "user:1").unwrap();
4046 driver.append(&tag_name, "user:2").unwrap();
4047 let members = driver.get_tag_items("users").unwrap();
4048 assert_eq!(members.len(), 2);
4049 assert!(members.contains(&"user:1".to_string()));
4050 assert!(members.contains(&"user:2".to_string()));
4051 }
4052
4053 #[test]
4054 fn test_redis_driver_clear_tag() {
4055 let driver = make_redis_driver();
4056 driver.set_raw("key1", b"v1".to_vec(), None).unwrap();
4057 driver.set_raw("key2", b"v2".to_vec(), None).unwrap();
4058 driver.clear_tag(&["key1", "key2"]).unwrap();
4059 assert_eq!(driver.get_raw("key1").unwrap(), None);
4060 assert_eq!(driver.get_raw("key2").unwrap(), None);
4061 }
4062
4063 #[test]
4068 fn test_redis_driver_set_with_ttl_uses_setex() {
4069 let driver = make_redis_driver();
4071 driver
4072 .set_raw("key1", b"value1".to_vec(), Some(Duration::from_millis(100)))
4073 .unwrap();
4074 assert!(driver.get_raw("key1").unwrap().is_some());
4075 std::thread::sleep(Duration::from_millis(150));
4076 assert_eq!(driver.get_raw("key1").unwrap(), None);
4077 }
4078
4079 #[test]
4080 fn test_redis_driver_set_without_ttl_uses_set() {
4081 let driver = make_redis_driver();
4083 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
4084 std::thread::sleep(Duration::from_millis(50));
4085 assert!(driver.get_raw("key1").unwrap().is_some());
4086 }
4087
4088 #[test]
4089 fn test_redis_driver_set_with_config_expire() {
4090 let config = RedisConfig::with_expire(Duration::from_millis(100));
4092 let driver = RedisCacheDriver::new(config);
4093 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
4094 assert!(driver.get_raw("key1").unwrap().is_some());
4095 std::thread::sleep(Duration::from_millis(150));
4096 assert_eq!(driver.get_raw("key1").unwrap(), None);
4097 }
4098
4099 #[test]
4100 fn test_redis_driver_set_ttl_overrides_config_expire() {
4101 let config = RedisConfig::with_expire(Duration::from_secs(3600));
4103 let driver = RedisCacheDriver::new(config);
4104 driver
4105 .set_raw("key1", b"value1".to_vec(), Some(Duration::from_millis(50)))
4106 .unwrap();
4107 std::thread::sleep(Duration::from_millis(80));
4108 assert_eq!(driver.get_raw("key1").unwrap(), None);
4109 }
4110
4111 #[test]
4116 fn test_redis_driver_with_cache_facade() {
4117 let cache = Cache::new();
4119 let driver = RedisCacheDriver::new(RedisConfig::default());
4120 cache.register_store("redis", Box::new(driver));
4121 cache.set_default_store("redis").unwrap();
4122 cache.set("key", "value", None).unwrap();
4123 let val: String = cache.get("key").unwrap().unwrap();
4124 assert_eq!(val, "value");
4125 }
4126
4127 #[test]
4128 fn test_redis_driver_with_cache_facade_inc() {
4129 let cache = Cache::new();
4131 let driver = RedisCacheDriver::new(RedisConfig::default());
4132 cache.register_store("redis", Box::new(driver));
4133 cache.set_default_store("redis").unwrap();
4134 let result = cache.inc("counter", 5).unwrap();
4135 assert_eq!(result, 5);
4136 let result = cache.inc("counter", 3).unwrap();
4137 assert_eq!(result, 8);
4138 }
4139
4140 #[test]
4145 fn test_php_redis_inc_not_through_serialize() {
4146 let driver = make_redis_driver();
4151 driver.inc("counter", 5).unwrap();
4152 let val = driver.backend().get(&driver.cache_key("counter")).unwrap();
4153 assert_eq!(val, Some(b"5".to_vec())); assert_ne!(val, Some(b"i:5;".to_vec())); }
4156
4157 #[test]
4158 fn test_php_redis_set_with_ttl_expires() {
4159 let driver = make_redis_driver();
4161 driver
4162 .set_raw("key", b"value".to_vec(), Some(Duration::from_millis(50)))
4163 .unwrap();
4164 assert!(driver.get_raw("key").unwrap().is_some());
4165 std::thread::sleep(Duration::from_millis(80));
4166 assert_eq!(driver.get_raw("key").unwrap(), None);
4167 }
4168
4169 #[test]
4170 fn test_php_redis_set_without_ttl_permanent() {
4171 let driver = make_redis_driver();
4173 driver.set_raw("key", b"value".to_vec(), None).unwrap();
4174 std::thread::sleep(Duration::from_millis(50));
4175 assert!(driver.get_raw("key").unwrap().is_some());
4176 }
4177
4178 #[test]
4179 fn test_php_redis_tag_key_format() {
4180 let driver = make_redis_driver();
4182 let tag_key = driver.tag_key("users");
4183 let expected = format!("tag:{}", compute_md5("users"));
4184 assert_eq!(tag_key, expected);
4185 assert_eq!(compute_md5("users").len(), 32);
4186 }
4187
4188 #[test]
4189 fn test_php_redis_clear_uses_flushdb() {
4190 let driver = make_redis_driver();
4192 driver.set_raw("key1", b"v1".to_vec(), None).unwrap();
4193 driver.set_raw("key2", b"v2".to_vec(), None).unwrap();
4194 driver.append("tag:1", "m1").unwrap();
4195 driver.clear().unwrap();
4196 assert_eq!(driver.get_raw("key1").unwrap(), None);
4197 assert_eq!(driver.get_raw("key2").unwrap(), None);
4198 assert!(driver.backend().smembers("tag:1").unwrap().is_empty());
4199 }
4200
4201 #[test]
4202 fn test_php_redis_inc_returns_new_value() {
4203 let driver = make_redis_driver();
4205 let r1 = driver.inc("c", 1).unwrap();
4206 assert_eq!(r1, 1);
4207 let r2 = driver.inc("c", 1).unwrap();
4208 assert_eq!(r2, 2);
4209 let r3 = driver.inc("c", 10).unwrap();
4210 assert_eq!(r3, 12);
4211 let r4 = driver.dec("c", 5).unwrap();
4212 assert_eq!(r4, 7);
4213 }
4214
4215 #[test]
4216 fn test_php_redis_delete_nonexistent_returns_ok() {
4217 let driver = make_redis_driver();
4219 driver.delete("nonexistent").unwrap();
4220 }
4221
4222 #[test]
4223 fn test_php_redis_md5_alignment() {
4224 assert_eq!(compute_md5("hello"), "5d41402abc4b2a76b9719d911017c592");
4227 assert_eq!(compute_md5(""), "d41d8cd98f00b204e9800998ecf8427e");
4229 assert_eq!(compute_md5("users").len(), 32);
4230 }
4231
4232 #[test]
4233 fn test_php_redis_append_uses_sadd() {
4234 let driver = make_redis_driver();
4237 driver.append("tag:1", "m1").unwrap();
4238 driver.append("tag:1", "m1").unwrap(); driver.append("tag:1", "m2").unwrap();
4240 let members = driver.backend().smembers("tag:1").unwrap();
4241 assert_eq!(members.len(), 2);
4243 }
4244
4245 #[test]
4246 fn test_php_redis_config_precedence_ttl() {
4247 let config = RedisConfig::with_expire(Duration::from_secs(3600));
4250 let driver = RedisCacheDriver::new(config);
4251 driver
4252 .set_raw("key1", b"v1".to_vec(), Some(Duration::from_millis(50)))
4253 .unwrap();
4254 std::thread::sleep(Duration::from_millis(80));
4255 assert_eq!(driver.get_raw("key1").unwrap(), None); let config = RedisConfig::with_expire(Duration::from_millis(50));
4259 let driver = RedisCacheDriver::new(config);
4260 driver.set_raw("key2", b"v2".to_vec(), None).unwrap();
4261 std::thread::sleep(Duration::from_millis(80));
4262 assert_eq!(driver.get_raw("key2").unwrap(), None); let driver = make_redis_driver();
4266 driver.set_raw("key3", b"v3".to_vec(), None).unwrap();
4267 std::thread::sleep(Duration::from_millis(50));
4268 assert!(driver.get_raw("key3").unwrap().is_some()); }
4270
4271 #[test]
4276 fn test_multi_level_driver_set_get() {
4277 let l1 = sz_rust_orm_facade::MemoryCache::new();
4278 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4279
4280 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
4281 let val = driver.get_raw("key1").unwrap();
4282 assert_eq!(val, Some(b"value1".to_vec()));
4283 }
4284
4285 #[test]
4286 fn test_multi_level_driver_delete() {
4287 let l1 = sz_rust_orm_facade::MemoryCache::new();
4288 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4289
4290 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
4291 driver.delete("key1").unwrap();
4292 assert_eq!(driver.get_raw("key1").unwrap(), None);
4293 }
4294
4295 #[test]
4296 fn test_multi_level_driver_has() {
4297 let l1 = sz_rust_orm_facade::MemoryCache::new();
4298 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4299
4300 assert!(!driver.has("key1").unwrap());
4301 driver.set_raw("key1", b"value1".to_vec(), None).unwrap();
4302 assert!(driver.has("key1").unwrap());
4303 }
4304
4305 #[test]
4306 fn test_multi_level_driver_clear() {
4307 let l1 = sz_rust_orm_facade::MemoryCache::new();
4308 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4309
4310 driver.set_raw("key1", b"v1".to_vec(), None).unwrap();
4311 driver.set_raw("key2", b"v2".to_vec(), None).unwrap();
4312 driver.clear().unwrap();
4313 assert_eq!(driver.get_raw("key1").unwrap(), None);
4314 assert_eq!(driver.get_raw("key2").unwrap(), None);
4315 }
4316
4317 #[test]
4322 fn test_multi_level_two_levels_cascade_get() {
4323 let l1 = sz_rust_orm_facade::MemoryCache::new();
4325 let l2 = sz_rust_orm_facade::MemoryCache::new();
4326
4327 l2.set("key", b"from_l2".to_vec(), None).unwrap();
4329
4330 let driver = MultiLevelCacheDriver::new()
4331 .add_level(Box::new(l1.clone()))
4332 .add_level(Box::new(l2));
4333
4334 let val = driver.get_raw("key").unwrap();
4336 assert_eq!(val, Some(b"from_l2".to_vec()));
4337
4338 let l1_val = l1.get("key").unwrap();
4340 assert_eq!(l1_val, Some(b"from_l2".to_vec()));
4341 }
4342
4343 #[test]
4344 fn test_multi_level_set_writes_all_levels() {
4345 let l1 = sz_rust_orm_facade::MemoryCache::new();
4346 let l2 = sz_rust_orm_facade::MemoryCache::new();
4347
4348 let driver = MultiLevelCacheDriver::new()
4349 .add_level(Box::new(l1.clone()))
4350 .add_level(Box::new(l2.clone()));
4351
4352 driver.set_raw("key", b"value".to_vec(), None).unwrap();
4353
4354 assert_eq!(l1.get("key").unwrap(), Some(b"value".to_vec()));
4356 assert_eq!(l2.get("key").unwrap(), Some(b"value".to_vec()));
4357 }
4358
4359 #[test]
4360 fn test_multi_level_delete_removes_all_levels() {
4361 let l1 = sz_rust_orm_facade::MemoryCache::new();
4362 let l2 = sz_rust_orm_facade::MemoryCache::new();
4363
4364 let driver = MultiLevelCacheDriver::new()
4365 .add_level(Box::new(l1.clone()))
4366 .add_level(Box::new(l2.clone()));
4367
4368 driver.set_raw("key", b"value".to_vec(), None).unwrap();
4369 driver.delete("key").unwrap();
4370
4371 assert_eq!(l1.get("key").unwrap(), None);
4372 assert_eq!(l2.get("key").unwrap(), None);
4373 }
4374
4375 #[test]
4376 fn test_multi_level_l1_hit_skips_l2() {
4377 let l1 = sz_rust_orm_facade::MemoryCache::new();
4379 let l2 = sz_rust_orm_facade::MemoryCache::new();
4380
4381 l1.set("key", b"from_l1".to_vec(), None).unwrap();
4382 l2.set("key", b"from_l2".to_vec(), None).unwrap();
4383
4384 let driver = MultiLevelCacheDriver::new()
4385 .add_level(Box::new(l1))
4386 .add_level(Box::new(l2));
4387
4388 let val = driver.get_raw("key").unwrap();
4389 assert_eq!(val, Some(b"from_l1".to_vec()));
4390 }
4391
4392 #[test]
4397 fn test_multi_level_driver_inc_initial_value() {
4398 let l1 = sz_rust_orm_facade::MemoryCache::new();
4399 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4400
4401 let new_val = driver.inc("counter", 1).unwrap();
4402 assert_eq!(new_val, 1);
4403
4404 let val = driver.get_raw("counter").unwrap();
4405 assert_eq!(val, Some(b"1".to_vec()));
4406 }
4407
4408 #[test]
4409 fn test_multi_level_driver_inc_accumulate() {
4410 let l1 = sz_rust_orm_facade::MemoryCache::new();
4411 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4412
4413 driver.inc("counter", 5).unwrap();
4414 driver.inc("counter", 3).unwrap();
4415 driver.inc("counter", 1).unwrap();
4416
4417 let val = driver.get_raw("counter").unwrap();
4418 assert_eq!(val, Some(b"9".to_vec()));
4419 }
4420
4421 #[test]
4422 fn test_multi_level_driver_dec() {
4423 let l1 = sz_rust_orm_facade::MemoryCache::new();
4424 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4425
4426 driver.set_raw("counter", b"10".to_vec(), None).unwrap();
4427 let new_val = driver.dec("counter", 3).unwrap();
4428 assert_eq!(new_val, 7);
4429
4430 let val = driver.get_raw("counter").unwrap();
4431 assert_eq!(val, Some(b"7".to_vec()));
4432 }
4433
4434 #[test]
4435 fn test_multi_level_driver_inc_preserves_ttl() {
4436 let l1 = sz_rust_orm_facade::MemoryCache::new();
4438 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4439
4440 driver
4441 .set_raw("counter", b"5".to_vec(), Some(Duration::from_millis(200)))
4442 .unwrap();
4443
4444 let ttl_before = driver.inner().ttl("counter").unwrap();
4446 assert!(ttl_before.is_some());
4447
4448 driver.inc("counter", 1).unwrap();
4449
4450 let ttl_after = driver.inner().ttl("counter").unwrap();
4452 assert!(ttl_after.is_some());
4453 }
4454
4455 #[test]
4460 fn test_multi_level_driver_ttl_expiration() {
4461 let l1 = sz_rust_orm_facade::MemoryCache::new();
4462 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4463
4464 driver
4465 .set_raw("key", b"value".to_vec(), Some(Duration::from_millis(50)))
4466 .unwrap();
4467 assert!(driver.get_raw("key").unwrap().is_some());
4468
4469 std::thread::sleep(Duration::from_millis(80));
4470 assert_eq!(driver.get_raw("key").unwrap(), None);
4471 }
4472
4473 #[test]
4474 fn test_multi_level_driver_has_checks_ttl() {
4475 let l1 = sz_rust_orm_facade::MemoryCache::new();
4476 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4477
4478 driver
4479 .set_raw("key", b"value".to_vec(), Some(Duration::from_millis(50)))
4480 .unwrap();
4481 assert!(driver.has("key").unwrap());
4482
4483 std::thread::sleep(Duration::from_millis(80));
4484 assert!(!driver.has("key").unwrap());
4485 }
4486
4487 #[test]
4492 fn test_multi_level_driver_with_cache_facade() {
4493 let l1 = sz_rust_orm_facade::MemoryCache::new();
4494 let l2 = sz_rust_orm_facade::MemoryCache::new();
4495 let driver = MultiLevelCacheDriver::new()
4496 .add_level(Box::new(l1))
4497 .add_level(Box::new(l2));
4498
4499 let cache = Cache::new();
4500 cache.register_store("default", Box::new(driver));
4501
4502 cache.set("user:1", "Alice", None).unwrap();
4503 assert_eq!(
4504 cache.get::<String>("user:1").unwrap(),
4505 Some("Alice".to_string())
4506 );
4507
4508 cache.delete("user:1").unwrap();
4509 assert_eq!(cache.get::<String>("user:1").unwrap(), None);
4510 }
4511
4512 #[test]
4513 fn test_multi_level_driver_with_cache_facade_inc() {
4514 let l1 = sz_rust_orm_facade::MemoryCache::new();
4515 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4516
4517 let cache = Cache::new();
4518 cache.register_store("default", Box::new(driver));
4519
4520 cache.inc("counter", 5).unwrap();
4521 cache.inc("counter", 3).unwrap();
4522
4523 let val = cache.get::<String>("counter").unwrap();
4526 assert_eq!(val, Some("8".to_string()));
4527 }
4528
4529 #[test]
4534 fn test_multi_level_driver_empty_levels_get_returns_none() {
4535 let driver = MultiLevelCacheDriver::new();
4537 assert_eq!(driver.get_raw("key").unwrap(), None);
4538 }
4539
4540 #[test]
4541 fn test_multi_level_driver_empty_levels_has_returns_false() {
4542 let driver = MultiLevelCacheDriver::new();
4543 assert!(!driver.has("key").unwrap());
4544 }
4545
4546 #[test]
4547 fn test_multi_level_driver_inc_non_numeric_value_resets_to_step() {
4548 let l1 = sz_rust_orm_facade::MemoryCache::new();
4550 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4551
4552 driver
4553 .set_raw("counter", b"not_a_number".to_vec(), None)
4554 .unwrap();
4555 let new_val = driver.inc("counter", 5).unwrap();
4556 assert_eq!(new_val, 5);
4557 }
4558
4559 #[test]
4560 fn test_multi_level_driver_default_impl() {
4561 let driver = MultiLevelCacheDriver::default();
4563 assert_eq!(driver.get_raw("key").unwrap(), None);
4564 }
4565
4566 #[test]
4571 fn test_r5_multi_level_get_set_basic() {
4572 let l1 = sz_rust_orm_facade::MemoryCache::new();
4574 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4575
4576 driver.set_raw("key", b"value".to_vec(), None).unwrap();
4577 assert_eq!(driver.get_raw("key").unwrap(), Some(b"value".to_vec()));
4578 }
4579
4580 #[test]
4581 fn test_r5_multi_level_delete_nonexistent_no_error() {
4582 let l1 = sz_rust_orm_facade::MemoryCache::new();
4584 let driver = MultiLevelCacheDriver::new().add_level(Box::new(l1));
4585
4586 assert!(driver.delete("nonexistent").is_ok());
4587 }
4588
4589 #[test]
4590 fn test_r5_multi_level_clear_empties_all() {
4591 let l1 = sz_rust_orm_facade::MemoryCache::new();
4593 let l2 = sz_rust_orm_facade::MemoryCache::new();
4594 let driver = MultiLevelCacheDriver::new()
4595 .add_level(Box::new(l1))
4596 .add_level(Box::new(l2));
4597
4598 driver.set_raw("k1", b"v1".to_vec(), None).unwrap();
4599 driver.set_raw("k2", b"v2".to_vec(), None).unwrap();
4600 driver.clear().unwrap();
4601
4602 assert_eq!(driver.get_raw("k1").unwrap(), None);
4603 assert_eq!(driver.get_raw("k2").unwrap(), None);
4604 }
4605
4606 #[test]
4607 fn test_r5_multi_level_cascade_fill_back() {
4608 let l1 = sz_rust_orm_facade::MemoryCache::new();
4610 let l2 = sz_rust_orm_facade::MemoryCache::new();
4611
4612 l2.set("key", b"from_l2".to_vec(), None).unwrap();
4614
4615 let driver = MultiLevelCacheDriver::new()
4616 .add_level(Box::new(l1.clone()))
4617 .add_level(Box::new(l2));
4618
4619 let val = driver.get_raw("key").unwrap();
4621 assert_eq!(val, Some(b"from_l2".to_vec()));
4622
4623 assert_eq!(l1.get("key").unwrap(), Some(b"from_l2".to_vec()));
4625 }
4626
4627 #[test]
4632 fn test_tag_get_cache_key_default_no_prefix() {
4633 let driver = MemoryCacheDriver::new();
4635 assert_eq!(driver.get_cache_key("user:1"), "user:1");
4636 assert_eq!(driver.get_cache_key("hello"), "hello");
4637 }
4638
4639 #[test]
4640 fn test_tag_get_tag_key_default_format() {
4641 let driver = MemoryCacheDriver::new();
4643 let tag_key = driver.get_tag_key("user");
4644 assert_eq!(tag_key, "tag:ee11cbb19052e40b07aac0ca060c23ee");
4646 }
4647
4648 #[test]
4649 fn test_tag_append_creates_new_tag_set() {
4650 let driver = MemoryCacheDriver::new();
4652 driver.tag_append("tag:abc123", "user:1").unwrap();
4653 let storage_key = "tag:abc123"; let raw = driver.get_raw(storage_key).unwrap();
4656 let stored: Vec<String> = serde_json::from_slice(&raw.unwrap()).unwrap();
4657 assert_eq!(stored, vec!["user:1"]);
4658 }
4659
4660 #[test]
4661 fn test_tag_append_appends_to_existing() {
4662 let driver = MemoryCacheDriver::new();
4663 driver.tag_append("tag:abc", "key1").unwrap();
4664 driver.tag_append("tag:abc", "key2").unwrap();
4665 let storage_key = "tag:abc";
4666 let raw = driver.get_raw(storage_key).unwrap();
4667 let stored: Vec<String> = serde_json::from_slice(&raw.unwrap()).unwrap();
4668 assert_eq!(stored, vec!["key1", "key2"]);
4669 }
4670
4671 #[test]
4672 fn test_tag_append_dedup() {
4673 let driver = MemoryCacheDriver::new();
4675 driver.tag_append("tag:abc", "key1").unwrap();
4676 driver.tag_append("tag:abc", "key1").unwrap(); let storage_key = "tag:abc";
4678 let raw = driver.get_raw(storage_key).unwrap();
4679 let stored: Vec<String> = serde_json::from_slice(&raw.unwrap()).unwrap();
4680 assert_eq!(stored, vec!["key1"]);
4681 }
4682
4683 #[test]
4684 fn test_tag_append_max_1000_cap() {
4685 let driver = MemoryCacheDriver::new();
4687 for i in 0..1001i64 {
4688 driver.tag_append("tag:abc", &format!("key{}", i)).unwrap();
4689 }
4690 let storage_key = "tag:abc";
4691 let raw = driver.get_raw(storage_key).unwrap();
4692 let stored: Vec<String> = serde_json::from_slice(&raw.unwrap()).unwrap();
4693 assert_eq!(stored.len(), 1000);
4695 assert!(!stored.contains(&"key0".to_string()));
4696 assert!(stored.contains(&"key1".to_string()));
4697 assert!(stored.contains(&"key1000".to_string()));
4698 }
4699
4700 #[test]
4701 fn test_tag_items_empty_returns_empty() {
4702 let driver = MemoryCacheDriver::new();
4703 let items = driver.tag_items("nonexistent_tag").unwrap();
4704 assert!(items.is_empty());
4705 }
4706
4707 #[test]
4708 fn test_tag_items_returns_stored_keys() {
4709 let driver = MemoryCacheDriver::new();
4710 let tag_key = driver.get_tag_key("mytag");
4712 driver.tag_append(&tag_key, "key1").unwrap();
4713 driver.tag_append(&tag_key, "key2").unwrap();
4714 let items = driver.tag_items("mytag").unwrap();
4715 assert_eq!(items, vec!["key1", "key2"]);
4716 }
4717
4718 #[test]
4719 fn test_tag_clear_deletes_keys() {
4720 let driver = MemoryCacheDriver::new();
4721 driver.set_raw("key1", b"v1".to_vec(), None).unwrap();
4723 driver.set_raw("key2", b"v2".to_vec(), None).unwrap();
4724 driver
4726 .tag_clear(&["key1".to_string(), "key2".to_string()])
4727 .unwrap();
4728 assert!(!driver.has("key1").unwrap());
4729 assert!(!driver.has("key2").unwrap());
4730 }
4731
4732 #[test]
4733 fn test_tag_clear_empty_no_error() {
4734 let driver = MemoryCacheDriver::new();
4735 driver.tag_clear(&[]).unwrap();
4737 }
4738
4739 #[test]
4744 fn test_redis_tag_get_cache_key_with_prefix() {
4745 let config = RedisConfig {
4746 prefix: "myapp:".to_string(),
4747 ..RedisConfig::default()
4748 };
4749 let driver = RedisCacheDriver::new(config);
4750 assert_eq!(driver.get_cache_key("user:1"), "myapp:user:1");
4751 }
4752
4753 #[test]
4754 fn test_redis_tag_get_tag_key_with_tag_prefix() {
4755 let config = RedisConfig {
4756 tag_prefix: "tag:".to_string(),
4757 ..RedisConfig::default()
4758 };
4759 let driver = RedisCacheDriver::new(config);
4760 let tag_key = driver.get_tag_key("user");
4761 assert_eq!(tag_key, "tag:ee11cbb19052e40b07aac0ca060c23ee");
4763 }
4764
4765 #[test]
4766 fn test_redis_tag_get_tag_key_custom_prefix() {
4767 let config = RedisConfig {
4768 tag_prefix: "t:".to_string(),
4769 ..RedisConfig::default()
4770 };
4771 let driver = RedisCacheDriver::new(config);
4772 let tag_key = driver.get_tag_key("user");
4773 assert_eq!(tag_key, "t:ee11cbb19052e40b07aac0ca060c23ee");
4774 }
4775
4776 #[test]
4777 fn test_redis_tag_append_uses_sadd() {
4778 let driver = RedisCacheDriver::new(RedisConfig::default());
4780 let tag_key = driver.get_tag_key("mytag");
4781 driver.tag_append(&tag_key, "key1").unwrap();
4782 driver.tag_append(&tag_key, "key2").unwrap();
4783 driver.tag_append(&tag_key, "key1").unwrap(); let items = driver.tag_items("mytag").unwrap();
4785 assert_eq!(items.len(), 2);
4787 assert!(items.contains(&"key1".to_string()));
4788 assert!(items.contains(&"key2".to_string()));
4789 }
4790
4791 #[test]
4792 fn test_redis_tag_items_uses_smembers() {
4793 let driver = RedisCacheDriver::new(RedisConfig::default());
4794 let tag_key = driver.get_tag_key("mytag");
4795 driver.tag_append(&tag_key, "a").unwrap();
4796 driver.tag_append(&tag_key, "b").unwrap();
4797 driver.tag_append(&tag_key, "c").unwrap();
4798 let items = driver.tag_items("mytag").unwrap();
4799 assert_eq!(items.len(), 3);
4800 }
4801
4802 #[test]
4803 fn test_redis_tag_clear_does_not_double_prefix() {
4804 let config = RedisConfig {
4806 prefix: "app:".to_string(),
4807 ..RedisConfig::default()
4808 };
4809 let driver = RedisCacheDriver::new(config);
4810 driver.set_raw("key1", b"v1".to_vec(), None).unwrap();
4812 let tag_key = driver.get_tag_key("mytag");
4814 driver.tag_append(&tag_key, "app:key1").unwrap();
4815 let items = driver.tag_items("mytag").unwrap();
4816 assert_eq!(items, vec!["app:key1"]);
4817 driver.tag_clear(&items).unwrap();
4819 assert!(!driver.has("key1").unwrap());
4820 }
4821
4822 #[test]
4823 fn test_redis_tag_clear_empty_no_error() {
4824 let driver = RedisCacheDriver::new(RedisConfig::default());
4825 driver.tag_clear(&[]).unwrap();
4826 }
4827
4828 #[test]
4833 fn test_tagset_set_stores_value_and_appends_tag() {
4834 let cache = Cache::new();
4835 cache.register_default(MemoryCacheDriver::new());
4836
4837 cache.tag("user").set("user:1", "Alice", None).unwrap();
4839
4840 assert_eq!(
4842 cache.get::<String>("user:1").unwrap(),
4843 Some("Alice".to_string())
4844 );
4845
4846 let mgr = cache.manager.read();
4848 let driver = mgr.default_store().unwrap();
4849 let items = driver.tag_items("user").unwrap();
4850 assert_eq!(items, vec!["user:1"]);
4851 }
4852
4853 #[test]
4854 fn test_tagset_set_multiple_keys_same_tag() {
4855 let cache = Cache::new();
4856 cache.register_default(MemoryCacheDriver::new());
4857
4858 cache.tag("user").set("user:1", "Alice", None).unwrap();
4859 cache.tag("user").set("user:2", "Bob", None).unwrap();
4860 cache.tag("user").set("user:3", "Carol", None).unwrap();
4861
4862 let mgr = cache.manager.read();
4863 let driver = mgr.default_store().unwrap();
4864 let items = driver.tag_items("user").unwrap();
4865 assert_eq!(items, vec!["user:1", "user:2", "user:3"]);
4866 }
4867
4868 #[test]
4869 fn test_tagset_clear_deletes_all_tagged_keys() {
4870 let cache = Cache::new();
4871 cache.register_default(MemoryCacheDriver::new());
4872
4873 cache.tag("user").set("user:1", "Alice", None).unwrap();
4874 cache.tag("user").set("user:2", "Bob", None).unwrap();
4875 cache.tag("user").set("user:3", "Carol", None).unwrap();
4876
4877 cache.tag("user").clear().unwrap();
4879
4880 assert!(cache.get::<String>("user:1").unwrap().is_none());
4881 assert!(cache.get::<String>("user:2").unwrap().is_none());
4882 assert!(cache.get::<String>("user:3").unwrap().is_none());
4883 }
4884
4885 #[test]
4886 fn test_tagset_clear_deletes_tag_key() {
4887 let cache = Cache::new();
4888 cache.register_default(MemoryCacheDriver::new());
4889
4890 cache.tag("user").set("user:1", "Alice", None).unwrap();
4891
4892 let mgr = cache.manager.read();
4894 let driver = mgr.default_store().unwrap();
4895 let tag_key = driver.get_tag_key("user");
4896 assert!(driver.has(&tag_key).unwrap());
4897 drop(mgr);
4898
4899 cache.tag("user").clear().unwrap();
4900
4901 let mgr = cache.manager.read();
4903 let driver = mgr.default_store().unwrap();
4904 assert!(!driver.has(&tag_key).unwrap());
4905 }
4906
4907 #[test]
4908 fn test_tagset_clear_empty_tag_no_error() {
4909 let cache = Cache::new();
4910 cache.register_default(MemoryCacheDriver::new());
4911
4912 cache.tag("empty").clear().unwrap();
4914 }
4915
4916 #[test]
4917 fn test_tagset_append_adds_key_to_tag() {
4918 let cache = Cache::new();
4919 cache.register_default(MemoryCacheDriver::new());
4920
4921 cache.set("user:1", "Alice", None).unwrap();
4923 cache.tag("user").append("user:1").unwrap();
4925
4926 let mgr = cache.manager.read();
4927 let driver = mgr.default_store().unwrap();
4928 let items = driver.tag_items("user").unwrap();
4929 assert_eq!(items, vec!["user:1"]);
4930 }
4931
4932 #[test]
4933 fn test_tagset_many_tags_single_key() {
4934 let cache = Cache::new();
4935 cache.register_default(MemoryCacheDriver::new());
4936
4937 cache
4939 .tag_many(&["user", "admin"])
4940 .set("key1", "val", None)
4941 .unwrap();
4942
4943 let mgr = cache.manager.read();
4945 let driver = mgr.default_store().unwrap();
4946 let user_items = driver.tag_items("user").unwrap();
4947 let admin_items = driver.tag_items("admin").unwrap();
4948 assert_eq!(user_items, vec!["key1"]);
4949 assert_eq!(admin_items, vec!["key1"]);
4950 }
4951
4952 #[test]
4953 fn test_tagset_many_tags_clear_one() {
4954 let cache = Cache::new();
4955 cache.register_default(MemoryCacheDriver::new());
4956
4957 cache
4958 .tag_many(&["user", "admin"])
4959 .set("key1", "val", None)
4960 .unwrap();
4961
4962 cache.tag("user").clear().unwrap();
4964
4965 assert!(cache.get::<String>("key1").unwrap().is_none());
4967
4968 let mgr = cache.manager.read();
4971 let driver = mgr.default_store().unwrap();
4972 let admin_items = driver.tag_items("admin").unwrap();
4973 assert_eq!(admin_items, vec!["key1"]); let user_tag_key = driver.get_tag_key("user");
4976 assert!(!driver.has(&user_tag_key).unwrap());
4977 }
4978
4979 #[test]
4980 fn test_tagset_tags_getter() {
4981 let cache = Cache::new();
4982 let ts = cache.tag_many(&["a", "b", "c"]);
4983 assert_eq!(ts.tags(), &["a", "b", "c"]);
4984 }
4985
4986 #[test]
4991 fn test_redis_tagset_set_stores_value_and_appends_tag() {
4992 let cache = Cache::new();
4993 let driver = RedisCacheDriver::new(RedisConfig::default());
4994 cache.register_store("redis", Box::new(driver));
4995
4996 cache.tag("user").set("user:1", "Alice", None).unwrap();
4997
4998 assert_eq!(
5000 cache.get::<String>("user:1").unwrap(),
5001 Some("Alice".to_string())
5002 );
5003
5004 let mgr = cache.manager.read();
5006 let driver = mgr.default_store().unwrap();
5007 let items = driver.tag_items("user").unwrap();
5008 assert_eq!(items, vec!["user:1"]);
5009 }
5010
5011 #[test]
5012 fn test_redis_tagset_set_with_prefix() {
5013 let cache = Cache::new();
5014 let config = RedisConfig {
5015 prefix: "app:".to_string(),
5016 ..RedisConfig::default()
5017 };
5018 let driver = RedisCacheDriver::new(config);
5019 cache.register_store("redis", Box::new(driver));
5020
5021 cache.tag("user").set("user:1", "Alice", None).unwrap();
5022
5023 let mgr = cache.manager.read();
5025 let driver = mgr.default_store().unwrap();
5026 let items = driver.tag_items("user").unwrap();
5027 assert_eq!(items, vec!["app:user:1"]);
5028 }
5029
5030 #[test]
5031 fn test_redis_tagset_clear_deletes_all_tagged_keys() {
5032 let cache = Cache::new();
5033 let driver = RedisCacheDriver::new(RedisConfig::default());
5034 cache.register_store("redis", Box::new(driver));
5035
5036 cache.tag("user").set("user:1", "Alice", None).unwrap();
5037 cache.tag("user").set("user:2", "Bob", None).unwrap();
5038 cache.tag("user").set("user:3", "Carol", None).unwrap();
5039
5040 cache.tag("user").clear().unwrap();
5041
5042 assert!(cache.get::<String>("user:1").unwrap().is_none());
5043 assert!(cache.get::<String>("user:2").unwrap().is_none());
5044 assert!(cache.get::<String>("user:3").unwrap().is_none());
5045 }
5046
5047 #[test]
5048 fn test_redis_tagset_clear_deletes_tag_key() {
5049 let cache = Cache::new();
5050 let driver = RedisCacheDriver::new(RedisConfig::default());
5051 cache.register_store("redis", Box::new(driver));
5052
5053 cache.tag("user").set("user:1", "Alice", None).unwrap();
5054
5055 let mgr = cache.manager.read();
5056 let driver = mgr.default_store().unwrap();
5057 let tag_key = driver.get_tag_key("user");
5058 assert!(driver.has(&tag_key).unwrap());
5060 drop(mgr);
5061
5062 cache.tag("user").clear().unwrap();
5063
5064 let mgr = cache.manager.read();
5065 let driver = mgr.default_store().unwrap();
5066 assert!(!driver.has(&tag_key).unwrap());
5067 }
5068
5069 #[test]
5070 fn test_redis_tagset_many_tags() {
5071 let cache = Cache::new();
5072 let driver = RedisCacheDriver::new(RedisConfig::default());
5073 cache.register_store("redis", Box::new(driver));
5074
5075 cache
5076 .tag_many(&["user", "admin"])
5077 .set("key1", "val", None)
5078 .unwrap();
5079
5080 let mgr = cache.manager.read();
5081 let driver = mgr.default_store().unwrap();
5082 let user_items = driver.tag_items("user").unwrap();
5083 let admin_items = driver.tag_items("admin").unwrap();
5084 assert_eq!(user_items, vec!["key1"]);
5085 assert_eq!(admin_items, vec!["key1"]);
5086 }
5087
5088 #[test]
5093 fn test_r5_php_tag_set_then_clear() {
5094 let cache = Cache::new();
5096 cache.register_default(MemoryCacheDriver::new());
5097
5098 cache.tag("user").set("u1", "Alice", None).unwrap();
5099 cache.tag("user").set("u2", "Bob", None).unwrap();
5100
5101 cache.set("other", "data", None).unwrap();
5103
5104 cache.tag("user").clear().unwrap();
5105
5106 assert!(cache.get::<String>("u1").unwrap().is_none());
5108 assert!(cache.get::<String>("u2").unwrap().is_none());
5109 assert_eq!(
5111 cache.get::<String>("other").unwrap(),
5112 Some("data".to_string())
5113 );
5114 }
5115
5116 #[test]
5117 fn test_r5_php_tag_multiple_tags_clear() {
5118 let cache = Cache::new();
5120 cache.register_default(MemoryCacheDriver::new());
5121
5122 cache
5124 .tag_many(&["user", "admin"])
5125 .set("key1", "v1", None)
5126 .unwrap();
5127 cache.tag("user").set("key2", "v2", None).unwrap();
5129
5130 cache.tag("user").clear().unwrap();
5132
5133 assert!(cache.get::<String>("key1").unwrap().is_none());
5134 assert!(cache.get::<String>("key2").unwrap().is_none());
5135 }
5136
5137 #[test]
5138 fn test_r5_php_tag_get_cache_key_prefix() {
5139 let cache = Cache::new();
5141 cache.register_default(MemoryCacheDriver::new());
5142 let mgr = cache.manager.read();
5143 let driver = mgr.default_store().unwrap();
5144 assert_eq!(driver.get_cache_key("test"), "test");
5145 }
5146
5147 #[test]
5148 fn test_r5_php_tag_get_tag_key_md5() {
5149 let cache = Cache::new();
5151 cache.register_default(MemoryCacheDriver::new());
5152 let mgr = cache.manager.read();
5153 let driver = mgr.default_store().unwrap();
5154 assert_eq!(
5156 driver.get_tag_key("hello"),
5157 "tag:5d41402abc4b2a76b9719d911017c592"
5158 );
5159 }
5160
5161 #[test]
5162 fn test_r5_php_tag_push_max_1000_array_shift() {
5163 let driver = MemoryCacheDriver::new();
5165 for i in 0..1005i64 {
5166 driver.tag_append("tag:test", &format!("key{}", i)).unwrap();
5167 }
5168 let storage_key = "tag:test";
5169 let raw = driver.get_raw(storage_key).unwrap();
5170 let stored: Vec<String> = serde_json::from_slice(&raw.unwrap()).unwrap();
5171 assert_eq!(stored.len(), 1000);
5173 assert!(!stored.contains(&"key0".to_string()));
5175 assert!(!stored.contains(&"key4".to_string()));
5176 assert!(stored.contains(&"key5".to_string()));
5178 assert!(stored.contains(&"key1004".to_string()));
5179 }
5180
5181 #[test]
5182 fn test_r5_php_tag_push_array_unique() {
5183 let driver = MemoryCacheDriver::new();
5185 driver.tag_append("tag:u", "a").unwrap();
5186 driver.tag_append("tag:u", "b").unwrap();
5187 driver.tag_append("tag:u", "a").unwrap(); driver.tag_append("tag:u", "c").unwrap();
5189 driver.tag_append("tag:u", "b").unwrap(); let storage_key = "tag:u";
5192 let raw = driver.get_raw(storage_key).unwrap();
5193 let stored: Vec<String> = serde_json::from_slice(&raw.unwrap()).unwrap();
5194 assert_eq!(stored, vec!["a", "b", "c"]);
5196 }
5197
5198 #[test]
5199 fn test_r5_php_tag_singleton_equivalent() {
5200 let cache = Cache::new();
5202 cache.register_default(MemoryCacheDriver::new());
5203
5204 cache.tag("user").set("u1", "Alice", None).unwrap();
5206 cache.tag("user").set("u2", "Bob", None).unwrap();
5208
5209 let mgr = cache.manager.read();
5211 let driver = mgr.default_store().unwrap();
5212 let items = driver.tag_items("user").unwrap();
5213 assert_eq!(items, vec!["u1", "u2"]);
5214
5215 cache.tag("user").clear().unwrap();
5217 assert!(cache.get::<String>("u1").unwrap().is_none());
5218 assert!(cache.get::<String>("u2").unwrap().is_none());
5219 }
5220
5221 #[test]
5222 fn test_r5_php_tag_clear_then_set_again() {
5223 let cache = Cache::new();
5225 cache.register_default(MemoryCacheDriver::new());
5226
5227 cache.tag("user").set("u1", "Alice", None).unwrap();
5228 cache.tag("user").clear().unwrap();
5229 assert!(cache.get::<String>("u1").unwrap().is_none());
5230
5231 cache.tag("user").set("u1", "Alice2", None).unwrap();
5233 assert_eq!(
5234 cache.get::<String>("u1").unwrap(),
5235 Some("Alice2".to_string())
5236 );
5237
5238 let mgr = cache.manager.read();
5240 let driver = mgr.default_store().unwrap();
5241 let items = driver.tag_items("user").unwrap();
5242 assert_eq!(items, vec!["u1"]);
5243 }
5244
5245 #[test]
5246 fn test_r5_php_tag_redis_set_then_clear() {
5247 let cache = Cache::new();
5249 let driver = RedisCacheDriver::new(RedisConfig::default());
5250 cache.register_store("redis", Box::new(driver));
5251
5252 cache.tag("article").set("a:1", "Hello", None).unwrap();
5253 cache.tag("article").set("a:2", "World", None).unwrap();
5254 cache.set("untagged", "data", None).unwrap();
5255
5256 cache.tag("article").clear().unwrap();
5257
5258 assert!(cache.get::<String>("a:1").unwrap().is_none());
5259 assert!(cache.get::<String>("a:2").unwrap().is_none());
5260 assert_eq!(
5262 cache.get::<String>("untagged").unwrap(),
5263 Some("data".to_string())
5264 );
5265 }
5266
5267 #[test]
5268 fn test_r5_php_tag_redis_with_prefix() {
5269 let cache = Cache::new();
5271 let config = RedisConfig {
5272 prefix: "myapp:".to_string(),
5273 tag_prefix: "tag:".to_string(),
5274 ..RedisConfig::default()
5275 };
5276 let driver = RedisCacheDriver::new(config);
5277 cache.register_store("redis", Box::new(driver));
5278
5279 cache.tag("user").set("u1", "Alice", None).unwrap();
5280
5281 let mgr = cache.manager.read();
5283 let driver = mgr.default_store().unwrap();
5284 let items = driver.tag_items("user").unwrap();
5285 assert_eq!(items, vec!["myapp:u1"]);
5286
5287 drop(mgr);
5289 cache.tag("user").clear().unwrap();
5290 assert!(cache.get::<String>("u1").unwrap().is_none());
5291 }
5292
5293 #[test]
5294 fn test_r5_php_tag_different_tags_isolation() {
5295 let cache = Cache::new();
5297 cache.register_default(MemoryCacheDriver::new());
5298
5299 cache.tag("user").set("u1", "Alice", None).unwrap();
5300 cache.tag("article").set("a1", "Hello", None).unwrap();
5301
5302 cache.tag("user").clear().unwrap();
5304
5305 assert!(cache.get::<String>("u1").unwrap().is_none());
5306 assert_eq!(
5307 cache.get::<String>("a1").unwrap(),
5308 Some("Hello".to_string())
5309 );
5310 }
5311
5312 #[test]
5313 fn test_r5_php_tag_set_with_ttl() {
5314 let cache = Cache::new();
5316 cache.register_default(MemoryCacheDriver::new());
5317
5318 cache
5319 .tag("user")
5320 .set("u1", "Alice", Some(Duration::from_millis(50)))
5321 .unwrap();
5322
5323 assert_eq!(
5324 cache.get::<String>("u1").unwrap(),
5325 Some("Alice".to_string())
5326 );
5327
5328 std::thread::sleep(Duration::from_millis(60));
5329 assert!(cache.get::<String>("u1").unwrap().is_none());
5330 }
5331
5332 #[test]
5337 fn test_delete_many_multiple_keys() {
5338 let cache = Cache::new();
5340 cache.register_default(MemoryCacheDriver::new());
5341 cache.set("k1", "v1", None).unwrap();
5342 cache.set("k2", "v2", None).unwrap();
5343 cache.set("k3", "v3", None).unwrap();
5344
5345 cache.delete_many(&["k1", "k2", "k3"]).unwrap();
5346
5347 assert!(cache.get::<String>("k1").unwrap().is_none());
5348 assert!(cache.get::<String>("k2").unwrap().is_none());
5349 assert!(cache.get::<String>("k3").unwrap().is_none());
5350 }
5351
5352 #[test]
5353 fn test_delete_many_nonexistent_keys_ok() {
5354 let cache = Cache::new();
5356 cache.register_default(MemoryCacheDriver::new());
5357 cache.set("exists", "v", None).unwrap();
5358
5359 let result = cache.delete_many(&["exists", "nonexistent"]);
5361 assert!(result.is_ok());
5362 }
5363
5364 #[test]
5365 fn test_delete_many_empty_slice() {
5366 let cache = Cache::new();
5368 cache.register_default(MemoryCacheDriver::new());
5369 let result = cache.delete_many(&[]);
5370 assert!(result.is_ok());
5371 }
5372
5373 #[test]
5374 fn test_delete_many_partial_delete_before_failure() {
5375 let cache = Cache::new();
5378 cache.register_default(MemoryCacheDriver::new());
5379 cache.set("a", "1", None).unwrap();
5380 cache.set("b", "2", None).unwrap();
5381
5382 cache.delete_many(&["a", "b"]).unwrap();
5383 assert!(cache.get::<String>("a").unwrap().is_none());
5384 assert!(cache.get::<String>("b").unwrap().is_none());
5385 }
5386
5387 #[test]
5392 fn test_invalidate_after_write_basic() {
5393 let cache = Cache::new();
5395 cache.register_default(MemoryCacheDriver::new());
5396 cache.set("user:1", "Alice", None).unwrap();
5397 assert_eq!(
5398 cache.get::<String>("user:1").unwrap(),
5399 Some("Alice".to_string())
5400 );
5401
5402 cache.invalidate_after_write(&["user:1"]).unwrap();
5404 assert!(cache.get::<String>("user:1").unwrap().is_none());
5405 }
5406
5407 #[test]
5408 fn test_invalidate_after_write_multiple_keys() {
5409 let cache = Cache::new();
5411 cache.register_default(MemoryCacheDriver::new());
5412 cache.set("sdp_category_tree", "t1", None).unwrap();
5413 cache.set("sdp_category_select", "s1", None).unwrap();
5414 cache.set("sdp_category_child", "c1", None).unwrap();
5415
5416 cache
5417 .invalidate_after_write(&[
5418 "sdp_category_tree",
5419 "sdp_category_select",
5420 "sdp_category_child",
5421 ])
5422 .unwrap();
5423
5424 assert!(cache.get::<String>("sdp_category_tree").unwrap().is_none());
5425 assert!(cache
5426 .get::<String>("sdp_category_select")
5427 .unwrap()
5428 .is_none());
5429 assert!(cache.get::<String>("sdp_category_child").unwrap().is_none());
5430 }
5431
5432 #[test]
5433 fn test_invalidate_after_write_fire_and_forget() {
5434 let cache = Cache::new();
5436 cache.register_default(MemoryCacheDriver::new());
5437 cache.set("clerk:1", "data", None).unwrap();
5438
5439 let _ = cache.invalidate_after_write(&["clerk:1"]);
5441 assert!(cache.get::<String>("clerk:1").unwrap().is_none());
5442 }
5443
5444 #[test]
5449 fn test_refresh_force_update() {
5450 let cache = Cache::new();
5452 cache.register_default(MemoryCacheDriver::new());
5453 cache.set("store:1", "old_data", None).unwrap();
5454
5455 let result: String = cache
5456 .refresh("store:1", None, || Ok("new_data".to_string()))
5457 .unwrap();
5458
5459 assert_eq!(result, "new_data");
5460 assert_eq!(
5461 cache.get::<String>("store:1").unwrap(),
5462 Some("new_data".to_string())
5463 );
5464 }
5465
5466 #[test]
5467 fn test_refresh_fetcher_error_no_write() {
5468 let cache = Cache::new();
5470 cache.register_default(MemoryCacheDriver::new());
5471 cache.set("key", "original", None).unwrap();
5472
5473 let result: Result<String, CacheError> = cache.refresh("key", None, || {
5475 Err(CacheError::SerializationError("fetch failed".to_string()))
5476 });
5477
5478 assert!(result.is_err());
5479 assert!(cache.get::<String>("key").unwrap().is_none());
5481 }
5482
5483 #[test]
5484 fn test_refresh_ttl_propagation() {
5485 let cache = Cache::new();
5487 cache.register_default(MemoryCacheDriver::new());
5488
5489 let _result: String = cache
5490 .refresh("ttl_key", Some(Duration::from_millis(50)), || {
5491 Ok("value".to_string())
5492 })
5493 .unwrap();
5494
5495 assert_eq!(
5497 cache.get::<String>("ttl_key").unwrap(),
5498 Some("value".to_string())
5499 );
5500
5501 std::thread::sleep(Duration::from_millis(60));
5503 assert!(cache.get::<String>("ttl_key").unwrap().is_none());
5504 }
5505
5506 #[test]
5507 fn test_refresh_returns_fetcher_value() {
5508 let cache = Cache::new();
5511 cache.register_default(MemoryCacheDriver::new());
5512 cache.set("counter", "old_value", None).unwrap();
5513
5514 let result: String = cache
5515 .refresh("counter", None, || Ok("new_value".to_string()))
5516 .unwrap();
5517 assert_eq!(result, "new_value");
5518 assert_eq!(
5519 cache.get::<String>("counter").unwrap(),
5520 Some("new_value".to_string())
5521 );
5522 }
5523
5524 #[test]
5529 fn test_r5_php_delete_multiple_semantics() {
5530 let cache = Cache::new();
5533 cache.register_default(MemoryCacheDriver::new());
5534 cache.set("a", "1", None).unwrap();
5535 cache.set("b", "2", None).unwrap();
5536 cache.set("c", "3", None).unwrap();
5537
5538 let result = cache.delete_many(&["a", "b", "c"]);
5540 assert!(result.is_ok()); assert!(cache.get::<String>("a").unwrap().is_none());
5544 assert!(cache.get::<String>("b").unwrap().is_none());
5545 assert!(cache.get::<String>("c").unwrap().is_none());
5546 }
5547
5548 #[test]
5549 fn test_r5_php_invalidate_after_write_pattern() {
5550 let cache = Cache::new();
5553 cache.register_default(MemoryCacheDriver::new());
5554
5555 cache
5557 .set("foodCashierClerkAll_1", vec!["clerk1"], None)
5558 .unwrap();
5559
5560 let write_success = true;
5562 if write_success {
5563 cache
5564 .invalidate_after_write(&["foodCashierClerkAll_1"])
5565 .unwrap();
5566 }
5567
5568 assert!(cache
5570 .get::<Vec<String>>("foodCashierClerkAll_1")
5571 .unwrap()
5572 .is_none());
5573 }
5574
5575 #[test]
5576 fn test_r5_php_refresh_pattern() {
5577 let cache = Cache::new();
5580 cache.register_default(MemoryCacheDriver::new());
5581
5582 cache
5584 .set("wmall_store_info_1", "old_store_data", None)
5585 .unwrap();
5586
5587 let result: String = cache
5589 .refresh("wmall_store_info_1", None, || {
5590 Ok("fresh_store_data".to_string())
5592 })
5593 .unwrap();
5594
5595 assert_eq!(result, "fresh_store_data");
5596 assert_eq!(
5597 cache.get::<String>("wmall_store_info_1").unwrap(),
5598 Some("fresh_store_data".to_string())
5599 );
5600 }
5601
5602 #[test]
5607 fn test_fetch_singleflight_cache_hit() {
5608 let cache = Cache::new();
5610 cache.register_default(MemoryCacheDriver::new());
5611 cache.set("hot", "cached_value", None).unwrap();
5612
5613 let called = Arc::new(Mutex::new(false));
5614 let called_clone = called.clone();
5615 let result: String = cache
5616 .fetch_singleflight("hot", None, || {
5617 *called_clone.lock() = true;
5618 Ok("fetcher_value".to_string())
5619 })
5620 .unwrap();
5621
5622 assert_eq!(result, "cached_value");
5623 assert!(!*called.lock(), "fetcher 不应被调用(缓存命中)");
5624 }
5625
5626 #[test]
5627 fn test_fetch_singleflight_cache_miss_invokes_fetcher() {
5628 let cache = Cache::new();
5630 cache.register_default(MemoryCacheDriver::new());
5631
5632 let result: String = cache
5633 .fetch_singleflight("miss_key", None, || Ok("fetched".to_string()))
5634 .unwrap();
5635
5636 assert_eq!(result, "fetched");
5637 assert_eq!(
5638 cache.get::<String>("miss_key").unwrap(),
5639 Some("fetched".to_string())
5640 );
5641 }
5642
5643 #[test]
5644 fn test_fetch_singleflight_concurrent_only_one_fetcher_call() {
5645 let cache = Arc::new(Cache::new());
5647 cache.register_default(MemoryCacheDriver::new());
5648
5649 let fetcher_call_count = Arc::new(Mutex::new(0u32));
5650 let barrier = Arc::new(Barrier::new(4));
5651 let results = Arc::new(Mutex::new(Vec::<String>::new()));
5652
5653 let mut handles = Vec::new();
5654 for _ in 0..4 {
5655 let cache_clone = Arc::clone(&cache);
5656 let count_clone = Arc::clone(&fetcher_call_count);
5657 let barrier_clone = Arc::clone(&barrier);
5658 let results_clone = Arc::clone(&results);
5659
5660 handles.push(std::thread::spawn(move || {
5661 barrier_clone.wait();
5663
5664 let value: String = cache_clone
5665 .fetch_singleflight("concurrent_key", None, || {
5666 std::thread::sleep(Duration::from_millis(50));
5668 let mut count = count_clone.lock();
5669 *count += 1;
5670 Ok(format!("fetched_{}", *count))
5671 })
5672 .unwrap();
5673
5674 results_clone.lock().push(value);
5675 }));
5676 }
5677
5678 for handle in handles {
5679 handle.join().unwrap();
5680 }
5681
5682 assert_eq!(
5684 *fetcher_call_count.lock(),
5685 1,
5686 "fetcher 应只调用一次(singleflight)"
5687 );
5688
5689 let results = results.lock();
5691 assert_eq!(results.len(), 4);
5692 for value in results.iter() {
5693 assert_eq!(value, "fetched_1");
5694 }
5695 }
5696
5697 #[test]
5698 fn test_fetch_singleflight_fetcher_error_propagates() {
5699 let cache = Cache::new();
5701 cache.register_default(MemoryCacheDriver::new());
5702
5703 let result: Result<String, CacheError> = cache.fetch_singleflight("err_key", None, || {
5704 Err(CacheError::SerializationError("fetcher failed".to_string()))
5705 });
5706
5707 assert!(result.is_err());
5708 assert!(cache.get::<String>("err_key").unwrap().is_none());
5709 }
5710
5711 #[test]
5716 fn test_set_with_jitter_basic() {
5717 let cache = Cache::new();
5719 cache.register_default(MemoryCacheDriver::new());
5720
5721 cache
5722 .set_with_jitter(
5723 "jitter_key",
5724 "value",
5725 Some(Duration::from_secs(60)),
5726 Duration::from_secs(10),
5727 )
5728 .unwrap();
5729
5730 assert_eq!(
5731 cache.get::<String>("jitter_key").unwrap(),
5732 Some("value".to_string())
5733 );
5734 }
5735
5736 #[test]
5737 fn test_set_with_jitter_zero_jitter_equivalent_to_set() {
5738 let cache = Cache::new();
5740 cache.register_default(MemoryCacheDriver::new());
5741
5742 cache
5743 .set_with_jitter(
5744 "no_jitter",
5745 "value",
5746 Some(Duration::from_secs(60)),
5747 Duration::ZERO,
5748 )
5749 .unwrap();
5750
5751 assert_eq!(
5752 cache.get::<String>("no_jitter").unwrap(),
5753 Some("value".to_string())
5754 );
5755 }
5756
5757 #[test]
5758 fn test_set_with_jitter_none_ttl_no_jitter() {
5759 let cache = Cache::new();
5761 cache.register_default(MemoryCacheDriver::new());
5762
5763 cache
5764 .set_with_jitter("permanent", "value", None, Duration::from_secs(10))
5765 .unwrap();
5766
5767 assert_eq!(
5768 cache.get::<String>("permanent").unwrap(),
5769 Some("value".to_string())
5770 );
5771 }
5772
5773 #[test]
5774 fn test_set_with_jitter_ttl_in_expected_range() {
5775 let cache = Cache::new();
5777 cache.register_default(MemoryCacheDriver::new());
5778
5779 let base_ttl = Duration::from_millis(50);
5780 let jitter = Duration::from_millis(100);
5781
5782 cache
5783 .set_with_jitter("range_key", "value", Some(base_ttl), jitter)
5784 .unwrap();
5785
5786 assert!(cache.get::<String>("range_key").unwrap().is_some());
5788
5789 std::thread::sleep(base_ttl + jitter + Duration::from_millis(20));
5791 assert!(
5792 cache.get::<String>("range_key").unwrap().is_none(),
5793 "TTL 应在 [{:?}, {:?}] 范围内,已过期",
5794 base_ttl,
5795 base_ttl + jitter
5796 );
5797 }
5798
5799 #[test]
5804 fn test_fetch_with_protection_cache_hit() {
5805 let cache = Cache::new();
5807 cache.register_default(MemoryCacheDriver::new());
5808 cache.set("protected", "cached", None).unwrap();
5809
5810 let called = Arc::new(Mutex::new(false));
5811 let called_clone = called.clone();
5812 let result: String = cache
5813 .fetch_with_protection(
5814 "protected",
5815 Some(Duration::from_secs(60)),
5816 Duration::from_secs(10),
5817 || {
5818 *called_clone.lock() = true;
5819 Ok("fetched".to_string())
5820 },
5821 )
5822 .unwrap();
5823
5824 assert_eq!(result, "cached");
5825 assert!(!*called.lock());
5826 }
5827
5828 #[test]
5829 fn test_fetch_with_protection_cache_miss_invokes_fetcher() {
5830 let cache = Cache::new();
5832 cache.register_default(MemoryCacheDriver::new());
5833
5834 let result: String = cache
5835 .fetch_with_protection(
5836 "miss_protected",
5837 Some(Duration::from_secs(60)),
5838 Duration::from_secs(10),
5839 || Ok("fetched_protected".to_string()),
5840 )
5841 .unwrap();
5842
5843 assert_eq!(result, "fetched_protected");
5844 assert_eq!(
5845 cache.get::<String>("miss_protected").unwrap(),
5846 Some("fetched_protected".to_string())
5847 );
5848 }
5849
5850 #[test]
5851 fn test_fetch_with_protection_concurrent_single_flight() {
5852 let cache = Arc::new(Cache::new());
5854 cache.register_default(MemoryCacheDriver::new());
5855
5856 let fetcher_call_count = Arc::new(Mutex::new(0u32));
5857 let barrier = Arc::new(Barrier::new(4));
5858 let results = Arc::new(Mutex::new(Vec::<String>::new()));
5859
5860 let mut handles = Vec::new();
5861 for _ in 0..4 {
5862 let cache_clone = Arc::clone(&cache);
5863 let count_clone = Arc::clone(&fetcher_call_count);
5864 let barrier_clone = Arc::clone(&barrier);
5865 let results_clone = Arc::clone(&results);
5866
5867 handles.push(std::thread::spawn(move || {
5868 barrier_clone.wait();
5869
5870 let value: String = cache_clone
5871 .fetch_with_protection(
5872 "concurrent_protected",
5873 Some(Duration::from_secs(60)),
5874 Duration::from_secs(10),
5875 || {
5876 std::thread::sleep(Duration::from_millis(50));
5877 let mut count = count_clone.lock();
5878 *count += 1;
5879 Ok(format!("value_{}", *count))
5880 },
5881 )
5882 .unwrap();
5883
5884 results_clone.lock().push(value);
5885 }));
5886 }
5887
5888 for handle in handles {
5889 handle.join().unwrap();
5890 }
5891
5892 assert_eq!(*fetcher_call_count.lock(), 1, "fetcher 应只调用一次");
5893
5894 let results = results.lock();
5895 assert_eq!(results.len(), 4);
5896 for value in results.iter() {
5897 assert_eq!(value, "value_1");
5898 }
5899 }
5900
5901 #[test]
5902 fn test_fetch_with_protection_fetcher_error_propagates() {
5903 let cache = Cache::new();
5905 cache.register_default(MemoryCacheDriver::new());
5906
5907 let result: Result<String, CacheError> = cache.fetch_with_protection(
5908 "err_protected",
5909 Some(Duration::from_secs(60)),
5910 Duration::from_secs(10),
5911 || Err(CacheError::SerializationError("failed".to_string())),
5912 );
5913
5914 assert!(result.is_err());
5915 assert!(cache.get::<String>("err_protected").unwrap().is_none());
5916 }
5917
5918 #[test]
5923 fn test_r5_php_remember_lock_vs_rust_singleflight() {
5924 let cache = Arc::new(Cache::new());
5928 cache.register_default(MemoryCacheDriver::new());
5929
5930 let call_count = Arc::new(Mutex::new(0u32));
5931 let barrier = Arc::new(Barrier::new(3));
5932 let results = Arc::new(Mutex::new(Vec::<String>::new()));
5933
5934 let mut handles = Vec::new();
5935 for _ in 0..3 {
5936 let cache_clone = Arc::clone(&cache);
5937 let count_clone = Arc::clone(&call_count);
5938 let barrier_clone = Arc::clone(&barrier);
5939 let results_clone = Arc::clone(&results);
5940
5941 handles.push(std::thread::spawn(move || {
5942 barrier_clone.wait();
5943
5944 let value: String = cache_clone
5945 .fetch_singleflight("r5_compare_key", None, || {
5946 std::thread::sleep(Duration::from_millis(30));
5947 let mut count = count_clone.lock();
5948 *count += 1;
5949 Ok(format!("v_{}", *count))
5950 })
5951 .unwrap();
5952
5953 results_clone.lock().push(value);
5954 }));
5955 }
5956
5957 for handle in handles {
5958 handle.join().unwrap();
5959 }
5960
5961 assert_eq!(
5963 *call_count.lock(),
5964 1,
5965 "Rust singleflight fetcher 应只调用一次"
5966 );
5967
5968 let results = results.lock();
5970 assert_eq!(results.len(), 3);
5971 for value in results.iter() {
5972 assert_eq!(value, "v_1");
5973 }
5974 }
5975
5976 #[test]
5977 fn test_r5_php_no_jitter_vs_rust_jitter() {
5978 let cache = Cache::new();
5982 cache.register_default(MemoryCacheDriver::new());
5983
5984 let mut ttl_samples = Vec::new();
5986 for i in 0..10 {
5987 let key = format!("jitter_sample_{}", i);
5988 cache
5989 .set_with_jitter(
5990 &key,
5991 "value",
5992 Some(Duration::from_secs(60)),
5993 Duration::from_secs(10),
5994 )
5995 .unwrap();
5996
5997 let _ = cache.get::<String>(&key).unwrap();
6000 ttl_samples.push(key);
6001 }
6002
6003 for key in &ttl_samples {
6005 assert_eq!(
6006 cache.get::<String>(key).unwrap(),
6007 Some("value".to_string()),
6008 "所有带抖动 TTL 的 key 都应写入成功"
6009 );
6010 }
6011 }
6012
6013 #[test]
6014 fn test_r5_php_remember_no_double_check_vs_rust_double_check() {
6015 let cache = Cache::new();
6019 cache.register_default(MemoryCacheDriver::new());
6020
6021 cache.set("double_check_key", "pre_cached", None).unwrap();
6023
6024 let called = Arc::new(Mutex::new(false));
6026 let called_clone = called.clone();
6027 let result: String = cache
6028 .fetch_singleflight("double_check_key", None, || {
6029 *called_clone.lock() = true;
6030 Ok("fetched".to_string())
6031 })
6032 .unwrap();
6033
6034 assert_eq!(result, "pre_cached");
6036 assert!(
6037 !*called.lock(),
6038 "double-check 应命中预缓存,fetcher 不被调用"
6039 );
6040 }
6041
6042 #[test]
6054 fn test_cache_thundering_herd_singleflight_collapses() {
6055 let cache = Arc::new(Cache::new());
6056 cache.register_default(MemoryCacheDriver::new());
6057
6058 let call_count = Arc::new(Mutex::new(0u32));
6059 let num_tasks = 50;
6060 let barrier = Arc::new(Barrier::new(num_tasks));
6061 let mut handles = Vec::new();
6062
6063 for _ in 0..num_tasks {
6064 let cache = Arc::clone(&cache);
6065 let cc = Arc::clone(&call_count);
6066 let barrier = Arc::clone(&barrier);
6067 handles.push(std::thread::spawn(move || {
6068 barrier.wait(); let result: String = cache
6070 .fetch_singleflight("herd_key", None, || {
6071 *cc.lock() += 1;
6073 std::thread::sleep(Duration::from_millis(10));
6074 Ok("single_source".to_string())
6075 })
6076 .unwrap();
6077 result
6078 }));
6079 }
6080
6081 let results: Vec<_> = handles.into_iter().map(|h| h.join().unwrap()).collect();
6082
6083 for r in &results {
6085 assert_eq!(r, "single_source");
6086 }
6087
6088 let calls = *call_count.lock();
6090 assert_eq!(
6091 calls, 1,
6092 "P3-CHAOS-01: 50 并发请求应合并为 1 次实际回源,实际 {} 次",
6093 calls
6094 );
6095 }
6096
6097 #[test]
6103 fn test_cache_slow_backend_timeout_degradation() {
6104 let cache = Cache::new();
6105 cache.register_default(MemoryCacheDriver::new());
6106
6107 let (tx, rx) = std::sync::mpsc::channel::<String>();
6108
6109 let handle = std::thread::spawn(move || {
6111 let result: String = cache
6112 .fetch_singleflight("slow_key", None, || {
6113 std::thread::sleep(Duration::from_millis(500));
6114 Ok("slow_value".to_string())
6115 })
6116 .unwrap();
6117 let _ = tx.send(result);
6118 });
6119
6120 let early = rx.recv_timeout(Duration::from_millis(200));
6122 assert!(
6123 early.is_err(),
6124 "P3-CHAOS-02: 慢回源(500ms)在 200ms 内不应完成,调用方应已触发超时降级"
6125 );
6126
6127 handle.join().unwrap();
6129 let final_val = rx.recv_timeout(Duration::from_secs(2)).unwrap();
6130 assert_eq!(
6131 final_val, "slow_value",
6132 "P3-CHAOS-02: 慢回源完成后结果应正确传播"
6133 );
6134 }
6135
6136 #[test]
6143 fn test_cache_ttl_eviction_under_concurrent_load() {
6144 use std::time::Duration;
6145
6146 let cache = Arc::new(Cache::new());
6147 cache.register_default(MemoryCacheDriver::new());
6148
6149 let num_writers = 16;
6150 let writes_per_writer = 100;
6151 let ttl = Duration::from_millis(50);
6152 let barrier = Arc::new(Barrier::new(num_writers));
6153
6154 let mut handles = Vec::new();
6155
6156 for w in 0..num_writers {
6158 let cache = Arc::clone(&cache);
6159 let barrier = Arc::clone(&barrier);
6160 handles.push(std::thread::spawn(move || {
6161 barrier.wait(); for i in 0..writes_per_writer {
6163 let key = format!("ttl_key_{}", i % 20); let val = format!("writer{}_val{}", w, i);
6165 let _ = cache.set(&key, &val, Some(ttl));
6166 }
6167 }));
6168 }
6169
6170 for h in handles {
6171 h.join().unwrap();
6172 }
6173
6174 std::thread::sleep(ttl * 3);
6176
6177 for i in 0..20 {
6179 let key = format!("ttl_key_{}", i);
6180 let val: Option<String> = cache.get(&key).unwrap();
6181 assert!(
6182 val.is_none(),
6183 "P3-CHAOS-03: key={} 应在 TTL 过期后为 None,实际 {:?}",
6184 key,
6185 val
6186 );
6187 }
6188
6189 cache.set("post_eviction_key", "fresh", None).unwrap();
6191 let val: Option<String> = cache.get("post_eviction_key").unwrap();
6192 assert_eq!(val, Some("fresh".to_string()));
6193 }
6194}