diff --git a/pom.xml b/pom.xml
index aa84f2d5aa..884b417183 100644
--- a/pom.xml
+++ b/pom.xml
@@ -67,7 +67,7 @@
org.json
json
- 20240205
+ 20240303
com.google.code.gson
diff --git a/src/main/java/redis/clients/jedis/Protocol.java b/src/main/java/redis/clients/jedis/Protocol.java
index 40989c2502..c36eb6625b 100644
--- a/src/main/java/redis/clients/jedis/Protocol.java
+++ b/src/main/java/redis/clients/jedis/Protocol.java
@@ -312,7 +312,7 @@ public static enum Keyword implements Rawable {
DELETE, LIBRARYNAME, WITHCODE, DESCRIPTION, GETKEYS, GETKEYSANDFLAGS, DOCS, FILTERBY, DUMP,
MODULE, ACLCAT, PATTERN, DOCTOR, LATEST, HISTORY, USAGE, SAMPLES, PURGE, STATS, LOADEX, CONFIG, ARGS, RANK,
NOW, VERSION, ADDR, SKIPME, USER, LADDR,
- CHANNELS, NUMPAT, NUMSUB, SHARDCHANNELS, SHARDNUMSUB, NOVALUES;
+ CHANNELS, NUMPAT, NUMSUB, SHARDCHANNELS, SHARDNUMSUB, NOVALUES, MAXAGE;
private final byte[] raw;
diff --git a/src/main/java/redis/clients/jedis/commands/ClientCommands.java b/src/main/java/redis/clients/jedis/commands/ClientCommands.java
index edcfbd602e..75bda24a30 100644
--- a/src/main/java/redis/clients/jedis/commands/ClientCommands.java
+++ b/src/main/java/redis/clients/jedis/commands/ClientCommands.java
@@ -30,10 +30,10 @@ public interface ClientCommands {
String clientKill(String ip, int port);
/**
- * Close a given client connection.
+ * Close client connections based on certain selection parameters.
*
- * @param params Connection info will be closed
- * @return Close success return OK
+ * @param params Parameters defining what client connections to close.
+ * @return The number of client connections that were closed.
*/
long clientKill(ClientKillParams params);
diff --git a/src/main/java/redis/clients/jedis/params/ClientKillParams.java b/src/main/java/redis/clients/jedis/params/ClientKillParams.java
index 12c65be882..0082ef3340 100644
--- a/src/main/java/redis/clients/jedis/params/ClientKillParams.java
+++ b/src/main/java/redis/clients/jedis/params/ClientKillParams.java
@@ -67,6 +67,16 @@ public ClientKillParams laddr(String ip, int port) {
return addParam(Keyword.LADDR, ip + ':' + port);
}
+ /**
+ * Kill clients older than {@code maxAge} seconds.
+ *
+ * @param maxAge Clients older than this number of seconds will be killed.
+ * @return The {@code ClientKillParams} instance, for call chaining.
+ */
+ public ClientKillParams maxAge(long maxAge) {
+ return addParam(Keyword.MAXAGE, maxAge);
+ }
+
@Override
public void addParams(CommandArguments args) {
params.forEach(kv -> args.add(kv.getKey()).add(kv.getValue()));
diff --git a/src/test/java/redis/clients/jedis/MigratePipeliningTest.java b/src/test/java/redis/clients/jedis/MigratePipeliningTest.java
new file mode 100644
index 0000000000..b7942fc140
--- /dev/null
+++ b/src/test/java/redis/clients/jedis/MigratePipeliningTest.java
@@ -0,0 +1,398 @@
+package redis.clients.jedis;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.both;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasItems;
+import static org.hamcrest.Matchers.hasToString;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import redis.clients.jedis.commands.jedis.JedisCommandsTestBase;
+import redis.clients.jedis.exceptions.JedisDataException;
+import redis.clients.jedis.params.MigrateParams;
+
+public class MigratePipeliningTest extends JedisCommandsTestBase {
+
+ private static final byte[] bfoo = { 0x01, 0x02, 0x03 };
+ private static final byte[] bbar = { 0x04, 0x05, 0x06 };
+ private static final byte[] bfoo1 = { 0x07, 0x08, 0x01 };
+ private static final byte[] bbar1 = { 0x09, 0x00, 0x01 };
+ private static final byte[] bfoo2 = { 0x07, 0x08, 0x02 };
+ private static final byte[] bbar2 = { 0x09, 0x00, 0x02 };
+ private static final byte[] bfoo3 = { 0x07, 0x08, 0x03 };
+ private static final byte[] bbar3 = { 0x09, 0x00, 0x03 };
+
+ private static final String host = hnp.getHost();
+ private static final int port = 6386;
+ private static final int portAuth = hnp.getPort() + 1;
+ private static final int db = 2;
+ private static final int dbAuth = 3;
+ private static final int timeout = Protocol.DEFAULT_TIMEOUT;
+
+ private Jedis dest;
+ private Jedis destAuth;
+
+ @Before
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ dest = new Jedis(host, port, 500);
+ dest.flushAll();
+ dest.select(db);
+
+ destAuth = new Jedis(host, portAuth, 500);
+ destAuth.auth("foobared");
+ destAuth.flushAll();
+ destAuth.select(dbAuth);
+ }
+
+ @After
+ @Override
+ public void tearDown() throws Exception {
+ dest.close();
+ destAuth.close();
+ super.tearDown();
+ }
+
+ @Test
+ public void noKey() {
+ Pipeline p = jedis.pipelined();
+
+ p.migrate(host, port, "foo", db, timeout);
+ p.migrate(host, port, bfoo, db, timeout);
+ p.migrate(host, port, db, timeout, new MigrateParams(), "foo1", "foo2", "foo3");
+ p.migrate(host, port, db, timeout, new MigrateParams(), bfoo1, bfoo2, bfoo3);
+
+ assertThat(p.syncAndReturnAll(),
+ hasItems("NOKEY", "NOKEY", "NOKEY", "NOKEY"));
+ }
+
+ @Test
+ public void migrate() {
+ assertNull(dest.get("foo"));
+
+ Pipeline p = jedis.pipelined();
+
+ p.set("foo", "bar");
+ p.migrate(host, port, "foo", db, timeout);
+ p.get("foo");
+
+ assertThat(p.syncAndReturnAll(),
+ hasItems("OK", "OK", null));
+
+ assertEquals("bar", dest.get("foo"));
+ }
+
+ @Test
+ public void migrateBinary() {
+ assertNull(dest.get(bfoo));
+
+ Pipeline p = jedis.pipelined();
+
+ p.set(bfoo, bbar);
+ p.migrate(host, port, bfoo, db, timeout);
+ p.get(bfoo);
+
+ assertThat(p.syncAndReturnAll(),
+ hasItems("OK", "OK", null));
+
+ assertArrayEquals(bbar, dest.get(bfoo));
+ }
+
+ @Test
+ public void migrateEmptyParams() {
+ assertNull(dest.get("foo"));
+
+ Pipeline p = jedis.pipelined();
+
+ p.set("foo", "bar");
+ p.migrate(host, port, db, timeout, new MigrateParams(), "foo");
+ p.get("foo");
+
+ assertThat(p.syncAndReturnAll(),
+ hasItems("OK", "OK", null));
+
+ assertEquals("bar", dest.get("foo"));
+ }
+
+ @Test
+ public void migrateEmptyParamsBinary() {
+ assertNull(dest.get(bfoo));
+
+ Pipeline p = jedis.pipelined();
+
+ p.set(bfoo, bbar);
+ p.migrate(host, port, db, timeout, new MigrateParams(), bfoo);
+ p.get(bfoo);
+
+ assertThat(p.syncAndReturnAll(),
+ hasItems("OK", "OK", null));
+
+ assertArrayEquals(bbar, dest.get(bfoo));
+ }
+
+ @Test
+ public void migrateCopy() {
+ assertNull(dest.get("foo"));
+
+ Pipeline p = jedis.pipelined();
+
+ p.set("foo", "bar");
+ p.migrate(host, port, db, timeout, new MigrateParams().copy(), "foo");
+ p.get("foo");
+
+ assertThat(p.syncAndReturnAll(),
+ hasItems("OK", "OK", "bar"));
+
+ assertEquals("bar", dest.get("foo"));
+ }
+
+ @Test
+ public void migrateCopyBinary() {
+ assertNull(dest.get(bfoo));
+
+ Pipeline p = jedis.pipelined();
+
+ p.set(bfoo, bbar);
+ p.migrate(host, port, db, timeout, new MigrateParams().copy(), bfoo);
+ p.get(bfoo);
+
+ assertThat(p.syncAndReturnAll(),
+ hasItems("OK", "OK", bbar));
+
+ assertArrayEquals(bbar, dest.get(bfoo));
+ }
+
+ @Test
+ public void migrateReplace() {
+ dest.set("foo", "bar2");
+
+ assertEquals("bar2", dest.get("foo"));
+
+ Pipeline p = jedis.pipelined();
+
+ p.set("foo", "bar1");
+ p.migrate(host, port, db, timeout, new MigrateParams().replace(), "foo");
+ p.get("foo");
+
+ assertThat(p.syncAndReturnAll(),
+ hasItems("OK", "OK", null));
+
+ assertEquals("bar1", dest.get("foo"));
+ }
+
+ @Test
+ public void migrateReplaceBinary() {
+ dest.set(bfoo, bbar2);
+
+ assertArrayEquals(bbar2, dest.get(bfoo));
+
+ Pipeline p = jedis.pipelined();
+
+ p.set(bfoo, bbar1);
+ p.migrate(host, port, db, timeout, new MigrateParams().replace(), bfoo);
+ p.get(bfoo);
+
+ assertThat(p.syncAndReturnAll(),
+ hasItems("OK", "OK", null));
+
+ assertArrayEquals(bbar1, dest.get(bfoo));
+ }
+
+ @Test
+ public void migrateCopyReplace() {
+ dest.set("foo", "bar2");
+
+ assertEquals("bar2", dest.get("foo"));
+
+ Pipeline p = jedis.pipelined();
+
+ p.set("foo", "bar1");
+ p.migrate(host, port, db, timeout, new MigrateParams().copy().replace(), "foo");
+ p.get("foo");
+
+ assertThat(p.syncAndReturnAll(),
+ hasItems("OK", "OK", "bar1"));
+
+ assertEquals("bar1", dest.get("foo"));
+ }
+
+ @Test
+ public void migrateCopyReplaceBinary() {
+ dest.set(bfoo, bbar2);
+
+ assertArrayEquals(bbar2, dest.get(bfoo));
+
+ Pipeline p = jedis.pipelined();
+
+ p.set(bfoo, bbar1);
+ p.migrate(host, port, db, timeout, new MigrateParams().copy().replace(), bfoo);
+ p.get(bfoo);
+
+ assertThat(p.syncAndReturnAll(),
+ hasItems("OK", "OK", bbar1));
+
+ assertArrayEquals(bbar1, dest.get(bfoo));
+ }
+
+ @Test
+ public void migrateAuth() {
+ assertNull(dest.get("foo"));
+
+ Pipeline p = jedis.pipelined();
+
+ p.set("foo", "bar");
+ p.migrate(host, portAuth, dbAuth, timeout, new MigrateParams().auth("foobared"), "foo");
+ p.get("foo");
+
+ assertThat(p.syncAndReturnAll(),
+ hasItems("OK", "OK", null));
+
+ assertEquals("bar", destAuth.get("foo"));
+ }
+
+ @Test
+ public void migrateAuthBinary() {
+ assertNull(dest.get(bfoo));
+
+ Pipeline p = jedis.pipelined();
+
+ p.set(bfoo, bbar);
+ p.migrate(host, portAuth, dbAuth, timeout, new MigrateParams().auth("foobared"), bfoo);
+ p.get(bfoo);
+
+ assertThat(p.syncAndReturnAll(),
+ hasItems("OK", "OK", null));
+
+ assertArrayEquals(bbar, destAuth.get(bfoo));
+ }
+
+ @Test
+ public void migrateAuth2() {
+ assertNull(jedis.get("foo"));
+
+ Pipeline p = destAuth.pipelined();
+
+ p.set("foo", "bar");
+ p.migrate(host, hnp.getPort(), 0, timeout,
+ new MigrateParams().auth2("acljedis", "fizzbuzz"), "foo");
+ p.get("foo");
+
+ assertThat(p.syncAndReturnAll(),
+ hasItems("OK", "OK", null));
+
+ assertEquals("bar", jedis.get("foo"));
+ }
+
+ @Test
+ public void migrateAuth2Binary() {
+ assertNull(jedis.get(bfoo));
+
+ Pipeline p = dest.pipelined();
+
+ p.set(bfoo, bbar);
+ p.migrate(host, hnp.getPort(), 0, timeout,
+ new MigrateParams().auth2("acljedis", "fizzbuzz"), bfoo);
+ p.get(bfoo);
+
+ assertThat(p.syncAndReturnAll(),
+ hasItems("OK", "OK", null));
+
+ assertArrayEquals(bbar, jedis.get(bfoo));
+ }
+
+ @Test
+ public void migrateMulti() {
+ assertNull(dest.get("foo1"));
+ assertNull(dest.get("foo2"));
+ assertNull(dest.get("foo3"));
+
+ Pipeline p = jedis.pipelined();
+
+ p.mset("foo1", "bar1", "foo2", "bar2", "foo3", "bar3");
+ p.migrate(host, port, db, timeout, new MigrateParams(), "foo1", "foo2", "foo3");
+
+ assertThat(p.syncAndReturnAll(),
+ hasItems("OK", "OK"));
+
+ assertEquals("bar1", dest.get("foo1"));
+ assertEquals("bar2", dest.get("foo2"));
+ assertEquals("bar3", dest.get("foo3"));
+ }
+
+ @Test
+ public void migrateMultiBinary() {
+ assertNull(dest.get(bfoo1));
+ assertNull(dest.get(bfoo2));
+ assertNull(dest.get(bfoo3));
+
+ Pipeline p = jedis.pipelined();
+
+ p.mset(bfoo1, bbar1, bfoo2, bbar2, bfoo3, bbar3);
+ p.migrate(host, port, db, timeout, new MigrateParams(), bfoo1, bfoo2, bfoo3);
+
+ assertThat(p.syncAndReturnAll(),
+ hasItems("OK", "OK"));
+
+ assertArrayEquals(bbar1, dest.get(bfoo1));
+ assertArrayEquals(bbar2, dest.get(bfoo2));
+ assertArrayEquals(bbar3, dest.get(bfoo3));
+ }
+
+ @Test
+ public void migrateConflict() {
+ dest.set("foo2", "bar");
+
+ assertNull(dest.get("foo1"));
+ assertEquals("bar", dest.get("foo2"));
+ assertNull(dest.get("foo3"));
+
+ Pipeline p = jedis.pipelined();
+
+ p.mset("foo1", "bar1", "foo2", "bar2", "foo3", "bar3");
+ p.migrate(host, port, db, timeout, new MigrateParams(), "foo1", "foo2", "foo3");
+
+ assertThat(p.syncAndReturnAll(),
+ hasItems(
+ equalTo("OK"),
+ both(instanceOf(JedisDataException.class)).and(hasToString(containsString("BUSYKEY")))
+ ));
+
+ assertEquals("bar1", dest.get("foo1"));
+ assertEquals("bar", dest.get("foo2"));
+ assertEquals("bar3", dest.get("foo3"));
+ }
+
+ @Test
+ public void migrateConflictBinary() {
+ dest.set(bfoo2, bbar);
+
+ assertNull(dest.get(bfoo1));
+ assertArrayEquals(bbar, dest.get(bfoo2));
+ assertNull(dest.get(bfoo3));
+
+ Pipeline p = jedis.pipelined();
+
+ p.mset(bfoo1, bbar1, bfoo2, bbar2, bfoo3, bbar3);
+ p.migrate(host, port, db, timeout, new MigrateParams(), bfoo1, bfoo2, bfoo3);
+
+ assertThat(p.syncAndReturnAll(),
+ hasItems(
+ equalTo("OK"),
+ both(instanceOf(JedisDataException.class)).and(hasToString(containsString("BUSYKEY")))
+ ));
+
+ assertArrayEquals(bbar1, dest.get(bfoo1));
+ assertArrayEquals(bbar, dest.get(bfoo2));
+ assertArrayEquals(bbar3, dest.get(bfoo3));
+ }
+
+}
diff --git a/src/test/java/redis/clients/jedis/PipeliningTest.java b/src/test/java/redis/clients/jedis/PipeliningTest.java
index bb9834c8d6..527b9dfc6d 100644
--- a/src/test/java/redis/clients/jedis/PipeliningTest.java
+++ b/src/test/java/redis/clients/jedis/PipeliningTest.java
@@ -1,5 +1,10 @@
package redis.clients.jedis;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasItems;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.matchesPattern;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -16,18 +21,23 @@
import java.util.Set;
import java.util.UUID;
-import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
import org.junit.Test;
-
-import redis.clients.jedis.exceptions.JedisDataException;
-import redis.clients.jedis.resps.Tuple;
+import redis.clients.jedis.commands.ProtocolCommand;
import redis.clients.jedis.commands.jedis.JedisCommandsTestBase;
+import redis.clients.jedis.exceptions.JedisDataException;
import redis.clients.jedis.params.SetParams;
+import redis.clients.jedis.resps.Tuple;
import redis.clients.jedis.util.SafeEncoder;
public class PipeliningTest extends JedisCommandsTestBase {
+ private static final byte[] bfoo = { 0x01, 0x02, 0x03, 0x04 };
+ private static final byte[] bfoo1 = { 0x01, 0x02, 0x03, 0x04, 0x11, 0x12, 0x13, 0x14 };
+ private static final byte[] bbar = { 0x05, 0x06, 0x07, 0x08 };
+ private static final byte[] bbaz = { 0x09, 0x0A, 0x0B, 0x0C };
+
@Test
public void pipeline() {
Pipeline p = jedis.pipelined();
@@ -271,150 +281,6 @@ public void piplineWithError() {
}
assertEquals(r.get(), "bar");
}
-//
-// @Test
-// public void multi() {
-// Pipeline p = jedis.pipelined();
-// p.multi();
-// Response r1 = p.hincrBy("a", "f1", -1);
-// Response r2 = p.hincrBy("a", "f1", -2);
-// Response> r3 = p.exec();
-// List