From 516149492edcefa45e910d39101fea1a2ae2ca8f Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Sun, 7 Apr 2024 21:29:55 +0600 Subject: [PATCH 1/9] Support transaction from UnifiedJedis without calling multi first (#3804) ### Changes * Support transaction from UnifiedJedis without calling multi first * Return type of `multi()` method in JedisCluster and JedisSharding classes is changed to `AbstractTransaction` instead of `Transaction` --- * Support transaction from UnifiedJedis without calling multi first * Javadoc * JedisCluster and JedisSharding return AbstractTransaction --- .../redis/clients/jedis/JedisCluster.java | 3 +- .../redis/clients/jedis/JedisSharding.java | 3 +- .../redis/clients/jedis/UnifiedJedis.java | 17 ++++- .../pooled/PooledMiscellaneousTest.java | 72 +++++++++++-------- 4 files changed, 60 insertions(+), 35 deletions(-) diff --git a/src/main/java/redis/clients/jedis/JedisCluster.java b/src/main/java/redis/clients/jedis/JedisCluster.java index 55495e6513..6c5843c16e 100644 --- a/src/main/java/redis/clients/jedis/JedisCluster.java +++ b/src/main/java/redis/clients/jedis/JedisCluster.java @@ -258,11 +258,12 @@ public ClusterPipeline pipelined() { } /** + * @param doMulti param * @return nothing * @throws UnsupportedOperationException */ @Override - public Transaction multi() { + public AbstractTransaction transaction(boolean doMulti) { throw new UnsupportedOperationException(); } } diff --git a/src/main/java/redis/clients/jedis/JedisSharding.java b/src/main/java/redis/clients/jedis/JedisSharding.java index 2a94ea2df2..cf1758f44b 100644 --- a/src/main/java/redis/clients/jedis/JedisSharding.java +++ b/src/main/java/redis/clients/jedis/JedisSharding.java @@ -59,11 +59,12 @@ public ShardedPipeline pipelined() { } /** + * @param doMulti param * @return nothing * @throws UnsupportedOperationException */ @Override - public Transaction multi() { + public AbstractTransaction transaction(boolean doMulti) { throw new UnsupportedOperationException(); } } diff --git a/src/main/java/redis/clients/jedis/UnifiedJedis.java b/src/main/java/redis/clients/jedis/UnifiedJedis.java index 5c7b6e161f..452798d303 100644 --- a/src/main/java/redis/clients/jedis/UnifiedJedis.java +++ b/src/main/java/redis/clients/jedis/UnifiedJedis.java @@ -4878,13 +4878,24 @@ public PipelineBase pipelined() { } } + /** + * @return transaction object + */ public AbstractTransaction multi() { + return transaction(true); + } + + /** + * @param doMulti {@code false} should be set to enable manual WATCH, UNWATCH and MULTI + * @return transaction object + */ + public AbstractTransaction transaction(boolean doMulti) { if (provider == null) { - throw new IllegalStateException("It is not allowed to create Pipeline from this " + getClass()); + throw new IllegalStateException("It is not allowed to create Transaction from this " + getClass()); } else if (provider instanceof MultiClusterPooledConnectionProvider) { - return new MultiClusterTransaction((MultiClusterPooledConnectionProvider) provider, true, commandObjects); + return new MultiClusterTransaction((MultiClusterPooledConnectionProvider) provider, doMulti, commandObjects); } else { - return new Transaction(provider.getConnection(), true, true); + return new Transaction(provider.getConnection(), doMulti, true); } } diff --git a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledMiscellaneousTest.java b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledMiscellaneousTest.java index 6f2f42e754..5c66363345 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledMiscellaneousTest.java +++ b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledMiscellaneousTest.java @@ -1,6 +1,7 @@ package redis.clients.jedis.commands.unified.pooled; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThrows; import java.util.ArrayList; @@ -12,20 +13,16 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import redis.clients.jedis.JedisPooled; -import redis.clients.jedis.Pipeline; +import redis.clients.jedis.AbstractPipeline; +import redis.clients.jedis.AbstractTransaction; import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.Response; -import redis.clients.jedis.AbstractTransaction; import redis.clients.jedis.commands.unified.UnifiedJedisCommandsTestBase; import redis.clients.jedis.exceptions.JedisDataException; @RunWith(Parameterized.class) public class PooledMiscellaneousTest extends UnifiedJedisCommandsTestBase { - protected Pipeline pipeline; - protected AbstractTransaction transaction; - public PooledMiscellaneousTest(RedisProtocol protocol) { super(protocol); } @@ -34,8 +31,6 @@ public PooledMiscellaneousTest(RedisProtocol protocol) { public void setUp() { jedis = PooledCommandsTestHelper.getPooled(protocol); PooledCommandsTestHelper.clearData(); - pipeline = ((JedisPooled) jedis).pipelined(); - transaction = jedis.multi(); } @After @@ -43,12 +38,6 @@ public void cleanUp() { jedis.close(); } - @After - public void tearDown() { - pipeline.close(); - transaction.close(); - } - @Test public void pipeline() { final int count = 10; @@ -64,15 +53,18 @@ public void pipeline() { List> responses = new ArrayList<>(totalCount); List expected = new ArrayList<>(totalCount); - for (int i = 0; i < count; i++) { - responses.add(pipeline.get("foo" + i)); - expected.add("bar" + i); - } - for (int i = 0; i < count; i++) { - responses.add(pipeline.lrange("foobar" + i, 0, -1)); - expected.add(Arrays.asList("foo" + i, "bar" + i)); + + try (AbstractPipeline pipeline = jedis.pipelined()) { + for (int i = 0; i < count; i++) { + responses.add(pipeline.get("foo" + i)); + expected.add("bar" + i); + } + for (int i = 0; i < count; i++) { + responses.add(pipeline.lrange("foobar" + i, 0, -1)); + expected.add(Arrays.asList("foo" + i, "bar" + i)); + } + pipeline.sync(); } - pipeline.sync(); for (int i = 0; i < totalCount; i++) { assertEquals(expected.get(i), responses.get(i).get()); @@ -92,22 +84,42 @@ public void transaction() { } totalCount += count; + List responses; List expected = new ArrayList<>(totalCount); - for (int i = 0; i < count; i++) { - transaction.get("foo" + i); - expected.add("bar" + i); - } - for (int i = 0; i < count; i++) { - transaction.lrange("foobar" + i, 0, -1); - expected.add(Arrays.asList("foo" + i, "bar" + i)); + + try (AbstractTransaction transaction = jedis.multi()) { + for (int i = 0; i < count; i++) { + transaction.get("foo" + i); + expected.add("bar" + i); + } + for (int i = 0; i < count; i++) { + transaction.lrange("foobar" + i, 0, -1); + expected.add(Arrays.asList("foo" + i, "bar" + i)); + } + responses = transaction.exec(); } - List responses = transaction.exec(); for (int i = 0; i < totalCount; i++) { assertEquals(expected.get(i), responses.get(i)); } } + @Test + public void watch() { + List resp; + try (AbstractTransaction tx = jedis.transaction(false)) { + assertEquals("OK", tx.watch("mykey", "somekey")); + tx.multi(); + + jedis.set("mykey", "bar"); + + tx.set("mykey", "foo"); + resp = tx.exec(); + } + assertNull(resp); + assertEquals("bar", jedis.get("mykey")); + } + @Test public void broadcast() { From 93288a03e512dc02d3ebdfe43010bc3d4209a79f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 16:06:34 +0600 Subject: [PATCH 2/9] Bump org.apache.maven.plugins:maven-source-plugin from 3.3.0 to 3.3.1 (#3807) Bumps [org.apache.maven.plugins:maven-source-plugin](https://github.com/apache/maven-source-plugin) from 3.3.0 to 3.3.1. - [Commits](https://github.com/apache/maven-source-plugin/compare/maven-source-plugin-3.3.0...maven-source-plugin-3.3.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-source-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 402cd35842..52f2bda20e 100644 --- a/pom.xml +++ b/pom.xml @@ -216,7 +216,7 @@ maven-source-plugin - 3.3.0 + 3.3.1 true From 8cfd407364108bcdfe7ace3484e1939a86ef8393 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 16:06:44 +0600 Subject: [PATCH 3/9] Bump org.jacoco:jacoco-maven-plugin from 0.8.11 to 0.8.12 (#3805) Bumps [org.jacoco:jacoco-maven-plugin](https://github.com/jacoco/jacoco) from 0.8.11 to 0.8.12. - [Release notes](https://github.com/jacoco/jacoco/releases) - [Commits](https://github.com/jacoco/jacoco/compare/v0.8.11...v0.8.12) --- updated-dependencies: - dependency-name: org.jacoco:jacoco-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 52f2bda20e..f4e1421d47 100644 --- a/pom.xml +++ b/pom.xml @@ -177,7 +177,7 @@ org.jacoco jacoco-maven-plugin - 0.8.11 + 0.8.12 From d3ab354c98be6dec1ab29361bc98c59877d1e692 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 16:06:52 +0600 Subject: [PATCH 4/9] Bump com.kohlschutter.junixsocket:junixsocket-core from 2.9.0 to 2.9.1 (#3806) Bumps [com.kohlschutter.junixsocket:junixsocket-core](https://github.com/kohlschutter/junixsocket) from 2.9.0 to 2.9.1. - [Release notes](https://github.com/kohlschutter/junixsocket/releases) - [Commits](https://github.com/kohlschutter/junixsocket/compare/junixsocket-2.9.0...junixsocket-2.9.1) --- updated-dependencies: - dependency-name: com.kohlschutter.junixsocket:junixsocket-core dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f4e1421d47..d1800644ab 100644 --- a/pom.xml +++ b/pom.xml @@ -79,7 +79,7 @@ com.kohlschutter.junixsocket junixsocket-core - 2.9.0 + 2.9.1 pom test From e8c0f01c292126ee24b34ab1752553b6809e2b97 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Mon, 8 Apr 2024 22:29:05 +0600 Subject: [PATCH 5/9] Resolve compile warnings (#3810) with message `... non-varargs call of varargs method with inexact argument type for last parameter; ...` --- .../clients/jedis/UnifiedJedisCustomCommandsTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/redis/clients/jedis/UnifiedJedisCustomCommandsTest.java b/src/test/java/redis/clients/jedis/UnifiedJedisCustomCommandsTest.java index bb125cc28d..4ffc54cc54 100644 --- a/src/test/java/redis/clients/jedis/UnifiedJedisCustomCommandsTest.java +++ b/src/test/java/redis/clients/jedis/UnifiedJedisCustomCommandsTest.java @@ -46,7 +46,7 @@ public void testSendCommandWithProtocolCommandAndByteArrayArgs() { byte[][] args = { "arg1".getBytes(), "arg2".getBytes() }; CommandArguments commandArguments = mock(CommandArguments.class); CommandArguments commandArgumentsWithArgs = mock(CommandArguments.class); - when(commandArguments.addObjects(args)).thenReturn(commandArgumentsWithArgs); + when(commandArguments.addObjects((Object[]) args)).thenReturn(commandArgumentsWithArgs); when(commandObjects.commandArguments(cmd)).thenReturn(commandArguments); when(commandExecutor.executeCommand(any())).thenReturn("OK"); @@ -74,7 +74,7 @@ public void testSendBlockingCommandWithProtocolCommandAndByteArrayArgs() { CommandArguments commandArgumentsWithArgs = mock(CommandArguments.class); when(commandArgumentsWithArgs.blocking()).thenReturn(commandArgumentsBlocking); - when(commandArguments.addObjects(args)).thenReturn(commandArgumentsWithArgs); + when(commandArguments.addObjects((Object[]) args)).thenReturn(commandArgumentsWithArgs); when(commandObjects.commandArguments(cmd)).thenReturn(commandArguments); when(commandExecutor.executeCommand(any())).thenReturn("OK"); @@ -98,7 +98,7 @@ public void testSendCommandWithProtocolCommandAndStringArgs() { String[] args = { "arg1", "arg2" }; CommandArguments commandArguments = mock(CommandArguments.class); CommandArguments commandArgumentsWithArgs = mock(CommandArguments.class); - when(commandArguments.addObjects(args)).thenReturn(commandArgumentsWithArgs); + when(commandArguments.addObjects((Object[]) args)).thenReturn(commandArgumentsWithArgs); when(commandObjects.commandArguments(cmd)).thenReturn(commandArguments); when(commandExecutor.executeCommand(any())).thenReturn("OK"); @@ -126,7 +126,7 @@ public void testSendBlockingCommandWithProtocolCommandAndStringArgs() { CommandArguments commandArgumentsWithArgs = mock(CommandArguments.class); when(commandArgumentsWithArgs.blocking()).thenReturn(commandArgumentsBlocking); - when(commandArguments.addObjects(args)).thenReturn(commandArgumentsWithArgs); + when(commandArguments.addObjects((Object[]) args)).thenReturn(commandArgumentsWithArgs); when(commandObjects.commandArguments(cmd)).thenReturn(commandArguments); when(commandExecutor.executeCommand(any())).thenReturn("OK"); From b617822690615e77e2de931d94240dcf5b12d03f Mon Sep 17 00:00:00 2001 From: Gabriel Erzse Date: Mon, 8 Apr 2024 22:11:09 +0300 Subject: [PATCH 6/9] Add more tests for the CommandObjects class (#3809) * Add more tests for the CommandObjects class Continue the series of tests dedicated to the CommandObjects class, mostly with generic commands and search, and with a bit of polishing the existing tests. * Separate test for XADD with null Id --------- Co-authored-by: Gabriel Erzse --- .../CommandObjectsGenericCommandsTest.java | 1359 ++++++++++++++++- ...mandObjectsSearchAndQueryCommandsTest.java | 329 ++++ .../CommandObjectsSortedSetCommandsTest.java | 56 +- .../CommandObjectsStreamCommandsTest.java | 104 +- 4 files changed, 1828 insertions(+), 20 deletions(-) diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsGenericCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsGenericCommandsTest.java index 0182de207f..1849d26687 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsGenericCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsGenericCommandsTest.java @@ -1,23 +1,1034 @@ package redis.clients.jedis.commands.commandobjects; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import org.junit.Test; import redis.clients.jedis.Jedis; import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.args.ExpiryOption; +import redis.clients.jedis.params.RestoreParams; +import redis.clients.jedis.params.ScanParams; +import redis.clients.jedis.params.SortingParams; +import redis.clients.jedis.resps.ScanResult; + +/** + * Tests related to Generic commands. + */ +public class CommandObjectsGenericCommandsTest extends CommandObjectsStandaloneTestBase { + + public CommandObjectsGenericCommandsTest(RedisProtocol protocol) { + super(protocol); + } + + @Test + public void testExists() { + String key1 = "existsKey1"; + String key2 = "existsKey2"; + String value = "value"; + + exec(commandObjects.set(key1, value)); + exec(commandObjects.set(key2, value)); + + Boolean existsSingle = exec(commandObjects.exists(key1)); + assertThat(existsSingle, equalTo(true)); + + Long existsMultiple = exec(commandObjects.exists(key1, key2, "nonExistingKey")); + assertThat(existsMultiple, equalTo(2L)); + + Boolean existsSingleByte = exec(commandObjects.exists(key1.getBytes())); + assertThat(existsSingleByte, equalTo(true)); + + Long existsMultipleByte = exec(commandObjects.exists(key1.getBytes(), key2.getBytes(), "nonExistingKey".getBytes())); + assertThat(existsMultipleByte, equalTo(2L)); + + Boolean existsNonExisting = exec(commandObjects.exists("nonExistingKey")); + assertThat(existsNonExisting, equalTo(false)); + + Boolean existsNonExistingBytes = exec(commandObjects.exists("nonExistingKey".getBytes())); + assertThat(existsNonExistingBytes, equalTo(false)); + } + + @Test + public void testPersist() { + String key1 = "persistKey1"; + byte[] key2 = "persistKey2".getBytes(); + String value = "value"; + int expireTime = 10; // seconds + + exec(commandObjects.setex(key1, expireTime, value)); + exec(commandObjects.setex(key2, expireTime, value.getBytes())); + + Long ttlBeforePersist1 = exec(commandObjects.ttl(key1)); + assertThat(ttlBeforePersist1, greaterThan(0L)); + + Long ttlBeforePersist2 = exec(commandObjects.ttl(key2)); + assertThat(ttlBeforePersist2, greaterThan(0L)); + + Long persist1 = exec(commandObjects.persist(key1)); + assertThat(persist1, equalTo(1L)); + + Long persist2 = exec(commandObjects.persist(key2)); + assertThat(persist2, equalTo(1L)); + + Long ttlAfterPersist1 = exec(commandObjects.ttl(key1)); + assertThat(ttlAfterPersist1, equalTo(-1L)); + + Long ttlAfterPersist2 = exec(commandObjects.ttl(key2)); + assertThat(ttlAfterPersist2, equalTo(-1L)); + } + + @Test + public void testType() { + String stringKey = "stringKey"; + String listKey = "listKey"; + byte[] hashKey = "hashKey".getBytes(); + + exec(commandObjects.set(stringKey, "value")); + exec(commandObjects.rpush(listKey, "value")); + exec(commandObjects.hset(hashKey, "field".getBytes(), "hvalue".getBytes())); + + String stringKeyType = exec(commandObjects.type(stringKey)); + assertThat(stringKeyType, equalTo("string")); + + String listKeyType = exec(commandObjects.type(listKey)); + assertThat(listKeyType, equalTo("list")); + + String hashKeyType = exec(commandObjects.type(hashKey)); + assertThat(hashKeyType, equalTo("hash")); + + String nonExistingKeyType = exec(commandObjects.type("nonExistingKey")); + assertThat(nonExistingKeyType, equalTo("none")); + } + + @Test + public void testDumpAndRestore() { + String key = "dumpRestoreKey"; + String value = "value"; + + exec(commandObjects.set(key, value)); + + byte[] dumpedValue = exec(commandObjects.dump(key)); + assertThat(dumpedValue, notNullValue()); + + exec(commandObjects.del(key)); + + Boolean existsAfterDel = exec(commandObjects.exists(key)); + assertThat(existsAfterDel, equalTo(false)); + + String restore = exec(commandObjects.restore(key, 0, dumpedValue)); + assertThat(restore, equalTo("OK")); + + String restoredValue = exec(commandObjects.get(key)); + assertThat(restoredValue, equalTo(value)); + + Long ttlAfterRestore = exec(commandObjects.pttl(key)); + assertThat(ttlAfterRestore, equalTo(-1L)); + + exec(commandObjects.del(key)); + + Boolean existsAfterSecondDel = exec(commandObjects.exists(key)); + assertThat(existsAfterSecondDel, equalTo(false)); + + long ttl = 5000; // milliseconds + RestoreParams params = new RestoreParams().idleTime(500); + + String restoreWithParams = exec(commandObjects.restore(key, ttl, dumpedValue, params)); + assertThat(restoreWithParams, equalTo("OK")); + + String secondRestoredValue = exec(commandObjects.get(key)); + assertThat(secondRestoredValue, equalTo(value)); + + Long ttlAfterSecondRestore = exec(commandObjects.pttl(key)); + assertThat(ttlAfterSecondRestore, greaterThan(0L)); + } + + @Test + public void testDumpAndRestoreBinary() { + byte[] key = "dumpRestoreKey".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(key, value)); + + byte[] dumpedValue = exec(commandObjects.dump(key)); + assertThat(dumpedValue, notNullValue()); + + exec(commandObjects.del(key)); + + Boolean existsAfterDel = exec(commandObjects.exists(key)); + assertThat(existsAfterDel, equalTo(false)); + + String restore = exec(commandObjects.restore(key, 0, dumpedValue)); + assertThat(restore, equalTo("OK")); + + byte[] restoredValue = exec(commandObjects.get(key)); + assertThat(restoredValue, equalTo(value)); + + Long ttlAfterRestore = exec(commandObjects.pttl(key)); + assertThat(ttlAfterRestore, equalTo(-1L)); + + exec(commandObjects.del(key)); + + Boolean existsAfterSecondDel = exec(commandObjects.exists(key)); + assertThat(existsAfterSecondDel, equalTo(false)); + + long ttl = 5000; // milliseconds + RestoreParams params = new RestoreParams().idleTime(500); + + String restoreWithParams = exec(commandObjects.restore(key, ttl, dumpedValue, params)); + assertThat(restoreWithParams, equalTo("OK")); + + byte[] secondRestoredValue = exec(commandObjects.get(key)); + assertThat(secondRestoredValue, equalTo(value)); + + Long ttlAfterSecondRestore = exec(commandObjects.pttl(key)); + assertThat(ttlAfterSecondRestore, greaterThan(0L)); + } + + @Test + public void testExpireAndExpireTime() { + String key = "expireKey"; + String value = "value"; + + exec(commandObjects.set(key, value)); + + Long expireTimeBefore = exec(commandObjects.expireTime(key)); + assertThat(expireTimeBefore, equalTo(-1L)); + + long seconds = 60; + + Long expire = exec(commandObjects.expire(key, seconds)); + assertThat(expire, equalTo(1L)); + + Long expireTimeAfter = exec(commandObjects.expireTime(key)); + assertThat(expireTimeAfter, greaterThan(System.currentTimeMillis() / 1000)); + } + + @Test + public void testExpireAndExpireTimeBinary() { + byte[] key = "expireKey".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(key, value)); + + Long expireTimeBefore = exec(commandObjects.expireTime(key)); + assertThat(expireTimeBefore, equalTo(-1L)); + + long seconds = 60; + + Long expire = exec(commandObjects.expire(key, seconds)); + assertThat(expire, equalTo(1L)); + + Long expireTimeAfter = exec(commandObjects.expireTime(key)); + assertThat(expireTimeAfter, greaterThan(System.currentTimeMillis() / 1000)); + } + + @Test + public void testExpireWithExpiryOption() { + String key = "expireWithOptionKey"; + String value = "value"; + + exec(commandObjects.set(key, value)); + + Long expireTimeBefore = exec(commandObjects.expireTime(key)); + assertThat(expireTimeBefore, equalTo(-1L)); + + long seconds = 120; + ExpiryOption expiryOptionNX = ExpiryOption.NX; + + Long expireNx = exec(commandObjects.expire(key, seconds, expiryOptionNX)); + assertThat(expireNx, equalTo(1L)); + + Long expireNxAgain = exec(commandObjects.expire(key, seconds, expiryOptionNX)); + assertThat(expireNxAgain, equalTo(0L)); + + Long expireTimeAfter = exec(commandObjects.expireTime(key)); + assertThat(expireTimeAfter, greaterThan(System.currentTimeMillis() / 1000)); + } + + @Test + public void testExpireWithExpiryOptionTimeBinary() { + byte[] key = "expireWithOptionKey".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(key, value)); + + Long expireTimeBefore = exec(commandObjects.expireTime(key)); + assertThat(expireTimeBefore, equalTo(-1L)); + + long seconds = 120; + ExpiryOption expiryOptionNX = ExpiryOption.NX; + + Long expireNx = exec(commandObjects.expire(key, seconds, expiryOptionNX)); + assertThat(expireNx, equalTo(1L)); + + Long expireNxAgain = exec(commandObjects.expire(key, seconds, expiryOptionNX)); + assertThat(expireNxAgain, equalTo(0L)); + + Long expireTimeAfter = exec(commandObjects.expireTime(key)); + assertThat(expireTimeAfter, greaterThan(System.currentTimeMillis() / 1000)); + } + + @Test + public void testPexpireAndPexpireTime() { + String key = "pexpireKey"; + String value = "value"; + + exec(commandObjects.set(key, value)); + + long expireTimeMillis = 15000; // 15 seconds + + Long pexpireTimeBefore = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeBefore, equalTo(-1L)); + + Long pexpire = exec(commandObjects.pexpire(key, expireTimeMillis)); + assertThat(pexpire, equalTo(1L)); + + Long pexpireTimeAfter = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeAfter, greaterThan(System.currentTimeMillis())); + } + + @Test + public void testPexpireAndPexpireTimeBinary() { + byte[] key = "pexpireKey".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(key, value)); + + long expireTimeMillis = 15000; // 15 seconds + + Long pexpireTimeBefore = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeBefore, equalTo(-1L)); + + Long pexpire = exec(commandObjects.pexpire(key, expireTimeMillis)); + assertThat(pexpire, equalTo(1L)); + + Long pexpireTimeAfter = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeAfter, greaterThan(System.currentTimeMillis())); + } + + @Test + public void testPexpireWithOptionsAndPexpireTime() { + String key = "pexpireWithOptionsKey"; + String value = "value"; + + exec(commandObjects.set(key, value)); + + long expireTimeMillis = 20000; // 20 seconds + + Long pexpireTimeBefore = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeBefore, equalTo(-1L)); + + Long pexpire = exec(commandObjects.pexpire(key, expireTimeMillis, ExpiryOption.NX)); + assertThat(pexpire, equalTo(1L)); + + Long pexpireTimeAfterSet = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeAfterSet, greaterThan(System.currentTimeMillis())); + + Long pexpireWithNx = exec(commandObjects.pexpire(key, expireTimeMillis, ExpiryOption.NX)); + assertThat(pexpireWithNx, equalTo(0L)); + + Long pexpireWithXx = exec(commandObjects.pexpire(key, expireTimeMillis, ExpiryOption.XX)); + assertThat(pexpireWithXx, equalTo(1L)); + } + + @Test + public void testPexpireWithOptionsAndPexpireTimeBinary() { + byte[] key = "pexpireWithOptionsKey".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(key, value)); + + long expireTimeMillis = 20000; // 20 seconds + + Long pexpireTimeBefore = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeBefore, equalTo(-1L)); + + Long pexpire = exec(commandObjects.pexpire(key, expireTimeMillis, ExpiryOption.NX)); + assertThat(pexpire, equalTo(1L)); + + Long pexpireTimeAfterSet = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeAfterSet, greaterThan(System.currentTimeMillis())); + + Long pexpireWithNx = exec(commandObjects.pexpire(key, expireTimeMillis, ExpiryOption.NX)); + assertThat(pexpireWithNx, equalTo(0L)); + + Long pexpireWithXx = exec(commandObjects.pexpire(key, expireTimeMillis, ExpiryOption.XX)); + assertThat(pexpireWithXx, equalTo(1L)); + } + + @Test + public void testExpireAtAndExpireTime() { + String key = "expireAtKey"; + String value = "value"; + + exec(commandObjects.set(key, value)); + + long futureExpireTime = System.currentTimeMillis() / 1000 + 10; // 10 seconds from now + + // Setting expire at in the future + Long expireAt = exec(commandObjects.expireAt(key, futureExpireTime)); + assertThat(expireAt, equalTo(1L)); + + Long expireTime = exec(commandObjects.expireTime(key)); + assertThat(expireTime, equalTo(futureExpireTime)); + + // Setting expire at in the past should delete the key + long pastExpireTime = System.currentTimeMillis() / 1000 - 10; + Long expireAtPast = exec(commandObjects.expireAt(key, pastExpireTime)); + assertThat(expireAtPast, equalTo(1L)); + + Long expireTimeAfterPast = exec(commandObjects.expireTime(key)); + assertThat(expireTimeAfterPast, equalTo(-2L)); // Key does not exist + } + + @Test + public void testExpireAtAndExpireTimeBinary() { + byte[] key = "expireAtKey".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(key, value)); + + long futureExpireTime = System.currentTimeMillis() / 1000 + 10; // 10 seconds from now + + // Setting expire at in the future + Long expireAt = exec(commandObjects.expireAt(key, futureExpireTime)); + assertThat(expireAt, equalTo(1L)); + + Long expireTime = exec(commandObjects.expireTime(key)); + assertThat(expireTime, equalTo(futureExpireTime)); + + // Setting expire at in the past should delete the key + long pastExpireTime = System.currentTimeMillis() / 1000 - 10; + Long expireAtPast = exec(commandObjects.expireAt(key, pastExpireTime)); + assertThat(expireAtPast, equalTo(1L)); + + Long expireTimeAfterPast = exec(commandObjects.expireTime(key)); + assertThat(expireTimeAfterPast, equalTo(-2L)); // Key does not exist + } + + @Test + public void testExpireAtWithOptionsAndExpireTime() { + String key = "expireAtWithOptionsKey"; + String value = "value"; + + exec(commandObjects.set(key, value)); + + long futureExpireTime = System.currentTimeMillis() / 1000 + 20; // 20 seconds from now + + // Setting expire at in the future, with NX + Long expireAtNx = exec(commandObjects.expireAt(key, futureExpireTime, ExpiryOption.NX)); + assertThat(expireAtNx, equalTo(1L)); + + Long expireTimeAfterNx = exec(commandObjects.expireTime(key)); + assertThat(expireTimeAfterNx, equalTo(futureExpireTime)); + + // Update expire at in the future, with XX + long laterFutureExpireTime = futureExpireTime + 10; + Long expireAtXx = exec(commandObjects.expireAt(key, laterFutureExpireTime, ExpiryOption.XX)); + assertThat(expireAtXx, equalTo(1L)); + + Long expireTimeAfterXx = exec(commandObjects.expireTime(key)); + assertThat(expireTimeAfterXx, equalTo(laterFutureExpireTime)); + + // Try to reset with NX, should fail + Long expireAtNxAgain = exec(commandObjects.expireAt(key, futureExpireTime, ExpiryOption.NX)); + assertThat(expireAtNxAgain, equalTo(0L)); + + Long expireTimeAfterNxAgain = exec(commandObjects.expireTime(key)); + assertThat(expireTimeAfterNxAgain, equalTo(laterFutureExpireTime)); + } + + @Test + public void testExpireAtWithOptionsAndExpireTimeBinary() { + byte[] key = "expireAtWithOptionsKey".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(key, value)); + + long futureExpireTime = System.currentTimeMillis() / 1000 + 20; // 20 seconds from now + + // Setting expire at in the future, with NX + Long expireAtNx = exec(commandObjects.expireAt(key, futureExpireTime, ExpiryOption.NX)); + assertThat(expireAtNx, equalTo(1L)); + + Long expireTimeAfterNx = exec(commandObjects.expireTime(key)); + assertThat(expireTimeAfterNx, equalTo(futureExpireTime)); + + // Update expire at in the future, with XX + long laterFutureExpireTime = futureExpireTime + 10; + Long expireAtXx = exec(commandObjects.expireAt(key, laterFutureExpireTime, ExpiryOption.XX)); + assertThat(expireAtXx, equalTo(1L)); + + Long expireTime = exec(commandObjects.expireTime(key)); + assertThat(expireTime, equalTo(laterFutureExpireTime)); + + // Try to reset with NX, should fail + Long expireAtNxAgain = exec(commandObjects.expireAt(key, futureExpireTime, ExpiryOption.NX)); + assertThat(expireAtNxAgain, equalTo(0L)); + + Long expireTimeAfterNxAgain = exec(commandObjects.expireTime(key)); + assertThat(expireTimeAfterNxAgain, equalTo(laterFutureExpireTime)); + } + + @Test + public void testPexpireAtAndPexpireTime() { + String key = "pexpireAtKey"; + String value = "value"; + + exec(commandObjects.set(key, value)); + + long futureTimestampMillis = System.currentTimeMillis() + 20000; // 20 seconds from now + + Long pexpireAt = exec(commandObjects.pexpireAt(key, futureTimestampMillis)); + assertThat(pexpireAt, equalTo(1L)); + + Long pexpireTime = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTime, equalTo(futureTimestampMillis)); + + // Setting pexpire at a past timestamp should delete the key + long pastTimestampMillis = System.currentTimeMillis() - 20000; + Long pexpireAtPast = exec(commandObjects.pexpireAt(key, pastTimestampMillis)); + assertThat(pexpireAtPast, equalTo(1L)); + + Long pexpireTimeAfterPast = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeAfterPast, equalTo(-2L)); // Key does not exist + } + + @Test + public void testPexpireAtAndPexpireTimeBinary() { + byte[] key = "pexpireAtKey".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(key, value)); + + long futureTimestampMillis = System.currentTimeMillis() + 20000; // 20 seconds from now + + Long pexpireAt = exec(commandObjects.pexpireAt(key, futureTimestampMillis)); + assertThat(pexpireAt, equalTo(1L)); + + Long pexpireTime = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTime, equalTo(futureTimestampMillis)); + + // Setting pexpire at a past timestamp should delete the key + long pastTimestampMillis = System.currentTimeMillis() - 20000; + Long pexpireAtPast = exec(commandObjects.pexpireAt(key, pastTimestampMillis)); + assertThat(pexpireAtPast, equalTo(1L)); + + Long pexpireTimeAfterPast = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeAfterPast, equalTo(-2L)); // Key does not exist + } + + @Test + public void testPexpireAtWithOptionsAndPexpireTime() { + String key = "pexpireAtWithOptionsKey"; + String value = "value"; + + exec(commandObjects.set(key, value)); + + long futureTimestampMillis = System.currentTimeMillis() + 30000; // 30 seconds from now + + // Setting with NX + Long pexpireAtNx = exec(commandObjects.pexpireAt(key, futureTimestampMillis, ExpiryOption.NX)); + assertThat(pexpireAtNx, equalTo(1L)); + + Long pexpireTimeAfterNx = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeAfterNx, equalTo(futureTimestampMillis)); + + // Updating with XX + long laterFutureTimestampMillis = futureTimestampMillis + 10000; // Further 10 seconds in the future + Long pexpireAtXx = exec(commandObjects.pexpireAt(key, laterFutureTimestampMillis, ExpiryOption.XX)); + assertThat(pexpireAtXx, equalTo(1L)); + + Long pexpireTimeAfterXx = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeAfterXx, equalTo(laterFutureTimestampMillis)); + + // Updating with NX fails + Long pexpireAtNxAgain = exec(commandObjects.pexpireAt(key, futureTimestampMillis, ExpiryOption.NX)); + assertThat(pexpireAtNxAgain, equalTo(0L)); + + Long pexpireTimeAfterNxAgain = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeAfterNxAgain, equalTo(laterFutureTimestampMillis)); + } + + @Test + public void testPexpireAtWithOptionsAndPexpireTimeBinary() { + byte[] key = "pexpireAtWithOptionsKey".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(key, value)); + + long futureTimestampMillis = System.currentTimeMillis() + 30000; // 30 seconds from now + + // Setting with NX + Long pexpireAtNx = exec(commandObjects.pexpireAt(key, futureTimestampMillis, ExpiryOption.NX)); + assertThat(pexpireAtNx, equalTo(1L)); + + Long pexpireTimeAfterNx = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeAfterNx, equalTo(futureTimestampMillis)); + + // Updating with XX + long laterFutureTimestampMillis = futureTimestampMillis + 10000; // Further 10 seconds in the future + Long pexpireAtXx = exec(commandObjects.pexpireAt(key, laterFutureTimestampMillis, ExpiryOption.XX)); + assertThat(pexpireAtXx, equalTo(1L)); + + Long pexpireTimeAfterXx = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeAfterXx, equalTo(laterFutureTimestampMillis)); + + // Updating with NX fails + Long pexpireAtNxAgain = exec(commandObjects.pexpireAt(key, futureTimestampMillis, ExpiryOption.NX)); + assertThat(pexpireAtNxAgain, equalTo(0L)); + + Long pexpireTimeAfterNxAgain = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeAfterNxAgain, equalTo(laterFutureTimestampMillis)); + } + + @Test + public void testTtl() { + String key = "ttlKey"; + String value = "value"; + + long seconds = 10; + + exec(commandObjects.set(key, value)); + exec(commandObjects.expire(key, seconds)); + + Long ttl = exec(commandObjects.ttl(key)); + assertThat(ttl, greaterThan(0L)); + } + + @Test + public void testTtlBinary() { + byte[] key = "ttlKey".getBytes(); + byte[] value = "value".getBytes(); + + long seconds = 10; + + exec(commandObjects.set(key, value)); + exec(commandObjects.expire(key, seconds)); + + Long ttl = exec(commandObjects.ttl(key)); + assertThat(ttl, greaterThan(1L)); + } + + @Test + public void testPttl() { + String key = "pttlKey"; + String value = "value"; + + long milliseconds = 10000; // 10 seconds + + exec(commandObjects.set(key, value)); + exec(commandObjects.pexpire(key, milliseconds)); + + Long pttl = exec(commandObjects.pttl(key)); + assertThat(pttl, greaterThan(0L)); + } + + @Test + public void testPttlBinary() { + byte[] key = "pttlKey".getBytes(); + byte[] value = "value".getBytes(); + + long milliseconds = 10000; // 10 seconds + + exec(commandObjects.set(key, value)); + exec(commandObjects.pexpire(key, milliseconds)); + + Long pttl = exec(commandObjects.pttl(key)); + assertThat(pttl, greaterThan(1L)); + } + + @Test + public void testTouch() { + String key = "touchKey"; + + exec(commandObjects.set(key, "value")); + + Long touchExisting = exec(commandObjects.touch(key)); + assertThat(touchExisting, equalTo(1L)); + + Long touchNonExistent = exec(commandObjects.touch("nonExistentKey")); + assertThat(touchNonExistent, equalTo(0L)); + } + + @Test + public void testTouchBinary() { + byte[] key = "touchKey".getBytes(); + + exec(commandObjects.set(key, "value".getBytes())); + + Long touchExisting = exec(commandObjects.touch(key)); + assertThat(touchExisting, equalTo(1L)); + + Long touchNonExistent = exec(commandObjects.touch("nonExistentKey".getBytes())); + assertThat(touchNonExistent, equalTo(0L)); + } + + @Test + public void testTouchMultiple() { + String key1 = "touchMultiKey1"; + String key2 = "touchMultiKey2"; + String key3 = "nonExistentKey"; + + exec(commandObjects.set(key1, "value1")); + exec(commandObjects.set(key2, "value2")); + + Long touch = exec(commandObjects.touch(key1, key2, key3)); + assertThat(touch, equalTo(2L)); + } + + @Test + public void testTouchMultipleBinary() { + byte[] key1 = "touchMultiKey1".getBytes(); + byte[] key2 = "touchMultiKey2".getBytes(); + byte[] key3 = "nonExistentKey".getBytes(); + + exec(commandObjects.set(key1, "value1".getBytes())); + exec(commandObjects.set(key2, "value2".getBytes())); + + Long touch = exec(commandObjects.touch(key1, key2, key3)); + assertThat(touch, equalTo(2L)); + } + + @Test + public void testSort() { + String listKey = "sortList"; + + exec(commandObjects.lpush(listKey, "3", "1", "2")); + + List sorted = exec(commandObjects.sort(listKey)); + assertThat(sorted, contains("1", "2", "3")); + } + + @Test + public void testSortBinary() { + byte[] listKey = "sortList".getBytes(); + + exec(commandObjects.lpush(listKey, "3".getBytes(), "1".getBytes(), "2".getBytes())); + + List sorted = exec(commandObjects.sort(listKey)); + assertThat(sorted, contains("1".getBytes(), "2".getBytes(), "3".getBytes())); + } -/** - * Tests related to Generic commands. - */ -public class CommandObjectsGenericCommandsTest extends CommandObjectsStandaloneTestBase { + @Test + public void testSortWithSortingParams() { + String listKey = "sortListParams"; - public CommandObjectsGenericCommandsTest(RedisProtocol protocol) { - super(protocol); + exec(commandObjects.lpush(listKey, "item3", "item1", "item2")); + + SortingParams sortingParams = new SortingParams().alpha().limit(0, 2); + + List sorted = exec(commandObjects.sort(listKey, sortingParams)); + assertThat(sorted, contains("item1", "item2")); + } + + @Test + public void testSortBinaryWithSortingParams() { + byte[] listKey = "sortListParams".getBytes(); + + exec(commandObjects.lpush(listKey, "item3".getBytes(), "item1".getBytes(), "item2".getBytes())); + + SortingParams sortingParams = new SortingParams().alpha().limit(0, 2); + + List sorted = exec(commandObjects.sort(listKey, sortingParams)); + assertThat(sorted, contains("item1".getBytes(), "item2".getBytes())); + } + + @Test + public void testSortAndStore() { + String listKey = "sortStoreList"; + String destinationKey = "sortedList"; + + exec(commandObjects.lpush(listKey, "9", "3", "6")); + + Long sort = exec(commandObjects.sort(listKey, destinationKey)); + assertThat(sort, equalTo(3L)); + + List sorted = exec(commandObjects.lrange(destinationKey, 0, -1)); + assertThat(sorted, contains("3", "6", "9")); + } + + @Test + public void testSortAndStoreBinary() { + byte[] listKey = "sortStoreList".getBytes(); + byte[] destinationKey = "sortedList".getBytes(); + + exec(commandObjects.lpush(listKey, "9".getBytes(), "3".getBytes(), "6".getBytes())); + + Long sort = exec(commandObjects.sort(listKey, destinationKey)); + assertThat(sort, equalTo(3L)); + + List sorted = exec(commandObjects.lrange(destinationKey, 0, -1)); + assertThat(sorted, contains("3".getBytes(), "6".getBytes(), "9".getBytes())); + } + + @Test + public void testSortWithParamsAndStore() { + String listKey = "sortParamsStoreList"; + String destinationKey = "sortedParamsList"; + + exec(commandObjects.lpush(listKey, "item3", "item1", "item2")); + + SortingParams sortingParams = new SortingParams().alpha().limit(0, 2); + + Long sort = exec(commandObjects.sort(listKey, sortingParams, destinationKey)); + assertThat(sort, equalTo(2L)); + + List sorted = exec(commandObjects.lrange(destinationKey, 0, -1)); + assertThat(sorted, contains("item1", "item2")); + } + + @Test + public void testSortWithParamsAndStoreBinary() { + byte[] listKey = "sortParamsStoreList".getBytes(); + byte[] destinationKey = "sortedParamsList".getBytes(); + + exec(commandObjects.lpush(listKey, "item3".getBytes(), "item1".getBytes(), "item2".getBytes())); + + SortingParams sortingParams = new SortingParams().alpha().limit(0, 2); + + Long sort = exec(commandObjects.sort(listKey, sortingParams, destinationKey)); + assertThat(sort, equalTo(2L)); + + List sorted = exec(commandObjects.lrange(destinationKey, 0, -1)); + assertThat(sorted, contains("item1".getBytes(), "item2".getBytes())); + } + + @Test + public void testSortReadonly() { + String listKey = "readonlySortList"; + + exec(commandObjects.lpush(listKey, "3", "1", "2")); + + SortingParams sortingParams = new SortingParams().desc(); + + List sorted = exec(commandObjects.sortReadonly(listKey, sortingParams)); + assertThat(sorted, contains("3", "2", "1")); + } + + @Test + public void testSortReadonlyBinary() { + byte[] listKey = "readonlySortList".getBytes(); + + exec(commandObjects.lpush(listKey, "3".getBytes(), "1".getBytes(), "2".getBytes())); + + SortingParams sortingParams = new SortingParams().desc(); + + List sorted = exec(commandObjects.sortReadonly(listKey, sortingParams)); + assertThat(sorted, contains("3".getBytes(), "2".getBytes(), "1".getBytes())); + } + + @Test + public void testDel() { + String key = "delKey"; + String value = "value"; + + exec(commandObjects.set(key, value)); + + String getBeforeDel = exec(commandObjects.get(key)); + assertThat(getBeforeDel, equalTo(value)); + + Long del = exec(commandObjects.del(key)); + assertThat(del, equalTo(1L)); + + String getAfterDel = exec(commandObjects.get(key)); + assertThat(getAfterDel, nullValue()); + } + + @Test + public void testDelBinary() { + byte[] key = "delKey".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(key, value)); + + byte[] getBeforeDel = exec(commandObjects.get(key)); + assertThat(getBeforeDel, equalTo(value)); + + Long del = exec(commandObjects.del(key)); + assertThat(del, equalTo(1L)); + + byte[] getAfterDel = exec(commandObjects.get(key)); + assertThat(getAfterDel, nullValue()); + } + + @Test + public void testDelMultiple() { + String key1 = "key1"; + String key2 = "key2"; + + exec(commandObjects.set(key1, "value")); + exec(commandObjects.set(key2, "value")); + + Long del = exec(commandObjects.del(key1, key2, "nonExistingKey")); + assertThat(del, equalTo(2L)); + + Long exists = exec(commandObjects.exists(key1, key2)); + assertThat(exists, equalTo(0L)); + } + + @Test + public void testDelMultipleBinary() { + byte[] key1 = "key1".getBytes(); + byte[] key2 = "key2".getBytes(); + + exec(commandObjects.set(key1, "value".getBytes())); + exec(commandObjects.set(key2, "value".getBytes())); + + Long del = exec(commandObjects.del(key1, key2, "nonExistingKey".getBytes())); + assertThat(del, equalTo(2L)); + + Long exists = exec(commandObjects.exists(key1, key2)); + assertThat(exists, equalTo(0L)); + } + + @Test + public void testUnlink() { + String key = "unlinkKey"; + + exec(commandObjects.set(key, "value")); + + Long unlink = exec(commandObjects.unlink(key)); + assertThat(unlink, equalTo(1L)); + + Boolean exists = exec(commandObjects.exists(key)); + assertThat(exists, equalTo(false)); + } + + @Test + public void testUnlinkBinary() { + byte[] key = "unlinkKey".getBytes(); + + exec(commandObjects.set(key, "value".getBytes())); + + Long unlink = exec(commandObjects.unlink(key)); + assertThat(unlink, equalTo(1L)); + + Boolean exists = exec(commandObjects.exists(key)); + assertThat(exists, equalTo(false)); + } + + @Test + public void testUnlinkMultiple() { + String key1 = "key1ToUnlink"; + String key2 = "key2ToUnlink"; + + exec(commandObjects.set(key1, "value")); + exec(commandObjects.set(key2, "value")); + + Long unlink = exec(commandObjects.unlink(key1, key2, "nonExistingKey")); + assertThat(unlink, equalTo(2L)); + + Long exists = exec(commandObjects.exists(key1, key2)); + assertThat(exists, equalTo(0L)); + } + + @Test + public void testUnlinkMultipleBinary() { + byte[] key1 = "key1ToUnlink".getBytes(); + byte[] key2 = "key2ToUnlink".getBytes(); + + exec(commandObjects.set(key1, "value".getBytes())); + exec(commandObjects.set(key2, "value".getBytes())); + + Long unlink = exec(commandObjects.unlink(key1, key2, "nonExistingKey".getBytes())); + assertThat(unlink, equalTo(2L)); + + Long exists = exec(commandObjects.exists(key1, key2)); + assertThat(exists, equalTo(0L)); + } + + @Test + public void testCopyWithStringKeys() { + String srcKey = "sourceKey"; + String dstKey = "destinationKey"; + String value = "value"; + String otherValue = "otherValue"; + + exec(commandObjects.set(srcKey, value)); + + String initialValue = exec(commandObjects.get(srcKey)); + assertThat(initialValue, equalTo(value)); + + String dstBeforeCopy = exec(commandObjects.get(dstKey)); + assertThat(dstBeforeCopy, nullValue()); + + Boolean copy = exec(commandObjects.copy(srcKey, dstKey, false)); + assertThat(copy, equalTo(true)); + + String dstAfterCopy = exec(commandObjects.get(dstKey)); + assertThat(dstAfterCopy, equalTo(value)); + + exec(commandObjects.set(srcKey, otherValue)); + + Boolean copyFail = exec(commandObjects.copy(srcKey, dstKey, false)); + assertThat(copyFail, equalTo(false)); + + String dstAfterFailedCopy = exec(commandObjects.get(dstKey)); + assertThat(dstAfterFailedCopy, equalTo(value)); + + Boolean copyReplace = exec(commandObjects.copy(srcKey, dstKey, true)); + assertThat(copyReplace, equalTo(true)); + + String dstAfterReplace = exec(commandObjects.get(dstKey)); + assertThat(dstAfterReplace, equalTo(otherValue)); + } + + @Test + public void testCopyWithBinaryKeys() { + byte[] srcKey = "sourceKey".getBytes(); + byte[] dstKey = "destinationKey".getBytes(); + byte[] value = "value".getBytes(); + byte[] otherValue = "otherValue".getBytes(); + + exec(commandObjects.set(srcKey, value)); + + byte[] initialValue = exec(commandObjects.get(srcKey)); + assertThat(initialValue, equalTo(value)); + + byte[] dstBeforeCopy = exec(commandObjects.get(dstKey)); + assertThat(dstBeforeCopy, nullValue()); + + Boolean copy = exec(commandObjects.copy(srcKey, dstKey, false)); + assertThat(copy, equalTo(true)); + + byte[] dstAfterCopy = exec(commandObjects.get(dstKey)); + assertThat(dstAfterCopy, equalTo(value)); + + exec(commandObjects.set(srcKey, otherValue)); + + Boolean copyFail = exec(commandObjects.copy(srcKey, dstKey, false)); + assertThat(copyFail, equalTo(false)); + + byte[] dstAfterFailedCopy = exec(commandObjects.get(dstKey)); + assertThat(dstAfterFailedCopy, equalTo(value)); + + Boolean copyReplace = exec(commandObjects.copy(srcKey, dstKey, true)); + assertThat(copyReplace, equalTo(true)); + + byte[] dstAfterReplace = exec(commandObjects.get(dstKey)); + assertThat(dstAfterReplace, equalTo(otherValue)); } @Test - public void testCopy() { + public void testCopyToDb() { String srcKey = "sourceKey"; String dstKey = "destinationKey"; int dstDB = 1; @@ -43,7 +1054,7 @@ public void testCopy() { } @Test - public void testCopyBinary() { + public void testCopyToDbBinary() { String srcKey = "sourceKey"; String dstKey = "destinationKey"; int dstDB = 1; @@ -78,4 +1089,336 @@ private void assertKeyExists(int dstDb, String key, Object expectedValue) { } } + @Test + public void testRenameWithStringKeys() { + String oldKey = "oldKeyName"; + String newKey = "newKeyName"; + String value = "value"; + + exec(commandObjects.set(oldKey, value)); + + String oldValue = exec(commandObjects.get(oldKey)); + assertThat(oldValue, equalTo(value)); + + String newKeyBeforeRename = exec(commandObjects.get(newKey)); + assertThat(newKeyBeforeRename, nullValue()); + + String rename = exec(commandObjects.rename(oldKey, newKey)); + assertThat(rename, equalTo("OK")); + + String oldKeyAfterRename = exec(commandObjects.get(oldKey)); + assertThat(oldKeyAfterRename, nullValue()); + + String newValue = exec(commandObjects.get(newKey)); + assertThat(newValue, equalTo(value)); + } + + @Test + public void testRenameWithBinaryKeys() { + byte[] oldKey = "oldKeyName".getBytes(); + byte[] newKey = "newKeyName".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(oldKey, value)); + + byte[] oldValue = exec(commandObjects.get(oldKey)); + assertThat(oldValue, equalTo(value)); + + byte[] newKeyBeforeRename = exec(commandObjects.get(newKey)); + assertThat(newKeyBeforeRename, nullValue()); + + String rename = exec(commandObjects.rename(oldKey, newKey)); + assertThat(rename, equalTo("OK")); + + byte[] oldKeyAfterRename = exec(commandObjects.get(oldKey)); + assertThat(oldKeyAfterRename, nullValue()); + + byte[] newValue = exec(commandObjects.get(newKey)); + assertThat(newValue, equalTo(value)); + } + + @Test + public void testRenamenx() { + String oldKey = "oldKeyToRenameNX"; + String newKey = "newKeyForRenameNX"; + String anotherKey = "anotherKey"; + String value = "value"; + + exec(commandObjects.set(oldKey, value)); + exec(commandObjects.set(anotherKey, value)); + + String newKeyBefore = exec(commandObjects.get(newKey)); + assertThat(newKeyBefore, nullValue()); + + Long renamenx = exec(commandObjects.renamenx(oldKey, newKey)); + assertThat(renamenx, equalTo(1L)); + + String newValue = exec(commandObjects.get(newKey)); + assertThat(newValue, equalTo(value)); + + Long renamenxFail = exec(commandObjects.renamenx(anotherKey, newKey)); + assertThat(renamenxFail, equalTo(0L)); + + String anotherKeyStillExists = exec(commandObjects.get(anotherKey)); + assertThat(anotherKeyStillExists, equalTo(value)); + } + + @Test + public void testRenamenxBinary() { + byte[] oldKey = "oldKeyToRenameNX".getBytes(); + byte[] newKey = "newKeyForRenameNX".getBytes(); + byte[] anotherKey = "anotherKey".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(oldKey, value)); + exec(commandObjects.set(anotherKey, value)); + + byte[] newKeyBefore = exec(commandObjects.get(newKey)); + assertThat(newKeyBefore, nullValue()); + + Long renamenx = exec(commandObjects.renamenx(oldKey, newKey)); + assertThat(renamenx, equalTo(1L)); + + byte[] newValue = exec(commandObjects.get(newKey)); + assertThat(newValue, equalTo(value)); + + Long renamenxFail = exec(commandObjects.renamenx(anotherKey, newKey)); + assertThat(renamenxFail, equalTo(0L)); + + byte[] anotherKeyStillExists = exec(commandObjects.get(anotherKey)); + assertThat(anotherKeyStillExists, equalTo(value)); + } + + @Test + public void testDbSize() { + Long initialSize = exec(commandObjects.dbSize()); + assertThat(initialSize, greaterThanOrEqualTo(0L)); + + String key = "testKey"; + + exec(commandObjects.set(key, "testValue")); + + Long newSize = exec(commandObjects.dbSize()); + assertThat(newSize, equalTo(initialSize + 1)); + + exec(commandObjects.del(key)); + + Long finalSize = exec(commandObjects.dbSize()); + assertThat(finalSize, equalTo(initialSize)); + } + + @Test + public void testKeysWithStringPattern() { + String pattern = "testKey:*"; + String matchingKey1 = "testKey:1"; + String matchingKey2 = "testKey:2"; + String value = "value"; + + exec(commandObjects.set(matchingKey1, value)); + exec(commandObjects.set(matchingKey2, value)); + exec(commandObjects.set("otherKey", value)); + + Set keys = exec(commandObjects.keys(pattern)); + assertThat(keys, containsInAnyOrder(matchingKey1, matchingKey2)); + + exec(commandObjects.del(matchingKey1, matchingKey2)); + + Set keysAfterDeletion = exec(commandObjects.keys(pattern)); + assertThat(keysAfterDeletion, empty()); + } + + @Test + public void testKeysWithBinaryPattern() { + byte[] pattern = "testKey:*".getBytes(); + byte[] matchingKey1 = "testKey:1".getBytes(); + byte[] matchingKey2 = "testKey:2".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(matchingKey1, value)); + exec(commandObjects.set(matchingKey2, value)); + exec(commandObjects.set("otherKey".getBytes(), value)); + + Set keys = exec(commandObjects.keys(pattern)); + assertThat(keys, containsInAnyOrder(matchingKey1, matchingKey2)); + + exec(commandObjects.del(matchingKey1, matchingKey2)); + + Set keysAfterDeletion = exec(commandObjects.keys(pattern)); + assertThat(keysAfterDeletion, empty()); + } + + @Test + public void testScan() { + String key1 = "scanKey1"; + String key2 = "scanKey2"; + + exec(commandObjects.set(key1, "value")); + exec(commandObjects.set(key2, "value")); + + Set collectedKeys = new HashSet<>(); + + ScanResult scanResult; + String nextCursor = "0"; + + do { + scanResult = exec(commandObjects.scan(nextCursor)); + nextCursor = scanResult.getCursor(); + collectedKeys.addAll(scanResult.getResult()); + } while (!"0".equals(nextCursor)); + + assertThat(collectedKeys, hasItems(key1, key2)); + } + + @Test + public void testScanBinary() { + byte[] key1 = "scanKey1".getBytes(); + byte[] key2 = "scanKey2".getBytes(); + + exec(commandObjects.set(key1, "value".getBytes())); + exec(commandObjects.set(key2, "value".getBytes())); + + Set collectedKeys = new HashSet<>(); + + ScanResult scanResult; + byte[] cursor = "0".getBytes(); + + do { + scanResult = exec(commandObjects.scan(cursor)); + cursor = scanResult.getCursorAsBytes(); + collectedKeys.addAll(scanResult.getResult()); + } while (!Arrays.equals("0".getBytes(), cursor)); + + assertThat(collectedKeys, hasItems(key1, key2)); + } + + @Test + public void testScanWithParams() { + String matchingKey1 = "user:123"; + String matchingKey2 = "user:456"; + String nonMatchingKey = "config:123"; + + exec(commandObjects.set(matchingKey1, "testValue")); + exec(commandObjects.set(matchingKey2, "testValue")); + exec(commandObjects.set(nonMatchingKey, "testValue")); + + ScanParams params = new ScanParams().match("user:*").count(2); + + Set collectedKeys = new HashSet<>(); + + ScanResult scanResult; + String cursor = "0"; + + do { + scanResult = exec(commandObjects.scan(cursor, params)); + collectedKeys.addAll(scanResult.getResult()); + cursor = scanResult.getCursor(); + } while (!"0".equals(scanResult.getCursor())); + + assertThat(collectedKeys, hasItems(matchingKey1, matchingKey2)); + assertThat(collectedKeys, not(hasItem(nonMatchingKey))); + } + + @Test + public void testScanWithParamsBinary() { + byte[] matchingKey1 = "user:123".getBytes(); + byte[] matchingKey2 = "user:456".getBytes(); + byte[] nonMatchingKey = "config:123".getBytes(); + + exec(commandObjects.set(matchingKey1, "testValue".getBytes())); + exec(commandObjects.set(matchingKey2, "testValue".getBytes())); + exec(commandObjects.set(nonMatchingKey, "testValue".getBytes())); + + ScanParams params = new ScanParams().match("user:*").count(2); + + Set collectedKeys = new HashSet<>(); + + ScanResult scanResult; + byte[] cursor = "0".getBytes(); + + do { + scanResult = exec(commandObjects.scan(cursor, params)); + collectedKeys.addAll(scanResult.getResult()); + cursor = scanResult.getCursorAsBytes(); + } while (!Arrays.equals("0".getBytes(), cursor)); + + assertThat(collectedKeys, hasItems(matchingKey1, matchingKey2)); + assertThat(collectedKeys, not(hasItem(nonMatchingKey))); + } + + @Test + public void testScanWithParamsAndType() { + String stringKey = "user:string:1"; + String listKey = "user:list:1"; + + exec(commandObjects.set(stringKey, "value")); + exec(commandObjects.rpush(listKey, "value1", "value2")); + + ScanParams params = new ScanParams().match("user:*"); + + Set collectedKeys = new HashSet<>(); + + ScanResult scanResult; + String cursor = "0"; + + do { + scanResult = exec(commandObjects.scan(cursor, params, "string")); + collectedKeys.addAll(scanResult.getResult()); + cursor = scanResult.getCursor(); + } while (!"0".equals(scanResult.getCursor())); + + assertThat(collectedKeys, hasItem(stringKey)); + assertThat(collectedKeys, not(hasItem(listKey))); + } + + @Test + public void testScanWithParamsAndTypeBinary() { + byte[] stringKey = "user:string:1".getBytes(); + byte[] listKey = "user:list:1".getBytes(); + + exec(commandObjects.set(stringKey, "value".getBytes())); + exec(commandObjects.rpush(listKey, "value1".getBytes(), "value2".getBytes())); + + ScanParams params = new ScanParams().match("user:*".getBytes()); + + Set collectedKeys = new HashSet<>(); + + ScanResult scanResult; + byte[] cursor = "0".getBytes(); + + do { + scanResult = exec(commandObjects.scan(cursor, params, "string".getBytes())); + collectedKeys.addAll(scanResult.getResult()); + cursor = scanResult.getCursorAsBytes(); + } while (!Arrays.equals("0".getBytes(), cursor)); + + assertThat(collectedKeys, hasItem(stringKey)); + assertThat(collectedKeys, not(hasItem(listKey))); + } + + @Test + public void testRandomKey() { + String key1 = "testKey1"; + String key2 = "testKey2"; + + exec(commandObjects.set(key1, "value")); + exec(commandObjects.set(key2, "value")); + + String randomKey = exec(commandObjects.randomKey()); + + assertThat(randomKey, anyOf(equalTo(key1), equalTo(key2))); + } + + @Test + public void testRandomBinaryKey() { + byte[] key1 = "testKey1".getBytes(); + byte[] key2 = "testKey2".getBytes(); + + exec(commandObjects.set(key1, "value".getBytes())); + exec(commandObjects.set(key2, "value".getBytes())); + + byte[] randomBinaryKey = exec(commandObjects.randomBinaryKey()); + + assertThat(randomBinaryKey, anyOf(equalTo(key1), equalTo(key2))); + } + } diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSearchAndQueryCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSearchAndQueryCommandsTest.java index d1b1eaacaa..4fd7c60fc4 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSearchAndQueryCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSearchAndQueryCommandsTest.java @@ -1,19 +1,29 @@ package redis.clients.jedis.commands.commandobjects; +import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.anEmptyMap; import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.emptyOrNullString; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.equalToIgnoringCase; import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.hasKey; import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; import org.json.JSONObject; @@ -21,8 +31,12 @@ import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.args.SortingOrder; import redis.clients.jedis.json.Path2; +import redis.clients.jedis.resps.Tuple; import redis.clients.jedis.search.Document; +import redis.clients.jedis.search.FTCreateParams; import redis.clients.jedis.search.FTSearchParams; +import redis.clients.jedis.search.FTSpellCheckParams; +import redis.clients.jedis.search.IndexDataType; import redis.clients.jedis.search.IndexDefinition; import redis.clients.jedis.search.IndexOptions; import redis.clients.jedis.search.Query; @@ -31,6 +45,10 @@ import redis.clients.jedis.search.aggr.AggregationBuilder; import redis.clients.jedis.search.aggr.AggregationResult; import redis.clients.jedis.search.aggr.Reducers; +import redis.clients.jedis.search.schemafields.NumericField; +import redis.clients.jedis.search.schemafields.SchemaField; +import redis.clients.jedis.search.schemafields.TagField; +import redis.clients.jedis.search.schemafields.TextField; /** * Tests related to Search and query commands. @@ -169,6 +187,108 @@ public void testFtSearchJson() { assertThat(document.get("$"), equalTo("{\"title\":\"Redis in Action\",\"price\":17.99,\"author\":\"John Doe\"}")); } + @Test + public void testFtCreateWithParams() { + String indexName = "booksIndex"; + + SchemaField[] schema = { + TextField.of("$.title").as("title"), + NumericField.of("$.price").as("price") + }; + + FTCreateParams createParams = FTCreateParams.createParams() + .on(IndexDataType.JSON) + .addPrefix("books:"); + + String createResult = exec(commandObjects.ftCreate(indexName, createParams, Arrays.asList(schema))); + assertThat(createResult, equalTo("OK")); + + JSONObject bookRedisInAction = new JSONObject(); + bookRedisInAction.put("title", "Redis in Action"); + bookRedisInAction.put("price", 17.99); + bookRedisInAction.put("author", "John Doe"); + + String jsonSet = exec(commandObjects.jsonSet("books:1000", Path2.ROOT_PATH, bookRedisInAction)); + assertThat(jsonSet, equalTo("OK")); + + JSONObject bookRedisEssentials = new JSONObject(); + bookRedisEssentials.put("title", "Redis Essentials"); + bookRedisEssentials.put("price", 19.99); + bookRedisEssentials.put("author", "Jane Doe"); + + String jsonSet2 = exec(commandObjects.jsonSet("books:1200", Path2.ROOT_PATH, bookRedisEssentials)); + assertThat(jsonSet2, equalTo("OK")); + + SearchResult searchResult = exec(commandObjects.ftSearch(indexName, "Action")); + + assertThat(searchResult.getTotalResults(), equalTo(1L)); + assertThat(searchResult.getDocuments(), hasSize(1)); + + Document document = searchResult.getDocuments().get(0); + assertThat(document.getId(), equalTo("books:1000")); + + Object documentRoot = document.get("$"); + assertThat(documentRoot, instanceOf(String.class)); // Unparsed! + assertThat(documentRoot, jsonEquals(bookRedisInAction)); + } + + @Test + public void testFtAlterWithParams() throws InterruptedException { + String indexName = "booksIndex"; + + List schema = new ArrayList<>(); + schema.add(TextField.of("$.title").as("title")); + schema.add(NumericField.of("$.price").as("price")); + + FTCreateParams createParams = FTCreateParams.createParams() + .on(IndexDataType.JSON) + .addPrefix("books:"); + + String createResult = exec(commandObjects.ftCreate(indexName, createParams, schema)); + assertThat(createResult, equalTo("OK")); + + JSONObject bookRedisInAction = new JSONObject(); + bookRedisInAction.put("title", "Redis in Action"); + bookRedisInAction.put("price", 17.99); + bookRedisInAction.put("author", "John Doe"); + + String jsonSet = exec(commandObjects.jsonSet("books:1000", Path2.ROOT_PATH, bookRedisInAction)); + assertThat(jsonSet, equalTo("OK")); + + JSONObject bookRedisEssentials = new JSONObject(); + bookRedisEssentials.put("title", "Redis Essentials"); + bookRedisEssentials.put("price", 19.99); + bookRedisEssentials.put("author", "Jane Doe"); + + String jsonSet2 = exec(commandObjects.jsonSet("books:1200", Path2.ROOT_PATH, bookRedisEssentials)); + assertThat(jsonSet2, equalTo("OK")); + + SearchResult searchNotInIndex = exec(commandObjects.ftSearch(indexName, "John")); + + assertThat(searchNotInIndex.getTotalResults(), equalTo(0L)); + assertThat(searchNotInIndex.getDocuments(), empty()); + + List schemaExtension = new ArrayList<>(); + schemaExtension.add(TextField.of("$.author").as("author")); + + String alter = exec(commandObjects.ftAlter(indexName, schemaExtension)); + assertThat(alter, equalTo("OK")); + + Thread.sleep(300); // wait for index to be updated + + SearchResult searchInIndex = exec(commandObjects.ftSearch(indexName, "John")); + + assertThat(searchInIndex.getTotalResults(), equalTo(1L)); + assertThat(searchInIndex.getDocuments(), hasSize(1)); + + Document document = searchInIndex.getDocuments().get(0); + assertThat(document.getId(), equalTo("books:1000")); + + Object documentRoot = document.get("$"); + assertThat(documentRoot, instanceOf(String.class)); // Unparsed! + assertThat(documentRoot, jsonEquals(bookRedisInAction)); + } + @Test public void testFtExplain() { String indexName = "booksIndex"; @@ -252,4 +372,213 @@ public void testFtAggregate() { assertThat(result, hasEntry("genre", "Technology")); assertThat(result, hasEntry("avgPrice", "23.49")); } + + @Test + public void testSpellCheck() { + // Add some terms to an index + String indexName = "techArticles"; + + List schemaFields = Collections.singletonList(TextField.of("$.technology")); + exec(commandObjects.ftCreate(indexName, FTCreateParams.createParams().on(IndexDataType.JSON), schemaFields)); + + exec(commandObjects.jsonSet("articles:02", Path2.ROOT_PATH, new JSONObject().put("technology", "Flutter"))); + exec(commandObjects.jsonSet("articles:03", Path2.ROOT_PATH, new JSONObject().put("technology", "Rust"))); + exec(commandObjects.jsonSet("articles:04", Path2.ROOT_PATH, new JSONObject().put("technology", "Angular"))); + + SearchResult searchInIndex = exec(commandObjects.ftSearch(indexName, "Flutter")); + assertThat(searchInIndex.getTotalResults(), equalTo(1L)); + + String query = "Fluter JavaScrit Pyhton Rust"; + + // Spellcheck based on index only + Map> indexOnly = exec(commandObjects.ftSpellCheck(indexName, query)); + assertThat(indexOnly.get("fluter"), hasKey(equalToIgnoringCase("Flutter"))); + assertThat(indexOnly.get("javascrit"), anEmptyMap()); + assertThat(indexOnly.get("pyhton"), anEmptyMap()); + + // Add more terms to a dictionary + String dictionary = "techDict"; + + Long addResult = exec(commandObjects.ftDictAdd(dictionary, "JavaScript", "Python")); + assertThat(addResult, equalTo(2L)); + + // Spellcheck based on index and dictionary + FTSpellCheckParams paramsWithDict = new FTSpellCheckParams().includeTerm(dictionary); + + Map> indexAndDictionary = exec(commandObjects.ftSpellCheck(indexName, query, paramsWithDict)); + assertThat(indexAndDictionary.get("fluter"), hasKey(equalToIgnoringCase("Flutter"))); + assertThat(indexAndDictionary.get("javascrit"), hasKey("JavaScript")); + assertThat(indexAndDictionary.get("pyhton"), anEmptyMap()); + + // Increase Levenshtein distance, to allow for misspelled letter + FTSpellCheckParams paramsWithDictAndDist = new FTSpellCheckParams().includeTerm(dictionary).distance(2); + + Map> indexAndDictionaryWithDist = exec(commandObjects.ftSpellCheck(indexName, query, paramsWithDictAndDist)); + assertThat(indexAndDictionaryWithDist.get("fluter"), hasKey(equalToIgnoringCase("Flutter"))); + assertThat(indexAndDictionaryWithDist.get("javascrit"), hasKey("JavaScript")); + assertThat(indexAndDictionaryWithDist.get("pyhton"), hasKey("Python")); + } + + @Test + public void testFtDictAddDelAndDump() { + String dictionary = "programmingLanguages"; + + Long addResult = exec(commandObjects.ftDictAdd(dictionary, "Java", "Python", "JavaScript", "Rust")); + assertThat(addResult, equalTo(4L)); + + Set dumpResultAfterAdd = exec(commandObjects.ftDictDump(dictionary)); + assertThat(dumpResultAfterAdd, containsInAnyOrder("Java", "Python", "JavaScript", "Rust")); + + Long delResult = exec(commandObjects.ftDictDel(dictionary, "Rust")); + assertThat(delResult, equalTo(1L)); + + Set dumpResultAfterDel = exec(commandObjects.ftDictDump(dictionary)); + assertThat(dumpResultAfterDel, containsInAnyOrder("Java", "Python", "JavaScript")); + } + + @Test + public void testFtDictAddDelAndDumpWithSampleKeys() { + String index = "index"; // not used actually, but needed for the command + + String dictionary = "programmingLanguages"; + + Long addResult = exec(commandObjects.ftDictAddBySampleKey(index, dictionary, "Java", "Python", "JavaScript", "Rust")); + assertThat(addResult, equalTo(4L)); + + Set dumpResultAfterAdd = exec(commandObjects.ftDictDumpBySampleKey(index, dictionary)); + assertThat(dumpResultAfterAdd, containsInAnyOrder("Java", "Python", "JavaScript", "Rust")); + + Long delResult = exec(commandObjects.ftDictDelBySampleKey(index, dictionary, "Rust")); + assertThat(delResult, equalTo(1L)); + + Set dumpResultAfterDel = exec(commandObjects.ftDictDumpBySampleKey(index, dictionary)); + assertThat(dumpResultAfterDel, containsInAnyOrder("Java", "Python", "JavaScript")); + } + + @Test + public void testFtTags() { + String indexName = "booksIndex"; + + SchemaField[] schema = { + TextField.of("$.title"), + TagField.of("$.genre").as("genre").separator(',') + }; + + FTCreateParams createParams = FTCreateParams.createParams() + .on(IndexDataType.JSON) + .addPrefix("books:"); + + String createResult = exec(commandObjects.ftCreate(indexName, createParams, Arrays.asList(schema))); + assertThat(createResult, equalTo("OK")); + + JSONObject bookDune = new JSONObject(); + bookDune.put("title", "Dune"); + bookDune.put("genre", "Science Fiction, Fantasy, Adventure"); + + String jsonSet = exec(commandObjects.jsonSet("books:1000", Path2.ROOT_PATH, bookDune)); + assertThat(jsonSet, equalTo("OK")); + + JSONObject bookTheFoundation = new JSONObject(); + bookTheFoundation.put("title", "The Foundation"); + bookTheFoundation.put("genre", "Technical, Novel, Essential"); + + String jsonSet2 = exec(commandObjects.jsonSet("books:1200", Path2.ROOT_PATH, bookTheFoundation)); + assertThat(jsonSet2, equalTo("OK")); + + Set tagVals = exec(commandObjects.ftTagVals(indexName, "genre")); + assertThat(tagVals, containsInAnyOrder( + "science fiction", "fantasy", "adventure", "technical", "novel", "essential")); + + SearchResult searchSimple = exec(commandObjects.ftSearch(indexName, "Fantasy")); + + assertThat(searchSimple.getTotalResults(), equalTo(0L)); + assertThat(searchSimple.getDocuments(), empty()); + + SearchResult searchSpecialSyntax = exec(commandObjects.ftSearch(indexName, "@genre:{ fantasy }")); + + assertThat(searchSpecialSyntax.getTotalResults(), equalTo(1L)); + assertThat(searchSpecialSyntax.getDocuments(), hasSize(1)); + + Document document = searchSpecialSyntax.getDocuments().get(0); + assertThat(document.getId(), equalTo("books:1000")); + + Object documentRoot = document.get("$"); + assertThat(documentRoot, instanceOf(String.class)); // Unparsed! + assertThat(documentRoot, jsonEquals(bookDune)); + } + + @Test + public void testFtInfo() { + String indexName = "booksIndex"; + + SchemaField[] schema = { + TextField.of("$.title"), + TagField.of("$.genre").as("genre").separator(',') + }; + + FTCreateParams createParams = FTCreateParams.createParams() + .on(IndexDataType.JSON) + .addPrefix("books:"); + + String createResult = exec(commandObjects.ftCreate(indexName, createParams, Arrays.asList(schema))); + assertThat(createResult, equalTo("OK")); + + JSONObject bookDune = new JSONObject(); + bookDune.put("title", "Dune"); + bookDune.put("genre", "Science Fiction, Fantasy, Adventure"); + + String jsonSet = exec(commandObjects.jsonSet("books:1000", Path2.ROOT_PATH, bookDune)); + assertThat(jsonSet, equalTo("OK")); + + JSONObject bookTheFoundation = new JSONObject(); + bookTheFoundation.put("title", "The Foundation"); + bookTheFoundation.put("genre", "Technical, Novel, Essential"); + + String jsonSet2 = exec(commandObjects.jsonSet("books:1200", Path2.ROOT_PATH, bookTheFoundation)); + assertThat(jsonSet2, equalTo("OK")); + + Map infoResult = exec(commandObjects.ftInfo(indexName)); + assertThat(infoResult, hasEntry("index_name", indexName)); + } + + @Test + public void testFtSugAddAndGet() { + String key = "autocomplete"; + + // Round 1: single suggestion with weight 2.0 + Long sugAdd1 = exec(commandObjects.ftSugAdd(key, "Redis", 2.0)); + assertThat(sugAdd1, equalTo(1L)); + + List suggestionsOneOption = exec(commandObjects.ftSugGet(key, "Re")); + assertThat(suggestionsOneOption, contains("Redis")); + + List suggestionsWithScoresOneOption = exec(commandObjects.ftSugGetWithScores(key, "Re")); + assertThat(suggestionsWithScoresOneOption, contains( + new Tuple("Redis", 1.0))); + + // Round 2: two suggestions with weights 2.0 and 1.0 + Long sugAdd2 = exec(commandObjects.ftSugAdd(key, "Redux", 1.0)); + assertThat(sugAdd2, equalTo(2L)); + + List suggestionsTwoOptions = exec(commandObjects.ftSugGet(key, "Re")); + assertThat(suggestionsTwoOptions, contains("Redis", "Redux")); + + List suggestionsWithScoresTwoOptions = exec(commandObjects.ftSugGetWithScores(key, "Re")); + assertThat(suggestionsWithScoresTwoOptions, contains( + new Tuple("Redis", 1.0), + new Tuple("Redux", 0.5))); + + // Round 2: same two suggestions with weights 2.0 and 3.0 + Long sugAddIncr = exec(commandObjects.ftSugAddIncr(key, "Redux", 2.0)); + assertThat(sugAddIncr, equalTo(2L)); + + List suggestionsAfterScoreChange = exec(commandObjects.ftSugGet(key, "Re")); + assertThat(suggestionsAfterScoreChange, contains("Redux", "Redis")); + + List suggestionsWithScoresAfterChange = exec(commandObjects.ftSugGetWithScores(key, "Re")); + assertThat(suggestionsWithScoresAfterChange, contains( + new Tuple("Redux", 1.5), + new Tuple("Redis", 1.0))); + } + } diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSortedSetCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSortedSetCommandsTest.java index cf2be1b0a7..21a573c8db 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSortedSetCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSortedSetCommandsTest.java @@ -1470,6 +1470,60 @@ public void testZmpopAndZmpopWithCountBinary() { @Test public void testBzmpop() { + String key1 = "sortedSet1"; + String key2 = "sortedSet2"; + double score1 = 1.0; + double score2 = 2.0; + String member1 = "member1"; + String member2 = "member2"; + double timeout = 0.1; + + exec(commandObjects.zadd(key1, score1, member1)); + exec(commandObjects.zadd(key1, score2, member2)); + + exec(commandObjects.zadd(key2, score1, member1)); + exec(commandObjects.zadd(key2, score2, member2)); + + KeyValue> bzmpopMax = exec(commandObjects.bzmpop(timeout, SortedSetOption.MAX, key1, key2)); + assertThat(bzmpopMax, notNullValue()); + assertThat(bzmpopMax.getKey(), anyOf(equalTo(key1), equalTo(key2))); + assertThat(bzmpopMax.getValue(), contains(new Tuple(member2, score2))); + + KeyValue> bzmpopMin = exec(commandObjects.bzmpop(timeout, SortedSetOption.MIN, key1, key2)); + assertThat(bzmpopMin, notNullValue()); + assertThat(bzmpopMin.getKey(), anyOf(equalTo(key1), equalTo(key2))); + assertThat(bzmpopMin.getValue(), contains(new Tuple(member1, score1))); + } + + @Test + public void testBzmpopBinary() { + byte[] key1 = "sortedSet1".getBytes(); + byte[] key2 = "sortedSet2".getBytes(); + double score1 = 1.0; + double score2 = 2.0; + byte[] member1 = "member1".getBytes(); + byte[] member2 = "member2".getBytes(); + double timeout = 0.1; + + exec(commandObjects.zadd(key1, score1, member1)); + exec(commandObjects.zadd(key1, score2, member2)); + + exec(commandObjects.zadd(key2, score1, member1)); + exec(commandObjects.zadd(key2, score2, member2)); + + KeyValue> bzmpopMax = exec(commandObjects.bzmpop(timeout, SortedSetOption.MAX, key1, key2)); + assertThat(bzmpopMax, notNullValue()); + assertThat(bzmpopMax.getKey(), anyOf(equalTo(key1), equalTo(key2))); + assertThat(bzmpopMax.getValue(), contains(new Tuple(member2, score2))); + + KeyValue> bzmpopMin = exec(commandObjects.bzmpop(timeout, SortedSetOption.MIN, key1, key2)); + assertThat(bzmpopMin, notNullValue()); + assertThat(bzmpopMin.getKey(), anyOf(equalTo(key1), equalTo(key2))); + assertThat(bzmpopMin.getValue(), contains(new Tuple(member1, score1))); + } + + @Test + public void testBzmpopCount() { String key1 = "sortedSet1"; String key2 = "sortedSet2"; double score1 = 1.0; @@ -1488,7 +1542,7 @@ public void testBzmpop() { } @Test - public void testBzmpopBinary() { + public void testBzmpopCountBinary() { byte[] key1 = "sortedSet1".getBytes(); byte[] key2 = "sortedSet2".getBytes(); double score1 = 1.0; diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStreamCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStreamCommandsTest.java index 2978544093..8d01e4283c 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStreamCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStreamCommandsTest.java @@ -3,8 +3,10 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.lessThanOrEqualTo; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; @@ -24,6 +26,7 @@ import redis.clients.jedis.params.XPendingParams; import redis.clients.jedis.params.XReadGroupParams; import redis.clients.jedis.params.XReadParams; +import redis.clients.jedis.params.XTrimParams; import redis.clients.jedis.resps.StreamConsumerInfo; import redis.clients.jedis.resps.StreamConsumersInfo; import redis.clients.jedis.resps.StreamEntry; @@ -301,6 +304,26 @@ public void testXrevrangeWithBinaryParameters() { assertThat(xrevrangeUnknown, empty()); } + @Test + public void testXaddWithNullId() { + String key = "testStreamWithString"; + + // Add two entries, don't specify the IDs + StreamEntryID firstId = exec(commandObjects.xadd(key, (StreamEntryID) null, Collections.singletonMap("field", "value"))); + assertThat(firstId, notNullValue()); + + StreamEntryID secondId = exec(commandObjects.xadd(key, (StreamEntryID) null, Collections.singletonMap("field", "value"))); + assertThat(secondId, notNullValue()); + + assertThat(secondId, not(equalTo(firstId))); + assertThat(secondId.getSequence(), greaterThanOrEqualTo(firstId.getSequence())); + + List xrangeAll = exec(commandObjects.xrange(key, (StreamEntryID) null, null)); + assertThat(xrangeAll.size(), equalTo(2)); + assertThat(xrangeAll.get(0).getID(), equalTo(firstId)); + assertThat(xrangeAll.get(1).getID(), equalTo(secondId)); + } + @Test public void testXackXpending() { String key = "testStreamForXackEffect"; @@ -568,27 +591,86 @@ public void testXTrimCommands() { Long sizeBeforeTrim = exec(commandObjects.xlen(key)); assertThat(sizeBeforeTrim, equalTo(10L)); - Long xtrim = exec(commandObjects.xtrim(key, 5, false)); - assertThat(xtrim, equalTo(5L)); + Long xtrim = exec(commandObjects.xtrim(key, 6, false)); + assertThat(xtrim, equalTo(4L)); Long sizeAfterTrim = exec(commandObjects.xlen(key)); - assertThat(sizeAfterTrim, equalTo(5L)); + assertThat(sizeAfterTrim, equalTo(6L)); - // Repopulate the stream for byte[] parameter tests. - // Adding back 5 entries to ensure we have 10 again. - byte[] bKey = key.getBytes(); - for (int i = 5; i < 10; i++) { - exec(commandObjects.xadd(key, StreamEntryID.NEW_ENTRY, Collections.singletonMap("field" + i, "value" + i))); + Long xtrimApproximate = exec(commandObjects.xtrim(key, 3, true)); + assertThat(xtrimApproximate, lessThanOrEqualTo(3L)); + + Long sizeAfterApproximateTrim = exec(commandObjects.xlen(key)); + assertThat(sizeAfterApproximateTrim, greaterThanOrEqualTo(3L)); + } + + @Test + public void testXTrimCommandsBinary() { + String keyStr = "testStream"; + byte[] key = keyStr.getBytes(); + + // Populate the stream with more entries than we intend to keep + for (int i = 0; i < 10; i++) { + exec(commandObjects.xadd(keyStr, StreamEntryID.NEW_ENTRY, Collections.singletonMap("field" + i, "value" + i))); } Long sizeBeforeBinaryTrim = exec(commandObjects.xlen(key)); assertThat(sizeBeforeBinaryTrim, equalTo(10L)); - Long xtrimBinary = exec(commandObjects.xtrim(bKey, 5, false)); - assertThat(xtrimBinary, equalTo(5L)); + Long xtrimBinary = exec(commandObjects.xtrim(key, 6, false)); + assertThat(xtrimBinary, equalTo(4L)); Long sizeAfterBinaryTrim = exec(commandObjects.xlen(key)); - assertThat(sizeAfterBinaryTrim, equalTo(5L)); + assertThat(sizeAfterBinaryTrim, equalTo(6L)); + + Long xtrimApproximateBinary = exec(commandObjects.xtrim(key, 3, true)); + assertThat(xtrimApproximateBinary, lessThanOrEqualTo(3L)); + + Long sizeAfterApproximateBinaryTrim = exec(commandObjects.xlen(key)); + assertThat(sizeAfterApproximateBinaryTrim, greaterThanOrEqualTo(3L)); + } + + @Test + public void testXTrimWithParams() { + String key = "testStream"; + + // Populate the stream with more entries than we intend to keep + for (int i = 0; i < 10; i++) { + exec(commandObjects.xadd(key, StreamEntryID.NEW_ENTRY, Collections.singletonMap("field" + i, "value" + i))); + } + + Long sizeBeforeTrim = exec(commandObjects.xlen(key)); + assertThat(sizeBeforeTrim, equalTo(10L)); + + XTrimParams params = new XTrimParams().maxLen(6); + + Long xtrim = exec(commandObjects.xtrim(key, params)); + assertThat(xtrim, equalTo(4L)); + + Long sizeAfterTrim = exec(commandObjects.xlen(key)); + assertThat(sizeAfterTrim, equalTo(6L)); + } + + @Test + public void testXTrimWithParamsBinary() { + String keyStr = "testStream"; + byte[] key = keyStr.getBytes(); + + // Populate the stream with more entries than we intend to keep + for (int i = 0; i < 10; i++) { + exec(commandObjects.xadd(keyStr, StreamEntryID.NEW_ENTRY, Collections.singletonMap("field" + i, "value" + i))); + } + + Long sizeBeforeTrim = exec(commandObjects.xlen(key)); + assertThat(sizeBeforeTrim, equalTo(10L)); + + XTrimParams params = new XTrimParams().maxLen(6); + + Long xtrimBinary = exec(commandObjects.xtrim(key, params)); + assertThat(xtrimBinary, equalTo(4L)); + + Long sizeAfterTrim = exec(commandObjects.xlen(key)); + assertThat(sizeAfterTrim, equalTo(6L)); } @Test From 44d34a6ab8529301712d4707c9a27a1a310971af Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Tue, 9 Apr 2024 19:03:49 +0600 Subject: [PATCH 7/9] PubSub handle array of messages for RESP2 (#3811) * PubSub handle array of messages for RESP2 only * Modify test and add binary mode test * Edit --- .../redis/clients/jedis/JedisPubSubBase.java | 9 ++- .../jedis/PublishSubscribeCommandsTest.java | 73 +++++++++++++++++++ 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/src/main/java/redis/clients/jedis/JedisPubSubBase.java b/src/main/java/redis/clients/jedis/JedisPubSubBase.java index 552310e4de..bf9d0a32c5 100644 --- a/src/main/java/redis/clients/jedis/JedisPubSubBase.java +++ b/src/main/java/redis/clients/jedis/JedisPubSubBase.java @@ -133,10 +133,13 @@ private void process() { onUnsubscribe(enchannel, subscribedChannels); } else if (Arrays.equals(MESSAGE.getRaw(), resp)) { final byte[] bchannel = (byte[]) listReply.get(1); - final byte[] bmesg = (byte[]) listReply.get(2); + final Object mesg = listReply.get(2); final T enchannel = (bchannel == null) ? null : encode(bchannel); - final T enmesg = (bmesg == null) ? null : encode(bmesg); - onMessage(enchannel, enmesg); + if (mesg instanceof List) { + ((List) mesg).forEach(bmesg -> onMessage(enchannel, encode(bmesg))); + } else { + onMessage(enchannel, (mesg == null) ? null : encode((byte[]) mesg)); + } } else if (Arrays.equals(PMESSAGE.getRaw(), resp)) { final byte[] bpattern = (byte[]) listReply.get(1); final byte[] bchannel = (byte[]) listReply.get(2); diff --git a/src/test/java/redis/clients/jedis/commands/jedis/PublishSubscribeCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/PublishSubscribeCommandsTest.java index 75968fdc04..240c198716 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/PublishSubscribeCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/PublishSubscribeCommandsTest.java @@ -4,7 +4,9 @@ import static org.hamcrest.Matchers.hasItems; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static redis.clients.jedis.Protocol.Command.CLIENT; import java.io.IOException; import java.net.UnknownHostException; @@ -15,7 +17,9 @@ import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; +import org.hamcrest.Matchers; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -537,4 +541,73 @@ private String makeLargeString(int size) { return sb.toString(); } + + @Test(timeout = 5000) + public void subscribeCacheInvalidateChannel() { + org.junit.Assume.assumeThat(protocol, Matchers.not(RedisProtocol.RESP3)); + + final String cacheInvalidate = "__redis__:invalidate"; + final AtomicBoolean onMessage = new AtomicBoolean(false); + final JedisPubSub pubsub = new JedisPubSub() { + @Override public void onMessage(String channel, String message) { + onMessage.set(true); + assertEquals(cacheInvalidate, channel); + if (message != null) { + assertEquals("foo", message); + consumeJedis(j -> j.flushAll()); + } else { + unsubscribe(channel); + } + } + + @Override public void onSubscribe(String channel, int subscribedChannels) { + assertEquals(cacheInvalidate, channel); + consumeJedis(j -> j.set("foo", "bar")); + } + }; + + try (Jedis subscriber = createJedis()) { + long clientId = subscriber.clientId(); + subscriber.sendCommand(CLIENT, "TRACKING", "ON", "REDIRECT", Long.toString(clientId), "BCAST"); + subscriber.subscribe(pubsub, cacheInvalidate); + assertTrue("Subscriber didn't get any message.", onMessage.get()); + } + } + + @Test(timeout = 5000) + public void subscribeCacheInvalidateChannelBinary() { + org.junit.Assume.assumeThat(protocol, Matchers.not(RedisProtocol.RESP3)); + + final byte[] cacheInvalidate = "__redis__:invalidate".getBytes(); + final AtomicBoolean onMessage = new AtomicBoolean(false); + final BinaryJedisPubSub pubsub = new BinaryJedisPubSub() { + @Override public void onMessage(byte[] channel, byte[] message) { + onMessage.set(true); + assertArrayEquals(cacheInvalidate, channel); + if (message != null) { + assertArrayEquals("foo".getBytes(), message); + consumeJedis(j -> j.flushAll()); + } else { + unsubscribe(channel); + } + } + + @Override public void onSubscribe(byte[] channel, int subscribedChannels) { + assertArrayEquals(cacheInvalidate, channel); + consumeJedis(j -> j.set("foo".getBytes(), "bar".getBytes())); + } + }; + + try (Jedis subscriber = createJedis()) { + long clientId = subscriber.clientId(); + subscriber.sendCommand(CLIENT, "TRACKING", "ON", "REDIRECT", Long.toString(clientId), "BCAST"); + subscriber.subscribe(pubsub, cacheInvalidate); + assertTrue("Subscriber didn't get any message.", onMessage.get()); + } + } + + private void consumeJedis(Consumer consumer) { + Thread t = new Thread(() -> consumer.accept(jedis)); + t.start(); + } } From c068c07f5b036ddb761fce4c511723e8cee84af4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Apr 2024 19:56:21 +0600 Subject: [PATCH 8/9] Bump org.apache.maven.plugins:maven-gpg-plugin from 3.2.2 to 3.2.3 (#3818) Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.2.2 to 3.2.3. - [Release notes](https://github.com/apache/maven-gpg-plugin/releases) - [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.2...maven-gpg-plugin-3.2.3) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-gpg-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d1800644ab..36bfe85439 100644 --- a/pom.xml +++ b/pom.xml @@ -306,7 +306,7 @@ maven-gpg-plugin - 3.2.2 + 3.2.3 --pinentry-mode From e60759386060544c5f96f0ab76ce90f1b61a798f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Apr 2024 20:23:28 +0600 Subject: [PATCH 9/9] Bump org.apache.maven.plugins:maven-jar-plugin from 3.3.0 to 3.4.0 (#3819) Bumps [org.apache.maven.plugins:maven-jar-plugin](https://github.com/apache/maven-jar-plugin) from 3.3.0 to 3.4.0. - [Release notes](https://github.com/apache/maven-jar-plugin/releases) - [Commits](https://github.com/apache/maven-jar-plugin/compare/maven-jar-plugin-3.3.0...maven-jar-plugin-3.4.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-jar-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 36bfe85439..e399192d1d 100644 --- a/pom.xml +++ b/pom.xml @@ -272,7 +272,7 @@ maven-jar-plugin - 3.3.0 + 3.4.0 ${project.build.outputDirectory}/META-INF/MANIFEST.MF