RedisClientHotkeysCommandsTest.java
package redis.clients.jedis.commands.unified.client;
import static org.awaitility.Awaitility.await;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.lessThan;
import static org.hamcrest.Matchers.lessThanOrEqualTo;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static redis.clients.jedis.util.RedisVersionUtil.getRedisVersion;
import java.time.Duration;
import io.redis.test.utils.RedisVersion;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedClass;
import org.junit.jupiter.params.provider.MethodSource;
import redis.clients.jedis.RedisProtocol;
import redis.clients.jedis.UnifiedJedis;
import redis.clients.jedis.args.HotkeysMetric;
import redis.clients.jedis.commands.unified.HotkeysCommandsTestBase;
import redis.clients.jedis.params.HotkeysParams;
import redis.clients.jedis.resps.HotkeysInfo;
import redis.clients.jedis.util.RedisVersionUtil;
import redis.clients.jedis.util.TestDataUtil;
@ParameterizedClass
@MethodSource("redis.clients.jedis.commands.CommandsTestsParameters#respVersions")
public class RedisClientHotkeysCommandsTest extends HotkeysCommandsTestBase {
public RedisClientHotkeysCommandsTest(RedisProtocol protocol) {
super(protocol);
}
@Override
protected UnifiedJedis createTestClient() {
return RedisClientCommandsTestHelper.getClient(protocol);
}
@Test
public void hotkeysGetBeforeStart() {
HotkeysInfo reply = jedis.hotkeysGet();
assertNull(reply);
}
@Test
public void hotkeysLifecycle() {
String startResult = jedis
.hotkeysStart(HotkeysParams.hotkeysParams().metrics(HotkeysMetric.CPU));
assertEquals("OK", startResult);
jedis.set("key1", "value1");
jedis.get("key1");
HotkeysInfo reply = jedis.hotkeysGet();
assertNotNull(reply);
assertTrue(reply.isTrackingActive());
String stopResult = jedis.hotkeysStop();
assertEquals("OK", stopResult);
reply = jedis.hotkeysGet();
assertNotNull(reply);
assertFalse(reply.isTrackingActive());
assertTrue(reply.getByCpuTimeUs().containsKey("key1"));
jedis.hotkeysStart(HotkeysParams.hotkeysParams().metrics(HotkeysMetric.CPU));
jedis.set("key2", "val2");
reply = jedis.hotkeysGet();
assertTrue(reply.isTrackingActive());
assertTrue(reply.getByCpuTimeUs().containsKey("key2"));
assertFalse(reply.getByCpuTimeUs().containsKey("key1"));
jedis.hotkeysStop();
String resetResult = jedis.hotkeysReset();
assertEquals("OK", resetResult);
reply = jedis.hotkeysGet();
assertNull(reply);
}
@Test
public void hotkeysBothMetrics() {
jedis.hotkeysStart(
HotkeysParams.hotkeysParams().metrics(HotkeysMetric.CPU, HotkeysMetric.NET).sample(1));
String cpuHot = "stats:counter";
for (int i = 0; i < 20; i++) {
jedis.incr(cpuHot);
}
String netHot = "blob:data";
jedis.set(netHot, TestDataUtil.generateString(6000));
jedis.get(netHot);
HotkeysInfo reply = jedis.hotkeysGet();
assertNotNull(reply);
assertTrue(reply.getByCpuTimeUs().containsKey(cpuHot));
assertThat(reply.getByCpuTimeUs().get(cpuHot), greaterThan(0L));
assertTrue(reply.getByNetBytes().containsKey(netHot));
assertThat(reply.getByNetBytes().get(netHot), greaterThan(6000L));
}
@Test
public void hotkeysStartOptionsSample() {
jedis.hotkeysStart(HotkeysParams.hotkeysParams().metrics(HotkeysMetric.CPU).sample(5));
for (int i = 0; i < 20; i++) {
jedis.set("samplekey" + i, "value" + i);
}
HotkeysInfo reply = jedis.hotkeysGet();
assertNotNull(reply);
assertEquals(5, reply.getSampleRatio());
assertThat(reply.getByCpuTimeUs().size(), lessThan(20));
}
@Test
public void hotkeysStartOptionsCount() {
jedis.hotkeysStart(HotkeysParams.hotkeysParams().metrics(HotkeysMetric.CPU).count(10));
for (int i = 1; i <= 25; i++) {
jedis.set("countkey" + i, "value" + i);
}
HotkeysInfo reply = jedis.hotkeysGet();
assertNotNull(reply);
assertThat(reply.getByCpuTimeUs().size(), lessThanOrEqualTo(10));
}
@Test
public void hotkeysDurationOption() {
jedis.hotkeysStart(HotkeysParams.hotkeysParams().metrics(HotkeysMetric.CPU).duration(1));
jedis.set("durationkey", "testvalue");
await().atMost(Duration.ofSeconds(2)).until(() -> {
HotkeysInfo info = jedis.hotkeysGet();
return info != null && !info.isTrackingActive();
});
HotkeysInfo reply = jedis.hotkeysGet();
assertNotNull(reply);
assertFalse(reply.isTrackingActive());
assertThat(reply.getCollectionDurationMs(), greaterThanOrEqualTo(1000L));
assertTrue(reply.getByCpuTimeUs().containsKey("durationkey"));
}
@Test
public void hotkeysResponseFields() {
jedis.hotkeysStart(HotkeysParams.hotkeysParams().metrics(HotkeysMetric.CPU, HotkeysMetric.NET));
jedis.set("testkey", "testvalue");
jedis.get("testkey");
HotkeysInfo reply = jedis.hotkeysGet();
assertNotNull(reply);
assertTrue(reply.isTrackingActive());
assertEquals(1, reply.getSampleRatio());
assertNotNull(reply.getSelectedSlots());
// In standalone mode, server returns slot ranges (e.g., [[0, 16383]] for all slots)
assertThat(reply.getCollectionStartTimeUnixMs(), greaterThan(0L));
assertThat(reply.getCollectionDurationMs(), greaterThanOrEqualTo(0L));
assertNotNull(reply.getByCpuTimeUs());
assertNotNull(reply.getByNetBytes());
assertThat(reply.getTotalCpuTimeUserMs(), greaterThanOrEqualTo(0L));
assertThat(reply.getTotalCpuTimeSysMs(), greaterThanOrEqualTo(0L));
assertThat(reply.getTotalNetBytes(), greaterThanOrEqualTo(0L));
assertNull(reply.getSampledCommandSelectedSlotsUs());
assertNull(reply.getAllCommandsSelectedSlotsUs());
assertThat(reply.getAllCommandsAllSlotsUs(), greaterThanOrEqualTo(0L));
assertNull(reply.getNetBytesSampledCommandsSelectedSlots());
assertNull(reply.getNetBytesAllCommandsSelectedSlots());
assertThat(reply.getNetBytesAllCommandsAllSlots(), greaterThanOrEqualTo(0L));
}
@Test
public void infoHotkeysSection() {
boolean isRedis8_6_1OrHigher = getRedisVersion(jedis)
.isGreaterThanOrEqualTo(RedisVersion.of("8.6.1"));
String info = jedis.info();
// Hotkeys section is displayed in info even when empty starting from Redis 8.6.1+
if (isRedis8_6_1OrHigher) {
assertTrue(info.contains("# Hotkeys"));
} else {
assertFalse(info.contains("# Hotkeys"));
}
jedis.hotkeysStart(HotkeysParams.hotkeysParams().metrics(HotkeysMetric.CPU));
info = jedis.info();
assertTrue(info.contains("# Hotkeys"));
assertTrue(info.contains("hotkeys-tracking-active:1"));
jedis.hotkeysStop();
info = jedis.info();
assertTrue(info.contains("# Hotkeys"));
assertTrue(info.contains("hotkeys-tracking-active:0"));
jedis.hotkeysReset();
info = jedis.info();
// Hotkeys section is displayed in info even when empty starting from Redis 8.6.1+
if (isRedis8_6_1OrHigher) {
assertTrue(info.contains("# Hotkeys"));
} else {
assertFalse(info.contains("# Hotkeys"));
}
}
}