ClientCommandsTest.java
package redis.clients.jedis.commands.jedis;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static redis.clients.jedis.params.ClientKillParams.SkipMe;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import io.redis.test.annotations.SinceRedisVersion;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedClass;
import org.junit.jupiter.params.provider.MethodSource;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.RedisProtocol;
import redis.clients.jedis.args.ClientAttributeOption;
import redis.clients.jedis.args.ClientType;
import redis.clients.jedis.args.UnblockType;
import redis.clients.jedis.exceptions.JedisConnectionException;
import redis.clients.jedis.params.ClientKillParams;
import redis.clients.jedis.resps.TrackingInfo;
@ParameterizedClass
@MethodSource("redis.clients.jedis.commands.CommandsTestsParameters#respVersions")
public class ClientCommandsTest extends JedisCommandsTestBase {
private final String clientName = "fancy_jedis_name";
private final Pattern pattern = Pattern.compile("\\bname=" + clientName + "\\b");
private Jedis client;
public ClientCommandsTest(RedisProtocol protocol) {
super(protocol);
}
@BeforeEach
@Override
public void setUp() throws Exception {
super.setUp();
client = new Jedis(endpoint.getHost(), endpoint.getPort(), 500);
client.auth(endpoint.getPassword());
client.clientSetname(clientName);
}
@AfterEach
@Override
public void tearDown() throws Exception {
client.close();
super.tearDown();
}
@Test
public void nameString() {
String name = "string";
client.clientSetname(name);
assertEquals(name, client.clientGetname());
}
@Test
public void nameBinary() {
byte[] name = "binary".getBytes();
client.clientSetname(name);
assertArrayEquals(name, client.clientGetnameBinary());
}
@Test
@SinceRedisVersion("7.2.0")
public void clientSetInfoCommand() {
String libName = "Jedis::A-Redis-Java-library";
String libVersion = "999.999.999";
assertEquals("OK", client.clientSetInfo(ClientAttributeOption.LIB_NAME, libName));
assertEquals("OK", client.clientSetInfo(ClientAttributeOption.LIB_VER, libVersion));
String info = client.clientInfo();
assertTrue(info.contains("lib-name=" + libName));
assertTrue(info.contains("lib-ver=" + libVersion));
}
@Test
public void clientId() {
long clientId = client.clientId();
String info = findInClientList();
Matcher matcher = Pattern.compile("\\bid=(\\d+)\\b").matcher(info);
matcher.find();
assertEquals(clientId, Long.parseLong(matcher.group(1)));
}
@Test
public void clientIdmultipleConnection() {
try (Jedis client2 = new Jedis(endpoint.getHost(), endpoint.getPort(), 500)) {
client2.auth(endpoint.getPassword());
client2.clientSetname("fancy_jedis_another_name");
// client-id is monotonically increasing
assertTrue(client.clientId() < client2.clientId());
}
}
@Test
public void clientIdReconnect() {
long clientIdInitial = client.clientId();
client.disconnect();
client.connect();
client.auth(endpoint.getPassword());
long clientIdAfterReconnect = client.clientId();
assertTrue(clientIdInitial < clientIdAfterReconnect);
}
@Test
public void clientUnblock() throws InterruptedException, TimeoutException {
long clientId = client.clientId();
assertEquals(0, jedis.clientUnblock(clientId, UnblockType.ERROR));
Future<?> future = Executors.newSingleThreadExecutor().submit(() -> client.brpop(100000, "foo"));
try {
// to make true command already executed
TimeUnit.MILLISECONDS.sleep(500);
assertEquals(1, jedis.clientUnblock(clientId, UnblockType.ERROR));
future.get(1, TimeUnit.SECONDS);
} catch (ExecutionException e) {
assertEquals("redis.clients.jedis.exceptions.JedisDataException: UNBLOCKED client unblocked via CLIENT UNBLOCK", e.getMessage());
}
}
@Test
public void killIdString() {
String info = findInClientList();
Matcher matcher = Pattern.compile("\\bid=(\\d+)\\b").matcher(info);
matcher.find();
String id = matcher.group(1);
assertEquals(1, jedis.clientKill(new ClientKillParams().id(id)));
assertDisconnected(client);
}
@Test
public void killIdBinary() {
String info = findInClientList();
Matcher matcher = Pattern.compile("\\bid=(\\d+)\\b").matcher(info);
matcher.find();
byte[] id = matcher.group(1).getBytes();
assertEquals(1, jedis.clientKill(new ClientKillParams().id(id)));
assertDisconnected(client);
}
@Test
public void killTypeNormal() {
long clients = jedis.clientKill(new ClientKillParams().type(ClientType.NORMAL));
assertTrue(clients > 0);
assertDisconnected(client);
}
@Test
public void killSkipmeNo() {
jedis.clientKill(new ClientKillParams().type(ClientType.NORMAL).skipMe(SkipMe.NO));
assertDisconnected(client);
assertDisconnected(jedis);
}
@Test
public void killSkipmeYesNo() {
jedis.clientKill(new ClientKillParams().type(ClientType.NORMAL).skipMe(SkipMe.YES));
assertDisconnected(client);
assertEquals(1, jedis.clientKill(new ClientKillParams().type(ClientType.NORMAL).skipMe(SkipMe.NO)));
assertDisconnected(jedis);
}
@Test
public void killAddrString() {
String info = findInClientList();
Matcher matcher = Pattern.compile("\\baddr=(\\S+)\\b").matcher(info);
matcher.find();
String addr = matcher.group(1);
assertEquals(1, jedis.clientKill(new ClientKillParams().addr(addr)));
assertDisconnected(client);
}
@Test
public void killAddrBinary() {
String info = findInClientList();
Matcher matcher = Pattern.compile("\\baddr=(\\S+)\\b").matcher(info);
matcher.find();
String addr = matcher.group(1);
assertEquals(1, jedis.clientKill(new ClientKillParams().addr(addr)));
assertDisconnected(client);
}
@Test
public void killLAddr() {
String info = findInClientList();
Matcher matcher = Pattern.compile("\\bladdr=(\\S+)\\b").matcher(info);
matcher.find();
String laddr = matcher.group(1);
long clients = jedis.clientKill(new ClientKillParams().laddr(laddr));
assertTrue(clients >= 1);
assertDisconnected(client);
}
@Test
public void killAddrIpPort() {
String info = findInClientList();
Matcher matcher = Pattern.compile("\\baddr=(\\S+)\\b").matcher(info);
matcher.find();
String addr = matcher.group(1);
int lastColon = addr.lastIndexOf(":");
String[] hp = new String[]{addr.substring(0, lastColon), addr.substring(lastColon + 1)};
assertEquals(1, jedis.clientKill(new ClientKillParams().addr(hp[0], Integer.parseInt(hp[1]))));
assertDisconnected(client);
}
@Test
public void killUser() {
client.aclSetUser("test_kill", "on", "+acl", ">password1");
try (Jedis client2 = new Jedis(endpoint.getHost(), endpoint.getPort(), 500)) {
client2.auth("test_kill", "password1");
assertEquals(1, jedis.clientKill(new ClientKillParams().user("test_kill")));
assertDisconnected(client2);
} finally {
jedis.aclDelUser("test_kill");
}
}
@Test
@SinceRedisVersion(value = "7.4.0", message = "MAXAGE (since Redis 7.4)")
public void killMaxAge() throws InterruptedException {
long maxAge = 2;
// sleep twice the maxAge, to be sure
Thread.sleep(maxAge * 2 * 1000);
try (Jedis client2 = new Jedis(endpoint.getHost(), endpoint.getPort(), 500)) {
client2.auth(endpoint.getPassword());
long killedClients = jedis.clientKill(new ClientKillParams().maxAge(maxAge));
// The reality is that some tests leak clients, so we can't assert
// on the exact number of killed clients.
assertTrue(killedClients > 0);
assertDisconnected(client);
assertConnected(client2);
}
}
@Test
public void clientInfo() {
String info = client.clientInfo();
assertNotNull(info);
assertEquals(1, info.split("\n").length);
assertTrue(info.contains(clientName));
}
@Test
public void clientListWithClientId() {
long id = client.clientId();
String listInfo = jedis.clientList(id);
assertNotNull(listInfo);
assertTrue(listInfo.contains(clientName));
}
@Test
public void listWithType() {
assertTrue(client.clientList(ClientType.NORMAL).split("\\n").length > 1);
assertEquals(0, client.clientList(ClientType.MASTER).length());
assertEquals(1, client.clientList(ClientType.SLAVE).split("\\n").length);
assertEquals(1, client.clientList(ClientType.REPLICA).split("\\n").length);
assertEquals(1, client.clientList(ClientType.PUBSUB).split("\\n").length);
}
@Test
public void trackingInfo() {
TrackingInfo trackingInfo = client.clientTrackingInfo();
assertEquals(1, trackingInfo.getFlags().size());
assertEquals(-1, trackingInfo.getRedirect());
assertEquals(0, trackingInfo.getPrefixes().size());
}
@Test
public void trackingInfoResp3() {
Jedis clientResp3 = new Jedis(endpoint.getHostAndPort(), endpoint.getClientConfigBuilder()
.protocol(RedisProtocol.RESP3).build());
TrackingInfo trackingInfo = clientResp3.clientTrackingInfo();
assertEquals(1, trackingInfo.getFlags().size());
assertEquals(-1, trackingInfo.getRedirect());
assertEquals(0, trackingInfo.getPrefixes().size());
}
private void assertDisconnected(Jedis j) {
try {
j.ping();
fail("Jedis connection should be disconnected");
} catch (JedisConnectionException jce) {
// should be here
}
}
private void assertConnected(Jedis j) {
assertEquals("PONG", j.ping());
}
private String findInClientList() {
for (String clientInfo : jedis.clientList().split("\n")) {
if (pattern.matcher(clientInfo).find()) {
return clientInfo;
}
}
return null;
}
}