From 6c512ba3b233dae7ec06fd214cb80620911fd38a Mon Sep 17 00:00:00 2001 From: root Date: Fri, 26 Jun 2026 05:08:25 +0800 Subject: [PATCH] =?UTF-8?q?test(cache):=20=E9=9B=86=E6=88=90=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E6=98=BE=E5=BC=8F=20expire=20=E7=BB=AD=E6=9C=9F?= =?UTF-8?q?=E4=B8=8E=E6=BB=91=E5=8A=A8=E8=BF=87=E6=9C=9F(=E7=9C=9F?= =?UTF-8?q?=E5=AE=9E=E5=80=BC=E7=BB=AD=E3=80=81=E7=A9=BA=E6=A0=87=E8=AE=B0?= =?UTF-8?q?=E4=B8=8D=E7=BB=AD)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../integration/CacheExpireSlidingTest.java | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 src/test/java/com/njcn/middle/cache/integration/CacheExpireSlidingTest.java diff --git a/src/test/java/com/njcn/middle/cache/integration/CacheExpireSlidingTest.java b/src/test/java/com/njcn/middle/cache/integration/CacheExpireSlidingTest.java new file mode 100644 index 0000000..b1f43e5 --- /dev/null +++ b/src/test/java/com/njcn/middle/cache/integration/CacheExpireSlidingTest.java @@ -0,0 +1,102 @@ +package com.njcn.middle.cache.integration; + +import com.njcn.middle.cache.support.CacheKeyBuilder; +import com.njcn.middle.cache.template.RedisCacheEnhanceTemplate; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.redis.core.StringRedisTemplate; + +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * 集成测试:显式 expire 续期、滑动过期续真实值、空值标记不被续。 + * default-ttl=3600,故滑动续期会把 TTL 拉到远大于初始 60s。 + */ +@ExtendWith(RedisAvailableCondition.class) +@SpringBootTest(classes = CacheExpireSlidingTest.TestApp.class, + properties = { + "redis-cache.key-prefix=it-cache:", + "redis-cache.default-ttl-seconds=3600", + "redis-cache.null-ttl-seconds=60", + "redis-cache.jitter-ratio=0", + "redis-cache.sliding-expire-enabled=true" + }) +class CacheExpireSlidingTest { + + @Autowired + private RedisCacheEnhanceTemplate cache; + @Autowired + private StringRedisTemplate redis; + @Autowired + private CacheKeyBuilder keyBuilder; + + private long ttl(String bizKey) { + Long e = redis.getExpire(keyBuilder.build(bizKey), TimeUnit.SECONDS); + return e == null ? -1 : e; + } + + @Test + void explicitExpireExtendsTtl() { + String key = "exp:1"; + cache.set(key, new User(1L, "a"), 60); + assertTrue(ttl(key) <= 60 && ttl(key) > 0); + assertTrue(cache.expire(key, 600)); + assertTrue(ttl(key) > 100, "expire 应把 TTL 续到 600 量级"); + cache.delete(key); + } + + @Test + void expireOnMissingKeyReturnsFalse() { + String key = "exp:missing"; + cache.delete(key); + assertFalse(cache.expire(key, 600)); + } + + @Test + void slidingRenewsRealValueOnGet() { + String key = "sld:1"; + cache.set(key, new User(1L, "a"), 60); // 初始 ~60s + assertTrue(ttl(key) <= 60 && ttl(key) > 0); + cache.get(key, User.class); // 命中真实值 → 滑动续到 default 3600 + assertTrue(ttl(key) > 1000, "滑动过期应把 TTL 续到 default 量级"); + cache.delete(key); + } + + @Test + void slidingDoesNotRenewNullSentinel() { + String key = "sld:missing"; + cache.delete(key); + Supplier loader = () -> null; + assertNull(cache.getOrLoad(key, User.class, 60, loader)); // 写空标记 ttl=60 + long before = ttl(key); + assertTrue(before <= 60 && before > 0); + assertNull(cache.get(key, User.class)); // 命中空标记,不续 + assertTrue(ttl(key) <= 60, "空值标记不应被滑动续期"); + cache.delete(key); + } + + @SpringBootConfiguration + @EnableAutoConfiguration + static class TestApp { + } + + @Data + @AllArgsConstructor + @NoArgsConstructor + static class User { + private Long id; + private String name; + } +}