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 01/51] 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 55495e6513e..6c5843c16ed 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 2a94ea2df2e..cf1758f44bf 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 5c7b6e161f7..452798d303c 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 6f2f42e7542..5c663633452 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 02/51] 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 402cd358424..52f2bda20e7 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 03/51] 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 52f2bda20e7..f4e1421d477 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 04/51] 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 f4e1421d477..d1800644abf 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 05/51] 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 bb125cc28dc..4ffc54cc541 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 06/51] 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 0182de207f6..1849d26687e 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 d1b1eaacaa4..4fd7c60fc4f 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 cf2be1b0a7f..21a573c8db4 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 29785440939..8d01e4283c4 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 07/51] 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 552310e4dec..bf9d0a32c5e 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 75968fdc041..240c198716c 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 08/51] 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 d1800644abf..36bfe85439e 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 09/51] 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 36bfe85439e..e399192d1dc 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 From 4a85d11ca0c3d08a748d76585d63624280ecc1d1 Mon Sep 17 00:00:00 2001 From: Thach Le Date: Thu, 18 Apr 2024 14:53:47 +0700 Subject: [PATCH 10/51] Custom connection pool to MultiClusterPooledConnectionProvider (#3801) * Add support for configuring connection pool to MultiClusterPooledConnectionProvider * Add ClusterConfig constructor to include ConnectionPoolConfig, add test * Update src/main/java/redis/clients/jedis/MultiClusterClientConfig.java Co-authored-by: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> * Update src/main/java/redis/clients/jedis/MultiClusterClientConfig.java Co-authored-by: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> * Update test * Update src/main/java/redis/clients/jedis/MultiClusterClientConfig.java Co-authored-by: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> * Update src/test/java/redis/clients/jedis/providers/MultiClusterPooledConnectionProviderTest.java Co-authored-by: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> * Format testConnectionPoolConfigApplied --------- Co-authored-by: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> --- .../jedis/MultiClusterClientConfig.java | 13 ++++++++++++ .../MultiClusterPooledConnectionProvider.java | 15 +++++++++++--- ...tiClusterPooledConnectionProviderTest.java | 20 ++++++++++++++++++- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/main/java/redis/clients/jedis/MultiClusterClientConfig.java b/src/main/java/redis/clients/jedis/MultiClusterClientConfig.java index 10dff9ef642..247ffb7ae86 100644 --- a/src/main/java/redis/clients/jedis/MultiClusterClientConfig.java +++ b/src/main/java/redis/clients/jedis/MultiClusterClientConfig.java @@ -7,6 +7,7 @@ import java.util.Arrays; import java.util.List; +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import redis.clients.jedis.annots.Experimental; import redis.clients.jedis.exceptions.JedisConnectionException; import redis.clients.jedis.exceptions.JedisValidationException; @@ -177,12 +178,20 @@ public static class ClusterConfig { private int priority; private HostAndPort hostAndPort; private JedisClientConfig clientConfig; + private GenericObjectPoolConfig connectionPoolConfig; public ClusterConfig(HostAndPort hostAndPort, JedisClientConfig clientConfig) { this.hostAndPort = hostAndPort; this.clientConfig = clientConfig; } + public ClusterConfig(HostAndPort hostAndPort, JedisClientConfig clientConfig, + GenericObjectPoolConfig connectionPoolConfig) { + this.hostAndPort = hostAndPort; + this.clientConfig = clientConfig; + this.connectionPoolConfig = connectionPoolConfig; + } + public int getPriority() { return priority; } @@ -198,6 +207,10 @@ public HostAndPort getHostAndPort() { public JedisClientConfig getJedisClientConfig() { return clientConfig; } + + public GenericObjectPoolConfig getConnectionPoolConfig() { + return connectionPoolConfig; + } } public static class Builder { diff --git a/src/main/java/redis/clients/jedis/providers/MultiClusterPooledConnectionProvider.java b/src/main/java/redis/clients/jedis/providers/MultiClusterPooledConnectionProvider.java index f26716086ee..47b03c77733 100644 --- a/src/main/java/redis/clients/jedis/providers/MultiClusterPooledConnectionProvider.java +++ b/src/main/java/redis/clients/jedis/providers/MultiClusterPooledConnectionProvider.java @@ -14,6 +14,8 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; + +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -112,6 +114,7 @@ public MultiClusterPooledConnectionProvider(MultiClusterClientConfig multiCluste ClusterConfig[] clusterConfigs = multiClusterClientConfig.getClusterConfigs(); for (ClusterConfig config : clusterConfigs) { + GenericObjectPoolConfig poolConfig = config.getConnectionPoolConfig(); String clusterId = "cluster:" + config.getPriority() + ":" + config.getHostAndPort(); @@ -130,9 +133,15 @@ public MultiClusterPooledConnectionProvider(MultiClusterClientConfig multiCluste circuitBreakerEventPublisher.onSlowCallRateExceeded(event -> log.error(String.valueOf(event))); circuitBreakerEventPublisher.onStateTransition(event -> log.warn(String.valueOf(event))); - multiClusterMap.put(config.getPriority(), - new Cluster(new ConnectionPool(config.getHostAndPort(), - config.getJedisClientConfig()), retry, circuitBreaker)); + if (poolConfig != null) { + multiClusterMap.put(config.getPriority(), + new Cluster(new ConnectionPool(config.getHostAndPort(), + config.getJedisClientConfig(), poolConfig), retry, circuitBreaker)); + } else { + multiClusterMap.put(config.getPriority(), + new Cluster(new ConnectionPool(config.getHostAndPort(), + config.getJedisClientConfig()), retry, circuitBreaker)); + } } /// --- /// diff --git a/src/test/java/redis/clients/jedis/providers/MultiClusterPooledConnectionProviderTest.java b/src/test/java/redis/clients/jedis/providers/MultiClusterPooledConnectionProviderTest.java index 7cf7d3323bc..d094d26b4f5 100644 --- a/src/test/java/redis/clients/jedis/providers/MultiClusterPooledConnectionProviderTest.java +++ b/src/test/java/redis/clients/jedis/providers/MultiClusterPooledConnectionProviderTest.java @@ -131,4 +131,22 @@ public void testSetActiveMultiClusterIndexOutOfRange() { provider.setActiveMultiClusterIndex(3); // Should throw an exception } -} \ No newline at end of file + @Test + public void testConnectionPoolConfigApplied() { + ConnectionPoolConfig poolConfig = new ConnectionPoolConfig(); + poolConfig.setMaxTotal(8); + poolConfig.setMaxIdle(4); + poolConfig.setMinIdle(1); + ClusterConfig[] clusterConfigs = new ClusterConfig[2]; + clusterConfigs[0] = new ClusterConfig(hostAndPort1, DefaultJedisClientConfig.builder().build(), poolConfig); + clusterConfigs[1] = new ClusterConfig(hostAndPort2, DefaultJedisClientConfig.builder().build(), poolConfig); + try (MultiClusterPooledConnectionProvider customProvider = new MultiClusterPooledConnectionProvider( + new MultiClusterClientConfig.Builder(clusterConfigs).build())) { + MultiClusterPooledConnectionProvider.Cluster activeCluster = customProvider.getCluster(); + ConnectionPool connectionPool = activeCluster.getConnectionPool(); + assertEquals(8, connectionPool.getMaxTotal()); + assertEquals(4, connectionPool.getMaxIdle()); + assertEquals(1, connectionPool.getMinIdle()); + } + } +} From e236dcb6dfb2ac208b3ed3f164da2af284277611 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Apr 2024 13:24:30 +0600 Subject: [PATCH 11/51] Bump org.apache.maven.plugins:maven-gpg-plugin from 3.2.3 to 3.2.4 (#3823) Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.2.3 to 3.2.4. - [Release notes](https://github.com/apache/maven-gpg-plugin/releases) - [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.3...maven-gpg-plugin-3.2.4) --- 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 e399192d1dc..ba599a75c40 100644 --- a/pom.xml +++ b/pom.xml @@ -306,7 +306,7 @@ maven-gpg-plugin - 3.2.3 + 3.2.4 --pinentry-mode From 8049b7b51b5f484c0f7bd5bb391f5d5f42e2ebca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Apr 2024 13:24:41 +0600 Subject: [PATCH 12/51] Bump org.apache.maven.plugins:maven-jar-plugin from 3.4.0 to 3.4.1 (#3822) Bumps [org.apache.maven.plugins:maven-jar-plugin](https://github.com/apache/maven-jar-plugin) from 3.4.0 to 3.4.1. - [Release notes](https://github.com/apache/maven-jar-plugin/releases) - [Commits](https://github.com/apache/maven-jar-plugin/compare/maven-jar-plugin-3.4.0...maven-jar-plugin-3.4.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-jar-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 ba599a75c40..28b418417a7 100644 --- a/pom.xml +++ b/pom.xml @@ -272,7 +272,7 @@ maven-jar-plugin - 3.4.0 + 3.4.1 ${project.build.outputDirectory}/META-INF/MANIFEST.MF From dfb1640f76549f23eccef946b3baa11bd86e2ea4 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Mon, 29 Apr 2024 23:49:34 +0600 Subject: [PATCH 13/51] Modify and fail-fast GeoSearchParam (#3827) --- .../clients/jedis/params/GeoSearchParam.java | 23 +++++++++----- .../jedis/commands/jedis/GeoCommandsTest.java | 20 ++++++------- .../commands/unified/GeoCommandsTestBase.java | 20 ++++++------- .../cluster/ClusterGeoCommandsTest.java | 4 +-- .../pipeline/GeoPipelineCommandsTest.java | 30 +++++++------------ 5 files changed, 48 insertions(+), 49 deletions(-) diff --git a/src/main/java/redis/clients/jedis/params/GeoSearchParam.java b/src/main/java/redis/clients/jedis/params/GeoSearchParam.java index 9c12269c6b9..6fc0ecbbffa 100644 --- a/src/main/java/redis/clients/jedis/params/GeoSearchParam.java +++ b/src/main/java/redis/clients/jedis/params/GeoSearchParam.java @@ -115,18 +115,25 @@ public GeoSearchParam any() { @Override public void addParams(CommandArguments args) { - if (this.fromMember) { - args.add(Keyword.FROMMEMBER).add(this.member); - } else if (this.fromLonLat) { + if (fromMember && fromLonLat) { + throw new IllegalArgumentException("Both FROMMEMBER and FROMLONLAT cannot be used."); + } else if (fromMember) { + args.add(Keyword.FROMMEMBER).add(member); + } else if (fromLonLat) { args.add(Keyword.FROMLONLAT).add(coord.getLongitude()).add(coord.getLatitude()); + } else { + throw new IllegalArgumentException("Either FROMMEMBER or FROMLONLAT must be used."); } - if (this.byRadius) { - args.add(Keyword.BYRADIUS).add(this.radius); - } else if (this.byBox) { - args.add(Keyword.BYBOX).add(this.width).add(this.height); + if (byRadius && byBox) { + throw new IllegalArgumentException("Both BYRADIUS and BYBOX cannot be used."); + } else if (byRadius) { + args.add(Keyword.BYRADIUS).add(radius).add(unit); + } else if (byBox) { + args.add(Keyword.BYBOX).add(width).add(height).add(unit); + } else { + throw new IllegalArgumentException("Either BYRADIUS or BYBOX must be used."); } - args.add(this.unit); if (withCoord) { args.add(Keyword.WITHCOORD); diff --git a/src/test/java/redis/clients/jedis/commands/jedis/GeoCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/GeoCommandsTest.java index 04fe32ee84b..be00a4d6658 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/GeoCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/GeoCommandsTest.java @@ -540,30 +540,30 @@ public void geosearchNegative() { // combine byradius and bybox try { jedis.geosearch("barcelona", new GeoSearchParam() - .byRadius(3000, GeoUnit.M).byBox(300, 300, GeoUnit.M)); + .byRadius(3000, GeoUnit.M) + .byBox(300, 300, GeoUnit.M)); fail(); - } catch (Exception ignored) { } + } catch (IllegalArgumentException ignored) { } // without byradius and without bybox try { - jedis.geosearch("barcelona", new GeoSearchParam() - .fromMember("foobar")); + jedis.geosearch("barcelona", new GeoSearchParam().fromMember("foobar")); fail(); - } catch (Exception ignored) { } + } catch (IllegalArgumentException ignored) { } // combine frommember and fromlonlat try { jedis.geosearch("barcelona", new GeoSearchParam() - .fromMember("foobar").fromLonLat(10,10)); + .fromMember("foobar") + .fromLonLat(10,10)); fail(); - } catch (Exception ignored) { } + } catch (IllegalArgumentException ignored) { } // without frommember and without fromlonlat try { - jedis.geosearch("barcelona", new GeoSearchParam() - .byRadius(10, GeoUnit.MI)); + jedis.geosearch("barcelona", new GeoSearchParam().byRadius(10, GeoUnit.MI)); fail(); - } catch (Exception ignored) { } + } catch (IllegalArgumentException ignored) { } } @Test diff --git a/src/test/java/redis/clients/jedis/commands/unified/GeoCommandsTestBase.java b/src/test/java/redis/clients/jedis/commands/unified/GeoCommandsTestBase.java index 63cd661ccb4..e05a5f99cff 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/GeoCommandsTestBase.java +++ b/src/test/java/redis/clients/jedis/commands/unified/GeoCommandsTestBase.java @@ -537,30 +537,30 @@ public void geosearchNegative() { // combine byradius and bybox try { jedis.geosearch("barcelona", new GeoSearchParam() - .byRadius(3000, GeoUnit.M).byBox(300, 300, GeoUnit.M)); + .byRadius(3000, GeoUnit.M) + .byBox(300, 300, GeoUnit.M)); fail(); - } catch (redis.clients.jedis.exceptions.JedisDataException ignored) { } + } catch (IllegalArgumentException ignored) { } // without byradius and without bybox try { - jedis.geosearch("barcelona", new GeoSearchParam() - .fromMember("foobar")); + jedis.geosearch("barcelona", new GeoSearchParam().fromMember("foobar")); fail(); - } catch (java.lang.IllegalArgumentException ignored) { } + } catch (IllegalArgumentException ignored) { } // combine frommember and fromlonlat try { jedis.geosearch("barcelona", new GeoSearchParam() - .fromMember("foobar").fromLonLat(10,10)); + .fromMember("foobar") + .fromLonLat(10,10)); fail(); - } catch (java.lang.IllegalArgumentException ignored) { } + } catch (IllegalArgumentException ignored) { } // without frommember and without fromlonlat try { - jedis.geosearch("barcelona", new GeoSearchParam() - .byRadius(10, GeoUnit.MI)); + jedis.geosearch("barcelona", new GeoSearchParam().byRadius(10, GeoUnit.MI)); fail(); - } catch (redis.clients.jedis.exceptions.JedisDataException ignored) { } + } catch (IllegalArgumentException ignored) { } } @Test diff --git a/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterGeoCommandsTest.java b/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterGeoCommandsTest.java index 75d5902a8ea..11630fa5893 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterGeoCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterGeoCommandsTest.java @@ -84,13 +84,13 @@ public void georadiusByMemberStore() { public void georadiusByMemberStoreBinary() { } - @Test @Ignore + @Override public void geosearchstore() { } - @Test @Ignore + @Override public void geosearchstoreWithdist() { } } diff --git a/src/test/java/redis/clients/jedis/commands/unified/pipeline/GeoPipelineCommandsTest.java b/src/test/java/redis/clients/jedis/commands/unified/pipeline/GeoPipelineCommandsTest.java index ccfd70bc8fc..d8b7443a8fa 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/pipeline/GeoPipelineCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/unified/pipeline/GeoPipelineCommandsTest.java @@ -798,32 +798,24 @@ public void geosearch() { contains(0L)); } - @Test - public void geosearchNegative() { - // combine byradius and bybox - pipe.geosearch("barcelona", - new GeoSearchParam().byRadius(3000, GeoUnit.M).byBox(300, 300, GeoUnit.M)); - - // without frommember and without fromlonlat - pipe.geosearch("barcelona", - new GeoSearchParam().byRadius(10, GeoUnit.MI)); + @Test(expected = IllegalArgumentException.class) + public void geosearchSearchParamCombineFromMemberAndFromLonLat() { + pipe.geosearch("barcelona", new GeoSearchParam().fromMember("foobar").fromLonLat(10, 10)); + } - assertThat(pipe.syncAndReturnAll(), contains( - instanceOf(JedisDataException.class), - instanceOf(JedisDataException.class) - )); + @Test(expected = IllegalArgumentException.class) + public void geosearchSearchParamWithoutFromMemberAndFromLonLat() { + pipe.geosearch("barcelona", new GeoSearchParam().byRadius(10, GeoUnit.MI)); } @Test(expected = IllegalArgumentException.class) - public void geosearchSearchParamWithoutRadiousAndWithoutBox() { - pipe.geosearch("barcelona", - new GeoSearchParam().fromMember("foobar")); + public void geosearchSearchParamCombineByRadiousAndByBox() { + pipe.geosearch("barcelona", new GeoSearchParam().byRadius(3000, GeoUnit.M).byBox(300, 300, GeoUnit.M)); } @Test(expected = IllegalArgumentException.class) - public void geosearchSearchParamCombineMemberAndLonLat() { - pipe.geosearch("barcelona", - new GeoSearchParam().fromMember("foobar").fromLonLat(10, 10)); + public void geosearchSearchParamWithoutByRadiousAndByBox() { + pipe.geosearch("barcelona", new GeoSearchParam().fromMember("foobar")); } @Test From 0691b57325c14dac210a9bc52e74e77ff0d9722d Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Sun, 5 May 2024 17:55:55 +0600 Subject: [PATCH 14/51] Declare the dialectOptional method as Internal --- src/main/java/redis/clients/jedis/search/FTSearchParams.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/redis/clients/jedis/search/FTSearchParams.java b/src/main/java/redis/clients/jedis/search/FTSearchParams.java index 1bb55970856..d2ca5d6d946 100644 --- a/src/main/java/redis/clients/jedis/search/FTSearchParams.java +++ b/src/main/java/redis/clients/jedis/search/FTSearchParams.java @@ -6,6 +6,7 @@ import redis.clients.jedis.CommandArguments; import redis.clients.jedis.Protocol; +import redis.clients.jedis.annots.Internal; import redis.clients.jedis.args.GeoUnit; import redis.clients.jedis.args.SortingOrder; import redis.clients.jedis.params.IParams; @@ -427,6 +428,7 @@ public FTSearchParams dialect(int dialect) { * @param dialect dialect * @return this */ + @Internal public FTSearchParams dialectOptional(int dialect) { if (dialect != 0 && this.dialect == null) { this.dialect = dialect; From 9d945ff886fabf32bc4615a2bffccf1c9ac0afe6 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Mon, 6 May 2024 11:47:58 +0600 Subject: [PATCH 15/51] Add methods in CommandArguments and RawableFactory (#3834) * Add direct methods in CommandArguments * Add methods for boolean and long in RawableFactory --- .../redis/clients/jedis/CommandArguments.java | 42 ++++++++++++++++--- .../clients/jedis/args/RawableFactory.java | 18 ++++++++ 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/src/main/java/redis/clients/jedis/CommandArguments.java b/src/main/java/redis/clients/jedis/CommandArguments.java index b9190245cee..c630ae76dec 100644 --- a/src/main/java/redis/clients/jedis/CommandArguments.java +++ b/src/main/java/redis/clients/jedis/CommandArguments.java @@ -1,6 +1,7 @@ package redis.clients.jedis; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Iterator; @@ -29,6 +30,35 @@ public ProtocolCommand getCommand() { return (ProtocolCommand) args.get(0); } + public CommandArguments add(Rawable arg) { + args.add(arg); + return this; + } + + public CommandArguments add(byte[] arg) { + return add(RawableFactory.from(arg)); + } + + public CommandArguments add(boolean arg) { + return add(RawableFactory.from(arg)); + } + + public CommandArguments add(int arg) { + return add(RawableFactory.from(arg)); + } + + public CommandArguments add(long arg) { + return add(RawableFactory.from(arg)); + } + + public CommandArguments add(double arg) { + return add(RawableFactory.from(arg)); + } + + public CommandArguments add(String arg) { + return add(RawableFactory.from(arg)); + } + public CommandArguments add(Object arg) { if (arg == null) { throw new IllegalArgumentException("null is not a valid argument."); @@ -36,12 +66,14 @@ public CommandArguments add(Object arg) { args.add((Rawable) arg); } else if (arg instanceof byte[]) { args.add(RawableFactory.from((byte[]) arg)); + } else if (arg instanceof Boolean) { + args.add(RawableFactory.from((Boolean) arg)); } else if (arg instanceof Integer) { args.add(RawableFactory.from((Integer) arg)); + } else if (arg instanceof Long) { + args.add(RawableFactory.from((Long) arg)); } else if (arg instanceof Double) { args.add(RawableFactory.from((Double) arg)); - } else if (arg instanceof Boolean) { - args.add(RawableFactory.from((Boolean) arg ? 1 : 0)); } else if (arg instanceof float[]) { args.add(RawableFactory.from(RediSearchUtil.toByteArray((float[]) arg))); } else if (arg instanceof String) { @@ -87,14 +119,12 @@ public CommandArguments key(Object key) { } public final CommandArguments keys(Object... keys) { - for (Object key : keys) { - key(key); - } + Arrays.stream(keys).forEach(this::key); return this; } public final CommandArguments keys(Collection keys) { - keys.forEach(key -> key(key)); + keys.forEach(this::key); return this; } diff --git a/src/main/java/redis/clients/jedis/args/RawableFactory.java b/src/main/java/redis/clients/jedis/args/RawableFactory.java index 8bce7f0e78d..813ddd021be 100644 --- a/src/main/java/redis/clients/jedis/args/RawableFactory.java +++ b/src/main/java/redis/clients/jedis/args/RawableFactory.java @@ -10,6 +10,15 @@ */ public final class RawableFactory { + /** + * Get a {@link Rawable} from a {@code boolean}. + * @param b boolean value + * @return raw + */ + public static Rawable from(boolean b) { + return from(toByteArray(b)); + } + /** * Get a {@link Rawable} from an {@code int}. * @param i integer value @@ -19,6 +28,15 @@ public static Rawable from(int i) { return from(toByteArray(i)); } + /** + * Get a {@link Rawable} from a {@code long}. + * @param l long value + * @return raw + */ + public static Rawable from(long l) { + return from(toByteArray(l)); + } + /** * Get a {@link Rawable} from a {@code double}. * @param d numeric value From 344ded3b773d61146bc269e59f795c2eb6680b5a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 13:13:15 +0600 Subject: [PATCH 16/51] Bump jackson.version from 2.17.0 to 2.17.1 (#3833) Bumps `jackson.version` from 2.17.0 to 2.17.1. Updates `com.fasterxml.jackson.core:jackson-databind` from 2.17.0 to 2.17.1 - [Commits](https://github.com/FasterXML/jackson/commits) Updates `com.fasterxml.jackson.datatype:jackson-datatype-jsr310` from 2.17.0 to 2.17.1 --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson.datatype:jackson-datatype-jsr310 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 28b418417a7..1ae12c300cc 100644 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,7 @@ redis.clients.jedis 1.7.36 1.7.1 - 2.17.0 + 2.17.1 3.2.5 From 7aad706e61f8686e5801179689dc6f790ccbb196 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Mon, 6 May 2024 15:43:37 +0600 Subject: [PATCH 17/51] Add missing ClusterHashesCommandsTest --- .../cluster/ClusterHashesCommandsTest.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterHashesCommandsTest.java diff --git a/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterHashesCommandsTest.java b/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterHashesCommandsTest.java new file mode 100644 index 00000000000..a5590a2730e --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterHashesCommandsTest.java @@ -0,0 +1,27 @@ +package redis.clients.jedis.commands.unified.cluster; + +import org.junit.After; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.commands.unified.HashesCommandsTestBase; + +@RunWith(Parameterized.class) +public class ClusterHashesCommandsTest extends HashesCommandsTestBase { + + public ClusterHashesCommandsTest(RedisProtocol protocol) { + super(protocol); + } + + @Before + public void setUp() { + jedis = ClusterCommandsTestHelper.getCleanCluster(protocol); + } + + @After + public void tearDown() { + jedis.close(); + ClusterCommandsTestHelper.clearClusterData(); + } +} From 026d5e4d8edc2dbd5f2e1f18c52f1965cf32abc2 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Sun, 19 May 2024 15:11:07 +0600 Subject: [PATCH 18/51] Address Gears test fail - Cleanup Function libraries (#3840) * Check Gears test fail * Check modules package * Revert all changes in Makefile * Cleanup Function libraries --- ...ommandObjectsTriggersAndFunctionsCommandsTest.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTriggersAndFunctionsCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTriggersAndFunctionsCommandsTest.java index 31528e80928..6403f57404c 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTriggersAndFunctionsCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTriggersAndFunctionsCommandsTest.java @@ -7,9 +7,11 @@ import java.util.ArrayList; import java.util.List; - +import org.junit.After; import org.junit.Test; + import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.exceptions.JedisDataException; import redis.clients.jedis.gears.TFunctionListParams; import redis.clients.jedis.gears.TFunctionLoadParams; import redis.clients.jedis.gears.resps.GearsLibraryInfo; @@ -23,6 +25,13 @@ public CommandObjectsTriggersAndFunctionsCommandsTest(RedisProtocol protocol) { super(protocol); } + @After + public void tearDown() throws Exception { + try { + exec(commandObjects.tFunctionDelete("lib")); + } catch (JedisDataException de) { } + } + @Test public void testTFunctionLoadAndCall() { String libraryCode = "#!js api_version=1.0 name=lib\n" + From 327215a68be7f60183712db001454aff6d2b3c90 Mon Sep 17 00:00:00 2001 From: Igor Malinovskiy Date: Tue, 21 May 2024 17:23:01 +0200 Subject: [PATCH 19/51] Introduce EndpointConfig and load endpoint settings from the endpoints.json file (#3836) * Let's get the hardcode-removal party started :) * Fix URLs in endpoints.json * Use 2 endpoints for different users * Fix some broken tests * Remove more hardcoded connection settings * Fix JedisCommandsTestBase * Remove unnecessary timeout * Add missing tls setting to fix SSLACLJedisClusterTest * Allow supplying custom endpoints config via env variable * Introduce EndpointURIBuilder for creating customized URIs * Remove getJedis and getConnection methods * Improve naming for endpoint variables * Fix name of endpoint variable in JedisPooledTest * Add support for endpoints without username * Improve endpoints naming in AutomaticFailoverTest * Remove more hardcoded settings from Migrate tests * Fix comments in SSLACL tests * Fix endpoint naming in AA failover test --- .../redis/clients/jedis/ACLJedisPoolTest.java | 90 ++++++------ .../jedis/ACLJedisSentinelPoolTest.java | 4 +- .../redis/clients/jedis/ACLJedisTest.java | 39 +++--- .../redis/clients/jedis/EndpointConfig.java | 129 ++++++++++++++++++ .../redis/clients/jedis/HostAndPorts.java | 48 ++----- .../redis/clients/jedis/JedisPoolTest.java | 103 +++++++------- .../redis/clients/jedis/JedisPooledTest.java | 55 ++++---- .../clients/jedis/JedisSentinelPoolTest.java | 3 - .../clients/jedis/JedisSentinelTest.java | 4 +- .../java/redis/clients/jedis/JedisTest.java | 90 ++++++------ .../jedis/ManagedConnectionProviderTest.java | 4 +- .../clients/jedis/MigratePipeliningTest.java | 34 +++-- .../redis/clients/jedis/PipeliningTest.java | 20 +-- .../jedis/ReliableTransactionTest.java | 12 +- .../clients/jedis/SSLACLJedisClusterTest.java | 11 +- .../redis/clients/jedis/SSLACLJedisTest.java | 30 ++-- .../redis/clients/jedis/SSLJedisTest.java | 23 ++-- .../SentineledConnectionProviderTest.java | 3 - .../clients/jedis/ShardedConnectionTest.java | 14 +- .../clients/jedis/ShardedPipelineTest.java | 12 +- .../redis/clients/jedis/ShardingTest.java | 54 ++++---- .../clients/jedis/TransactionV2Test.java | 13 +- .../jedis/benchmark/GetSetBenchmark.java | 8 +- .../benchmark/PipelinedGetSetBenchmark.java | 11 +- .../jedis/benchmark/PoolBenchmark.java | 15 +- .../jedis/benchmark/PooledBenchmark.java | 13 +- .../jedis/benchmark/ShardingBenchmark.java | 13 +- .../CommandObjectsGenericCommandsTest.java | 4 +- .../CommandObjectsModulesTestBase.java | 6 +- .../CommandObjectsStandaloneTestBase.java | 2 +- .../CommandObjectsTestBase.java | 25 ++-- .../jedis/AccessControlListCommandsTest.java | 12 +- .../jedis/AllKindOfValuesCommandsTest.java | 19 +-- .../commands/jedis/ClientCommandsTest.java | 21 ++- .../commands/jedis/ControlCommandsTest.java | 29 ++-- .../commands/jedis/FailoverCommandsTest.java | 17 +-- .../commands/jedis/JedisCommandsTestBase.java | 18 +-- .../jedis/commands/jedis/MigrateTest.java | 47 ++++--- .../commands/jedis/ObjectCommandsTest.java | 10 +- .../commands/jedis/SentinelCommandsTest.java | 4 +- .../jedis/TransactionCommandsTest.java | 9 +- .../pooled/PooledCommandsTestHelper.java | 17 +-- .../jedis/misc/AutomaticFailoverTest.java | 29 ++-- .../jedis/misc/ClusterInitErrorTest.java | 12 +- ...tiClusterPooledConnectionProviderTest.java | 12 +- .../clients/jedis/util/RedisVersionUtil.java | 11 +- src/test/resources/endpoints.json | 107 +++++++++++++++ 47 files changed, 748 insertions(+), 518 deletions(-) create mode 100644 src/test/java/redis/clients/jedis/EndpointConfig.java create mode 100644 src/test/resources/endpoints.json diff --git a/src/test/java/redis/clients/jedis/ACLJedisPoolTest.java b/src/test/java/redis/clients/jedis/ACLJedisPoolTest.java index 36474e12d50..5d7579b3670 100644 --- a/src/test/java/redis/clients/jedis/ACLJedisPoolTest.java +++ b/src/test/java/redis/clients/jedis/ACLJedisPoolTest.java @@ -21,19 +21,21 @@ * This test is only executed when the server/cluster is Redis 6. or more. */ public class ACLJedisPoolTest { - private static final HostAndPort hnp = HostAndPorts.getRedisServers().get(0); + private static final EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone0-acl"); + + private static final EndpointConfig endpointWithDefaultUser = HostAndPorts.getRedisEndpoint("standalone0"); @BeforeClass public static void prepare() throws Exception { // Use to check if the ACL test should be ran. ACL are available only in 6.0 and later org.junit.Assume.assumeTrue("Not running ACL test on this version of Redis", - RedisVersionUtil.checkRedisMajorVersionNumber(6)); + RedisVersionUtil.checkRedisMajorVersionNumber(6, endpoint)); } @Test public void checkConnections() { - JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort(), "acljedis", - "fizzbuzz"); + JedisPool pool = new JedisPool(new JedisPoolConfig(), endpoint.getHost(), endpoint.getPort(), + endpoint.getUsername(), endpoint.getPassword()); try (Jedis jedis = pool.getResource()) { jedis.set("foo", "bar"); assertEquals("bar", jedis.get("foo")); @@ -44,7 +46,8 @@ public void checkConnections() { @Test public void checkCloseableConnections() throws Exception { - JedisPool pool = new JedisPool(hnp.getHost(), hnp.getPort(), "acljedis", "fizzbuzz"); + JedisPool pool = new JedisPool(endpoint.getHost(), endpoint.getPort(), endpoint.getUsername(), + endpoint.getPassword()); try (Jedis jedis = pool.getResource()) { jedis.set("foo", "bar"); assertEquals("bar", jedis.get("foo")); @@ -58,9 +61,9 @@ public void checkResourceIsClosableAndReusable() { GenericObjectPoolConfig config = new GenericObjectPoolConfig<>(); config.setMaxTotal(1); config.setBlockWhenExhausted(false); - try (JedisPool pool = new JedisPool(config, hnp.getHost(), hnp.getPort(), - Protocol.DEFAULT_TIMEOUT, Protocol.DEFAULT_TIMEOUT, 0 /* infinite */, "acljedis", - "fizzbuzz", Protocol.DEFAULT_DATABASE, "closable-reusable-pool", false, null, null, null)) { + try (JedisPool pool = new JedisPool(config, endpoint.getHost(), endpoint.getPort(), + Protocol.DEFAULT_TIMEOUT, Protocol.DEFAULT_TIMEOUT, 0 /* infinite */, endpoint.getUsername(), + endpoint.getPassword(), Protocol.DEFAULT_DATABASE, "closable-reusable-pool", false, null, null, null)) { Jedis jedis = pool.getResource(); jedis.set("hello", "jedis"); @@ -78,8 +81,8 @@ public void checkResourceWithConfigIsClosableAndReusable() { GenericObjectPoolConfig config = new GenericObjectPoolConfig<>(); config.setMaxTotal(1); config.setBlockWhenExhausted(false); - try (JedisPool pool = new JedisPool(config, hnp, DefaultJedisClientConfig.builder() - .user("acljedis").password("fizzbuzz").clientName("closable-reusable-pool") + try (JedisPool pool = new JedisPool(config, endpoint.getHostAndPort(), + endpoint.getClientConfigBuilder().clientName("closable-reusable-pool") .build())) { Jedis jedis = pool.getResource(); @@ -96,9 +99,9 @@ public void checkResourceWithConfigIsClosableAndReusable() { @Test public void checkPoolRepairedWhenJedisIsBroken() { - JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort(), - Protocol.DEFAULT_TIMEOUT, Protocol.DEFAULT_TIMEOUT, 0 /* infinite */, "acljedis", - "fizzbuzz", Protocol.DEFAULT_DATABASE, "repairable-pool"); + JedisPool pool = new JedisPool(new JedisPoolConfig(), endpoint.getHost(), endpoint.getPort(), + Protocol.DEFAULT_TIMEOUT, Protocol.DEFAULT_TIMEOUT, 0 /* infinite */, endpoint.getUsername(), + endpoint.getPassword(), Protocol.DEFAULT_DATABASE, "repairable-pool"); try (Jedis jedis = pool.getResource()) { jedis.set("foo", "0"); jedis.disconnect(); @@ -116,12 +119,12 @@ public void checkPoolOverflow() { GenericObjectPoolConfig config = new GenericObjectPoolConfig<>(); config.setMaxTotal(1); config.setBlockWhenExhausted(false); - try (JedisPool pool = new JedisPool(config, hnp.getHost(), hnp.getPort()); + try (JedisPool pool = new JedisPool(config, endpoint.getHost(), endpoint.getPort()); Jedis jedis = pool.getResource()) { - jedis.auth("acljedis", "fizzbuzz"); + jedis.auth(endpoint.getUsername(), endpoint.getPassword()); try (Jedis jedis2 = pool.getResource()) { - jedis2.auth("acljedis", "fizzbuzz"); + jedis2.auth(endpoint.getUsername(), endpoint.getPassword()); } } } @@ -130,8 +133,8 @@ public void checkPoolOverflow() { public void securePool() { JedisPoolConfig config = new JedisPoolConfig(); config.setTestOnBorrow(true); - JedisPool pool = new JedisPool(config, hnp.getHost(), hnp.getPort(), 2000, "acljedis", - "fizzbuzz"); + JedisPool pool = new JedisPool(config, endpoint.getHost(), endpoint.getPort(), 2000, endpoint.getUsername(), + endpoint.getPassword()); try (Jedis jedis = pool.getResource()) { jedis.set("foo", "bar"); } @@ -143,8 +146,8 @@ public void securePool() { public void securePoolNonSSL() { JedisPoolConfig config = new JedisPoolConfig(); config.setTestOnBorrow(true); - JedisPool pool = new JedisPool(config, hnp.getHost(), hnp.getPort(), 2000, "acljedis", - "fizzbuzz", false); + JedisPool pool = new JedisPool(config, endpoint.getHost(), endpoint.getPort(), 2000, endpoint.getUsername(), + endpoint.getPassword(), false); try (Jedis jedis = pool.getResource()) { jedis.set("foo", "bar"); } @@ -154,27 +157,28 @@ public void securePoolNonSSL() { @Test public void nonDefaultDatabase() { - try (JedisPool pool0 = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort(), 2000, - "acljedis", "fizzbuzz"); Jedis jedis0 = pool0.getResource()) { + try (JedisPool pool0 = new JedisPool(new JedisPoolConfig(), endpoint.getHost(), endpoint.getPort(), 2000, + endpoint.getUsername(), endpoint.getPassword()); Jedis jedis0 = pool0.getResource()) { jedis0.set("foo", "bar"); assertEquals("bar", jedis0.get("foo")); } - try (JedisPool pool1 = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort(), 2000, - "acljedis", "fizzbuzz", 1); Jedis jedis1 = pool1.getResource()) { + try (JedisPool pool1 = new JedisPool(new JedisPoolConfig(), endpoint.getHost(), endpoint.getPort(), 2000, + endpoint.getUsername(), endpoint.getPassword(), 1); Jedis jedis1 = pool1.getResource()) { assertNull(jedis1.get("foo")); } } @Test public void startWithUrlString() { - try (Jedis j = new Jedis("localhost", 6379)) { - j.auth("acljedis", "fizzbuzz"); + try (Jedis j = new Jedis(endpoint.getHost(), endpoint.getPort())) { + j.auth(endpoint.getUsername(), endpoint.getPassword()); j.select(2); j.set("foo", "bar"); } - try (JedisPool pool = new JedisPool("redis://acljedis:fizzbuzz@localhost:6379/2"); + try (JedisPool pool = new JedisPool( + endpoint.getURIBuilder().defaultCredentials().path("/2").build()); Jedis jedis = pool.getResource()) { assertEquals("bar", jedis.get("foo")); } @@ -182,18 +186,20 @@ public void startWithUrlString() { @Test public void startWithUrl() throws URISyntaxException { - try (Jedis j = new Jedis("localhost", 6379)) { - j.auth("acljedis", "fizzbuzz"); + try (Jedis j = new Jedis(endpoint.getHost(), endpoint.getPort())) { + j.auth(endpoint.getUsername(), endpoint.getPassword()); j.select(2); j.set("foo", "bar"); } - try (JedisPool pool = new JedisPool(new URI("redis://acljedis:fizzbuzz@localhost:6379/2")); + try (JedisPool pool = new JedisPool( + endpoint.getURIBuilder().defaultCredentials().path("/2").build()); Jedis jedis = pool.getResource()) { assertEquals("bar", jedis.get("foo")); } - try (JedisPool pool = new JedisPool(new URI("redis://default:foobared@localhost:6379/2")); + try (JedisPool pool = new JedisPool( + endpointWithDefaultUser.getURIBuilder().defaultCredentials().path("/2").build()); Jedis jedis = pool.getResource()) { assertEquals("bar", jedis.get("foo")); } @@ -206,14 +212,14 @@ public void shouldThrowInvalidURIExceptionForInvalidURI() throws URISyntaxExcept @Test public void allowUrlWithNoDBAndNoPassword() throws URISyntaxException { - new JedisPool("redis://localhost:6379").close(); - new JedisPool(new URI("redis://localhost:6379")).close(); + new JedisPool(endpoint.getURI().toString()).close(); + new JedisPool(endpoint.getURI()).close(); } @Test public void selectDatabaseOnActivation() { - try (JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort(), 2000, - "acljedis", "fizzbuzz")) { + try (JedisPool pool = new JedisPool(new JedisPoolConfig(), endpoint.getHost(), endpoint.getPort(), 2000, + endpoint.getUsername(), endpoint.getPassword())) { Jedis jedis0 = pool.getResource(); assertEquals(0, jedis0.getDB()); @@ -233,8 +239,8 @@ public void selectDatabaseOnActivation() { @Test public void customClientName() { - try (JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort(), 2000, - "acljedis", "fizzbuzz", 0, "my_shiny_client_name"); Jedis jedis = pool.getResource()) { + try (JedisPool pool = new JedisPool(new JedisPoolConfig(), endpoint.getHost(), endpoint.getPort(), 2000, + endpoint.getUsername(), endpoint.getPassword(), 0, "my_shiny_client_name"); Jedis jedis = pool.getResource()) { assertEquals("my_shiny_client_name", jedis.clientGetname()); } @@ -242,8 +248,8 @@ public void customClientName() { @Test public void customClientNameNoSSL() { - try (JedisPool pool0 = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort(), 2000, - "acljedis", "fizzbuzz", 0, "my_shiny_client_name_no_ssl", false); + try (JedisPool pool0 = new JedisPool(new JedisPoolConfig(), endpoint.getHost(), endpoint.getPort(), 2000, + endpoint.getUsername(), endpoint.getPassword(), 0, "my_shiny_client_name_no_ssl", false); Jedis jedis = pool0.getResource()) { assertEquals("my_shiny_client_name_no_ssl", jedis.clientGetname()); @@ -254,8 +260,10 @@ public void customClientNameNoSSL() { public void testCloseConnectionOnMakeObject() { JedisPoolConfig config = new JedisPoolConfig(); config.setTestOnBorrow(true); - try (JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort(), 2000, - "acljedis", "foobared"); Jedis jedis = new Jedis("redis://:foobared@localhost:6379/")) { + try (JedisPool pool = new JedisPool(new JedisPoolConfig(), endpoint.getHost(), + endpoint.getPort(), 2000, endpoint.getUsername(), "wrongpassword"); + Jedis jedis = new Jedis(endpointWithDefaultUser.getURIBuilder() + .credentials("", endpointWithDefaultUser.getPassword()).build())) { int currentClientCount = getClientCount(jedis.clientList()); try { pool.getResource(); diff --git a/src/test/java/redis/clients/jedis/ACLJedisSentinelPoolTest.java b/src/test/java/redis/clients/jedis/ACLJedisSentinelPoolTest.java index 75325c43be9..b62809f0bbf 100644 --- a/src/test/java/redis/clients/jedis/ACLJedisSentinelPoolTest.java +++ b/src/test/java/redis/clients/jedis/ACLJedisSentinelPoolTest.java @@ -24,15 +24,15 @@ public class ACLJedisSentinelPoolTest { private static final String MASTER_NAME = "aclmaster"; - //protected static HostAndPort master = HostAndPortUtil.getRedisServers().get(8); protected static HostAndPort sentinel1 = HostAndPorts.getSentinelServers().get(4); protected Set sentinels = new HashSet<>(); @BeforeClass public static void prepare() throws Exception { + EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone2-primary"); org.junit.Assume.assumeTrue("Not running ACL test on this version of Redis", - RedisVersionUtil.checkRedisMajorVersionNumber(6)); + RedisVersionUtil.checkRedisMajorVersionNumber(6, endpoint)); } @Before diff --git a/src/test/java/redis/clients/jedis/ACLJedisTest.java b/src/test/java/redis/clients/jedis/ACLJedisTest.java index a6a9deff771..d1ef40b95b6 100644 --- a/src/test/java/redis/clients/jedis/ACLJedisTest.java +++ b/src/test/java/redis/clients/jedis/ACLJedisTest.java @@ -2,7 +2,6 @@ import static org.junit.Assert.assertEquals; -import java.net.URI; import java.net.URISyntaxException; import org.junit.BeforeClass; import org.junit.Test; @@ -20,6 +19,8 @@ @RunWith(Parameterized.class) public class ACLJedisTest extends JedisCommandsTestBase { + protected static final EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone0-acl"); + /** * Use to check if the ACL test should be ran. ACL are available only in 6.0 and later * @throws Exception @@ -27,7 +28,7 @@ public class ACLJedisTest extends JedisCommandsTestBase { @BeforeClass public static void prepare() throws Exception { org.junit.Assume.assumeTrue("Not running ACL test on this version of Redis", - RedisVersionUtil.checkRedisMajorVersionNumber(6)); + RedisVersionUtil.checkRedisMajorVersionNumber(6, endpoint)); } public ACLJedisTest(RedisProtocol redisProtocol) { @@ -37,39 +38,38 @@ public ACLJedisTest(RedisProtocol redisProtocol) { @Test public void useWithoutConnecting() { try (Jedis j = new Jedis()) { - assertEquals("OK", j.auth("acljedis", "fizzbuzz")); + assertEquals("OK", j.auth(endpoint.getUsername(), endpoint.getPassword())); j.dbSize(); } } @Test public void connectWithConfig() { - try (Jedis jedis = new Jedis(hnp, DefaultJedisClientConfig.builder().build())) { - jedis.auth("acljedis", "fizzbuzz"); + try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), DefaultJedisClientConfig.builder().build())) { + jedis.auth(endpoint.getUsername(), endpoint.getPassword()); assertEquals("PONG", jedis.ping()); } - try (Jedis jedis = new Jedis(hnp, DefaultJedisClientConfig.builder().user("acljedis") - .password("fizzbuzz").build())) { + try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), endpoint.getClientConfigBuilder().build())) { assertEquals("PONG", jedis.ping()); } } @Test public void connectWithConfigInterface() { - try (Jedis jedis = new Jedis(hnp, new JedisClientConfig() { + try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), new JedisClientConfig() { })) { - jedis.auth("acljedis", "fizzbuzz"); + jedis.auth(endpoint.getUsername(), endpoint.getPassword()); assertEquals("PONG", jedis.ping()); } - try (Jedis jedis = new Jedis(hnp, new JedisClientConfig() { + try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), new JedisClientConfig() { @Override public String getUser() { - return "acljedis"; + return endpoint.getUsername(); } @Override public String getPassword() { - return "fizzbuzz"; + return endpoint.getPassword(); } })) { assertEquals("PONG", jedis.ping()); @@ -78,12 +78,13 @@ public String getPassword() { @Test public void startWithUrl() { - try (Jedis j = new Jedis("localhost", 6379)) { - assertEquals("OK", j.auth("acljedis", "fizzbuzz")); + try (Jedis j = new Jedis(endpoint.getHostAndPort())) { + assertEquals("OK", j.auth(endpoint.getUsername(), endpoint.getPassword())); assertEquals("OK", j.select(2)); j.set("foo", "bar"); } - try (Jedis j2 = new Jedis("redis://acljedis:fizzbuzz@localhost:6379/2")) { + try (Jedis j2 = new Jedis( + endpoint.getURIBuilder().defaultCredentials().path("/2").build().toString())) { assertEquals("PONG", j2.ping()); assertEquals("bar", j2.get("foo")); } @@ -91,16 +92,16 @@ public void startWithUrl() { @Test public void startWithUri() throws URISyntaxException { - try (Jedis j = new Jedis("localhost", 6379)) { - assertEquals("OK", j.auth("acljedis", "fizzbuzz")); + try (Jedis j = new Jedis(endpoint.getHostAndPort())) { + assertEquals("OK", j.auth(endpoint.getUsername(), endpoint.getPassword())); assertEquals("OK", j.select(2)); j.set("foo", "bar"); } - try (Jedis j1 = new Jedis(new URI("redis://acljedis:fizzbuzz@localhost:6379/2"))) { + try (Jedis j1 = new Jedis(endpoint.getURIBuilder().defaultCredentials().path("/2").build())) { assertEquals("PONG", j1.ping()); assertEquals("bar", j1.get("foo")); } - try (Jedis j2 = new Jedis(new URI("redis://acljedis:fizzbuzz@localhost:6379/2"))) { + try (Jedis j2 = new Jedis(endpoint.getURIBuilder().defaultCredentials().path("/2").build())) { assertEquals("PONG", j2.ping()); assertEquals("bar", j2.get("foo")); } diff --git a/src/test/java/redis/clients/jedis/EndpointConfig.java b/src/test/java/redis/clients/jedis/EndpointConfig.java new file mode 100644 index 00000000000..5cb322224dd --- /dev/null +++ b/src/test/java/redis/clients/jedis/EndpointConfig.java @@ -0,0 +1,129 @@ +package redis.clients.jedis; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import redis.clients.jedis.util.JedisURIHelper; + +import java.io.FileReader; +import java.net.URI; +import java.util.*; + +public class EndpointConfig { + + private final boolean tls; + private final String username; + private final String password; + private final int bdbId; + private final List endpoints; + + public EndpointConfig(HostAndPort hnp, String username, String password, boolean tls) { + this.tls = tls; + this.username = username; + this.password = password; + this.bdbId = 0; + this.endpoints = Collections.singletonList( + URI.create(getURISchema(tls) + hnp.getHost() + ":" + hnp.getPort())); + } + + public HostAndPort getHostAndPort() { + return JedisURIHelper.getHostAndPort(endpoints.get(0)); + } + + public String getPassword() { + return password; + } + + public String getUsername() { + return username == null? "default" : username; + } + + public String getHost() { + return getHostAndPort().getHost(); + } + + public int getPort() { + return getHostAndPort().getPort(); + } + + public int getBdbId() { return bdbId; } + + public URI getURI() { + return endpoints.get(0); + } + + public class EndpointURIBuilder { + private boolean tls; + + private String username; + + private String password; + + private String path; + + public EndpointURIBuilder() { + this.username = ""; + this.password = ""; + this.path = ""; + this.tls = EndpointConfig.this.tls; + } + + public EndpointURIBuilder defaultCredentials() { + this.username = EndpointConfig.this.username == null ? "" : getUsername(); + this.password = EndpointConfig.this.getPassword(); + return this; + } + + public EndpointURIBuilder tls(boolean v) { + this.tls = v; + return this; + } + + public EndpointURIBuilder path(String v) { + this.path = v; + return this; + } + + public EndpointURIBuilder credentials(String u, String p) { + this.username = u; + this.password = p; + return this; + } + + public URI build() { + String userInfo = !(this.username.isEmpty() && this.password.isEmpty()) ? + this.username + ':' + this.password + '@' : + ""; + return URI.create( + getURISchema(this.tls) + userInfo + getHost() + ":" + getPort() + this.path); + } + } + + public EndpointURIBuilder getURIBuilder() { + return new EndpointURIBuilder(); + } + + public DefaultJedisClientConfig.Builder getClientConfigBuilder() { + DefaultJedisClientConfig.Builder builder = DefaultJedisClientConfig.builder() + .password(password).ssl(tls); + + if (username != null) { + return builder.user(username); + } + + return builder; + } + + protected String getURISchema(boolean tls) { + return (tls ? "rediss" : "redis") + "://"; + } + + public static HashMap loadFromJSON(String filePath) throws Exception { + Gson gson = new Gson(); + HashMap configs; + try (FileReader reader = new FileReader(filePath)) { + configs = gson.fromJson(reader, new TypeToken>() { + }.getType()); + } + return configs; + } +} diff --git a/src/test/java/redis/clients/jedis/HostAndPorts.java b/src/test/java/redis/clients/jedis/HostAndPorts.java index 1f919117bb1..2a1fc5581d1 100644 --- a/src/test/java/redis/clients/jedis/HostAndPorts.java +++ b/src/test/java/redis/clients/jedis/HostAndPorts.java @@ -1,27 +1,24 @@ package redis.clients.jedis; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class HostAndPorts { - private static List redisHostAndPortList = new ArrayList<>(); + private static HashMap endpointConfigs; + private static List sentinelHostAndPortList = new ArrayList<>(); private static List clusterHostAndPortList = new ArrayList<>(); private static List stableClusterHostAndPortList = new ArrayList<>(); static { - redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT)); - redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 1)); - redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 2)); - redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 3)); - redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 4)); - redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 5)); - redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 6)); - redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 7)); - redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 8)); - redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 9)); - redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 10)); + String endpointsPath = System.getenv().getOrDefault("REDIS_ENDPOINTS_CONFIG_PATH", "src/test/resources/endpoints.json"); + try { + endpointConfigs = EndpointConfig.loadFromJSON(endpointsPath); + } catch (Exception e) { + throw new RuntimeException(e); + } sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT)); sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT + 1)); @@ -41,31 +38,12 @@ public final class HostAndPorts { stableClusterHostAndPortList.add(new HostAndPort("localhost", 7481)); } - public static List parseHosts(String envHosts, - List existingHostsAndPorts) { - - if (null != envHosts && 0 < envHosts.length()) { - - String[] hostDefs = envHosts.split(","); - - if (null != hostDefs && 2 <= hostDefs.length) { - - List envHostsAndPorts = new ArrayList<>(hostDefs.length); - - for (String hostDef : hostDefs) { - - envHostsAndPorts.add(HostAndPort.from(hostDef)); - } - - return envHostsAndPorts; - } + public static EndpointConfig getRedisEndpoint(String endpointName) { + if (!endpointConfigs.containsKey(endpointName)) { + throw new IllegalArgumentException("Unknown Redis endpoint: " + endpointName); } - return existingHostsAndPorts; - } - - public static List getRedisServers() { - return redisHostAndPortList; + return endpointConfigs.get(endpointName); } public static List getSentinelServers() { diff --git a/src/test/java/redis/clients/jedis/JedisPoolTest.java b/src/test/java/redis/clients/jedis/JedisPoolTest.java index a256abcae07..29b3fd8438d 100644 --- a/src/test/java/redis/clients/jedis/JedisPoolTest.java +++ b/src/test/java/redis/clients/jedis/JedisPoolTest.java @@ -22,13 +22,15 @@ public class JedisPoolTest { - private static final HostAndPort hnp = HostAndPorts.getRedisServers().get(0); + private static final EndpointConfig endpointStandalone0 = HostAndPorts.getRedisEndpoint("standalone0"); + + private static final EndpointConfig endpointStandalone1 = HostAndPorts.getRedisEndpoint("standalone1"); @Test public void checkConnections() { - JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort(), 2000); + JedisPool pool = new JedisPool(new JedisPoolConfig(), endpointStandalone0.getHost(), endpointStandalone0.getPort(), 2000); try (Jedis jedis = pool.getResource()) { - jedis.auth("foobared"); + jedis.auth(endpointStandalone0.getPassword()); jedis.set("foo", "bar"); assertEquals("bar", jedis.get("foo")); } @@ -38,7 +40,7 @@ public void checkConnections() { @Test public void checkResourceWithConfig() { - try (JedisPool pool = new JedisPool(HostAndPorts.getRedisServers().get(7), + try (JedisPool pool = new JedisPool(HostAndPorts.getRedisEndpoint("standalone7-with-lfu-policy").getHostAndPort(), DefaultJedisClientConfig.builder().socketTimeoutMillis(5000).build())) { try (Jedis jedis = pool.getResource()) { @@ -51,9 +53,9 @@ public void checkResourceWithConfig() { @Test public void checkCloseableConnections() throws Exception { - JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort(), 2000); + JedisPool pool = new JedisPool(new JedisPoolConfig(), endpointStandalone0.getHost(), endpointStandalone0.getPort(), 2000); try (Jedis jedis = pool.getResource()) { - jedis.auth("foobared"); + jedis.auth(endpointStandalone0.getPassword()); jedis.set("foo", "bar"); assertEquals("bar", jedis.get("foo")); } @@ -65,7 +67,7 @@ public void checkCloseableConnections() throws Exception { public void checkConnectionWithDefaultHostAndPort() { JedisPool pool = new JedisPool(new JedisPoolConfig()); try (Jedis jedis = pool.getResource()) { - jedis.auth("foobared"); + jedis.auth(endpointStandalone0.getPassword()); jedis.set("foo", "bar"); assertEquals("bar", jedis.get("foo")); } @@ -78,7 +80,7 @@ public void checkResourceIsClosableAndReusable() { GenericObjectPoolConfig config = new GenericObjectPoolConfig<>(); config.setMaxTotal(1); config.setBlockWhenExhausted(false); - try (JedisPool pool = new JedisPool(config, hnp.getHost(), hnp.getPort(), 2000, "foobared", 0, + try (JedisPool pool = new JedisPool(config, endpointStandalone0.getHost(), endpointStandalone0.getPort(), 2000, endpointStandalone0.getPassword(), 0, "closable-reusable-pool", false, null, null, null)) { Jedis jedis = pool.getResource(); @@ -94,15 +96,15 @@ public void checkResourceIsClosableAndReusable() { @Test public void checkPoolRepairedWhenJedisIsBroken() { - JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort()); + JedisPool pool = new JedisPool(new JedisPoolConfig(), endpointStandalone0.getHost(), endpointStandalone0.getPort()); try (Jedis jedis = pool.getResource()) { - jedis.auth("foobared"); + jedis.auth(endpointStandalone0.getPassword()); jedis.set("foo", "0"); jedis.disconnect(); } try (Jedis jedis = pool.getResource()) { - jedis.auth("foobared"); + jedis.auth(endpointStandalone0.getPassword()); jedis.incr("foo"); } pool.close(); @@ -114,12 +116,12 @@ public void checkPoolOverflow() { GenericObjectPoolConfig config = new GenericObjectPoolConfig<>(); config.setMaxTotal(1); config.setBlockWhenExhausted(false); - try (JedisPool pool = new JedisPool(config, hnp.getHost(), hnp.getPort()); + try (JedisPool pool = new JedisPool(config, endpointStandalone0.getHost(), endpointStandalone0.getPort()); Jedis jedis = pool.getResource()) { - jedis.auth("foobared"); + jedis.auth(endpointStandalone0.getPassword()); try (Jedis jedis2 = pool.getResource()) { - jedis2.auth("foobared"); + jedis2.auth(endpointStandalone0.getPassword()); } } } @@ -128,7 +130,7 @@ public void checkPoolOverflow() { public void securePool() { JedisPoolConfig config = new JedisPoolConfig(); config.setTestOnBorrow(true); - JedisPool pool = new JedisPool(config, hnp.getHost(), hnp.getPort(), 2000, "foobared"); + JedisPool pool = new JedisPool(config, endpointStandalone0.getHost(), endpointStandalone0.getPort(), 2000, endpointStandalone0.getPassword()); try (Jedis jedis = pool.getResource()) { jedis.set("foo", "bar"); } @@ -138,27 +140,28 @@ public void securePool() { @Test public void nonDefaultDatabase() { - try (JedisPool pool0 = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort(), 2000, - "foobared"); Jedis jedis0 = pool0.getResource()) { + try (JedisPool pool0 = new JedisPool(new JedisPoolConfig(), endpointStandalone0.getHost(), endpointStandalone0.getPort(), 2000, + endpointStandalone0.getPassword()); Jedis jedis0 = pool0.getResource()) { jedis0.set("foo", "bar"); assertEquals("bar", jedis0.get("foo")); } - try (JedisPool pool1 = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort(), 2000, - "foobared", 1); Jedis jedis1 = pool1.getResource()) { + try (JedisPool pool1 = new JedisPool(new JedisPoolConfig(), endpointStandalone0.getHost(), endpointStandalone0.getPort(), 2000, + endpointStandalone0.getPassword(), 1); Jedis jedis1 = pool1.getResource()) { assertNull(jedis1.get("foo")); } } @Test public void startWithUrlString() { - try (Jedis j = new Jedis("localhost", 6380)) { - j.auth("foobared"); + try (Jedis j = new Jedis(endpointStandalone1.getHostAndPort())) { + j.auth(endpointStandalone1.getPassword()); j.select(2); j.set("foo", "bar"); } - try (JedisPool pool = new JedisPool("redis://:foobared@localhost:6380/2"); + try (JedisPool pool = new JedisPool( + endpointStandalone1.getURIBuilder().credentials("", endpointStandalone1.getPassword()).path("/2").build()); Jedis jedis = pool.getResource()) { assertEquals("PONG", jedis.ping()); assertEquals("bar", jedis.get("foo")); @@ -167,13 +170,14 @@ public void startWithUrlString() { @Test public void startWithUrl() throws URISyntaxException { - try (Jedis j = new Jedis("localhost", 6380)) { - j.auth("foobared"); + try (Jedis j = new Jedis(endpointStandalone1.getHostAndPort())) { + j.auth(endpointStandalone1.getPassword()); j.select(2); j.set("foo", "bar"); } - try (JedisPool pool = new JedisPool(new URI("redis://:foobared@localhost:6380/2")); + try (JedisPool pool = new JedisPool( + endpointStandalone1.getURIBuilder().credentials("", endpointStandalone1.getPassword()).path("/2").build()); Jedis jedis = pool.getResource()) { assertEquals("bar", jedis.get("foo")); } @@ -186,14 +190,14 @@ public void shouldThrowInvalidURIExceptionForInvalidURI() throws URISyntaxExcept @Test public void allowUrlWithNoDBAndNoPassword() throws URISyntaxException { - new JedisPool("redis://localhost:6380").close(); - new JedisPool(new URI("redis://localhost:6380")).close(); + new JedisPool(endpointStandalone1.getURI().toString()).close(); + new JedisPool(endpointStandalone1.getURI()).close(); } @Test public void selectDatabaseOnActivation() { - try (JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort(), 2000, - "foobared")) { + try (JedisPool pool = new JedisPool(new JedisPoolConfig(), endpointStandalone0.getHost(), endpointStandalone0.getPort(), 2000, + endpointStandalone0.getPassword())) { Jedis jedis0 = pool.getResource(); assertEquals(0, jedis0.getDB()); @@ -213,8 +217,8 @@ public void selectDatabaseOnActivation() { @Test public void customClientName() { - try (JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort(), 2000, - "foobared", 0, "my_shiny_client_name"); Jedis jedis = pool.getResource()) { + try (JedisPool pool = new JedisPool(new JedisPoolConfig(), endpointStandalone0.getHost(), endpointStandalone0.getPort(), 2000, + endpointStandalone0.getPassword(), 0, "my_shiny_client_name"); Jedis jedis = pool.getResource()) { assertEquals("my_shiny_client_name", jedis.clientGetname()); } @@ -222,8 +226,8 @@ public void customClientName() { @Test public void invalidClientName() { - try (JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort(), 2000, - "foobared", 0, "invalid client name"); Jedis jedis = pool.getResource()) { + try (JedisPool pool = new JedisPool(new JedisPoolConfig(), endpointStandalone0.getHost(), endpointStandalone0.getPort(), 2000, + endpointStandalone0.getPassword(), 0, "invalid client name"); Jedis jedis = pool.getResource()) { } catch (Exception e) { if (!e.getMessage().startsWith("client info cannot contain space")) { Assert.fail("invalid client name test fail"); @@ -287,7 +291,7 @@ public void returnResourceShouldResetState() { GenericObjectPoolConfig config = new GenericObjectPoolConfig<>(); config.setMaxTotal(1); config.setBlockWhenExhausted(false); - JedisPool pool = new JedisPool(config, hnp.getHost(), hnp.getPort(), 2000, "foobared"); + JedisPool pool = new JedisPool(config, endpointStandalone0.getHost(), endpointStandalone0.getPort(), 2000, endpointStandalone0.getPassword()); Jedis jedis = pool.getResource(); try { @@ -312,8 +316,8 @@ public void returnResourceShouldResetState() { @Test public void getNumActiveWhenPoolIsClosed() { - JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort(), 2000, - "foobared", 0, "my_shiny_client_name"); + JedisPool pool = new JedisPool(new JedisPoolConfig(), endpointStandalone0.getHost(), endpointStandalone0.getPort(), 2000, + endpointStandalone0.getPassword(), 0, "my_shiny_client_name"); try (Jedis j = pool.getResource()) { j.ping(); @@ -325,16 +329,16 @@ public void getNumActiveWhenPoolIsClosed() { @Test public void getNumActiveReturnsTheCorrectNumber() { - try (JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort(), 2000)) { + try (JedisPool pool = new JedisPool(new JedisPoolConfig(), endpointStandalone0.getHost(), endpointStandalone0.getPort(), 2000)) { Jedis jedis = pool.getResource(); - jedis.auth("foobared"); + jedis.auth(endpointStandalone0.getPassword()); jedis.set("foo", "bar"); assertEquals("bar", jedis.get("foo")); assertEquals(1, pool.getNumActive()); Jedis jedis2 = pool.getResource(); - jedis.auth("foobared"); + jedis.auth(endpointStandalone0.getPassword()); jedis.set("foo", "bar"); assertEquals(2, pool.getNumActive()); @@ -350,7 +354,7 @@ public void getNumActiveReturnsTheCorrectNumber() { @Test public void testAddObject() { - try (JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort(), 2000)) { + try (JedisPool pool = new JedisPool(new JedisPoolConfig(), endpointStandalone0.getHost(), endpointStandalone0.getPort(), 2000)) { pool.addObjects(1); assertEquals(1, pool.getNumIdle()); } @@ -358,9 +362,9 @@ public void testAddObject() { @Test public void closeResourceTwice() { - try (JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort(), 2000)) { + try (JedisPool pool = new JedisPool(new JedisPoolConfig(), endpointStandalone0.getHost(), endpointStandalone0.getPort(), 2000)) { Jedis j = pool.getResource(); - j.auth("foobared"); + j.auth(endpointStandalone0.getPassword()); j.ping(); j.close(); j.close(); @@ -369,7 +373,7 @@ public void closeResourceTwice() { @Test public void closeBrokenResourceTwice() { - try (JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort(), 2000)) { + try (JedisPool pool = new JedisPool(new JedisPoolConfig(), endpointStandalone0.getHost(), endpointStandalone0.getPort(), 2000)) { Jedis j = pool.getResource(); try { // make connection broken @@ -388,8 +392,9 @@ public void closeBrokenResourceTwice() { public void testCloseConnectionOnMakeObject() { JedisPoolConfig config = new JedisPoolConfig(); config.setTestOnBorrow(true); - try (JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort(), 2000, - "wrong pass"); Jedis jedis = new Jedis("redis://:foobared@localhost:6379/")) { + try (JedisPool pool = new JedisPool(new JedisPoolConfig(), endpointStandalone0.getHost(), + endpointStandalone0.getPort(), 2000, "wrong pass"); + Jedis jedis = new Jedis(endpointStandalone0.getURIBuilder().defaultCredentials().build())) { int currentClientCount = getClientCount(jedis.clientList()); try { pool.getResource(); @@ -407,8 +412,8 @@ private int getClientCount(final String clientList) { @Test public void testResetInvalidCredentials() { DefaultRedisCredentialsProvider credentialsProvider - = new DefaultRedisCredentialsProvider(new DefaultRedisCredentials(null, "foobared")); - JedisFactory factory = new JedisFactory(hnp, DefaultJedisClientConfig.builder() + = new DefaultRedisCredentialsProvider(new DefaultRedisCredentials(null, endpointStandalone0.getPassword())); + JedisFactory factory = new JedisFactory(endpointStandalone0.getHostAndPort(), DefaultJedisClientConfig.builder() .credentialsProvider(credentialsProvider).clientName("my_shiny_client_name").build()); try (JedisPool pool = new JedisPool(new JedisPoolConfig(), factory)) { @@ -437,7 +442,7 @@ public void testResetInvalidCredentials() { public void testResetValidCredentials() { DefaultRedisCredentialsProvider credentialsProvider = new DefaultRedisCredentialsProvider(new DefaultRedisCredentials(null, "bad password")); - JedisFactory factory = new JedisFactory(hnp, DefaultJedisClientConfig.builder() + JedisFactory factory = new JedisFactory(endpointStandalone0.getHostAndPort(), DefaultJedisClientConfig.builder() .credentialsProvider(credentialsProvider).clientName("my_shiny_client_name").build()); try (JedisPool pool = new JedisPool(new JedisPoolConfig(), factory)) { @@ -446,7 +451,7 @@ public void testResetValidCredentials() { } catch (JedisException e) { } assertEquals(0, pool.getNumActive()); - credentialsProvider.setCredentials(new DefaultRedisCredentials(null, "foobared")); + credentialsProvider.setCredentials(new DefaultRedisCredentials(null, endpointStandalone0.getPassword())); try (Jedis obj2 = pool.getResource()) { obj2.set("foo", "bar"); assertEquals("bar", obj2.get("foo")); diff --git a/src/test/java/redis/clients/jedis/JedisPooledTest.java b/src/test/java/redis/clients/jedis/JedisPooledTest.java index 6036062f5bd..12fa2c0e3e5 100644 --- a/src/test/java/redis/clients/jedis/JedisPooledTest.java +++ b/src/test/java/redis/clients/jedis/JedisPooledTest.java @@ -21,12 +21,15 @@ public class JedisPooledTest { - private static final HostAndPort hnp = HostAndPorts.getRedisServers().get(7); - private static final HostAndPort pwp = HostAndPorts.getRedisServers().get(1); // password protected + private static final EndpointConfig endpointStandalone7 = HostAndPorts.getRedisEndpoint( + "standalone7-with-lfu-policy"); + private static final EndpointConfig endpointStandalone1 = HostAndPorts.getRedisEndpoint( + "standalone1"); // password protected @Test public void checkCloseableConnections() { - JedisPooled pool = new JedisPooled(new ConnectionPoolConfig(), hnp.getHost(), hnp.getPort(), 2000); + JedisPooled pool = new JedisPooled(new ConnectionPoolConfig(), endpointStandalone7.getHost(), + endpointStandalone7.getPort(), 2000); pool.set("foo", "bar"); assertEquals("bar", pool.get("foo")); pool.close(); @@ -35,7 +38,7 @@ public void checkCloseableConnections() { @Test public void checkResourceWithConfig() { - try (JedisPooled pool = new JedisPooled(hnp, + try (JedisPooled pool = new JedisPooled(endpointStandalone7.getHostAndPort(), DefaultJedisClientConfig.builder().socketTimeoutMillis(5000).build())) { try (Connection jedis = pool.getPool().getResource()) { @@ -50,7 +53,7 @@ public void checkPoolOverflow() { GenericObjectPoolConfig config = new GenericObjectPoolConfig<>(); config.setMaxTotal(1); config.setBlockWhenExhausted(false); - try (JedisPooled pool = new JedisPooled(hnp, config); + try (JedisPooled pool = new JedisPooled(endpointStandalone7.getHostAndPort(), config); Connection jedis = pool.getPool().getResource()) { try (Connection jedis2 = pool.getPool().getResource()) { @@ -60,26 +63,29 @@ public void checkPoolOverflow() { @Test public void startWithUrlString() { - try (Jedis j = new Jedis("localhost", 6380)) { - j.auth("foobared"); + try (Jedis j = new Jedis(endpointStandalone1.getHostAndPort())) { + j.auth(endpointStandalone1.getPassword()); j.select(2); j.set("foo", "bar"); } - try (JedisPooled pool = new JedisPooled("redis://:foobared@localhost:6380/2")) { + try (JedisPooled pool = new JedisPooled( + endpointStandalone1.getURIBuilder().credentials("", endpointStandalone1.getPassword()).path("/2").build() + .toString())) { assertEquals("bar", pool.get("foo")); } } @Test public void startWithUrl() throws URISyntaxException { - try (Jedis j = new Jedis("localhost", 6380)) { - j.auth("foobared"); + try (Jedis j = new Jedis(endpointStandalone1.getHostAndPort())) { + j.auth(endpointStandalone1.getPassword()); j.select(2); j.set("foo", "bar"); } - try (JedisPooled pool = new JedisPooled(new URI("redis://:foobared@localhost:6380/2"))) { + try (JedisPooled pool = new JedisPooled( + endpointStandalone1.getURIBuilder().credentials("", endpointStandalone1.getPassword()).path("/2").build())) { assertEquals("bar", pool.get("foo")); } } @@ -91,13 +97,13 @@ public void shouldThrowExceptionForInvalidURI() throws URISyntaxException { @Test public void allowUrlWithNoDBAndNoPassword() throws URISyntaxException { - new JedisPooled("redis://localhost:6380").close(); - new JedisPooled(new URI("redis://localhost:6380")).close(); + new JedisPooled(endpointStandalone1.getURI().toString()).close(); + new JedisPooled(endpointStandalone1.getURI()).close(); } @Test public void customClientName() { - try (JedisPooled pool = new JedisPooled(hnp, DefaultJedisClientConfig.builder() + try (JedisPooled pool = new JedisPooled(endpointStandalone7.getHostAndPort(), DefaultJedisClientConfig.builder() .clientName("my_shiny_client_name").build()); Connection jedis = pool.getPool().getResource()) { assertEquals("my_shiny_client_name", new Jedis(jedis).clientGetname()); @@ -106,7 +112,7 @@ public void customClientName() { @Test public void invalidClientName() { - try (JedisPooled pool = new JedisPooled(hnp, DefaultJedisClientConfig.builder() + try (JedisPooled pool = new JedisPooled(endpointStandalone7.getHostAndPort(), DefaultJedisClientConfig.builder() .clientName("invalid client name").build()); Connection jedis = pool.getPool().getResource()) { } catch (Exception e) { @@ -118,7 +124,7 @@ public void invalidClientName() { @Test public void getNumActiveWhenPoolIsClosed() { - JedisPooled pool = new JedisPooled(hnp); + JedisPooled pool = new JedisPooled(endpointStandalone7.getHostAndPort()); try (Connection j = pool.getPool().getResource()) { j.ping(); @@ -130,7 +136,8 @@ public void getNumActiveWhenPoolIsClosed() { @Test public void getNumActiveReturnsTheCorrectNumber() { - try (JedisPooled pool = new JedisPooled(new ConnectionPoolConfig(), hnp.getHost(), hnp.getPort(), 2000)) { + try (JedisPooled pool = new JedisPooled(new ConnectionPoolConfig(), + endpointStandalone7.getHost(), endpointStandalone7.getPort(), 2000)) { Connection jedis = pool.getPool().getResource(); assertEquals(1, pool.getPool().getNumActive()); @@ -148,7 +155,8 @@ public void getNumActiveReturnsTheCorrectNumber() { @Test public void closeResourceTwice() { - try (JedisPooled pool = new JedisPooled(new ConnectionPoolConfig(), hnp.getHost(), hnp.getPort(), 2000)) { + try (JedisPooled pool = new JedisPooled(new ConnectionPoolConfig(), + endpointStandalone7.getHost(), endpointStandalone7.getPort(), 2000)) { Connection j = pool.getPool().getResource(); j.ping(); j.close(); @@ -158,7 +166,8 @@ public void closeResourceTwice() { @Test public void closeBrokenResourceTwice() { - try (JedisPooled pool = new JedisPooled(new ConnectionPoolConfig(), hnp.getHost(), hnp.getPort(), 2000)) { + try (JedisPooled pool = new JedisPooled(new ConnectionPoolConfig(), + endpointStandalone7.getHost(), endpointStandalone7.getPort(), 2000)) { Connection j = pool.getPool().getResource(); try { // make connection broken @@ -178,7 +187,7 @@ public void testResetValidCredentials() { DefaultRedisCredentialsProvider credentialsProvider = new DefaultRedisCredentialsProvider(new DefaultRedisCredentials(null, "bad password")); - try (JedisPooled pool = new JedisPooled(pwp, DefaultJedisClientConfig.builder() + try (JedisPooled pool = new JedisPooled(endpointStandalone1.getHostAndPort(), DefaultJedisClientConfig.builder() .credentialsProvider(credentialsProvider).build())) { try { pool.get("foo"); @@ -186,7 +195,7 @@ public void testResetValidCredentials() { } catch (JedisException e) { } assertEquals(0, pool.getPool().getNumActive()); - credentialsProvider.setCredentials(new DefaultRedisCredentials(null, "foobared")); + credentialsProvider.setCredentials(new DefaultRedisCredentials(null, endpointStandalone1.getPassword())); assertThat(pool.get("foo"), anything()); } } @@ -223,7 +232,7 @@ public String getUser() { @Override public char[] getPassword() { - return "foobared".toCharArray(); + return endpointStandalone1.getPassword().toCharArray(); } }; } @@ -238,7 +247,7 @@ public void cleanUp() { GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig<>(); poolConfig.setMaxTotal(1); poolConfig.setTestOnBorrow(true); - try (JedisPooled pool = new JedisPooled(pwp, DefaultJedisClientConfig.builder() + try (JedisPooled pool = new JedisPooled(endpointStandalone1.getHostAndPort(), DefaultJedisClientConfig.builder() .credentialsProvider(credentialsProvider).build(), poolConfig)) { try { pool.get("foo"); diff --git a/src/test/java/redis/clients/jedis/JedisSentinelPoolTest.java b/src/test/java/redis/clients/jedis/JedisSentinelPoolTest.java index d00da824477..3329c45647c 100644 --- a/src/test/java/redis/clients/jedis/JedisSentinelPoolTest.java +++ b/src/test/java/redis/clients/jedis/JedisSentinelPoolTest.java @@ -18,9 +18,6 @@ public class JedisSentinelPoolTest { private static final String MASTER_NAME = "mymaster"; - //protected static HostAndPort master = HostAndPorts.getRedisServers().get(2); - //protected static HostAndPort slave1 = HostAndPorts.getRedisServers().get(3); - protected static final HostAndPort sentinel1 = HostAndPorts.getSentinelServers().get(1); protected static final HostAndPort sentinel2 = HostAndPorts.getSentinelServers().get(3); diff --git a/src/test/java/redis/clients/jedis/JedisSentinelTest.java b/src/test/java/redis/clients/jedis/JedisSentinelTest.java index 6fc01eb2f8c..eb956d5eb1d 100644 --- a/src/test/java/redis/clients/jedis/JedisSentinelTest.java +++ b/src/test/java/redis/clients/jedis/JedisSentinelTest.java @@ -24,12 +24,10 @@ public class JedisSentinelTest { private static final String FAILOVER_MASTER_NAME = "mymasterfailover"; private static final String MASTER_IP = "127.0.0.1"; - protected static HostAndPort master = HostAndPorts.getRedisServers().get(0); - protected static HostAndPort slave = HostAndPorts.getRedisServers().get(4); + protected static EndpointConfig master = HostAndPorts.getRedisEndpoint("standalone0"); protected static HostAndPort sentinel = HostAndPorts.getSentinelServers().get(0); protected static HostAndPort sentinelForFailover = HostAndPorts.getSentinelServers().get(2); - protected static HostAndPort masterForFailover = HostAndPorts.getRedisServers().get(5); @Before public void setup() throws InterruptedException { diff --git a/src/test/java/redis/clients/jedis/JedisTest.java b/src/test/java/redis/clients/jedis/JedisTest.java index 52d8c80c02a..560c5a05774 100644 --- a/src/test/java/redis/clients/jedis/JedisTest.java +++ b/src/test/java/redis/clients/jedis/JedisTest.java @@ -36,7 +36,7 @@ public JedisTest(RedisProtocol protocol) { @Test public void useWithoutConnecting() { try (Jedis j = new Jedis()) { - j.auth("foobared"); + j.auth(endpoint.getPassword()); j.dbSize(); } } @@ -56,31 +56,31 @@ public void checkBinaryData() { @Test public void connectWithConfig() { - try (Jedis jedis = new Jedis(hnp, DefaultJedisClientConfig.builder().build())) { - jedis.auth("foobared"); + try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), DefaultJedisClientConfig.builder().build())) { + jedis.auth(endpoint.getPassword()); assertEquals("PONG", jedis.ping()); } - try (Jedis jedis = new Jedis(hnp, DefaultJedisClientConfig.builder().password("foobared") - .build())) { + try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), + endpoint.getClientConfigBuilder().build())) { assertEquals("PONG", jedis.ping()); } } @Test public void connectWithEmptyConfigInterface() { - try (Jedis jedis = new Jedis(hnp, new JedisClientConfig() { + try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), new JedisClientConfig() { })) { - jedis.auth("foobared"); + jedis.auth(endpoint.getPassword()); assertEquals("PONG", jedis.ping()); } } @Test public void connectWithConfigInterface() { - try (Jedis jedis = new Jedis(hnp, new JedisClientConfig() { + try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), new JedisClientConfig() { @Override public String getPassword() { - return "foobared"; + return endpoint.getPassword(); } })) { assertEquals("PONG", jedis.ping()); @@ -89,8 +89,8 @@ public String getPassword() { @Test public void connectOnResp3Protocol() { - try (Jedis jedis = new Jedis(hnp, DefaultJedisClientConfig.builder() - .protocol(RedisProtocol.RESP3).password("foobared").build())) { + try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), endpoint.getClientConfigBuilder() + .protocol(RedisProtocol.RESP3).build())) { assertEquals("PONG", jedis.ping()); assertEquals(RedisProtocol.RESP3, jedis.getConnection().getRedisProtocol()); } @@ -98,8 +98,8 @@ public void connectOnResp3Protocol() { @Test public void connectOnResp3ProtocolShortcut() { - try (Jedis jedis = new Jedis(hnp, DefaultJedisClientConfig.builder().resp3() - .password("foobared").build())) { + try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), endpoint.getClientConfigBuilder() + .resp3().build())) { assertEquals("PONG", jedis.ping()); assertEquals(RedisProtocol.RESP3, jedis.getConnection().getRedisProtocol()); } @@ -109,8 +109,9 @@ public void connectOnResp3ProtocolShortcut() { public void timeoutConnection() throws Exception { final String TIMEOUT_STR = "timeout"; - Jedis jedis = new Jedis("localhost", 6379, 15000); - jedis.auth("foobared"); + Jedis jedis = new Jedis(endpoint.getHostAndPort(), + endpoint.getClientConfigBuilder().timeoutMillis(15000).build()); + // read current config final String timeout = jedis.configGet(TIMEOUT_STR).get(TIMEOUT_STR); try { @@ -125,8 +126,7 @@ public void timeoutConnection() throws Exception { jedis.close(); } finally { // reset config - jedis = new Jedis("localhost", 6379); - jedis.auth("foobared"); + jedis = new Jedis(endpoint.getHostAndPort(), endpoint.getClientConfigBuilder().build()); jedis.configSet(TIMEOUT_STR, timeout); jedis.close(); } @@ -134,8 +134,8 @@ public void timeoutConnection() throws Exception { @Test public void infiniteTimeout() throws Exception { - try (Jedis timeoutJedis = new Jedis("localhost", 6379, 200, 200, 200)) { - timeoutJedis.auth("foobared"); + try (Jedis timeoutJedis = new Jedis(endpoint.getHost(), endpoint.getPort(), 200, 200, 200)) { + timeoutJedis.auth(endpoint.getPassword()); try { timeoutJedis.blpop(0, "foo"); fail("SocketTimeoutException should occur"); @@ -168,13 +168,15 @@ public void shouldThrowInvalidURIExceptionForInvalidURI() throws URISyntaxExcept @Test public void connectWithUrl() { - try (Jedis j = new Jedis("localhost", 6380)) { - j.auth("foobared"); + EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone1"); + try (Jedis j = new Jedis(endpoint.getHostAndPort())) { + j.auth(endpoint.getPassword()); j.select(2); j.set("foo", "bar"); } - try (Jedis j2 = new Jedis("redis://:foobared@localhost:6380/2")) { + try (Jedis j2 = new Jedis( + endpoint.getURIBuilder().defaultCredentials().path("/2").build().toString())) { assertEquals("PONG", j2.ping()); assertEquals("bar", j2.get("foo")); } @@ -182,13 +184,15 @@ public void connectWithUrl() { @Test public void connectWithUri() throws URISyntaxException { - try (Jedis j = new Jedis("localhost", 6380)) { - j.auth("foobared"); + EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone1"); + try (Jedis j = new Jedis(endpoint.getHostAndPort())) { + j.auth(endpoint.getPassword()); j.select(2); j.set("foo", "bar"); } - try (Jedis jedis = new Jedis(new URI("redis://:foobared@localhost:6380/2"))) { + try (Jedis jedis = new Jedis( + endpoint.getURIBuilder().defaultCredentials().path("/2").build())) { assertEquals("PONG", jedis.ping()); assertEquals("bar", jedis.get("foo")); } @@ -196,13 +200,16 @@ public void connectWithUri() throws URISyntaxException { @Test public void connectWithUrlOnResp3() { - try (Jedis j = new Jedis("localhost", 6380)) { - j.auth("foobared"); + EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone1"); + + try (Jedis j = new Jedis(endpoint.getHostAndPort())) { + j.auth(endpoint.getPassword()); j.select(2); j.set("foo", "bar"); } - try (Jedis j2 = new Jedis("redis://:foobared@localhost:6380/2?protocol=3")) { + try (Jedis j2 = new Jedis( + endpoint.getURIBuilder().defaultCredentials().path("/2?protocol=3").build().toString())) { assertEquals("PONG", j2.ping()); assertEquals("bar", j2.get("foo")); } @@ -210,13 +217,16 @@ public void connectWithUrlOnResp3() { @Test public void connectWithUriOnResp3() throws URISyntaxException { - try (Jedis j = new Jedis("localhost", 6380)) { - j.auth("foobared"); + EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone1"); + + try (Jedis j = new Jedis(endpoint.getHostAndPort())) { + j.auth(endpoint.getPassword()); j.select(2); j.set("foo", "bar"); } - try (Jedis jedis = new Jedis(new URI("redis://:foobared@localhost:6380/2?protocol=3"))) { + try (Jedis jedis = new Jedis( + endpoint.getURIBuilder().defaultCredentials().path("/2?protocol=3").build())) { assertEquals("PONG", jedis.ping()); assertEquals("bar", jedis.get("foo")); } @@ -237,15 +247,17 @@ public void shouldNotUpdateDbIndexIfSelectFails() { @Test public void allowUrlWithNoDBAndNoPassword() { - try (Jedis j1 = new Jedis("redis://localhost:6380")) { - j1.auth("foobared"); + EndpointConfig endpointStandalone1 = HostAndPorts.getRedisEndpoint("standalone1"); + + try (Jedis j1 = new Jedis(endpointStandalone1.getURI().toString())) { + j1.auth(endpointStandalone1.getPassword()); // assertEquals("localhost", j1.getClient().getHost()); // assertEquals(6380, j1.getClient().getPort()); assertEquals(0, j1.getDB()); } - try (Jedis j2 = new Jedis("redis://localhost:6380/")) { - j2.auth("foobared"); + try (Jedis j2 = new Jedis(endpointStandalone1.getURI().toString())) { + j2.auth(endpointStandalone1.getPassword()); // assertEquals("localhost", j2.getClient().getHost()); // assertEquals(6380, j2.getClient().getPort()); assertEquals(0, j2.getDB()); @@ -285,7 +297,7 @@ public void checkCloseableAfterConnect() { @Test public void checkCloseableAfterCommand() { Jedis bj = new Jedis(); - bj.auth("foobared"); + bj.auth(endpoint.getPassword()); bj.close(); } @@ -297,7 +309,7 @@ public void checkDisconnectOnQuit() { @Test public void clientSetInfoDefault() { - try (Jedis jedis = new Jedis(hnp, DefaultJedisClientConfig.builder().password("foobared") + try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), endpoint.getClientConfigBuilder() .clientSetInfoConfig(ClientSetInfoConfig.DEFAULT).build())) { assertEquals("PONG", jedis.ping()); String info = jedis.clientInfo(); @@ -308,7 +320,7 @@ public void clientSetInfoDefault() { @Test public void clientSetInfoDisabled() { - try (Jedis jedis = new Jedis(hnp, DefaultJedisClientConfig.builder().password("foobared") + try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), endpoint.getClientConfigBuilder() .clientSetInfoConfig(ClientSetInfoConfig.DISABLED).build())) { assertEquals("PONG", jedis.ping()); String info = jedis.clientInfo(); @@ -321,7 +333,7 @@ public void clientSetInfoDisabled() { public void clientSetInfoLibNameSuffix() { final String libNameSuffix = "for-redis"; ClientSetInfoConfig setInfoConfig = ClientSetInfoConfig.withLibNameSuffix(libNameSuffix); - try (Jedis jedis = new Jedis(hnp, DefaultJedisClientConfig.builder().password("foobared") + try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), endpoint.getClientConfigBuilder() .clientSetInfoConfig(setInfoConfig).build())) { assertEquals("PONG", jedis.ping()); String info = jedis.clientInfo(); diff --git a/src/test/java/redis/clients/jedis/ManagedConnectionProviderTest.java b/src/test/java/redis/clients/jedis/ManagedConnectionProviderTest.java index 84bca8d1fa9..44ca793ef56 100644 --- a/src/test/java/redis/clients/jedis/ManagedConnectionProviderTest.java +++ b/src/test/java/redis/clients/jedis/ManagedConnectionProviderTest.java @@ -14,8 +14,8 @@ public class ManagedConnectionProviderTest { @Before public void setUp() { - connection = new Connection(HostAndPorts.getRedisServers().get(0), - DefaultJedisClientConfig.builder().user("acljedis").password("fizzbuzz").build()); + EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone0"); + connection = new Connection(endpoint.getHostAndPort(), endpoint.getClientConfigBuilder().build()); } @After diff --git a/src/test/java/redis/clients/jedis/MigratePipeliningTest.java b/src/test/java/redis/clients/jedis/MigratePipeliningTest.java index f8e7d8278c1..8cac62c1f08 100644 --- a/src/test/java/redis/clients/jedis/MigratePipeliningTest.java +++ b/src/test/java/redis/clients/jedis/MigratePipeliningTest.java @@ -33,9 +33,17 @@ public class MigratePipeliningTest extends JedisCommandsTestBase { 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 EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone0-acl"); + + private static final EndpointConfig destEndpoint = HostAndPorts.getRedisEndpoint( + "standalone7-with-lfu-policy"); + + private static final EndpointConfig destEndpointWithAuth = HostAndPorts.getRedisEndpoint( + "standalone1"); + + private static final String host = destEndpoint.getHost(); + private static final int port = destEndpoint.getPort(); + private static final int portAuth = destEndpointWithAuth.getPort(); private static final int db = 2; private static final int dbAuth = 3; private static final int timeout = Protocol.DEFAULT_TIMEOUT; @@ -56,8 +64,8 @@ public void setUp() throws Exception { dest.flushAll(); dest.select(db); - destAuth = new Jedis(host, portAuth, 500); - destAuth.auth("foobared"); + destAuth = new Jedis(destEndpointWithAuth.getHostAndPort(), + destEndpointWithAuth.getClientConfigBuilder().build()); destAuth.flushAll(); destAuth.select(dbAuth); } @@ -258,7 +266,8 @@ public void migrateAuth() { Pipeline p = jedis.pipelined(); p.set("foo", "bar"); - p.migrate(host, portAuth, dbAuth, timeout, new MigrateParams().auth("foobared"), "foo"); + p.migrate(host, portAuth, dbAuth, timeout, + new MigrateParams().auth(destEndpointWithAuth.getPassword()), "foo"); p.get("foo"); assertThat(p.syncAndReturnAll(), @@ -274,7 +283,8 @@ public void migrateAuthBinary() { Pipeline p = jedis.pipelined(); p.set(bfoo, bbar); - p.migrate(host, portAuth, dbAuth, timeout, new MigrateParams().auth("foobared"), bfoo); + p.migrate(host, portAuth, dbAuth, timeout, + new MigrateParams().auth(destEndpointWithAuth.getPassword()), bfoo); p.get(bfoo); assertThat(p.syncAndReturnAll(), @@ -290,8 +300,9 @@ public void migrateAuth2() { Pipeline p = destAuth.pipelined(); p.set("foo", "bar"); - p.migrate(host, hnp.getPort(), 0, timeout, - new MigrateParams().auth2("acljedis", "fizzbuzz"), "foo"); + p.migrate(endpoint.getHost(), endpoint.getPort(), 0, timeout, + new MigrateParams().auth2(endpoint.getUsername(), endpoint.getPassword()), + "foo"); p.get("foo"); assertThat(p.syncAndReturnAll(), @@ -307,8 +318,9 @@ public void migrateAuth2Binary() { Pipeline p = dest.pipelined(); p.set(bfoo, bbar); - p.migrate(host, hnp.getPort(), 0, timeout, - new MigrateParams().auth2("acljedis", "fizzbuzz"), bfoo); + p.migrate(endpoint.getHost(), endpoint.getPort(), 0, timeout, + new MigrateParams().auth2(endpoint.getUsername(), endpoint.getPassword()), + bfoo); p.get(bfoo); assertThat(p.syncAndReturnAll(), diff --git a/src/test/java/redis/clients/jedis/PipeliningTest.java b/src/test/java/redis/clients/jedis/PipeliningTest.java index fffaa06a89d..9340f366db9 100644 --- a/src/test/java/redis/clients/jedis/PipeliningTest.java +++ b/src/test/java/redis/clients/jedis/PipeliningTest.java @@ -323,8 +323,10 @@ public void waitReplicas() { p.waitReplicas(1, 10); p.sync(); - try (Jedis j = new Jedis(HostAndPorts.getRedisServers().get(4))) { - j.auth("foobared"); + EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone4-replica-of-standalone1"); + + try (Jedis j = new Jedis(endpoint.getHostAndPort())) { + j.auth(endpoint.getPassword()); assertEquals("replicas", j.get("wait")); } } @@ -336,8 +338,10 @@ public void waitAof() { p.waitAOF(1L, 0L, 0L); p.sync(); - try (Jedis j = new Jedis(HostAndPorts.getRedisServers().get(4))) { - j.auth("foobared"); + EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone4-replica-of-standalone1"); + + try (Jedis j = new Jedis(endpoint.getHostAndPort())) { + j.auth(endpoint.getPassword()); assertEquals("aof", j.get("wait")); } } @@ -523,14 +527,14 @@ public void testEvalshaKeyAndArgWithBinary() { @Test public void testSyncWithNoCommandQueued() { // we need to test with fresh instance of Jedis - Jedis jedis2 = new Jedis(hnp.getHost(), hnp.getPort(), 500); + Jedis jedis2 = new Jedis(endpoint.getHost(), endpoint.getPort(), 500); Pipeline pipeline = jedis2.pipelined(); pipeline.sync(); jedis2.close(); - jedis2 = new Jedis(hnp.getHost(), hnp.getPort(), 500); + jedis2 = new Jedis(endpoint.getHost(), endpoint.getPort(), 500); pipeline = jedis2.pipelined(); List resp = pipeline.syncAndReturnAll(); @@ -542,8 +546,8 @@ public void testSyncWithNoCommandQueued() { @Test public void testCloseable() throws IOException { // we need to test with fresh instance of Jedis - Jedis jedis2 = new Jedis(hnp.getHost(), hnp.getPort(), 500); - jedis2.auth("foobared"); + Jedis jedis2 = new Jedis(endpoint.getHost(), endpoint.getPort(), 500); + jedis2.auth(endpoint.getPassword()); Pipeline pipeline = jedis2.pipelined(); Response retFuture1 = pipeline.set("a", "1"); diff --git a/src/test/java/redis/clients/jedis/ReliableTransactionTest.java b/src/test/java/redis/clients/jedis/ReliableTransactionTest.java index 5abd5cf1261..e3218d02d20 100644 --- a/src/test/java/redis/clients/jedis/ReliableTransactionTest.java +++ b/src/test/java/redis/clients/jedis/ReliableTransactionTest.java @@ -23,16 +23,18 @@ public class ReliableTransactionTest { final byte[] bmykey = { 0x42, 0x02, 0x03, 0x04 }; - private static final HostAndPort hnp = HostAndPorts.getRedisServers().get(0); + private static final EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone0"); private Connection conn; private Jedis nj; @Before public void setUp() throws Exception { - conn = new Connection(hnp, DefaultJedisClientConfig.builder().timeoutMillis(500).password("foobared").build()); + conn = new Connection(endpoint.getHostAndPort(), + endpoint.getClientConfigBuilder().timeoutMillis(500).build()); - nj = new Jedis(hnp, DefaultJedisClientConfig.builder().timeoutMillis(500).password("foobared").build()); + nj = new Jedis(endpoint.getHostAndPort(), + endpoint.getClientConfigBuilder().timeoutMillis(500).build()); nj.flushAll(); } @@ -211,10 +213,6 @@ public void transactionResponseWithError() { @Test public void testCloseable() { - // we need to test with fresh instance of Jedis -// Jedis jedis2 = new Jedis(hnp.getHost(), hnp.getPort(), 500); -// jedis2.auth("foobared"); - ReliableTransaction transaction = new ReliableTransaction(conn); transaction.set("a", "1"); transaction.set("b", "2"); diff --git a/src/test/java/redis/clients/jedis/SSLACLJedisClusterTest.java b/src/test/java/redis/clients/jedis/SSLACLJedisClusterTest.java index c2f0e0ee3ac..16eb63c0e0e 100644 --- a/src/test/java/redis/clients/jedis/SSLACLJedisClusterTest.java +++ b/src/test/java/redis/clients/jedis/SSLACLJedisClusterTest.java @@ -43,10 +43,15 @@ public class SSLACLJedisClusterTest extends JedisClusterTestBase { @BeforeClass public static void prepare() { - org.junit.Assume.assumeTrue("Not running ACL test on this version of Redis", - RedisVersionUtil.checkRedisMajorVersionNumber(6)); - + // We need to set up certificates first before connecting to the endpoint with enabled TLS SSLJedisTest.setupTrustStore(); + + // TODO(imalinovskyi): Remove hardcoded connection settings + // once this test is refactored to support RE + org.junit.Assume.assumeTrue("Not running ACL test on this version of Redis", + RedisVersionUtil.checkRedisMajorVersionNumber(6, + new EndpointConfig(new HostAndPort("localhost", 8379), + "default", "cluster", true))); } @Test diff --git a/src/test/java/redis/clients/jedis/SSLACLJedisTest.java b/src/test/java/redis/clients/jedis/SSLACLJedisTest.java index 0d0ca4e7ebc..8151729e6e8 100644 --- a/src/test/java/redis/clients/jedis/SSLACLJedisTest.java +++ b/src/test/java/redis/clients/jedis/SSLACLJedisTest.java @@ -4,7 +4,6 @@ import java.io.FileInputStream; import java.io.InputStream; -import java.net.URI; import java.security.InvalidAlgorithmParameterException; import java.security.KeyStore; import java.security.SecureRandom; @@ -23,28 +22,32 @@ */ public class SSLACLJedisTest { + protected static final EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone0-acl-tls"); + + protected static final EndpointConfig endpointWithDefaultUser = HostAndPorts.getRedisEndpoint("standalone0-tls"); + @BeforeClass public static void prepare() { + // We need to set up certificates first before connecting to the endpoint with enabled TLS + SSLJedisTest.setupTrustStore(); // Use to check if the ACL test should be ran. ACL are available only in 6.0 and later org.junit.Assume.assumeTrue("Not running ACL test on this version of Redis", - RedisVersionUtil.checkRedisMajorVersionNumber(6)); - - SSLJedisTest.setupTrustStore(); + RedisVersionUtil.checkRedisMajorVersionNumber(6, endpoint)); } @Test public void connectWithSsl() { - try (Jedis jedis = new Jedis("localhost", 6390, true)) { - jedis.auth("acljedis", "fizzbuzz"); + try (Jedis jedis = new Jedis(endpoint.getHost(), endpoint.getPort(), true)) { + jedis.auth(endpoint.getUsername(), endpoint.getPassword()); assertEquals("PONG", jedis.ping()); } } @Test public void connectWithConfig() { - try (Jedis jedis = new Jedis(new HostAndPort("localhost", 6390), + try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), DefaultJedisClientConfig.builder().ssl(true).build())) { - jedis.auth("acljedis", "fizzbuzz"); + jedis.auth(endpoint.getUsername(), endpoint.getPassword()); assertEquals("PONG", jedis.ping()); } } @@ -52,10 +55,12 @@ public void connectWithConfig() { @Test public void connectWithUrl() { // The "rediss" scheme instructs jedis to open a SSL/TLS connection. - try (Jedis jedis = new Jedis("rediss://default:foobared@localhost:6390")) { + try (Jedis jedis = new Jedis( + endpointWithDefaultUser.getURIBuilder().defaultCredentials().build().toString())) { assertEquals("PONG", jedis.ping()); } - try (Jedis jedis = new Jedis("rediss://acljedis:fizzbuzz@localhost:6390")) { + try (Jedis jedis = new Jedis( + endpoint.getURIBuilder().defaultCredentials().build().toString())) { assertEquals("PONG", jedis.ping()); } } @@ -63,10 +68,11 @@ public void connectWithUrl() { @Test public void connectWithUri() { // The "rediss" scheme instructs jedis to open a SSL/TLS connection. - try (Jedis jedis = new Jedis(URI.create("rediss://default:foobared@localhost:6390"))) { + try (Jedis jedis = new Jedis( + endpointWithDefaultUser.getURIBuilder().defaultCredentials().build())) { assertEquals("PONG", jedis.ping()); } - try (Jedis jedis = new Jedis(URI.create("rediss://acljedis:fizzbuzz@localhost:6390"))) { + try (Jedis jedis = new Jedis(endpoint.getURIBuilder().defaultCredentials().build())) { assertEquals("PONG", jedis.ping()); } } diff --git a/src/test/java/redis/clients/jedis/SSLJedisTest.java b/src/test/java/redis/clients/jedis/SSLJedisTest.java index 75619dfef91..d3a5853f421 100644 --- a/src/test/java/redis/clients/jedis/SSLJedisTest.java +++ b/src/test/java/redis/clients/jedis/SSLJedisTest.java @@ -6,7 +6,6 @@ import java.io.File; import java.io.FileInputStream; import java.io.InputStream; -import java.net.URI; import java.security.InvalidAlgorithmParameterException; import java.security.KeyStore; import java.security.SecureRandom; @@ -26,6 +25,8 @@ public class SSLJedisTest { + protected static final EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone0-tls"); + @BeforeClass public static void prepare() { setupTrustStore(); @@ -44,31 +45,31 @@ private static void setJvmTrustStore(String trustStoreFilePath, String trustStor @Test public void connectWithSsl() { - try (Jedis jedis = new Jedis("localhost", 6390, true)) { - jedis.auth("foobared"); + try (Jedis jedis = new Jedis(endpoint.getHost(), endpoint.getPort(), true)) { + jedis.auth(endpoint.getPassword()); assertEquals("PONG", jedis.ping()); } } @Test public void connectWithConfig() { - try (Jedis jedis = new Jedis(new HostAndPort("localhost", 6390), + try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), DefaultJedisClientConfig.builder().ssl(true).build())) { - jedis.auth("foobared"); + jedis.auth(endpoint.getPassword()); assertEquals("PONG", jedis.ping()); } } @Test public void connectWithConfigInterface() { - try (Jedis jedis = new Jedis(new HostAndPort("localhost", 6390), + try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), new JedisClientConfig() { @Override public boolean isSsl() { return true; } })) { - jedis.auth("foobared"); + jedis.auth(endpoint.getPassword()); assertEquals("PONG", jedis.ping()); } } @@ -79,8 +80,8 @@ public boolean isSsl() { @Test public void connectWithUrl() { // The "rediss" scheme instructs jedis to open a SSL/TLS connection. - try (Jedis jedis = new Jedis("rediss://localhost:6390")) { - jedis.auth("foobared"); + try (Jedis jedis = new Jedis(endpoint.getURI().toString())) { + jedis.auth(endpoint.getPassword()); assertEquals("PONG", jedis.ping()); } } @@ -91,8 +92,8 @@ public void connectWithUrl() { @Test public void connectWithUri() { // The "rediss" scheme instructs jedis to open a SSL/TLS connection. - try (Jedis jedis = new Jedis(URI.create("rediss://localhost:6390"))) { - jedis.auth("foobared"); + try (Jedis jedis = new Jedis(endpoint.getURI())) { + jedis.auth(endpoint.getPassword()); assertEquals("PONG", jedis.ping()); } } diff --git a/src/test/java/redis/clients/jedis/SentineledConnectionProviderTest.java b/src/test/java/redis/clients/jedis/SentineledConnectionProviderTest.java index 593875710b0..746c50bc43f 100644 --- a/src/test/java/redis/clients/jedis/SentineledConnectionProviderTest.java +++ b/src/test/java/redis/clients/jedis/SentineledConnectionProviderTest.java @@ -22,9 +22,6 @@ public class SentineledConnectionProviderTest { private static final String MASTER_NAME = "mymaster"; - //protected static HostAndPort master = HostAndPorts.getRedisServers().get(2); - //protected static HostAndPort slave1 = HostAndPorts.getRedisServers().get(3); - protected static final HostAndPort sentinel1 = HostAndPorts.getSentinelServers().get(1); protected static final HostAndPort sentinel2 = HostAndPorts.getSentinelServers().get(3); diff --git a/src/test/java/redis/clients/jedis/ShardedConnectionTest.java b/src/test/java/redis/clients/jedis/ShardedConnectionTest.java index 2318b7b3d2d..f849315d2ed 100644 --- a/src/test/java/redis/clients/jedis/ShardedConnectionTest.java +++ b/src/test/java/redis/clients/jedis/ShardedConnectionTest.java @@ -9,13 +9,15 @@ import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.junit.Before; import org.junit.Test; -import redis.clients.jedis.exceptions.JedisConnectionException; import redis.clients.jedis.exceptions.JedisDataException; public class ShardedConnectionTest { - private static final HostAndPort redis1 = HostAndPorts.getRedisServers().get(0); - private static final HostAndPort redis2 = HostAndPorts.getRedisServers().get(1); + /** + * NOTE(imalinovskyi): Both endpoints should share the same password. + */ + private static final EndpointConfig redis1 = HostAndPorts.getRedisEndpoint("standalone0"); + private static final EndpointConfig redis2 = HostAndPorts.getRedisEndpoint("standalone1"); private List shards; private JedisClientConfig clientConfig; @@ -23,10 +25,10 @@ public class ShardedConnectionTest { @Before public void startUp() { shards = new ArrayList<>(); - shards.add(redis1); - shards.add(redis2); + shards.add(redis1.getHostAndPort()); + shards.add(redis2.getHostAndPort()); - clientConfig = DefaultJedisClientConfig.builder().password("foobared").build(); + clientConfig = redis1.getClientConfigBuilder().build(); for (HostAndPort shard : shards) { try (Jedis j = new Jedis(shard, clientConfig)) { diff --git a/src/test/java/redis/clients/jedis/ShardedPipelineTest.java b/src/test/java/redis/clients/jedis/ShardedPipelineTest.java index a0d5a66d623..86349bf68cd 100644 --- a/src/test/java/redis/clients/jedis/ShardedPipelineTest.java +++ b/src/test/java/redis/clients/jedis/ShardedPipelineTest.java @@ -10,20 +10,20 @@ public class ShardedPipelineTest { - private static final HostAndPort redis1 = HostAndPorts.getRedisServers().get(0); - private static final HostAndPort redis2 = HostAndPorts.getRedisServers().get(1); + private static final EndpointConfig redis1 = HostAndPorts.getRedisEndpoint("standalone0"); + private static final EndpointConfig redis2 = HostAndPorts.getRedisEndpoint("standalone1"); private static final ConnectionPoolConfig DEFAULT_POOL_CONFIG = new ConnectionPoolConfig(); - private static final DefaultJedisClientConfig DEFAULT_CLIENT_CONFIG = DefaultJedisClientConfig - .builder().password("foobared").build(); + private static final DefaultJedisClientConfig DEFAULT_CLIENT_CONFIG = redis1.getClientConfigBuilder() + .build(); - private List shards = Arrays.asList(redis1, redis2); + private List shards = Arrays.asList(redis1.getHostAndPort(), redis2.getHostAndPort()); @Before public void setUp() { for (HostAndPort shard : shards) { try (Jedis j = new Jedis(shard)) { - j.auth("foobared"); + j.auth(redis1.getPassword()); j.flushAll(); } } diff --git a/src/test/java/redis/clients/jedis/ShardingTest.java b/src/test/java/redis/clients/jedis/ShardingTest.java index b673b581ac7..a865740ee6c 100644 --- a/src/test/java/redis/clients/jedis/ShardingTest.java +++ b/src/test/java/redis/clients/jedis/ShardingTest.java @@ -14,17 +14,17 @@ public class ShardingTest { - private static final HostAndPort redis1 = HostAndPorts.getRedisServers().get(0); - private static final HostAndPort redis2 = HostAndPorts.getRedisServers().get(1); + private static final EndpointConfig redis1 = HostAndPorts.getRedisEndpoint("standalone0"); + private static final EndpointConfig redis2 = HostAndPorts.getRedisEndpoint("standalone1"); - private JedisClientConfig clientConfig = DefaultJedisClientConfig.builder().password("foobared").build(); + private JedisClientConfig clientConfig = redis1.getClientConfigBuilder().build(); @Before public void setUp() { - try (Jedis j = new Jedis(redis1, clientConfig)) { + try (Jedis j = new Jedis(redis1.getHostAndPort(), redis1.getClientConfigBuilder().build())) { j.flushAll(); } - try (Jedis j = new Jedis(redis2, clientConfig)) { + try (Jedis j = new Jedis(redis2.getHostAndPort(), redis2.getClientConfigBuilder().build())) { j.flushAll(); } } @@ -32,8 +32,8 @@ public void setUp() { @Test public void trySharding() { List shards = new ArrayList<>(); - shards.add(redis1); - shards.add(redis2); + shards.add(redis1.getHostAndPort()); + shards.add(redis2.getHostAndPort()); try (JedisSharding jedis = new JedisSharding(shards, clientConfig)) { for (int i = 0; i < 1000; i++) { jedis.set("key" + i, Integer.toString(i)); @@ -41,14 +41,14 @@ public void trySharding() { } long totalDbSize = 0; - try (Jedis j = new Jedis(redis1)) { - j.auth("foobared"); + try (Jedis j = new Jedis(redis1.getHostAndPort())) { + j.auth(redis1.getPassword()); long dbSize = j.dbSize(); assertTrue(dbSize > 400); totalDbSize += dbSize; } - try (Jedis j = new Jedis(redis2)) { - j.auth("foobared"); + try (Jedis j = new Jedis(redis2.getHostAndPort())) { + j.auth(redis2.getPassword()); long dbSize = j.dbSize(); assertTrue(dbSize > 400); totalDbSize += dbSize; @@ -59,8 +59,8 @@ public void trySharding() { @Test public void tryShardingWithMurmur() { List shards = new ArrayList<>(); - shards.add(redis1); - shards.add(redis2); + shards.add(redis1.getHostAndPort()); + shards.add(redis2.getHostAndPort()); try (JedisSharding jedis = new JedisSharding(shards, clientConfig, Hashing.MURMUR_HASH)) { for (int i = 0; i < 1000; i++) { jedis.set("key" + i, Integer.toString(i)); @@ -68,14 +68,14 @@ public void tryShardingWithMurmur() { } long totalDbSize = 0; - try (Jedis j = new Jedis(redis1)) { - j.auth("foobared"); + try (Jedis j = new Jedis(redis1.getHostAndPort())) { + j.auth(redis1.getPassword()); long dbSize = j.dbSize(); assertTrue(dbSize > 400); totalDbSize += dbSize; } - try (Jedis j = new Jedis(redis2)) { - j.auth("foobared"); + try (Jedis j = new Jedis(redis2.getHostAndPort())) { + j.auth(redis2.getPassword()); long dbSize = j.dbSize(); assertTrue(dbSize > 400); totalDbSize += dbSize; @@ -86,8 +86,8 @@ public void tryShardingWithMurmur() { @Test public void tryShardingWithMD5() { List shards = new ArrayList<>(); - shards.add(redis1); - shards.add(redis2); + shards.add(redis1.getHostAndPort()); + shards.add(redis2.getHostAndPort()); try (JedisSharding jedis = new JedisSharding(shards, clientConfig, Hashing.MD5)) { for (int i = 0; i < 1000; i++) { jedis.set("key" + i, Integer.toString(i)); @@ -95,14 +95,14 @@ public void tryShardingWithMD5() { } long totalDbSize = 0; - try (Jedis j = new Jedis(redis1)) { - j.auth("foobared"); + try (Jedis j = new Jedis(redis1.getHostAndPort())) { + j.auth(redis1.getPassword()); long dbSize = j.dbSize(); assertTrue(dbSize > 400); totalDbSize += dbSize; } - try (Jedis j = new Jedis(redis2)) { - j.auth("foobared"); + try (Jedis j = new Jedis(redis2.getHostAndPort())) { + j.auth(redis2.getPassword()); long dbSize = j.dbSize(); totalDbSize += dbSize; } @@ -124,8 +124,8 @@ public void checkKeyTags() { @Test public void checkCloseable() { List shards = new ArrayList<>(); - shards.add(redis1); - shards.add(redis2); + shards.add(redis1.getHostAndPort()); + shards.add(redis2.getHostAndPort()); JedisSharding jedis = new JedisSharding(shards, clientConfig); jedis.set("closeable", "true"); @@ -141,8 +141,8 @@ public void checkCloseable() { @Test public void testGeneralCommand() { List shards = new ArrayList<>(); - shards.add(redis1); - shards.add(redis2); + shards.add(redis1.getHostAndPort()); + shards.add(redis2.getHostAndPort()); try (JedisSharding jedis = new JedisSharding(shards, clientConfig)) { jedis.sendCommand("command", SET, "command", "general"); diff --git a/src/test/java/redis/clients/jedis/TransactionV2Test.java b/src/test/java/redis/clients/jedis/TransactionV2Test.java index cf63db1c03f..81267246624 100644 --- a/src/test/java/redis/clients/jedis/TransactionV2Test.java +++ b/src/test/java/redis/clients/jedis/TransactionV2Test.java @@ -25,16 +25,19 @@ public class TransactionV2Test { final byte[] bmykey = { 0x42, 0x02, 0x03, 0x04 }; - private static final HostAndPort hnp = HostAndPorts.getRedisServers().get(0); + private static final EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone0"); private Connection conn; private Jedis nj; @Before public void setUp() throws Exception { - conn = new Connection(hnp, DefaultJedisClientConfig.builder().timeoutMillis(500).password("foobared").build()); + conn = new Connection(endpoint.getHostAndPort(), + endpoint.getClientConfigBuilder().timeoutMillis(500).build()); + + nj = new Jedis(endpoint.getHostAndPort(), + endpoint.getClientConfigBuilder().timeoutMillis(500).build()); - nj = new Jedis(hnp, DefaultJedisClientConfig.builder().timeoutMillis(500).password("foobared").build()); nj.flushAll(); } @@ -212,10 +215,6 @@ public void transactionResponseWithError() { @Test public void testCloseable() { - // we need to test with fresh instance of Jedis -// Jedis jedis2 = new Jedis(hnp.getHost(), hnp.getPort(), 500); -// jedis2.auth("foobared"); - Transaction transaction = new Transaction(conn); transaction.set("a", "1"); transaction.set("b", "2"); diff --git a/src/test/java/redis/clients/jedis/benchmark/GetSetBenchmark.java b/src/test/java/redis/clients/jedis/benchmark/GetSetBenchmark.java index 93d450abc11..59a50d6e5e3 100644 --- a/src/test/java/redis/clients/jedis/benchmark/GetSetBenchmark.java +++ b/src/test/java/redis/clients/jedis/benchmark/GetSetBenchmark.java @@ -4,19 +4,19 @@ import java.net.UnknownHostException; import java.util.Calendar; -import redis.clients.jedis.HostAndPort; +import redis.clients.jedis.EndpointConfig; import redis.clients.jedis.Jedis; import redis.clients.jedis.HostAndPorts; public class GetSetBenchmark { - private static HostAndPort hnp = HostAndPorts.getRedisServers().get(0); + private static EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone0"); private static final int TOTAL_OPERATIONS = 100000; public static void main(String[] args) throws UnknownHostException, IOException { - Jedis jedis = new Jedis(hnp); + Jedis jedis = new Jedis(endpoint.getHostAndPort()); jedis.connect(); - jedis.auth("foobared"); + jedis.auth(endpoint.getPassword()); jedis.flushAll(); long begin = Calendar.getInstance().getTimeInMillis(); diff --git a/src/test/java/redis/clients/jedis/benchmark/PipelinedGetSetBenchmark.java b/src/test/java/redis/clients/jedis/benchmark/PipelinedGetSetBenchmark.java index 413fa55428b..c19c5444bcb 100644 --- a/src/test/java/redis/clients/jedis/benchmark/PipelinedGetSetBenchmark.java +++ b/src/test/java/redis/clients/jedis/benchmark/PipelinedGetSetBenchmark.java @@ -4,20 +4,17 @@ import java.net.UnknownHostException; import java.util.Calendar; -import redis.clients.jedis.HostAndPort; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.Pipeline; -import redis.clients.jedis.HostAndPorts; +import redis.clients.jedis.*; public class PipelinedGetSetBenchmark { - private static HostAndPort hnp = HostAndPorts.getRedisServers().get(0); + private static EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone0"); private static final int TOTAL_OPERATIONS = 200000; public static void main(String[] args) throws UnknownHostException, IOException { - Jedis jedis = new Jedis(hnp); + Jedis jedis = new Jedis(endpoint.getHostAndPort()); jedis.connect(); - jedis.auth("foobared"); + jedis.auth(endpoint.getPassword()); jedis.flushAll(); long begin = Calendar.getInstance().getTimeInMillis(); diff --git a/src/test/java/redis/clients/jedis/benchmark/PoolBenchmark.java b/src/test/java/redis/clients/jedis/benchmark/PoolBenchmark.java index 5b8dc5dc060..b7861950ece 100644 --- a/src/test/java/redis/clients/jedis/benchmark/PoolBenchmark.java +++ b/src/test/java/redis/clients/jedis/benchmark/PoolBenchmark.java @@ -6,20 +6,17 @@ import org.apache.commons.pool2.impl.GenericObjectPoolConfig; -import redis.clients.jedis.HostAndPort; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.JedisPool; -import redis.clients.jedis.HostAndPorts; +import redis.clients.jedis.*; public class PoolBenchmark { - private static HostAndPort hnp = HostAndPorts.getRedisServers().get(0); + private static EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone0"); private static final int TOTAL_OPERATIONS = 100000; public static void main(String[] args) throws Exception { - Jedis j = new Jedis(hnp); + Jedis j = new Jedis(endpoint.getHostAndPort()); j.connect(); - j.auth("foobared"); + j.auth(endpoint.getPassword()); j.flushAll(); j.disconnect(); long t = System.currentTimeMillis(); @@ -30,8 +27,8 @@ public static void main(String[] args) throws Exception { } private static void withPool() throws Exception { - final JedisPool pool = new JedisPool(new GenericObjectPoolConfig(), hnp.getHost(), - hnp.getPort(), 2000, "foobared"); + final JedisPool pool = new JedisPool(new GenericObjectPoolConfig(), endpoint.getHost(), + endpoint.getPort(), 2000, endpoint.getPassword()); List tds = new ArrayList(); final AtomicInteger ind = new AtomicInteger(); diff --git a/src/test/java/redis/clients/jedis/benchmark/PooledBenchmark.java b/src/test/java/redis/clients/jedis/benchmark/PooledBenchmark.java index 2c34beef314..9641d10d0c2 100644 --- a/src/test/java/redis/clients/jedis/benchmark/PooledBenchmark.java +++ b/src/test/java/redis/clients/jedis/benchmark/PooledBenchmark.java @@ -4,19 +4,16 @@ import java.util.List; import java.util.concurrent.atomic.AtomicInteger; -import redis.clients.jedis.HostAndPort; -import redis.clients.jedis.HostAndPorts; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.JedisPooled; +import redis.clients.jedis.*; public class PooledBenchmark { - private static HostAndPort hnp = HostAndPorts.getRedisServers().get(0); + private static EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone0"); private static final int TOTAL_OPERATIONS = 100000; public static void main(String[] args) throws Exception { - try (Jedis j = new Jedis(hnp.getHost(), hnp.getPort())) { - j.auth("foobared"); + try (Jedis j = new Jedis(endpoint.getHost(), endpoint.getPort())) { + j.auth(endpoint.getPassword()); j.flushAll(); j.disconnect(); } @@ -27,7 +24,7 @@ public static void main(String[] args) throws Exception { } private static void withPool() throws Exception { - final JedisPooled j = new JedisPooled(hnp.getHost(), hnp.getPort(), null, "foobared"); + final JedisPooled j = new JedisPooled(endpoint.getHost(), endpoint.getPort(), null, endpoint.getPassword()); List tds = new ArrayList<>(); final AtomicInteger ind = new AtomicInteger(); diff --git a/src/test/java/redis/clients/jedis/benchmark/ShardingBenchmark.java b/src/test/java/redis/clients/jedis/benchmark/ShardingBenchmark.java index ea3c490bcca..4bee304f4e7 100644 --- a/src/test/java/redis/clients/jedis/benchmark/ShardingBenchmark.java +++ b/src/test/java/redis/clients/jedis/benchmark/ShardingBenchmark.java @@ -5,20 +5,17 @@ import java.util.Arrays; import java.util.Calendar; -import redis.clients.jedis.DefaultJedisClientConfig; -import redis.clients.jedis.HostAndPort; -import redis.clients.jedis.HostAndPorts; -import redis.clients.jedis.JedisSharding; +import redis.clients.jedis.*; public class ShardingBenchmark { - private static HostAndPort hnp1 = HostAndPorts.getRedisServers().get(0); - private static HostAndPort hnp2 = HostAndPorts.getRedisServers().get(1); + private static EndpointConfig endpointStandalone0 = HostAndPorts.getRedisEndpoint("standalone0"); + private static EndpointConfig endpointStandalone1 = HostAndPorts.getRedisEndpoint("standalone1"); private static final int TOTAL_OPERATIONS = 100000; public static void main(String[] args) throws UnknownHostException, IOException { - try (JedisSharding jedis = new JedisSharding(Arrays.asList(hnp1, hnp2), - DefaultJedisClientConfig.builder().password("foobared").build())) { + try (JedisSharding jedis = new JedisSharding(Arrays.asList(endpointStandalone0.getHostAndPort(), endpointStandalone1.getHostAndPort()), + endpointStandalone0.getClientConfigBuilder().build())) { long begin = Calendar.getInstance().getTimeInMillis(); 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 1849d26687e..f558a4f686e 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsGenericCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsGenericCommandsTest.java @@ -1082,8 +1082,8 @@ public void testCopyToDbBinary() { private void assertKeyExists(int dstDb, String key, Object expectedValue) { // Cheat and use Jedis, it gives us access to any db. - try (Jedis jedis = new Jedis(nodeInfo)) { - jedis.auth("foobared"); + try (Jedis jedis = new Jedis(endpoint.getHostAndPort())) { + jedis.auth(endpoint.getPassword()); jedis.select(dstDb); assertThat(jedis.get(key), equalTo(expectedValue)); } diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsModulesTestBase.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsModulesTestBase.java index 3bac716fa4a..37c6500aebc 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsModulesTestBase.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsModulesTestBase.java @@ -1,6 +1,7 @@ package redis.clients.jedis.commands.commandobjects; import redis.clients.jedis.HostAndPort; +import redis.clients.jedis.HostAndPorts; import redis.clients.jedis.Protocol; import redis.clients.jedis.RedisProtocol; @@ -9,11 +10,8 @@ */ public abstract class CommandObjectsModulesTestBase extends CommandObjectsTestBase { - private static final String address = - System.getProperty("modulesDocker", Protocol.DEFAULT_HOST + ':' + 6479); - public CommandObjectsModulesTestBase(RedisProtocol protocol) { - super(protocol, HostAndPort.from(address), null); + super(protocol, HostAndPorts.getRedisEndpoint("modules-docker")); } } diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStandaloneTestBase.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStandaloneTestBase.java index fa4a43ea800..128642d2a78 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStandaloneTestBase.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStandaloneTestBase.java @@ -9,7 +9,7 @@ public abstract class CommandObjectsStandaloneTestBase extends CommandObjectsTestBase { public CommandObjectsStandaloneTestBase(RedisProtocol protocol) { - super(protocol, HostAndPorts.getRedisServers().get(0), "foobared"); + super(protocol, HostAndPorts.getRedisEndpoint("standalone0")); } } diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTestBase.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTestBase.java index 5fde2888393..45e0c71ad4f 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTestBase.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTestBase.java @@ -8,11 +8,7 @@ import org.junit.Before; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import redis.clients.jedis.CommandObject; -import redis.clients.jedis.CommandObjects; -import redis.clients.jedis.DefaultJedisClientConfig; -import redis.clients.jedis.HostAndPort; -import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.*; import redis.clients.jedis.args.FlushMode; import redis.clients.jedis.commands.CommandsTestsParameters; import redis.clients.jedis.executors.CommandExecutor; @@ -52,12 +48,7 @@ public static Collection data() { /** * Host and port of the Redis server to connect to. Injected from subclasses. */ - protected final HostAndPort nodeInfo; - - /** - * Password to use when connecting to the Redis server, if needed. Injected from subclasses. - */ - private final String authPassword; + protected final EndpointConfig endpoint; /** * The {@link CommandObjects} to use for the tests. This is the subject-under-test. @@ -70,10 +61,9 @@ public static Collection data() { */ private CommandExecutor commandExecutor; - public CommandObjectsTestBase(RedisProtocol protocol, HostAndPort nodeInfo, String authPassword) { + public CommandObjectsTestBase(RedisProtocol protocol, EndpointConfig endpoint) { this.protocol = protocol; - this.nodeInfo = nodeInfo; - this.authPassword = authPassword; + this.endpoint = endpoint; commandObjects = new CommandObjects(); commandObjects.setProtocol(protocol); } @@ -81,10 +71,11 @@ public CommandObjectsTestBase(RedisProtocol protocol, HostAndPort nodeInfo, Stri @Before public void setUp() { // Configure a default command executor. - DefaultJedisClientConfig clientConfig = DefaultJedisClientConfig.builder() - .protocol(protocol).password(authPassword).build(); + DefaultJedisClientConfig clientConfig = endpoint.getClientConfigBuilder().protocol(protocol) + .build(); - ConnectionProvider connectionProvider = new PooledConnectionProvider(nodeInfo, clientConfig); + ConnectionProvider connectionProvider = new PooledConnectionProvider(endpoint.getHostAndPort(), + clientConfig); commandExecutor = new DefaultCommandExecutor(connectionProvider); diff --git a/src/test/java/redis/clients/jedis/commands/jedis/AccessControlListCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/AccessControlListCommandsTest.java index c8f56bc7eb9..150211383e0 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/AccessControlListCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/AccessControlListCommandsTest.java @@ -46,7 +46,7 @@ public class AccessControlListCommandsTest extends JedisCommandsTestBase { public static void prepare() throws Exception { // Use to check if the ACL test should be ran. ACL are available only in 6.0 and later org.junit.Assume.assumeTrue("Not running ACL test on this version of Redis", - RedisVersionUtil.checkRedisMajorVersionNumber(6)); + RedisVersionUtil.checkRedisMajorVersionNumber(6, endpoint)); } public AccessControlListCommandsTest(RedisProtocol protocol) { @@ -359,7 +359,7 @@ public void aclLogTest() { } // test the ACL Log - jedis.auth("default", "foobared"); + jedis.auth(endpoint.getUsername(), endpoint.getPassword()); List aclEntries = jedis.aclLog(); assertEquals("Number of log messages ", 1, aclEntries.size()); @@ -385,7 +385,7 @@ public void aclLogTest() { } // test the ACL Log - jedis.auth("default", "foobared"); + jedis.auth(endpoint.getUsername(), endpoint.getPassword()); assertEquals("Number of log messages ", 1, jedis.aclLog().size()); assertEquals(10, jedis.aclLog().get(0).getCount()); assertEquals("get", jedis.aclLog().get(0).getObject()); @@ -399,7 +399,7 @@ public void aclLogTest() { } // test the ACL Log - jedis.auth("default", "foobared"); + jedis.auth(endpoint.getUsername(), endpoint.getPassword()); assertEquals("Number of log messages ", 2, jedis.aclLog().size()); assertEquals(1, jedis.aclLog().get(0).getCount()); assertEquals("somekeynotallowed", jedis.aclLog().get(0).getObject()); @@ -418,7 +418,7 @@ public void aclLogTest() { } t.close(); - jedis.auth("default", "foobared"); + jedis.auth(endpoint.getUsername(), endpoint.getPassword()); assertEquals("Number of log messages ", 1, jedis.aclLog().size()); assertEquals(1, jedis.aclLog().get(0).getCount()); assertEquals("multi", jedis.aclLog().get(0).getContext()); @@ -439,7 +439,7 @@ public void aclLogTest() { } catch (JedisAccessControlException e) { } - jedis.auth("default", "foobared"); + jedis.auth(endpoint.getUsername(), endpoint.getPassword()); assertEquals("Number of log messages ", 3, jedis.aclLog().size()); assertEquals("Number of log messages ", 2, jedis.aclLog(2).size()); diff --git a/src/test/java/redis/clients/jedis/commands/jedis/AllKindOfValuesCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/AllKindOfValuesCommandsTest.java index e7381a7440b..868195961ea 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/AllKindOfValuesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/AllKindOfValuesCommandsTest.java @@ -21,17 +21,12 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import redis.clients.jedis.HostAndPort; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.Transaction; +import redis.clients.jedis.*; import redis.clients.jedis.args.ExpiryOption; import redis.clients.jedis.params.ScanParams; import redis.clients.jedis.resps.ScanResult; -import redis.clients.jedis.StreamEntryID; import redis.clients.jedis.args.FlushMode; import redis.clients.jedis.params.RestoreParams; -import redis.clients.jedis.HostAndPorts; -import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.util.SafeEncoder; import redis.clients.jedis.exceptions.JedisDataException; import redis.clients.jedis.params.SetParams; @@ -57,7 +52,7 @@ public class AllKindOfValuesCommandsTest extends JedisCommandsTestBase { final byte[] bex = { 0x65, 0x78 }; final int expireSeconds = 2; - private static final HostAndPort lfuHnp = HostAndPorts.getRedisServers().get(7); + private static final EndpointConfig lfuEndpoint = HostAndPorts.getRedisEndpoint("standalone7-with-lfu-policy"); public AllKindOfValuesCommandsTest(RedisProtocol redisProtocol) { super(redisProtocol); @@ -604,8 +599,8 @@ public void dumpAndRestore() { @Test public void restoreParams() { // take a separate instance - Jedis jedis2 = new Jedis(hnp.getHost(), 6380, 500); - jedis2.auth("foobared"); + Jedis jedis2 = new Jedis(endpoint.getHost(), endpoint.getPort(), 500); + jedis2.auth(endpoint.getPassword()); jedis2.flushAll(); jedis2.set("foo", "bar"); @@ -637,7 +632,7 @@ public void restoreParams() { assertEquals(1000, jedis2.objectIdletime("bar1").longValue()); jedis2.close(); - Jedis lfuJedis = new Jedis(lfuHnp.getHost(), lfuHnp.getPort(), 500); + Jedis lfuJedis = new Jedis(lfuEndpoint.getHostAndPort(), lfuEndpoint.getClientConfigBuilder().timeoutMillis(500).build());; lfuJedis.restore("bar1", 1000, serialized, RestoreParams.restoreParams().replace().frequency(90)); assertEquals(90, lfuJedis.objectFreq("bar1").longValue()); lfuJedis.close(); @@ -1146,7 +1141,7 @@ public void reset() { assertEquals("NOAUTH Authentication required.", ex1.getMessage()); // multi reset - jedis.auth("foobared"); + jedis.auth(endpoint.getPassword()); jedis.set(counter, "1"); Transaction trans = jedis.multi(); @@ -1156,7 +1151,7 @@ public void reset() { Exception ex2 = assertThrows(JedisDataException.class, trans::exec); assertEquals("EXECABORT Transaction discarded because of: NOAUTH Authentication required.", ex2.getMessage()); - jedis.auth("foobared"); + jedis.auth(endpoint.getPassword()); assertEquals("1", jedis.get(counter)); } } diff --git a/src/test/java/redis/clients/jedis/commands/jedis/ClientCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/ClientCommandsTest.java index 2a4657ecd5a..1b221cfc555 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/ClientCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/ClientCommandsTest.java @@ -21,7 +21,6 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import redis.clients.jedis.DefaultJedisClientConfig; import redis.clients.jedis.Jedis; import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.args.ClientAttributeOption; @@ -47,8 +46,8 @@ public ClientCommandsTest(RedisProtocol protocol) { @Override public void setUp() throws Exception { super.setUp(); - client = new Jedis(hnp.getHost(), hnp.getPort(), 500); - client.auth("foobared"); + client = new Jedis(endpoint.getHost(), endpoint.getPort(), 500); + client.auth(endpoint.getPassword()); client.clientSetname(clientName); } @@ -97,8 +96,8 @@ public void clientId() { @Test public void clientIdmultipleConnection() { - try (Jedis client2 = new Jedis(hnp.getHost(), hnp.getPort(), 500)) { - client2.auth("foobared"); + try (Jedis client2 = new Jedis(endpoint.getHost(), endpoint.getPort(), 500)) { + client2.auth(endpoint.getPassword()); client2.clientSetname("fancy_jedis_another_name"); // client-id is monotonically increasing @@ -111,7 +110,7 @@ public void clientIdReconnect() { long clientIdInitial = client.clientId(); client.disconnect(); client.connect(); - client.auth("foobared"); + client.auth(endpoint.getPassword()); long clientIdAfterReconnect = client.clientId(); assertTrue(clientIdInitial < clientIdAfterReconnect); @@ -233,7 +232,7 @@ public void killAddrIpPort() { @Test public void killUser() { client.aclSetUser("test_kill", "on", "+acl", ">password1"); - try (Jedis client2 = new Jedis(hnp.getHost(), hnp.getPort(), 500)) { + try (Jedis client2 = new Jedis(endpoint.getHost(), endpoint.getPort(), 500)) { client2.auth("test_kill", "password1"); assertEquals(1, jedis.clientKill(new ClientKillParams().user("test_kill"))); @@ -250,8 +249,8 @@ public void killMaxAge() throws InterruptedException { // sleep twice the maxAge, to be sure Thread.sleep(maxAge * 2 * 1000); - try (Jedis client2 = new Jedis(hnp.getHost(), hnp.getPort(), 500)) { - client2.auth("foobared"); + try (Jedis client2 = new Jedis(endpoint.getHost(), endpoint.getPort(), 500)) { + client2.auth(endpoint.getPassword()); long killedClients = jedis.clientKill(new ClientKillParams().maxAge(maxAge)); @@ -300,8 +299,8 @@ public void trackingInfo() { @Test public void trackingInfoResp3() { - Jedis clientResp3 = new Jedis(hnp, DefaultJedisClientConfig.builder() - .protocol(RedisProtocol.RESP3).password("foobared").build()); + Jedis clientResp3 = new Jedis(endpoint.getHostAndPort(), endpoint.getClientConfigBuilder() + .protocol(RedisProtocol.RESP3).build()); TrackingInfo trackingInfo = clientResp3.clientTrackingInfo(); assertEquals(1, trackingInfo.getFlags().size()); diff --git a/src/test/java/redis/clients/jedis/commands/jedis/ControlCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/ControlCommandsTest.java index 0287095e4c1..4c9059f8d03 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/ControlCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/ControlCommandsTest.java @@ -27,15 +27,10 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import redis.clients.jedis.DefaultJedisClientConfig; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.JedisMonitor; -import redis.clients.jedis.Protocol; -import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.*; import redis.clients.jedis.args.ClientPauseMode; import redis.clients.jedis.args.LatencyEvent; import redis.clients.jedis.exceptions.JedisDataException; -import redis.clients.jedis.HostAndPorts; import redis.clients.jedis.params.CommandListFilterByParams; import redis.clients.jedis.params.LolwutParams; import redis.clients.jedis.resps.CommandDocument; @@ -129,8 +124,10 @@ public void readwrite() { @Test public void roleMaster() { - try (Jedis master = new Jedis(HostAndPorts.getRedisServers().get(0), - DefaultJedisClientConfig.builder().password("foobared").build())) { + EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone0"); + + try (Jedis master = new Jedis(endpoint.getHostAndPort(), + endpoint.getClientConfigBuilder().build())) { List role = master.role(); assertEquals("master", role.get(0)); @@ -147,19 +144,23 @@ public void roleMaster() { @Test public void roleSlave() { - try (Jedis slave = new Jedis(HostAndPorts.getRedisServers().get(4), - DefaultJedisClientConfig.builder().password("foobared").build())) { + EndpointConfig primaryEndpoint = HostAndPorts.getRedisEndpoint("standalone0"); + EndpointConfig secondaryEndpoint = HostAndPorts.getRedisEndpoint( + "standalone4-replica-of-standalone1"); + + try (Jedis slave = new Jedis(secondaryEndpoint.getHostAndPort(), + secondaryEndpoint.getClientConfigBuilder().build())) { List role = slave.role(); assertEquals("slave", role.get(0)); - assertEquals((long) HostAndPorts.getRedisServers().get(0).getPort(), role.get(2)); + assertEquals((long) primaryEndpoint.getPort(), role.get(2)); assertEquals("connected", role.get(3)); assertTrue(role.get(4) instanceof Long); // binary List brole = slave.roleBinary(); assertArrayEquals("slave".getBytes(), (byte[]) brole.get(0)); - assertEquals((long) HostAndPorts.getRedisServers().get(0).getPort(), brole.get(2)); + assertEquals((long) primaryEndpoint.getPort(), brole.get(2)); assertArrayEquals("connected".getBytes(), (byte[]) brole.get(3)); assertTrue(brole.get(4) instanceof Long); } @@ -192,8 +193,8 @@ public void run() { Thread.sleep(100); } catch (InterruptedException e) { } - Jedis j = new Jedis(); - j.auth("foobared"); + Jedis j = new Jedis(endpoint.getHostAndPort()); + j.auth(endpoint.getPassword()); for (int i = 0; i < 5; i++) { j.incr("foobared"); } diff --git a/src/test/java/redis/clients/jedis/commands/jedis/FailoverCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/FailoverCommandsTest.java index 20ec8009cd4..cd5bd5b025e 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/FailoverCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/FailoverCommandsTest.java @@ -6,6 +6,7 @@ import org.junit.Before; import org.junit.Test; +import redis.clients.jedis.EndpointConfig; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.Jedis; import redis.clients.jedis.exceptions.JedisDataException; @@ -16,8 +17,8 @@ public class FailoverCommandsTest { private static final int INVALID_PORT = 6000; - private static final HostAndPort node1 = HostAndPorts.getRedisServers().get(9); - private static final HostAndPort node2 = HostAndPorts.getRedisServers().get(10); + private static final EndpointConfig node1 = HostAndPorts.getRedisEndpoint("standalone9"); + private static final EndpointConfig node2 = HostAndPorts.getRedisEndpoint("standalone10-replica-of-standalone9"); private HostAndPort masterAddress; private HostAndPort replicaAddress; @@ -25,19 +26,19 @@ public class FailoverCommandsTest { @Before public void prepare() { String role1, role2; - try (Jedis jedis1 = new Jedis(node1)) { + try (Jedis jedis1 = new Jedis(node1.getHostAndPort(), node1.getClientConfigBuilder().build())) { role1 = (String) jedis1.role().get(0); } - try (Jedis jedis2 = new Jedis(node2)) { + try (Jedis jedis2 = new Jedis(node2.getHostAndPort(), node2.getClientConfigBuilder().build())) { role2 = (String) jedis2.role().get(0); } if ("master".equals(role1) && "slave".equals(role2)) { - masterAddress = node1; - replicaAddress = node2; + masterAddress = node1.getHostAndPort(); + replicaAddress = node2.getHostAndPort(); } else if ("master".equals(role2) && "slave".equals(role1)) { - masterAddress = node2; - replicaAddress = node1; + masterAddress = node2.getHostAndPort(); + replicaAddress = node1.getHostAndPort(); } else { fail(); } diff --git a/src/test/java/redis/clients/jedis/commands/jedis/JedisCommandsTestBase.java b/src/test/java/redis/clients/jedis/commands/jedis/JedisCommandsTestBase.java index 1d40a22b5fc..cec36a0866c 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/JedisCommandsTestBase.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/JedisCommandsTestBase.java @@ -5,11 +5,7 @@ import org.junit.After; import org.junit.Before; import org.junit.runners.Parameterized.Parameters; -import redis.clients.jedis.DefaultJedisClientConfig; -import redis.clients.jedis.HostAndPort; -import redis.clients.jedis.HostAndPorts; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.*; import redis.clients.jedis.commands.CommandsTestsParameters; public abstract class JedisCommandsTestBase { @@ -25,7 +21,7 @@ public static Collection data() { return CommandsTestsParameters.respVersions(); } - protected static final HostAndPort hnp = HostAndPorts.getRedisServers().get(0); + protected static final EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone0"); protected final RedisProtocol protocol; @@ -46,9 +42,8 @@ public JedisCommandsTestBase(RedisProtocol protocol) { @Before public void setUp() throws Exception { -// jedis = new Jedis(hnp, DefaultJedisClientConfig.builder().timeoutMillis(500).password("foobared").build()); - jedis = new Jedis(hnp, DefaultJedisClientConfig.builder() - .protocol(protocol).timeoutMillis(500).password("foobared").build()); + jedis = new Jedis(endpoint.getHostAndPort(), endpoint.getClientConfigBuilder() + .protocol(protocol).timeoutMillis(500).build()); jedis.flushAll(); } @@ -58,8 +53,7 @@ public void tearDown() throws Exception { } protected Jedis createJedis() { -// return new Jedis(hnp, DefaultJedisClientConfig.builder().password("foobared").build()); - return new Jedis(hnp, DefaultJedisClientConfig.builder() - .protocol(protocol).password("foobared").build()); + return new Jedis(endpoint.getHostAndPort(), endpoint.getClientConfigBuilder() + .protocol(protocol).build()); } } diff --git a/src/test/java/redis/clients/jedis/commands/jedis/MigrateTest.java b/src/test/java/redis/clients/jedis/commands/jedis/MigrateTest.java index 529d64ebbf6..9d44302e373 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/MigrateTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/MigrateTest.java @@ -12,9 +12,7 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.Protocol; -import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.*; import redis.clients.jedis.exceptions.JedisDataException; import redis.clients.jedis.params.MigrateParams; @@ -32,9 +30,18 @@ public class MigrateTest extends JedisCommandsTestBase { private Jedis dest; private Jedis destAuth; - private static final String host = hnp.getHost(); - private static final int port = 6386; - private static final int portAuth = hnp.getPort() + 1; + + private static final EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone0-acl"); + + private static final EndpointConfig destEndpoint = HostAndPorts.getRedisEndpoint( + "standalone7-with-lfu-policy"); + + private static final EndpointConfig destEndpointWithAuth = HostAndPorts.getRedisEndpoint( + "standalone1"); + + private static final String host = destEndpoint.getHost(); + private static final int port = destEndpoint.getPort(); + private static final int portAuth = destEndpointWithAuth.getPort(); private static final int db = 2; private static final int dbAuth = 3; private static final int timeout = Protocol.DEFAULT_TIMEOUT; @@ -52,8 +59,8 @@ public void setUp() throws Exception { dest.flushAll(); dest.select(db); - destAuth = new Jedis(host, portAuth, 500); - destAuth.auth("foobared"); + destAuth = new Jedis(destEndpointWithAuth.getHostAndPort(), + destEndpointWithAuth.getClientConfigBuilder().build()); destAuth.flushAll(); destAuth.select(dbAuth); } @@ -150,14 +157,14 @@ public void migrateCopyReplace() { @Test public void migrateAuth() { jedis.set("foo", "bar"); - assertEquals("OK", - jedis.migrate(host, portAuth, dbAuth, timeout, new MigrateParams().auth("foobared"), "foo")); + assertEquals("OK", jedis.migrate(host, portAuth, dbAuth, timeout, + new MigrateParams().auth(destEndpointWithAuth.getPassword()), "foo")); assertEquals("bar", destAuth.get("foo")); assertNull(jedis.get("foo")); jedis.set(bfoo, bbar); - assertEquals("OK", - jedis.migrate(host, portAuth, dbAuth, timeout, new MigrateParams().auth("foobared"), bfoo)); + assertEquals("OK", jedis.migrate(host, portAuth, dbAuth, timeout, + new MigrateParams().auth(destEndpointWithAuth.getPassword()), bfoo)); assertArrayEquals(bbar, destAuth.get(bfoo)); assertNull(jedis.get(bfoo)); } @@ -165,15 +172,15 @@ public void migrateAuth() { @Test public void migrateAuth2() { destAuth.set("foo", "bar"); - assertEquals("OK", destAuth.migrate(host, hnp.getPort(), 0, timeout, - new MigrateParams().auth2("acljedis", "fizzbuzz"), "foo")); + assertEquals("OK", destAuth.migrate(host, endpoint.getPort(), 0, timeout, + new MigrateParams().auth2(endpoint.getUsername(), endpoint.getPassword()), "foo")); assertEquals("bar", jedis.get("foo")); assertNull(destAuth.get("foo")); // binary dest.set(bfoo1, bbar1); - assertEquals("OK", dest.migrate(host, hnp.getPort(), 0, timeout, - new MigrateParams().auth2("acljedis", "fizzbuzz"), bfoo1)); + assertEquals("OK", dest.migrate(host, endpoint.getPort(), 0, timeout, + new MigrateParams().auth2(endpoint.getUsername(), endpoint.getPassword()), bfoo1)); assertArrayEquals(bbar1, jedis.get(bfoo1)); assertNull(dest.get(bfoo1)); } @@ -182,10 +189,8 @@ public void migrateAuth2() { public void migrateCopyReplaceAuth() { jedis.set("foo", "bar1"); destAuth.set("foo", "bar2"); - assertEquals( - "OK", - jedis.migrate(host, portAuth, dbAuth, timeout, - new MigrateParams().copy().replace().auth("foobared"), "foo")); + assertEquals("OK", jedis.migrate(host, portAuth, dbAuth, timeout, + new MigrateParams().copy().replace().auth(destEndpointWithAuth.getPassword()), "foo")); assertEquals("bar1", destAuth.get("foo")); assertEquals("bar1", jedis.get("foo")); @@ -194,7 +199,7 @@ public void migrateCopyReplaceAuth() { assertEquals( "OK", jedis.migrate(host, portAuth, dbAuth, timeout, - new MigrateParams().copy().replace().auth("foobared"), bfoo)); + new MigrateParams().copy().replace().auth(destEndpointWithAuth.getPassword()), bfoo)); assertArrayEquals(bbar1, destAuth.get(bfoo)); assertArrayEquals(bbar1, jedis.get(bfoo)); } diff --git a/src/test/java/redis/clients/jedis/commands/jedis/ObjectCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/ObjectCommandsTest.java index 0f4cf70b150..a62cbea52a3 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/ObjectCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/ObjectCommandsTest.java @@ -13,11 +13,8 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import redis.clients.jedis.HostAndPort; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.*; import redis.clients.jedis.exceptions.JedisDataException; -import redis.clients.jedis.HostAndPorts; import redis.clients.jedis.util.SafeEncoder; @RunWith(Parameterized.class) @@ -25,7 +22,7 @@ public class ObjectCommandsTest extends JedisCommandsTestBase { private final String key = "mylist"; private final byte[] binaryKey = SafeEncoder.encode(key); - private final HostAndPort lfuHnp = HostAndPorts.getRedisServers().get(7); + private final EndpointConfig lfuEndpoint = HostAndPorts.getRedisEndpoint("standalone7-with-lfu-policy"); private Jedis lfuJedis; public ObjectCommandsTest(RedisProtocol protocol) { @@ -37,7 +34,8 @@ public ObjectCommandsTest(RedisProtocol protocol) { public void setUp() throws Exception { super.setUp(); - lfuJedis = new Jedis(lfuHnp.getHost(), lfuHnp.getPort(), 500); + lfuJedis = new Jedis(lfuEndpoint.getHostAndPort(), + lfuEndpoint.getClientConfigBuilder().build()); lfuJedis.connect(); lfuJedis.flushAll(); } diff --git a/src/test/java/redis/clients/jedis/commands/jedis/SentinelCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/SentinelCommandsTest.java index babaf28a10d..48fa43e4e6e 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/SentinelCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/SentinelCommandsTest.java @@ -22,7 +22,9 @@ public class SentinelCommandsTest { protected static final String MASTER_NAME = "mymaster"; protected static final List nodes = - Arrays.asList(HostAndPorts.getRedisServers().get(2), HostAndPorts.getRedisServers().get(3)); + Arrays.asList( + HostAndPorts.getRedisEndpoint("standalone2-primary").getHostAndPort(), + HostAndPorts.getRedisEndpoint("standalone3-replica-of-standalone2").getHostAndPort()); protected static final Set nodesPorts = nodes.stream() .map(HostAndPort::getPort).map(String::valueOf).collect(Collectors.toSet()); diff --git a/src/test/java/redis/clients/jedis/commands/jedis/TransactionCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/TransactionCommandsTest.java index 5130552009b..f7ab13df25b 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/TransactionCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/TransactionCommandsTest.java @@ -20,7 +20,6 @@ import org.mockito.MockedStatic; import org.mockito.Mockito; -import redis.clients.jedis.DefaultJedisClientConfig; import redis.clients.jedis.Jedis; import redis.clients.jedis.Protocol; import redis.clients.jedis.RedisProtocol; @@ -50,7 +49,8 @@ public TransactionCommandsTest(RedisProtocol protocol) { public void setUp() throws Exception { super.setUp(); - nj = new Jedis(hnp, DefaultJedisClientConfig.builder().timeoutMillis(500).password("foobared").build()); + nj = new Jedis(endpoint.getHostAndPort(), + endpoint.getClientConfigBuilder().timeoutMillis(500).build()); } @After @@ -348,7 +348,6 @@ public void testResetStateWhenInWatch() { @Test public void testResetStateWithFullyExecutedTransaction() { Jedis jedis2 = createJedis(); - jedis2.auth("foobared"); Transaction t = jedis2.multi(); t.set("mykey", "foo"); @@ -365,8 +364,8 @@ public void testResetStateWithFullyExecutedTransaction() { @Test public void testCloseable() { // we need to test with fresh instance of Jedis - Jedis jedis2 = new Jedis(hnp.getHost(), hnp.getPort(), 500); - jedis2.auth("foobared"); + Jedis jedis2 = new Jedis(endpoint.getHostAndPort(), + endpoint.getClientConfigBuilder().timeoutMillis(500).build());; Transaction transaction = jedis2.multi(); transaction.set("a", "1"); diff --git a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledCommandsTestHelper.java b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledCommandsTestHelper.java index 82c84f8890c..ab69c57f4e8 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledCommandsTestHelper.java +++ b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledCommandsTestHelper.java @@ -1,24 +1,19 @@ package redis.clients.jedis.commands.unified.pooled; -import redis.clients.jedis.DefaultJedisClientConfig; -import redis.clients.jedis.HostAndPort; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.JedisPooled; -import redis.clients.jedis.HostAndPorts; -import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.*; public class PooledCommandsTestHelper { - private static final HostAndPort nodeInfo = HostAndPorts.getRedisServers().get(0); + private static final EndpointConfig nodeInfo = HostAndPorts.getRedisEndpoint("standalone0"); public static JedisPooled getPooled(RedisProtocol redisProtocol) { - return new JedisPooled(nodeInfo, DefaultJedisClientConfig.builder() - .protocol(redisProtocol).password("foobared").build()); + return new JedisPooled(nodeInfo.getHostAndPort(), nodeInfo.getClientConfigBuilder() + .protocol(redisProtocol).build()); } public static void clearData() { - try (Jedis node = new Jedis(nodeInfo)) { - node.auth("foobared"); + try (Jedis node = new Jedis(nodeInfo.getHostAndPort())) { + node.auth(nodeInfo.getPassword()); node.flushAll(); } } diff --git a/src/test/java/redis/clients/jedis/misc/AutomaticFailoverTest.java b/src/test/java/redis/clients/jedis/misc/AutomaticFailoverTest.java index c6b25d764b0..46c40fae6a6 100644 --- a/src/test/java/redis/clients/jedis/misc/AutomaticFailoverTest.java +++ b/src/test/java/redis/clients/jedis/misc/AutomaticFailoverTest.java @@ -16,15 +16,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import redis.clients.jedis.AbstractPipeline; -import redis.clients.jedis.AbstractTransaction; -import redis.clients.jedis.DefaultJedisClientConfig; -import redis.clients.jedis.HostAndPort; -import redis.clients.jedis.HostAndPorts; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.JedisClientConfig; -import redis.clients.jedis.MultiClusterClientConfig; -import redis.clients.jedis.UnifiedJedis; +import redis.clients.jedis.*; import redis.clients.jedis.exceptions.JedisAccessControlException; import redis.clients.jedis.exceptions.JedisConnectionException; import redis.clients.jedis.providers.MultiClusterPooledConnectionProvider; @@ -34,9 +26,9 @@ public class AutomaticFailoverTest { private static final Logger log = LoggerFactory.getLogger(AutomaticFailoverTest.class); - private final HostAndPort hostPort_1 = new HostAndPort(HostAndPorts.getRedisServers().get(0).getHost(), 6378); - private final HostAndPort hostPort_1_2 = HostAndPorts.getRedisServers().get(0); - private final HostAndPort hostPort_2 = HostAndPorts.getRedisServers().get(7); + private final HostAndPort hostPortWithFailure = new HostAndPort(HostAndPorts.getRedisEndpoint("standalone0").getHost(), 6378); + private final EndpointConfig endpointForAuthFailure = HostAndPorts.getRedisEndpoint("standalone0"); + private final EndpointConfig workingEndpoint = HostAndPorts.getRedisEndpoint("standalone7-with-lfu-policy"); private final JedisClientConfig clientConfig = DefaultJedisClientConfig.builder().build(); @@ -51,7 +43,8 @@ private List getClusterConfigs( @Before public void setUp() { - jedis2 = new Jedis(hostPort_2, clientConfig); + jedis2 = new Jedis(workingEndpoint.getHostAndPort(), + workingEndpoint.getClientConfigBuilder().build()); jedis2.flushAll(); } @@ -63,7 +56,7 @@ public void cleanUp() { @Test public void pipelineWithSwitch() { MultiClusterPooledConnectionProvider provider = new MultiClusterPooledConnectionProvider( - new MultiClusterClientConfig.Builder(getClusterConfigs(clientConfig, hostPort_1, hostPort_2)).build()); + new MultiClusterClientConfig.Builder(getClusterConfigs(clientConfig, hostPortWithFailure, workingEndpoint.getHostAndPort())).build()); try (UnifiedJedis client = new UnifiedJedis(provider)) { AbstractPipeline pipe = client.pipelined(); @@ -80,7 +73,7 @@ public void pipelineWithSwitch() { @Test public void transactionWithSwitch() { MultiClusterPooledConnectionProvider provider = new MultiClusterPooledConnectionProvider( - new MultiClusterClientConfig.Builder(getClusterConfigs(clientConfig, hostPort_1, hostPort_2)).build()); + new MultiClusterClientConfig.Builder(getClusterConfigs(clientConfig, hostPortWithFailure, workingEndpoint.getHostAndPort())).build()); try (UnifiedJedis client = new UnifiedJedis(provider)) { AbstractTransaction tx = client.multi(); @@ -100,7 +93,7 @@ public void commandFailover() { int slidingWindowSize = 10; MultiClusterClientConfig.Builder builder = new MultiClusterClientConfig.Builder( - getClusterConfigs(clientConfig, hostPort_1, hostPort_2)) + getClusterConfigs(clientConfig, hostPortWithFailure, workingEndpoint.getHostAndPort())) .circuitBreakerSlidingWindowMinCalls(slidingWindowMinCalls) .circuitBreakerSlidingWindowSize(slidingWindowSize); @@ -138,7 +131,7 @@ public void pipelineFailover() { int slidingWindowSize = 10; MultiClusterClientConfig.Builder builder = new MultiClusterClientConfig.Builder( - getClusterConfigs(clientConfig, hostPort_1, hostPort_2)) + getClusterConfigs(clientConfig, hostPortWithFailure, workingEndpoint.getHostAndPort())) .circuitBreakerSlidingWindowMinCalls(slidingWindowMinCalls) .circuitBreakerSlidingWindowSize(slidingWindowSize) .fallbackExceptionList(Arrays.asList(JedisConnectionException.class)); @@ -171,7 +164,7 @@ public void failoverFromAuthError() { int slidingWindowSize = 10; MultiClusterClientConfig.Builder builder = new MultiClusterClientConfig.Builder( - getClusterConfigs(clientConfig, hostPort_1_2, hostPort_2)) + getClusterConfigs(clientConfig, endpointForAuthFailure.getHostAndPort(), workingEndpoint.getHostAndPort())) .circuitBreakerSlidingWindowMinCalls(slidingWindowMinCalls) .circuitBreakerSlidingWindowSize(slidingWindowSize) .fallbackExceptionList(Arrays.asList(JedisAccessControlException.class)); diff --git a/src/test/java/redis/clients/jedis/misc/ClusterInitErrorTest.java b/src/test/java/redis/clients/jedis/misc/ClusterInitErrorTest.java index 619c08cead5..76998dc8086 100644 --- a/src/test/java/redis/clients/jedis/misc/ClusterInitErrorTest.java +++ b/src/test/java/redis/clients/jedis/misc/ClusterInitErrorTest.java @@ -4,7 +4,7 @@ import org.junit.After; import org.junit.Assert; import org.junit.Test; -import redis.clients.jedis.DefaultJedisClientConfig; +import redis.clients.jedis.EndpointConfig; import redis.clients.jedis.HostAndPorts; import redis.clients.jedis.JedisCluster; import redis.clients.jedis.exceptions.JedisClusterOperationException; @@ -21,9 +21,10 @@ public void cleanUp() { @Test(expected = JedisClusterOperationException.class) public void initError() { Assert.assertNull(System.getProperty(INIT_NO_ERROR_PROPERTY)); + EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone0"); try (JedisCluster cluster = new JedisCluster( - Collections.singleton(HostAndPorts.getRedisServers().get(0)), - DefaultJedisClientConfig.builder().password("foobared").build())) { + Collections.singleton(endpoint.getHostAndPort()), + endpoint.getClientConfigBuilder().build())) { throw new IllegalStateException("should not reach here"); } } @@ -31,9 +32,10 @@ public void initError() { @Test public void initNoError() { System.setProperty(INIT_NO_ERROR_PROPERTY, ""); + EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone0"); try (JedisCluster cluster = new JedisCluster( - Collections.singleton(HostAndPorts.getRedisServers().get(0)), - DefaultJedisClientConfig.builder().password("foobared").build())) { + Collections.singleton(endpoint.getHostAndPort()), + endpoint.getClientConfigBuilder().build())) { Assert.assertThrows(JedisClusterOperationException.class, () -> cluster.get("foo")); } } diff --git a/src/test/java/redis/clients/jedis/providers/MultiClusterPooledConnectionProviderTest.java b/src/test/java/redis/clients/jedis/providers/MultiClusterPooledConnectionProviderTest.java index d094d26b4f5..1f2c7576f61 100644 --- a/src/test/java/redis/clients/jedis/providers/MultiClusterPooledConnectionProviderTest.java +++ b/src/test/java/redis/clients/jedis/providers/MultiClusterPooledConnectionProviderTest.java @@ -17,8 +17,8 @@ */ public class MultiClusterPooledConnectionProviderTest { - private final HostAndPort hostAndPort1 = HostAndPorts.getRedisServers().get(0); - private final HostAndPort hostAndPort2 = HostAndPorts.getRedisServers().get(1); + private final EndpointConfig endpointStandalone0 = HostAndPorts.getRedisEndpoint("standalone0"); + private final EndpointConfig endpointStandalone1 = HostAndPorts.getRedisEndpoint("standalone1"); private MultiClusterPooledConnectionProvider provider; @@ -26,8 +26,8 @@ public class MultiClusterPooledConnectionProviderTest { public void setUp() { ClusterConfig[] clusterConfigs = new ClusterConfig[2]; - clusterConfigs[0] = new ClusterConfig(hostAndPort1, DefaultJedisClientConfig.builder().build()); - clusterConfigs[1] = new ClusterConfig(hostAndPort2, DefaultJedisClientConfig.builder().build()); + clusterConfigs[0] = new ClusterConfig(endpointStandalone0.getHostAndPort(), endpointStandalone0.getClientConfigBuilder().build()); + clusterConfigs[1] = new ClusterConfig(endpointStandalone1.getHostAndPort(), endpointStandalone0.getClientConfigBuilder().build()); provider = new MultiClusterPooledConnectionProvider(new MultiClusterClientConfig.Builder(clusterConfigs).build()); } @@ -138,8 +138,8 @@ public void testConnectionPoolConfigApplied() { poolConfig.setMaxIdle(4); poolConfig.setMinIdle(1); ClusterConfig[] clusterConfigs = new ClusterConfig[2]; - clusterConfigs[0] = new ClusterConfig(hostAndPort1, DefaultJedisClientConfig.builder().build(), poolConfig); - clusterConfigs[1] = new ClusterConfig(hostAndPort2, DefaultJedisClientConfig.builder().build(), poolConfig); + clusterConfigs[0] = new ClusterConfig(endpointStandalone0.getHostAndPort(), endpointStandalone0.getClientConfigBuilder().build(), poolConfig); + clusterConfigs[1] = new ClusterConfig(endpointStandalone1.getHostAndPort(), endpointStandalone0.getClientConfigBuilder().build(), poolConfig); try (MultiClusterPooledConnectionProvider customProvider = new MultiClusterPooledConnectionProvider( new MultiClusterClientConfig.Builder(clusterConfigs).build())) { MultiClusterPooledConnectionProvider.Cluster activeCluster = customProvider.getCluster(); diff --git a/src/test/java/redis/clients/jedis/util/RedisVersionUtil.java b/src/test/java/redis/clients/jedis/util/RedisVersionUtil.java index 8b125ca7d38..fed3055b4f5 100644 --- a/src/test/java/redis/clients/jedis/util/RedisVersionUtil.java +++ b/src/test/java/redis/clients/jedis/util/RedisVersionUtil.java @@ -1,14 +1,15 @@ package redis.clients.jedis.util; +import redis.clients.jedis.EndpointConfig; import redis.clients.jedis.Jedis; public class RedisVersionUtil { - public static Integer getRedisMajorVersionNumber() { + public static Integer getRedisMajorVersionNumber(EndpointConfig endpoint) { String completeVersion = null; - try (Jedis jedis = new Jedis()) { - jedis.auth("foobared"); + try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), + endpoint.getClientConfigBuilder().build())) { String info = jedis.info("server"); String[] splitted = info.split("\\s+|:"); for (int i = 0; i < splitted.length; i++) { @@ -25,7 +26,7 @@ public static Integer getRedisMajorVersionNumber() { return Integer.parseInt(completeVersion.substring(0, completeVersion.indexOf("."))); } - public static boolean checkRedisMajorVersionNumber(int minVersion) { - return getRedisMajorVersionNumber() >= minVersion; + public static boolean checkRedisMajorVersionNumber(int minVersion, EndpointConfig endpoint) { + return getRedisMajorVersionNumber(endpoint) >= minVersion; } } diff --git a/src/test/resources/endpoints.json b/src/test/resources/endpoints.json new file mode 100644 index 00000000000..c1d905bfb88 --- /dev/null +++ b/src/test/resources/endpoints.json @@ -0,0 +1,107 @@ +{ + "standalone0": { + "password": "foobared", + "tls": false, + "endpoints": [ + "redis://localhost:6379" + ] + }, + "standalone0-tls": { + "username": "default", + "password": "foobared", + "tls": true, + "endpoints": [ + "rediss://localhost:6390" + ] + }, + "standalone0-acl": { + "username": "acljedis", + "password": "fizzbuzz", + "tls": false, + "endpoints": [ + "redis://localhost:6379" + ] + }, + "standalone0-acl-tls": { + "username": "acljedis", + "password": "fizzbuzz", + "tls": true, + "endpoints": [ + "rediss://localhost:6390" + ] + }, + "standalone1": { + "username": "default", + "password": "foobared", + "tls": false, + "endpoints": [ + "redis://localhost:6380" + ] + }, + "standalone2-primary": { + "username": "default", + "password": "foobared", + "tls": false, + "endpoints": [ + "redis://localhost:6381" + ] + }, + "standalone3-replica-of-standalone2": { + "username": "default", + "password": "foobared", + "tls": false, + "endpoints": [ + "redis://localhost:6382" + ] + }, + "standalone4-replica-of-standalone1": { + "username": "default", + "password": "foobared", + "tls": false, + "endpoints": [ + "redis://localhost:6383" + ] + }, + "standalone5-primary": { + "username": "default", + "password": "foobared", + "tls": false, + "endpoints": [ + "redis://localhost:6384" + ] + }, + "standalone6-replica-of-standalone5": { + "username": "default", + "password": "foobared", + "tls": false, + "endpoints": [ + "redis://localhost:6385" + ] + }, + "standalone7-with-lfu-policy": { + "username": "default", + "password": "foobared", + "tls": false, + "endpoints": [ + "redis://localhost:6386" + ] + }, + "standalone9": { + "tls": false, + "endpoints": [ + "redis://localhost:6388" + ] + }, + "standalone10-replica-of-standalone9": { + "tls": false, + "endpoints": [ + "redis://localhost:6389" + ] + }, + "modules-docker": { + "tls": false, + "endpoints": [ + "redis://localhost:6479" + ] + } +} \ No newline at end of file From e5977661e253fdeca74891ccf6b8fe63e1423c1f Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Thu, 6 Jun 2024 20:39:03 +0600 Subject: [PATCH 20/51] Support Hash field expiration (#3826) * Support Hash field expiration (Strings) * Support Hash field expiration (byte[]s) * Test new hash commands in CommandObjects * Hash expiration is now supported with listpack * Address constant FIELDS argument in Hash field expiration commands * Fix FIELDS place * Back to using Redis unstable branch * Modify HFE tests due to changes in server --- .../redis/clients/jedis/CommandObjects.java | 138 +++++- src/main/java/redis/clients/jedis/Jedis.java | 156 +++++++ .../redis/clients/jedis/PipeliningBase.java | 130 ++++++ .../java/redis/clients/jedis/Protocol.java | 5 +- .../redis/clients/jedis/UnifiedJedis.java | 130 ++++++ .../jedis/commands/HashBinaryCommands.java | 134 ++++++ .../clients/jedis/commands/HashCommands.java | 135 ++++++ .../commands/HashPipelineBinaryCommands.java | 26 ++ .../jedis/commands/HashPipelineCommands.java | 27 ++ .../CommandObjectsHashCommandsTest.java | 170 +++++++ .../commands/jedis/HashesCommandsTest.java | 168 +++++++ .../unified/HashesCommandsTestBase.java | 168 +++++++ .../PipeliningBaseHashCommandsTest.java | 319 +++++++++++++ .../unified/UnifiedJedisHashCommandsTest.java | 423 ++++++++++++++++++ 14 files changed, 2123 insertions(+), 6 deletions(-) diff --git a/src/main/java/redis/clients/jedis/CommandObjects.java b/src/main/java/redis/clients/jedis/CommandObjects.java index 896ef38293b..754c25cf35e 100644 --- a/src/main/java/redis/clients/jedis/CommandObjects.java +++ b/src/main/java/redis/clients/jedis/CommandObjects.java @@ -1140,10 +1140,6 @@ public final CommandObject> hscanNoValues(String key, String return new CommandObject<>(commandArguments(HSCAN).key(key).add(cursor).addParams(params).add(NOVALUES), BuilderFactory.SCAN_RESPONSE); } - public final CommandObject hstrlen(String key, String field) { - return new CommandObject<>(commandArguments(HSTRLEN).key(key).add(field), BuilderFactory.LONG); - } - public final CommandObject>> hscan(byte[] key, byte[] cursor, ScanParams params) { return new CommandObject<>(commandArguments(HSCAN).key(key).add(cursor).addParams(params), BuilderFactory.HSCAN_BINARY_RESPONSE); } @@ -1152,9 +1148,143 @@ public final CommandObject> hscanNoValues(byte[] key, byte[] return new CommandObject<>(commandArguments(HSCAN).key(key).add(cursor).addParams(params).add(NOVALUES), BuilderFactory.SCAN_BINARY_RESPONSE); } + public final CommandObject hstrlen(String key, String field) { + return new CommandObject<>(commandArguments(HSTRLEN).key(key).add(field), BuilderFactory.LONG); + } + public final CommandObject hstrlen(byte[] key, byte[] field) { return new CommandObject<>(commandArguments(HSTRLEN).key(key).add(field), BuilderFactory.LONG); } + + public final CommandObject> hexpire(String key, long seconds, String... fields) { + return new CommandObject<>(commandArguments(HEXPIRE).key(key).add(seconds) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } + + public final CommandObject> hexpire(String key, long seconds, ExpiryOption condition, String... fields) { + return new CommandObject<>(commandArguments(HEXPIRE).key(key).add(seconds).add(condition) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } + + public final CommandObject> hpexpire(String key, long milliseconds, String... fields) { + return new CommandObject<>(commandArguments(HPEXPIRE).key(key).add(milliseconds) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } + + public final CommandObject> hpexpire(String key, long milliseconds, ExpiryOption condition, String... fields) { + return new CommandObject<>(commandArguments(HPEXPIRE).key(key).add(milliseconds).add(condition) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } + + public final CommandObject> hexpireAt(String key, long unixTimeSeconds, String... fields) { + return new CommandObject<>(commandArguments(HEXPIREAT).key(key).add(unixTimeSeconds) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } + + public final CommandObject> hexpireAt(String key, long unixTimeSeconds, ExpiryOption condition, String... fields) { + return new CommandObject<>(commandArguments(HEXPIREAT).key(key).add(unixTimeSeconds).add(condition) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } + + public final CommandObject> hpexpireAt(String key, long unixTimeMillis, String... fields) { + return new CommandObject<>(commandArguments(HPEXPIREAT).key(key).add(unixTimeMillis) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } + + public final CommandObject> hpexpireAt(String key, long unixTimeMillis, ExpiryOption condition, String... fields) { + return new CommandObject<>(commandArguments(HPEXPIREAT).key(key).add(unixTimeMillis).add(condition) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } + + public final CommandObject> hexpire(byte[] key, long seconds, byte[]... fields) { + return new CommandObject<>(commandArguments(HEXPIRE).key(key).add(seconds) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } + + public final CommandObject> hexpire(byte[] key, long seconds, ExpiryOption condition, byte[]... fields) { + return new CommandObject<>(commandArguments(HEXPIRE).key(key).add(seconds).add(condition) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } + + public final CommandObject> hpexpire(byte[] key, long milliseconds, byte[]... fields) { + return new CommandObject<>(commandArguments(HPEXPIRE).key(key).add(milliseconds) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } + + public final CommandObject> hpexpire(byte[] key, long milliseconds, ExpiryOption condition, byte[]... fields) { + return new CommandObject<>(commandArguments(HPEXPIRE).key(key).add(milliseconds).add(condition) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } + + public final CommandObject> hexpireAt(byte[] key, long unixTimeSeconds, byte[]... fields) { + return new CommandObject<>(commandArguments(HEXPIREAT).key(key).add(unixTimeSeconds) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } + + public final CommandObject> hexpireAt(byte[] key, long unixTimeSeconds, ExpiryOption condition, byte[]... fields) { + return new CommandObject<>(commandArguments(HEXPIREAT).key(key).add(unixTimeSeconds).add(condition) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } + + public final CommandObject> hpexpireAt(byte[] key, long unixTimeMillis, byte[]... fields) { + return new CommandObject<>(commandArguments(HPEXPIREAT).key(key).add(unixTimeMillis) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } + + public final CommandObject> hpexpireAt(byte[] key, long unixTimeMillis, ExpiryOption condition, byte[]... fields) { + return new CommandObject<>(commandArguments(HPEXPIREAT).key(key).add(unixTimeMillis).add(condition) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } + + public final CommandObject> hexpireTime(String key, String... fields) { + return new CommandObject<>(commandArguments(HEXPIRETIME).key(key) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } + + public final CommandObject> hpexpireTime(String key, String... fields) { + return new CommandObject<>(commandArguments(HPEXPIRETIME).key(key) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } + + public final CommandObject> httl(String key, String... fields) { + return new CommandObject<>(commandArguments(HTTL).key(key) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } + + public final CommandObject> hpttl(String key, String... fields) { + return new CommandObject<>(commandArguments(HPTTL).key(key) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } + + public final CommandObject> hexpireTime(byte[] key, byte[]... fields) { + return new CommandObject<>(commandArguments(HEXPIRETIME).key(key) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } + + public final CommandObject> hpexpireTime(byte[] key, byte[]... fields) { + return new CommandObject<>(commandArguments(HPEXPIRETIME).key(key) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } + + public final CommandObject> httl(byte[] key, byte[]... fields) { + return new CommandObject<>(commandArguments(HTTL).key(key) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } + + public final CommandObject> hpttl(byte[] key, byte[]... fields) { + return new CommandObject<>(commandArguments(HPTTL).key(key) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } + + public final CommandObject> hpersist(String key, String... fields) { + return new CommandObject<>(commandArguments(HPERSIST).key(key) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } + + public final CommandObject> hpersist(byte[] key, byte[]... fields) { + return new CommandObject<>(commandArguments(HPERSIST).key(key) + .add(FIELDS).add(fields.length).addObjects((Object[]) fields), BuilderFactory.LONG_LIST); + } // Hash commands // Set commands diff --git a/src/main/java/redis/clients/jedis/Jedis.java b/src/main/java/redis/clients/jedis/Jedis.java index 03a2bc1ed18..66d64fa6eb0 100644 --- a/src/main/java/redis/clients/jedis/Jedis.java +++ b/src/main/java/redis/clients/jedis/Jedis.java @@ -4656,6 +4656,84 @@ public long hstrlen(final byte[] key, final byte[] field) { return connection.executeCommand(commandObjects.hstrlen(key, field)); } + @Override + public List hexpire(byte[] key, long seconds, byte[]... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.hexpire(key, seconds, fields)); + } + + @Override + public List hexpire(byte[] key, long seconds, ExpiryOption condition, byte[]... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.hexpire(key, seconds, condition, fields)); + } + + @Override + public List hpexpire(byte[] key, long milliseconds, byte[]... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.hpexpire(key, milliseconds, fields)); + } + + @Override + public List hpexpire(byte[] key, long milliseconds, ExpiryOption condition, byte[]... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.hpexpire(key, milliseconds, condition, fields)); + } + + @Override + public List hexpireAt(byte[] key, long unixTimeSeconds, byte[]... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.hexpireAt(key, unixTimeSeconds, fields)); + } + + @Override + public List hexpireAt(byte[] key, long unixTimeSeconds, ExpiryOption condition, byte[]... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.hexpireAt(key, unixTimeSeconds, condition, fields)); + } + + @Override + public List hpexpireAt(byte[] key, long unixTimeMillis, byte[]... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.hpexpireAt(key, unixTimeMillis, fields)); + } + + @Override + public List hpexpireAt(byte[] key, long unixTimeMillis, ExpiryOption condition, byte[]... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.hpexpireAt(key, unixTimeMillis, condition, fields)); + } + + @Override + public List hexpireTime(byte[] key, byte[]... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.hexpireTime(key, fields)); + } + + @Override + public List hpexpireTime(byte[] key, byte[]... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.hpexpireTime(key, fields)); + } + + @Override + public List httl(byte[] key, byte[]... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.httl(key, fields)); + } + + @Override + public List hpttl(byte[] key, byte[]... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.hpttl(key, fields)); + } + + @Override + public List hpersist(byte[] key, byte[]... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.hpersist(key, fields)); + } + @Override public List xread(XReadParams xReadParams, Entry... streams) { checkIsInMultiOrPipeline(); @@ -9237,6 +9315,84 @@ public long hstrlen(final String key, final String field) { return connection.executeCommand(commandObjects.hstrlen(key, field)); } + @Override + public List hexpire(String key, long seconds, String... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.hexpire(key, seconds, fields)); + } + + @Override + public List hexpire(String key, long seconds, ExpiryOption condition, String... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.hexpire(key, seconds, condition, fields)); + } + + @Override + public List hpexpire(String key, long milliseconds, String... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.hpexpire(key, milliseconds, fields)); + } + + @Override + public List hpexpire(String key, long milliseconds, ExpiryOption condition, String... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.hpexpire(key, milliseconds, condition, fields)); + } + + @Override + public List hexpireAt(String key, long unixTimeSeconds, String... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.hexpireAt(key, unixTimeSeconds, fields)); + } + + @Override + public List hexpireAt(String key, long unixTimeSeconds, ExpiryOption condition, String... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.hexpireAt(key, unixTimeSeconds, condition, fields)); + } + + @Override + public List hpexpireAt(String key, long unixTimeMillis, String... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.hpexpireAt(key, unixTimeMillis, fields)); + } + + @Override + public List hpexpireAt(String key, long unixTimeMillis, ExpiryOption condition, String... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.hpexpireAt(key, unixTimeMillis, condition, fields)); + } + + @Override + public List hexpireTime(String key, String... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.hexpireTime(key, fields)); + } + + @Override + public List hpexpireTime(String key, String... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.hpexpireTime(key, fields)); + } + + @Override + public List httl(String key, String... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.httl(key, fields)); + } + + @Override + public List hpttl(String key, String... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.hpttl(key, fields)); + } + + @Override + public List hpersist(String key, String... fields) { + checkIsInMultiOrPipeline(); + return connection.executeCommand(commandObjects.hpersist(key, fields)); + } + @Override public String memoryDoctor() { checkIsInMultiOrPipeline(); diff --git a/src/main/java/redis/clients/jedis/PipeliningBase.java b/src/main/java/redis/clients/jedis/PipeliningBase.java index 2dac5af7120..928126a7047 100644 --- a/src/main/java/redis/clients/jedis/PipeliningBase.java +++ b/src/main/java/redis/clients/jedis/PipeliningBase.java @@ -725,6 +725,71 @@ public Response hstrlen(String key, String field) { return appendCommand(commandObjects.hstrlen(key, field)); } + @Override + public Response> hexpire(String key, long seconds, String... fields) { + return appendCommand(commandObjects.hexpire(key, seconds, fields)); + } + + @Override + public Response> hexpire(String key, long seconds, ExpiryOption condition, String... fields) { + return appendCommand(commandObjects.hexpire(key, seconds, condition, fields)); + } + + @Override + public Response> hpexpire(String key, long milliseconds, String... fields) { + return appendCommand(commandObjects.hpexpire(key, milliseconds, fields)); + } + + @Override + public Response> hpexpire(String key, long milliseconds, ExpiryOption condition, String... fields) { + return appendCommand(commandObjects.hpexpire(key, milliseconds, condition, fields)); + } + + @Override + public Response> hexpireAt(String key, long unixTimeSeconds, String... fields) { + return appendCommand(commandObjects.hexpireAt(key, unixTimeSeconds, fields)); + } + + @Override + public Response> hexpireAt(String key, long unixTimeSeconds, ExpiryOption condition, String... fields) { + return appendCommand(commandObjects.hexpireAt(key, unixTimeSeconds, condition, fields)); + } + + @Override + public Response> hpexpireAt(String key, long unixTimeMillis, String... fields) { + return appendCommand(commandObjects.hpexpireAt(key, unixTimeMillis, fields)); + } + + @Override + public Response> hpexpireAt(String key, long unixTimeMillis, ExpiryOption condition, String... fields) { + return appendCommand(commandObjects.hpexpireAt(key, unixTimeMillis, condition, fields)); + } + + @Override + public Response> hexpireTime(String key, String... fields) { + return appendCommand(commandObjects.hexpireTime(key, fields)); + } + + @Override + public Response> hpexpireTime(String key, String... fields) { + return appendCommand(commandObjects.hpexpireTime(key, fields)); + } + + @Override + public Response> httl(String key, String... fields) { + return appendCommand(commandObjects.httl(key, fields)); + } + + @Override + public Response> hpttl(String key, String... fields) { + return appendCommand(commandObjects.hpttl(key, fields)); + } + + @Override + public Response> hpersist(String key, String... fields) { + return appendCommand(commandObjects.hpersist(key, fields)); + } + @Override public Response sadd(String key, String... members) { return appendCommand(commandObjects.sadd(key, members)); @@ -2006,6 +2071,71 @@ public Response hstrlen(byte[] key, byte[] field) { return appendCommand(commandObjects.hstrlen(key, field)); } + @Override + public Response> hexpire(byte[] key, long seconds, byte[]... fields) { + return appendCommand(commandObjects.hexpire(key, seconds, fields)); + } + + @Override + public Response> hexpire(byte[] key, long seconds, ExpiryOption condition, byte[]... fields) { + return appendCommand(commandObjects.hexpire(key, seconds, condition, fields)); + } + + @Override + public Response> hpexpire(byte[] key, long milliseconds, byte[]... fields) { + return appendCommand(commandObjects.hpexpire(key, milliseconds, fields)); + } + + @Override + public Response> hpexpire(byte[] key, long milliseconds, ExpiryOption condition, byte[]... fields) { + return appendCommand(commandObjects.hpexpire(key, milliseconds, condition, fields)); + } + + @Override + public Response> hexpireAt(byte[] key, long unixTimeSeconds, byte[]... fields) { + return appendCommand(commandObjects.hexpireAt(key, unixTimeSeconds, fields)); + } + + @Override + public Response> hexpireAt(byte[] key, long unixTimeSeconds, ExpiryOption condition, byte[]... fields) { + return appendCommand(commandObjects.hexpireAt(key, unixTimeSeconds, condition, fields)); + } + + @Override + public Response> hpexpireAt(byte[] key, long unixTimeMillis, byte[]... fields) { + return appendCommand(commandObjects.hpexpireAt(key, unixTimeMillis, fields)); + } + + @Override + public Response> hpexpireAt(byte[] key, long unixTimeMillis, ExpiryOption condition, byte[]... fields) { + return appendCommand(commandObjects.hpexpireAt(key, unixTimeMillis, condition, fields)); + } + + @Override + public Response> hexpireTime(byte[] key, byte[]... fields) { + return appendCommand(commandObjects.hexpireTime(key, fields)); + } + + @Override + public Response> hpexpireTime(byte[] key, byte[]... fields) { + return appendCommand(commandObjects.hpexpireTime(key, fields)); + } + + @Override + public Response> httl(byte[] key, byte[]... fields) { + return appendCommand(commandObjects.httl(key, fields)); + } + + @Override + public Response> hpttl(byte[] key, byte[]... fields) { + return appendCommand(commandObjects.hpttl(key, fields)); + } + + @Override + public Response> hpersist(byte[] key, byte[]... fields) { + return appendCommand(commandObjects.hpersist(key, fields)); + } + @Override public Response pfadd(byte[] key, byte[]... elements) { return appendCommand(commandObjects.pfadd(key, elements)); diff --git a/src/main/java/redis/clients/jedis/Protocol.java b/src/main/java/redis/clients/jedis/Protocol.java index 531ee768c9d..448bd7ff123 100644 --- a/src/main/java/redis/clients/jedis/Protocol.java +++ b/src/main/java/redis/clients/jedis/Protocol.java @@ -254,6 +254,7 @@ public static enum Command implements ProtocolCommand { STRLEN, APPEND, SUBSTR, // <-- string SETBIT, GETBIT, BITPOS, SETRANGE, GETRANGE, BITCOUNT, BITOP, BITFIELD, BITFIELD_RO, // <-- bit (string) HSET, HGET, HSETNX, HMSET, HMGET, HINCRBY, HEXISTS, HDEL, HLEN, HKEYS, HVALS, HGETALL, HSTRLEN, + HEXPIRE, HPEXPIRE, HEXPIREAT, HPEXPIREAT, HTTL, HPTTL, HEXPIRETIME, HPEXPIRETIME, HPERSIST, HRANDFIELD, HINCRBYFLOAT, // <-- hash RPUSH, LPUSH, LLEN, LRANGE, LTRIM, LINDEX, LSET, LREM, LPOP, RPOP, BLPOP, BRPOP, LINSERT, LPOS, RPOPLPUSH, BRPOPLPUSH, BLMOVE, LMOVE, LMPOP, BLMPOP, LPUSHX, RPUSHX, // <-- list @@ -299,8 +300,8 @@ public static enum Keyword implements Rawable { REV, WITHCOORD, WITHDIST, WITHHASH, ANY, FROMMEMBER, FROMLONLAT, BYRADIUS, BYBOX, BYLEX, BYSCORE, STOREDIST, TO, FORCE, TIMEOUT, DB, UNLOAD, ABORT, IDX, MINMATCHLEN, WITHMATCHLEN, FULL, 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, + MODULE, ACLCAT, PATTERN, DOCTOR, LATEST, HISTORY, USAGE, SAMPLES, PURGE, STATS, LOADEX, CONFIG, + ARGS, RANK, NOW, VERSION, ADDR, SKIPME, USER, LADDR, FIELDS, CHANNELS, NUMPAT, NUMSUB, SHARDCHANNELS, SHARDNUMSUB, NOVALUES, MAXAGE; private final byte[] raw; diff --git a/src/main/java/redis/clients/jedis/UnifiedJedis.java b/src/main/java/redis/clients/jedis/UnifiedJedis.java index 452798d303c..2d6e77fcf0a 100644 --- a/src/main/java/redis/clients/jedis/UnifiedJedis.java +++ b/src/main/java/redis/clients/jedis/UnifiedJedis.java @@ -1600,6 +1600,136 @@ public ScanResult hscanNoValues(byte[] key, byte[] cursor, ScanParams pa public long hstrlen(byte[] key, byte[] field) { return executeCommand(commandObjects.hstrlen(key, field)); } + + @Override + public List hexpire(String key, long seconds, String... fields) { + return executeCommand(commandObjects.hexpire(key, seconds, fields)); + } + + @Override + public List hexpire(String key, long seconds, ExpiryOption condition, String... fields) { + return executeCommand(commandObjects.hexpire(key, seconds, condition, fields)); + } + + @Override + public List hpexpire(String key, long milliseconds, String... fields) { + return executeCommand(commandObjects.hpexpire(key, milliseconds, fields)); + } + + @Override + public List hpexpire(String key, long milliseconds, ExpiryOption condition, String... fields) { + return executeCommand(commandObjects.hpexpire(key, milliseconds, condition, fields)); + } + + @Override + public List hexpireAt(String key, long unixTimeSeconds, String... fields) { + return executeCommand(commandObjects.hexpireAt(key, unixTimeSeconds, fields)); + } + + @Override + public List hexpireAt(String key, long unixTimeSeconds, ExpiryOption condition, String... fields) { + return executeCommand(commandObjects.hexpireAt(key, unixTimeSeconds, condition, fields)); + } + + @Override + public List hpexpireAt(String key, long unixTimeMillis, String... fields) { + return executeCommand(commandObjects.hpexpireAt(key, unixTimeMillis, fields)); + } + + @Override + public List hpexpireAt(String key, long unixTimeMillis, ExpiryOption condition, String... fields) { + return executeCommand(commandObjects.hpexpireAt(key, unixTimeMillis, condition, fields)); + } + + @Override + public List hexpire(byte[] key, long seconds, byte[]... fields) { + return executeCommand(commandObjects.hexpire(key, seconds, fields)); + } + + @Override + public List hexpire(byte[] key, long seconds, ExpiryOption condition, byte[]... fields) { + return executeCommand(commandObjects.hexpire(key, seconds, condition, fields)); + } + + @Override + public List hpexpire(byte[] key, long milliseconds, byte[]... fields) { + return executeCommand(commandObjects.hpexpire(key, milliseconds, fields)); + } + + @Override + public List hpexpire(byte[] key, long milliseconds, ExpiryOption condition, byte[]... fields) { + return executeCommand(commandObjects.hpexpire(key, milliseconds, condition, fields)); + } + + @Override + public List hexpireAt(byte[] key, long unixTimeSeconds, byte[]... fields) { + return executeCommand(commandObjects.hexpireAt(key, unixTimeSeconds, fields)); + } + + @Override + public List hexpireAt(byte[] key, long unixTimeSeconds, ExpiryOption condition, byte[]... fields) { + return executeCommand(commandObjects.hexpireAt(key, unixTimeSeconds, condition, fields)); + } + + @Override + public List hpexpireAt(byte[] key, long unixTimeMillis, byte[]... fields) { + return executeCommand(commandObjects.hpexpireAt(key, unixTimeMillis, fields)); + } + + @Override + public List hpexpireAt(byte[] key, long unixTimeMillis, ExpiryOption condition, byte[]... fields) { + return executeCommand(commandObjects.hpexpireAt(key, unixTimeMillis, condition, fields)); + } + + @Override + public List hexpireTime(String key, String... fields) { + return executeCommand(commandObjects.hexpireTime(key, fields)); + } + + @Override + public List hpexpireTime(String key, String... fields) { + return executeCommand(commandObjects.hpexpireTime(key, fields)); + } + + @Override + public List httl(String key, String... fields) { + return executeCommand(commandObjects.httl(key, fields)); + } + + @Override + public List hpttl(String key, String... fields) { + return executeCommand(commandObjects.hpttl(key, fields)); + } + + @Override + public List hexpireTime(byte[] key, byte[]... fields) { + return executeCommand(commandObjects.hexpireTime(key, fields)); + } + + @Override + public List hpexpireTime(byte[] key, byte[]... fields) { + return executeCommand(commandObjects.hpexpireTime(key, fields)); + } + + @Override + public List httl(byte[] key, byte[]... fields) { + return executeCommand(commandObjects.httl(key, fields)); + } + + @Override + public List hpttl(byte[] key, byte[]... fields) { + return executeCommand(commandObjects.hpttl(key, fields)); + } + + @Override + public List hpersist(String key, String... fields) { + return executeCommand(commandObjects.hpersist(key, fields)); + } + + @Override + public List hpersist(byte[] key, byte[]... fields) { + return executeCommand(commandObjects.hpersist(key, fields)); + } // Hash commands // Set commands diff --git a/src/main/java/redis/clients/jedis/commands/HashBinaryCommands.java b/src/main/java/redis/clients/jedis/commands/HashBinaryCommands.java index 15a462c9b79..f32eca202e7 100644 --- a/src/main/java/redis/clients/jedis/commands/HashBinaryCommands.java +++ b/src/main/java/redis/clients/jedis/commands/HashBinaryCommands.java @@ -4,6 +4,7 @@ import java.util.Map; import java.util.Set; +import redis.clients.jedis.args.ExpiryOption; import redis.clients.jedis.params.ScanParams; import redis.clients.jedis.resps.ScanResult; @@ -57,4 +58,137 @@ default ScanResult hscanNoValues(byte[] key, byte[] cursor) { long hstrlen(byte[] key, byte[] field); + /** + * Set expiry for hash field using relative time to expire (seconds). + * + * @param key hash + * @param seconds time to expire + * @param fields + * @return integer-reply: 1 if the timeout was set, 0 otherwise + */ + List hexpire(byte[] key, long seconds, byte[]... fields); + + /** + * Set expiry for hash field using relative time to expire (seconds). + * + * @param key hash + * @param seconds time to expire + * @param condition can be NX, XX, GT or LT + * @param fields + * @return integer-reply: 1 if the timeout was set, 0 otherwise + */ + List hexpire(byte[] key, long seconds, ExpiryOption condition, byte[]... fields); + + /** + * Set expiry for hash field using relative time to expire (milliseconds). + * + * @param key hash + * @param milliseconds time to expire + * @param fields + * @return integer-reply: 1 if the timeout was set, 0 otherwise + */ + List hpexpire(byte[] key, long milliseconds, byte[]... fields); + + /** + * Set expiry for hash field using relative time to expire (milliseconds). + * + * @param key hash + * @param milliseconds time to expire + * @param condition can be NX, XX, GT or LT + * @param fields + * @return integer-reply: 1 if the timeout was set, 0 otherwise + */ + List hpexpire(byte[] key, long milliseconds, ExpiryOption condition, byte[]... fields); + + /** + * Set expiry for hash field using an absolute Unix timestamp (seconds). + * + * @param key hash + * @param unixTimeSeconds time to expire + * @param fields + * @return integer-reply: 1 if the timeout was set, 0 otherwise + */ + List hexpireAt(byte[] key, long unixTimeSeconds, byte[]... fields); + + /** + * Set expiry for hash field using an absolute Unix timestamp (seconds). + * + * @param key hash + * @param unixTimeSeconds time to expire + * @param condition can be NX, XX, GT or LT + * @param fields + * @return integer-reply: 1 if the timeout was set, 0 otherwise + */ + List hexpireAt(byte[] key, long unixTimeSeconds, ExpiryOption condition, byte[]... fields); + + /** + * Set expiry for hash field using an absolute Unix timestamp (milliseconds). + * + * @param key hash + * @param unixTimeMillis time to expire + * @param fields + * @return integer-reply: 1 if the timeout was set, 0 otherwise + */ + List hpexpireAt(byte[] key, long unixTimeMillis, byte[]... fields); + + /** + * Set expiry for hash field using an absolute Unix timestamp (milliseconds). + * + * @param key hash + * @param unixTimeMillis time to expire + * @param condition can be NX, XX, GT or LT + * @param fields + * @return integer-reply: 1 if the timeout was set, 0 otherwise + */ + List hpexpireAt(byte[] key, long unixTimeMillis, ExpiryOption condition, byte[]... fields); + + /** + * Returns the expiration time of a hash field as a Unix timestamp, in seconds. + * + * @param key hash + * @param fields + * @return Expiration Unix timestamp in seconds; + * or -1 if the field exists but has no associated expire or -2 if the field does not exist. + */ + List hexpireTime(byte[] key, byte[]... fields); + + /** + * Returns the expiration time of a hash field as a Unix timestamp, in milliseconds. + * + * @param key hash + * @param fields + * @return Expiration Unix timestamp in milliseconds; + * or -1 if the field exists but has no associated expire or -2 if the field does not exist. + */ + List hpexpireTime(byte[] key, byte[]... fields); + + /** + * Returns the TTL in seconds of a hash field. + * + * @param key hash + * @param fields + * @return TTL in seconds; + * or -1 if the field exists but has no associated expire or -2 if the field does not exist. + */ + List httl(byte[] key, byte[]... fields); + + /** + * Returns the TTL in milliseconds of a hash field. + * + * @param key hash + * @param fields + * @return TTL in milliseconds; + * or -1 if the field exists but has no associated expire or -2 if the field does not exist. + */ + List hpttl(byte[] key, byte[]... fields); + + /** + * Removes the expiration time for each specified field. + * + * @param key hash + * @param fields + * @return integer-reply: 1 if the expiration time was removed, + * or -1 if the field exists but has no associated expire or -2 if the field does not exist. + */ + List hpersist(byte[] key, byte[]... fields); } diff --git a/src/main/java/redis/clients/jedis/commands/HashCommands.java b/src/main/java/redis/clients/jedis/commands/HashCommands.java index ef18e34aee0..3be6ec1959a 100644 --- a/src/main/java/redis/clients/jedis/commands/HashCommands.java +++ b/src/main/java/redis/clients/jedis/commands/HashCommands.java @@ -4,6 +4,7 @@ import java.util.Map; import java.util.Set; +import redis.clients.jedis.args.ExpiryOption; import redis.clients.jedis.params.ScanParams; import redis.clients.jedis.resps.ScanResult; @@ -56,4 +57,138 @@ default ScanResult hscanNoValues(String key, String cursor) { ScanResult hscanNoValues(String key, String cursor, ScanParams params); long hstrlen(String key, String field); + + /** + * Set expiry for hash field using relative time to expire (seconds). + * + * @param key hash + * @param seconds time to expire + * @param fields + * @return integer-reply: 1 if the timeout was set, 0 otherwise + */ + List hexpire(String key, long seconds, String... fields); + + /** + * Set expiry for hash field using relative time to expire (seconds). + * + * @param key hash + * @param seconds time to expire + * @param condition can be NX, XX, GT or LT + * @param fields + * @return integer-reply: 1 if the timeout was set, 0 otherwise + */ + List hexpire(String key, long seconds, ExpiryOption condition, String... fields); + + /** + * Set expiry for hash field using relative time to expire (milliseconds). + * + * @param key hash + * @param milliseconds time to expire + * @param fields + * @return integer-reply: 1 if the timeout was set, 0 otherwise + */ + List hpexpire(String key, long milliseconds, String... fields); + + /** + * Set expiry for hash field using relative time to expire (milliseconds). + * + * @param key hash + * @param milliseconds time to expire + * @param condition can be NX, XX, GT or LT + * @param fields + * @return integer-reply: 1 if the timeout was set, 0 otherwise + */ + List hpexpire(String key, long milliseconds, ExpiryOption condition, String... fields); + + /** + * Set expiry for hash field using an absolute Unix timestamp (seconds). + * + * @param key hash + * @param unixTimeSeconds time to expire + * @param fields + * @return integer-reply: 1 if the timeout was set, 0 otherwise + */ + List hexpireAt(String key, long unixTimeSeconds, String... fields); + + /** + * Set expiry for hash field using an absolute Unix timestamp (seconds). + * + * @param key hash + * @param unixTimeSeconds time to expire + * @param condition can be NX, XX, GT or LT + * @param fields + * @return integer-reply: 1 if the timeout was set, 0 otherwise + */ + List hexpireAt(String key, long unixTimeSeconds, ExpiryOption condition, String... fields); + + /** + * Set expiry for hash field using an absolute Unix timestamp (milliseconds). + * + * @param key hash + * @param unixTimeMillis time to expire + * @param fields + * @return integer-reply: 1 if the timeout was set, 0 otherwise + */ + List hpexpireAt(String key, long unixTimeMillis, String... fields); + + /** + * Set expiry for hash field using an absolute Unix timestamp (milliseconds). + * + * @param key hash + * @param unixTimeMillis time to expire + * @param condition can be NX, XX, GT or LT + * @param fields + * @return integer-reply: 1 if the timeout was set, 0 otherwise + */ + List hpexpireAt(String key, long unixTimeMillis, ExpiryOption condition, String... fields); + + /** + * Returns the expiration time of a hash field as a Unix timestamp, in seconds. + * + * @param key hash + * @param fields + * @return Expiration Unix timestamp in seconds; + * or -1 if the field exists but has no associated expire or -2 if the field does not exist. + */ + List hexpireTime(String key, String... fields); + + /** + * Returns the expiration time of a hash field as a Unix timestamp, in milliseconds. + * + * @param key hash + * @param fields + * @return Expiration Unix timestamp in milliseconds; + * or -1 if the field exists but has no associated expire or -2 if the field does not exist. + */ + List hpexpireTime(String key, String... fields); + + /** + * Returns the TTL in seconds of a hash field. + * + * @param key hash + * @param fields + * @return TTL in seconds; + * or -1 if the field exists but has no associated expire or -2 if the field does not exist. + */ + List httl(String key, String... fields); + + /** + * Returns the TTL in milliseconds of a hash field. + * + * @param key hash + * @param fields + * @return TTL in milliseconds; + * or -1 if the field exists but has no associated expire or -2 if the field does not exist. + */ + List hpttl(String key, String... fields); + + /** + * Removes the expiration time for each specified field. + * + * @param key hash + * @param fields + * @return integer-reply: 1 if the expiration time was removed, + * or -1 if the field exists but has no associated expire or -2 if the field does not exist. + */ + List hpersist(String key, String... fields); } diff --git a/src/main/java/redis/clients/jedis/commands/HashPipelineBinaryCommands.java b/src/main/java/redis/clients/jedis/commands/HashPipelineBinaryCommands.java index cf104f7a338..e428e72a639 100644 --- a/src/main/java/redis/clients/jedis/commands/HashPipelineBinaryCommands.java +++ b/src/main/java/redis/clients/jedis/commands/HashPipelineBinaryCommands.java @@ -5,6 +5,7 @@ import java.util.Set; import redis.clients.jedis.Response; +import redis.clients.jedis.args.ExpiryOption; import redis.clients.jedis.params.ScanParams; import redis.clients.jedis.resps.ScanResult; @@ -58,4 +59,29 @@ default Response> hscanNoValues(byte[] key, byte[] cursor) { Response hstrlen(byte[] key, byte[] field); + Response> hexpire(byte[] key, long seconds, byte[]... fields); + + Response> hexpire(byte[] key, long seconds, ExpiryOption condition, byte[]... fields); + + Response> hpexpire(byte[] key, long milliseconds, byte[]... fields); + + Response> hpexpire(byte[] key, long milliseconds, ExpiryOption condition, byte[]... fields); + + Response> hexpireAt(byte[] key, long unixTimeSeconds, byte[]... fields); + + Response> hexpireAt(byte[] key, long unixTimeSeconds, ExpiryOption condition, byte[]... fields); + + Response> hpexpireAt(byte[] key, long unixTimeMillis, byte[]... fields); + + Response> hpexpireAt(byte[] key, long unixTimeMillis, ExpiryOption condition, byte[]... fields); + + Response> hexpireTime(byte[] key, byte[]... fields); + + Response> hpexpireTime(byte[] key, byte[]... fields); + + Response> httl(byte[] key, byte[]... fields); + + Response> hpttl(byte[] key, byte[]... fields); + + Response> hpersist(byte[] key, byte[]... fields); } diff --git a/src/main/java/redis/clients/jedis/commands/HashPipelineCommands.java b/src/main/java/redis/clients/jedis/commands/HashPipelineCommands.java index dabcac4e901..4de4839a9d9 100644 --- a/src/main/java/redis/clients/jedis/commands/HashPipelineCommands.java +++ b/src/main/java/redis/clients/jedis/commands/HashPipelineCommands.java @@ -5,6 +5,7 @@ import java.util.Set; import redis.clients.jedis.Response; +import redis.clients.jedis.args.ExpiryOption; import redis.clients.jedis.params.ScanParams; import redis.clients.jedis.resps.ScanResult; @@ -57,4 +58,30 @@ default Response> hscanNoValues(String key, String cursor) { Response> hscanNoValues(String key, String cursor, ScanParams params); Response hstrlen(String key, String field); + + Response> hexpire(String key, long seconds, String... fields); + + Response> hexpire(String key, long seconds, ExpiryOption condition, String... fields); + + Response> hpexpire(String key, long milliseconds, String... fields); + + Response> hpexpire(String key, long milliseconds, ExpiryOption condition, String... fields); + + Response> hexpireAt(String key, long unixTimeSeconds, String... fields); + + Response> hexpireAt(String key, long unixTimeSeconds, ExpiryOption condition, String... fields); + + Response> hpexpireAt(String key, long unixTimeMillis, String... fields); + + Response> hpexpireAt(String key, long unixTimeMillis, ExpiryOption condition, String... fields); + + Response> hexpireTime(String key, String... fields); + + Response> hpexpireTime(String key, String... fields); + + Response> httl(String key, String... fields); + + Response> hpttl(String key, String... fields); + + Response> hpersist(String key, String... fields); } diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsHashCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsHashCommandsTest.java index b025b854408..a8de3122abf 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsHashCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsHashCommandsTest.java @@ -1,12 +1,16 @@ package redis.clients.jedis.commands.commandobjects; +import static java.util.Arrays.asList; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.both; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.everyItem; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.lessThanOrEqualTo; @@ -19,6 +23,7 @@ import org.junit.Test; import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.args.ExpiryOption; import redis.clients.jedis.params.ScanParams; import redis.clients.jedis.resps.ScanResult; @@ -27,6 +32,13 @@ */ public class CommandObjectsHashCommandsTest extends CommandObjectsStandaloneTestBase { + private final byte[] bfoo = { 0x01, 0x02, 0x03, 0x04 }; + private final byte[] bcar = { 0x09, 0x0A, 0x0B, 0x0C }; + + private final byte[] bbar1 = { 0x05, 0x06, 0x07, 0x08, 0x0A }; + private final byte[] bbar2 = { 0x05, 0x06, 0x07, 0x08, 0x0B }; + private final byte[] bbar3 = { 0x05, 0x06, 0x07, 0x08, 0x0C }; + public CommandObjectsHashCommandsTest(RedisProtocol protocol) { super(protocol); } @@ -402,4 +414,162 @@ public void testHashStrlen() { Long strlenNonExistingFieldBinary = exec(commandObjects.hstrlen(bkey, "nonExistingField".getBytes())); assertThat(strlenNonExistingFieldBinary, equalTo(0L)); } + + @Test + public void hexpireAndHttl() { + long seconds1 = 20; + long seconds2 = 10; + + exec(commandObjects.hset("foo", "bar", "car")); + exec(commandObjects.hset("foo", "bare", "care")); + assertThat(exec(commandObjects.hexpire("foo", seconds1, "bar", "bared")), equalTo(asList(1L, -2L))); + + exec(commandObjects.hset("foo", "bared", "cared")); + assertThat(exec(commandObjects.hexpire("foo", seconds2, ExpiryOption.NX, "bar", "bared")), equalTo(asList(0L, 1L))); + + assertThat(exec(commandObjects.httl("foo", "bar", "bare", "bared")), + contains(greaterThanOrEqualTo(seconds1 - 1), equalTo(-1L), + both(lessThanOrEqualTo(seconds2)).and(greaterThanOrEqualTo(seconds2 - 1)))); + } + + @Test + public void hexpireAndHttlBinary() { + long seconds1 = 20; + long seconds2 = 10; + + exec(commandObjects.hset(bfoo, bbar1, bcar)); + exec(commandObjects.hset(bfoo, bbar2, bcar)); + assertThat(exec(commandObjects.hexpire(bfoo, seconds1, bbar1, bbar3)), equalTo(asList(1L, -2L))); + + exec(commandObjects.hset(bfoo, bbar3, bcar)); + assertThat(exec(commandObjects.hexpire(bfoo, seconds2, ExpiryOption.NX, bbar1, bbar3)), equalTo(asList(0L, 1L))); + + assertThat(exec(commandObjects.httl(bfoo, bbar1, bbar2, bbar3)), + contains(greaterThanOrEqualTo(seconds1 - 1), equalTo(-1L), + both(lessThanOrEqualTo(seconds2)).and(greaterThanOrEqualTo(seconds2 - 1)))); + } + + @Test + public void hpexpireAndHpttl() { + long millis1 = 20_000; + long millis2 = 10_000; + + exec(commandObjects.hset("foo", "bar", "car")); + assertThat(exec(commandObjects.hpexpire("foo", millis1, "bar", "bared")), equalTo(asList(1L, -2L))); + + exec(commandObjects.hset("foo", "bared", "cared")); + assertThat(exec(commandObjects.hpexpire("foo", millis2, ExpiryOption.XX, "bar", "bared")), equalTo(asList(1L, 0L))); + + assertThat(exec(commandObjects.hpttl("foo", "bar", "bare", "bared")), + contains(both(lessThanOrEqualTo(millis2)).and(greaterThan(millis2 - 10)), equalTo(-2L), equalTo(-1L))); + } + + @Test + public void hpexpireAndHpttlBinary() { + long millis1 = 20_000; + long millis2 = 10_000; + + exec(commandObjects.hset(bfoo, bbar1, bcar)); + assertThat(exec(commandObjects.hpexpire(bfoo, millis1, bbar1, bbar3)), equalTo(asList(1L, -2L))); + + exec(commandObjects.hset(bfoo, bbar3, bcar)); + assertThat(exec(commandObjects.hpexpire(bfoo, millis2, ExpiryOption.XX, bbar1, bbar3)), equalTo(asList(1L, 0L))); + + assertThat(exec(commandObjects.hpttl(bfoo, bbar1, bbar2, bbar3)), + contains(both(lessThanOrEqualTo(millis2)).and(greaterThan(millis2 - 10)), equalTo(-2L), equalTo(-1L))); + } + + @Test + public void hexpireAtAndExpireTime() { + long currSeconds = System.currentTimeMillis() / 1000; + long seconds1 = currSeconds + 20; + long seconds2 = currSeconds + 10; + + exec(commandObjects.hset("foo", "bar", "car")); + exec(commandObjects.hset("foo", "bare", "care")); + assertThat(exec(commandObjects.hexpireAt("foo", seconds1, "bar", "bared")), equalTo(asList(1L, -2L))); + + exec(commandObjects.hset("foo", "bared", "cared")); + assertThat(exec(commandObjects.hexpireAt("foo", seconds2, ExpiryOption.LT, "bar", "bared")), equalTo(asList(1L, 1L))); + + assertThat(exec(commandObjects.hexpireTime("foo", "bar", "bare", "bared")), + contains(both(lessThanOrEqualTo(seconds2)).and(greaterThanOrEqualTo(seconds2 - 1)), equalTo(-1L), + both(lessThanOrEqualTo(seconds2)).and(greaterThanOrEqualTo(seconds2 - 1)))); + } + + @Test + public void hexpireAtAndExpireTimeBinary() { + long currSeconds = System.currentTimeMillis() / 1000; + long seconds1 = currSeconds + 20; + long seconds2 = currSeconds + 10; + + exec(commandObjects.hset(bfoo, bbar1, bcar)); + exec(commandObjects.hset(bfoo, bbar2, bcar)); + assertThat(exec(commandObjects.hexpireAt(bfoo, seconds1, bbar1, bbar3)), equalTo(asList(1L, -2L))); + + exec(commandObjects.hset(bfoo, bbar3, bcar)); + assertThat(exec(commandObjects.hexpireAt(bfoo, seconds2, ExpiryOption.LT, bbar1, bbar3)), equalTo(asList(1L, 1L))); + + assertThat(exec(commandObjects.hexpireTime(bfoo, bbar1, bbar2, bbar3)), + contains(both(lessThanOrEqualTo(seconds2)).and(greaterThanOrEqualTo(seconds2 - 1)), equalTo(-1L), + both(lessThanOrEqualTo(seconds2)).and(greaterThanOrEqualTo(seconds2 - 1)))); + } + + @Test + public void hpexpireAtAndPexpireTime() { + long currMillis = System.currentTimeMillis(); + long unixMillis = currMillis + 20_000; + + exec(commandObjects.hset("foo", "bar", "car")); + assertThat(exec(commandObjects.hpexpireAt("foo", unixMillis - 100, "bar", "bared")), equalTo(asList(1L, -2L))); + + exec(commandObjects.hset("foo", "bared", "cared")); + assertThat(exec(commandObjects.hpexpireAt("foo", unixMillis, ExpiryOption.GT, "bar", "bared")), equalTo(asList(1L, 0L))); + + assertThat(exec(commandObjects.hpexpireTime("foo", "bar", "bare", "bared")), + contains(equalTo(unixMillis), equalTo(-2L), equalTo(-1L))); + } + + @Test + public void hpexpireAtAndPexpireTimeBinary() { + long currMillis = System.currentTimeMillis(); + long unixMillis = currMillis + 20_000; + + exec(commandObjects.hset(bfoo, bbar1, bcar)); + assertThat(exec(commandObjects.hpexpireAt(bfoo, unixMillis - 100, bbar1, bbar3)), equalTo(asList(1L, -2L))); + + exec(commandObjects.hset(bfoo, bbar3, bcar)); + assertThat(exec(commandObjects.hpexpireAt(bfoo, unixMillis, ExpiryOption.GT, bbar1, bbar3)), equalTo(asList(1L, 0L))); + + assertThat(exec(commandObjects.hpexpireTime(bfoo, bbar1, bbar2, bbar3)), + contains(equalTo(unixMillis), equalTo(-2L), equalTo(-1L))); + } + + @Test + public void hpersist() { + long seconds = 20; + + exec(commandObjects.hset("foo", "bar", "car")); + exec(commandObjects.hset("foo", "bare", "care")); + assertThat(exec(commandObjects.hexpire("foo", seconds, "bar", "bared")), equalTo(asList(1L, -2L))); + + assertThat(exec(commandObjects.hpersist("foo", "bar", "bare", "bared")), equalTo(asList(1L, -1L, -2L))); + + assertThat(exec(commandObjects.httl("foo", "bar", "bare", "bared")), + contains(equalTo(-1L), equalTo(-1L), equalTo(-2L))); + } + + @Test + public void hpersistBinary() { + long seconds = 20; + + exec(commandObjects.hset(bfoo, bbar1, bcar)); + exec(commandObjects.hset(bfoo, bbar2, bcar)); + assertThat(exec(commandObjects.hexpire(bfoo, seconds, bbar1, bbar3)), equalTo(asList(1L, -2L))); + + assertThat(exec(commandObjects.hpersist(bfoo, bbar1, bbar2, bbar3)), equalTo(asList(1L, -1L, -2L))); + + assertThat(exec(commandObjects.httl(bfoo, bbar1, bbar2, bbar3)), + contains(equalTo(-1L), equalTo(-1L), equalTo(-2L))); + } } diff --git a/src/test/java/redis/clients/jedis/commands/jedis/HashesCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/HashesCommandsTest.java index c07adc86b4e..88ca543fc45 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/HashesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/HashesCommandsTest.java @@ -1,7 +1,16 @@ package redis.clients.jedis.commands.jedis; +import static java.util.Arrays.asList; + import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.both; +import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.lessThanOrEqualTo; + import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -29,6 +38,7 @@ import redis.clients.jedis.Pipeline; import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.Response; +import redis.clients.jedis.args.ExpiryOption; import redis.clients.jedis.params.ScanParams; import redis.clients.jedis.resps.ScanResult; import redis.clients.jedis.util.AssertUtil; @@ -641,4 +651,162 @@ public void hrandfield() { assertEquals(5, bactual.size()); bactual.forEach(e -> assertArrayEquals(bhash.get(e.getKey()), e.getValue())); } + + @Test + public void hexpireAndHttl() { + long seconds1 = 20; + long seconds2 = 10; + + jedis.hset("foo", "bar", "car"); + jedis.hset("foo", "bare", "care"); + assertEquals(asList(1L, -2L), jedis.hexpire("foo", seconds1, "bar", "bared")); + + jedis.hset("foo", "bared", "cared"); + assertEquals(asList(0L, 1L), jedis.hexpire("foo", seconds2, ExpiryOption.NX, "bar", "bared")); + + assertThat(jedis.httl("foo", "bar", "bare", "bared"), + contains(greaterThanOrEqualTo(seconds1 - 1), equalTo(-1L), + both(lessThanOrEqualTo(seconds2)).and(greaterThanOrEqualTo(seconds2 - 1)))); + } + + @Test + public void hexpireAndHttlBinary() { + long seconds1 = 20; + long seconds2 = 10; + + jedis.hset(bfoo, bbar1, bcar); + jedis.hset(bfoo, bbar2, bcar); + assertEquals(asList(1L, -2L), jedis.hexpire(bfoo, seconds1, bbar1, bbar3)); + + jedis.hset(bfoo, bbar3, bcar); + assertEquals(asList(0L, 1L), jedis.hexpire(bfoo, seconds2, ExpiryOption.NX, bbar1, bbar3)); + + assertThat(jedis.httl(bfoo, bbar1, bbar2, bbar3), + contains(greaterThanOrEqualTo(seconds1 - 1), equalTo(-1L), + both(lessThanOrEqualTo(seconds2)).and(greaterThanOrEqualTo(seconds2 - 1)))); + } + + @Test + public void hpexpireAndHpttl() { + long millis1 = 20_000; + long millis2 = 10_000; + + jedis.hset("foo", "bar", "car"); + assertEquals(asList(1L, -2L), jedis.hpexpire("foo", millis1, "bar", "bared")); + + jedis.hset("foo", "bared", "cared"); + assertEquals(asList(1L, 0L), jedis.hpexpire("foo", millis2, ExpiryOption.XX, "bar", "bared")); + + assertThat(jedis.hpttl("foo", "bar", "bare", "bared"), + contains(both(lessThanOrEqualTo(millis2)).and(greaterThan(millis2 - 10)), equalTo(-2L), equalTo(-1L))); + } + + @Test + public void hpexpireAndHpttlBinary() { + long millis1 = 20_000; + long millis2 = 10_000; + + jedis.hset(bfoo, bbar1, bcar); + assertEquals(asList(1L, -2L), jedis.hpexpire(bfoo, millis1, bbar1, bbar3)); + + jedis.hset(bfoo, bbar3, bcar); + assertEquals(asList(1L, 0L), jedis.hpexpire(bfoo, millis2, ExpiryOption.XX, bbar1, bbar3)); + + assertThat(jedis.hpttl(bfoo, bbar1, bbar2, bbar3), + contains(both(lessThanOrEqualTo(millis2)).and(greaterThan(millis2 - 10)), equalTo(-2L), equalTo(-1L))); + } + + @Test + public void hexpireAtAndExpireTime() { + long currSeconds = System.currentTimeMillis() / 1000; + long seconds1 = currSeconds + 20; + long seconds2 = currSeconds + 10; + + jedis.hset("foo", "bar", "car"); + jedis.hset("foo", "bare", "care"); + assertEquals(asList(1L, -2L), jedis.hexpireAt("foo", seconds1, "bar", "bared")); + + jedis.hset("foo", "bared", "cared"); + assertEquals(asList(1L, 1L), jedis.hexpireAt("foo", seconds2, ExpiryOption.LT, "bar", "bared")); + + assertThat(jedis.hexpireTime("foo", "bar", "bare", "bared"), + contains(both(lessThanOrEqualTo(seconds2)).and(greaterThanOrEqualTo(seconds2 - 1)), equalTo(-1L), + both(lessThanOrEqualTo(seconds2)).and(greaterThanOrEqualTo(seconds2 - 1)))); + } + + @Test + public void hexpireAtAndExpireTimeBinary() { + long currSeconds = System.currentTimeMillis() / 1000; + long seconds1 = currSeconds + 20; + long seconds2 = currSeconds + 10; + + jedis.hset(bfoo, bbar1, bcar); + jedis.hset(bfoo, bbar2, bcar); + assertEquals(asList(1L, -2L), jedis.hexpireAt(bfoo, seconds1, bbar1, bbar3)); + + jedis.hset(bfoo, bbar3, bcar); + assertEquals(asList(1L, 1L), jedis.hexpireAt(bfoo, seconds2, ExpiryOption.LT, bbar1, bbar3)); + + assertThat(jedis.hexpireTime(bfoo, bbar1, bbar2, bbar3), + contains(both(lessThanOrEqualTo(seconds2)).and(greaterThanOrEqualTo(seconds2 - 1)), equalTo(-1L), + both(lessThanOrEqualTo(seconds2)).and(greaterThanOrEqualTo(seconds2 - 1)))); + } + + @Test + public void hpexpireAtAndPexpireTime() { + long currMillis = System.currentTimeMillis(); + long unixMillis = currMillis + 20_000; + + jedis.hset("foo", "bar", "car"); + assertEquals(asList(1L, -2L), jedis.hpexpireAt("foo", unixMillis - 100, "bar", "bared")); + + jedis.hset("foo", "bared", "cared"); + assertEquals(asList(1L, 0L), jedis.hpexpireAt("foo", unixMillis, ExpiryOption.GT, "bar", "bared")); + + assertThat(jedis.hpexpireTime("foo", "bar", "bare", "bared"), + contains(equalTo(unixMillis), equalTo(-2L), equalTo(-1L))); + } + + @Test + public void hpexpireAtAndPexpireTimeBinary() { + long currMillis = System.currentTimeMillis(); + long unixMillis = currMillis + 20_000; + + jedis.hset(bfoo, bbar1, bcar); + assertEquals(asList(1L, -2L), jedis.hpexpireAt(bfoo, unixMillis - 100, bbar1, bbar3)); + + jedis.hset(bfoo, bbar3, bcar); + assertEquals(asList(1L, 0L), jedis.hpexpireAt(bfoo, unixMillis, ExpiryOption.GT, bbar1, bbar3)); + + assertThat(jedis.hpexpireTime(bfoo, bbar1, bbar2, bbar3), + contains(equalTo(unixMillis), equalTo(-2L), equalTo(-1L))); + } + + @Test + public void hpersist() { + long seconds = 20; + + jedis.hset("foo", "bar", "car"); + jedis.hset("foo", "bare", "care"); + assertEquals(asList(1L, -2L), jedis.hexpire("foo", seconds, "bar", "bared")); + + assertEquals(asList(1L, -1L, -2L), jedis.hpersist("foo", "bar", "bare", "bared")); + + assertThat(jedis.httl("foo", "bar", "bare", "bared"), + contains(equalTo(-1L), equalTo(-1L), equalTo(-2L))); + } + + @Test + public void hpersistBinary() { + long seconds = 20; + + jedis.hset(bfoo, bbar1, bcar); + jedis.hset(bfoo, bbar2, bcar); + assertEquals(asList(1L, -2L), jedis.hexpire(bfoo, seconds, bbar1, bbar3)); + + assertEquals(asList(1L, -1L, -2L), jedis.hpersist(bfoo, bbar1, bbar2, bbar3)); + + assertThat(jedis.httl(bfoo, bbar1, bbar2, bbar3), + contains(equalTo(-1L), equalTo(-1L), equalTo(-2L))); + } } diff --git a/src/test/java/redis/clients/jedis/commands/unified/HashesCommandsTestBase.java b/src/test/java/redis/clients/jedis/commands/unified/HashesCommandsTestBase.java index 401f29dbe3b..f84b0c2cc6e 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/HashesCommandsTestBase.java +++ b/src/test/java/redis/clients/jedis/commands/unified/HashesCommandsTestBase.java @@ -1,7 +1,16 @@ package redis.clients.jedis.commands.unified; +import static java.util.Arrays.asList; + import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.both; +import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.lessThanOrEqualTo; + import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -25,6 +34,7 @@ import org.junit.Test; import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.args.ExpiryOption; import redis.clients.jedis.params.ScanParams; import redis.clients.jedis.resps.ScanResult; import redis.clients.jedis.util.AssertUtil; @@ -613,4 +623,162 @@ public void hrandfield() { assertEquals(5, bactual.size()); bactual.forEach(e -> assertArrayEquals(bhash.get(e.getKey()), e.getValue())); } + + @Test + public void hexpireAndHttl() { + long seconds1 = 20; + long seconds2 = 10; + + jedis.hset("foo", "bar", "car"); + jedis.hset("foo", "bare", "care"); + assertEquals(asList(1L, -2L), jedis.hexpire("foo", seconds1, "bar", "bared")); + + jedis.hset("foo", "bared", "cared"); + assertEquals(asList(0L, 1L), jedis.hexpire("foo", seconds2, ExpiryOption.NX, "bar", "bared")); + + assertThat(jedis.httl("foo", "bar", "bare", "bared"), + contains(greaterThanOrEqualTo(seconds1 - 1), equalTo(-1L), + both(lessThanOrEqualTo(seconds2)).and(greaterThanOrEqualTo(seconds2 - 1)))); + } + + @Test + public void hexpireAndHttlBinary() { + long seconds1 = 20; + long seconds2 = 10; + + jedis.hset(bfoo, bbar1, bcar); + jedis.hset(bfoo, bbar2, bcar); + assertEquals(asList(1L, -2L), jedis.hexpire(bfoo, seconds1, bbar1, bbar3)); + + jedis.hset(bfoo, bbar3, bcar); + assertEquals(asList(0L, 1L), jedis.hexpire(bfoo, seconds2, ExpiryOption.NX, bbar1, bbar3)); + + assertThat(jedis.httl(bfoo, bbar1, bbar2, bbar3), + contains(greaterThanOrEqualTo(seconds1 - 1), equalTo(-1L), + both(lessThanOrEqualTo(seconds2)).and(greaterThanOrEqualTo(seconds2 - 1)))); + } + + @Test + public void hpexpireAndHpttl() { + long millis1 = 20_000; + long millis2 = 10_000; + + jedis.hset("foo", "bar", "car"); + assertEquals(asList(1L, -2L), jedis.hpexpire("foo", millis1, "bar", "bared")); + + jedis.hset("foo", "bared", "cared"); + assertEquals(asList(1L, 0L), jedis.hpexpire("foo", millis2, ExpiryOption.XX, "bar", "bared")); + + assertThat(jedis.hpttl("foo", "bar", "bare", "bared"), + contains(both(lessThanOrEqualTo(millis2)).and(greaterThan(millis2 - 10)), equalTo(-2L), equalTo(-1L))); + } + + @Test + public void hpexpireAndHpttlBinary() { + long millis1 = 20_000; + long millis2 = 10_000; + + jedis.hset(bfoo, bbar1, bcar); + assertEquals(asList(1L, -2L), jedis.hpexpire(bfoo, millis1, bbar1, bbar3)); + + jedis.hset(bfoo, bbar3, bcar); + assertEquals(asList(1L, 0L), jedis.hpexpire(bfoo, millis2, ExpiryOption.XX, bbar1, bbar3)); + + assertThat(jedis.hpttl(bfoo, bbar1, bbar2, bbar3), + contains(both(lessThanOrEqualTo(millis2)).and(greaterThan(millis2 - 10)), equalTo(-2L), equalTo(-1L))); + } + + @Test + public void hexpireAtAndExpireTime() { + long currSeconds = System.currentTimeMillis() / 1000; + long seconds1 = currSeconds + 20; + long seconds2 = currSeconds + 10; + + jedis.hset("foo", "bar", "car"); + jedis.hset("foo", "bare", "care"); + assertEquals(asList(1L, -2L), jedis.hexpireAt("foo", seconds1, "bar", "bared")); + + jedis.hset("foo", "bared", "cared"); + assertEquals(asList(1L, 1L), jedis.hexpireAt("foo", seconds2, ExpiryOption.LT, "bar", "bared")); + + assertThat(jedis.hexpireTime("foo", "bar", "bare", "bared"), + contains(both(lessThanOrEqualTo(seconds2)).and(greaterThanOrEqualTo(seconds2 - 1)), equalTo(-1L), + both(lessThanOrEqualTo(seconds2)).and(greaterThanOrEqualTo(seconds2 - 1)))); + } + + @Test + public void hexpireAtAndExpireTimeBinary() { + long currSeconds = System.currentTimeMillis() / 1000; + long seconds1 = currSeconds + 20; + long seconds2 = currSeconds + 10; + + jedis.hset(bfoo, bbar1, bcar); + jedis.hset(bfoo, bbar2, bcar); + assertEquals(asList(1L, -2L), jedis.hexpireAt(bfoo, seconds1, bbar1, bbar3)); + + jedis.hset(bfoo, bbar3, bcar); + assertEquals(asList(1L, 1L), jedis.hexpireAt(bfoo, seconds2, ExpiryOption.LT, bbar1, bbar3)); + + assertThat(jedis.hexpireTime(bfoo, bbar1, bbar2, bbar3), + contains(both(lessThanOrEqualTo(seconds2)).and(greaterThanOrEqualTo(seconds2 - 1)), equalTo(-1L), + both(lessThanOrEqualTo(seconds2)).and(greaterThanOrEqualTo(seconds2 - 1)))); + } + + @Test + public void hpexpireAtAndPexpireTime() { + long currMillis = System.currentTimeMillis(); + long unixMillis = currMillis + 20_000; + + jedis.hset("foo", "bar", "car"); + assertEquals(asList(1L, -2L), jedis.hpexpireAt("foo", unixMillis - 100, "bar", "bared")); + + jedis.hset("foo", "bared", "cared"); + assertEquals(asList(1L, 0L), jedis.hpexpireAt("foo", unixMillis, ExpiryOption.GT, "bar", "bared")); + + assertThat(jedis.hpexpireTime("foo", "bar", "bare", "bared"), + contains(equalTo(unixMillis), equalTo(-2L), equalTo(-1L))); + } + + @Test + public void hpexpireAtAndPexpireTimeBinary() { + long currMillis = System.currentTimeMillis(); + long unixMillis = currMillis + 20_000; + + jedis.hset(bfoo, bbar1, bcar); + assertEquals(asList(1L, -2L), jedis.hpexpireAt(bfoo, unixMillis - 100, bbar1, bbar3)); + + jedis.hset(bfoo, bbar3, bcar); + assertEquals(asList(1L, 0L), jedis.hpexpireAt(bfoo, unixMillis, ExpiryOption.GT, bbar1, bbar3)); + + assertThat(jedis.hpexpireTime(bfoo, bbar1, bbar2, bbar3), + contains(equalTo(unixMillis), equalTo(-2L), equalTo(-1L))); + } + + @Test + public void hpersist() { + long seconds = 20; + + jedis.hset("foo", "bar", "car"); + jedis.hset("foo", "bare", "care"); + assertEquals(asList(1L, -2L), jedis.hexpire("foo", seconds, "bar", "bared")); + + assertEquals(asList(1L, -1L, -2L), jedis.hpersist("foo", "bar", "bare", "bared")); + + assertThat(jedis.httl("foo", "bar", "bare", "bared"), + contains(equalTo(-1L), equalTo(-1L), equalTo(-2L))); + } + + @Test + public void hpersistBinary() { + long seconds = 20; + + jedis.hset(bfoo, bbar1, bcar); + jedis.hset(bfoo, bbar2, bcar); + assertEquals(asList(1L, -2L), jedis.hexpire(bfoo, seconds, bbar1, bbar3)); + + assertEquals(asList(1L, -1L, -2L), jedis.hpersist(bfoo, bbar1, bbar2, bbar3)); + + assertThat(jedis.httl(bfoo, bbar1, bbar2, bbar3), + contains(equalTo(-1L), equalTo(-1L), equalTo(-2L))); + } } diff --git a/src/test/java/redis/clients/jedis/mocked/pipeline/PipeliningBaseHashCommandsTest.java b/src/test/java/redis/clients/jedis/mocked/pipeline/PipeliningBaseHashCommandsTest.java index b23cee6da26..1ea0d0b3c2d 100644 --- a/src/test/java/redis/clients/jedis/mocked/pipeline/PipeliningBaseHashCommandsTest.java +++ b/src/test/java/redis/clients/jedis/mocked/pipeline/PipeliningBaseHashCommandsTest.java @@ -2,7 +2,9 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.in; import static org.hamcrest.Matchers.is; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.util.HashMap; @@ -12,11 +14,18 @@ import org.junit.Test; import redis.clients.jedis.Response; +import redis.clients.jedis.args.ExpiryOption; import redis.clients.jedis.params.ScanParams; import redis.clients.jedis.resps.ScanResult; public class PipeliningBaseHashCommandsTest extends PipeliningBaseMockedTestBase { + private final byte[] bfoo = { 0x01, 0x02, 0x03, 0x04 }; + + private final byte[] bbar1 = { 0x05, 0x06, 0x07, 0x08, 0x0A }; + private final byte[] bbar2 = { 0x05, 0x06, 0x07, 0x08, 0x0B }; + private final byte[] bbar3 = { 0x05, 0x06, 0x07, 0x08, 0x0C }; + @Test public void testHdel() { when(commandObjects.hdel("key", "field1", "field2")).thenReturn(longCommandObject); @@ -502,4 +511,314 @@ public void testHvalsBinary() { assertThat(response, is(predefinedResponse)); } + @Test + public void hexpire() { + String key = "hash"; + long seconds = 100; + String[] fields = { "one", "two", "three" }; + + when(commandObjects.hexpire(key, seconds, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.hexpire(key, seconds, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + + @Test + public void hexpireCondition() { + String key = "hash"; + long seconds = 100; + ExpiryOption condition = mock(ExpiryOption.class); + String[] fields = { "one", "two", "three" }; + + when(commandObjects.hexpire(key, seconds, condition, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.hexpire(key, seconds, condition, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + + @Test + public void hpexpire() { + String key = "hash"; + long milliseconds = 10000; + String[] fields = { "one", "two", "three" }; + + when(commandObjects.hpexpire(key, milliseconds, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.hpexpire(key, milliseconds, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + + @Test + public void hpexpireCondition() { + String key = "hash"; + long milliseconds = 10000; + ExpiryOption condition = mock(ExpiryOption.class); + String[] fields = { "one", "two", "three" }; + + when(commandObjects.hpexpire(key, milliseconds, condition, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.hpexpire(key, milliseconds, condition, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + + @Test + public void hexpireAt() { + String key = "hash"; + long seconds = 100; + String[] fields = { "one", "two", "three" }; + + when(commandObjects.hexpireAt(key, seconds, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.hexpireAt(key, seconds, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + + @Test + public void hexpireAtCondition() { + String key = "hash"; + long seconds = 100; + ExpiryOption condition = mock(ExpiryOption.class); + String[] fields = { "one", "two", "three" }; + + when(commandObjects.hexpireAt(key, seconds, condition, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.hexpireAt(key, seconds, condition, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + + @Test + public void hpexpireAt() { + String key = "hash"; + long milliseconds = 10000; + String[] fields = { "one", "two", "three" }; + + when(commandObjects.hpexpireAt(key, milliseconds, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.hpexpireAt(key, milliseconds, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + + @Test + public void hpexpireAtCondition() { + String key = "hash"; + long milliseconds = 10000; + ExpiryOption condition = mock(ExpiryOption.class); + String[] fields = { "one", "two", "three" }; + + when(commandObjects.hpexpireAt(key, milliseconds, condition, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.hpexpireAt(key, milliseconds, condition, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + + @Test + public void hexpireTime() { + String key = "hash"; + String[] fields = { "one", "two", "three" }; + + when(commandObjects.hexpireTime(key, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.hexpireTime(key, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + + @Test + public void hpexpireTime() { + String key = "hash"; + String[] fields = { "one", "two", "three" }; + + when(commandObjects.hpexpireTime(key, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.hpexpireTime(key, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + + @Test + public void httl() { + String key = "hash"; + String[] fields = { "one", "two", "three" }; + + when(commandObjects.httl(key, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.httl(key, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + + @Test + public void hpttl() { + String key = "hash"; + String[] fields = { "one", "two", "three" }; + + when(commandObjects.hpttl(key, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.hpttl(key, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + + @Test + public void hpersist() { + String key = "hash"; + String[] fields = { "one", "two", "three" }; + + when(commandObjects.hpersist(key, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.hpersist(key, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + + @Test + public void hexpireBinary() { + byte[] key = bfoo; + long seconds = 100; + byte[][] fields = { bbar1, bbar2, bbar3 }; + + when(commandObjects.hexpire(key, seconds, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.hexpire(key, seconds, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + + @Test + public void hexpireConditionBinary() { + byte[] key = bfoo; + long seconds = 100; + ExpiryOption condition = mock(ExpiryOption.class); + byte[][] fields = { bbar1, bbar2, bbar3 }; + + when(commandObjects.hexpire(key, seconds, condition, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.hexpire(key, seconds, condition, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + + @Test + public void hpexpireBinary() { + byte[] key = bfoo; + long milliseconds = 10000; + byte[][] fields = { bbar1, bbar2, bbar3 }; + + when(commandObjects.hpexpire(key, milliseconds, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.hpexpire(key, milliseconds, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + + @Test + public void hpexpireConditionBinary() { + byte[] key = bfoo; + long milliseconds = 10000; + ExpiryOption condition = mock(ExpiryOption.class); + byte[][] fields = { bbar1, bbar2, bbar3 }; + + when(commandObjects.hpexpire(key, milliseconds, condition, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.hpexpire(key, milliseconds, condition, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + + @Test + public void hexpireAtBinary() { + byte[] key = bfoo; + long seconds = 100; + byte[][] fields = { bbar1, bbar2, bbar3 }; + + when(commandObjects.hexpireAt(key, seconds, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.hexpireAt(key, seconds, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + + @Test + public void hexpireAtConditionBinary() { + byte[] key = bfoo; + long seconds = 100; + ExpiryOption condition = mock(ExpiryOption.class); + byte[][] fields = { bbar1, bbar2, bbar3 }; + + when(commandObjects.hexpireAt(key, seconds, condition, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.hexpireAt(key, seconds, condition, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + + @Test + public void hpexpireAtBinary() { + byte[] key = bfoo; + long milliseconds = 10000; + byte[][] fields = { bbar1, bbar2, bbar3 }; + + when(commandObjects.hpexpireAt(key, milliseconds, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.hpexpireAt(key, milliseconds, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + + @Test + public void hpexpireAtConditionBinary() { + byte[] key = bfoo; + long milliseconds = 10000; + ExpiryOption condition = mock(ExpiryOption.class); + byte[][] fields = { bbar1, bbar2, bbar3 }; + + when(commandObjects.hpexpireAt(key, milliseconds, condition, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.hpexpireAt(key, milliseconds, condition, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + + @Test + public void hexpireTimeBinary() { + byte[] key = bfoo; + byte[][] fields = { bbar1, bbar2, bbar3 }; + + when(commandObjects.hexpireTime(key, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.hexpireTime(key, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + + @Test + public void hpexpireTimeBinary() { + byte[] key = bfoo; + byte[][] fields = { bbar1, bbar2, bbar3 }; + + when(commandObjects.hpexpireTime(key, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.hpexpireTime(key, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + + @Test + public void httlBinary() { + byte[] key = bfoo; + byte[][] fields = { bbar1, bbar2, bbar3 }; + + when(commandObjects.httl(key, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.httl(key, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + + @Test + public void hpttlBinary() { + byte[] key = bfoo; + byte[][] fields = { bbar1, bbar2, bbar3 }; + + when(commandObjects.hpttl(key, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.hpttl(key, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + + @Test + public void hpersistBinary() { + byte[] key = bfoo; + byte[][] fields = { bbar1, bbar2, bbar3 }; + + when(commandObjects.hpersist(key, fields)).thenReturn(listLongCommandObject); + + assertThat(pipeliningBase.hpersist(key, fields), is(predefinedResponse)); + assertThat(listLongCommandObject, in(commands)); + } + } diff --git a/src/test/java/redis/clients/jedis/mocked/unified/UnifiedJedisHashCommandsTest.java b/src/test/java/redis/clients/jedis/mocked/unified/UnifiedJedisHashCommandsTest.java index c867e4d3e51..d2dc8d88922 100644 --- a/src/test/java/redis/clients/jedis/mocked/unified/UnifiedJedisHashCommandsTest.java +++ b/src/test/java/redis/clients/jedis/mocked/unified/UnifiedJedisHashCommandsTest.java @@ -1,7 +1,9 @@ package redis.clients.jedis.mocked.unified; +import static java.util.Arrays.asList; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -15,11 +17,18 @@ import java.util.Set; import org.junit.Test; +import redis.clients.jedis.args.ExpiryOption; import redis.clients.jedis.params.ScanParams; import redis.clients.jedis.resps.ScanResult; public class UnifiedJedisHashCommandsTest extends UnifiedJedisMockedTestBase { + private final byte[] bfoo = { 0x01, 0x02, 0x03, 0x04 }; + + private final byte[] bbar1 = { 0x05, 0x06, 0x07, 0x08, 0x0A }; + private final byte[] bbar2 = { 0x05, 0x06, 0x07, 0x08, 0x0B }; + private final byte[] bbar3 = { 0x05, 0x06, 0x07, 0x08, 0x0C }; + @Test public void testHdel() { String key = "hashKey"; @@ -764,4 +773,418 @@ public void testHvalsBinary() { verify(commandObjects).hvals(key); } + @Test + public void hexpire() { + String key = "hash"; + long seconds = 100; + String[] fields = { "one", "two", "three" }; + List expected = asList( 1L, 2L, 3L ); + + when(commandObjects.hexpire(key, seconds, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.hexpire(key, seconds, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).hexpire(key, seconds, fields); + } + + @Test + public void hexpireCondition() { + String key = "hash"; + long seconds = 100; + ExpiryOption condition = mock(ExpiryOption.class); + String[] fields = { "one", "two", "three" }; + List expected = asList( 1L, 2L, 3L ); + + when(commandObjects.hexpire(key, seconds, condition, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.hexpire(key, seconds, condition, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).hexpire(key, seconds, condition, fields); + } + + @Test + public void hpexpire() { + String key = "hash"; + long milliseconds = 10000; + String[] fields = { "one", "two", "three" }; + List expected = asList( 100L, 200L, 300L ); + + when(commandObjects.hpexpire(key, milliseconds, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.hpexpire(key, milliseconds, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).hpexpire(key, milliseconds, fields); + } + + @Test + public void hpexpireCondition() { + String key = "hash"; + long milliseconds = 10000; + ExpiryOption condition = mock(ExpiryOption.class); + String[] fields = { "one", "two", "three" }; + List expected = asList( 100L, 200L, 300L ); + + when(commandObjects.hpexpire(key, milliseconds, condition, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.hpexpire(key, milliseconds, condition, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).hpexpire(key, milliseconds, condition, fields); + } + + @Test + public void hexpireAt() { + String key = "hash"; + long seconds = 100; + String[] fields = { "one", "two", "three" }; + List expected = asList( 1L, 2L, 3L ); + + when(commandObjects.hexpireAt(key, seconds, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.hexpireAt(key, seconds, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).hexpireAt(key, seconds, fields); + } + + @Test + public void hexpireAtCondition() { + String key = "hash"; + long seconds = 100; + ExpiryOption condition = mock(ExpiryOption.class); + String[] fields = { "one", "two", "three" }; + List expected = asList( 1L, 2L, 3L ); + + when(commandObjects.hexpireAt(key, seconds, condition, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.hexpireAt(key, seconds, condition, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).hexpireAt(key, seconds, condition, fields); + } + + @Test + public void hpexpireAt() { + String key = "hash"; + long milliseconds = 10000; + String[] fields = { "one", "two", "three" }; + List expected = asList( 1L, 2L, 3L ); + + when(commandObjects.hpexpireAt(key, milliseconds, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.hpexpireAt(key, milliseconds, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).hpexpireAt(key, milliseconds, fields); + } + + @Test + public void hpexpireAtCondition() { + String key = "hash"; + long milliseconds = 100; + ExpiryOption condition = mock(ExpiryOption.class); + String[] fields = { "one", "two", "three" }; + List expected = asList( 1L, 2L, 3L ); + + when(commandObjects.hpexpireAt(key, milliseconds, condition, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.hpexpireAt(key, milliseconds, condition, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).hpexpireAt(key, milliseconds, condition, fields); + } + + @Test + public void hexpireTime() { + String key = "hash"; + String[] fields = { "one", "two", "three" }; + List expected = asList( 10L, 20L, 30L ); + + when(commandObjects.hexpireTime(key, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.hexpireTime(key, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).hexpireTime(key, fields); + } + + @Test + public void hpexpireTime() { + String key = "hash"; + String[] fields = { "one", "two", "three" }; + List expected = asList( 1000L, 2000L, 3000L ); + + when(commandObjects.hpexpireTime(key, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.hpexpireTime(key, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).hpexpireTime(key, fields); + } + + @Test + public void httl() { + String key = "hash"; + String[] fields = { "one", "two", "three" }; + List expected = asList( 10L, 20L, 30L ); + + when(commandObjects.httl(key, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.httl(key, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).httl(key, fields); + } + + @Test + public void hpttl() { + String key = "hash"; + String[] fields = { "one", "two", "three" }; + List expected = asList( 1000L, 2000L, 3000L ); + + when(commandObjects.hpttl(key, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.hpttl(key, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).hpttl(key, fields); + } + + @Test + public void hpersist() { + String key = "hash"; + String[] fields = { "one", "two", "three" }; + List expected = asList( 1L, 2L, 3L ); + + when(commandObjects.hpersist(key, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.hpersist(key, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).hpersist(key, fields); + } + + @Test + public void hexpireBinary() { + byte[] key = bfoo; + long seconds = 100; + byte[][] fields = { bbar1, bbar2, bbar3 }; + List expected = asList( 1L, 2L, 3L ); + + when(commandObjects.hexpire(key, seconds, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.hexpire(key, seconds, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).hexpire(key, seconds, fields); + } + + @Test + public void hexpireConditionBinary() { + byte[] key = bfoo; + long seconds = 100; + ExpiryOption condition = mock(ExpiryOption.class); + byte[][] fields = { bbar1, bbar2, bbar3 }; + List expected = asList( 1L, 2L, 3L ); + + when(commandObjects.hexpire(key, seconds, condition, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.hexpire(key, seconds, condition, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).hexpire(key, seconds, condition, fields); + } + + @Test + public void hpexpireBinary() { + byte[] key = bfoo; + long milliseconds = 10000; + byte[][] fields = { bbar1, bbar2, bbar3 }; + List expected = asList( 100L, 200L, 300L ); + + when(commandObjects.hpexpire(key, milliseconds, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.hpexpire(key, milliseconds, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).hpexpire(key, milliseconds, fields); + } + + @Test + public void hpexpireConditionBinary() { + byte[] key = bfoo; + long milliseconds = 10000; + ExpiryOption condition = mock(ExpiryOption.class); + byte[][] fields = { bbar1, bbar2, bbar3 }; + List expected = asList( 100L, 200L, 300L ); + + when(commandObjects.hpexpire(key, milliseconds, condition, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.hpexpire(key, milliseconds, condition, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).hpexpire(key, milliseconds, condition, fields); + } + + @Test + public void hexpireAtBinary() { + byte[] key = bfoo; + long seconds = 100; + byte[][] fields = { bbar1, bbar2, bbar3 }; + List expected = asList( 1L, 2L, 3L ); + + when(commandObjects.hexpireAt(key, seconds, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.hexpireAt(key, seconds, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).hexpireAt(key, seconds, fields); + } + + @Test + public void hexpireAtConditionBinary() { + byte[] key = bfoo; + long seconds = 100; + ExpiryOption condition = mock(ExpiryOption.class); + byte[][] fields = { bbar1, bbar2, bbar3 }; + List expected = asList( 1L, 2L, 3L ); + + when(commandObjects.hexpireAt(key, seconds, condition, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.hexpireAt(key, seconds, condition, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).hexpireAt(key, seconds, condition, fields); + } + + @Test + public void hpexpireAtBinary() { + byte[] key = bfoo; + long milliseconds = 10000; + byte[][] fields = { bbar1, bbar2, bbar3 }; + List expected = asList( 1L, 2L, 3L ); + + when(commandObjects.hpexpireAt(key, milliseconds, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.hpexpireAt(key, milliseconds, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).hpexpireAt(key, milliseconds, fields); + } + + @Test + public void hpexpireAtConditionBinary() { + byte[] key = bfoo; + long milliseconds = 100; + ExpiryOption condition = mock(ExpiryOption.class); + byte[][] fields = { bbar1, bbar2, bbar3 }; + List expected = asList( 1L, 2L, 3L ); + + when(commandObjects.hpexpireAt(key, milliseconds, condition, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.hpexpireAt(key, milliseconds, condition, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).hpexpireAt(key, milliseconds, condition, fields); + } + + @Test + public void hexpireTimeBinary() { + byte[] key = bfoo; + byte[][] fields = { bbar1, bbar2, bbar3 }; + List expected = asList( 10L, 20L, 30L ); + + when(commandObjects.hexpireTime(key, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.hexpireTime(key, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).hexpireTime(key, fields); + } + + @Test + public void hpexpireTimeBinary() { + byte[] key = bfoo; + byte[][] fields = { bbar1, bbar2, bbar3 }; + List expected = asList( 1000L, 2000L, 3000L ); + + when(commandObjects.hpexpireTime(key, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.hpexpireTime(key, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).hpexpireTime(key, fields); + } + + @Test + public void httlBinary() { + byte[] key = bfoo; + byte[][] fields = { bbar1, bbar2, bbar3 }; + List expected = asList( 10L, 20L, 30L ); + + when(commandObjects.httl(key, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.httl(key, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).httl(key, fields); + } + + @Test + public void hpttlBinary() { + byte[] key = bfoo; + byte[][] fields = { bbar1, bbar2, bbar3 }; + List expected = asList( 1000L, 2000L, 3000L ); + + when(commandObjects.hpttl(key, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.hpttl(key, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).hpttl(key, fields); + } + + @Test + public void hpersistBinary() { + byte[] key = bfoo; + byte[][] fields = { bbar1, bbar2, bbar3 }; + List expected = asList( 1L, 2L, 3L ); + + when(commandObjects.hpersist(key, fields)).thenReturn(listLongCommandObject); + when(commandExecutor.executeCommand(listLongCommandObject)).thenReturn(expected); + + assertThat(jedis.hpersist(key, fields), equalTo(expected)); + + verify(commandExecutor).executeCommand(listLongCommandObject); + verify(commandObjects).hpersist(key, fields); + } + } From 32d69ad3bfe219988a177f0125026fa721d249b7 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Fri, 7 Jun 2024 14:57:21 +0600 Subject: [PATCH 21/51] Disable Redis Graph tests (#3856) We use redis-stack-server image to test all module commands. RedisGraph module has been removed from that image. --- .../java/redis/clients/jedis/modules/graph/GraphAPITest.java | 2 +- .../redis/clients/jedis/modules/graph/GraphPipelineTest.java | 1 + .../redis/clients/jedis/modules/graph/GraphTransactionTest.java | 1 + .../java/redis/clients/jedis/modules/graph/GraphValuesTest.java | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/test/java/redis/clients/jedis/modules/graph/GraphAPITest.java b/src/test/java/redis/clients/jedis/modules/graph/GraphAPITest.java index 46b135070c9..6b1011829bf 100644 --- a/src/test/java/redis/clients/jedis/modules/graph/GraphAPITest.java +++ b/src/test/java/redis/clients/jedis/modules/graph/GraphAPITest.java @@ -22,9 +22,9 @@ import redis.clients.jedis.graph.ResultSet; import redis.clients.jedis.graph.Statistics; import redis.clients.jedis.graph.entities.*; - import redis.clients.jedis.modules.RedisModuleCommandsTestBase; +@org.junit.Ignore @RunWith(Parameterized.class) public class GraphAPITest extends RedisModuleCommandsTestBase { diff --git a/src/test/java/redis/clients/jedis/modules/graph/GraphPipelineTest.java b/src/test/java/redis/clients/jedis/modules/graph/GraphPipelineTest.java index f69dd06712c..e021c0252cc 100644 --- a/src/test/java/redis/clients/jedis/modules/graph/GraphPipelineTest.java +++ b/src/test/java/redis/clients/jedis/modules/graph/GraphPipelineTest.java @@ -26,6 +26,7 @@ import redis.clients.jedis.graph.entities.Property; import redis.clients.jedis.modules.RedisModuleCommandsTestBase; +@org.junit.Ignore @RunWith(Parameterized.class) public class GraphPipelineTest extends RedisModuleCommandsTestBase { diff --git a/src/test/java/redis/clients/jedis/modules/graph/GraphTransactionTest.java b/src/test/java/redis/clients/jedis/modules/graph/GraphTransactionTest.java index 9a7a8e502c9..d33477dfcda 100644 --- a/src/test/java/redis/clients/jedis/modules/graph/GraphTransactionTest.java +++ b/src/test/java/redis/clients/jedis/modules/graph/GraphTransactionTest.java @@ -23,6 +23,7 @@ import redis.clients.jedis.graph.entities.Property; import redis.clients.jedis.modules.RedisModuleCommandsTestBase; +@org.junit.Ignore @RunWith(Parameterized.class) public class GraphTransactionTest extends RedisModuleCommandsTestBase { diff --git a/src/test/java/redis/clients/jedis/modules/graph/GraphValuesTest.java b/src/test/java/redis/clients/jedis/modules/graph/GraphValuesTest.java index ea9c6a77991..3a199a14644 100644 --- a/src/test/java/redis/clients/jedis/modules/graph/GraphValuesTest.java +++ b/src/test/java/redis/clients/jedis/modules/graph/GraphValuesTest.java @@ -12,6 +12,7 @@ import redis.clients.jedis.graph.ResultSet; import redis.clients.jedis.modules.RedisModuleCommandsTestBase; +@org.junit.Ignore @RunWith(Parameterized.class) public class GraphValuesTest extends RedisModuleCommandsTestBase { From 36668bcb0e746314bb94db9b133c878fbfbfa093 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Fri, 7 Jun 2024 16:07:53 +0600 Subject: [PATCH 22/51] Deprecate unused Set builders (#3857) --- src/main/java/redis/clients/jedis/BuilderFactory.java | 2 ++ src/main/java/redis/clients/jedis/CommandObjects.java | 4 ---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/redis/clients/jedis/BuilderFactory.java b/src/main/java/redis/clients/jedis/BuilderFactory.java index 26d5b5c384b..18eeb64afda 100644 --- a/src/main/java/redis/clients/jedis/BuilderFactory.java +++ b/src/main/java/redis/clients/jedis/BuilderFactory.java @@ -661,6 +661,7 @@ public String toString() { } }; + @Deprecated public static final Builder> TUPLE_ZSET = new Builder>() { @Override @SuppressWarnings("unchecked") @@ -683,6 +684,7 @@ public String toString() { } }; + @Deprecated public static final Builder> TUPLE_ZSET_RESP3 = new Builder>() { @Override @SuppressWarnings("unchecked") diff --git a/src/main/java/redis/clients/jedis/CommandObjects.java b/src/main/java/redis/clients/jedis/CommandObjects.java index 754c25cf35e..efaf19397ca 100644 --- a/src/main/java/redis/clients/jedis/CommandObjects.java +++ b/src/main/java/redis/clients/jedis/CommandObjects.java @@ -2150,10 +2150,6 @@ public final CommandObject>> bzmpop(double timeout, private Builder> getTupleListBuilder() { return protocol == RedisProtocol.RESP3 ? BuilderFactory.TUPLE_LIST_RESP3 : BuilderFactory.TUPLE_LIST; } - - private Builder> getTupleSetBuilder() { - return protocol == RedisProtocol.RESP3 ? BuilderFactory.TUPLE_ZSET_RESP3 : BuilderFactory.TUPLE_ZSET; - } // Sorted Set commands // Geo commands From 4ca869e9c4c8a4f4706a8f8bae916f4e578253bc Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Fri, 7 Jun 2024 16:32:07 +0600 Subject: [PATCH 23/51] Address change in JSON.GET command without path (#3858) --- .../redis/clients/jedis/CommandObjects.java | 3 +-- .../CommandObjectsJsonCommandsTest.java | 27 +------------------ .../jedis/modules/json/RedisJsonV2Test.java | 25 ----------------- 3 files changed, 2 insertions(+), 53 deletions(-) diff --git a/src/main/java/redis/clients/jedis/CommandObjects.java b/src/main/java/redis/clients/jedis/CommandObjects.java index efaf19397ca..7226a014a79 100644 --- a/src/main/java/redis/clients/jedis/CommandObjects.java +++ b/src/main/java/redis/clients/jedis/CommandObjects.java @@ -3621,8 +3621,7 @@ public final CommandObject jsonMerge(String key, Path path, Object pojo) } public final CommandObject jsonGet(String key) { - return new CommandObject<>(commandArguments(JsonCommand.GET).key(key), - protocol != RedisProtocol.RESP3 ? JSON_GENERIC_OBJECT : JsonBuilderFactory.JSON_OBJECT); + return new CommandObject<>(commandArguments(JsonCommand.GET).key(key), JSON_GENERIC_OBJECT); } @Deprecated diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsJsonCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsJsonCommandsTest.java index a416be21039..6e24cdd3220 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsJsonCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsJsonCommandsTest.java @@ -235,9 +235,7 @@ public void testJsonMergeOldPath() { @Test @Deprecated - public void testJsonGenericObjectResp2() { - assumeThat(protocol, not(equalTo(RedisProtocol.RESP3))); - + public void testJsonGenericObject() { String key = "user:1000"; Person person = new Person(); @@ -256,29 +254,6 @@ public void testJsonGenericObjectResp2() { assertThat(resultMap, hasEntry("age", 30.0)); } - @Test - @Deprecated - public void testJsonGenericObjectResp3() { - assumeThat(protocol, equalTo(RedisProtocol.RESP3)); - - String key = "user:1000"; - - Person person = new Person("John Doe", 30); - - String setResult = exec(commandObjects.jsonSet(key, Path.ROOT_PATH, person)); - assertThat(setResult, equalTo("OK")); - - Object getRoot = exec(commandObjects.jsonGet(key)); - assertThat(getRoot, instanceOf(JSONArray.class)); - - JSONObject expectedPerson = new JSONObject(); - expectedPerson.put("name", "John Doe"); - expectedPerson.put("age", 30); - - JSONArray expected = new JSONArray().put(expectedPerson); - assertThat(getRoot, jsonEquals(expected)); - } - @Test @Deprecated public void testJsonGetWithClass() { diff --git a/src/test/java/redis/clients/jedis/modules/json/RedisJsonV2Test.java b/src/test/java/redis/clients/jedis/modules/json/RedisJsonV2Test.java index 6168c2e2de8..688e64a12e1 100644 --- a/src/test/java/redis/clients/jedis/modules/json/RedisJsonV2Test.java +++ b/src/test/java/redis/clients/jedis/modules/json/RedisJsonV2Test.java @@ -50,8 +50,6 @@ public void setUp() { @Test public void basicSetGetShouldSucceed() { - Assume.assumeFalse(protocol == RedisProtocol.RESP3); - // naive set with a path jsonV2.jsonSetWithEscape("null", ROOT_PATH, (Object) null); assertJsonArrayEquals(jsonArray((Object) null), jsonV2.jsonGet("null", ROOT_PATH)); @@ -72,29 +70,6 @@ public void basicSetGetShouldSucceed() { assertJsonArrayEquals(jsonArray("strung"), jsonV2.jsonGet("obj", p)); } - @Test - public void basicSetGetShouldSucceedResp3() { - Assume.assumeTrue(protocol == RedisProtocol.RESP3); - - // naive set with a path - jsonV2.jsonSetWithEscape("null", ROOT_PATH, (Object) null); - assertJsonArrayEquals(jsonArray((Object) null), jsonV2.jsonGet("null", ROOT_PATH)); - - // real scalar value and no path - jsonV2.jsonSetWithEscape("str", "strong"); - assertJsonArrayEquals(jsonArray("strong"), jsonV2.jsonGet("str")); - - // a slightly more complex object - IRLObject obj = new IRLObject(); - jsonV2.jsonSetWithEscape("obj", obj); - assertJsonArrayEquals(jsonArray(new JSONObject(gson.toJson(obj))), jsonV2.jsonGet("obj")); - - // check an update - Path2 p = Path2.of(".str"); - jsonV2.jsonSet("obj", p, gson.toJson("strung")); - assertJsonArrayEquals(jsonArray("strung"), jsonV2.jsonGet("obj", p)); - } - @Test public void setExistingPathOnlyIfExistsShouldSucceed() { jsonV2.jsonSetWithEscape("obj", new IRLObject()); From 811dca045e979b7ddb58176ca2c09636b1f38473 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Mon, 10 Jun 2024 22:29:54 +0600 Subject: [PATCH 24/51] Support [S]PUBLISH in pipelines and transactions (#3859) 1. We already have PUBLISH in simple Pipeline. 2. We have SPUBLISH only in JedisCluster; so it's only added in ClusterPipeline. 3. We don't have transaction with cluster. So obviously [S]PUBLISH isn't implemented for such case. --- * Support PUBLISH in Transaction(s) * Support SPUBLISH in ClusterPipeline --- .../clients/jedis/AbstractTransaction.java | 8 ++++++++ .../redis/clients/jedis/ClusterPipeline.java | 18 +++++++++++++----- .../java/redis/clients/jedis/Connection.java | 2 +- .../clients/jedis/ClusterPipeliningTest.java | 12 ++++++++++++ .../redis/clients/jedis/PipeliningTest.java | 2 +- .../pooled/PooledMiscellaneousTest.java | 19 +++++++++++++++---- 6 files changed, 50 insertions(+), 11 deletions(-) diff --git a/src/main/java/redis/clients/jedis/AbstractTransaction.java b/src/main/java/redis/clients/jedis/AbstractTransaction.java index 2a551224fa7..a4369075405 100644 --- a/src/main/java/redis/clients/jedis/AbstractTransaction.java +++ b/src/main/java/redis/clients/jedis/AbstractTransaction.java @@ -36,4 +36,12 @@ protected AbstractTransaction(CommandObjects commandObjects) { public Response waitReplicas(int replicas, long timeout) { return appendCommand(commandObjects.waitReplicas(replicas, timeout)); } + + public Response publish(String channel, String message) { + return appendCommand(commandObjects.publish(channel, message)); + } + + public Response publish(byte[] channel, byte[] message) { + return appendCommand(commandObjects.publish(channel, message)); + } } diff --git a/src/main/java/redis/clients/jedis/ClusterPipeline.java b/src/main/java/redis/clients/jedis/ClusterPipeline.java index 0c850c8ed8a..a122b41688c 100644 --- a/src/main/java/redis/clients/jedis/ClusterPipeline.java +++ b/src/main/java/redis/clients/jedis/ClusterPipeline.java @@ -46,6 +46,13 @@ private static ClusterCommandObjects createClusterCommandObjects(RedisProtocol p return cco; } + /** + * This method must be called after constructor, if graph commands are going to be used. + */ + public void prepareGraphCommands() { + super.prepareGraphCommands(provider); + } + @Override public void close() { try { @@ -65,10 +72,11 @@ protected Connection getConnection(HostAndPort nodeKey) { return provider.getConnection(nodeKey); } - /** - * This method must be called after constructor, if graph commands are going to be used. - */ - public void prepareGraphCommands() { - super.prepareGraphCommands(provider); + public Response spublish(String channel, String message) { + return appendCommand(commandObjects.spublish(channel, message)); + } + + public Response spublish(byte[] channel, byte[] message) { + return appendCommand(commandObjects.spublish(channel, message)); } } diff --git a/src/main/java/redis/clients/jedis/Connection.java b/src/main/java/redis/clients/jedis/Connection.java index 50243e20d7e..f9fe5594829 100644 --- a/src/main/java/redis/clients/jedis/Connection.java +++ b/src/main/java/redis/clients/jedis/Connection.java @@ -349,7 +349,7 @@ protected Object readProtocolWithCheckingBroken() { try { return Protocol.read(inputStream); // Object read = Protocol.read(inputStream); -// System.out.println(SafeEncoder.encodeObject(read)); +// System.out.println(redis.clients.jedis.util.SafeEncoder.encodeObject(read)); // return read; } catch (JedisConnectionException exc) { broken = true; diff --git a/src/test/java/redis/clients/jedis/ClusterPipeliningTest.java b/src/test/java/redis/clients/jedis/ClusterPipeliningTest.java index ff196ec4ea6..2edcb674560 100644 --- a/src/test/java/redis/clients/jedis/ClusterPipeliningTest.java +++ b/src/test/java/redis/clients/jedis/ClusterPipeliningTest.java @@ -1024,6 +1024,18 @@ public void testEvalshaKeyAndArgWithBinary() { } } + @Test + public void spublishInPipeline() { + try (JedisCluster jedis = new JedisCluster(nodes, DEFAULT_CLIENT_CONFIG)) { + ClusterPipeline pipelined = jedis.pipelined(); + Response p1 = pipelined.publish("foo", "bar"); + Response p2 = pipelined.publish("foo".getBytes(), "bar".getBytes()); + pipelined.sync(); + assertEquals(0, p1.get().longValue()); + assertEquals(0, p2.get().longValue()); + } + } + @Test public void simple() { // TODO: move into 'redis.clients.jedis.commands.unified.cluster' package try (JedisCluster jedis = new JedisCluster(nodes, DEFAULT_CLIENT_CONFIG)) { diff --git a/src/test/java/redis/clients/jedis/PipeliningTest.java b/src/test/java/redis/clients/jedis/PipeliningTest.java index 9340f366db9..7df000c7a39 100644 --- a/src/test/java/redis/clients/jedis/PipeliningTest.java +++ b/src/test/java/redis/clients/jedis/PipeliningTest.java @@ -257,7 +257,7 @@ public void pipelineResponseWithinPipeline() { } @Test - public void pipelineWithPubSub() { + public void publishInPipeline() { Pipeline pipelined = jedis.pipelined(); Response p1 = pipelined.publish("foo", "bar"); Response p2 = pipelined.publish("foo".getBytes(), "bar".getBytes()); 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 5c663633452..d6feb05fa3b 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 @@ -106,7 +106,6 @@ public void transaction() { @Test public void watch() { - List resp; try (AbstractTransaction tx = jedis.transaction(false)) { assertEquals("OK", tx.watch("mykey", "somekey")); tx.multi(); @@ -114,10 +113,22 @@ public void watch() { jedis.set("mykey", "bar"); tx.set("mykey", "foo"); - resp = tx.exec(); + assertNull(tx.exec()); + + assertEquals("bar", jedis.get("mykey")); + } + } + + @Test + public void publishInTransaction() { + try (AbstractTransaction tx = jedis.multi()) { + Response p1 = tx.publish("foo", "bar"); + Response p2 = tx.publish("foo".getBytes(), "bar".getBytes()); + tx.exec(); + + assertEquals(0, p1.get().longValue()); + assertEquals(0, p2.get().longValue()); } - assertNull(resp); - assertEquals("bar", jedis.get("mykey")); } @Test From e7503d78f86f166028327e45ae1150bd96f2271b Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Fri, 14 Jun 2024 10:16:47 +0600 Subject: [PATCH 25/51] Support IGNORE and other optional arguments for timeseries commands (#3860) * Re-implement TS.ADD command with optional arguments * Implement TS.INCRBY and TS.DECRBY commands with optional arguments * Support IGNORE argument for TS.[ CREATE | ALTER | ADD | INCRBY | DECRBY] commands --- * Cover optional arguments for timeseries commands - Re-implement TS.ADD command with optional arguments - Implement TS.INCRBY and TS.DECRBY commands with optional arguments * Introduce EncodingFormat enum for * Support IGNORE option and rename to TSIncrOrDecrByParams --- .../redis/clients/jedis/CommandObjects.java | 20 ++- .../redis/clients/jedis/PipeliningBase.java | 15 ++ .../redis/clients/jedis/UnifiedJedis.java | 15 ++ .../jedis/timeseries/EncodingFormat.java | 24 ++++ .../timeseries/RedisTimeSeriesCommands.java | 55 +++++++- .../RedisTimeSeriesPipelineCommands.java | 7 + .../clients/jedis/timeseries/TSAddParams.java | 128 +++++++++++++++++ .../jedis/timeseries/TSAlterParams.java | 28 ++++ .../jedis/timeseries/TSCreateParams.java | 39 ++++-- .../timeseries/TSIncrOrDecrByParams.java | 132 ++++++++++++++++++ .../jedis/timeseries/TimeSeriesProtocol.java | 1 + .../PipeliningBaseTimeSeriesCommandsTest.java | 47 +++++-- .../UnifiedJedisTimeSeriesCommandsTest.java | 71 ++++++++-- .../modules/timeseries/TimeSeriesTest.java | 55 ++++++++ 14 files changed, 600 insertions(+), 37 deletions(-) create mode 100644 src/main/java/redis/clients/jedis/timeseries/EncodingFormat.java create mode 100644 src/main/java/redis/clients/jedis/timeseries/TSAddParams.java create mode 100644 src/main/java/redis/clients/jedis/timeseries/TSIncrOrDecrByParams.java diff --git a/src/main/java/redis/clients/jedis/CommandObjects.java b/src/main/java/redis/clients/jedis/CommandObjects.java index 7226a014a79..421b81c4e2d 100644 --- a/src/main/java/redis/clients/jedis/CommandObjects.java +++ b/src/main/java/redis/clients/jedis/CommandObjects.java @@ -3946,9 +3946,15 @@ public final CommandObject tsAdd(String key, long timestamp, double value) return new CommandObject<>(commandArguments(TimeSeriesCommand.ADD).key(key).add(timestamp).add(value), BuilderFactory.LONG); } + @Deprecated public final CommandObject tsAdd(String key, long timestamp, double value, TSCreateParams createParams) { - return new CommandObject<>(commandArguments(TimeSeriesCommand.ADD).key(key) - .add(timestamp).add(value).addParams(createParams), BuilderFactory.LONG); + return new CommandObject<>(commandArguments(TimeSeriesCommand.ADD).key(key).add(timestamp).add(value) + .addParams(createParams), BuilderFactory.LONG); + } + + public final CommandObject tsAdd(String key, long timestamp, double value, TSAddParams addParams) { + return new CommandObject<>(commandArguments(TimeSeriesCommand.ADD).key(key).add(timestamp).add(value) + .addParams(addParams), BuilderFactory.LONG); } public final CommandObject> tsMAdd(Map.Entry... entries) { @@ -3968,6 +3974,11 @@ public final CommandObject tsIncrBy(String key, double value, long timesta .add(TimeSeriesKeyword.TIMESTAMP).add(timestamp), BuilderFactory.LONG); } + public final CommandObject tsIncrBy(String key, double addend, TSIncrOrDecrByParams incrByParams) { + return new CommandObject<>(commandArguments(TimeSeriesCommand.INCRBY).key(key).add(addend) + .addParams(incrByParams), BuilderFactory.LONG); + } + public final CommandObject tsDecrBy(String key, double value) { return new CommandObject<>(commandArguments(TimeSeriesCommand.DECRBY).key(key).add(value), BuilderFactory.LONG); } @@ -3977,6 +3988,11 @@ public final CommandObject tsDecrBy(String key, double value, long timesta .add(TimeSeriesKeyword.TIMESTAMP).add(timestamp), BuilderFactory.LONG); } + public final CommandObject tsDecrBy(String key, double subtrahend, TSIncrOrDecrByParams decrByParams) { + return new CommandObject<>(commandArguments(TimeSeriesCommand.DECRBY).key(key).add(subtrahend) + .addParams(decrByParams), BuilderFactory.LONG); + } + public final CommandObject> tsRange(String key, long fromTimestamp, long toTimestamp) { return new CommandObject<>(commandArguments(TimeSeriesCommand.RANGE).key(key) .add(fromTimestamp).add(toTimestamp), TimeSeriesBuilderFactory.TIMESERIES_ELEMENT_LIST); diff --git a/src/main/java/redis/clients/jedis/PipeliningBase.java b/src/main/java/redis/clients/jedis/PipeliningBase.java index 928126a7047..9967a2e6940 100644 --- a/src/main/java/redis/clients/jedis/PipeliningBase.java +++ b/src/main/java/redis/clients/jedis/PipeliningBase.java @@ -3948,6 +3948,11 @@ public Response tsAdd(String key, long timestamp, double value, TSCreatePa return appendCommand(commandObjects.tsAdd(key, timestamp, value, createParams)); } + @Override + public Response tsAdd(String key, long timestamp, double value, TSAddParams addParams) { + return appendCommand(commandObjects.tsAdd(key, timestamp, value, addParams)); + } + @Override public Response> tsMAdd(Map.Entry... entries) { return appendCommand(commandObjects.tsMAdd(entries)); @@ -3963,6 +3968,11 @@ public Response tsIncrBy(String key, double value, long timestamp) { return appendCommand(commandObjects.tsIncrBy(key, value, timestamp)); } + @Override + public Response tsIncrBy(String key, double addend, TSIncrOrDecrByParams incrByParams) { + return appendCommand(commandObjects.tsIncrBy(key, addend, incrByParams)); + } + @Override public Response tsDecrBy(String key, double value) { return appendCommand(commandObjects.tsDecrBy(key, value)); @@ -3973,6 +3983,11 @@ public Response tsDecrBy(String key, double value, long timestamp) { return appendCommand(commandObjects.tsDecrBy(key, value, timestamp)); } + @Override + public Response tsDecrBy(String key, double subtrahend, TSIncrOrDecrByParams decrByParams) { + return appendCommand(commandObjects.tsDecrBy(key, subtrahend, decrByParams)); + } + @Override public Response> tsRange(String key, long fromTimestamp, long toTimestamp) { return appendCommand(commandObjects.tsRange(key, fromTimestamp, toTimestamp)); diff --git a/src/main/java/redis/clients/jedis/UnifiedJedis.java b/src/main/java/redis/clients/jedis/UnifiedJedis.java index 2d6e77fcf0a..87ba0d8a142 100644 --- a/src/main/java/redis/clients/jedis/UnifiedJedis.java +++ b/src/main/java/redis/clients/jedis/UnifiedJedis.java @@ -4473,6 +4473,11 @@ public long tsAdd(String key, long timestamp, double value, TSCreateParams creat return executeCommand(commandObjects.tsAdd(key, timestamp, value, createParams)); } + @Override + public long tsAdd(String key, long timestamp, double value, TSAddParams addParams) { + return executeCommand(commandObjects.tsAdd(key, timestamp, value, addParams)); + } + @Override public List tsMAdd(Map.Entry... entries) { return executeCommand(commandObjects.tsMAdd(entries)); @@ -4488,6 +4493,11 @@ public long tsIncrBy(String key, double value, long timestamp) { return executeCommand(commandObjects.tsIncrBy(key, value, timestamp)); } + @Override + public long tsIncrBy(String key, double addend, TSIncrOrDecrByParams incrByParams) { + return executeCommand(commandObjects.tsIncrBy(key, addend, incrByParams)); + } + @Override public long tsDecrBy(String key, double value) { return executeCommand(commandObjects.tsDecrBy(key, value)); @@ -4498,6 +4508,11 @@ public long tsDecrBy(String key, double value, long timestamp) { return executeCommand(commandObjects.tsDecrBy(key, value, timestamp)); } + @Override + public long tsDecrBy(String key, double subtrahend, TSIncrOrDecrByParams decrByParams) { + return executeCommand(commandObjects.tsDecrBy(key, subtrahend, decrByParams)); + } + @Override public List tsRange(String key, long fromTimestamp, long toTimestamp) { return executeCommand(commandObjects.tsRange(key, fromTimestamp, toTimestamp)); diff --git a/src/main/java/redis/clients/jedis/timeseries/EncodingFormat.java b/src/main/java/redis/clients/jedis/timeseries/EncodingFormat.java new file mode 100644 index 00000000000..5130d7da251 --- /dev/null +++ b/src/main/java/redis/clients/jedis/timeseries/EncodingFormat.java @@ -0,0 +1,24 @@ +package redis.clients.jedis.timeseries; + +import redis.clients.jedis.args.Rawable; +import redis.clients.jedis.util.SafeEncoder; + +/** + * Specifies the series samples encoding format. + */ +public enum EncodingFormat implements Rawable { + + COMPRESSED, + UNCOMPRESSED; + + private final byte[] raw; + + private EncodingFormat() { + raw = SafeEncoder.encode(name()); + } + + @Override + public byte[] getRaw() { + return raw; + } +} diff --git a/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesCommands.java b/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesCommands.java index c002b94c08e..67c1b26fcf8 100644 --- a/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesCommands.java +++ b/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesCommands.java @@ -59,16 +59,33 @@ public interface RedisTimeSeriesCommands { long tsAdd(String key, long timestamp, double value); /** - * {@code TS.ADD key timestamp value [RETENTION retentionTime] [ENCODING [COMPRESSED|UNCOMPRESSED]] [CHUNK_SIZE size] [ON_DUPLICATE policy] [LABELS label value..]} - * * @param key * @param timestamp * @param value * @param createParams * @return timestamp + * @deprecated Use {@link RedisTimeSeriesCommands#tsAdd(java.lang.String, long, double, redis.clients.jedis.timeseries.TSAddParams)}. */ + @Deprecated long tsAdd(String key, long timestamp, double value, TSCreateParams createParams); + /** + * {@code TS.ADD key timestamp value + * [RETENTION retentionTime] + * [ENCODING ] + * [CHUNK_SIZE size] + * [DUPLICATE_POLICY policy] + * [ON_DUPLICATE policy_ovr] + * [LABELS label value..]} + * + * @param key + * @param timestamp + * @param value + * @param addParams + * @return timestamp + */ + long tsAdd(String key, long timestamp, double value, TSAddParams addParams); + /** * {@code TS.MADD key timestamp value [key timestamp value ...]} * @@ -81,10 +98,44 @@ public interface RedisTimeSeriesCommands { long tsIncrBy(String key, double value, long timestamp); + /** + * {@code TS.INCRBY key addend + * [TIMESTAMP timestamp] + * [RETENTION retentionPeriod] + * [ENCODING ] + * [CHUNK_SIZE size] + * [DUPLICATE_POLICY policy] + * [IGNORE ignoreMaxTimediff ignoreMaxValDiff] + * [LABELS [label value ...]]} + * + * @param key + * @param addend + * @param incrByParams + * @return timestamp + */ + long tsIncrBy(String key, double addend, TSIncrOrDecrByParams incrByParams); + long tsDecrBy(String key, double value); long tsDecrBy(String key, double value, long timestamp); + /** + * {@code TS.DECRBY key subtrahend + * [TIMESTAMP timestamp] + * [RETENTION retentionPeriod] + * [ENCODING ] + * [CHUNK_SIZE size] + * [DUPLICATE_POLICY policy] + * [IGNORE ignoreMaxTimediff ignoreMaxValDiff] + * [LABELS [label value ...]]} + * + * @param key + * @param subtrahend + * @param decrByParams + * @return timestamp + */ + long tsDecrBy(String key, double subtrahend, TSIncrOrDecrByParams decrByParams); + /** * {@code TS.RANGE key fromTimestamp toTimestamp} * diff --git a/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesPipelineCommands.java b/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesPipelineCommands.java index 288b3f195e9..b3304716ddd 100644 --- a/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesPipelineCommands.java +++ b/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesPipelineCommands.java @@ -18,18 +18,25 @@ public interface RedisTimeSeriesPipelineCommands { Response tsAdd(String key, long timestamp, double value); + @Deprecated Response tsAdd(String key, long timestamp, double value, TSCreateParams createParams); + Response tsAdd(String key, long timestamp, double value, TSAddParams addParams); + Response> tsMAdd(Map.Entry... entries); Response tsIncrBy(String key, double value); Response tsIncrBy(String key, double value, long timestamp); + Response tsIncrBy(String key, double addend, TSIncrOrDecrByParams incrByParams); + Response tsDecrBy(String key, double value); Response tsDecrBy(String key, double value, long timestamp); + Response tsDecrBy(String key, double subtrahend, TSIncrOrDecrByParams decrByParams); + Response> tsRange(String key, long fromTimestamp, long toTimestamp); Response> tsRange(String key, TSRangeParams rangeParams); diff --git a/src/main/java/redis/clients/jedis/timeseries/TSAddParams.java b/src/main/java/redis/clients/jedis/timeseries/TSAddParams.java new file mode 100644 index 00000000000..0a9713cefb8 --- /dev/null +++ b/src/main/java/redis/clients/jedis/timeseries/TSAddParams.java @@ -0,0 +1,128 @@ +package redis.clients.jedis.timeseries; + +import static redis.clients.jedis.Protocol.toByteArray; +import static redis.clients.jedis.timeseries.TimeSeriesProtocol.TimeSeriesKeyword.*; + +import java.util.LinkedHashMap; +import java.util.Map; +import redis.clients.jedis.CommandArguments; +import redis.clients.jedis.params.IParams; + +/** + * Represents optional arguments of TS.ADD command. + */ +public class TSAddParams implements IParams { + + private Long retentionPeriod; + private EncodingFormat encoding; + private Long chunkSize; + private DuplicatePolicy duplicatePolicy; + private DuplicatePolicy onDuplicate; + + private boolean ignore; + private long ignoreMaxTimediff; + private double ignoreMaxValDiff; + + private Map labels; + + public TSAddParams() { + } + + public static TSAddParams addParams() { + return new TSAddParams(); + } + + public TSAddParams retention(long retentionPeriod) { + this.retentionPeriod = retentionPeriod; + return this; + } + + public TSAddParams encoding(EncodingFormat encoding) { + this.encoding = encoding; + return this; + } + + public TSAddParams chunkSize(long chunkSize) { + this.chunkSize = chunkSize; + return this; + } + + public TSAddParams duplicatePolicy(DuplicatePolicy duplicatePolicy) { + this.duplicatePolicy = duplicatePolicy; + return this; + } + + public TSAddParams onDuplicate(DuplicatePolicy onDuplicate) { + this.onDuplicate = onDuplicate; + return this; + } + + public TSAddParams ignore(long maxTimediff, double maxValDiff) { + this.ignore = true; + this.ignoreMaxTimediff = maxTimediff; + this.ignoreMaxValDiff = maxValDiff; + return this; + } + + /** + * Set label-value pairs + * + * @param labels label-value pairs + * @return the object itself + */ + public TSAddParams labels(Map labels) { + this.labels = labels; + return this; + } + + /** + * Add label-value pair. Multiple pairs can be added through chaining. + * @param label + * @param value + * @return the object itself + */ + public TSAddParams label(String label, String value) { + if (this.labels == null) { + this.labels = new LinkedHashMap<>(); + } + this.labels.put(label, value); + return this; + } + + @Override + public void addParams(CommandArguments args) { + + if (retentionPeriod != null) { + args.add(RETENTION).add(toByteArray(retentionPeriod)); + } + + if (encoding != null) { + args.add(ENCODING).add(encoding); + } + + if (chunkSize != null) { + args.add(CHUNK_SIZE).add(toByteArray(chunkSize)); + } + + if (duplicatePolicy != null) { + args.add(DUPLICATE_POLICY).add(duplicatePolicy); + } + + if (duplicatePolicy != null) { + args.add(DUPLICATE_POLICY).add(duplicatePolicy); + } + + if (onDuplicate != null) { + args.add(ON_DUPLICATE).add(onDuplicate); + } + + if (ignore) { + args.add(IGNORE).add(ignoreMaxTimediff).add(ignoreMaxValDiff); + } + + if (labels != null) { + args.add(LABELS); + labels.entrySet().forEach((entry) -> args.add(entry.getKey()).add(entry.getValue())); + } + } +} diff --git a/src/main/java/redis/clients/jedis/timeseries/TSAlterParams.java b/src/main/java/redis/clients/jedis/timeseries/TSAlterParams.java index 4576a1b6b75..50ba9723acc 100644 --- a/src/main/java/redis/clients/jedis/timeseries/TSAlterParams.java +++ b/src/main/java/redis/clients/jedis/timeseries/TSAlterParams.java @@ -17,6 +17,11 @@ public class TSAlterParams implements IParams { private Long retentionPeriod; private Long chunkSize; private DuplicatePolicy duplicatePolicy; + + private boolean ignore; + private long ignoreMaxTimediff; + private double ignoreMaxValDiff; + private Map labels; public TSAlterParams() { @@ -41,11 +46,30 @@ public TSAlterParams duplicatePolicy(DuplicatePolicy duplicatePolicy) { return this; } + public TSAlterParams ignore(long maxTimediff, double maxValDiff) { + this.ignore = true; + this.ignoreMaxTimediff = maxTimediff; + this.ignoreMaxValDiff = maxValDiff; + return this; + } + + /** + * Set label-value pairs + * + * @param labels label-value pairs + * @return the object itself + */ public TSAlterParams labels(Map labels) { this.labels = labels; return this; } + /** + * Add label-value pair. Multiple pairs can be added through chaining. + * @param label + * @param value + * @return the object itself + */ public TSAlterParams label(String label, String value) { if (this.labels == null) { this.labels = new LinkedHashMap<>(); @@ -73,6 +97,10 @@ public void addParams(CommandArguments args) { args.add(DUPLICATE_POLICY).add(duplicatePolicy); } + if (ignore) { + args.add(IGNORE).add(ignoreMaxTimediff).add(ignoreMaxValDiff); + } + if (labels != null) { args.add(LABELS); labels.entrySet().forEach((entry) -> args.add(entry.getKey()).add(entry.getValue())); diff --git a/src/main/java/redis/clients/jedis/timeseries/TSCreateParams.java b/src/main/java/redis/clients/jedis/timeseries/TSCreateParams.java index ca07de1f01f..0611383d4d2 100644 --- a/src/main/java/redis/clients/jedis/timeseries/TSCreateParams.java +++ b/src/main/java/redis/clients/jedis/timeseries/TSCreateParams.java @@ -14,10 +14,14 @@ public class TSCreateParams implements IParams { private Long retentionPeriod; - private boolean uncompressed; - private boolean compressed; + private EncodingFormat encoding; private Long chunkSize; private DuplicatePolicy duplicatePolicy; + + private boolean ignore; + private long ignoreMaxTimediff; + private double ignoreMaxValDiff; + private Map labels; public TSCreateParams() { @@ -32,13 +36,18 @@ public TSCreateParams retention(long retentionPeriod) { return this; } + // TODO: deprecate public TSCreateParams uncompressed() { - this.uncompressed = true; - return this; + return encoding(EncodingFormat.UNCOMPRESSED); } + // TODO: deprecate public TSCreateParams compressed() { - this.compressed = true; + return encoding(EncodingFormat.COMPRESSED); + } + + public TSCreateParams encoding(EncodingFormat encoding) { + this.encoding = encoding; return this; } @@ -52,6 +61,13 @@ public TSCreateParams duplicatePolicy(DuplicatePolicy duplicatePolicy) { return this; } + public TSCreateParams ignore(long maxTimediff, double maxValDiff) { + this.ignore = true; + this.ignoreMaxTimediff = maxTimediff; + this.ignoreMaxValDiff = maxValDiff; + return this; + } + /** * Set label-value pairs * @@ -65,6 +81,9 @@ public TSCreateParams labels(Map labels) { /** * Add label-value pair. Multiple pairs can be added through chaining. + * @param label + * @param value + * @return the object itself */ public TSCreateParams label(String label, String value) { if (this.labels == null) { @@ -81,10 +100,8 @@ public void addParams(CommandArguments args) { args.add(RETENTION).add(toByteArray(retentionPeriod)); } - if (uncompressed) { - args.add(ENCODING).add(UNCOMPRESSED); - } else if (compressed) { - args.add(ENCODING).add(COMPRESSED); + if (encoding != null) { + args.add(ENCODING).add(encoding); } if (chunkSize != null) { @@ -95,6 +112,10 @@ public void addParams(CommandArguments args) { args.add(DUPLICATE_POLICY).add(duplicatePolicy); } + if (ignore) { + args.add(IGNORE).add(ignoreMaxTimediff).add(ignoreMaxValDiff); + } + if (labels != null) { args.add(LABELS); labels.entrySet().forEach((entry) -> args.add(entry.getKey()).add(entry.getValue())); diff --git a/src/main/java/redis/clients/jedis/timeseries/TSIncrOrDecrByParams.java b/src/main/java/redis/clients/jedis/timeseries/TSIncrOrDecrByParams.java new file mode 100644 index 00000000000..fde848fb5a8 --- /dev/null +++ b/src/main/java/redis/clients/jedis/timeseries/TSIncrOrDecrByParams.java @@ -0,0 +1,132 @@ +package redis.clients.jedis.timeseries; + +import static redis.clients.jedis.Protocol.toByteArray; +import static redis.clients.jedis.timeseries.TimeSeriesProtocol.TimeSeriesKeyword.*; + +import java.util.LinkedHashMap; +import java.util.Map; +import redis.clients.jedis.CommandArguments; +import redis.clients.jedis.params.IParams; + +/** + * Represents optional arguments of TS.INCRBY or TS.DECRBY commands. + */ +public class TSIncrOrDecrByParams implements IParams { + + private Long timestamp; + private Long retentionPeriod; + private EncodingFormat encoding; + private Long chunkSize; + private DuplicatePolicy duplicatePolicy; + + private boolean ignore; + private long ignoreMaxTimediff; + private double ignoreMaxValDiff; + + private Map labels; + + public TSIncrOrDecrByParams() { + } + + public static TSIncrOrDecrByParams params() { + return new TSIncrOrDecrByParams(); + } + + public static TSIncrOrDecrByParams incrByParams() { + return new TSIncrOrDecrByParams(); + } + + public static TSIncrOrDecrByParams decrByParams() { + return new TSIncrOrDecrByParams(); + } + + public TSIncrOrDecrByParams timestamp(long timestamp) { + this.timestamp = timestamp; + return this; + } + + public TSIncrOrDecrByParams retention(long retentionPeriod) { + this.retentionPeriod = retentionPeriod; + return this; + } + + public TSIncrOrDecrByParams encoding(EncodingFormat encoding) { + this.encoding = encoding; + return this; + } + + public TSIncrOrDecrByParams chunkSize(long chunkSize) { + this.chunkSize = chunkSize; + return this; + } + + public TSIncrOrDecrByParams duplicatePolicy(DuplicatePolicy duplicatePolicy) { + this.duplicatePolicy = duplicatePolicy; + return this; + } + + public TSIncrOrDecrByParams ignore(long maxTimediff, double maxValDiff) { + this.ignore = true; + this.ignoreMaxTimediff = maxTimediff; + this.ignoreMaxValDiff = maxValDiff; + return this; + } + + /** + * Set label-value pairs + * + * @param labels label-value pairs + * @return the object itself + */ + public TSIncrOrDecrByParams labels(Map labels) { + this.labels = labels; + return this; + } + + /** + * Add label-value pair. Multiple pairs can be added through chaining. + * @param label + * @param value + * @return the object itself + */ + public TSIncrOrDecrByParams label(String label, String value) { + if (this.labels == null) { + this.labels = new LinkedHashMap<>(); + } + this.labels.put(label, value); + return this; + } + + @Override + public void addParams(CommandArguments args) { + + if (timestamp != null) { + args.add(TIMESTAMP).add(timestamp); + } + + if (retentionPeriod != null) { + args.add(RETENTION).add(toByteArray(retentionPeriod)); + } + + if (encoding != null) { + args.add(ENCODING).add(encoding); + } + + if (chunkSize != null) { + args.add(CHUNK_SIZE).add(toByteArray(chunkSize)); + } + + if (duplicatePolicy != null) { + args.add(DUPLICATE_POLICY).add(duplicatePolicy); + } + + if (ignore) { + args.add(IGNORE).add(ignoreMaxTimediff).add(ignoreMaxValDiff); + } + + if (labels != null) { + args.add(LABELS); + labels.entrySet().forEach((entry) -> args.add(entry.getKey()).add(entry.getValue())); + } + } +} diff --git a/src/main/java/redis/clients/jedis/timeseries/TimeSeriesProtocol.java b/src/main/java/redis/clients/jedis/timeseries/TimeSeriesProtocol.java index 2476979f0d0..384a4549218 100644 --- a/src/main/java/redis/clients/jedis/timeseries/TimeSeriesProtocol.java +++ b/src/main/java/redis/clients/jedis/timeseries/TimeSeriesProtocol.java @@ -57,6 +57,7 @@ public enum TimeSeriesKeyword implements Rawable { UNCOMPRESSED, CHUNK_SIZE, DUPLICATE_POLICY, + IGNORE, ON_DUPLICATE, ALIGN, FILTER_BY_TS, diff --git a/src/test/java/redis/clients/jedis/mocked/pipeline/PipeliningBaseTimeSeriesCommandsTest.java b/src/test/java/redis/clients/jedis/mocked/pipeline/PipeliningBaseTimeSeriesCommandsTest.java index 44e653c0116..b8cfb85dc8b 100644 --- a/src/test/java/redis/clients/jedis/mocked/pipeline/PipeliningBaseTimeSeriesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/mocked/pipeline/PipeliningBaseTimeSeriesCommandsTest.java @@ -3,6 +3,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.is; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.util.AbstractMap; @@ -11,17 +12,7 @@ import org.junit.Test; import redis.clients.jedis.Response; -import redis.clients.jedis.timeseries.AggregationType; -import redis.clients.jedis.timeseries.TSAlterParams; -import redis.clients.jedis.timeseries.TSCreateParams; -import redis.clients.jedis.timeseries.TSElement; -import redis.clients.jedis.timeseries.TSGetParams; -import redis.clients.jedis.timeseries.TSInfo; -import redis.clients.jedis.timeseries.TSMGetElement; -import redis.clients.jedis.timeseries.TSMGetParams; -import redis.clients.jedis.timeseries.TSMRangeElements; -import redis.clients.jedis.timeseries.TSMRangeParams; -import redis.clients.jedis.timeseries.TSRangeParams; +import redis.clients.jedis.timeseries.*; public class PipeliningBaseTimeSeriesCommandsTest extends PipeliningBaseMockedTestBase { @@ -57,6 +48,18 @@ public void testTsAddWithTimestampAndParams() { assertThat(response, is(predefinedResponse)); } + @Test + public void testTsAddWithParams() { + TSAddParams addParams = mock(TSAddParams.class); + + when(commandObjects.tsAdd("myTimeSeries", 1000L, 42.0, addParams)).thenReturn(longCommandObject); + + Response response = pipeliningBase.tsAdd("myTimeSeries", 1000L, 42.0, addParams); + + assertThat(commands, contains(longCommandObject)); + assertThat(response, is(predefinedResponse)); + } + @Test public void testTsAlter() { TSAlterParams alterParams = TSAlterParams.alterParams(); @@ -138,6 +141,17 @@ public void testTsDecrByWithTimestamp() { assertThat(response, is(predefinedResponse)); } + @Test + public void testTsDecrByWithParams() { + TSIncrOrDecrByParams DecrByParams = mock(TSIncrOrDecrByParams.class); + when(commandObjects.tsDecrBy("myTimeSeries", 1.0, DecrByParams)).thenReturn(longCommandObject); + + Response response = pipeliningBase.tsDecrBy("myTimeSeries", 1.0, DecrByParams); + + assertThat(commands, contains(longCommandObject)); + assertThat(response, is(predefinedResponse)); + } + @Test public void testTsDel() { when(commandObjects.tsDel("myTimeSeries", 1000L, 2000L)).thenReturn(longCommandObject); @@ -200,6 +214,17 @@ public void testTsIncrByWithTimestamp() { assertThat(response, is(predefinedResponse)); } + @Test + public void testTsIncrByWithParams() { + TSIncrOrDecrByParams incrByParams = mock(TSIncrOrDecrByParams.class); + when(commandObjects.tsIncrBy("myTimeSeries", 1.0, incrByParams)).thenReturn(longCommandObject); + + Response response = pipeliningBase.tsIncrBy("myTimeSeries", 1.0, incrByParams); + + assertThat(commands, contains(longCommandObject)); + assertThat(response, is(predefinedResponse)); + } + @Test public void testTsInfo() { when(commandObjects.tsInfo("myTimeSeries")).thenReturn(tsInfoCommandObject); diff --git a/src/test/java/redis/clients/jedis/mocked/unified/UnifiedJedisTimeSeriesCommandsTest.java b/src/test/java/redis/clients/jedis/mocked/unified/UnifiedJedisTimeSeriesCommandsTest.java index d9e06ce77cb..53c673da49d 100644 --- a/src/test/java/redis/clients/jedis/mocked/unified/UnifiedJedisTimeSeriesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/mocked/unified/UnifiedJedisTimeSeriesCommandsTest.java @@ -15,17 +15,7 @@ import java.util.Map; import org.junit.Test; -import redis.clients.jedis.timeseries.AggregationType; -import redis.clients.jedis.timeseries.TSAlterParams; -import redis.clients.jedis.timeseries.TSCreateParams; -import redis.clients.jedis.timeseries.TSElement; -import redis.clients.jedis.timeseries.TSGetParams; -import redis.clients.jedis.timeseries.TSInfo; -import redis.clients.jedis.timeseries.TSMGetElement; -import redis.clients.jedis.timeseries.TSMGetParams; -import redis.clients.jedis.timeseries.TSMRangeElements; -import redis.clients.jedis.timeseries.TSMRangeParams; -import redis.clients.jedis.timeseries.TSRangeParams; +import redis.clients.jedis.timeseries.*; public class UnifiedJedisTimeSeriesCommandsTest extends UnifiedJedisMockedTestBase { @@ -83,6 +73,25 @@ public void testTsAddWithTimestampAndParams() { verify(commandObjects).tsAdd(key, timestamp, value, createParams); } + @Test + public void testTsAddWithParams() { + String key = "testKey"; + long timestamp = 1582605077000L; + double value = 123.45; + TSAddParams createParams = mock(TSAddParams.class); + long expectedResponse = timestamp; // Timestamp of the added value + + when(commandObjects.tsAdd(key, timestamp, value, createParams)).thenReturn(longCommandObject); + when(commandExecutor.executeCommand(longCommandObject)).thenReturn(expectedResponse); + + long result = jedis.tsAdd(key, timestamp, value, createParams); + + assertEquals(expectedResponse, result); + + verify(commandExecutor).executeCommand(longCommandObject); + verify(commandObjects).tsAdd(key, timestamp, value, createParams); + } + @Test public void testTsAlter() { String key = "testKey"; @@ -194,7 +203,7 @@ public void testTsDecrByWithTimestamp() { String key = "testKey"; double value = 1.5; long timestamp = 1582605077000L; - long expectedResponse = -1L; // Assuming the decrement results in a total of -1 + long expectedResponse = 5L; when(commandObjects.tsDecrBy(key, value, timestamp)).thenReturn(longCommandObject); when(commandExecutor.executeCommand(longCommandObject)).thenReturn(expectedResponse); @@ -207,6 +216,24 @@ public void testTsDecrByWithTimestamp() { verify(commandObjects).tsDecrBy(key, value, timestamp); } + @Test + public void testTsDecrByWithParams() { + String key = "testKey"; + double value = 1.5; + TSIncrOrDecrByParams decrByParams = mock(TSIncrOrDecrByParams.class); + long expectedResponse = 5L; + + when(commandObjects.tsDecrBy(key, value, decrByParams)).thenReturn(longCommandObject); + when(commandExecutor.executeCommand(longCommandObject)).thenReturn(expectedResponse); + + long result = jedis.tsDecrBy(key, value, decrByParams); + + assertEquals(expectedResponse, result); + + verify(commandExecutor).executeCommand(longCommandObject); + verify(commandObjects).tsDecrBy(key, value, decrByParams); + } + @Test public void testTsDel() { String key = "testKey"; @@ -297,7 +324,7 @@ public void testTsIncrByWithTimestamp() { String key = "testKey"; double value = 2.5; long timestamp = 1582605077000L; - long expectedResponse = 5L; // Assuming the increment results in a total of 5 + long expectedResponse = 5L; when(commandObjects.tsIncrBy(key, value, timestamp)).thenReturn(longCommandObject); when(commandExecutor.executeCommand(longCommandObject)).thenReturn(expectedResponse); @@ -310,6 +337,24 @@ public void testTsIncrByWithTimestamp() { verify(commandObjects).tsIncrBy(key, value, timestamp); } + @Test + public void testTsIncrByWithParams() { + String key = "testKey"; + double value = 2.5; + TSIncrOrDecrByParams incrByParams = mock(TSIncrOrDecrByParams.class); + long expectedResponse = 5L; + + when(commandObjects.tsIncrBy(key, value, incrByParams)).thenReturn(longCommandObject); + when(commandExecutor.executeCommand(longCommandObject)).thenReturn(expectedResponse); + + long result = jedis.tsIncrBy(key, value, incrByParams); + + assertEquals(expectedResponse, result); + + verify(commandExecutor).executeCommand(longCommandObject); + verify(commandObjects).tsIncrBy(key, value, incrByParams); + } + @Test public void testTsInfo() { String key = "testKey"; diff --git a/src/test/java/redis/clients/jedis/modules/timeseries/TimeSeriesTest.java b/src/test/java/redis/clients/jedis/modules/timeseries/TimeSeriesTest.java index fe0f7d1604a..dd0688f080f 100644 --- a/src/test/java/redis/clients/jedis/modules/timeseries/TimeSeriesTest.java +++ b/src/test/java/redis/clients/jedis/modules/timeseries/TimeSeriesTest.java @@ -122,6 +122,23 @@ public void testAlter() { assertEquals("v33", info.getLabel("l3")); } + @Test + public void createAndAlterParams() { + Map labels = new HashMap<>(); + labels.put("l1", "v1"); + labels.put("l2", "v2"); + + assertEquals("OK", client.tsCreate("ts-params", + TSCreateParams.createParams().retention(60000).encoding(EncodingFormat.UNCOMPRESSED).chunkSize(4096) + .duplicatePolicy(DuplicatePolicy.BLOCK).ignore(50, 12.5).labels(labels))); + + labels.put("l1", "v11"); + labels.remove("l2"); + labels.put("l3", "v33"); + assertEquals("OK", client.tsAlter("ts-params", TSAlterParams.alterParams().retention(15000).chunkSize(8192) + .duplicatePolicy(DuplicatePolicy.SUM).ignore(50, 12.5).labels(labels))); + } + @Test public void testRule() { assertEquals("OK", client.tsCreate("source")); @@ -147,6 +164,21 @@ public void testRule() { } } + @Test + public void addParams() { + Map labels = new HashMap<>(); + labels.put("l1", "v1"); + labels.put("l2", "v2"); + + assertEquals(1000L, client.tsAdd("add1", 1000L, 1.1, + TSAddParams.addParams().retention(10000).encoding(EncodingFormat.UNCOMPRESSED).chunkSize(1000) + .duplicatePolicy(DuplicatePolicy.FIRST).onDuplicate(DuplicatePolicy.LAST).ignore(50, 12.5).labels(labels))); + + assertEquals(1000L, client.tsAdd("add2", 1000L, 1.1, + TSAddParams.addParams().retention(10000).encoding(EncodingFormat.COMPRESSED).chunkSize(1000) + .duplicatePolicy(DuplicatePolicy.MIN).onDuplicate(DuplicatePolicy.MAX).ignore(50, 12.5).labels(labels))); + } + @Test public void testAdd() { Map labels = new HashMap<>(); @@ -414,6 +446,29 @@ public void testIncrByDecrBy() throws InterruptedException { client.tsDecrBy("seriesIncDec", 33); } + @Test + public void incrByDecrByParams() { + Map labels = new HashMap<>(); + labels.put("l1", "v1"); + labels.put("l2", "v2"); + + assertEquals(1000L, client.tsIncrBy("incr1", 1.1, + TSIncrOrDecrByParams.incrByParams().timestamp(1000).retention(10000).encoding(EncodingFormat.UNCOMPRESSED) + .chunkSize(1000).duplicatePolicy(DuplicatePolicy.FIRST).ignore(50, 12.5).labels(labels))); + + assertEquals(1000L, client.tsIncrBy("incr2", 1.1, + TSIncrOrDecrByParams.incrByParams().timestamp(1000).retention(10000).encoding(EncodingFormat.COMPRESSED) + .chunkSize(1000).duplicatePolicy(DuplicatePolicy.MIN).ignore(50, 12.5).labels(labels))); + + assertEquals(1000L, client.tsDecrBy("decr1", 1.1, + TSIncrOrDecrByParams.decrByParams().timestamp(1000).retention(10000).encoding(EncodingFormat.COMPRESSED) + .chunkSize(1000).duplicatePolicy(DuplicatePolicy.LAST).ignore(50, 12.5).labels(labels))); + + assertEquals(1000L, client.tsDecrBy("decr2", 1.1, + TSIncrOrDecrByParams.decrByParams().timestamp(1000).retention(10000).encoding(EncodingFormat.UNCOMPRESSED) + .chunkSize(1000).duplicatePolicy(DuplicatePolicy.MAX).ignore(50, 12.5).labels(labels))); + } + @Test public void align() { client.tsAdd("align", 1, 10d); From 619f8e33c1469d759f7e35e441f7a656a3604229 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Fri, 14 Jun 2024 10:25:30 +0600 Subject: [PATCH 26/51] Revert "Support IGNORE and other optional arguments for timeseries commands (#3860)" This reverts commit e7503d78f86f166028327e45ae1150bd96f2271b. The commit e7503d78f86f166028327e45ae1150bd96f2271b is merged (cherry-picked) into 5.2.0 branch by commit ac18fd00fd919b2f1b2294a2311a56d59fffd33c. --- .../redis/clients/jedis/CommandObjects.java | 20 +-- .../redis/clients/jedis/PipeliningBase.java | 15 -- .../redis/clients/jedis/UnifiedJedis.java | 15 -- .../jedis/timeseries/EncodingFormat.java | 24 ---- .../timeseries/RedisTimeSeriesCommands.java | 55 +------- .../RedisTimeSeriesPipelineCommands.java | 7 - .../clients/jedis/timeseries/TSAddParams.java | 128 ----------------- .../jedis/timeseries/TSAlterParams.java | 28 ---- .../jedis/timeseries/TSCreateParams.java | 39 ++---- .../timeseries/TSIncrOrDecrByParams.java | 132 ------------------ .../jedis/timeseries/TimeSeriesProtocol.java | 1 - .../PipeliningBaseTimeSeriesCommandsTest.java | 47 ++----- .../UnifiedJedisTimeSeriesCommandsTest.java | 71 ++-------- .../modules/timeseries/TimeSeriesTest.java | 55 -------- 14 files changed, 37 insertions(+), 600 deletions(-) delete mode 100644 src/main/java/redis/clients/jedis/timeseries/EncodingFormat.java delete mode 100644 src/main/java/redis/clients/jedis/timeseries/TSAddParams.java delete mode 100644 src/main/java/redis/clients/jedis/timeseries/TSIncrOrDecrByParams.java diff --git a/src/main/java/redis/clients/jedis/CommandObjects.java b/src/main/java/redis/clients/jedis/CommandObjects.java index 421b81c4e2d..7226a014a79 100644 --- a/src/main/java/redis/clients/jedis/CommandObjects.java +++ b/src/main/java/redis/clients/jedis/CommandObjects.java @@ -3946,15 +3946,9 @@ public final CommandObject tsAdd(String key, long timestamp, double value) return new CommandObject<>(commandArguments(TimeSeriesCommand.ADD).key(key).add(timestamp).add(value), BuilderFactory.LONG); } - @Deprecated public final CommandObject tsAdd(String key, long timestamp, double value, TSCreateParams createParams) { - return new CommandObject<>(commandArguments(TimeSeriesCommand.ADD).key(key).add(timestamp).add(value) - .addParams(createParams), BuilderFactory.LONG); - } - - public final CommandObject tsAdd(String key, long timestamp, double value, TSAddParams addParams) { - return new CommandObject<>(commandArguments(TimeSeriesCommand.ADD).key(key).add(timestamp).add(value) - .addParams(addParams), BuilderFactory.LONG); + return new CommandObject<>(commandArguments(TimeSeriesCommand.ADD).key(key) + .add(timestamp).add(value).addParams(createParams), BuilderFactory.LONG); } public final CommandObject> tsMAdd(Map.Entry... entries) { @@ -3974,11 +3968,6 @@ public final CommandObject tsIncrBy(String key, double value, long timesta .add(TimeSeriesKeyword.TIMESTAMP).add(timestamp), BuilderFactory.LONG); } - public final CommandObject tsIncrBy(String key, double addend, TSIncrOrDecrByParams incrByParams) { - return new CommandObject<>(commandArguments(TimeSeriesCommand.INCRBY).key(key).add(addend) - .addParams(incrByParams), BuilderFactory.LONG); - } - public final CommandObject tsDecrBy(String key, double value) { return new CommandObject<>(commandArguments(TimeSeriesCommand.DECRBY).key(key).add(value), BuilderFactory.LONG); } @@ -3988,11 +3977,6 @@ public final CommandObject tsDecrBy(String key, double value, long timesta .add(TimeSeriesKeyword.TIMESTAMP).add(timestamp), BuilderFactory.LONG); } - public final CommandObject tsDecrBy(String key, double subtrahend, TSIncrOrDecrByParams decrByParams) { - return new CommandObject<>(commandArguments(TimeSeriesCommand.DECRBY).key(key).add(subtrahend) - .addParams(decrByParams), BuilderFactory.LONG); - } - public final CommandObject> tsRange(String key, long fromTimestamp, long toTimestamp) { return new CommandObject<>(commandArguments(TimeSeriesCommand.RANGE).key(key) .add(fromTimestamp).add(toTimestamp), TimeSeriesBuilderFactory.TIMESERIES_ELEMENT_LIST); diff --git a/src/main/java/redis/clients/jedis/PipeliningBase.java b/src/main/java/redis/clients/jedis/PipeliningBase.java index 9967a2e6940..928126a7047 100644 --- a/src/main/java/redis/clients/jedis/PipeliningBase.java +++ b/src/main/java/redis/clients/jedis/PipeliningBase.java @@ -3948,11 +3948,6 @@ public Response tsAdd(String key, long timestamp, double value, TSCreatePa return appendCommand(commandObjects.tsAdd(key, timestamp, value, createParams)); } - @Override - public Response tsAdd(String key, long timestamp, double value, TSAddParams addParams) { - return appendCommand(commandObjects.tsAdd(key, timestamp, value, addParams)); - } - @Override public Response> tsMAdd(Map.Entry... entries) { return appendCommand(commandObjects.tsMAdd(entries)); @@ -3968,11 +3963,6 @@ public Response tsIncrBy(String key, double value, long timestamp) { return appendCommand(commandObjects.tsIncrBy(key, value, timestamp)); } - @Override - public Response tsIncrBy(String key, double addend, TSIncrOrDecrByParams incrByParams) { - return appendCommand(commandObjects.tsIncrBy(key, addend, incrByParams)); - } - @Override public Response tsDecrBy(String key, double value) { return appendCommand(commandObjects.tsDecrBy(key, value)); @@ -3983,11 +3973,6 @@ public Response tsDecrBy(String key, double value, long timestamp) { return appendCommand(commandObjects.tsDecrBy(key, value, timestamp)); } - @Override - public Response tsDecrBy(String key, double subtrahend, TSIncrOrDecrByParams decrByParams) { - return appendCommand(commandObjects.tsDecrBy(key, subtrahend, decrByParams)); - } - @Override public Response> tsRange(String key, long fromTimestamp, long toTimestamp) { return appendCommand(commandObjects.tsRange(key, fromTimestamp, toTimestamp)); diff --git a/src/main/java/redis/clients/jedis/UnifiedJedis.java b/src/main/java/redis/clients/jedis/UnifiedJedis.java index 87ba0d8a142..2d6e77fcf0a 100644 --- a/src/main/java/redis/clients/jedis/UnifiedJedis.java +++ b/src/main/java/redis/clients/jedis/UnifiedJedis.java @@ -4473,11 +4473,6 @@ public long tsAdd(String key, long timestamp, double value, TSCreateParams creat return executeCommand(commandObjects.tsAdd(key, timestamp, value, createParams)); } - @Override - public long tsAdd(String key, long timestamp, double value, TSAddParams addParams) { - return executeCommand(commandObjects.tsAdd(key, timestamp, value, addParams)); - } - @Override public List tsMAdd(Map.Entry... entries) { return executeCommand(commandObjects.tsMAdd(entries)); @@ -4493,11 +4488,6 @@ public long tsIncrBy(String key, double value, long timestamp) { return executeCommand(commandObjects.tsIncrBy(key, value, timestamp)); } - @Override - public long tsIncrBy(String key, double addend, TSIncrOrDecrByParams incrByParams) { - return executeCommand(commandObjects.tsIncrBy(key, addend, incrByParams)); - } - @Override public long tsDecrBy(String key, double value) { return executeCommand(commandObjects.tsDecrBy(key, value)); @@ -4508,11 +4498,6 @@ public long tsDecrBy(String key, double value, long timestamp) { return executeCommand(commandObjects.tsDecrBy(key, value, timestamp)); } - @Override - public long tsDecrBy(String key, double subtrahend, TSIncrOrDecrByParams decrByParams) { - return executeCommand(commandObjects.tsDecrBy(key, subtrahend, decrByParams)); - } - @Override public List tsRange(String key, long fromTimestamp, long toTimestamp) { return executeCommand(commandObjects.tsRange(key, fromTimestamp, toTimestamp)); diff --git a/src/main/java/redis/clients/jedis/timeseries/EncodingFormat.java b/src/main/java/redis/clients/jedis/timeseries/EncodingFormat.java deleted file mode 100644 index 5130d7da251..00000000000 --- a/src/main/java/redis/clients/jedis/timeseries/EncodingFormat.java +++ /dev/null @@ -1,24 +0,0 @@ -package redis.clients.jedis.timeseries; - -import redis.clients.jedis.args.Rawable; -import redis.clients.jedis.util.SafeEncoder; - -/** - * Specifies the series samples encoding format. - */ -public enum EncodingFormat implements Rawable { - - COMPRESSED, - UNCOMPRESSED; - - private final byte[] raw; - - private EncodingFormat() { - raw = SafeEncoder.encode(name()); - } - - @Override - public byte[] getRaw() { - return raw; - } -} diff --git a/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesCommands.java b/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesCommands.java index 67c1b26fcf8..c002b94c08e 100644 --- a/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesCommands.java +++ b/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesCommands.java @@ -59,33 +59,16 @@ public interface RedisTimeSeriesCommands { long tsAdd(String key, long timestamp, double value); /** + * {@code TS.ADD key timestamp value [RETENTION retentionTime] [ENCODING [COMPRESSED|UNCOMPRESSED]] [CHUNK_SIZE size] [ON_DUPLICATE policy] [LABELS label value..]} + * * @param key * @param timestamp * @param value * @param createParams * @return timestamp - * @deprecated Use {@link RedisTimeSeriesCommands#tsAdd(java.lang.String, long, double, redis.clients.jedis.timeseries.TSAddParams)}. */ - @Deprecated long tsAdd(String key, long timestamp, double value, TSCreateParams createParams); - /** - * {@code TS.ADD key timestamp value - * [RETENTION retentionTime] - * [ENCODING ] - * [CHUNK_SIZE size] - * [DUPLICATE_POLICY policy] - * [ON_DUPLICATE policy_ovr] - * [LABELS label value..]} - * - * @param key - * @param timestamp - * @param value - * @param addParams - * @return timestamp - */ - long tsAdd(String key, long timestamp, double value, TSAddParams addParams); - /** * {@code TS.MADD key timestamp value [key timestamp value ...]} * @@ -98,44 +81,10 @@ public interface RedisTimeSeriesCommands { long tsIncrBy(String key, double value, long timestamp); - /** - * {@code TS.INCRBY key addend - * [TIMESTAMP timestamp] - * [RETENTION retentionPeriod] - * [ENCODING ] - * [CHUNK_SIZE size] - * [DUPLICATE_POLICY policy] - * [IGNORE ignoreMaxTimediff ignoreMaxValDiff] - * [LABELS [label value ...]]} - * - * @param key - * @param addend - * @param incrByParams - * @return timestamp - */ - long tsIncrBy(String key, double addend, TSIncrOrDecrByParams incrByParams); - long tsDecrBy(String key, double value); long tsDecrBy(String key, double value, long timestamp); - /** - * {@code TS.DECRBY key subtrahend - * [TIMESTAMP timestamp] - * [RETENTION retentionPeriod] - * [ENCODING ] - * [CHUNK_SIZE size] - * [DUPLICATE_POLICY policy] - * [IGNORE ignoreMaxTimediff ignoreMaxValDiff] - * [LABELS [label value ...]]} - * - * @param key - * @param subtrahend - * @param decrByParams - * @return timestamp - */ - long tsDecrBy(String key, double subtrahend, TSIncrOrDecrByParams decrByParams); - /** * {@code TS.RANGE key fromTimestamp toTimestamp} * diff --git a/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesPipelineCommands.java b/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesPipelineCommands.java index b3304716ddd..288b3f195e9 100644 --- a/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesPipelineCommands.java +++ b/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesPipelineCommands.java @@ -18,25 +18,18 @@ public interface RedisTimeSeriesPipelineCommands { Response tsAdd(String key, long timestamp, double value); - @Deprecated Response tsAdd(String key, long timestamp, double value, TSCreateParams createParams); - Response tsAdd(String key, long timestamp, double value, TSAddParams addParams); - Response> tsMAdd(Map.Entry... entries); Response tsIncrBy(String key, double value); Response tsIncrBy(String key, double value, long timestamp); - Response tsIncrBy(String key, double addend, TSIncrOrDecrByParams incrByParams); - Response tsDecrBy(String key, double value); Response tsDecrBy(String key, double value, long timestamp); - Response tsDecrBy(String key, double subtrahend, TSIncrOrDecrByParams decrByParams); - Response> tsRange(String key, long fromTimestamp, long toTimestamp); Response> tsRange(String key, TSRangeParams rangeParams); diff --git a/src/main/java/redis/clients/jedis/timeseries/TSAddParams.java b/src/main/java/redis/clients/jedis/timeseries/TSAddParams.java deleted file mode 100644 index 0a9713cefb8..00000000000 --- a/src/main/java/redis/clients/jedis/timeseries/TSAddParams.java +++ /dev/null @@ -1,128 +0,0 @@ -package redis.clients.jedis.timeseries; - -import static redis.clients.jedis.Protocol.toByteArray; -import static redis.clients.jedis.timeseries.TimeSeriesProtocol.TimeSeriesKeyword.*; - -import java.util.LinkedHashMap; -import java.util.Map; -import redis.clients.jedis.CommandArguments; -import redis.clients.jedis.params.IParams; - -/** - * Represents optional arguments of TS.ADD command. - */ -public class TSAddParams implements IParams { - - private Long retentionPeriod; - private EncodingFormat encoding; - private Long chunkSize; - private DuplicatePolicy duplicatePolicy; - private DuplicatePolicy onDuplicate; - - private boolean ignore; - private long ignoreMaxTimediff; - private double ignoreMaxValDiff; - - private Map labels; - - public TSAddParams() { - } - - public static TSAddParams addParams() { - return new TSAddParams(); - } - - public TSAddParams retention(long retentionPeriod) { - this.retentionPeriod = retentionPeriod; - return this; - } - - public TSAddParams encoding(EncodingFormat encoding) { - this.encoding = encoding; - return this; - } - - public TSAddParams chunkSize(long chunkSize) { - this.chunkSize = chunkSize; - return this; - } - - public TSAddParams duplicatePolicy(DuplicatePolicy duplicatePolicy) { - this.duplicatePolicy = duplicatePolicy; - return this; - } - - public TSAddParams onDuplicate(DuplicatePolicy onDuplicate) { - this.onDuplicate = onDuplicate; - return this; - } - - public TSAddParams ignore(long maxTimediff, double maxValDiff) { - this.ignore = true; - this.ignoreMaxTimediff = maxTimediff; - this.ignoreMaxValDiff = maxValDiff; - return this; - } - - /** - * Set label-value pairs - * - * @param labels label-value pairs - * @return the object itself - */ - public TSAddParams labels(Map labels) { - this.labels = labels; - return this; - } - - /** - * Add label-value pair. Multiple pairs can be added through chaining. - * @param label - * @param value - * @return the object itself - */ - public TSAddParams label(String label, String value) { - if (this.labels == null) { - this.labels = new LinkedHashMap<>(); - } - this.labels.put(label, value); - return this; - } - - @Override - public void addParams(CommandArguments args) { - - if (retentionPeriod != null) { - args.add(RETENTION).add(toByteArray(retentionPeriod)); - } - - if (encoding != null) { - args.add(ENCODING).add(encoding); - } - - if (chunkSize != null) { - args.add(CHUNK_SIZE).add(toByteArray(chunkSize)); - } - - if (duplicatePolicy != null) { - args.add(DUPLICATE_POLICY).add(duplicatePolicy); - } - - if (duplicatePolicy != null) { - args.add(DUPLICATE_POLICY).add(duplicatePolicy); - } - - if (onDuplicate != null) { - args.add(ON_DUPLICATE).add(onDuplicate); - } - - if (ignore) { - args.add(IGNORE).add(ignoreMaxTimediff).add(ignoreMaxValDiff); - } - - if (labels != null) { - args.add(LABELS); - labels.entrySet().forEach((entry) -> args.add(entry.getKey()).add(entry.getValue())); - } - } -} diff --git a/src/main/java/redis/clients/jedis/timeseries/TSAlterParams.java b/src/main/java/redis/clients/jedis/timeseries/TSAlterParams.java index 50ba9723acc..4576a1b6b75 100644 --- a/src/main/java/redis/clients/jedis/timeseries/TSAlterParams.java +++ b/src/main/java/redis/clients/jedis/timeseries/TSAlterParams.java @@ -17,11 +17,6 @@ public class TSAlterParams implements IParams { private Long retentionPeriod; private Long chunkSize; private DuplicatePolicy duplicatePolicy; - - private boolean ignore; - private long ignoreMaxTimediff; - private double ignoreMaxValDiff; - private Map labels; public TSAlterParams() { @@ -46,30 +41,11 @@ public TSAlterParams duplicatePolicy(DuplicatePolicy duplicatePolicy) { return this; } - public TSAlterParams ignore(long maxTimediff, double maxValDiff) { - this.ignore = true; - this.ignoreMaxTimediff = maxTimediff; - this.ignoreMaxValDiff = maxValDiff; - return this; - } - - /** - * Set label-value pairs - * - * @param labels label-value pairs - * @return the object itself - */ public TSAlterParams labels(Map labels) { this.labels = labels; return this; } - /** - * Add label-value pair. Multiple pairs can be added through chaining. - * @param label - * @param value - * @return the object itself - */ public TSAlterParams label(String label, String value) { if (this.labels == null) { this.labels = new LinkedHashMap<>(); @@ -97,10 +73,6 @@ public void addParams(CommandArguments args) { args.add(DUPLICATE_POLICY).add(duplicatePolicy); } - if (ignore) { - args.add(IGNORE).add(ignoreMaxTimediff).add(ignoreMaxValDiff); - } - if (labels != null) { args.add(LABELS); labels.entrySet().forEach((entry) -> args.add(entry.getKey()).add(entry.getValue())); diff --git a/src/main/java/redis/clients/jedis/timeseries/TSCreateParams.java b/src/main/java/redis/clients/jedis/timeseries/TSCreateParams.java index 0611383d4d2..ca07de1f01f 100644 --- a/src/main/java/redis/clients/jedis/timeseries/TSCreateParams.java +++ b/src/main/java/redis/clients/jedis/timeseries/TSCreateParams.java @@ -14,14 +14,10 @@ public class TSCreateParams implements IParams { private Long retentionPeriod; - private EncodingFormat encoding; + private boolean uncompressed; + private boolean compressed; private Long chunkSize; private DuplicatePolicy duplicatePolicy; - - private boolean ignore; - private long ignoreMaxTimediff; - private double ignoreMaxValDiff; - private Map labels; public TSCreateParams() { @@ -36,18 +32,13 @@ public TSCreateParams retention(long retentionPeriod) { return this; } - // TODO: deprecate public TSCreateParams uncompressed() { - return encoding(EncodingFormat.UNCOMPRESSED); + this.uncompressed = true; + return this; } - // TODO: deprecate public TSCreateParams compressed() { - return encoding(EncodingFormat.COMPRESSED); - } - - public TSCreateParams encoding(EncodingFormat encoding) { - this.encoding = encoding; + this.compressed = true; return this; } @@ -61,13 +52,6 @@ public TSCreateParams duplicatePolicy(DuplicatePolicy duplicatePolicy) { return this; } - public TSCreateParams ignore(long maxTimediff, double maxValDiff) { - this.ignore = true; - this.ignoreMaxTimediff = maxTimediff; - this.ignoreMaxValDiff = maxValDiff; - return this; - } - /** * Set label-value pairs * @@ -81,9 +65,6 @@ public TSCreateParams labels(Map labels) { /** * Add label-value pair. Multiple pairs can be added through chaining. - * @param label - * @param value - * @return the object itself */ public TSCreateParams label(String label, String value) { if (this.labels == null) { @@ -100,8 +81,10 @@ public void addParams(CommandArguments args) { args.add(RETENTION).add(toByteArray(retentionPeriod)); } - if (encoding != null) { - args.add(ENCODING).add(encoding); + if (uncompressed) { + args.add(ENCODING).add(UNCOMPRESSED); + } else if (compressed) { + args.add(ENCODING).add(COMPRESSED); } if (chunkSize != null) { @@ -112,10 +95,6 @@ public void addParams(CommandArguments args) { args.add(DUPLICATE_POLICY).add(duplicatePolicy); } - if (ignore) { - args.add(IGNORE).add(ignoreMaxTimediff).add(ignoreMaxValDiff); - } - if (labels != null) { args.add(LABELS); labels.entrySet().forEach((entry) -> args.add(entry.getKey()).add(entry.getValue())); diff --git a/src/main/java/redis/clients/jedis/timeseries/TSIncrOrDecrByParams.java b/src/main/java/redis/clients/jedis/timeseries/TSIncrOrDecrByParams.java deleted file mode 100644 index fde848fb5a8..00000000000 --- a/src/main/java/redis/clients/jedis/timeseries/TSIncrOrDecrByParams.java +++ /dev/null @@ -1,132 +0,0 @@ -package redis.clients.jedis.timeseries; - -import static redis.clients.jedis.Protocol.toByteArray; -import static redis.clients.jedis.timeseries.TimeSeriesProtocol.TimeSeriesKeyword.*; - -import java.util.LinkedHashMap; -import java.util.Map; -import redis.clients.jedis.CommandArguments; -import redis.clients.jedis.params.IParams; - -/** - * Represents optional arguments of TS.INCRBY or TS.DECRBY commands. - */ -public class TSIncrOrDecrByParams implements IParams { - - private Long timestamp; - private Long retentionPeriod; - private EncodingFormat encoding; - private Long chunkSize; - private DuplicatePolicy duplicatePolicy; - - private boolean ignore; - private long ignoreMaxTimediff; - private double ignoreMaxValDiff; - - private Map labels; - - public TSIncrOrDecrByParams() { - } - - public static TSIncrOrDecrByParams params() { - return new TSIncrOrDecrByParams(); - } - - public static TSIncrOrDecrByParams incrByParams() { - return new TSIncrOrDecrByParams(); - } - - public static TSIncrOrDecrByParams decrByParams() { - return new TSIncrOrDecrByParams(); - } - - public TSIncrOrDecrByParams timestamp(long timestamp) { - this.timestamp = timestamp; - return this; - } - - public TSIncrOrDecrByParams retention(long retentionPeriod) { - this.retentionPeriod = retentionPeriod; - return this; - } - - public TSIncrOrDecrByParams encoding(EncodingFormat encoding) { - this.encoding = encoding; - return this; - } - - public TSIncrOrDecrByParams chunkSize(long chunkSize) { - this.chunkSize = chunkSize; - return this; - } - - public TSIncrOrDecrByParams duplicatePolicy(DuplicatePolicy duplicatePolicy) { - this.duplicatePolicy = duplicatePolicy; - return this; - } - - public TSIncrOrDecrByParams ignore(long maxTimediff, double maxValDiff) { - this.ignore = true; - this.ignoreMaxTimediff = maxTimediff; - this.ignoreMaxValDiff = maxValDiff; - return this; - } - - /** - * Set label-value pairs - * - * @param labels label-value pairs - * @return the object itself - */ - public TSIncrOrDecrByParams labels(Map labels) { - this.labels = labels; - return this; - } - - /** - * Add label-value pair. Multiple pairs can be added through chaining. - * @param label - * @param value - * @return the object itself - */ - public TSIncrOrDecrByParams label(String label, String value) { - if (this.labels == null) { - this.labels = new LinkedHashMap<>(); - } - this.labels.put(label, value); - return this; - } - - @Override - public void addParams(CommandArguments args) { - - if (timestamp != null) { - args.add(TIMESTAMP).add(timestamp); - } - - if (retentionPeriod != null) { - args.add(RETENTION).add(toByteArray(retentionPeriod)); - } - - if (encoding != null) { - args.add(ENCODING).add(encoding); - } - - if (chunkSize != null) { - args.add(CHUNK_SIZE).add(toByteArray(chunkSize)); - } - - if (duplicatePolicy != null) { - args.add(DUPLICATE_POLICY).add(duplicatePolicy); - } - - if (ignore) { - args.add(IGNORE).add(ignoreMaxTimediff).add(ignoreMaxValDiff); - } - - if (labels != null) { - args.add(LABELS); - labels.entrySet().forEach((entry) -> args.add(entry.getKey()).add(entry.getValue())); - } - } -} diff --git a/src/main/java/redis/clients/jedis/timeseries/TimeSeriesProtocol.java b/src/main/java/redis/clients/jedis/timeseries/TimeSeriesProtocol.java index 384a4549218..2476979f0d0 100644 --- a/src/main/java/redis/clients/jedis/timeseries/TimeSeriesProtocol.java +++ b/src/main/java/redis/clients/jedis/timeseries/TimeSeriesProtocol.java @@ -57,7 +57,6 @@ public enum TimeSeriesKeyword implements Rawable { UNCOMPRESSED, CHUNK_SIZE, DUPLICATE_POLICY, - IGNORE, ON_DUPLICATE, ALIGN, FILTER_BY_TS, diff --git a/src/test/java/redis/clients/jedis/mocked/pipeline/PipeliningBaseTimeSeriesCommandsTest.java b/src/test/java/redis/clients/jedis/mocked/pipeline/PipeliningBaseTimeSeriesCommandsTest.java index b8cfb85dc8b..44e653c0116 100644 --- a/src/test/java/redis/clients/jedis/mocked/pipeline/PipeliningBaseTimeSeriesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/mocked/pipeline/PipeliningBaseTimeSeriesCommandsTest.java @@ -3,7 +3,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.is; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.util.AbstractMap; @@ -12,7 +11,17 @@ import org.junit.Test; import redis.clients.jedis.Response; -import redis.clients.jedis.timeseries.*; +import redis.clients.jedis.timeseries.AggregationType; +import redis.clients.jedis.timeseries.TSAlterParams; +import redis.clients.jedis.timeseries.TSCreateParams; +import redis.clients.jedis.timeseries.TSElement; +import redis.clients.jedis.timeseries.TSGetParams; +import redis.clients.jedis.timeseries.TSInfo; +import redis.clients.jedis.timeseries.TSMGetElement; +import redis.clients.jedis.timeseries.TSMGetParams; +import redis.clients.jedis.timeseries.TSMRangeElements; +import redis.clients.jedis.timeseries.TSMRangeParams; +import redis.clients.jedis.timeseries.TSRangeParams; public class PipeliningBaseTimeSeriesCommandsTest extends PipeliningBaseMockedTestBase { @@ -48,18 +57,6 @@ public void testTsAddWithTimestampAndParams() { assertThat(response, is(predefinedResponse)); } - @Test - public void testTsAddWithParams() { - TSAddParams addParams = mock(TSAddParams.class); - - when(commandObjects.tsAdd("myTimeSeries", 1000L, 42.0, addParams)).thenReturn(longCommandObject); - - Response response = pipeliningBase.tsAdd("myTimeSeries", 1000L, 42.0, addParams); - - assertThat(commands, contains(longCommandObject)); - assertThat(response, is(predefinedResponse)); - } - @Test public void testTsAlter() { TSAlterParams alterParams = TSAlterParams.alterParams(); @@ -141,17 +138,6 @@ public void testTsDecrByWithTimestamp() { assertThat(response, is(predefinedResponse)); } - @Test - public void testTsDecrByWithParams() { - TSIncrOrDecrByParams DecrByParams = mock(TSIncrOrDecrByParams.class); - when(commandObjects.tsDecrBy("myTimeSeries", 1.0, DecrByParams)).thenReturn(longCommandObject); - - Response response = pipeliningBase.tsDecrBy("myTimeSeries", 1.0, DecrByParams); - - assertThat(commands, contains(longCommandObject)); - assertThat(response, is(predefinedResponse)); - } - @Test public void testTsDel() { when(commandObjects.tsDel("myTimeSeries", 1000L, 2000L)).thenReturn(longCommandObject); @@ -214,17 +200,6 @@ public void testTsIncrByWithTimestamp() { assertThat(response, is(predefinedResponse)); } - @Test - public void testTsIncrByWithParams() { - TSIncrOrDecrByParams incrByParams = mock(TSIncrOrDecrByParams.class); - when(commandObjects.tsIncrBy("myTimeSeries", 1.0, incrByParams)).thenReturn(longCommandObject); - - Response response = pipeliningBase.tsIncrBy("myTimeSeries", 1.0, incrByParams); - - assertThat(commands, contains(longCommandObject)); - assertThat(response, is(predefinedResponse)); - } - @Test public void testTsInfo() { when(commandObjects.tsInfo("myTimeSeries")).thenReturn(tsInfoCommandObject); diff --git a/src/test/java/redis/clients/jedis/mocked/unified/UnifiedJedisTimeSeriesCommandsTest.java b/src/test/java/redis/clients/jedis/mocked/unified/UnifiedJedisTimeSeriesCommandsTest.java index 53c673da49d..d9e06ce77cb 100644 --- a/src/test/java/redis/clients/jedis/mocked/unified/UnifiedJedisTimeSeriesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/mocked/unified/UnifiedJedisTimeSeriesCommandsTest.java @@ -15,7 +15,17 @@ import java.util.Map; import org.junit.Test; -import redis.clients.jedis.timeseries.*; +import redis.clients.jedis.timeseries.AggregationType; +import redis.clients.jedis.timeseries.TSAlterParams; +import redis.clients.jedis.timeseries.TSCreateParams; +import redis.clients.jedis.timeseries.TSElement; +import redis.clients.jedis.timeseries.TSGetParams; +import redis.clients.jedis.timeseries.TSInfo; +import redis.clients.jedis.timeseries.TSMGetElement; +import redis.clients.jedis.timeseries.TSMGetParams; +import redis.clients.jedis.timeseries.TSMRangeElements; +import redis.clients.jedis.timeseries.TSMRangeParams; +import redis.clients.jedis.timeseries.TSRangeParams; public class UnifiedJedisTimeSeriesCommandsTest extends UnifiedJedisMockedTestBase { @@ -73,25 +83,6 @@ public void testTsAddWithTimestampAndParams() { verify(commandObjects).tsAdd(key, timestamp, value, createParams); } - @Test - public void testTsAddWithParams() { - String key = "testKey"; - long timestamp = 1582605077000L; - double value = 123.45; - TSAddParams createParams = mock(TSAddParams.class); - long expectedResponse = timestamp; // Timestamp of the added value - - when(commandObjects.tsAdd(key, timestamp, value, createParams)).thenReturn(longCommandObject); - when(commandExecutor.executeCommand(longCommandObject)).thenReturn(expectedResponse); - - long result = jedis.tsAdd(key, timestamp, value, createParams); - - assertEquals(expectedResponse, result); - - verify(commandExecutor).executeCommand(longCommandObject); - verify(commandObjects).tsAdd(key, timestamp, value, createParams); - } - @Test public void testTsAlter() { String key = "testKey"; @@ -203,7 +194,7 @@ public void testTsDecrByWithTimestamp() { String key = "testKey"; double value = 1.5; long timestamp = 1582605077000L; - long expectedResponse = 5L; + long expectedResponse = -1L; // Assuming the decrement results in a total of -1 when(commandObjects.tsDecrBy(key, value, timestamp)).thenReturn(longCommandObject); when(commandExecutor.executeCommand(longCommandObject)).thenReturn(expectedResponse); @@ -216,24 +207,6 @@ public void testTsDecrByWithTimestamp() { verify(commandObjects).tsDecrBy(key, value, timestamp); } - @Test - public void testTsDecrByWithParams() { - String key = "testKey"; - double value = 1.5; - TSIncrOrDecrByParams decrByParams = mock(TSIncrOrDecrByParams.class); - long expectedResponse = 5L; - - when(commandObjects.tsDecrBy(key, value, decrByParams)).thenReturn(longCommandObject); - when(commandExecutor.executeCommand(longCommandObject)).thenReturn(expectedResponse); - - long result = jedis.tsDecrBy(key, value, decrByParams); - - assertEquals(expectedResponse, result); - - verify(commandExecutor).executeCommand(longCommandObject); - verify(commandObjects).tsDecrBy(key, value, decrByParams); - } - @Test public void testTsDel() { String key = "testKey"; @@ -324,7 +297,7 @@ public void testTsIncrByWithTimestamp() { String key = "testKey"; double value = 2.5; long timestamp = 1582605077000L; - long expectedResponse = 5L; + long expectedResponse = 5L; // Assuming the increment results in a total of 5 when(commandObjects.tsIncrBy(key, value, timestamp)).thenReturn(longCommandObject); when(commandExecutor.executeCommand(longCommandObject)).thenReturn(expectedResponse); @@ -337,24 +310,6 @@ public void testTsIncrByWithTimestamp() { verify(commandObjects).tsIncrBy(key, value, timestamp); } - @Test - public void testTsIncrByWithParams() { - String key = "testKey"; - double value = 2.5; - TSIncrOrDecrByParams incrByParams = mock(TSIncrOrDecrByParams.class); - long expectedResponse = 5L; - - when(commandObjects.tsIncrBy(key, value, incrByParams)).thenReturn(longCommandObject); - when(commandExecutor.executeCommand(longCommandObject)).thenReturn(expectedResponse); - - long result = jedis.tsIncrBy(key, value, incrByParams); - - assertEquals(expectedResponse, result); - - verify(commandExecutor).executeCommand(longCommandObject); - verify(commandObjects).tsIncrBy(key, value, incrByParams); - } - @Test public void testTsInfo() { String key = "testKey"; diff --git a/src/test/java/redis/clients/jedis/modules/timeseries/TimeSeriesTest.java b/src/test/java/redis/clients/jedis/modules/timeseries/TimeSeriesTest.java index dd0688f080f..fe0f7d1604a 100644 --- a/src/test/java/redis/clients/jedis/modules/timeseries/TimeSeriesTest.java +++ b/src/test/java/redis/clients/jedis/modules/timeseries/TimeSeriesTest.java @@ -122,23 +122,6 @@ public void testAlter() { assertEquals("v33", info.getLabel("l3")); } - @Test - public void createAndAlterParams() { - Map labels = new HashMap<>(); - labels.put("l1", "v1"); - labels.put("l2", "v2"); - - assertEquals("OK", client.tsCreate("ts-params", - TSCreateParams.createParams().retention(60000).encoding(EncodingFormat.UNCOMPRESSED).chunkSize(4096) - .duplicatePolicy(DuplicatePolicy.BLOCK).ignore(50, 12.5).labels(labels))); - - labels.put("l1", "v11"); - labels.remove("l2"); - labels.put("l3", "v33"); - assertEquals("OK", client.tsAlter("ts-params", TSAlterParams.alterParams().retention(15000).chunkSize(8192) - .duplicatePolicy(DuplicatePolicy.SUM).ignore(50, 12.5).labels(labels))); - } - @Test public void testRule() { assertEquals("OK", client.tsCreate("source")); @@ -164,21 +147,6 @@ public void testRule() { } } - @Test - public void addParams() { - Map labels = new HashMap<>(); - labels.put("l1", "v1"); - labels.put("l2", "v2"); - - assertEquals(1000L, client.tsAdd("add1", 1000L, 1.1, - TSAddParams.addParams().retention(10000).encoding(EncodingFormat.UNCOMPRESSED).chunkSize(1000) - .duplicatePolicy(DuplicatePolicy.FIRST).onDuplicate(DuplicatePolicy.LAST).ignore(50, 12.5).labels(labels))); - - assertEquals(1000L, client.tsAdd("add2", 1000L, 1.1, - TSAddParams.addParams().retention(10000).encoding(EncodingFormat.COMPRESSED).chunkSize(1000) - .duplicatePolicy(DuplicatePolicy.MIN).onDuplicate(DuplicatePolicy.MAX).ignore(50, 12.5).labels(labels))); - } - @Test public void testAdd() { Map labels = new HashMap<>(); @@ -446,29 +414,6 @@ public void testIncrByDecrBy() throws InterruptedException { client.tsDecrBy("seriesIncDec", 33); } - @Test - public void incrByDecrByParams() { - Map labels = new HashMap<>(); - labels.put("l1", "v1"); - labels.put("l2", "v2"); - - assertEquals(1000L, client.tsIncrBy("incr1", 1.1, - TSIncrOrDecrByParams.incrByParams().timestamp(1000).retention(10000).encoding(EncodingFormat.UNCOMPRESSED) - .chunkSize(1000).duplicatePolicy(DuplicatePolicy.FIRST).ignore(50, 12.5).labels(labels))); - - assertEquals(1000L, client.tsIncrBy("incr2", 1.1, - TSIncrOrDecrByParams.incrByParams().timestamp(1000).retention(10000).encoding(EncodingFormat.COMPRESSED) - .chunkSize(1000).duplicatePolicy(DuplicatePolicy.MIN).ignore(50, 12.5).labels(labels))); - - assertEquals(1000L, client.tsDecrBy("decr1", 1.1, - TSIncrOrDecrByParams.decrByParams().timestamp(1000).retention(10000).encoding(EncodingFormat.COMPRESSED) - .chunkSize(1000).duplicatePolicy(DuplicatePolicy.LAST).ignore(50, 12.5).labels(labels))); - - assertEquals(1000L, client.tsDecrBy("decr2", 1.1, - TSIncrOrDecrByParams.decrByParams().timestamp(1000).retention(10000).encoding(EncodingFormat.UNCOMPRESSED) - .chunkSize(1000).duplicatePolicy(DuplicatePolicy.MAX).ignore(50, 12.5).labels(labels))); - } - @Test public void align() { client.tsAdd("align", 1, 10d); From db826a6c7084b35ca2496ea242d01187dae2b884 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Fri, 14 Jun 2024 23:43:48 +0600 Subject: [PATCH 27/51] Ensure closing connection in Pipeline (#3865) even if there is an error in sync method. --- src/main/java/redis/clients/jedis/Pipeline.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/redis/clients/jedis/Pipeline.java b/src/main/java/redis/clients/jedis/Pipeline.java index 36fab65602f..af6d39ee2d2 100644 --- a/src/main/java/redis/clients/jedis/Pipeline.java +++ b/src/main/java/redis/clients/jedis/Pipeline.java @@ -10,6 +10,7 @@ import redis.clients.jedis.exceptions.JedisDataException; import redis.clients.jedis.graph.GraphCommandObjects; import redis.clients.jedis.params.*; +import redis.clients.jedis.util.IOUtils; import redis.clients.jedis.util.KeyValue; public class Pipeline extends PipelineBase implements DatabasePipelineCommands, Closeable { @@ -46,10 +47,12 @@ public final Response appendCommand(CommandObject commandObject) { @Override public void close() { - sync(); - - if (closeConnection) { - connection.close(); + try { + sync(); + } finally { + if (closeConnection) { + IOUtils.closeQuietly(connection); + } } } From f4fcc3628fcfcd29037e070071ea794669277679 Mon Sep 17 00:00:00 2001 From: Igor Malinovskiy Date: Tue, 18 Jun 2024 15:23:17 +0200 Subject: [PATCH 28/51] Merge doc tests into main branch to keep in-sync with the code (#3861) * Fix search_quickstart example * Add data_class step to SearchQuickstartExample * Update examples with new bikes and align to new tutorial * Fixes doctests for search tutorial * Small fixes doctests * Updates search tutorial doc examples to new format and data * Fix formatting in doc tests * Add Hashes and String Example (#3477) * Add Hashes Example * Fixes examples for hash tutorial * Refactor Hash Tutorial to Java 8 (from 17) * Change indentation to 4 spaces * Add Strings Example * Reformat samples to 2-space indentation --------- Co-authored-by: Elena Kolevska * Add Geospatial data type example (#3487) * Add Geospatial data type example * Add missing REMOVE_END * Added example Java code snippets for Streams (#3641) * Java example code snippets for T-Digest and TopK (#3660) * Created example for t digest * Added example for topK --------- Co-authored-by: Ranjeet Singh Co-authored-by: Ranjeet Singh * Create Java code snippets for sets redis#3626 (#3661) * Create Java code snippets for sets redis#3626 * Apply suggestions from code review to add // STEP_END lines. Co-authored-by: David Dougherty * format imports --------- Co-authored-by: David Dougherty Co-authored-by: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> * Create Java code snippets for count min sketch (#3644) * added code snippet for CMS in Java * Update CMSExample.java * format spaces * use cmsIncrBy simple variant * more format spaces --------- Co-authored-by: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> * Added Java code snippets for Bloom #3630 (#3671) * Added java example for bloom filter * Removed space * fix and format imports * fix compile error * format spaces * Add del command and rename obj * Add del command and fix format * change to junit assert * Update BloomFilterExample.java * Add correct output comment --------- Co-authored-by: Ranjeet Singh Co-authored-by: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Co-authored-by: Ranjeet Singh * Added java code snippet for hyperloglog (#3674) * Added Java code snippet for HyperLogLog * fix format and imports * fix spaces * change to junit assert * Added correct output comment * Update HyperLogLogExample.java --------- Co-authored-by: Ranjeet Singh Co-authored-by: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> * Added Java code snippets for cuckoo filters (#3679) * Add CuckooFilterExample * Add step start comment * Update CuckooFilterExample.java --------- Co-authored-by: Ranjeet Singh Co-authored-by: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> * Create Java code snippet for lists #3625 (#3677) * Added example Java code snippets for the List#3625 * format spaces --------- Co-authored-by: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> * Create Java code snippet for sorted sets (#3680) * added an example for SortedSets in java * Update SortedSetsExample.java * made changes as per the review. * Format spaces in SortedSetsExample.java --------- Co-authored-by: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> * Added Java code snippet for bitmap (#3687) * Add bitmap example * Change class name * Add assert for res3 and res4 * Update BitMapsExample.java * Format spaces in BitMapsExample.java --------- Co-authored-by: Ranjeet Singh Co-authored-by: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> --------- Co-authored-by: Elena Kolevska Co-authored-by: Brian Sam-Bodden Co-authored-by: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Co-authored-by: Harshvardhan Parmar Co-authored-by: Ranjeet SIngh <32495484+Ranjeet0611@users.noreply.github.com> Co-authored-by: Ranjeet Singh Co-authored-by: Ranjeet Singh Co-authored-by: Suraj <112368828+suraj11chauhan@users.noreply.github.com> Co-authored-by: David Dougherty Co-authored-by: Ranjeet Singh --- .../io/redis/examples/BitMapsExample.java | 47 ++ .../io/redis/examples/BloomFilterExample.java | 49 ++ .../java/io/redis/examples/CMSExample.java | 49 ++ .../redis/examples/CuckooFilterExample.java | 45 ++ .../java/io/redis/examples/GeoExample.java | 60 +++ .../java/io/redis/examples/HashExample.java | 101 ++++ .../io/redis/examples/HyperLogLogExample.java | 41 ++ .../java/io/redis/examples/ListExample.java | 323 ++++++++++++ .../examples/SearchQuickstartExample.java | 462 ++++++++++-------- .../java/io/redis/examples/SetGetExample.java | 41 +- .../java/io/redis/examples/SetsExample.java | 185 +++++++ .../io/redis/examples/SortedSetsExample.java | 124 +++++ .../io/redis/examples/StreamsExample.java | 270 ++++++++++ .../java/io/redis/examples/StringExample.java | 75 +++ .../io/redis/examples/TDigestExample.java | 85 ++++ .../java/io/redis/examples/TopKExample.java | 47 ++ 16 files changed, 1785 insertions(+), 219 deletions(-) create mode 100644 src/test/java/io/redis/examples/BitMapsExample.java create mode 100644 src/test/java/io/redis/examples/BloomFilterExample.java create mode 100644 src/test/java/io/redis/examples/CMSExample.java create mode 100644 src/test/java/io/redis/examples/CuckooFilterExample.java create mode 100644 src/test/java/io/redis/examples/GeoExample.java create mode 100644 src/test/java/io/redis/examples/HashExample.java create mode 100644 src/test/java/io/redis/examples/HyperLogLogExample.java create mode 100644 src/test/java/io/redis/examples/ListExample.java create mode 100644 src/test/java/io/redis/examples/SetsExample.java create mode 100644 src/test/java/io/redis/examples/SortedSetsExample.java create mode 100644 src/test/java/io/redis/examples/StreamsExample.java create mode 100644 src/test/java/io/redis/examples/StringExample.java create mode 100644 src/test/java/io/redis/examples/TDigestExample.java create mode 100644 src/test/java/io/redis/examples/TopKExample.java diff --git a/src/test/java/io/redis/examples/BitMapsExample.java b/src/test/java/io/redis/examples/BitMapsExample.java new file mode 100644 index 00000000000..a1b80600e0a --- /dev/null +++ b/src/test/java/io/redis/examples/BitMapsExample.java @@ -0,0 +1,47 @@ +// EXAMPLE: bitmap_tutorial +// HIDE_START +package io.redis.examples; + +import org.junit.Assert; +import org.junit.Test; +import redis.clients.jedis.UnifiedJedis; + +public class BitMapsExample { + + @Test + public void run() { + UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379"); + // HIDE_END + + // REMOVE_START + jedis.del("pings:2024-01-01-00:00"); + // REMOVE_END + + + // STEP_START ping + boolean res1 = jedis.setbit("pings:2024-01-01-00:00", 123, true); + System.out.println(res1); // >>> false + + boolean res2 = jedis.getbit("pings:2024-01-01-00:00", 123); + System.out.println(res2); // >>> true + + boolean res3 = jedis.getbit("pings:2024-01-01-00:00", 456); + System.out.println(res3); // >>> false + // STEP_END + + // REMOVE_START + Assert.assertFalse(res1); + Assert.assertTrue(res2); + Assert.assertFalse(res3); + // REMOVE_END + + // STEP_START bitcount + long res4 = jedis.bitcount("pings:2024-01-01-00:00"); + System.out.println(res4); // >>> 1 + // STEP_END + + // REMOVE_START + Assert.assertEquals(res4, 1); + // REMOVE_END + } +} diff --git a/src/test/java/io/redis/examples/BloomFilterExample.java b/src/test/java/io/redis/examples/BloomFilterExample.java new file mode 100644 index 00000000000..a6abe79b90b --- /dev/null +++ b/src/test/java/io/redis/examples/BloomFilterExample.java @@ -0,0 +1,49 @@ +// EXAMPLE: bf_tutorial + +// HIDE_START +package io.redis.examples; + +import redis.clients.jedis.UnifiedJedis; +import org.junit.Test; +import org.junit.Assert; +import java.util.List; + +public class BloomFilterExample { + + @Test + public void run() { + UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379"); + // HIDE_END + + // REMOVE_START + jedis.del("bikes:models"); + // REMOVE_END + + // STEP_START bloom + String res1 = jedis.bfReserve("bikes:models", 0.01, 1000); + System.out.println(res1); // >>> OK + + // REMOVE_START + Assert.assertEquals("OK", res1); + // REMOVE_END + + boolean res2 = jedis.bfAdd("bikes:models", "Smoky Mountain Striker"); + System.out.println(res2); // >>> True + + boolean res3 = jedis.bfExists("bikes:models", "Smoky Mountain Striker"); + System.out.println(res3); // >>> True + + List res4 = jedis.bfMAdd("bikes:models", + "Rocky Mountain Racer", + "Cloudy City Cruiser", + "Windy City Wippet"); + System.out.println(res4); // >>> [True, True, True] + + List res5 = jedis.bfMExists("bikes:models", + "Rocky Mountain Racer", + "Cloudy City Cruiser", + "Windy City Wippet"); + System.out.println(res5); // >>> [True, True, True] + // STEP_END + } +} diff --git a/src/test/java/io/redis/examples/CMSExample.java b/src/test/java/io/redis/examples/CMSExample.java new file mode 100644 index 00000000000..aa9e93714b8 --- /dev/null +++ b/src/test/java/io/redis/examples/CMSExample.java @@ -0,0 +1,49 @@ +//EXAMPLE: cms_tutorial +//HIDE_START +package io.redis.examples; +//HIDE_END + +//REMOVE_START +import redis.clients.jedis.UnifiedJedis; +import org.junit.Test; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +//REMOVE_END + +public class CMSExample { + + @Test + public void run() { + + //HIDE_START + UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379"); + //HIDE_END + + //REMOVE_START + jedis.del("bikes:profit"); + //REMOVE_END + + //STEP_START cms + String res1 = jedis.cmsInitByProb("bikes:profit", 0.001d, 0.002d); + System.out.println(res1); // >>> OK + + long res2 = jedis.cmsIncrBy("bikes:profit", "Smoky Mountain Striker", 100L); + System.out.println(res2); // >>> 100 + + List res3 = jedis.cmsIncrBy("bikes:profit", new HashMap() {{ + put("Rocky Mountain Racer", 200L); + put("Cloudy City Cruiser", 150L); + }}); + System.out.println(res3); // >>> [200, 150] + + List res4 = jedis.cmsQuery("bikes:profit", "Smoky Mountain Striker"); + System.out.println(res4); // >>> [100] + + Map res5 = jedis.cmsInfo("bikes:profit"); + System.out.println(res5.get("width") + " " + res5.get("depth") + " " + res5.get("count")); // >>> 2000 9 450 + //STEP_END + } + +} diff --git a/src/test/java/io/redis/examples/CuckooFilterExample.java b/src/test/java/io/redis/examples/CuckooFilterExample.java new file mode 100644 index 00000000000..33b84038433 --- /dev/null +++ b/src/test/java/io/redis/examples/CuckooFilterExample.java @@ -0,0 +1,45 @@ +// EXAMPLE: cuckoo_tutorial + +// HIDE_START +package io.redis.examples; + +import org.junit.Assert; +import org.junit.Test; +import redis.clients.jedis.UnifiedJedis; + +public class CuckooFilterExample { + @Test + public void run() { + UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379"); + // HIDE_END + + // REMOVE_START + jedis.del("bikes:models"); + // REMOVE_END + + // STEP_START cuckoo + String res1 = jedis.cfReserve("bikes:models", 1000000); + System.out.println(res1); // >>> OK + + // REMOVE_START + Assert.assertEquals(res1, "OK"); + // REMOVE_END + + boolean res2 = jedis.cfAdd("bikes:models", "Smoky Mountain Striker"); + System.out.println(res2); // >>> True + + boolean res3 = jedis.cfExists("bikes:models", "Smoky Mountain Striker"); + System.out.println(res3); // >>> True + + boolean res4 = jedis.cfExists("bikes:models", "Terrible Bike Name"); + System.out.println(res4); // >>> False + + boolean res5 = jedis.cfDel("bikes:models", "Smoky Mountain Striker"); + System.out.println(res5); // >>> True + + // REMOVE_START + Assert.assertTrue(res5); + // REMOVE_END + // STEP_END + } +} diff --git a/src/test/java/io/redis/examples/GeoExample.java b/src/test/java/io/redis/examples/GeoExample.java new file mode 100644 index 00000000000..f985c7f946d --- /dev/null +++ b/src/test/java/io/redis/examples/GeoExample.java @@ -0,0 +1,60 @@ +//EXAMPLE: geo_tutorial +package io.redis.examples; + +// REMOVE_START +import org.junit.Test; +// REMOVE_END +import redis.clients.jedis.GeoCoordinate; +import redis.clients.jedis.UnifiedJedis; +import redis.clients.jedis.args.GeoUnit; +import redis.clients.jedis.resps.GeoRadiusResponse; + +import java.util.List; +import java.util.stream.Collectors; + +import static org.junit.Assert.assertEquals; + +public class GeoExample { + @Test + public void run() { + try (UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379")) { + // REMOVE_START + jedis.del("bikes:rentable"); + // REMOVE_END + + // STEP_START geoadd + long res1 = jedis.geoadd("bikes:rentable", -122.27652, 37.805186, "station:1"); + System.out.println(res1); // 1 + + long res2 = jedis.geoadd("bikes:rentable", -122.2674626, 37.8062344, "station:2"); + System.out.println(res2); // 1 + + long res3 = jedis.geoadd("bikes:rentable", -122.2469854, 37.8104049, "station:3"); + System.out.println(res2); // 1 + // STEP_END + + // REMOVE_START + assertEquals(1, res1); + assertEquals(1, res1); + assertEquals(1, res1); + // REMOVE_END + + // STEP_START geosearch + List res4 = jedis.geosearch( + "bikes:rentable", + new GeoCoordinate(-122.27652, 37.805186), + 5, + GeoUnit.KM + ); + List members = res4.stream() // + .map(GeoRadiusResponse::getMemberByString) // + .collect(Collectors.toList()); + System.out.println(members); // [station:1, station:2, station:3] + // STEP_END + + // REMOVE_START + assertEquals("[station:1, station:2, station:3]", members.toString()); + // REMOVE_END + } + } +} diff --git a/src/test/java/io/redis/examples/HashExample.java b/src/test/java/io/redis/examples/HashExample.java new file mode 100644 index 00000000000..2d02849cf46 --- /dev/null +++ b/src/test/java/io/redis/examples/HashExample.java @@ -0,0 +1,101 @@ +//EXAMPLE: hash_tutorial +package io.redis.examples; + +import redis.clients.jedis.UnifiedJedis; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +//REMOVE_START +import org.junit.Test; +import static org.junit.Assert.assertEquals; +//REMOVE_END + +public class HashExample { + @Test + public void run() { + try (UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379")) { + // REMOVE_START + jedis.del("bike:1", "bike:1:stats"); + // REMOVE_END + + // STEP_START set_get_all + Map bike1 = new HashMap<>(); + bike1.put("model", "Deimos"); + bike1.put("brand", "Ergonom"); + bike1.put("type", "Enduro bikes"); + bike1.put("price", "4972"); + + Long res1 = jedis.hset("bike:1", bike1); + System.out.println(res1); // 4 + + String res2 = jedis.hget("bike:1", "model"); + System.out.println(res2); // Deimos + + String res3 = jedis.hget("bike:1", "price"); + System.out.println(res3); // 4972 + + Map res4 = jedis.hgetAll("bike:1"); + System.out.println(res4); // {type=Enduro bikes, brand=Ergonom, price=4972, model=Deimos} + // STEP_END + + // REMOVE_START + assertEquals(4, res1.longValue()); + assertEquals("Deimos", res2); + assertEquals("4972", res3); + assertEquals("Deimos", res4.get("model")); + assertEquals("Ergonom", res4.get("brand")); + assertEquals("Enduro bikes", res4.get("type")); + assertEquals("4972", res4.get("price")); + // REMOVE_END + + // STEP_START hmget + List res5 = jedis.hmget("bike:1", "model", "price"); + System.out.println(res5); // [Deimos, 4972] + // STEP_END + + // REMOVE_START + assert res5.toString().equals("[Deimos, 4972]"); + // REMOVE_END + + // STEP_START hincrby + Long res6 = jedis.hincrBy("bike:1", "price", 100); + System.out.println(res6); // 5072 + Long res7 = jedis.hincrBy("bike:1", "price", -100); + System.out.println(res7); // 4972 + // STEP_END + + // REMOVE_START + assertEquals(5072, res6.longValue()); + assertEquals(4972, res7.longValue()); + // REMOVE_END + + // STEP_START incrby_get_mget + Long res8 = jedis.hincrBy("bike:1:stats", "rides", 1); + System.out.println(res8); // 1 + Long res9 = jedis.hincrBy("bike:1:stats", "rides", 1); + System.out.println(res9); // 2 + Long res10 = jedis.hincrBy("bike:1:stats", "rides", 1); + System.out.println(res10); // 3 + Long res11 = jedis.hincrBy("bike:1:stats", "crashes", 1); + System.out.println(res11); // 1 + Long res12 = jedis.hincrBy("bike:1:stats", "owners", 1); + System.out.println(res12); // 1 + String res13 = jedis.hget("bike:1:stats", "rides"); + System.out.println(res13); // 3 + List res14 = jedis.hmget("bike:1:stats", "crashes", "owners"); + System.out.println(res14); // [1, 1] + // STEP_END + + // REMOVE_START + assertEquals(1, res8.longValue()); + assertEquals(2, res9.longValue()); + assertEquals(3, res10.longValue()); + assertEquals(1, res11.longValue()); + assertEquals(1, res12.longValue()); + assertEquals("3", res13); + assertEquals("[1, 1]", res14.toString()); + // REMOVE_END + } + } +} diff --git a/src/test/java/io/redis/examples/HyperLogLogExample.java b/src/test/java/io/redis/examples/HyperLogLogExample.java new file mode 100644 index 00000000000..97e0d2a4c0d --- /dev/null +++ b/src/test/java/io/redis/examples/HyperLogLogExample.java @@ -0,0 +1,41 @@ +// EXAMPLE: hll_tutorial +package io.redis.examples; + +import org.junit.Assert; +import org.junit.Test; +import redis.clients.jedis.UnifiedJedis; + +public class HyperLogLogExample { + + @Test + public void run() { + // HIDE_START + UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379"); + // HIDE_END + + // REMOVE_START + jedis.del("bikes", "commuter_bikes", "all_bikes"); + // REMOVE_END + + // STEP_START pfadd + long res1 = jedis.pfadd("bikes", "Hyperion", "Deimos", "Phoebe", "Quaoar"); + System.out.println(res1); // >>> 1 + + long res2 = jedis.pfcount("bikes"); + System.out.println(res2); // >>> 4 + + long res3 = jedis.pfadd("commuter_bikes", "Salacia", "Mimas", "Quaoar"); + System.out.println(res3); // >>> 1 + + String res4 = jedis.pfmerge("all_bikes", "bikes", "commuter_bikes"); + System.out.println(res4); // >>> OK + + // REMOVE_START + Assert.assertEquals("OK", res4); + // REMOVE_END + + long res5 = jedis.pfcount("all_bikes"); + System.out.println(res5); // >>> 6 + // STEP_END + } +} diff --git a/src/test/java/io/redis/examples/ListExample.java b/src/test/java/io/redis/examples/ListExample.java new file mode 100644 index 00000000000..f8095b0c91e --- /dev/null +++ b/src/test/java/io/redis/examples/ListExample.java @@ -0,0 +1,323 @@ +// EXAMPLE: list_tutorial +// HIDE_START +package io.redis.examples; + +import org.junit.Test; +import redis.clients.jedis.UnifiedJedis; +import redis.clients.jedis.args.ListDirection; +import java.util.List; +import static org.junit.Assert.*; + +public class ListExample { + @Test + public void run() { + UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379"); + + // HIDE_END + // REMOVE_START + jedis.del("bikes:repairs"); + jedis.del("bikes:finished"); + // REMOVE_END + + // STEP_START queue + long res1 = jedis.lpush("bikes:repairs", "bike:1"); + System.out.println(res1); // >>> 1 + + long res2 = jedis.lpush("bikes:repairs", "bike:2"); + System.out.println(res2); // >>> 2 + + String res3 = jedis.rpop("bikes:repairs"); + System.out.println(res3); // >>> bike:1 + + String res4 = jedis.rpop("bikes:repairs"); + System.out.println(res4); // >>> bike:2 + // STEP_END + + // REMOVE_START + assertEquals(1, res1); + assertEquals(2, res2); + assertEquals("bike:1", res3); + assertEquals("bike:2", res4); + // REMOVE_END + + // STEP_START stack + long res5 = jedis.lpush("bikes:repairs", "bike:1"); + System.out.println(res5); // >>> 1 + + long res6 = jedis.lpush("bikes:repairs", "bike:2"); + System.out.println(res6); // >>> 2 + + String res7 = jedis.lpop("bikes:repairs"); + System.out.println(res7); // >>> bike:2 + + String res8 = jedis.lpop("bikes:repairs"); + System.out.println(res8); // >>> bike:1 + // STEP_END + + // REMOVE_START + assertEquals(1, res5); + assertEquals(2, res6); + assertEquals("bike:2", res7); + assertEquals("bike:1", res8); + // REMOVE_END + + // STEP_START llen + long res9 = jedis.llen("bikes:repairs"); + System.out.println(res9); // >>> 0 + // STEP_END + + // REMOVE_START + assertEquals(0, res9); + // REMOVE_END + + // STEP_START lmove_lrange + long res10 = jedis.lpush("bikes:repairs", "bike:1"); + System.out.println(res10); // >>> 1 + + long res11 = jedis.lpush("bikes:repairs", "bike:2"); + System.out.println(res11); // >>> 2 + + String res12 = jedis.lmove("bikes:repairs", "bikes:finished", ListDirection.LEFT, ListDirection.LEFT); + System.out.println(res12); // >>> bike:2 + + List res13 = jedis.lrange("bikes:repairs", 0, -1); + System.out.println(res13); // >>> [bike:1] + + List res14 = jedis.lrange("bikes:finished", 0, -1); + System.out.println(res14); // >>> [bike:2] + // STEP_END + + // REMOVE_START + assertEquals(1, res10); + assertEquals(2, res11); + assertEquals("bike:2", res12); + assertEquals("[bike:1]", res13.toString()); + assertEquals("[bike:2]", res14.toString()); + jedis.del("bikes:repairs"); + // REMOVE_END + + // STEP_START lpush_rpush + long res15 = jedis.rpush("bikes:repairs", "bike:1"); + System.out.println(res15); // >>> 1 + + long res16 = jedis.rpush("bikes:repairs", "bike:2"); + System.out.println(res16); // >>> 2 + + long res17 = jedis.lpush("bikes:repairs", "bike:important_bike"); + System.out.println(res17); // >>> 3 + + List res18 = jedis.lrange("bikes:repairs", 0, -1); + System.out.println(res18); // >>> [bike:important_bike, bike:1, bike:2] + // STEP_END + + // REMOVE_START + assertEquals(1, res15); + assertEquals(2, res16); + assertEquals(3, res17); + assertEquals("[bike:important_bike, bike:1, bike:2]", res18.toString()); + jedis.del("bikes:repairs"); + // REMOVE_END + + // STEP_START variadic + long res19 = jedis.rpush("bikes:repairs", "bike:1", "bike:2", "bike:3"); + System.out.println(res19); // >>> 3 + + long res20 = jedis.lpush("bikes:repairs", "bike:important_bike", "bike:very_important_bike"); + System.out.println(res20); // >>> 5 + + List res21 = jedis.lrange("bikes:repairs", 0, -1); + System.out.println(res21); // >>> [bike:very_important_bike, bike:important_bike, bike:1, bike:2, bike:3] + // STEP_END + + // REMOVE_START + assertEquals(3, res19); + assertEquals(5, res20); + assertEquals("[bike:very_important_bike, bike:important_bike, bike:1, bike:2, bike:3]",res21.toString()); + jedis.del("bikes:repairs"); + // REMOVE_END + + // STEP_START lpop_rpop + long res22 = jedis.rpush("bikes:repairs", "bike:1", "bike:2", "bike:3"); + System.out.println(res22); // >>> 3 + + String res23 = jedis.rpop("bikes:repairs"); + System.out.println(res23); // >>> bike:3 + + String res24 = jedis.lpop("bikes:repairs"); + System.out.println(res24); // >>> bike:1 + + String res25 = jedis.rpop("bikes:repairs"); + System.out.println(res25); // >>> bike:2 + + String res26 = jedis.rpop("bikes:repairs"); + System.out.println(res26); // >>> null + // STEP_END + + // REMOVE_START + assertEquals(3, res22); + assertEquals("bike:3", res23); + assertEquals("bike:1", res24); + assertEquals("bike:2", res25); + assertNull(res26); + // REMOVE_END + + // STEP_START ltrim + long res27 = jedis.lpush("bikes:repairs", "bike:1", "bike:2", "bike:3", "bike:4", "bike:5"); + System.out.println(res27); // >>> 5 + + String res28 = jedis.ltrim("bikes:repairs", 0, 2); + System.out.println(res28); // >>> OK + + List res29 = jedis.lrange("bikes:repairs", 0, -1); + System.out.println(res29); // >>> [bike:5, bike:4, bike:3] + // STEP_END + + // REMOVE_START + assertEquals(5, res27); + assertEquals("OK", res28); + assertEquals("[bike:5, bike:4, bike:3]", res29.toString()); + jedis.del("bikes:repairs"); + // REMOVE_END + + // STEP_START ltrim_end_of_list + res27 = jedis.rpush("bikes:repairs", "bike:1", "bike:2", "bike:3", "bike:4", "bike:5"); + System.out.println(res27); // >>> 5 + + res28 = jedis.ltrim("bikes:repairs", -3, -1); + System.out.println(res2); // >>> OK + + res29 = jedis.lrange("bikes:repairs", 0, -1); + System.out.println(res29); // >>> [bike:3, bike:4, bike:5] + // STEP_END + + // REMOVE_START + assertEquals(5, res27); + assertEquals("OK", res28); + assertEquals("[bike:3, bike:4, bike:5]", res29.toString()); + jedis.del("bikes:repairs"); + // REMOVE_END + + // STEP_START brpop + long res31 = jedis.rpush("bikes:repairs", "bike:1", "bike:2"); + System.out.println(res31); // >>> 2 + + List res32 = jedis.brpop(1, "bikes:repairs"); + System.out.println(res32); // >>> (bikes:repairs, bike:2) + + List res33 = jedis.brpop(1,"bikes:repairs"); + System.out.println(res33); // >>> (bikes:repairs, bike:1) + + List res34 = jedis.brpop(1,"bikes:repairs"); + System.out.println(res34); // >>> null + // STEP_END + + // REMOVE_START + assertEquals(2, res31); + assertEquals("[bikes:repairs, bike:2]", res32.toString()); + assertEquals( "[bikes:repairs, bike:1]", res33.toString()); + assertNull(res34); + jedis.del("bikes:repairs"); + jedis.del("new_bikes"); + // REMOVE_END + + // STEP_START rule_1 + long res35 = jedis.del("new_bikes"); + System.out.println(res35); // >>> 0 + + long res36 = jedis.lpush("new_bikes", "bike:1", "bike:2", "bike:3"); + System.out.println(res36); // >>> 3 + // STEP_END + + // REMOVE_START + assertEquals(0, res35); + assertEquals(3, res36); + jedis.del("new_bikes"); + // REMOVE_END + + // STEP_START rule_1.1 + String res37 = jedis.set("new_bikes", "bike:1"); + System.out.println(res37); // >>> OK + + String res38 = jedis.type("new_bikes"); + System.out.println(res38); // >>> string + + try { + long res39 = jedis.lpush("new_bikes", "bike:2", "bike:3"); + } catch (Exception e) { + e.printStackTrace(); + // >>> redis.clients.jedis.exceptions.JedisDataException: + // >>> WRONGTYPE Operation against a key holding the wrong kind of value + } + // STEP_END + + // REMOVE_START + assertEquals("OK",res37); + assertEquals("string",res38); + jedis.del("new_bikes"); + // REMOVE_END + + // STEP_START rule_2 + jedis.lpush("bikes:repairs", "bike:1", "bike:2", "bike:3"); + System.out.println(res36); // >>> 3 + + boolean res40 = jedis.exists("bikes:repairs"); + System.out.println(res40); // >>> true + + String res41 = jedis.lpop("bikes:repairs"); + System.out.println(res41); // >>> bike:3 + + String res42 = jedis.lpop("bikes:repairs"); + System.out.println(res42); // >>> bike:2 + + String res43 = jedis.lpop("bikes:repairs"); + System.out.println(res43); // >>> bike:1 + + boolean res44 = jedis.exists("bikes:repairs"); + System.out.println(res44); // >>> false + // STEP_END + + // REMOVE_START + assertTrue(res40); + assertEquals(res41, "bike:3"); + assertEquals(res42, "bike:2"); + assertEquals(res43, "bike:1"); + assertFalse(res44); + // REMOVE_END + + // STEP_START rule_3 + long res45 = jedis.del("bikes:repairs"); + System.out.println(res45); // >>> 0 + + long res46 = jedis.llen("bikes:repairs"); + System.out.println(res46); // >>> 0 + + String res47 = jedis.lpop("bikes:repairs"); + System.out.println(res47); // >>> null + // STEP_END + + // REMOVE_START + assertEquals(0, res45); + assertEquals(0, res46); + assertNull(res47); + // REMOVE_END + + // STEP_START ltrim.1 + long res48 = jedis.lpush("bikes:repairs", "bike:1", "bike:2", "bike:3", "bike:4", "bike:5"); + System.out.println(res48); // >>> 5 + + String res49 = jedis.ltrim("bikes:repairs", 0, 2); + System.out.println(res49); // >>> OK + + List res50 = jedis.lrange("bikes:repairs", 0, -1); + System.out.println(res50); // >>> [bike:5, bike:4, bike:3] + // STEP_END + + // REMOVE_START + assertEquals(5, res48); + assertEquals("OK", res49); + assertEquals("[bike:5, bike:4, bike:3]", res50.toString()); + jedis.del("bikes:repairs"); + // REMOVE_END + + } +} diff --git a/src/test/java/io/redis/examples/SearchQuickstartExample.java b/src/test/java/io/redis/examples/SearchQuickstartExample.java index 5ef34b75299..c53fa2a847c 100644 --- a/src/test/java/io/redis/examples/SearchQuickstartExample.java +++ b/src/test/java/io/redis/examples/SearchQuickstartExample.java @@ -1,5 +1,4 @@ -//EXAMPLE: set_and_get -//HIDE_START +// EXAMPLE: search_quickstart package io.redis.examples; import java.math.BigDecimal; @@ -10,209 +9,276 @@ import redis.clients.jedis.search.*; import redis.clients.jedis.search.aggr.*; import redis.clients.jedis.search.schemafields.*; -//REMOVE_START +// REMOVE_START import org.junit.Test; import static org.junit.Assert.assertEquals; -//REMOVE_END + +// REMOVE_END class Bicycle { - public String brand; - public String model; - public BigDecimal price; - public String description; - public String condition; - - public Bicycle(String brand, String model, BigDecimal price, String description, String condition) { - this.brand = brand; - this.model = model; - this.price = price; - this.description = description; - this.condition = condition; - } + public String brand; + public String model; + public BigDecimal price; + public String description; + public String condition; + + public Bicycle(String brand, String model, BigDecimal price, String condition, String description) { + this.brand = brand; + this.model = model; + this.price = price; + this.condition = condition; + this.description = description; + } } public class SearchQuickstartExample { - @Test - public void run() { - //HIDE_END - - // STEP_START connect - UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379"); - // STEP_END - // REMOVE_START - try { - jedis.ftDropIndex("idx:bicycle"); - } catch (JedisDataException e) { - // ignore - } - // REMOVE_END - - // STEP_START data_sample - Bicycle bike1 = new Bicycle( - "Diaz Ltd", - "Dealer Sl", - new BigDecimal(7315.58), - "The Diaz Ltd Dealer Sl is a reliable choice" + - " for urban cycling. The Diaz Ltd Dealer Sl " + - "is a comfortable choice for urban cycling.", - "used" - ); - // STEP_END - - Bicycle[] bicycles = { - bike1, - new Bicycle( - "Bridges Group", - "Project Pro", - new BigDecimal(3610.82), - "This mountain bike is perfect for mountain biking. The Bridges" + - " Group Project Pro is a responsive choice for mountain biking.", - "used" - ), - new Bicycle( - "Vega, Cole and Miller", - "Group Advanced", - new BigDecimal(8961.42), - "The Vega, Cole and Miller Group Advanced provides a excellent" + - " ride. With its fast carbon frame and 24 gears, this bicycle is" + - " perfect for any terrain.", - "used" - ), - new Bicycle( - "Powell-Montgomery", - "Angle Race", - new BigDecimal(4050.27), - "The Powell-Montgomery Angle Race is a smooth choice for road" + - " cycling. The Powell-Montgomery Angle Race provides a durable" + - " ride.", - "used" - ), - new Bicycle( - "Gill-Lewis", - "Action Evo", - new BigDecimal(283.68), - "The Gill-Lewis Action Evo provides a smooth ride. The Gill-Lewis" + - " Action Evo provides a excellent ride.", - "used" - ), - new Bicycle( - "Rodriguez-Guerrero", - "Drama Comp", - new BigDecimal(4462.55), - "This kids bike is perfect for young riders. With its excellent" + - " aluminum frame and 12 gears, this bicycle is perfect for any" + - " terrain.", - "new" - ), - new Bicycle( - "Moore PLC", - "Award Race", - new BigDecimal(3790.76), - - "This olive folding bike features a carbon frame and 27.5 inch" + - " wheels. This folding bike is perfect for compact storage and" + - " transportation.", - "new" - ), - new Bicycle( - "Hall, Haley and Hayes", - "Weekend Plus", - new BigDecimal(2008.4), - "The Hall, Haley and Hayes Weekend Plus provides a comfortable" + - " ride. This blue kids bike features a steel frame and 29.0 inch" + - " wheels.", - "new" - ), - new Bicycle( - "Peck-Carson", - "Sun Hybrid", - new BigDecimal(9874.95), - "With its comfortable aluminum frame and 25 gears, this bicycle is" + - " perfect for any terrain. The Peck-Carson Sun Hybrid provides a" + - " comfortable ride.", - "new" - ), - new Bicycle( - "Fowler Ltd", - "Weekend Trail", - new BigDecimal(3833.71), - "The Fowler Ltd Letter Trail is a comfortable choice for" + - " transporting cargo. This cargo bike is perfect for transporting" + - " cargo.", - "refurbished" - ) - }; - - // STEP_START define_index - SchemaField[] schema = { - TextField.of("$.brand").as("brand"), - TextField.of("$.model").as("model"), - TextField.of("$.description").as("description"), - NumericField.of("$.price").as("price"), - TagField.of("$.condition").as("condition") - }; - // STEP_END - - // STEP_START create_index - jedis.ftCreate("idx:bicycle", - FTCreateParams.createParams() - .on(IndexDataType.JSON) - .addPrefix("bicycle:"), - schema - ); - // STEP_END - // STEP_START add_documents - for (int i = 0; i < bicycles.length; i++) { - jedis.jsonSetWithEscape(String.format("bicycle:%d", i), bicycles[i]); - } - // STEP_END - - // STEP_START query_single_term_and_num_range - Query query = new Query("folding @price:[1000 4000]"); - List result = jedis.ftSearch("idx:bicycle", query).getDocuments(); - System.out.println(result); - // Prints: [id:bicycle:6, score: 1.0, payload:null, properties:[ - // $={"brand":"Moore PLC","model":"Award Race","price":3790.76, - // "description":"This olive folding bike features a carbon frame and 27.5 inch wheels. - // This folding bike is perfect for compact storage and transportation.","condition":"new"}] - // ] - // STEP_END - // REMOVE_START - assertEquals("Validate folding bike id", "bicycle:6", result.get(0).getId()); - // REMOVE_END - - // STEP_START query_single_term_limit_fields - Query cargo_query = new Query("cargo").returnFields("price"); - List cargo_result = jedis.ftSearch( - "idx:bicycle", cargo_query).getDocuments(); - System.out.println(cargo_result); - // Prints: [id:bicycle:9, score: 1.0, payload:null, properties:[price=3833.71]] - // STEP_END - // REMOVE_START - assertEquals("Validate cargo bike id", "bicycle:9", cargo_result.get(0).getId()); - // REMOVE_END - - // STEP_START simple_aggregation - AggregationBuilder ab = new AggregationBuilder("*") - .groupBy("@condition", Reducers.count().as("count")); - AggregationResult ar = jedis.ftAggregate("idx:bicycle", ab); - - for (int i = 0; i < ar.getTotalResults(); i++) { - System.out.println( - ar.getRow(i).getString("condition") - + " - " - + ar.getRow(i).getString("count")); - } - // Prints: - // refurbished - 1 - // used - 5 - // new - 4 - // STEP_END - // REMOVE_START - assertEquals("Validate aggregation results", 3, ar.getTotalResults()); - // REMOVE_END + @Test + public void run() { + // STEP_START connect + // UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379"); + JedisPooled jedis = new JedisPooled("localhost", 6379); + // STEP_END + // REMOVE_START + try { + jedis.ftDropIndex("idx:bicycle"); + } catch (JedisDataException e) { + System.out.println("Can't connect to Redis: " + e.getMessage()); } -} -//HIDE_END + // REMOVE_END + + // STEP_START create_index + SchemaField[] schema = { + TextField.of("$.brand").as("brand"), + TextField.of("$.model").as("model"), + TextField.of("$.description").as("description"), + NumericField.of("$.price").as("price"), + TagField.of("$.condition").as("condition") + }; + + jedis.ftCreate("idx:bicycle", + FTCreateParams.createParams() + .on(IndexDataType.JSON) + .addPrefix("bicycle:"), + schema + ); + // STEP_END + + Bicycle[] bicycles = { + new Bicycle( + "Velorim", + "Jigger", + new BigDecimal(270), + "new", + "Small and powerful, the Jigger is the best ride " + + "for the smallest of tikes! This is the tiniest " + + "kids’ pedal bike on the market available without" + + " a coaster brake, the Jigger is the vehicle of " + + "choice for the rare tenacious little rider " + + "raring to go." + ), + new Bicycle( + "Bicyk", + "Hillcraft", + new BigDecimal(1200), + "used", + "Kids want to ride with as little weight as possible." + + " Especially on an incline! They may be at the age " + + "when a 27.5 inch wheel bike is just too clumsy coming " + + "off a 24 inch bike. The Hillcraft 26 is just the solution" + + " they need!" + ), + new Bicycle( + "Nord", + "Chook air 5", + new BigDecimal(815), + "used", + "The Chook Air 5 gives kids aged six years and older " + + "a durable and uberlight mountain bike for their first" + + " experience on tracks and easy cruising through forests" + + " and fields. The lower top tube makes it easy to mount" + + " and dismount in any situation, giving your kids greater" + + " safety on the trails." + ), + new Bicycle( + "Eva", + "Eva 291", + new BigDecimal(3400), + "used", + "The sister company to Nord, Eva launched in 2005 as the" + + " first and only women-dedicated bicycle brand. Designed" + + " by women for women, allEva bikes are optimized for the" + + " feminine physique using analytics from a body metrics" + + " database. If you like 29ers, try the Eva 291. It's a " + + "brand new bike for 2022.. This full-suspension, " + + "cross-country ride has been designed for velocity. The" + + " 291 has 100mm of front and rear travel, a superlight " + + "aluminum frame and fast-rolling 29-inch wheels. Yippee!" + ), + new Bicycle( + "Noka Bikes", + "Kahuna", + new BigDecimal(3200), + "used", + "Whether you want to try your hand at XC racing or are " + + "looking for a lively trail bike that's just as inspiring" + + " on the climbs as it is over rougher ground, the Wilder" + + " is one heck of a bike built specifically for short women." + + " Both the frames and components have been tweaked to " + + "include a women’s saddle, different bars and unique " + + "colourway." + ), + new Bicycle( + "Breakout", + "XBN 2.1 Alloy", + new BigDecimal(810), + "new", + "The XBN 2.1 Alloy is our entry-level road bike – but that’s" + + " not to say that it’s a basic machine. With an internal " + + "weld aluminium frame, a full carbon fork, and the slick-shifting" + + " Claris gears from Shimano’s, this is a bike which doesn’t" + + " break the bank and delivers craved performance." + ), + new Bicycle( + "ScramBikes", + "WattBike", + new BigDecimal(2300), + "new", + "The WattBike is the best e-bike for people who still feel young" + + " at heart. It has a Bafang 1000W mid-drive system and a 48V" + + " 17.5AH Samsung Lithium-Ion battery, allowing you to ride for" + + " more than 60 miles on one charge. It’s great for tackling hilly" + + " terrain or if you just fancy a more leisurely ride. With three" + + " working modes, you can choose between E-bike, assisted bicycle," + + " and normal bike modes." + ), + new Bicycle( + "Peaknetic", + "Secto", + new BigDecimal(430), + "new", + "If you struggle with stiff fingers or a kinked neck or back after" + + " a few minutes on the road, this lightweight, aluminum bike" + + " alleviates those issues and allows you to enjoy the ride. From" + + " the ergonomic grips to the lumbar-supporting seat position, the" + + " Roll Low-Entry offers incredible comfort. The rear-inclined seat" + + " tube facilitates stability by allowing you to put a foot on the" + + " ground to balance at a stop, and the low step-over frame makes it" + + " accessible for all ability and mobility levels. The saddle is" + + " very soft, with a wide back to support your hip joints and a" + + " cutout in the center to redistribute that pressure. Rim brakes" + + " deliver satisfactory braking control, and the wide tires provide" + + " a smooth, stable ride on paved roads and gravel. Rack and fender" + + " mounts facilitate setting up the Roll Low-Entry as your preferred" + + " commuter, and the BMX-like handlebar offers space for mounting a" + + " flashlight, bell, or phone holder." + ), + new Bicycle( + "nHill", + "Summit", + new BigDecimal(1200), + "new", + "This budget mountain bike from nHill performs well both on bike" + + " paths and on the trail. The fork with 100mm of travel absorbs" + + " rough terrain. Fat Kenda Booster tires give you grip in corners" + + " and on wet trails. The Shimano Tourney drivetrain offered enough" + + " gears for finding a comfortable pace to ride uphill, and the" + + " Tektro hydraulic disc brakes break smoothly. Whether you want an" + + " affordable bike that you can take to work, but also take trail in" + + " mountains on the weekends or you’re just after a stable," + + " comfortable ride for the bike path, the Summit gives a good value" + + " for money." + ), + new Bicycle( + "ThrillCycle", + "BikeShind", + new BigDecimal(815), + "refurbished", + "An artsy, retro-inspired bicycle that’s as functional as it is" + + " pretty: The ThrillCycle steel frame offers a smooth ride. A" + + " 9-speed drivetrain has enough gears for coasting in the city, but" + + " we wouldn’t suggest taking it to the mountains. Fenders protect" + + " you from mud, and a rear basket lets you transport groceries," + + " flowers and books. The ThrillCycle comes with a limited lifetime" + + " warranty, so this little guy will last you long past graduation." + ), + }; + + // STEP_START add_documents + for (int i = 0; i < bicycles.length; i++) { + jedis.jsonSetWithEscape(String.format("bicycle:%d", i), bicycles[i]); + } + // STEP_END + + // STEP_START wildcard_query + Query query1 = new Query("*"); + List result1 = jedis.ftSearch("idx:bicycle", query1).getDocuments(); + System.out.println("Documents found:" + result1.size()); + // Prints: Documents found: 10 + // STEP_END + // REMOVE_START + assertEquals("Validate total results", 10, result1.size()); + // REMOVE_END + + // STEP_START query_single_term + Query query2 = new Query("@model:Jigger"); + List result2 = jedis.ftSearch("idx:bicycle", query2).getDocuments(); + System.out.println(result2); + // Prints: [id:bicycle:0, score: 1.0, payload:null, + // properties:[$={"brand":"Velorim","model":"Jigger","price":270,"description":"Small and powerful, the Jigger is the best ride for the smallest of tikes! This is the tiniest kids’ pedal bike on the market available without a coaster brake, the Jigger is the vehicle of choice for the rare tenacious little rider raring to go.","condition":"new"}]] + // STEP_END + // REMOVE_START + assertEquals("Validate bike id", "bicycle:0", result2.get(0).getId()); + // REMOVE_END + + // STEP_START query_single_term_limit_fields + Query query3 = new Query("@model:Jigger").returnFields("price"); + List result3 = jedis.ftSearch("idx:bicycle", query3).getDocuments(); + System.out.println(result3); + // Prints: [id:bicycle:0, score: 1.0, payload:null, properties:[price=270]] + // STEP_END + // REMOVE_START + assertEquals("Validate cargo bike id", "bicycle:0", result3.get(0).getId()); + // REMOVE_END + + // STEP_START query_single_term_and_num_range + Query query4 = new Query("basic @price:[500 1000]"); + List result4 = jedis.ftSearch("idx:bicycle", query4).getDocuments(); + System.out.println(result4); + // Prints: [id:bicycle:5, score: 1.0, payload:null, + // properties:[$={"brand":"Breakout","model":"XBN 2.1 Alloy","price":810,"description":"The XBN 2.1 Alloy is our entry-level road bike – but that’s not to say that it’s a basic machine. With an internal weld aluminium frame, a full carbon fork, and the slick-shifting Claris gears from Shimano’s, this is a bike which doesn’t break the bank and delivers craved performance.","condition":"new"}]] + // STEP_END + // REMOVE_START + assertEquals("Validate bike id", "bicycle:5", result4.get(0).getId()); + // REMOVE_END + + // STEP_START query_exact_matching + Query query5 = new Query("@brand:\"Noka Bikes\""); + List result5 = jedis.ftSearch("idx:bicycle", query5).getDocuments(); + System.out.println(result5); + // Prints: [id:bicycle:4, score: 1.0, payload:null, + // properties:[$={"brand":"Noka Bikes","model":"Kahuna","price":3200,"description":"Whether you want to try your hand at XC racing or are looking for a lively trail bike that's just as inspiring on the climbs as it is over rougher ground, the Wilder is one heck of a bike built specifically for short women. Both the frames and components have been tweaked to include a women’s saddle, different bars and unique colourway.","condition":"used"}]] + // STEP_END + // REMOVE_START + assertEquals("Validate bike id", "bicycle:4", result5.get(0).getId()); + // REMOVE_END + + // STEP_START simple_aggregation + AggregationBuilder ab = new AggregationBuilder("*").groupBy("@condition", + Reducers.count().as("count")); + AggregationResult ar = jedis.ftAggregate("idx:bicycle", ab); + for (int i = 0; i < ar.getTotalResults(); i++) { + System.out.println(ar.getRow(i).getString("condition") + " - " + + ar.getRow(i).getString("count")); + } + // Prints: + // refurbished - 1 + // used - 5 + // new - 4 + assertEquals("Validate aggregation results", 3, ar.getTotalResults()); + // STEP_END + + jedis.close(); + } +} \ No newline at end of file diff --git a/src/test/java/io/redis/examples/SetGetExample.java b/src/test/java/io/redis/examples/SetGetExample.java index 282f1aebb2b..fa4485ef464 100644 --- a/src/test/java/io/redis/examples/SetGetExample.java +++ b/src/test/java/io/redis/examples/SetGetExample.java @@ -1,36 +1,35 @@ -//EXAMPLE: set_and_get -//HIDE_START +// EXAMPLE: set_and_get +// HIDE_START package io.redis.examples; import redis.clients.jedis.UnifiedJedis; -//REMOVE_START +// REMOVE_START import org.junit.Test; import static org.junit.Assert.assertEquals; -//REMOVE_END + +// REMOVE_END public class SetGetExample { - @Test - public void run() { + @Test + public void run() { - UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379"); + UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379"); - //HIDE_END - String status = jedis.set("bike:1", "Process 134"); + // HIDE_END + String status = jedis.set("bike:1", "Process 134"); - if ("OK".equals(status)) - System.out.println("Successfully added a bike."); + if ("OK".equals(status)) System.out.println("Successfully added a bike."); - String value = jedis.get("bike:1"); + String value = jedis.get("bike:1"); - if ( value != null) - System.out.println("The name of the bike is: " + value + "."); - //HIDE_START + if (value != null) System.out.println("The name of the bike is: " + value + "."); + // HIDE_START - //REMOVE_START - assertEquals("OK", status); - assertEquals("Process 134", value); - //REMOVE_END - } + // REMOVE_START + assertEquals("OK", status); + assertEquals("Process 134", value); + // REMOVE_END + } } -//HIDE_END +// HIDE_END diff --git a/src/test/java/io/redis/examples/SetsExample.java b/src/test/java/io/redis/examples/SetsExample.java new file mode 100644 index 00000000000..ceb8152017f --- /dev/null +++ b/src/test/java/io/redis/examples/SetsExample.java @@ -0,0 +1,185 @@ +//EXAMPLE: sets_tutorial +//HIDE_START +package io.redis.examples; + +import redis.clients.jedis.UnifiedJedis; +import org.junit.Test; +import java.util.List; +import java.util.Set; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertEquals; + +public class SetsExample { + + @Test + public void run() { + UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379"); + // HIDE_END + // REMOVE_START + jedis.del("bikes:racing:france"); + jedis.del("bikes:racing:usa"); + // REMOVE_END + // STEP_START sadd + long res1 = jedis.sadd("bikes:racing:france", "bike:1"); + System.out.println(res1); // >>> 1 + + long res2 = jedis.sadd("bikes:racing:france", "bike:1"); + System.out.println(res2); // >>> 0 + + long res3 = jedis.sadd("bikes:racing:france", "bike:2", "bike:3"); + System.out.println(res3); // >>> 2 + + long res4 = jedis.sadd("bikes:racing:usa", "bike:1", "bike:4"); + System.out.println(res4); // >>> 2 + // STEP_END + + // REMOVE_START + assertEquals(1,res1); + assertEquals(0,res2); + assertEquals(2,res3); + assertEquals(2,res4); + // REMOVE_END + + // STEP_START sismember + // HIDE_START + jedis.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3"); + jedis.sadd("bikes:racing:usa", "bike:1", "bike:4"); + // HIDE_END + + boolean res5 = jedis.sismember("bikes:racing:usa", "bike:1"); + System.out.println(res5); // >>> true + + boolean res6 = jedis.sismember("bikes:racing:usa", "bike:2"); + System.out.println(res6); // >>> false + // STEP_END + + // REMOVE_START + assertTrue(res5); + assertFalse(res6); + // REMOVE_END + + // STEP_START sinter + // HIDE_START + jedis.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3"); + jedis.sadd("bikes:racing:usa", "bike:1", "bike:4"); + // HIDE_END + + Set res7 = jedis.sinter("bikes:racing:france", "bikes:racing:usa"); + System.out.println(res7); // >>> [bike:1] + // STEP_END + + // REMOVE_START + assertEquals("[bike:1]",res7.toString()); + // REMOVE_END + + // STEP_START scard + jedis.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3"); + + long res8 = jedis.scard("bikes:racing:france"); + System.out.println(res8); // >>> 3 + // STEP_END + + // REMOVE_START + assertEquals(3,res8); + jedis.del("bikes:racing:france"); + // REMOVE_END + + // STEP_START sadd_smembers + long res9 = jedis.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3"); + System.out.println(res9); // >>> 3 + + Set res10 = jedis.smembers("bikes:racing:france"); + System.out.println(res10); // >>> [bike:1, bike:2, bike:3] + // STEP_END + + // REMOVE_START + assertEquals(3,res9); + assertEquals("[bike:1, bike:2, bike:3]",res10.toString()); + // REMOVE_END + + // STEP_START smismember + boolean res11 = jedis.sismember("bikes:racing:france", "bike:1"); + System.out.println(res11); // >>> true + + List res12 = jedis.smismember("bikes:racing:france", "bike:2", "bike:3", "bike:4"); + System.out.println(res12); // >>> [true,true,false] + // STEP_END + + // REMOVE_START + assertTrue(res11); + assertEquals("[true, true, false]",res12.toString()); + // REMOVE_END + + // STEP_START sdiff + jedis.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3"); + jedis.sadd("bikes:racing:usa", "bike:1", "bike:4"); + + Set res13 = jedis.sdiff("bikes:racing:france", "bikes:racing:usa"); + System.out.println(res13); // >>> [bike:2, bike:3] + + // REMOVE_START + assertEquals("[bike:2, bike:3]",res13.toString()); + jedis.del("bikes:racing:france"); + jedis.del("bikes:racing:usa"); + // REMOVE_END + // STEP_END + + // STEP_START multisets + jedis.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3"); + jedis.sadd("bikes:racing:usa", "bike:1", "bike:4"); + jedis.sadd("bikes:racing:italy", "bike:1", "bike:2", "bike:3", "bike:4"); + + Set res14 = jedis.sinter("bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy"); + System.out.println(res14); // >>> [bike:1] + + Set res15 = jedis.sunion("bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy"); + System.out.println(res15); // >>> [bike:1, bike:2, bike:3, bike:4] + + Set res16 = jedis.sdiff("bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy"); + System.out.println(res16); // >>> [] + + Set res17 = jedis.sdiff("bikes:racing:usa", "bikes:racing:france"); + System.out.println(res17); // >>> [bike:4] + + Set res18 = jedis.sdiff("bikes:racing:france", "bikes:racing:usa"); + System.out.println(res18); // >>> [bike:2, bike:3] + + // REMOVE_START + assertEquals("[bike:1]",res14.toString()); + assertEquals("[bike:1, bike:2, bike:3, bike:4]",res15.toString()); + assertEquals("[]",res16.toString()); + assertEquals("[bike:4]",res17.toString()); + assertEquals("[bike:2, bike:3]",res18.toString()); + jedis.del("bikes:racing:france"); + jedis.del("bikes:racing:usa"); + jedis.del("bikes:racing:italy"); + // REMOVE_END + // STEP_END + + // STEP_START srem + jedis.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3", "bike:4", "bike:5"); + + long res19 = jedis.srem("bikes:racing:france", "bike:1"); + System.out.println(res18); // >>> 1 + + String res20 = jedis.spop("bikes:racing:france"); + System.out.println(res20); // >>> bike:3 + + Set res21 = jedis.smembers("bikes:racing:france"); + System.out.println(res21); // >>> [bike:2, bike:4, bike:5] + + String res22 = jedis.srandmember("bikes:racing:france"); + System.out.println(res22); // >>> bike:4 + // STEP_END + + // REMOVE_START + assertEquals(1,res19); + // REMOVE_END + + // HIDE_START + jedis.close(); + // HIDE_END + } +} diff --git a/src/test/java/io/redis/examples/SortedSetsExample.java b/src/test/java/io/redis/examples/SortedSetsExample.java new file mode 100644 index 00000000000..946e181011d --- /dev/null +++ b/src/test/java/io/redis/examples/SortedSetsExample.java @@ -0,0 +1,124 @@ +//EXAMPLE: ss_tutorial +//HIDE_START +package io.redis.examples; + +import redis.clients.jedis.UnifiedJedis; +import redis.clients.jedis.resps.Tuple; +//HIDE_END + +//REMOVE_START +import org.junit.Test; +import java.util.HashMap; +import java.util.List; + +import static org.junit.Assert.assertEquals; +//REMOVE_END + +public class SortedSetsExample { + + @Test + public void run() { + + //HIDE_START + UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379"); + //HIDE_END + + //REMOVE_START + jedis.del("racer_scores"); + //REMOVE_END + + //STEP_START zadd + long res1 = jedis.zadd("racer_scores", 10d, "Norem"); + System.out.println(res1); // >>> 1 + + long res2 = jedis.zadd("racer_scores", 12d, "Castilla"); + System.out.println(res2); // >>> 1 + + long res3 = jedis.zadd("racer_scores", new HashMap() {{ + put("Sam-Bodden", 8d); + put("Royce", 10d); + put("Ford", 6d); + put("Prickett", 14d); + put("Castilla", 12d); + }}); + System.out.println(res3); // >>> 4 + //STEP_END + + //STEP_START zrange + List res4 = jedis.zrange("racer_scores", 0, -1); + System.out.println(res4); // >>> [Ford, Sam-Bodden, Norem, Royce, Castil, Castilla, Prickett] + + List res5 = jedis.zrevrange("racer_scores", 0, -1); + System.out.println(res5); // >>> [Prickett, Castilla, Castil, Royce, Norem, Sam-Bodden, Ford] + //STEP_END + + //STEP_START zrange_withscores + List res6 = jedis.zrangeWithScores("racer_scores", 0, -1); + System.out.println(res6); // >>> [[Ford,6.0], [Sam-Bodden,8.0], [Norem,10.0], [Royce,10.0], [Castil,12.0], [Castilla,12.0], [Prickett,14.0]] + //STEP_END + + //STEP_START zrangebyscore + List res7 = jedis.zrangeByScore("racer_scores", Double.MIN_VALUE, 10d); + System.out.println(res7); // >>> [Ford, Sam-Bodden, Norem, Royce] + //STEP_END + + //STEP_START zremrangebyscore + long res8 = jedis.zrem("racer_scores", "Castilla"); + System.out.println(res8); // >>> 1 + + long res9 = jedis.zremrangeByScore("racer_scores", Double.MIN_VALUE, 9d); + System.out.println(res9); // >>> 2 + + List res10 = jedis.zrange("racer_scores", 0, -1); + System.out.println(res10); // >>> [Norem, Royce, Prickett] + //STEP_END + + //REMOVE_START + assertEquals(3, jedis.zcard("racer_scores")); + //REMOVE_END + + //STEP_START zrank + long res11 = jedis.zrank("racer_scores", "Norem"); + System.out.println(res11); // >>> 0 + + long res12 = jedis.zrevrank("racer_scores", "Norem"); + System.out.println(res12); // >>> 2 + //STEP_END + + //STEP_START zadd_lex + long res13 = jedis.zadd("racer_scores", new HashMap() {{ + put("Norem", 0d); + put("Sam-Bodden", 0d); + put("Royce", 0d); + put("Ford", 0d); + put("Prickett", 0d); + put("Castilla", 0d); + }}); + System.out.println(res13); // >>> 3 + + List res14 = jedis.zrange("racer_scores", 0, -1); + System.out.println(res14); // >>> [Castilla, Ford, Norem, Prickett, Royce, Sam-Bodden] + + List res15 = jedis.zrangeByLex("racer_scores", "[A", "[L"); + System.out.println(res15); // >>> [Castilla, Ford] + //STEP_END + + //STEP_START leaderboard + long res16 = jedis.zadd("racer_scores", 100d, "Wood"); + System.out.println(res16); // >>> 1 + + long res17 = jedis.zadd("racer_scores", 100d, "Henshaw"); + System.out.println(res17); // >>> 1 + + long res18 = jedis.zadd("racer_scores", 100d, "Henshaw"); + System.out.println(res18); // >>> 0 + + double res19 = jedis.zincrby("racer_scores", 50d, "Wood"); + System.out.println(res19); // >>> 150.0 + + double res20 = jedis.zincrby("racer_scores", 50d, "Henshaw"); + System.out.println(res20); // >>> 200.0 + //STEP_END + } +} + diff --git a/src/test/java/io/redis/examples/StreamsExample.java b/src/test/java/io/redis/examples/StreamsExample.java new file mode 100644 index 00000000000..5190a1ba7db --- /dev/null +++ b/src/test/java/io/redis/examples/StreamsExample.java @@ -0,0 +1,270 @@ +//EXAMPLE: stream_tutorial +//HIDE_START +package io.redis.examples; + +import redis.clients.jedis.StreamEntryID; +import redis.clients.jedis.UnifiedJedis; +//HIDE_END + +//REMOVE_START +import org.junit.Test; +import redis.clients.jedis.exceptions.JedisDataException; +import redis.clients.jedis.params.*; +import redis.clients.jedis.resps.*; + +import java.util.*; + +import static org.junit.Assert.assertEquals; +//REMOVE_END + +public class StreamsExample { + + @Test + public void run(){ + + //HIDE_START + UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379"); + //HIDE_END + + //REMOVE_START + jedis.del("race:france", "race:italy", "race:usa"); + //REMOVE_END + + // STEP_START xadd + StreamEntryID res1 = jedis.xadd("race:france",new HashMap(){{put("rider","Castilla");put("speed","30.2");put("position","1");put("location_id","1");}} , XAddParams.xAddParams()); + + System.out.println(res1); // >>> 1701760582225-0 + + StreamEntryID res2 = jedis.xadd("race:france",new HashMap(){{put("rider","Norem");put("speed","28.8");put("position","3");put("location_id","1");}} , XAddParams.xAddParams()); + + System.out.println(res2); // >>> 1701760582225-1 + + StreamEntryID res3 = jedis.xadd("race:france",new HashMap(){{put("rider","Prickett");put("speed","29.7");put("position","2");put("location_id","1");}} , XAddParams.xAddParams()); + + System.out.println(res3); // >>> 1701760582226-0 + //STEP_END + + //REMOVE_START + assertEquals(jedis.xlen("race:france"),3); + //REMOVE_END + + //STEP_START xrange + List res4 = jedis.xrange("race:france","1701760582225-0","+",2); + + System.out.println(res4); // >>> [1701760841292-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701760841292-1 {rider=Norem, speed=28.8, location_id=1, position=3}] + //STEP_END + + //STEP_START xread_block + List>> res5= jedis.xread(XReadParams.xReadParams().block(300).count(100),new HashMap(){{put("race:france",new StreamEntryID());}}); + System.out.println( + res5 + ); // >>> [race:france=[1701761996660-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701761996661-0 {rider=Norem, speed=28.8, location_id=1, position=3}, 1701761996661-1 {rider=Prickett, speed=29.7, location_id=1, position=2}]] + //STEP_END + + //STEP_START xadd_2 + StreamEntryID res6 = jedis.xadd("race:france",new HashMap(){{put("rider","Castilla");put("speed","29.9");put("position","2");put("location_id","1");}} , XAddParams.xAddParams()); + System.out.println(res6); // >>> 1701762285679-0 + //STEP_END + + //STEP_START xlen + long res7 = jedis.xlen("race:france"); + System.out.println(res7); // >>> 4 + //STEP_END + + //STEP_START xadd_id + StreamEntryID res8 = jedis.xadd("race:usa", new HashMap(){{put("racer","Castilla");}},XAddParams.xAddParams().id("0-1")); + System.out.println(res8); // >>> 0-1 + + StreamEntryID res9 = jedis.xadd("race:usa", new HashMap(){{put("racer","Norem");}},XAddParams.xAddParams().id("0-2")); + System.out.println(res9); // >>> 0-2 + //STEP_END + + //STEP_START xadd_bad_id + try { + StreamEntryID res10 = jedis.xadd("race:usa", new HashMap(){{put("racer","Prickett");}},XAddParams.xAddParams().id("0-1")); + System.out.println(res10); // >>> 0-1 + } + catch (JedisDataException e){ + System.out.println(e); // >>> ERR The ID specified in XADD is equal or smaller than the target stream top item + } + //STEP_END + + //STEP_START xadd_7 + StreamEntryID res11 = jedis.xadd("race:usa", new HashMap(){{put("racer","Norem");}},XAddParams.xAddParams().id("0-*")); + System.out.println(res11); + //STEP_END + + //STEP_START xrange_all + List res12 = jedis.xrange("race:france","-","+"); + System.out.println( + res12 + ); // >>> [1701764734160-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701764734160-1 {rider=Norem, speed=28.8, location_id=1, position=3}, 1701764734161-0 {rider=Prickett, speed=29.7, location_id=1, position=2}, 1701764734162-0 {rider=Castilla, speed=29.9, location_id=1, position=2}] + //STEP_END + + //STEP_START xrange_time + List res13 = jedis.xrange("race:france",String.valueOf(System.currentTimeMillis()-1000),String.valueOf(System.currentTimeMillis()+1000)); + System.out.println( + res13 + ); // >>> [1701764734160-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701764734160-1 {rider=Norem, speed=28.8, location_id=1, position=3}, 1701764734161-0 {rider=Prickett, speed=29.7, location_id=1, position=2}, 1701764734162-0 {rider=Castilla, speed=29.9, location_id=1, position=2}] + //STEP_END + + //STEP_START xrange_step_1 + List res14 = jedis.xrange("race:france","-","+",2); + System.out.println(res14); // >>> [1701764887638-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701764887638-1 {rider=Norem, speed=28.8, location_id=1, position=3}] + //STEP_END + + //STEP_START xrange_step_2 + List res15 = jedis.xrange("race:france",String.valueOf(System.currentTimeMillis()-1000)+"-0","+",2); + System.out.println(res15); // >>> [1701764887638-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701764887638-1 {rider=Norem, speed=28.8, location_id=1, position=3}] + //STEP_END + + //STEP_START xrange_empty + List res16 = jedis.xrange("race:france",String.valueOf(System.currentTimeMillis()+1000)+"-0","+",2); + System.out.println(res16); // >>> [] + // STEP_END + + //STEP_START xrevrange + List res17 = jedis.xrevrange("race:france","+","-",1); + System.out.println(res17); // >>> [1701765218592-0 {rider=Castilla, speed=29.9, location_id=1, position=2}] + //STEP_END + + //STEP_START xread + List>> res18= jedis.xread(XReadParams.xReadParams().count(2),new HashMap(){{put("race:france",new StreamEntryID());}}); + System.out.println( + res18 + ); // >>> [race:france=[1701765384638-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701765384638-1 {rider=Norem, speed=28.8, location_id=1, position=3}]] + //STEP_END + + //STEP_START xgroup_create + String res19 = jedis.xgroupCreate("race:france","france_riders",StreamEntryID.LAST_ENTRY,false); + System.out.println(res19); // >>> OK + //STEP_END + + //STEP_START xgroup_create_mkstream + String res20 = jedis.xgroupCreate("race:italy","italy_riders",StreamEntryID.LAST_ENTRY,true); + System.out.println(res20); // >>> OK + //STEP_END + + //STEP_START xgroup_read + StreamEntryID id1 = jedis.xadd("race:italy", new HashMap(){{put("rider","Castilaa");}},XAddParams.xAddParams()); + StreamEntryID id2 = jedis.xadd("race:italy", new HashMap(){{put("rider","Royce");}},XAddParams.xAddParams()); + StreamEntryID id3 = jedis.xadd("race:italy", new HashMap(){{put("rider","Sam-Bodden");}},XAddParams.xAddParams()); + StreamEntryID id4 = jedis.xadd("race:italy", new HashMap(){{put("rider","Prickett");}},XAddParams.xAddParams()); + StreamEntryID id5 = jedis.xadd("race:italy", new HashMap(){{put("rider","Norem");}},XAddParams.xAddParams()); + + List>> res21 = jedis.xreadGroup("italy_riders","Alice", XReadGroupParams.xReadGroupParams().count(1),new HashMap(){{put("race:italy",StreamEntryID.UNRECEIVED_ENTRY);}}); + System.out.println(res21); // >>> [race:italy=[1701766299006-0 {rider=Castilaa}]] + //STEP_END + + //STEP_START xgroup_read_id + List>> res22 = jedis.xreadGroup("italy_riders","Alice", XReadGroupParams.xReadGroupParams().count(1),new HashMap(){{put("race:italy",new StreamEntryID());}}); + System.out.println(res22); // >>> [race:italy=[1701766299006-0 {rider=Castilaa}]] + //STEP_END + + //STEP_START xack + long res23 = jedis.xack("race:italy","italy_riders",id1); + System.out.println(res23); // >>> 1 + + List>> res24 = jedis.xreadGroup("italy_riders","Alice", XReadGroupParams.xReadGroupParams().count(1),new HashMap(){{put("race:italy",new StreamEntryID());}}); + System.out.println(res24); // >>> [race:italy=[]] + //STEP_END + + //STEP_START xgroup_read_bob + List>> res25 = jedis.xreadGroup("italy_riders","Bob", XReadGroupParams.xReadGroupParams().count(2),new HashMap(){{put("race:italy",StreamEntryID.UNRECEIVED_ENTRY);}}); + System.out.println(res25); // >>> [race:italy=[1701767632261-1 {rider=Royce}, 1701767632262-0 {rider=Sam-Bodden}]] + //STEP_END + + //STEP_START xpending + StreamPendingSummary res26 = jedis.xpending("race:italy","italy_riders"); + System.out.println(res26.getConsumerMessageCount()); // >>> {Bob=2} + //STEP_END + + //STEP_START xpending_plus_minus + List res27 = jedis.xpending("race:italy","italy_riders",XPendingParams.xPendingParams().start(StreamEntryID.MINIMUM_ID).end(StreamEntryID.MAXIMUM_ID).count(10)); + System.out.println(res27); // >>> [1701768567412-1 Bob idle:0 times:1, 1701768567412-2 Bob idle:0 times:1] + //STEP_END + + //STEP_START xrange_pending + List res28 = jedis.xrange("race:italy",id2.toString(),id2.toString()); + System.out.println(res28); // >>> [1701768744819-1 {rider=Royce}] + //STEP_END + + //STEP_START xclaim + List res29 = jedis.xclaim("race:italy","italy_riders","Alice", 0L, XClaimParams.xClaimParams().time(60000),id2); + System.out.println(res29); // >>> [1701769004195-1 {rider=Royce}] + //STEP_END + + //STEP_START xautoclaim + Map.Entry> res30 = jedis.xautoclaim("race:italy","italy_riders","Alice",1L,new StreamEntryID("0-0"),XAutoClaimParams.xAutoClaimParams().count(1)); + System.out.println(res30); // >>> [1701769266831-2=[1701769266831-1 {rider=Royce}] + //STEP_END + + //STEP_START xautoclaim_cursor + Map.Entry> res31 = jedis.xautoclaim("race:italy","italy_riders","Alice",1L,new StreamEntryID(id2.toString()),XAutoClaimParams.xAutoClaimParams().count(1)); + System.out.println(res31); // >>> [0-0=[1701769605847-2 {rider=Sam-Bodden}] + //STEP_END + + //STEP_START xinfo + StreamInfo res32 = jedis.xinfoStream("race:italy"); + System.out.println( + res32.getStreamInfo() + ); // >>> {radix-tree-keys=1, radix-tree-nodes=2, entries-added=5, length=5, groups=1, max-deleted-entry-id=0-0, first-entry=1701769637612-0 {rider=Castilaa}, last-generated-id=1701769637612-4, last-entry=1701769637612-4 {rider=Norem}, recorded-first-entry-id=1701769637612-0} + //STEP_END + + //STEP_START xinfo_groups + List res33 = jedis.xinfoGroups("race:italy"); + for (StreamGroupInfo a : res33){ + System.out.println( + a.getGroupInfo() + ); // >>> {last-delivered-id=1701770253659-0, lag=2, pending=2, name=italy_riders, consumers=2, entries-read=3} + } + //STEP_END + + //STEP_START xinfo_consumers + List res34 = jedis.xinfoConsumers("race:italy","italy_riders"); + for (StreamConsumerInfo a : res34){ + System.out.println( + a.getConsumerInfo() + ); // {inactive=1, idle=1, pending=1, name=Alice} , {inactive=3, idle=3, pending=1, name=Bob} + } + //STEP_END + + //STEP_START maxlen + jedis.xadd("race:italy", new HashMap(){{put("rider","Jones");}},XAddParams.xAddParams().maxLen(10)); + jedis.xadd("race:italy", new HashMap(){{put("rider","Wood");}},XAddParams.xAddParams().maxLen(10)); + jedis.xadd("race:italy", new HashMap(){{put("rider","Henshaw");}},XAddParams.xAddParams().maxLen(10)); + long res35 = jedis.xlen("race:italy"); + System.out.println(res35); // >>> 8 + + List res36 = jedis.xrange("race:italy","-","+"); + System.out.println(res36); // >>> [1701771219852-0 {rider=Castilaa}, 1701771219852-1 {rider=Royce}, 1701771219853-0 {rider=Sam-Bodden}, 1701771219853-1 {rider=Prickett}, 1701771219853-2 {rider=Norem}, 1701771219858-0 {rider=Jones}, 1701771219858-1 {rider=Wood}, 1701771219859-0 {rider=Henshaw}] + + StreamEntryID id6 = jedis.xadd("race:italy", new HashMap(){{put("rider","Smith");}},XAddParams.xAddParams().maxLen(2)); + + List res37 = jedis.xrange("race:italy","-","+"); + System.out.println(res37); // >>> [1701771067332-1 {rider=Henshaw}, 1701771067332-2 {rider=Smith}] + //STEP_END + + //STEP_START xtrim + long res38 = jedis.xtrim("race:italy",XTrimParams.xTrimParams().maxLen(10).exactTrimming()); + System.out.println(res38); /// >>> 0 + //STEP_END + + //STEP_START xtrim2 + long res39 = jedis.xtrim("race:italy",XTrimParams.xTrimParams().maxLen(10)); + System.out.println(res39); /// >>> 0 + //STEP_END + + //STEP_START xdel + List res40 = jedis.xrange("race:italy","-","+"); + System.out.println(res40); // >>> [1701771356428-2 {rider=Henshaw}, 1701771356429-0 {rider=Smith}] + + long res41 = jedis.xdel("race:italy",id6); + System.out.println(res41); // >>> 1 + + List res42 = jedis.xrange("race:italy","-","+"); + System.out.println(res42); // >>> [1701771517639-1 {rider=Henshaw}] + //STEP_END + } + +} diff --git a/src/test/java/io/redis/examples/StringExample.java b/src/test/java/io/redis/examples/StringExample.java new file mode 100644 index 00000000000..d868568a74a --- /dev/null +++ b/src/test/java/io/redis/examples/StringExample.java @@ -0,0 +1,75 @@ +// EXAMPLE: set_tutorial +package io.redis.examples; + +//REMOVE_START +import org.junit.Test; +import static org.junit.Assert.*; +//REMOVE_END + +import redis.clients.jedis.UnifiedJedis; +import redis.clients.jedis.params.SetParams; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class StringExample { + @Test + public void run() { + try (UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379")) { + + // STEP_START set_get + String res1 = jedis.set("bike:1", "Deimos"); + System.out.println(res1); // OK + String res2 = jedis.get("bike:1"); + System.out.println(res2); // Deimos + // STEP_END + + // REMOVE_START + assertEquals("OK", res1); + assertEquals("Deimos", res2); + // REMOVE_END + + // STEP_START setnx_xx + Long res3 = jedis.setnx("bike:1", "bike"); + System.out.println(res3); // 0 (because key already exists) + System.out.println(jedis.get("bike:1")); // Deimos (value is unchanged) + String res4 = jedis.set("bike:1", "bike", SetParams.setParams().xx()); // set the value to "bike" if it + // already + // exists + System.out.println(res4); // OK + // STEP_END + + // REMOVE_START + assertEquals(0L, res3.longValue()); + assertEquals("OK", res4); + // REMOVE_END + + // STEP_START mset + String res5 = jedis.mset("bike:1", "Deimos", "bike:2", "Ares", "bike:3", "Vanth"); + System.out.println(res5); // OK + List res6 = jedis.mget("bike:1", "bike:2", "bike:3"); + System.out.println(res6); // [Deimos, Ares, Vanth] + // STEP_END + + // REMOVE_START + assertEquals("OK", res5); + List expected = new ArrayList<>(Arrays.asList("Deimos", "Ares", "Vanth")); + assertEquals(expected, res6); + // REMOVE_END + + // STEP_START incr + jedis.set("total_crashes", "0"); + Long res7 = jedis.incr("total_crashes"); + System.out.println(res7); // 1 + Long res8 = jedis.incrBy("total_crashes", 10); + System.out.println(res8); // 11 + // STEP_END + + // REMOVE_START + assertEquals(1L, res7.longValue()); + assertEquals(11L, res8.longValue()); + // REMOVE_END + } + } +} diff --git a/src/test/java/io/redis/examples/TDigestExample.java b/src/test/java/io/redis/examples/TDigestExample.java new file mode 100644 index 00000000000..28c851a25bc --- /dev/null +++ b/src/test/java/io/redis/examples/TDigestExample.java @@ -0,0 +1,85 @@ +//EXAMPLE: tdigest_tutorial +//HIDE_START +package io.redis.examples; +//HIDE_END + +//REMOVE_START +import org.junit.Assert; +import org.junit.Test; +import redis.clients.jedis.UnifiedJedis; +import java.util.List; +//REMOVE_END + +public class TDigestExample { + @Test + public void run(){ + //HIDE_START + UnifiedJedis unifiedJedis = new UnifiedJedis("redis://127.0.0.1:6379"); + //HIDE_END + + //REMOVE_START + unifiedJedis.del("racer_ages"); + unifiedJedis.del("bikes:sales"); + //REMOVE_END + + //STEP_START tdig_start + String res1 = unifiedJedis.tdigestCreate("bikes:sales", 100); + System.out.println(res1); // >>> True + + String res2 = unifiedJedis.tdigestAdd("bikes:sales", 21); + System.out.println(res2); // >>> OK + + String res3 = unifiedJedis.tdigestAdd("bikes:sales", 150, 95, 75, 34); + System.out.println(res3); // >>> OK + //STEP_END + + //REMOVE_START + Assert.assertEquals("OK","OK"); + //REMOVE_END + + //STEP_START tdig_cdf + String res4 = unifiedJedis.tdigestCreate("racer_ages"); + System.out.println(res4); // >>> True + + String res5 = unifiedJedis.tdigestAdd("racer_ages", 45.88, + 44.2, + 58.03, + 19.76, + 39.84, + 69.28, + 50.97, + 25.41, + 19.27, + 85.71, + 42.63); + System.out.println(res5); // >>> OK + + List res6 = unifiedJedis.tdigestRank("racer_ages", 50); + System.out.println(res6); // >>> [7] + + List res7 = unifiedJedis.tdigestRank("racer_ages", 50, 40); + System.out.println(res7); // >>> [7, 4] + //STEP_END + + //STEP_START tdig_quant + List res8 = unifiedJedis.tdigestQuantile("racer_ages", 0.5); + System.out.println(res8); // >>> [44.2] + + List res9 = unifiedJedis.tdigestByRank("racer_ages", 4); + System.out.println(res9); // >>> [42.63] + //STEP_END + + //STEP_START tdig_min + double res10 = unifiedJedis.tdigestMin("racer_ages"); + System.out.println(res10); // >>> 19.27 + + double res11 = unifiedJedis.tdigestMax("racer_ages"); + System.out.println(res11); // >>> 85.71 + //STEP_END + + //STEP_START tdig_reset + String res12 = unifiedJedis.tdigestReset("racer_ages"); + System.out.println(res12); // >>> OK + //STEP_END + } +} diff --git a/src/test/java/io/redis/examples/TopKExample.java b/src/test/java/io/redis/examples/TopKExample.java new file mode 100644 index 00000000000..e7b243094d3 --- /dev/null +++ b/src/test/java/io/redis/examples/TopKExample.java @@ -0,0 +1,47 @@ +//EXAMPLE: topk_tutorial +//HIDE_START +package io.redis.examples; +//HIDE_END + +//REMOVE_START +import org.junit.Test; +import redis.clients.jedis.UnifiedJedis; + +import java.util.List; +//REMOVE_END + +public class TopKExample { + @Test + public void run(){ + //HIDE_START + UnifiedJedis unifiedJedis = new UnifiedJedis("redis://127.0.0.1:6379"); + //HIDE_END + + //REMOVE_START + unifiedJedis.del("bikes:keywords"); + //REMOVE_END + + //STEP_START topk + String res1 = unifiedJedis.topkReserve("bikes:keywords", 5L, 2000L, 7L, 0.925D); + System.out.println(res1); // >>> True + + List res2 = unifiedJedis.topkAdd("bikes:keywords", + "store", + "seat", + "handlebars", + "handles", + "pedals", + "tires", + "store", + "seat"); + + System.out.println(res2); // >>> [None, None, None, None, None, 'handlebars', None, None] + + List res3 = unifiedJedis.topkList("bikes:keywords"); + System.out.println(res3); // >>> ['store', 'seat', 'pedals', 'tires', 'handles'] + + List res4 = unifiedJedis.topkQuery("bikes:keywords", "store", "handlebars"); + System.out.println(res4); // >>> [1, 0] + //STEP_END + } +} From 780fbc74c6b114953ea31492c92c1955bab93ce7 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Wed, 3 Jul 2024 15:29:02 +0600 Subject: [PATCH 29/51] [TEMPORARY] [TEST] Disable FT.PROFILE tests (#3881) Disable FT.PROFILE tests --- .../jedis/modules/search/AggregationTest.java | 1 + .../jedis/modules/search/SearchTest.java | 55 ++++++++++--------- .../modules/search/SearchWithParamsTest.java | 7 +++ 3 files changed, 37 insertions(+), 26 deletions(-) diff --git a/src/test/java/redis/clients/jedis/modules/search/AggregationTest.java b/src/test/java/redis/clients/jedis/modules/search/AggregationTest.java index cefdfbe5d34..98e811472ed 100644 --- a/src/test/java/redis/clients/jedis/modules/search/AggregationTest.java +++ b/src/test/java/redis/clients/jedis/modules/search/AggregationTest.java @@ -134,6 +134,7 @@ public void testAggregations2() { assertEquals("10", rows.get(1).get("sum")); } + @org.junit.Ignore @Test public void testAggregations2Profile() { Schema sc = new Schema(); diff --git a/src/test/java/redis/clients/jedis/modules/search/SearchTest.java b/src/test/java/redis/clients/jedis/modules/search/SearchTest.java index 1bc6cb345db..27f72483dbc 100644 --- a/src/test/java/redis/clients/jedis/modules/search/SearchTest.java +++ b/src/test/java/redis/clients/jedis/modules/search/SearchTest.java @@ -1140,6 +1140,7 @@ public void testDialectsWithFTExplain() throws Exception { assertTrue("Should contain '{K=10 nearest vector'", client.ftExplain(index, query).contains("{K=10 nearest vector")); } + @org.junit.Ignore @Test public void searchProfile() { Schema sc = new Schema().addTextField("t1", 1.0).addTextField("t2", 1.0); @@ -1200,19 +1201,20 @@ public void testHNSWVVectorSimilarity() { assertEquals("a", doc1.getId()); assertEquals("0", doc1.get("__v_score")); - // profile - Map.Entry> reply - = client.ftProfileSearch(index, FTProfileParams.profileParams(), query); - doc1 = reply.getKey().getDocuments().get(0); - assertEquals("a", doc1.getId()); - assertEquals("0", doc1.get("__v_score")); - if (protocol != RedisProtocol.RESP3) { - assertEquals("VECTOR", ((Map) reply.getValue().get("Iterators profile")).get("Type")); - } else { - assertEquals(Arrays.asList("VECTOR"), - ((List>) reply.getValue().get("Iterators profile")).stream() - .map(map -> map.get("Type")).collect(Collectors.toList())); - } +// // @org.junit.Ignore +// // profile +// Map.Entry> reply +// = client.ftProfileSearch(index, FTProfileParams.profileParams(), query); +// doc1 = reply.getKey().getDocuments().get(0); +// assertEquals("a", doc1.getId()); +// assertEquals("0", doc1.get("__v_score")); +// if (protocol != RedisProtocol.RESP3) { +// assertEquals("VECTOR", ((Map) reply.getValue().get("Iterators profile")).get("Type")); +// } else { +// assertEquals(Arrays.asList("VECTOR"), +// ((List>) reply.getValue().get("Iterators profile")).stream() +// .map(map -> map.get("Type")).collect(Collectors.toList())); +// } } @Test @@ -1238,19 +1240,20 @@ public void testFlatVectorSimilarity() { assertEquals("a", doc1.getId()); assertEquals("0", doc1.get("__v_score")); - // profile - Map.Entry> reply - = client.ftProfileSearch(index, FTProfileParams.profileParams(), query); - doc1 = reply.getKey().getDocuments().get(0); - assertEquals("a", doc1.getId()); - assertEquals("0", doc1.get("__v_score")); - if (protocol != RedisProtocol.RESP3) { - assertEquals("VECTOR", ((Map) reply.getValue().get("Iterators profile")).get("Type")); - } else { - assertEquals(Arrays.asList("VECTOR"), - ((List>) reply.getValue().get("Iterators profile")).stream() - .map(map -> map.get("Type")).collect(Collectors.toList())); - } +// // @org.junit.Ignore +// // profile +// Map.Entry> reply +// = client.ftProfileSearch(index, FTProfileParams.profileParams(), query); +// doc1 = reply.getKey().getDocuments().get(0); +// assertEquals("a", doc1.getId()); +// assertEquals("0", doc1.get("__v_score")); +// if (protocol != RedisProtocol.RESP3) { +// assertEquals("VECTOR", ((Map) reply.getValue().get("Iterators profile")).get("Type")); +// } else { +// assertEquals(Arrays.asList("VECTOR"), +// ((List>) reply.getValue().get("Iterators profile")).stream() +// .map(map -> map.get("Type")).collect(Collectors.toList())); +// } } @Test diff --git a/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java b/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java index 897da8eece9..8550e5c64a1 100644 --- a/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java +++ b/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java @@ -9,6 +9,7 @@ import java.util.stream.Collectors; import org.hamcrest.Matchers; import org.junit.BeforeClass; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -1056,6 +1057,7 @@ public void testFlatVectorSimilarity() { assertEquals("0", doc1.get("__v_score")); } + @Ignore @Test public void searchProfile() { assertOK(client.ftCreate(index, TextField.of("t1"), TextField.of("t2"))); @@ -1092,6 +1094,7 @@ public void searchProfile() { .map(map -> map.get("Type")).collect(Collectors.toList())); } + @Ignore @Test public void vectorSearchProfile() { assertOK(client.ftCreate(index, VectorField.builder().fieldName("v") @@ -1131,6 +1134,7 @@ public void vectorSearchProfile() { assertEquals("Sorter", resultProcessorsProfile.get(2).get("Type")); } + @Ignore @Test public void maxPrefixExpansionSearchProfile() { final String configParam = "MAXPREFIXEXPANSIONS"; @@ -1158,6 +1162,7 @@ public void maxPrefixExpansionSearchProfile() { } } + @Ignore @Test public void noContentSearchProfile() { assertOK(client.ftCreate(index, TextField.of("t"))); @@ -1185,6 +1190,7 @@ public void noContentSearchProfile() { } } + @Ignore @Test public void deepReplySearchProfile() { assertOK(client.ftCreate(index, TextField.of("t"))); @@ -1226,6 +1232,7 @@ private void deepReplySearchProfile_assertProfile(Map attr, } } + @Ignore @Test public void limitedSearchProfile() { assertOK(client.ftCreate(index, TextField.of("t"))); From 7c0e57d222dbfefdaa4847cd2a1e19494dab4afd Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Fri, 14 Jun 2024 10:16:47 +0600 Subject: [PATCH 30/51] Support IGNORE and other optional arguments for timeseries commands (#3860) * Re-implement TS.ADD command with optional arguments * Implement TS.INCRBY and TS.DECRBY commands with optional arguments * Support IGNORE argument for TS.[ CREATE | ALTER | ADD | INCRBY | DECRBY] commands --- * Cover optional arguments for timeseries commands - Re-implement TS.ADD command with optional arguments - Implement TS.INCRBY and TS.DECRBY commands with optional arguments * Introduce EncodingFormat enum for * Support IGNORE option and rename to TSIncrOrDecrByParams --- .../redis/clients/jedis/CommandObjects.java | 20 ++- .../redis/clients/jedis/PipeliningBase.java | 15 ++ .../redis/clients/jedis/UnifiedJedis.java | 15 ++ .../jedis/timeseries/EncodingFormat.java | 24 ++++ .../timeseries/RedisTimeSeriesCommands.java | 55 +++++++- .../RedisTimeSeriesPipelineCommands.java | 7 + .../clients/jedis/timeseries/TSAddParams.java | 128 +++++++++++++++++ .../jedis/timeseries/TSAlterParams.java | 28 ++++ .../jedis/timeseries/TSCreateParams.java | 39 ++++-- .../timeseries/TSIncrOrDecrByParams.java | 132 ++++++++++++++++++ .../jedis/timeseries/TimeSeriesProtocol.java | 1 + .../PipeliningBaseTimeSeriesCommandsTest.java | 47 +++++-- .../UnifiedJedisTimeSeriesCommandsTest.java | 71 ++++++++-- .../modules/timeseries/TimeSeriesTest.java | 55 ++++++++ 14 files changed, 600 insertions(+), 37 deletions(-) create mode 100644 src/main/java/redis/clients/jedis/timeseries/EncodingFormat.java create mode 100644 src/main/java/redis/clients/jedis/timeseries/TSAddParams.java create mode 100644 src/main/java/redis/clients/jedis/timeseries/TSIncrOrDecrByParams.java diff --git a/src/main/java/redis/clients/jedis/CommandObjects.java b/src/main/java/redis/clients/jedis/CommandObjects.java index 7226a014a79..421b81c4e2d 100644 --- a/src/main/java/redis/clients/jedis/CommandObjects.java +++ b/src/main/java/redis/clients/jedis/CommandObjects.java @@ -3946,9 +3946,15 @@ public final CommandObject tsAdd(String key, long timestamp, double value) return new CommandObject<>(commandArguments(TimeSeriesCommand.ADD).key(key).add(timestamp).add(value), BuilderFactory.LONG); } + @Deprecated public final CommandObject tsAdd(String key, long timestamp, double value, TSCreateParams createParams) { - return new CommandObject<>(commandArguments(TimeSeriesCommand.ADD).key(key) - .add(timestamp).add(value).addParams(createParams), BuilderFactory.LONG); + return new CommandObject<>(commandArguments(TimeSeriesCommand.ADD).key(key).add(timestamp).add(value) + .addParams(createParams), BuilderFactory.LONG); + } + + public final CommandObject tsAdd(String key, long timestamp, double value, TSAddParams addParams) { + return new CommandObject<>(commandArguments(TimeSeriesCommand.ADD).key(key).add(timestamp).add(value) + .addParams(addParams), BuilderFactory.LONG); } public final CommandObject> tsMAdd(Map.Entry... entries) { @@ -3968,6 +3974,11 @@ public final CommandObject tsIncrBy(String key, double value, long timesta .add(TimeSeriesKeyword.TIMESTAMP).add(timestamp), BuilderFactory.LONG); } + public final CommandObject tsIncrBy(String key, double addend, TSIncrOrDecrByParams incrByParams) { + return new CommandObject<>(commandArguments(TimeSeriesCommand.INCRBY).key(key).add(addend) + .addParams(incrByParams), BuilderFactory.LONG); + } + public final CommandObject tsDecrBy(String key, double value) { return new CommandObject<>(commandArguments(TimeSeriesCommand.DECRBY).key(key).add(value), BuilderFactory.LONG); } @@ -3977,6 +3988,11 @@ public final CommandObject tsDecrBy(String key, double value, long timesta .add(TimeSeriesKeyword.TIMESTAMP).add(timestamp), BuilderFactory.LONG); } + public final CommandObject tsDecrBy(String key, double subtrahend, TSIncrOrDecrByParams decrByParams) { + return new CommandObject<>(commandArguments(TimeSeriesCommand.DECRBY).key(key).add(subtrahend) + .addParams(decrByParams), BuilderFactory.LONG); + } + public final CommandObject> tsRange(String key, long fromTimestamp, long toTimestamp) { return new CommandObject<>(commandArguments(TimeSeriesCommand.RANGE).key(key) .add(fromTimestamp).add(toTimestamp), TimeSeriesBuilderFactory.TIMESERIES_ELEMENT_LIST); diff --git a/src/main/java/redis/clients/jedis/PipeliningBase.java b/src/main/java/redis/clients/jedis/PipeliningBase.java index 928126a7047..9967a2e6940 100644 --- a/src/main/java/redis/clients/jedis/PipeliningBase.java +++ b/src/main/java/redis/clients/jedis/PipeliningBase.java @@ -3948,6 +3948,11 @@ public Response tsAdd(String key, long timestamp, double value, TSCreatePa return appendCommand(commandObjects.tsAdd(key, timestamp, value, createParams)); } + @Override + public Response tsAdd(String key, long timestamp, double value, TSAddParams addParams) { + return appendCommand(commandObjects.tsAdd(key, timestamp, value, addParams)); + } + @Override public Response> tsMAdd(Map.Entry... entries) { return appendCommand(commandObjects.tsMAdd(entries)); @@ -3963,6 +3968,11 @@ public Response tsIncrBy(String key, double value, long timestamp) { return appendCommand(commandObjects.tsIncrBy(key, value, timestamp)); } + @Override + public Response tsIncrBy(String key, double addend, TSIncrOrDecrByParams incrByParams) { + return appendCommand(commandObjects.tsIncrBy(key, addend, incrByParams)); + } + @Override public Response tsDecrBy(String key, double value) { return appendCommand(commandObjects.tsDecrBy(key, value)); @@ -3973,6 +3983,11 @@ public Response tsDecrBy(String key, double value, long timestamp) { return appendCommand(commandObjects.tsDecrBy(key, value, timestamp)); } + @Override + public Response tsDecrBy(String key, double subtrahend, TSIncrOrDecrByParams decrByParams) { + return appendCommand(commandObjects.tsDecrBy(key, subtrahend, decrByParams)); + } + @Override public Response> tsRange(String key, long fromTimestamp, long toTimestamp) { return appendCommand(commandObjects.tsRange(key, fromTimestamp, toTimestamp)); diff --git a/src/main/java/redis/clients/jedis/UnifiedJedis.java b/src/main/java/redis/clients/jedis/UnifiedJedis.java index 2d6e77fcf0a..87ba0d8a142 100644 --- a/src/main/java/redis/clients/jedis/UnifiedJedis.java +++ b/src/main/java/redis/clients/jedis/UnifiedJedis.java @@ -4473,6 +4473,11 @@ public long tsAdd(String key, long timestamp, double value, TSCreateParams creat return executeCommand(commandObjects.tsAdd(key, timestamp, value, createParams)); } + @Override + public long tsAdd(String key, long timestamp, double value, TSAddParams addParams) { + return executeCommand(commandObjects.tsAdd(key, timestamp, value, addParams)); + } + @Override public List tsMAdd(Map.Entry... entries) { return executeCommand(commandObjects.tsMAdd(entries)); @@ -4488,6 +4493,11 @@ public long tsIncrBy(String key, double value, long timestamp) { return executeCommand(commandObjects.tsIncrBy(key, value, timestamp)); } + @Override + public long tsIncrBy(String key, double addend, TSIncrOrDecrByParams incrByParams) { + return executeCommand(commandObjects.tsIncrBy(key, addend, incrByParams)); + } + @Override public long tsDecrBy(String key, double value) { return executeCommand(commandObjects.tsDecrBy(key, value)); @@ -4498,6 +4508,11 @@ public long tsDecrBy(String key, double value, long timestamp) { return executeCommand(commandObjects.tsDecrBy(key, value, timestamp)); } + @Override + public long tsDecrBy(String key, double subtrahend, TSIncrOrDecrByParams decrByParams) { + return executeCommand(commandObjects.tsDecrBy(key, subtrahend, decrByParams)); + } + @Override public List tsRange(String key, long fromTimestamp, long toTimestamp) { return executeCommand(commandObjects.tsRange(key, fromTimestamp, toTimestamp)); diff --git a/src/main/java/redis/clients/jedis/timeseries/EncodingFormat.java b/src/main/java/redis/clients/jedis/timeseries/EncodingFormat.java new file mode 100644 index 00000000000..5130d7da251 --- /dev/null +++ b/src/main/java/redis/clients/jedis/timeseries/EncodingFormat.java @@ -0,0 +1,24 @@ +package redis.clients.jedis.timeseries; + +import redis.clients.jedis.args.Rawable; +import redis.clients.jedis.util.SafeEncoder; + +/** + * Specifies the series samples encoding format. + */ +public enum EncodingFormat implements Rawable { + + COMPRESSED, + UNCOMPRESSED; + + private final byte[] raw; + + private EncodingFormat() { + raw = SafeEncoder.encode(name()); + } + + @Override + public byte[] getRaw() { + return raw; + } +} diff --git a/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesCommands.java b/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesCommands.java index c002b94c08e..67c1b26fcf8 100644 --- a/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesCommands.java +++ b/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesCommands.java @@ -59,16 +59,33 @@ public interface RedisTimeSeriesCommands { long tsAdd(String key, long timestamp, double value); /** - * {@code TS.ADD key timestamp value [RETENTION retentionTime] [ENCODING [COMPRESSED|UNCOMPRESSED]] [CHUNK_SIZE size] [ON_DUPLICATE policy] [LABELS label value..]} - * * @param key * @param timestamp * @param value * @param createParams * @return timestamp + * @deprecated Use {@link RedisTimeSeriesCommands#tsAdd(java.lang.String, long, double, redis.clients.jedis.timeseries.TSAddParams)}. */ + @Deprecated long tsAdd(String key, long timestamp, double value, TSCreateParams createParams); + /** + * {@code TS.ADD key timestamp value + * [RETENTION retentionTime] + * [ENCODING ] + * [CHUNK_SIZE size] + * [DUPLICATE_POLICY policy] + * [ON_DUPLICATE policy_ovr] + * [LABELS label value..]} + * + * @param key + * @param timestamp + * @param value + * @param addParams + * @return timestamp + */ + long tsAdd(String key, long timestamp, double value, TSAddParams addParams); + /** * {@code TS.MADD key timestamp value [key timestamp value ...]} * @@ -81,10 +98,44 @@ public interface RedisTimeSeriesCommands { long tsIncrBy(String key, double value, long timestamp); + /** + * {@code TS.INCRBY key addend + * [TIMESTAMP timestamp] + * [RETENTION retentionPeriod] + * [ENCODING ] + * [CHUNK_SIZE size] + * [DUPLICATE_POLICY policy] + * [IGNORE ignoreMaxTimediff ignoreMaxValDiff] + * [LABELS [label value ...]]} + * + * @param key + * @param addend + * @param incrByParams + * @return timestamp + */ + long tsIncrBy(String key, double addend, TSIncrOrDecrByParams incrByParams); + long tsDecrBy(String key, double value); long tsDecrBy(String key, double value, long timestamp); + /** + * {@code TS.DECRBY key subtrahend + * [TIMESTAMP timestamp] + * [RETENTION retentionPeriod] + * [ENCODING ] + * [CHUNK_SIZE size] + * [DUPLICATE_POLICY policy] + * [IGNORE ignoreMaxTimediff ignoreMaxValDiff] + * [LABELS [label value ...]]} + * + * @param key + * @param subtrahend + * @param decrByParams + * @return timestamp + */ + long tsDecrBy(String key, double subtrahend, TSIncrOrDecrByParams decrByParams); + /** * {@code TS.RANGE key fromTimestamp toTimestamp} * diff --git a/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesPipelineCommands.java b/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesPipelineCommands.java index 288b3f195e9..b3304716ddd 100644 --- a/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesPipelineCommands.java +++ b/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesPipelineCommands.java @@ -18,18 +18,25 @@ public interface RedisTimeSeriesPipelineCommands { Response tsAdd(String key, long timestamp, double value); + @Deprecated Response tsAdd(String key, long timestamp, double value, TSCreateParams createParams); + Response tsAdd(String key, long timestamp, double value, TSAddParams addParams); + Response> tsMAdd(Map.Entry... entries); Response tsIncrBy(String key, double value); Response tsIncrBy(String key, double value, long timestamp); + Response tsIncrBy(String key, double addend, TSIncrOrDecrByParams incrByParams); + Response tsDecrBy(String key, double value); Response tsDecrBy(String key, double value, long timestamp); + Response tsDecrBy(String key, double subtrahend, TSIncrOrDecrByParams decrByParams); + Response> tsRange(String key, long fromTimestamp, long toTimestamp); Response> tsRange(String key, TSRangeParams rangeParams); diff --git a/src/main/java/redis/clients/jedis/timeseries/TSAddParams.java b/src/main/java/redis/clients/jedis/timeseries/TSAddParams.java new file mode 100644 index 00000000000..0a9713cefb8 --- /dev/null +++ b/src/main/java/redis/clients/jedis/timeseries/TSAddParams.java @@ -0,0 +1,128 @@ +package redis.clients.jedis.timeseries; + +import static redis.clients.jedis.Protocol.toByteArray; +import static redis.clients.jedis.timeseries.TimeSeriesProtocol.TimeSeriesKeyword.*; + +import java.util.LinkedHashMap; +import java.util.Map; +import redis.clients.jedis.CommandArguments; +import redis.clients.jedis.params.IParams; + +/** + * Represents optional arguments of TS.ADD command. + */ +public class TSAddParams implements IParams { + + private Long retentionPeriod; + private EncodingFormat encoding; + private Long chunkSize; + private DuplicatePolicy duplicatePolicy; + private DuplicatePolicy onDuplicate; + + private boolean ignore; + private long ignoreMaxTimediff; + private double ignoreMaxValDiff; + + private Map labels; + + public TSAddParams() { + } + + public static TSAddParams addParams() { + return new TSAddParams(); + } + + public TSAddParams retention(long retentionPeriod) { + this.retentionPeriod = retentionPeriod; + return this; + } + + public TSAddParams encoding(EncodingFormat encoding) { + this.encoding = encoding; + return this; + } + + public TSAddParams chunkSize(long chunkSize) { + this.chunkSize = chunkSize; + return this; + } + + public TSAddParams duplicatePolicy(DuplicatePolicy duplicatePolicy) { + this.duplicatePolicy = duplicatePolicy; + return this; + } + + public TSAddParams onDuplicate(DuplicatePolicy onDuplicate) { + this.onDuplicate = onDuplicate; + return this; + } + + public TSAddParams ignore(long maxTimediff, double maxValDiff) { + this.ignore = true; + this.ignoreMaxTimediff = maxTimediff; + this.ignoreMaxValDiff = maxValDiff; + return this; + } + + /** + * Set label-value pairs + * + * @param labels label-value pairs + * @return the object itself + */ + public TSAddParams labels(Map labels) { + this.labels = labels; + return this; + } + + /** + * Add label-value pair. Multiple pairs can be added through chaining. + * @param label + * @param value + * @return the object itself + */ + public TSAddParams label(String label, String value) { + if (this.labels == null) { + this.labels = new LinkedHashMap<>(); + } + this.labels.put(label, value); + return this; + } + + @Override + public void addParams(CommandArguments args) { + + if (retentionPeriod != null) { + args.add(RETENTION).add(toByteArray(retentionPeriod)); + } + + if (encoding != null) { + args.add(ENCODING).add(encoding); + } + + if (chunkSize != null) { + args.add(CHUNK_SIZE).add(toByteArray(chunkSize)); + } + + if (duplicatePolicy != null) { + args.add(DUPLICATE_POLICY).add(duplicatePolicy); + } + + if (duplicatePolicy != null) { + args.add(DUPLICATE_POLICY).add(duplicatePolicy); + } + + if (onDuplicate != null) { + args.add(ON_DUPLICATE).add(onDuplicate); + } + + if (ignore) { + args.add(IGNORE).add(ignoreMaxTimediff).add(ignoreMaxValDiff); + } + + if (labels != null) { + args.add(LABELS); + labels.entrySet().forEach((entry) -> args.add(entry.getKey()).add(entry.getValue())); + } + } +} diff --git a/src/main/java/redis/clients/jedis/timeseries/TSAlterParams.java b/src/main/java/redis/clients/jedis/timeseries/TSAlterParams.java index 4576a1b6b75..50ba9723acc 100644 --- a/src/main/java/redis/clients/jedis/timeseries/TSAlterParams.java +++ b/src/main/java/redis/clients/jedis/timeseries/TSAlterParams.java @@ -17,6 +17,11 @@ public class TSAlterParams implements IParams { private Long retentionPeriod; private Long chunkSize; private DuplicatePolicy duplicatePolicy; + + private boolean ignore; + private long ignoreMaxTimediff; + private double ignoreMaxValDiff; + private Map labels; public TSAlterParams() { @@ -41,11 +46,30 @@ public TSAlterParams duplicatePolicy(DuplicatePolicy duplicatePolicy) { return this; } + public TSAlterParams ignore(long maxTimediff, double maxValDiff) { + this.ignore = true; + this.ignoreMaxTimediff = maxTimediff; + this.ignoreMaxValDiff = maxValDiff; + return this; + } + + /** + * Set label-value pairs + * + * @param labels label-value pairs + * @return the object itself + */ public TSAlterParams labels(Map labels) { this.labels = labels; return this; } + /** + * Add label-value pair. Multiple pairs can be added through chaining. + * @param label + * @param value + * @return the object itself + */ public TSAlterParams label(String label, String value) { if (this.labels == null) { this.labels = new LinkedHashMap<>(); @@ -73,6 +97,10 @@ public void addParams(CommandArguments args) { args.add(DUPLICATE_POLICY).add(duplicatePolicy); } + if (ignore) { + args.add(IGNORE).add(ignoreMaxTimediff).add(ignoreMaxValDiff); + } + if (labels != null) { args.add(LABELS); labels.entrySet().forEach((entry) -> args.add(entry.getKey()).add(entry.getValue())); diff --git a/src/main/java/redis/clients/jedis/timeseries/TSCreateParams.java b/src/main/java/redis/clients/jedis/timeseries/TSCreateParams.java index ca07de1f01f..0611383d4d2 100644 --- a/src/main/java/redis/clients/jedis/timeseries/TSCreateParams.java +++ b/src/main/java/redis/clients/jedis/timeseries/TSCreateParams.java @@ -14,10 +14,14 @@ public class TSCreateParams implements IParams { private Long retentionPeriod; - private boolean uncompressed; - private boolean compressed; + private EncodingFormat encoding; private Long chunkSize; private DuplicatePolicy duplicatePolicy; + + private boolean ignore; + private long ignoreMaxTimediff; + private double ignoreMaxValDiff; + private Map labels; public TSCreateParams() { @@ -32,13 +36,18 @@ public TSCreateParams retention(long retentionPeriod) { return this; } + // TODO: deprecate public TSCreateParams uncompressed() { - this.uncompressed = true; - return this; + return encoding(EncodingFormat.UNCOMPRESSED); } + // TODO: deprecate public TSCreateParams compressed() { - this.compressed = true; + return encoding(EncodingFormat.COMPRESSED); + } + + public TSCreateParams encoding(EncodingFormat encoding) { + this.encoding = encoding; return this; } @@ -52,6 +61,13 @@ public TSCreateParams duplicatePolicy(DuplicatePolicy duplicatePolicy) { return this; } + public TSCreateParams ignore(long maxTimediff, double maxValDiff) { + this.ignore = true; + this.ignoreMaxTimediff = maxTimediff; + this.ignoreMaxValDiff = maxValDiff; + return this; + } + /** * Set label-value pairs * @@ -65,6 +81,9 @@ public TSCreateParams labels(Map labels) { /** * Add label-value pair. Multiple pairs can be added through chaining. + * @param label + * @param value + * @return the object itself */ public TSCreateParams label(String label, String value) { if (this.labels == null) { @@ -81,10 +100,8 @@ public void addParams(CommandArguments args) { args.add(RETENTION).add(toByteArray(retentionPeriod)); } - if (uncompressed) { - args.add(ENCODING).add(UNCOMPRESSED); - } else if (compressed) { - args.add(ENCODING).add(COMPRESSED); + if (encoding != null) { + args.add(ENCODING).add(encoding); } if (chunkSize != null) { @@ -95,6 +112,10 @@ public void addParams(CommandArguments args) { args.add(DUPLICATE_POLICY).add(duplicatePolicy); } + if (ignore) { + args.add(IGNORE).add(ignoreMaxTimediff).add(ignoreMaxValDiff); + } + if (labels != null) { args.add(LABELS); labels.entrySet().forEach((entry) -> args.add(entry.getKey()).add(entry.getValue())); diff --git a/src/main/java/redis/clients/jedis/timeseries/TSIncrOrDecrByParams.java b/src/main/java/redis/clients/jedis/timeseries/TSIncrOrDecrByParams.java new file mode 100644 index 00000000000..fde848fb5a8 --- /dev/null +++ b/src/main/java/redis/clients/jedis/timeseries/TSIncrOrDecrByParams.java @@ -0,0 +1,132 @@ +package redis.clients.jedis.timeseries; + +import static redis.clients.jedis.Protocol.toByteArray; +import static redis.clients.jedis.timeseries.TimeSeriesProtocol.TimeSeriesKeyword.*; + +import java.util.LinkedHashMap; +import java.util.Map; +import redis.clients.jedis.CommandArguments; +import redis.clients.jedis.params.IParams; + +/** + * Represents optional arguments of TS.INCRBY or TS.DECRBY commands. + */ +public class TSIncrOrDecrByParams implements IParams { + + private Long timestamp; + private Long retentionPeriod; + private EncodingFormat encoding; + private Long chunkSize; + private DuplicatePolicy duplicatePolicy; + + private boolean ignore; + private long ignoreMaxTimediff; + private double ignoreMaxValDiff; + + private Map labels; + + public TSIncrOrDecrByParams() { + } + + public static TSIncrOrDecrByParams params() { + return new TSIncrOrDecrByParams(); + } + + public static TSIncrOrDecrByParams incrByParams() { + return new TSIncrOrDecrByParams(); + } + + public static TSIncrOrDecrByParams decrByParams() { + return new TSIncrOrDecrByParams(); + } + + public TSIncrOrDecrByParams timestamp(long timestamp) { + this.timestamp = timestamp; + return this; + } + + public TSIncrOrDecrByParams retention(long retentionPeriod) { + this.retentionPeriod = retentionPeriod; + return this; + } + + public TSIncrOrDecrByParams encoding(EncodingFormat encoding) { + this.encoding = encoding; + return this; + } + + public TSIncrOrDecrByParams chunkSize(long chunkSize) { + this.chunkSize = chunkSize; + return this; + } + + public TSIncrOrDecrByParams duplicatePolicy(DuplicatePolicy duplicatePolicy) { + this.duplicatePolicy = duplicatePolicy; + return this; + } + + public TSIncrOrDecrByParams ignore(long maxTimediff, double maxValDiff) { + this.ignore = true; + this.ignoreMaxTimediff = maxTimediff; + this.ignoreMaxValDiff = maxValDiff; + return this; + } + + /** + * Set label-value pairs + * + * @param labels label-value pairs + * @return the object itself + */ + public TSIncrOrDecrByParams labels(Map labels) { + this.labels = labels; + return this; + } + + /** + * Add label-value pair. Multiple pairs can be added through chaining. + * @param label + * @param value + * @return the object itself + */ + public TSIncrOrDecrByParams label(String label, String value) { + if (this.labels == null) { + this.labels = new LinkedHashMap<>(); + } + this.labels.put(label, value); + return this; + } + + @Override + public void addParams(CommandArguments args) { + + if (timestamp != null) { + args.add(TIMESTAMP).add(timestamp); + } + + if (retentionPeriod != null) { + args.add(RETENTION).add(toByteArray(retentionPeriod)); + } + + if (encoding != null) { + args.add(ENCODING).add(encoding); + } + + if (chunkSize != null) { + args.add(CHUNK_SIZE).add(toByteArray(chunkSize)); + } + + if (duplicatePolicy != null) { + args.add(DUPLICATE_POLICY).add(duplicatePolicy); + } + + if (ignore) { + args.add(IGNORE).add(ignoreMaxTimediff).add(ignoreMaxValDiff); + } + + if (labels != null) { + args.add(LABELS); + labels.entrySet().forEach((entry) -> args.add(entry.getKey()).add(entry.getValue())); + } + } +} diff --git a/src/main/java/redis/clients/jedis/timeseries/TimeSeriesProtocol.java b/src/main/java/redis/clients/jedis/timeseries/TimeSeriesProtocol.java index 2476979f0d0..384a4549218 100644 --- a/src/main/java/redis/clients/jedis/timeseries/TimeSeriesProtocol.java +++ b/src/main/java/redis/clients/jedis/timeseries/TimeSeriesProtocol.java @@ -57,6 +57,7 @@ public enum TimeSeriesKeyword implements Rawable { UNCOMPRESSED, CHUNK_SIZE, DUPLICATE_POLICY, + IGNORE, ON_DUPLICATE, ALIGN, FILTER_BY_TS, diff --git a/src/test/java/redis/clients/jedis/mocked/pipeline/PipeliningBaseTimeSeriesCommandsTest.java b/src/test/java/redis/clients/jedis/mocked/pipeline/PipeliningBaseTimeSeriesCommandsTest.java index 44e653c0116..b8cfb85dc8b 100644 --- a/src/test/java/redis/clients/jedis/mocked/pipeline/PipeliningBaseTimeSeriesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/mocked/pipeline/PipeliningBaseTimeSeriesCommandsTest.java @@ -3,6 +3,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.is; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.util.AbstractMap; @@ -11,17 +12,7 @@ import org.junit.Test; import redis.clients.jedis.Response; -import redis.clients.jedis.timeseries.AggregationType; -import redis.clients.jedis.timeseries.TSAlterParams; -import redis.clients.jedis.timeseries.TSCreateParams; -import redis.clients.jedis.timeseries.TSElement; -import redis.clients.jedis.timeseries.TSGetParams; -import redis.clients.jedis.timeseries.TSInfo; -import redis.clients.jedis.timeseries.TSMGetElement; -import redis.clients.jedis.timeseries.TSMGetParams; -import redis.clients.jedis.timeseries.TSMRangeElements; -import redis.clients.jedis.timeseries.TSMRangeParams; -import redis.clients.jedis.timeseries.TSRangeParams; +import redis.clients.jedis.timeseries.*; public class PipeliningBaseTimeSeriesCommandsTest extends PipeliningBaseMockedTestBase { @@ -57,6 +48,18 @@ public void testTsAddWithTimestampAndParams() { assertThat(response, is(predefinedResponse)); } + @Test + public void testTsAddWithParams() { + TSAddParams addParams = mock(TSAddParams.class); + + when(commandObjects.tsAdd("myTimeSeries", 1000L, 42.0, addParams)).thenReturn(longCommandObject); + + Response response = pipeliningBase.tsAdd("myTimeSeries", 1000L, 42.0, addParams); + + assertThat(commands, contains(longCommandObject)); + assertThat(response, is(predefinedResponse)); + } + @Test public void testTsAlter() { TSAlterParams alterParams = TSAlterParams.alterParams(); @@ -138,6 +141,17 @@ public void testTsDecrByWithTimestamp() { assertThat(response, is(predefinedResponse)); } + @Test + public void testTsDecrByWithParams() { + TSIncrOrDecrByParams DecrByParams = mock(TSIncrOrDecrByParams.class); + when(commandObjects.tsDecrBy("myTimeSeries", 1.0, DecrByParams)).thenReturn(longCommandObject); + + Response response = pipeliningBase.tsDecrBy("myTimeSeries", 1.0, DecrByParams); + + assertThat(commands, contains(longCommandObject)); + assertThat(response, is(predefinedResponse)); + } + @Test public void testTsDel() { when(commandObjects.tsDel("myTimeSeries", 1000L, 2000L)).thenReturn(longCommandObject); @@ -200,6 +214,17 @@ public void testTsIncrByWithTimestamp() { assertThat(response, is(predefinedResponse)); } + @Test + public void testTsIncrByWithParams() { + TSIncrOrDecrByParams incrByParams = mock(TSIncrOrDecrByParams.class); + when(commandObjects.tsIncrBy("myTimeSeries", 1.0, incrByParams)).thenReturn(longCommandObject); + + Response response = pipeliningBase.tsIncrBy("myTimeSeries", 1.0, incrByParams); + + assertThat(commands, contains(longCommandObject)); + assertThat(response, is(predefinedResponse)); + } + @Test public void testTsInfo() { when(commandObjects.tsInfo("myTimeSeries")).thenReturn(tsInfoCommandObject); diff --git a/src/test/java/redis/clients/jedis/mocked/unified/UnifiedJedisTimeSeriesCommandsTest.java b/src/test/java/redis/clients/jedis/mocked/unified/UnifiedJedisTimeSeriesCommandsTest.java index d9e06ce77cb..53c673da49d 100644 --- a/src/test/java/redis/clients/jedis/mocked/unified/UnifiedJedisTimeSeriesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/mocked/unified/UnifiedJedisTimeSeriesCommandsTest.java @@ -15,17 +15,7 @@ import java.util.Map; import org.junit.Test; -import redis.clients.jedis.timeseries.AggregationType; -import redis.clients.jedis.timeseries.TSAlterParams; -import redis.clients.jedis.timeseries.TSCreateParams; -import redis.clients.jedis.timeseries.TSElement; -import redis.clients.jedis.timeseries.TSGetParams; -import redis.clients.jedis.timeseries.TSInfo; -import redis.clients.jedis.timeseries.TSMGetElement; -import redis.clients.jedis.timeseries.TSMGetParams; -import redis.clients.jedis.timeseries.TSMRangeElements; -import redis.clients.jedis.timeseries.TSMRangeParams; -import redis.clients.jedis.timeseries.TSRangeParams; +import redis.clients.jedis.timeseries.*; public class UnifiedJedisTimeSeriesCommandsTest extends UnifiedJedisMockedTestBase { @@ -83,6 +73,25 @@ public void testTsAddWithTimestampAndParams() { verify(commandObjects).tsAdd(key, timestamp, value, createParams); } + @Test + public void testTsAddWithParams() { + String key = "testKey"; + long timestamp = 1582605077000L; + double value = 123.45; + TSAddParams createParams = mock(TSAddParams.class); + long expectedResponse = timestamp; // Timestamp of the added value + + when(commandObjects.tsAdd(key, timestamp, value, createParams)).thenReturn(longCommandObject); + when(commandExecutor.executeCommand(longCommandObject)).thenReturn(expectedResponse); + + long result = jedis.tsAdd(key, timestamp, value, createParams); + + assertEquals(expectedResponse, result); + + verify(commandExecutor).executeCommand(longCommandObject); + verify(commandObjects).tsAdd(key, timestamp, value, createParams); + } + @Test public void testTsAlter() { String key = "testKey"; @@ -194,7 +203,7 @@ public void testTsDecrByWithTimestamp() { String key = "testKey"; double value = 1.5; long timestamp = 1582605077000L; - long expectedResponse = -1L; // Assuming the decrement results in a total of -1 + long expectedResponse = 5L; when(commandObjects.tsDecrBy(key, value, timestamp)).thenReturn(longCommandObject); when(commandExecutor.executeCommand(longCommandObject)).thenReturn(expectedResponse); @@ -207,6 +216,24 @@ public void testTsDecrByWithTimestamp() { verify(commandObjects).tsDecrBy(key, value, timestamp); } + @Test + public void testTsDecrByWithParams() { + String key = "testKey"; + double value = 1.5; + TSIncrOrDecrByParams decrByParams = mock(TSIncrOrDecrByParams.class); + long expectedResponse = 5L; + + when(commandObjects.tsDecrBy(key, value, decrByParams)).thenReturn(longCommandObject); + when(commandExecutor.executeCommand(longCommandObject)).thenReturn(expectedResponse); + + long result = jedis.tsDecrBy(key, value, decrByParams); + + assertEquals(expectedResponse, result); + + verify(commandExecutor).executeCommand(longCommandObject); + verify(commandObjects).tsDecrBy(key, value, decrByParams); + } + @Test public void testTsDel() { String key = "testKey"; @@ -297,7 +324,7 @@ public void testTsIncrByWithTimestamp() { String key = "testKey"; double value = 2.5; long timestamp = 1582605077000L; - long expectedResponse = 5L; // Assuming the increment results in a total of 5 + long expectedResponse = 5L; when(commandObjects.tsIncrBy(key, value, timestamp)).thenReturn(longCommandObject); when(commandExecutor.executeCommand(longCommandObject)).thenReturn(expectedResponse); @@ -310,6 +337,24 @@ public void testTsIncrByWithTimestamp() { verify(commandObjects).tsIncrBy(key, value, timestamp); } + @Test + public void testTsIncrByWithParams() { + String key = "testKey"; + double value = 2.5; + TSIncrOrDecrByParams incrByParams = mock(TSIncrOrDecrByParams.class); + long expectedResponse = 5L; + + when(commandObjects.tsIncrBy(key, value, incrByParams)).thenReturn(longCommandObject); + when(commandExecutor.executeCommand(longCommandObject)).thenReturn(expectedResponse); + + long result = jedis.tsIncrBy(key, value, incrByParams); + + assertEquals(expectedResponse, result); + + verify(commandExecutor).executeCommand(longCommandObject); + verify(commandObjects).tsIncrBy(key, value, incrByParams); + } + @Test public void testTsInfo() { String key = "testKey"; diff --git a/src/test/java/redis/clients/jedis/modules/timeseries/TimeSeriesTest.java b/src/test/java/redis/clients/jedis/modules/timeseries/TimeSeriesTest.java index fe0f7d1604a..dd0688f080f 100644 --- a/src/test/java/redis/clients/jedis/modules/timeseries/TimeSeriesTest.java +++ b/src/test/java/redis/clients/jedis/modules/timeseries/TimeSeriesTest.java @@ -122,6 +122,23 @@ public void testAlter() { assertEquals("v33", info.getLabel("l3")); } + @Test + public void createAndAlterParams() { + Map labels = new HashMap<>(); + labels.put("l1", "v1"); + labels.put("l2", "v2"); + + assertEquals("OK", client.tsCreate("ts-params", + TSCreateParams.createParams().retention(60000).encoding(EncodingFormat.UNCOMPRESSED).chunkSize(4096) + .duplicatePolicy(DuplicatePolicy.BLOCK).ignore(50, 12.5).labels(labels))); + + labels.put("l1", "v11"); + labels.remove("l2"); + labels.put("l3", "v33"); + assertEquals("OK", client.tsAlter("ts-params", TSAlterParams.alterParams().retention(15000).chunkSize(8192) + .duplicatePolicy(DuplicatePolicy.SUM).ignore(50, 12.5).labels(labels))); + } + @Test public void testRule() { assertEquals("OK", client.tsCreate("source")); @@ -147,6 +164,21 @@ public void testRule() { } } + @Test + public void addParams() { + Map labels = new HashMap<>(); + labels.put("l1", "v1"); + labels.put("l2", "v2"); + + assertEquals(1000L, client.tsAdd("add1", 1000L, 1.1, + TSAddParams.addParams().retention(10000).encoding(EncodingFormat.UNCOMPRESSED).chunkSize(1000) + .duplicatePolicy(DuplicatePolicy.FIRST).onDuplicate(DuplicatePolicy.LAST).ignore(50, 12.5).labels(labels))); + + assertEquals(1000L, client.tsAdd("add2", 1000L, 1.1, + TSAddParams.addParams().retention(10000).encoding(EncodingFormat.COMPRESSED).chunkSize(1000) + .duplicatePolicy(DuplicatePolicy.MIN).onDuplicate(DuplicatePolicy.MAX).ignore(50, 12.5).labels(labels))); + } + @Test public void testAdd() { Map labels = new HashMap<>(); @@ -414,6 +446,29 @@ public void testIncrByDecrBy() throws InterruptedException { client.tsDecrBy("seriesIncDec", 33); } + @Test + public void incrByDecrByParams() { + Map labels = new HashMap<>(); + labels.put("l1", "v1"); + labels.put("l2", "v2"); + + assertEquals(1000L, client.tsIncrBy("incr1", 1.1, + TSIncrOrDecrByParams.incrByParams().timestamp(1000).retention(10000).encoding(EncodingFormat.UNCOMPRESSED) + .chunkSize(1000).duplicatePolicy(DuplicatePolicy.FIRST).ignore(50, 12.5).labels(labels))); + + assertEquals(1000L, client.tsIncrBy("incr2", 1.1, + TSIncrOrDecrByParams.incrByParams().timestamp(1000).retention(10000).encoding(EncodingFormat.COMPRESSED) + .chunkSize(1000).duplicatePolicy(DuplicatePolicy.MIN).ignore(50, 12.5).labels(labels))); + + assertEquals(1000L, client.tsDecrBy("decr1", 1.1, + TSIncrOrDecrByParams.decrByParams().timestamp(1000).retention(10000).encoding(EncodingFormat.COMPRESSED) + .chunkSize(1000).duplicatePolicy(DuplicatePolicy.LAST).ignore(50, 12.5).labels(labels))); + + assertEquals(1000L, client.tsDecrBy("decr2", 1.1, + TSIncrOrDecrByParams.decrByParams().timestamp(1000).retention(10000).encoding(EncodingFormat.UNCOMPRESSED) + .chunkSize(1000).duplicatePolicy(DuplicatePolicy.MAX).ignore(50, 12.5).labels(labels))); + } + @Test public void align() { client.tsAdd("align", 1, 10d); From beb39a1f3504d7e92d7143ece681d5bd7b86a99b Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Fri, 14 Jun 2024 19:59:25 +0600 Subject: [PATCH 31/51] Polish #3860: Separate params for TS.INCRBY and TS.DECRBY (#3863) --- .../redis/clients/jedis/CommandObjects.java | 4 +- .../redis/clients/jedis/PipeliningBase.java | 4 +- .../redis/clients/jedis/UnifiedJedis.java | 4 +- .../timeseries/RedisTimeSeriesCommands.java | 4 +- .../RedisTimeSeriesPipelineCommands.java | 4 +- ...DecrByParams.java => TSArithByParams.java} | 48 +++++++------------ .../jedis/timeseries/TSDecrByParams.java | 14 ++++++ .../jedis/timeseries/TSIncrByParams.java | 14 ++++++ .../PipeliningBaseTimeSeriesCommandsTest.java | 8 ++-- .../UnifiedJedisTimeSeriesCommandsTest.java | 4 +- .../modules/timeseries/TimeSeriesTest.java | 8 ++-- 11 files changed, 66 insertions(+), 50 deletions(-) rename src/main/java/redis/clients/jedis/timeseries/{TSIncrOrDecrByParams.java => TSArithByParams.java} (67%) create mode 100644 src/main/java/redis/clients/jedis/timeseries/TSDecrByParams.java create mode 100644 src/main/java/redis/clients/jedis/timeseries/TSIncrByParams.java diff --git a/src/main/java/redis/clients/jedis/CommandObjects.java b/src/main/java/redis/clients/jedis/CommandObjects.java index 421b81c4e2d..cbf0e197239 100644 --- a/src/main/java/redis/clients/jedis/CommandObjects.java +++ b/src/main/java/redis/clients/jedis/CommandObjects.java @@ -3974,7 +3974,7 @@ public final CommandObject tsIncrBy(String key, double value, long timesta .add(TimeSeriesKeyword.TIMESTAMP).add(timestamp), BuilderFactory.LONG); } - public final CommandObject tsIncrBy(String key, double addend, TSIncrOrDecrByParams incrByParams) { + public final CommandObject tsIncrBy(String key, double addend, TSIncrByParams incrByParams) { return new CommandObject<>(commandArguments(TimeSeriesCommand.INCRBY).key(key).add(addend) .addParams(incrByParams), BuilderFactory.LONG); } @@ -3988,7 +3988,7 @@ public final CommandObject tsDecrBy(String key, double value, long timesta .add(TimeSeriesKeyword.TIMESTAMP).add(timestamp), BuilderFactory.LONG); } - public final CommandObject tsDecrBy(String key, double subtrahend, TSIncrOrDecrByParams decrByParams) { + public final CommandObject tsDecrBy(String key, double subtrahend, TSDecrByParams decrByParams) { return new CommandObject<>(commandArguments(TimeSeriesCommand.DECRBY).key(key).add(subtrahend) .addParams(decrByParams), BuilderFactory.LONG); } diff --git a/src/main/java/redis/clients/jedis/PipeliningBase.java b/src/main/java/redis/clients/jedis/PipeliningBase.java index 9967a2e6940..ffe1c2a31c7 100644 --- a/src/main/java/redis/clients/jedis/PipeliningBase.java +++ b/src/main/java/redis/clients/jedis/PipeliningBase.java @@ -3969,7 +3969,7 @@ public Response tsIncrBy(String key, double value, long timestamp) { } @Override - public Response tsIncrBy(String key, double addend, TSIncrOrDecrByParams incrByParams) { + public Response tsIncrBy(String key, double addend, TSIncrByParams incrByParams) { return appendCommand(commandObjects.tsIncrBy(key, addend, incrByParams)); } @@ -3984,7 +3984,7 @@ public Response tsDecrBy(String key, double value, long timestamp) { } @Override - public Response tsDecrBy(String key, double subtrahend, TSIncrOrDecrByParams decrByParams) { + public Response tsDecrBy(String key, double subtrahend, TSDecrByParams decrByParams) { return appendCommand(commandObjects.tsDecrBy(key, subtrahend, decrByParams)); } diff --git a/src/main/java/redis/clients/jedis/UnifiedJedis.java b/src/main/java/redis/clients/jedis/UnifiedJedis.java index 87ba0d8a142..398b1302ba2 100644 --- a/src/main/java/redis/clients/jedis/UnifiedJedis.java +++ b/src/main/java/redis/clients/jedis/UnifiedJedis.java @@ -4494,7 +4494,7 @@ public long tsIncrBy(String key, double value, long timestamp) { } @Override - public long tsIncrBy(String key, double addend, TSIncrOrDecrByParams incrByParams) { + public long tsIncrBy(String key, double addend, TSIncrByParams incrByParams) { return executeCommand(commandObjects.tsIncrBy(key, addend, incrByParams)); } @@ -4509,7 +4509,7 @@ public long tsDecrBy(String key, double value, long timestamp) { } @Override - public long tsDecrBy(String key, double subtrahend, TSIncrOrDecrByParams decrByParams) { + public long tsDecrBy(String key, double subtrahend, TSDecrByParams decrByParams) { return executeCommand(commandObjects.tsDecrBy(key, subtrahend, decrByParams)); } diff --git a/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesCommands.java b/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesCommands.java index 67c1b26fcf8..513027c4cf2 100644 --- a/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesCommands.java +++ b/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesCommands.java @@ -113,7 +113,7 @@ public interface RedisTimeSeriesCommands { * @param incrByParams * @return timestamp */ - long tsIncrBy(String key, double addend, TSIncrOrDecrByParams incrByParams); + long tsIncrBy(String key, double addend, TSIncrByParams incrByParams); long tsDecrBy(String key, double value); @@ -134,7 +134,7 @@ public interface RedisTimeSeriesCommands { * @param decrByParams * @return timestamp */ - long tsDecrBy(String key, double subtrahend, TSIncrOrDecrByParams decrByParams); + long tsDecrBy(String key, double subtrahend, TSDecrByParams decrByParams); /** * {@code TS.RANGE key fromTimestamp toTimestamp} diff --git a/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesPipelineCommands.java b/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesPipelineCommands.java index b3304716ddd..71b6e4c8816 100644 --- a/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesPipelineCommands.java +++ b/src/main/java/redis/clients/jedis/timeseries/RedisTimeSeriesPipelineCommands.java @@ -29,13 +29,13 @@ public interface RedisTimeSeriesPipelineCommands { Response tsIncrBy(String key, double value, long timestamp); - Response tsIncrBy(String key, double addend, TSIncrOrDecrByParams incrByParams); + Response tsIncrBy(String key, double addend, TSIncrByParams incrByParams); Response tsDecrBy(String key, double value); Response tsDecrBy(String key, double value, long timestamp); - Response tsDecrBy(String key, double subtrahend, TSIncrOrDecrByParams decrByParams); + Response tsDecrBy(String key, double subtrahend, TSDecrByParams decrByParams); Response> tsRange(String key, long fromTimestamp, long toTimestamp); diff --git a/src/main/java/redis/clients/jedis/timeseries/TSIncrOrDecrByParams.java b/src/main/java/redis/clients/jedis/timeseries/TSArithByParams.java similarity index 67% rename from src/main/java/redis/clients/jedis/timeseries/TSIncrOrDecrByParams.java rename to src/main/java/redis/clients/jedis/timeseries/TSArithByParams.java index fde848fb5a8..1bc3df1c55b 100644 --- a/src/main/java/redis/clients/jedis/timeseries/TSIncrOrDecrByParams.java +++ b/src/main/java/redis/clients/jedis/timeseries/TSArithByParams.java @@ -11,7 +11,7 @@ /** * Represents optional arguments of TS.INCRBY or TS.DECRBY commands. */ -public class TSIncrOrDecrByParams implements IParams { +class TSArithByParams> implements IParams { private Long timestamp; private Long retentionPeriod; @@ -25,51 +25,39 @@ public class TSIncrOrDecrByParams implements IParams { private Map labels; - public TSIncrOrDecrByParams() { + TSArithByParams() { } - public static TSIncrOrDecrByParams params() { - return new TSIncrOrDecrByParams(); - } - - public static TSIncrOrDecrByParams incrByParams() { - return new TSIncrOrDecrByParams(); - } - - public static TSIncrOrDecrByParams decrByParams() { - return new TSIncrOrDecrByParams(); - } - - public TSIncrOrDecrByParams timestamp(long timestamp) { + public T timestamp(long timestamp) { this.timestamp = timestamp; - return this; + return (T) this; } - public TSIncrOrDecrByParams retention(long retentionPeriod) { + public T retention(long retentionPeriod) { this.retentionPeriod = retentionPeriod; - return this; + return (T) this; } - public TSIncrOrDecrByParams encoding(EncodingFormat encoding) { + public T encoding(EncodingFormat encoding) { this.encoding = encoding; - return this; + return (T) this; } - public TSIncrOrDecrByParams chunkSize(long chunkSize) { + public T chunkSize(long chunkSize) { this.chunkSize = chunkSize; - return this; + return (T) this; } - public TSIncrOrDecrByParams duplicatePolicy(DuplicatePolicy duplicatePolicy) { + public T duplicatePolicy(DuplicatePolicy duplicatePolicy) { this.duplicatePolicy = duplicatePolicy; - return this; + return (T) this; } - public TSIncrOrDecrByParams ignore(long maxTimediff, double maxValDiff) { + public T ignore(long maxTimediff, double maxValDiff) { this.ignore = true; this.ignoreMaxTimediff = maxTimediff; this.ignoreMaxValDiff = maxValDiff; - return this; + return (T) this; } /** @@ -78,9 +66,9 @@ public TSIncrOrDecrByParams ignore(long maxTimediff, double maxValDiff) { * @param labels label-value pairs * @return the object itself */ - public TSIncrOrDecrByParams labels(Map labels) { + public T labels(Map labels) { this.labels = labels; - return this; + return (T) this; } /** @@ -89,12 +77,12 @@ public TSIncrOrDecrByParams labels(Map labels) { * @param value * @return the object itself */ - public TSIncrOrDecrByParams label(String label, String value) { + public T label(String label, String value) { if (this.labels == null) { this.labels = new LinkedHashMap<>(); } this.labels.put(label, value); - return this; + return (T) this; } @Override diff --git a/src/main/java/redis/clients/jedis/timeseries/TSDecrByParams.java b/src/main/java/redis/clients/jedis/timeseries/TSDecrByParams.java new file mode 100644 index 00000000000..afb776ad6bc --- /dev/null +++ b/src/main/java/redis/clients/jedis/timeseries/TSDecrByParams.java @@ -0,0 +1,14 @@ +package redis.clients.jedis.timeseries; + +/** + * Represents optional arguments of TS.DECRBY command. + */ +public class TSDecrByParams extends TSArithByParams { + + public TSDecrByParams() { + } + + public static TSDecrByParams decrByParams() { + return new TSDecrByParams(); + } +} diff --git a/src/main/java/redis/clients/jedis/timeseries/TSIncrByParams.java b/src/main/java/redis/clients/jedis/timeseries/TSIncrByParams.java new file mode 100644 index 00000000000..db76a7ae265 --- /dev/null +++ b/src/main/java/redis/clients/jedis/timeseries/TSIncrByParams.java @@ -0,0 +1,14 @@ +package redis.clients.jedis.timeseries; + +/** + * Represents optional arguments of TS.INCRBY command. + */ +public class TSIncrByParams extends TSArithByParams { + + public TSIncrByParams() { + } + + public static TSIncrByParams incrByParams() { + return new TSIncrByParams(); + } +} diff --git a/src/test/java/redis/clients/jedis/mocked/pipeline/PipeliningBaseTimeSeriesCommandsTest.java b/src/test/java/redis/clients/jedis/mocked/pipeline/PipeliningBaseTimeSeriesCommandsTest.java index b8cfb85dc8b..671fc83ef9f 100644 --- a/src/test/java/redis/clients/jedis/mocked/pipeline/PipeliningBaseTimeSeriesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/mocked/pipeline/PipeliningBaseTimeSeriesCommandsTest.java @@ -143,10 +143,10 @@ public void testTsDecrByWithTimestamp() { @Test public void testTsDecrByWithParams() { - TSIncrOrDecrByParams DecrByParams = mock(TSIncrOrDecrByParams.class); - when(commandObjects.tsDecrBy("myTimeSeries", 1.0, DecrByParams)).thenReturn(longCommandObject); + TSDecrByParams decrByParams = mock(TSDecrByParams.class); + when(commandObjects.tsDecrBy("myTimeSeries", 1.0, decrByParams)).thenReturn(longCommandObject); - Response response = pipeliningBase.tsDecrBy("myTimeSeries", 1.0, DecrByParams); + Response response = pipeliningBase.tsDecrBy("myTimeSeries", 1.0, decrByParams); assertThat(commands, contains(longCommandObject)); assertThat(response, is(predefinedResponse)); @@ -216,7 +216,7 @@ public void testTsIncrByWithTimestamp() { @Test public void testTsIncrByWithParams() { - TSIncrOrDecrByParams incrByParams = mock(TSIncrOrDecrByParams.class); + TSIncrByParams incrByParams = mock(TSIncrByParams.class); when(commandObjects.tsIncrBy("myTimeSeries", 1.0, incrByParams)).thenReturn(longCommandObject); Response response = pipeliningBase.tsIncrBy("myTimeSeries", 1.0, incrByParams); diff --git a/src/test/java/redis/clients/jedis/mocked/unified/UnifiedJedisTimeSeriesCommandsTest.java b/src/test/java/redis/clients/jedis/mocked/unified/UnifiedJedisTimeSeriesCommandsTest.java index 53c673da49d..bfc17620ea1 100644 --- a/src/test/java/redis/clients/jedis/mocked/unified/UnifiedJedisTimeSeriesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/mocked/unified/UnifiedJedisTimeSeriesCommandsTest.java @@ -220,7 +220,7 @@ public void testTsDecrByWithTimestamp() { public void testTsDecrByWithParams() { String key = "testKey"; double value = 1.5; - TSIncrOrDecrByParams decrByParams = mock(TSIncrOrDecrByParams.class); + TSDecrByParams decrByParams = mock(TSDecrByParams.class); long expectedResponse = 5L; when(commandObjects.tsDecrBy(key, value, decrByParams)).thenReturn(longCommandObject); @@ -341,7 +341,7 @@ public void testTsIncrByWithTimestamp() { public void testTsIncrByWithParams() { String key = "testKey"; double value = 2.5; - TSIncrOrDecrByParams incrByParams = mock(TSIncrOrDecrByParams.class); + TSIncrByParams incrByParams = mock(TSIncrByParams.class); long expectedResponse = 5L; when(commandObjects.tsIncrBy(key, value, incrByParams)).thenReturn(longCommandObject); diff --git a/src/test/java/redis/clients/jedis/modules/timeseries/TimeSeriesTest.java b/src/test/java/redis/clients/jedis/modules/timeseries/TimeSeriesTest.java index dd0688f080f..723e914d473 100644 --- a/src/test/java/redis/clients/jedis/modules/timeseries/TimeSeriesTest.java +++ b/src/test/java/redis/clients/jedis/modules/timeseries/TimeSeriesTest.java @@ -453,19 +453,19 @@ public void incrByDecrByParams() { labels.put("l2", "v2"); assertEquals(1000L, client.tsIncrBy("incr1", 1.1, - TSIncrOrDecrByParams.incrByParams().timestamp(1000).retention(10000).encoding(EncodingFormat.UNCOMPRESSED) + TSIncrByParams.incrByParams().timestamp(1000).retention(10000).encoding(EncodingFormat.UNCOMPRESSED) .chunkSize(1000).duplicatePolicy(DuplicatePolicy.FIRST).ignore(50, 12.5).labels(labels))); assertEquals(1000L, client.tsIncrBy("incr2", 1.1, - TSIncrOrDecrByParams.incrByParams().timestamp(1000).retention(10000).encoding(EncodingFormat.COMPRESSED) + TSIncrByParams.incrByParams().timestamp(1000).retention(10000).encoding(EncodingFormat.COMPRESSED) .chunkSize(1000).duplicatePolicy(DuplicatePolicy.MIN).ignore(50, 12.5).labels(labels))); assertEquals(1000L, client.tsDecrBy("decr1", 1.1, - TSIncrOrDecrByParams.decrByParams().timestamp(1000).retention(10000).encoding(EncodingFormat.COMPRESSED) + TSDecrByParams.decrByParams().timestamp(1000).retention(10000).encoding(EncodingFormat.COMPRESSED) .chunkSize(1000).duplicatePolicy(DuplicatePolicy.LAST).ignore(50, 12.5).labels(labels))); assertEquals(1000L, client.tsDecrBy("decr2", 1.1, - TSIncrOrDecrByParams.decrByParams().timestamp(1000).retention(10000).encoding(EncodingFormat.UNCOMPRESSED) + TSDecrByParams.decrByParams().timestamp(1000).retention(10000).encoding(EncodingFormat.UNCOMPRESSED) .chunkSize(1000).duplicatePolicy(DuplicatePolicy.MAX).ignore(50, 12.5).labels(labels))); } From ec0e4d05da3e9b01dc6ede84be5ff13d200a5a24 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Sat, 15 Jun 2024 20:54:54 +0600 Subject: [PATCH 32/51] Support indexing of MISSING and EMPTY values (#3866) --- .../clients/jedis/search/FTSearchParams.java | 2 +- .../redis/clients/jedis/search/Query.java | 2 +- .../redis/clients/jedis/search/Schema.java | 2 +- .../clients/jedis/search/SearchProtocol.java | 2 +- .../jedis/search/aggr/AggregationBuilder.java | 4 +- .../jedis/search/querybuilder/QueryNode.java | 6 +- .../jedis/search/schemafields/GeoField.java | 33 ++++- .../search/schemafields/GeoShapeField.java | 23 +++- .../search/schemafields/NumericField.java | 14 +- .../jedis/search/schemafields/TagField.java | 78 +++++++---- .../jedis/search/schemafields/TextField.java | 85 +++++++----- .../search/schemafields/VectorField.java | 15 ++- .../modules/search/SearchWithParamsTest.java | 126 ++++++++++++++++-- 13 files changed, 307 insertions(+), 85 deletions(-) diff --git a/src/main/java/redis/clients/jedis/search/FTSearchParams.java b/src/main/java/redis/clients/jedis/search/FTSearchParams.java index d2ca5d6d946..2d4c6e00576 100644 --- a/src/main/java/redis/clients/jedis/search/FTSearchParams.java +++ b/src/main/java/redis/clients/jedis/search/FTSearchParams.java @@ -143,7 +143,7 @@ public void addParams(CommandArguments args) { } if (params != null && !params.isEmpty()) { - args.add(PARAMS).add(params.size() * 2); + args.add(PARAMS).add(params.size() << 1); params.entrySet().forEach(entry -> args.add(entry.getKey()).add(entry.getValue())); } diff --git a/src/main/java/redis/clients/jedis/search/Query.java b/src/main/java/redis/clients/jedis/search/Query.java index 66cba96acf5..66de3ce074c 100644 --- a/src/main/java/redis/clients/jedis/search/Query.java +++ b/src/main/java/redis/clients/jedis/search/Query.java @@ -292,7 +292,7 @@ public void addParams(CommandArguments args) { if (_params != null && _params.size() > 0) { args.add(SearchKeyword.PARAMS.getRaw()); - args.add(_params.size() * 2); + args.add(_params.size() << 1); for (Map.Entry entry : _params.entrySet()) { args.add(entry.getKey()); args.add(entry.getValue()); diff --git a/src/main/java/redis/clients/jedis/search/Schema.java b/src/main/java/redis/clients/jedis/search/Schema.java index 17f01cc9de2..1403aab5566 100644 --- a/src/main/java/redis/clients/jedis/search/Schema.java +++ b/src/main/java/redis/clients/jedis/search/Schema.java @@ -365,7 +365,7 @@ public VectorField(String name, VectorAlgo algorithm, Map attrib @Override public void addTypeArgs(CommandArguments args) { args.add(algorithm); - args.add(attributes.size() * 2); + args.add(attributes.size() << 1); for (Map.Entry entry : attributes.entrySet()) { args.add(entry.getKey()); args.add(entry.getValue()); diff --git a/src/main/java/redis/clients/jedis/search/SearchProtocol.java b/src/main/java/redis/clients/jedis/search/SearchProtocol.java index 7f2ad482fb7..64482f4fbb2 100644 --- a/src/main/java/redis/clients/jedis/search/SearchProtocol.java +++ b/src/main/java/redis/clients/jedis/search/SearchProtocol.java @@ -56,7 +56,7 @@ public enum SearchKeyword implements Rawable { LANGUAGE_FIELD, SCORE, SCORE_FIELD, SCORER, PARAMS, AS, DIALECT, SLOP, TIMEOUT, INORDER, EXPANDER, MAXTEXTFIELDS, SKIPINITIALSCAN, WITHSUFFIXTRIE, NOSTEM, NOINDEX, PHONETIC, WEIGHT, CASESENSITIVE, LOAD, APPLY, GROUPBY, MAXIDLE, WITHCURSOR, DISTANCE, TERMS, INCLUDE, EXCLUDE, - SEARCH, AGGREGATE, QUERY, LIMITED, COUNT, REDUCE; + SEARCH, AGGREGATE, QUERY, LIMITED, COUNT, REDUCE, INDEXMISSING, INDEXEMPTY; private final byte[] raw; diff --git a/src/main/java/redis/clients/jedis/search/aggr/AggregationBuilder.java b/src/main/java/redis/clients/jedis/search/aggr/AggregationBuilder.java index eb8e039d023..7c8b5473392 100644 --- a/src/main/java/redis/clients/jedis/search/aggr/AggregationBuilder.java +++ b/src/main/java/redis/clients/jedis/search/aggr/AggregationBuilder.java @@ -66,7 +66,7 @@ public AggregationBuilder limit(int count) { public AggregationBuilder sortBy(SortedField... fields) { aggrArgs.add(SearchKeyword.SORTBY); - aggrArgs.add(Integer.toString(fields.length * 2)); + aggrArgs.add(fields.length << 1); for (SortedField field : fields) { aggrArgs.add(field.getField()); aggrArgs.add(field.getOrder()); @@ -172,7 +172,7 @@ public AggregationBuilder timeout(long timeout) { public AggregationBuilder params(Map params) { aggrArgs.add(SearchKeyword.PARAMS); - aggrArgs.add(params.size() * 2); + aggrArgs.add(params.size() << 1); params.forEach((k, v) -> { aggrArgs.add(k); aggrArgs.add(v); diff --git a/src/main/java/redis/clients/jedis/search/querybuilder/QueryNode.java b/src/main/java/redis/clients/jedis/search/querybuilder/QueryNode.java index bc64374a5af..f5759b553de 100644 --- a/src/main/java/redis/clients/jedis/search/querybuilder/QueryNode.java +++ b/src/main/java/redis/clients/jedis/search/querybuilder/QueryNode.java @@ -61,11 +61,11 @@ public QueryNode add(Node... nodes) { protected boolean shouldParenthesize(Parenthesize mode) { if (mode == Parenthesize.ALWAYS) { return true; - } - if (mode == Parenthesize.NEVER) { + } else if (mode == Parenthesize.NEVER) { return false; + } else { + return children.size() > 1; } - return children.size() > 1; } @Override diff --git a/src/main/java/redis/clients/jedis/search/schemafields/GeoField.java b/src/main/java/redis/clients/jedis/search/schemafields/GeoField.java index 7ea421ab4f9..c5878f21b83 100644 --- a/src/main/java/redis/clients/jedis/search/schemafields/GeoField.java +++ b/src/main/java/redis/clients/jedis/search/schemafields/GeoField.java @@ -1,12 +1,16 @@ package redis.clients.jedis.search.schemafields; -import static redis.clients.jedis.search.SearchProtocol.SearchKeyword.GEO; +import static redis.clients.jedis.search.SearchProtocol.SearchKeyword.*; import redis.clients.jedis.CommandArguments; import redis.clients.jedis.search.FieldName; public class GeoField extends SchemaField { + private boolean indexMissing; + private boolean sortable; + private boolean noIndex; + public GeoField(String fieldName) { super(fieldName); } @@ -29,9 +33,36 @@ public GeoField as(String attribute) { return this; } + public GeoField indexMissing() { + this.indexMissing = true; + return this; + } + + public GeoField sortable() { + this.sortable = true; + return this; + } + + public GeoField noIndex() { + this.noIndex = true; + return this; + } + @Override public void addParams(CommandArguments args) { args.addParams(fieldName); args.add(GEO); + + if (indexMissing) { + args.add(INDEXMISSING); + } + + if (sortable) { + args.add(SORTABLE); + } + + if (noIndex) { + args.add(NOINDEX); + } } } diff --git a/src/main/java/redis/clients/jedis/search/schemafields/GeoShapeField.java b/src/main/java/redis/clients/jedis/search/schemafields/GeoShapeField.java index dd3b45e59ee..fedfed1297c 100644 --- a/src/main/java/redis/clients/jedis/search/schemafields/GeoShapeField.java +++ b/src/main/java/redis/clients/jedis/search/schemafields/GeoShapeField.java @@ -1,6 +1,6 @@ package redis.clients.jedis.search.schemafields; -import static redis.clients.jedis.search.SearchProtocol.SearchKeyword.GEOSHAPE; +import static redis.clients.jedis.search.SearchProtocol.SearchKeyword.*; import redis.clients.jedis.CommandArguments; import redis.clients.jedis.search.FieldName; @@ -22,6 +22,9 @@ public enum CoordinateSystem { private final CoordinateSystem system; + private boolean indexMissing; + private boolean noIndex; + public GeoShapeField(String fieldName, CoordinateSystem system) { super(fieldName); this.system = system; @@ -42,8 +45,26 @@ public GeoShapeField as(String attribute) { return this; } + public GeoShapeField indexMissing() { + this.indexMissing = true; + return this; + } + + public GeoShapeField noIndex() { + this.noIndex = true; + return this; + } + @Override public void addParams(CommandArguments args) { args.addParams(fieldName).add(GEOSHAPE).add(system); + + if (indexMissing) { + args.add(INDEXMISSING); + } + + if (noIndex) { + args.add(NOINDEX); + } } } diff --git a/src/main/java/redis/clients/jedis/search/schemafields/NumericField.java b/src/main/java/redis/clients/jedis/search/schemafields/NumericField.java index e1e39ef724f..244cc42640b 100644 --- a/src/main/java/redis/clients/jedis/search/schemafields/NumericField.java +++ b/src/main/java/redis/clients/jedis/search/schemafields/NumericField.java @@ -1,14 +1,13 @@ package redis.clients.jedis.search.schemafields; -import static redis.clients.jedis.search.SearchProtocol.SearchKeyword.NOINDEX; -import static redis.clients.jedis.search.SearchProtocol.SearchKeyword.NUMERIC; -import static redis.clients.jedis.search.SearchProtocol.SearchKeyword.SORTABLE; +import static redis.clients.jedis.search.SearchProtocol.SearchKeyword.*; import redis.clients.jedis.CommandArguments; import redis.clients.jedis.search.FieldName; public class NumericField extends SchemaField { + private boolean indexMissing; private boolean sortable; private boolean noIndex; @@ -34,6 +33,11 @@ public NumericField as(String attribute) { return this; } + public NumericField indexMissing() { + this.indexMissing = true; + return this; + } + /** * Sorts the results by the value of this field. */ @@ -55,6 +59,10 @@ public void addParams(CommandArguments args) { args.addParams(fieldName); args.add(NUMERIC); + if (indexMissing) { + args.add(INDEXMISSING); + } + if (sortable) { args.add(SORTABLE); } diff --git a/src/main/java/redis/clients/jedis/search/schemafields/TagField.java b/src/main/java/redis/clients/jedis/search/schemafields/TagField.java index 407c4dbddc4..451b12aad5a 100644 --- a/src/main/java/redis/clients/jedis/search/schemafields/TagField.java +++ b/src/main/java/redis/clients/jedis/search/schemafields/TagField.java @@ -8,12 +8,14 @@ public class TagField extends SchemaField { - private boolean sortable; - private boolean sortableUNF; - private boolean noIndex; + private boolean indexMissing; + private boolean indexEmpty; private byte[] separator; private boolean caseSensitive; private boolean withSuffixTrie; + private boolean sortable; + private boolean sortableUNF; + private boolean noIndex; public TagField(String fieldName) { super(fieldName); @@ -37,39 +39,19 @@ public TagField as(String attribute) { return this; } - /** - * Sorts the results by the value of this field. - */ - public TagField sortable() { - this.sortable = true; - return this; - } - - /** - * Sorts the results by the value of this field without normalization. - */ - public TagField sortableUNF() { - this.sortableUNF = true; + public TagField indexMissing() { + this.indexMissing = true; return this; } - /** - * @see TextField#sortableUNF() - */ - public TagField sortableUnNormalizedForm() { - return sortableUNF(); - } - - /** - * Avoid indexing. - */ - public TagField noIndex() { - this.noIndex = true; + public TagField indexEmpty() { + this.indexEmpty = true; return this; } /** * Indicates how the text contained in the attribute is to be split into individual tags. + * @param separator */ public TagField separator(char separator) { if (separator < 128) { @@ -97,11 +79,51 @@ public TagField withSuffixTrie() { return this; } + /** + * Sorts the results by the value of this field. + */ + public TagField sortable() { + this.sortable = true; + return this; + } + + /** + * Sorts the results by the value of this field without normalization. + */ + public TagField sortableUNF() { + this.sortableUNF = true; + return this; + } + + /** + * @deprecated Use {@code TagField#sortableUNF()}. + * @see TagField#sortableUNF() + */ + @Deprecated + public TagField sortableUnNormalizedForm() { + return sortableUNF(); + } + + /** + * Avoid indexing. + */ + public TagField noIndex() { + this.noIndex = true; + return this; + } + @Override public void addParams(CommandArguments args) { args.addParams(fieldName); args.add(TAG); + if (indexMissing) { + args.add(INDEXMISSING); + } + if (indexEmpty) { + args.add(INDEXEMPTY); + } + if (separator != null) { args.add(SEPARATOR).add(separator); } diff --git a/src/main/java/redis/clients/jedis/search/schemafields/TextField.java b/src/main/java/redis/clients/jedis/search/schemafields/TextField.java index 573cae90a3c..293104a1895 100644 --- a/src/main/java/redis/clients/jedis/search/schemafields/TextField.java +++ b/src/main/java/redis/clients/jedis/search/schemafields/TextField.java @@ -7,13 +7,15 @@ public class TextField extends SchemaField { - private boolean sortable; - private boolean sortableUNF; + private boolean indexMissing; + private boolean indexEmpty; + private Double weight; private boolean noStem; - private boolean noIndex; private String phoneticMatcher; - private Double weight; private boolean withSuffixTrie; + private boolean sortable; + private boolean sortableUNF; + private boolean noIndex; public TextField(String fieldName) { super(fieldName); @@ -37,27 +39,24 @@ public TextField as(String attribute) { return this; } - /** - * Sorts the results by the value of this field. - */ - public TextField sortable() { - this.sortable = true; + public TextField indexMissing() { + this.indexMissing = true; return this; } - /** - * Sorts the results by the value of this field without normalization. - */ - public TextField sortableUNF() { - this.sortableUNF = true; + public TextField indexEmpty() { + this.indexEmpty = true; return this; } /** - * @see TextField#sortableUNF() + * Declares the importance of this attribute when calculating result accuracy. This is a + * multiplication factor. + * @param weight */ - public TextField sortableUnNormalizedForm() { - return sortableUNF(); + public TextField weight(double weight) { + this.weight = weight; + return this; } /** @@ -69,36 +68,53 @@ public TextField noStem() { } /** - * Avoid indexing. + * Perform phonetic matching. + * @param matcher */ - public TextField noIndex() { - this.noIndex = true; + public TextField phonetic(String matcher) { + this.phoneticMatcher = matcher; return this; } /** - * Perform phonetic matching. + * Keeps a suffix trie with all terms which match the suffix. It is used to optimize + * contains and suffix queries. */ - public TextField phonetic(String matcher) { - this.phoneticMatcher = matcher; + public TextField withSuffixTrie() { + this.withSuffixTrie = true; return this; } /** - * Declares the importance of this attribute when calculating result accuracy. This is a - * multiplication factor. + * Sorts the results by the value of this field. */ - public TextField weight(double weight) { - this.weight = weight; + public TextField sortable() { + this.sortable = true; return this; } /** - * Keeps a suffix trie with all terms which match the suffix. It is used to optimize - * contains and suffix queries. + * Sorts the results by the value of this field without normalization. */ - public TextField withSuffixTrie() { - this.withSuffixTrie = true; + public TextField sortableUNF() { + this.sortableUNF = true; + return this; + } + + /** + * @deprecated Use {@code TextField#sortableUNF()}. + * @see TextField#sortableUNF() + */ + @Deprecated + public TextField sortableUnNormalizedForm() { + return sortableUNF(); + } + + /** + * Avoid indexing. + */ + public TextField noIndex() { + this.noIndex = true; return this; } @@ -107,6 +123,13 @@ public void addParams(CommandArguments args) { args.addParams(fieldName); args.add(TEXT); + if (indexMissing) { + args.add(INDEXMISSING); + } + if (indexEmpty) { + args.add(INDEXEMPTY); + } + if (weight != null) { args.add(WEIGHT).add(weight); } diff --git a/src/main/java/redis/clients/jedis/search/schemafields/VectorField.java b/src/main/java/redis/clients/jedis/search/schemafields/VectorField.java index 02287a5be35..f550f66e77c 100644 --- a/src/main/java/redis/clients/jedis/search/schemafields/VectorField.java +++ b/src/main/java/redis/clients/jedis/search/schemafields/VectorField.java @@ -1,5 +1,6 @@ package redis.clients.jedis.search.schemafields; +import static redis.clients.jedis.search.SearchProtocol.SearchKeyword.INDEXMISSING; import static redis.clients.jedis.search.SearchProtocol.SearchKeyword.VECTOR; import java.util.LinkedHashMap; @@ -17,6 +18,9 @@ public enum VectorAlgorithm { private final VectorAlgorithm algorithm; private final Map attributes; + private boolean indexMissing; + // private boolean noIndex; // throws Field `NOINDEX` does not have a type + public VectorField(String fieldName, VectorAlgorithm algorithm, Map attributes) { super(fieldName); this.algorithm = algorithm; @@ -35,14 +39,23 @@ public VectorField as(String attribute) { return this; } + public VectorField indexMissing() { + this.indexMissing = true; + return this; + } + @Override public void addParams(CommandArguments args) { args.addParams(fieldName); args.add(VECTOR); args.add(algorithm); - args.add(attributes.size() * 2); + args.add(attributes.size() << 1); attributes.forEach((name, value) -> args.add(name).add(value)); + + if (indexMissing) { + args.add(INDEXMISSING); + } } public static Builder builder() { diff --git a/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java b/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java index 8550e5c64a1..f8e282af42d 100644 --- a/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java +++ b/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java @@ -29,6 +29,7 @@ import redis.clients.jedis.json.Path; import redis.clients.jedis.search.*; import redis.clients.jedis.search.schemafields.*; +import redis.clients.jedis.search.schemafields.GeoShapeField.CoordinateSystem; import redis.clients.jedis.search.schemafields.VectorField.VectorAlgorithm; import redis.clients.jedis.modules.RedisModuleCommandsTestBase; @@ -195,19 +196,19 @@ public void search() { addDocument(String.format("doc%d", i), fields); } - SearchResult res = client.ftSearch(index, "hello world", + SearchResult result = client.ftSearch(index, "hello world", FTSearchParams.searchParams().limit(0, 5).withScores()); - assertEquals(100, res.getTotalResults()); - assertEquals(5, res.getDocuments().size()); - for (Document d : res.getDocuments()) { + assertEquals(100, result.getTotalResults()); + assertEquals(5, result.getDocuments().size()); + for (Document d : result.getDocuments()) { assertTrue(d.getId().startsWith("doc")); assertTrue(d.getScore() < 100); } client.del("doc0"); - res = client.ftSearch(index, "hello world"); - assertEquals(99, res.getTotalResults()); + result = client.ftSearch(index, "hello world"); + assertEquals(99, result.getTotalResults()); assertEquals("OK", client.ftDropIndex(index)); try { @@ -217,6 +218,57 @@ public void search() { } } + @Test + public void textFieldParams() { + assertOK(client.ftCreate("testindex", TextField.of("title").indexMissing().indexEmpty() + .weight(2.5).noStem().phonetic("dm:en").withSuffixTrie().sortable())); + + assertOK(client.ftCreate("testunfindex", TextField.of("title").indexMissing().indexEmpty() + .weight(2.5).noStem().phonetic("dm:en").withSuffixTrie().sortableUNF())); + + assertOK(client.ftCreate("testnoindex", TextField.of("title").sortable().noIndex())); + + assertOK(client.ftCreate("testunfnoindex", TextField.of("title").sortableUNF().noIndex())); + } + + @Test + public void searchTextFieldsCondition() { + assertOK(client.ftCreate(index, FTCreateParams.createParams(), TextField.of("title"), + TextField.of("body").indexMissing().indexEmpty())); + + Map regular = new HashMap<>(); + regular.put("title", "hello world"); + regular.put("body", "lorem ipsum"); + client.hset("regular-doc", regular); + + Map empty = new HashMap<>(); + empty.put("title", "hello world"); + empty.put("body", ""); + client.hset("empty-doc", empty); + + Map missing = new HashMap<>(); + missing.put("title", "hello world"); + client.hset("missing-doc", missing); + + SearchResult result = client.ftSearch(index, "", FTSearchParams.searchParams().dialect(2)); + assertEquals(0, result.getTotalResults()); + assertEquals(0, result.getDocuments().size()); + + result = client.ftSearch(index, "*", FTSearchParams.searchParams().dialect(2)); + assertEquals(3, result.getTotalResults()); + assertEquals(3, result.getDocuments().size()); + + result = client.ftSearch(index, "@body:''", FTSearchParams.searchParams().dialect(2)); + assertEquals(1, result.getTotalResults()); + assertEquals(1, result.getDocuments().size()); + assertEquals("empty-doc", result.getDocuments().get(0).getId()); + + result = client.ftSearch(index, "ismissing(@body)", FTSearchParams.searchParams().dialect(2)); + assertEquals(1, result.getTotalResults()); + assertEquals(1, result.getDocuments().size()); + assertEquals("missing-doc", result.getDocuments().get(0).getId()); + } + @Test public void numericFilter() { assertOK(client.ftCreate(index, TextField.of("title"), NumericField.of("price"))); @@ -269,7 +321,15 @@ public void numericFilter() { .filter("price", Double.NEGATIVE_INFINITY, 10)); assertEquals(11, res.getTotalResults()); assertEquals(10, res.getDocuments().size()); + } + + @Test + public void numericFieldParams() { + assertOK(client.ftCreate("testindex", TextField.of("title"), + NumericField.of("price").as("px").indexMissing().sortable())); + assertOK(client.ftCreate("testnoindex", TextField.of("title"), + NumericField.of("price").as("px").sortable().noIndex())); } @Test @@ -350,12 +410,19 @@ public void geoFilterAndGeoCoordinateObject() { assertEquals(2, res.getTotalResults()); } + @Test + public void geoFieldParams() { + assertOK(client.ftCreate("testindex", TextField.of("title"), GeoField.of("location").as("loc").indexMissing().sortable())); + + assertOK(client.ftCreate("testnoindex", TextField.of("title"), GeoField.of("location").as("loc").sortable().noIndex())); + } + @Test public void geoShapeFilterSpherical() throws ParseException { final WKTReader reader = new WKTReader(); final GeometryFactory factory = new GeometryFactory(); - assertOK(client.ftCreate(index, GeoShapeField.of("geom", GeoShapeField.CoordinateSystem.SPHERICAL))); + assertOK(client.ftCreate(index, GeoShapeField.of("geom", CoordinateSystem.SPHERICAL))); // polygon type final Polygon small = factory.createPolygon(new Coordinate[]{new Coordinate(34.9001, 29.7001), @@ -404,7 +471,7 @@ public void geoShapeFilterFlat() throws ParseException { final WKTReader reader = new WKTReader(); final GeometryFactory factory = new GeometryFactory(); - assertOK(client.ftCreate(index, GeoShapeField.of("geom", GeoShapeField.CoordinateSystem.FLAT))); + assertOK(client.ftCreate(index, GeoShapeField.of("geom", CoordinateSystem.FLAT))); // polygon type final Polygon small = factory.createPolygon(new Coordinate[]{new Coordinate(1, 1), @@ -444,6 +511,13 @@ public void geoShapeFilterFlat() throws ParseException { assertEquals(2, res.getDocuments().size()); } + @Test + public void geoShapeFieldParams() { + assertOK(client.ftCreate("testindex", GeoShapeField.of("geometry", CoordinateSystem.SPHERICAL).as("geom").indexMissing())); + + assertOK(client.ftCreate("testnoindex", GeoShapeField.of("geometry", CoordinateSystem.SPHERICAL).as("geom").noIndex())); + } + @Test public void testQueryFlags() { assertOK(client.ftCreate(index, TextField.of("title"))); @@ -841,6 +915,23 @@ public void caseSensitiveTagField() { assertEquals(1, client.ftSearch(index, "hello").getTotalResults()); } + @Test + public void tagFieldParams() { + assertOK(client.ftCreate("testindex", TextField.of("title"), + TagField.of("category").as("cat").indexMissing().indexEmpty() + .separator(',').caseSensitive().withSuffixTrie().sortable())); + + assertOK(client.ftCreate("testunfindex", TextField.of("title"), + TagField.of("category").as("cat").indexMissing().indexEmpty() + .separator(',').caseSensitive().withSuffixTrie().sortableUNF())); + + assertOK(client.ftCreate("testnoindex", TextField.of("title"), + TagField.of("category").as("cat").sortable().noIndex())); + + assertOK(client.ftCreate("testunfnoindex", TextField.of("title"), + TagField.of("category").as("cat").sortableUNF().noIndex())); + } + @Test public void testReturnFields() { assertOK(client.ftCreate(index, TextField.of("field1"), TextField.of("field2"))); @@ -1008,14 +1099,14 @@ public void inOrder() { } @Test - public void testHNSWVVectorSimilarity() { + public void testHNSWVectorSimilarity() { Map attr = new HashMap<>(); attr.put("TYPE", "FLOAT32"); attr.put("DIM", 2); attr.put("DISTANCE_METRIC", "L2"); assertOK(client.ftCreate(index, VectorField.builder().fieldName("v") - .algorithm(VectorField.VectorAlgorithm.HNSW).attributes(attr).build())); + .algorithm(VectorAlgorithm.HNSW).attributes(attr).build())); client.hset("a", "v", "aaaaaaaa"); client.hset("b", "v", "aaaabaaa"); @@ -1035,7 +1126,7 @@ public void testHNSWVVectorSimilarity() { public void testFlatVectorSimilarity() { assertOK(client.ftCreate(index, VectorField.builder().fieldName("v") - .algorithm(VectorField.VectorAlgorithm.FLAT) + .algorithm(VectorAlgorithm.FLAT) .addAttribute("TYPE", "FLOAT32") .addAttribute("DIM", 2) .addAttribute("DISTANCE_METRIC", "L2") @@ -1057,6 +1148,19 @@ public void testFlatVectorSimilarity() { assertEquals("0", doc1.get("__v_score")); } + @Test + public void vectorFieldParams() { + Map attr = new HashMap<>(); + attr.put("TYPE", "FLOAT32"); + attr.put("DIM", 2); + attr.put("DISTANCE_METRIC", "L2"); + + assertOK(client.ftCreate("testindex", new VectorField("vector", VectorAlgorithm.HNSW, attr).as("vec").indexMissing())); + + // assertOK(client.ftCreate("testnoindex", new VectorField("vector", VectorAlgorithm.HNSW, attr).as("vec").noIndex())); + // throws Field `NOINDEX` does not have a type + } + @Ignore @Test public void searchProfile() { From 856804a8015fc74bb13b3af04e7c7ac065d90110 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Thu, 13 Jun 2024 18:28:13 +0600 Subject: [PATCH 33/51] Test: INTERSECTS and DIJOINT conditions support in GeoSearch (#3862) --- .../GeoShapeFieldsUsageInRediSearch.java | 29 ++++--- .../modules/search/SearchWithParamsTest.java | 80 +++++++++++-------- 2 files changed, 64 insertions(+), 45 deletions(-) diff --git a/src/test/java/redis/clients/jedis/examples/GeoShapeFieldsUsageInRediSearch.java b/src/test/java/redis/clients/jedis/examples/GeoShapeFieldsUsageInRediSearch.java index fd309def50d..ea0570265d1 100644 --- a/src/test/java/redis/clients/jedis/examples/GeoShapeFieldsUsageInRediSearch.java +++ b/src/test/java/redis/clients/jedis/examples/GeoShapeFieldsUsageInRediSearch.java @@ -1,6 +1,5 @@ package redis.clients.jedis.examples; -import java.util.Collections; import org.junit.Assert; import org.locationtech.jts.geom.Coordinate; @@ -14,16 +13,21 @@ import redis.clients.jedis.JedisPooled; import redis.clients.jedis.UnifiedJedis; import redis.clients.jedis.search.FTSearchParams; -import redis.clients.jedis.search.RediSearchUtil; import redis.clients.jedis.search.SearchResult; import redis.clients.jedis.search.schemafields.GeoShapeField; /** * As of RediSearch 2.8.4, advanced GEO querying with GEOSHAPE fields is supported. + *

+ * Notes: + *

    + *
  • As of RediSearch 2.8.4, only POLYGON and POINT objects are supported.
  • + *
  • As of RediSearch 2.8.4, only WITHIN and CONTAINS conditions are supported.
  • + *
  • As of RedisStack 7.4.0, support for INTERSECTS and DISJOINT conditions are added.
  • + *
* - * Any object/library producing a - * well-known - * text (WKT) in {@code toString()} method can be used. + * Any object/library producing a + * well-known text (WKT) in {@code toString()} method can be used. * * This example uses the JTS library. *
@@ -65,7 +69,8 @@ public static void main(String[] args) {
     );
 
     // client.hset("small", RediSearchUtil.toStringMap(Collections.singletonMap("geometry", small))); // setting data
-    client.hset("small", "geometry", small.toString()); // simplified setting data
+    // client.hset("small", "geometry", small.toString()); // simplified setting data
+    client.hsetObject("small", "geometry", small); // more simplified setting data
 
     final Polygon large = factory.createPolygon(
         new Coordinate[]{new Coordinate(34.9001, 29.7001),
@@ -74,7 +79,8 @@ public static void main(String[] args) {
     );
 
     // client.hset("large", RediSearchUtil.toStringMap(Collections.singletonMap("geometry", large))); // setting data
-    client.hset("large", "geometry", large.toString()); // simplified setting data
+    // client.hset("large", "geometry", large.toString()); // simplified setting data
+    client.hsetObject("large", "geometry", large); // more simplified setting data
 
     // searching
     final Polygon within = factory.createPolygon(
@@ -84,11 +90,10 @@ public static void main(String[] args) {
     );
 
     SearchResult res = client.ftSearch("geometry-index",
-        "@geometry:[within $poly]", // querying 'within' condition.
-                                    // RediSearch also supports 'contains' condition.
+        "@geometry:[within $poly]",     // query string
         FTSearchParams.searchParams()
             .addParam("poly", within)
-            .dialect(3) // DIALECT '3' is required for this query
+            .dialect(3)                 // DIALECT '3' is required for this query
     ); 
     Assert.assertEquals(1, res.getTotalResults());
     Assert.assertEquals(1, res.getDocuments().size());
@@ -98,10 +103,8 @@ public static void main(String[] args) {
       final WKTReader reader = new WKTReader();
       Geometry object = reader.read(res.getDocuments().get(0).getString("geometry"));
       Assert.assertEquals(small, object);
-    } catch (ParseException ex) {
+    } catch (ParseException ex) { // WKTReader#read throws ParseException
       ex.printStackTrace(System.err);
     }
   }
-
-  // Note: As of RediSearch 2.8.4, only POLYGON and POINT objects are supported.
 }
diff --git a/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java b/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java
index f8e282af42d..e8029a42fd4 100644
--- a/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java
+++ b/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java
@@ -428,42 +428,42 @@ public void geoShapeFilterSpherical() throws ParseException {
     final Polygon small = factory.createPolygon(new Coordinate[]{new Coordinate(34.9001, 29.7001),
         new Coordinate(34.9001, 29.7100), new Coordinate(34.9100, 29.7100),
         new Coordinate(34.9100, 29.7001), new Coordinate(34.9001, 29.7001)});
-    client.hset("small", "geom", small.toString());
+    client.hsetObject("small", "geom", small);
 
     final Polygon large = factory.createPolygon(new Coordinate[]{new Coordinate(34.9001, 29.7001),
         new Coordinate(34.9001, 29.7200), new Coordinate(34.9200, 29.7200),
         new Coordinate(34.9200, 29.7001), new Coordinate(34.9001, 29.7001)});
-    client.hset("large", "geom", large.toString());
+    client.hsetObject("large", "geom", large);
 
     // within condition
     final Polygon within = factory.createPolygon(new Coordinate[]{new Coordinate(34.9000, 29.7000),
         new Coordinate(34.9000, 29.7150), new Coordinate(34.9150, 29.7150),
         new Coordinate(34.9150, 29.7000), new Coordinate(34.9000, 29.7000)});
 
-    SearchResult res = client.ftSearch(index, "@geom:[within $poly]",
+    SearchResult result = client.ftSearch(index, "@geom:[within $poly]",
         FTSearchParams.searchParams().addParam("poly", within).dialect(3));
-    assertEquals(1, res.getTotalResults());
-    assertEquals(1, res.getDocuments().size());
-    assertEquals(small, reader.read(res.getDocuments().get(0).getString("geom")));
+    assertEquals(1, result.getTotalResults());
+    assertEquals(1, result.getDocuments().size());
+    assertEquals(small, reader.read(result.getDocuments().get(0).getString("geom")));
 
     // contains condition
     final Polygon contains = factory.createPolygon(new Coordinate[]{new Coordinate(34.9002, 29.7002),
         new Coordinate(34.9002, 29.7050), new Coordinate(34.9050, 29.7050),
         new Coordinate(34.9050, 29.7002), new Coordinate(34.9002, 29.7002)});
 
-    res = client.ftSearch(index, "@geom:[contains $poly]",
+    result = client.ftSearch(index, "@geom:[contains $poly]",
         FTSearchParams.searchParams().addParam("poly", contains).dialect(3));
-    assertEquals(2, res.getTotalResults());
-    assertEquals(2, res.getDocuments().size());
+    assertEquals(2, result.getTotalResults());
+    assertEquals(2, result.getDocuments().size());
 
     // point type
     final Point point = factory.createPoint(new Coordinate(34.9010, 29.7010));
     client.hset("point", "geom", point.toString());
 
-    res = client.ftSearch(index, "@geom:[within $poly]",
+    result = client.ftSearch(index, "@geom:[within $poly]",
         FTSearchParams.searchParams().addParam("poly", within).dialect(3));
-    assertEquals(2, res.getTotalResults());
-    assertEquals(2, res.getDocuments().size());
+    assertEquals(2, result.getTotalResults());
+    assertEquals(2, result.getDocuments().size());
   }
 
   @Test
@@ -474,41 +474,57 @@ public void geoShapeFilterFlat() throws ParseException {
     assertOK(client.ftCreate(index, GeoShapeField.of("geom", CoordinateSystem.FLAT)));
 
     // polygon type
-    final Polygon small = factory.createPolygon(new Coordinate[]{new Coordinate(1, 1),
-        new Coordinate(1, 100), new Coordinate(100, 100), new Coordinate(100, 1), new Coordinate(1, 1)});
-    client.hset("small", "geom", small.toString());
+    final Polygon small = factory.createPolygon(new Coordinate[]{new Coordinate(20, 20),
+        new Coordinate(20, 100), new Coordinate(100, 100), new Coordinate(100, 20), new Coordinate(20, 20)});
+    client.hsetObject("small", "geom", small);
 
-    final Polygon large = factory.createPolygon(new Coordinate[]{new Coordinate(1, 1),
-        new Coordinate(1, 200), new Coordinate(200, 200), new Coordinate(200, 1), new Coordinate(1, 1)});
-    client.hset("large", "geom", large.toString());
+    final Polygon large = factory.createPolygon(new Coordinate[]{new Coordinate(10, 10),
+        new Coordinate(10, 200), new Coordinate(200, 200), new Coordinate(200, 10), new Coordinate(10, 10)});
+    client.hsetObject("large", "geom", large);
 
     // within condition
     final Polygon within = factory.createPolygon(new Coordinate[]{new Coordinate(0, 0),
         new Coordinate(0, 150), new Coordinate(150, 150), new Coordinate(150, 0), new Coordinate(0, 0)});
 
-    SearchResult res = client.ftSearch(index, "@geom:[within $poly]",
+    SearchResult result = client.ftSearch(index, "@geom:[within $poly]",
         FTSearchParams.searchParams().addParam("poly", within).dialect(3));
-    assertEquals(1, res.getTotalResults());
-    assertEquals(1, res.getDocuments().size());
-    assertEquals(small, reader.read(res.getDocuments().get(0).getString("geom")));
+    assertEquals(1, result.getTotalResults());
+    assertEquals(1, result.getDocuments().size());
+    assertEquals(small, reader.read(result.getDocuments().get(0).getString("geom")));
 
     // contains condition
-    final Polygon contains = factory.createPolygon(new Coordinate[]{new Coordinate(2, 2),
-        new Coordinate(2, 50), new Coordinate(50, 50), new Coordinate(50, 2), new Coordinate(2, 2)});
+    final Polygon contains = factory.createPolygon(new Coordinate[]{new Coordinate(25, 25),
+        new Coordinate(25, 50), new Coordinate(50, 50), new Coordinate(50, 25), new Coordinate(25, 25)});
 
-    res = client.ftSearch(index, "@geom:[contains $poly]",
+    result = client.ftSearch(index, "@geom:[contains $poly]",
         FTSearchParams.searchParams().addParam("poly", contains).dialect(3));
-    assertEquals(2, res.getTotalResults());
-    assertEquals(2, res.getDocuments().size());
+    assertEquals(2, result.getTotalResults());
+    assertEquals(2, result.getDocuments().size());
+
+    // intersects and disjoint
+    final Polygon disjointersect = factory.createPolygon(new Coordinate[]{new Coordinate(150, 150),
+        new Coordinate(150, 250), new Coordinate(250, 250), new Coordinate(250, 150), new Coordinate(150, 150)});
+
+    result = client.ftSearch(index, "@geom:[intersects $poly]",
+        FTSearchParams.searchParams().addParam("poly", disjointersect).dialect(3));
+    assertEquals(1, result.getTotalResults());
+    assertEquals(1, result.getDocuments().size());
+    assertEquals(large, reader.read(result.getDocuments().get(0).getString("geom")));
+
+    result = client.ftSearch(index, "@geom:[disjoint $poly]",
+        FTSearchParams.searchParams().addParam("poly", disjointersect).dialect(3));
+    assertEquals(1, result.getTotalResults());
+    assertEquals(1, result.getDocuments().size());
+    assertEquals(small, reader.read(result.getDocuments().get(0).getString("geom")));
 
     // point type
-    final Point point = factory.createPoint(new Coordinate(10, 10));
-    client.hset("point", "geom", point.toString());
+    final Point point = factory.createPoint(new Coordinate(30, 30));
+    client.hsetObject("point", "geom", point);
 
-    res = client.ftSearch(index, "@geom:[within $poly]",
+    result = client.ftSearch(index, "@geom:[within $poly]",
         FTSearchParams.searchParams().addParam("poly", within).dialect(3));
-    assertEquals(2, res.getTotalResults());
-    assertEquals(2, res.getDocuments().size());
+    assertEquals(2, result.getTotalResults());
+    assertEquals(2, result.getDocuments().size());
   }
 
   @Test

From 5277ed0072d222a504aa509a1d3d51e8c6a7d3b9 Mon Sep 17 00:00:00 2001
From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com>
Date: Thu, 13 Jun 2024 18:24:55 +0600
Subject: [PATCH 34/51] Support FLOAT16 and BFLOAT16 VecSim storage types
 (#3849)

---
 .../modules/search/SearchWithParamsTest.java  | 22 +++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java b/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java
index e8029a42fd4..2a60dec21f2 100644
--- a/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java
+++ b/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java
@@ -1177,6 +1177,28 @@ public void vectorFieldParams() {
     // throws Field `NOINDEX` does not have a type
   }
 
+  @Test
+  public void float16StorageType() {
+    assertOK(client.ftCreate(index,
+        VectorField.builder().fieldName("v")
+            .algorithm(VectorField.VectorAlgorithm.HNSW)
+            .addAttribute("TYPE", "FLOAT16")
+            .addAttribute("DIM", 4)
+            .addAttribute("DISTANCE_METRIC", "L2")
+            .build()));
+  }
+
+  @Test
+  public void bfloat16StorageType() {
+    assertOK(client.ftCreate(index,
+        VectorField.builder().fieldName("v")
+            .algorithm(VectorField.VectorAlgorithm.HNSW)
+            .addAttribute("TYPE", "BFLOAT16")
+            .addAttribute("DIM", 4)
+            .addAttribute("DISTANCE_METRIC", "L2")
+            .build()));
+  }
+
   @Ignore
   @Test
   public void searchProfile() {

From b2bee0e53db809a32dd579597ee7f45b9b253fb1 Mon Sep 17 00:00:00 2001
From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com>
Date: Thu, 13 Jun 2024 18:23:24 +0600
Subject: [PATCH 35/51] Support RediSearch DIALECT 5 (#3831)

- [x] Avoid escaping at query time
- [ ] Alias for tag fields (EXACT)
- [x] Avoid repeating for numeral equality
- [x] New dialect (5)
---
 .../clients/jedis/search/querybuilder/Values.java |  4 ++++
 .../clients/jedis/modules/search/SearchTest.java  | 13 +++++++++++++
 .../modules/search/SearchWithParamsTest.java      | 15 +++++++++++++++
 3 files changed, 32 insertions(+)

diff --git a/src/main/java/redis/clients/jedis/search/querybuilder/Values.java b/src/main/java/redis/clients/jedis/search/querybuilder/Values.java
index 67256f2359c..7b4971be191 100644
--- a/src/main/java/redis/clients/jedis/search/querybuilder/Values.java
+++ b/src/main/java/redis/clients/jedis/search/querybuilder/Values.java
@@ -41,10 +41,14 @@ public static RangeValue between(int from, int to) {
     return new LongRangeValue(from, to);
   }
 
+  // TODO: change to simpler [d] available since RedisStack 7.4.0-rc1;
+  // currently kept for backward compatibility
   public static RangeValue eq(double d) {
     return new DoubleRangeValue(d, d);
   }
 
+  // TODO: change to simpler [i] available since RedisStack 7.4.0-rc1;
+  // currently kept for backward compatibility
   public static RangeValue eq(int i) {
     return new LongRangeValue(i, i);
   }
diff --git a/src/test/java/redis/clients/jedis/modules/search/SearchTest.java b/src/test/java/redis/clients/jedis/modules/search/SearchTest.java
index 27f72483dbc..6fc9bcadf7a 100644
--- a/src/test/java/redis/clients/jedis/modules/search/SearchTest.java
+++ b/src/test/java/redis/clients/jedis/modules/search/SearchTest.java
@@ -412,6 +412,9 @@ public void testQueryParams() {
 
     Query query =  new Query("@numval:[$min $max]").addParam("min", 1).addParam("max", 2).dialect(2);
     assertEquals(2, client.ftSearch(index, query).getTotalResults());
+
+    query =  new Query("@numval:[$eq]").addParam("eq", 2).dialect(5);
+    assertEquals(1, client.ftSearch(index, query).getTotalResults());
   }
 
   @Test
@@ -532,6 +535,14 @@ public void testJsonWithAlias() {
     res = client.ftSearch(index, new Query("@num:[0 10]"));
     assertEquals(1, res.getTotalResults());
     assertEquals("king:2", res.getDocuments().get(0).getId());
+
+    res = client.ftSearch(index, new Query("@num:[42 42]"));
+    assertEquals(1, res.getTotalResults());
+    assertEquals("king:1", res.getDocuments().get(0).getId());
+
+    res = client.ftSearch(index, new Query("@num:[42]").dialect(5));
+    assertEquals(1, res.getTotalResults());
+    assertEquals("king:1", res.getDocuments().get(0).getId());
   }
 
   @Test
@@ -773,6 +784,7 @@ public void getTagField() {
     assertEquals(1, client.ftSearch(index, new Query("@category:{yellow}")).getTotalResults());
     assertEquals(0, client.ftSearch(index, new Query("@category:{purple}")).getTotalResults());
     assertEquals(1, client.ftSearch(index, new Query("@category:{orange\\;purple}")).getTotalResults());
+    assertEquals(1, client.ftSearch(index, new Query("@category:{orange;purple}").dialect(5)).getTotalResults());
     assertEquals(4, client.ftSearch(index, new Query("hello")).getTotalResults());
 
     assertEquals(new HashSet<>(Arrays.asList("red", "blue", "green", "yellow", "orange;purple")),
@@ -814,6 +826,7 @@ public void testGetTagFieldWithNonDefaultSeparator() {
     assertEquals(1, client.ftSearch(index, new Query("hello @category:{yellow}")).getTotalResults());
     assertEquals(0, client.ftSearch(index, new Query("@category:{purple}")).getTotalResults());
     assertEquals(1, client.ftSearch(index, new Query("@category:{orange\\,purple}")).getTotalResults());
+    assertEquals(1, client.ftSearch(index, new Query("@category:{orange,purple}").dialect(5)).getTotalResults());
     assertEquals(4, client.ftSearch(index, new Query("hello")).getTotalResults());
 
     assertEquals(new HashSet<>(Arrays.asList("red", "blue", "green", "yellow", "orange,purple")),
diff --git a/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java b/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java
index 2a60dec21f2..3cd6bca1c64 100644
--- a/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java
+++ b/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java
@@ -608,6 +608,9 @@ public void testQueryParams() {
     assertEquals(2, client.ftSearch(index, "@numval:[$min $max]",
         FTSearchParams.searchParams().params(paramValues)
             .dialect(2)).getTotalResults());
+
+    assertEquals(1, client.ftSearch(index, "@numval:[$eq]",
+        FTSearchParams.searchParams().addParam("eq", 2).dialect(5)).getTotalResults());
   }
 
   @Test
@@ -665,6 +668,14 @@ public void testJsonWithAlias() {
     res = client.ftSearch(index, "@num:[0 10]");
     assertEquals(1, res.getTotalResults());
     assertEquals("king:2", res.getDocuments().get(0).getId());
+
+    res = client.ftSearch(index, "@num:[42 42]", FTSearchParams.searchParams());
+    assertEquals(1, res.getTotalResults());
+    assertEquals("king:1", res.getDocuments().get(0).getId());
+
+    res = client.ftSearch(index, "@num:[42]", FTSearchParams.searchParams().dialect(5));
+    assertEquals(1, res.getTotalResults());
+    assertEquals("king:1", res.getDocuments().get(0).getId());
   }
 
   @Test
@@ -868,6 +879,8 @@ public void getTagField() {
     assertEquals(1, client.ftSearch(index, "@category:{yellow}").getTotalResults());
     assertEquals(0, client.ftSearch(index, "@category:{purple}").getTotalResults());
     assertEquals(1, client.ftSearch(index, "@category:{orange\\;purple}").getTotalResults());
+    assertEquals(1, client.ftSearch(index, "@category:{orange;purple}",
+        FTSearchParams.searchParams().dialect(5)).getTotalResults());
     assertEquals(4, client.ftSearch(index, "hello").getTotalResults());
 
     assertEquals(new HashSet<>(Arrays.asList("red", "blue", "green", "yellow", "orange;purple")),
@@ -907,6 +920,8 @@ public void testGetTagFieldWithNonDefaultSeparator() {
     assertEquals(1, client.ftSearch(index, "hello @category:{yellow}").getTotalResults());
     assertEquals(0, client.ftSearch(index, "@category:{purple}").getTotalResults());
     assertEquals(1, client.ftSearch(index, "@category:{orange\\,purple}").getTotalResults());
+    assertEquals(1, client.ftSearch(index, "@category:{orange,purple}",
+        FTSearchParams.searchParams().dialect(5)).getTotalResults());
     assertEquals(4, client.ftSearch(index, "hello").getTotalResults());
 
     assertEquals(new HashSet<>(Arrays.asList("red", "blue", "green", "yellow", "orange,purple")),

From b47b70f58f97495bac761be593be6402f462ab26 Mon Sep 17 00:00:00 2001
From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com>
Date: Thu, 11 Jul 2024 13:01:36 +0600
Subject: [PATCH 36/51] Remove RediSearch DIALECT 5 support (#3886)

This is partial revert of #3831.

Some changes are still available without dialect 5. For example:
* Avoid repeating for numeral equality
---
 .../redis/clients/jedis/modules/search/SearchTest.java    | 6 ++----
 .../jedis/modules/search/SearchWithParamsTest.java        | 8 ++------
 2 files changed, 4 insertions(+), 10 deletions(-)

diff --git a/src/test/java/redis/clients/jedis/modules/search/SearchTest.java b/src/test/java/redis/clients/jedis/modules/search/SearchTest.java
index 6fc9bcadf7a..0776eabcd46 100644
--- a/src/test/java/redis/clients/jedis/modules/search/SearchTest.java
+++ b/src/test/java/redis/clients/jedis/modules/search/SearchTest.java
@@ -413,7 +413,7 @@ public void testQueryParams() {
     Query query =  new Query("@numval:[$min $max]").addParam("min", 1).addParam("max", 2).dialect(2);
     assertEquals(2, client.ftSearch(index, query).getTotalResults());
 
-    query =  new Query("@numval:[$eq]").addParam("eq", 2).dialect(5);
+    query =  new Query("@numval:[$eq]").addParam("eq", 2).dialect(4);
     assertEquals(1, client.ftSearch(index, query).getTotalResults());
   }
 
@@ -540,7 +540,7 @@ public void testJsonWithAlias() {
     assertEquals(1, res.getTotalResults());
     assertEquals("king:1", res.getDocuments().get(0).getId());
 
-    res = client.ftSearch(index, new Query("@num:[42]").dialect(5));
+    res = client.ftSearch(index, new Query("@num:[42]").dialect(4));
     assertEquals(1, res.getTotalResults());
     assertEquals("king:1", res.getDocuments().get(0).getId());
   }
@@ -784,7 +784,6 @@ public void getTagField() {
     assertEquals(1, client.ftSearch(index, new Query("@category:{yellow}")).getTotalResults());
     assertEquals(0, client.ftSearch(index, new Query("@category:{purple}")).getTotalResults());
     assertEquals(1, client.ftSearch(index, new Query("@category:{orange\\;purple}")).getTotalResults());
-    assertEquals(1, client.ftSearch(index, new Query("@category:{orange;purple}").dialect(5)).getTotalResults());
     assertEquals(4, client.ftSearch(index, new Query("hello")).getTotalResults());
 
     assertEquals(new HashSet<>(Arrays.asList("red", "blue", "green", "yellow", "orange;purple")),
@@ -826,7 +825,6 @@ public void testGetTagFieldWithNonDefaultSeparator() {
     assertEquals(1, client.ftSearch(index, new Query("hello @category:{yellow}")).getTotalResults());
     assertEquals(0, client.ftSearch(index, new Query("@category:{purple}")).getTotalResults());
     assertEquals(1, client.ftSearch(index, new Query("@category:{orange\\,purple}")).getTotalResults());
-    assertEquals(1, client.ftSearch(index, new Query("@category:{orange,purple}").dialect(5)).getTotalResults());
     assertEquals(4, client.ftSearch(index, new Query("hello")).getTotalResults());
 
     assertEquals(new HashSet<>(Arrays.asList("red", "blue", "green", "yellow", "orange,purple")),
diff --git a/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java b/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java
index 3cd6bca1c64..f4c584d5075 100644
--- a/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java
+++ b/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java
@@ -610,7 +610,7 @@ public void testQueryParams() {
             .dialect(2)).getTotalResults());
 
     assertEquals(1, client.ftSearch(index, "@numval:[$eq]",
-        FTSearchParams.searchParams().addParam("eq", 2).dialect(5)).getTotalResults());
+        FTSearchParams.searchParams().addParam("eq", 2).dialect(4)).getTotalResults());
   }
 
   @Test
@@ -673,7 +673,7 @@ public void testJsonWithAlias() {
     assertEquals(1, res.getTotalResults());
     assertEquals("king:1", res.getDocuments().get(0).getId());
 
-    res = client.ftSearch(index, "@num:[42]", FTSearchParams.searchParams().dialect(5));
+    res = client.ftSearch(index, "@num:[42]", FTSearchParams.searchParams().dialect(4));
     assertEquals(1, res.getTotalResults());
     assertEquals("king:1", res.getDocuments().get(0).getId());
   }
@@ -879,8 +879,6 @@ public void getTagField() {
     assertEquals(1, client.ftSearch(index, "@category:{yellow}").getTotalResults());
     assertEquals(0, client.ftSearch(index, "@category:{purple}").getTotalResults());
     assertEquals(1, client.ftSearch(index, "@category:{orange\\;purple}").getTotalResults());
-    assertEquals(1, client.ftSearch(index, "@category:{orange;purple}",
-        FTSearchParams.searchParams().dialect(5)).getTotalResults());
     assertEquals(4, client.ftSearch(index, "hello").getTotalResults());
 
     assertEquals(new HashSet<>(Arrays.asList("red", "blue", "green", "yellow", "orange;purple")),
@@ -920,8 +918,6 @@ public void testGetTagFieldWithNonDefaultSeparator() {
     assertEquals(1, client.ftSearch(index, "hello @category:{yellow}").getTotalResults());
     assertEquals(0, client.ftSearch(index, "@category:{purple}").getTotalResults());
     assertEquals(1, client.ftSearch(index, "@category:{orange\\,purple}").getTotalResults());
-    assertEquals(1, client.ftSearch(index, "@category:{orange,purple}",
-        FTSearchParams.searchParams().dialect(5)).getTotalResults());
     assertEquals(4, client.ftSearch(index, "hello").getTotalResults());
 
     assertEquals(new HashSet<>(Arrays.asList("red", "blue", "green", "yellow", "orange,purple")),

From 59eaf342161b7c61478a2c1bf8807b39eb552ccc Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 15 Jul 2024 13:58:37 +0600
Subject: [PATCH 37/51] Bump com.google.code.gson:gson from 2.10.1 to 2.11.0
 (#3842)

Bumps [com.google.code.gson:gson](https://github.com/google/gson) from 2.10.1 to 2.11.0.
- [Release notes](https://github.com/google/gson/releases)
- [Changelog](https://github.com/google/gson/blob/main/CHANGELOG.md)
- [Commits](https://github.com/google/gson/compare/gson-parent-2.10.1...gson-parent-2.11.0)

---
updated-dependencies:
- dependency-name: com.google.code.gson:gson
  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 1ae12c300cc..00c30d37e1e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -72,7 +72,7 @@
 		
 			com.google.code.gson
 			gson
-			2.10.1
+			2.11.0
 		
 
 		

From bc94c53edd9c2d874d46e6aef584586506c0cd03 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 15 Jul 2024 14:39:17 +0600
Subject: [PATCH 38/51] Bump org.sonatype.plugins:nexus-staging-maven-plugin
 from 1.6.13 to 1.7.0 (#3850)

Bump org.sonatype.plugins:nexus-staging-maven-plugin

Bumps org.sonatype.plugins:nexus-staging-maven-plugin from 1.6.13 to 1.7.0.

---
updated-dependencies:
- dependency-name: org.sonatype.plugins:nexus-staging-maven-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 00c30d37e1e..d20da04a3ea 100644
--- a/pom.xml
+++ b/pom.xml
@@ -254,7 +254,7 @@
 			
 				org.sonatype.plugins
 				nexus-staging-maven-plugin
-				1.6.13
+				1.7.0
 				true
 				
 					ossrh

From 337d8cae9e957756fe207ea4f5040080cfec8067 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 15 Jul 2024 14:39:30 +0600
Subject: [PATCH 39/51] Bump org.apache.maven.plugins:maven-javadoc-plugin from
 3.6.3 to 3.7.0 (#3851)

Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.6.3 to 3.7.0.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.6.3...maven-javadoc-plugin-3.7.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-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 d20da04a3ea..cee45b01e9d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -231,7 +231,7 @@
 			
 			
 				maven-javadoc-plugin
-				3.6.3
+				3.7.0
 				
 					8
 					false

From b90fd0b5be3308b5fa68a27e025e9630146ded86 Mon Sep 17 00:00:00 2001
From: andy-stark-redis <164213578+andy-stark-redis@users.noreply.github.com>
Date: Tue, 16 Jul 2024 11:48:37 +0100
Subject: [PATCH 40/51] Added bitfield code samples (#3894)

Co-authored-by: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com>
---
 .../io/redis/examples/BitfieldExample.java    | 52 +++++++++++++++++++
 1 file changed, 52 insertions(+)
 create mode 100644 src/test/java/io/redis/examples/BitfieldExample.java

diff --git a/src/test/java/io/redis/examples/BitfieldExample.java b/src/test/java/io/redis/examples/BitfieldExample.java
new file mode 100644
index 00000000000..88f700c4c1b
--- /dev/null
+++ b/src/test/java/io/redis/examples/BitfieldExample.java
@@ -0,0 +1,52 @@
+// EXAMPLE: bitfield_tutorial
+// REMOVE_START
+package io.redis.examples;
+
+import org.junit.Assert;
+import org.junit.Test;
+import java.util.List;
+// REMOVE_END
+
+// HIDE_START
+import redis.clients.jedis.UnifiedJedis;
+// HIDE_END
+
+// HIDE_START
+public class BitfieldExample {
+    @Test
+    public void run() {
+        UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379");
+// HIDE_END
+
+        //REMOVE_START
+        // Clear any keys here before using them in tests.
+        jedis.del("bike:1:stats");
+        //REMOVE_END
+
+        // STEP_START bf
+        List res1 = jedis.bitfield("bike:1:stats", "SET", "u32", "#0", "1000");
+        System.out.println(res1);   // >>> [0]
+
+        List res2 = jedis.bitfield("bike:1:stats", "INCRBY", "u32", "#0", "-50", "INCRBY", "u32", "#1", "1");
+        System.out.println(res2);   // >>> [950, 1]
+
+        List res3 = jedis.bitfield("bike:1:stats", "INCRBY", "u32", "#0", "500", "INCRBY", "u32", "#1", "1");
+        System.out.println(res3);   // >>> [1450, 2]
+
+        List res4 = jedis.bitfield("bike:1:stats", "GET", "u32", "#0", "GET", "u32", "#1");
+        System.out.println(res4);   // >>> [1450, 2]
+        // STEP_END
+
+        // Tests for 'bf' step.
+        // REMOVE_START
+        Assert.assertEquals("[0]", res1.toString());
+        Assert.assertEquals("[950, 1]", res2.toString());
+        Assert.assertEquals("[1450, 2]", res3.toString());
+        Assert.assertEquals("[1450, 2]", res4.toString());
+        // REMOVE_END
+
+// HIDE_START
+        jedis.close();
+    }
+}
+// HIDE_END

From ba98da74bf0cb74f467ea3765339ef438e86bfe8 Mon Sep 17 00:00:00 2001
From: zyfx595701088 <50442211+zyfx595701088@users.noreply.github.com>
Date: Tue, 16 Jul 2024 19:14:36 +0800
Subject: [PATCH 41/51] Extract messages of unsupported exception as constants
 (#3887)

Co-authored-by: zhangshuai 
Co-authored-by: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com>
---
 .../jedis/mcf/MultiClusterTransaction.java    | 22 ++++++++++---------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/src/main/java/redis/clients/jedis/mcf/MultiClusterTransaction.java b/src/main/java/redis/clients/jedis/mcf/MultiClusterTransaction.java
index f39cdf36b69..7356f9ba79e 100644
--- a/src/main/java/redis/clients/jedis/mcf/MultiClusterTransaction.java
+++ b/src/main/java/redis/clients/jedis/mcf/MultiClusterTransaction.java
@@ -27,6 +27,8 @@
 public class MultiClusterTransaction extends TransactionBase {
 
   private static final Builder NO_OP_BUILDER = BuilderFactory.RAW_OBJECT;
+  
+  private static final String GRAPH_COMMANDS_NOT_SUPPORTED_MESSAGE = "Graph commands are not supported.";
 
   private final CircuitBreakerFailoverConnectionProvider failoverProvider;
   private final AtomicInteger extraCommandCount = new AtomicInteger();
@@ -213,52 +215,52 @@ public final String discard() {
   // RedisGraph commands
   @Override
   public Response graphQuery(String name, String query) {
-    throw new UnsupportedOperationException("Graph commands are not supported.");
+    throw new UnsupportedOperationException(GRAPH_COMMANDS_NOT_SUPPORTED_MESSAGE);
   }
 
   @Override
   public Response graphReadonlyQuery(String name, String query) {
-    throw new UnsupportedOperationException("Graph commands are not supported.");
+    throw new UnsupportedOperationException(GRAPH_COMMANDS_NOT_SUPPORTED_MESSAGE);
   }
 
   @Override
   public Response graphQuery(String name, String query, long timeout) {
-    throw new UnsupportedOperationException("Graph commands are not supported.");
+    throw new UnsupportedOperationException(GRAPH_COMMANDS_NOT_SUPPORTED_MESSAGE);
   }
 
   @Override
   public Response graphReadonlyQuery(String name, String query, long timeout) {
-    throw new UnsupportedOperationException("Graph commands are not supported.");
+    throw new UnsupportedOperationException(GRAPH_COMMANDS_NOT_SUPPORTED_MESSAGE);
   }
 
   @Override
   public Response graphQuery(String name, String query, Map params) {
-    throw new UnsupportedOperationException("Graph commands are not supported.");
+    throw new UnsupportedOperationException(GRAPH_COMMANDS_NOT_SUPPORTED_MESSAGE);
   }
 
   @Override
   public Response graphReadonlyQuery(String name, String query, Map params) {
-    throw new UnsupportedOperationException("Graph commands are not supported.");
+    throw new UnsupportedOperationException(GRAPH_COMMANDS_NOT_SUPPORTED_MESSAGE);
   }
 
   @Override
   public Response graphQuery(String name, String query, Map params, long timeout) {
-    throw new UnsupportedOperationException("Graph commands are not supported.");
+    throw new UnsupportedOperationException(GRAPH_COMMANDS_NOT_SUPPORTED_MESSAGE);
   }
 
   @Override
   public Response graphReadonlyQuery(String name, String query, Map params, long timeout) {
-    throw new UnsupportedOperationException("Graph commands are not supported.");
+    throw new UnsupportedOperationException(GRAPH_COMMANDS_NOT_SUPPORTED_MESSAGE);
   }
 
   @Override
   public Response graphDelete(String name) {
-    throw new UnsupportedOperationException("Graph commands are not supported.");
+    throw new UnsupportedOperationException(GRAPH_COMMANDS_NOT_SUPPORTED_MESSAGE);
   }
 
   @Override
   public Response> graphProfile(String graphName, String query) {
-    throw new UnsupportedOperationException("Graph commands are not supported.");
+    throw new UnsupportedOperationException(GRAPH_COMMANDS_NOT_SUPPORTED_MESSAGE);
   }
   // RedisGraph commands
 }

From e113b9ce3b1a3f51c2407cd237a849227434cf98 Mon Sep 17 00:00:00 2001
From: Ivan Babanin <1204061+babanin@users.noreply.github.com>
Date: Tue, 16 Jul 2024 13:41:25 +0200
Subject: [PATCH 42/51] Replace `synchronized` with `j.u.c.l.ReentrantLock` for
 Loom (#3480)

Co-authored-by: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com>
---
 .../redis/clients/jedis/CommandObjects.java   |  9 +++-
 .../clients/jedis/JedisSentinelPool.java      | 10 +++-
 .../jedis/graph/GraphCommandObjects.java      | 16 +++++--
 .../jedis/mcf/CircuitBreakerFailoverBase.java | 46 +++++++++++--------
 .../MultiClusterPooledConnectionProvider.java | 19 ++++++--
 .../SentineledConnectionProvider.java         | 10 +++-
 6 files changed, 77 insertions(+), 33 deletions(-)

diff --git a/src/main/java/redis/clients/jedis/CommandObjects.java b/src/main/java/redis/clients/jedis/CommandObjects.java
index cbf0e197239..5c6af322dc3 100644
--- a/src/main/java/redis/clients/jedis/CommandObjects.java
+++ b/src/main/java/redis/clients/jedis/CommandObjects.java
@@ -5,6 +5,8 @@
 
 import java.util.*;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
 import org.json.JSONArray;
@@ -50,6 +52,7 @@ protected RedisProtocol getProtocol() {
     return protocol;
   }
 
+  private Lock mapperLock = new ReentrantLock(true);    
   private volatile JsonObjectMapper jsonObjectMapper;
   private final AtomicInteger searchDialect = new AtomicInteger(0);
 
@@ -4435,11 +4438,15 @@ public final CommandObject tFunctionCallAsync(String library, String fun
   private JsonObjectMapper getJsonObjectMapper() {
     JsonObjectMapper localRef = this.jsonObjectMapper;
     if (Objects.isNull(localRef)) {
-      synchronized (this) {
+      mapperLock.lock();
+
+      try {
         localRef = this.jsonObjectMapper;
         if (Objects.isNull(localRef)) {
           this.jsonObjectMapper = localRef = new DefaultGsonObjectMapper();
         }
+      } finally {
+        mapperLock.unlock();
       }
     }
     return localRef;
diff --git a/src/main/java/redis/clients/jedis/JedisSentinelPool.java b/src/main/java/redis/clients/jedis/JedisSentinelPool.java
index 586750540c6..f6a9ea705d2 100644
--- a/src/main/java/redis/clients/jedis/JedisSentinelPool.java
+++ b/src/main/java/redis/clients/jedis/JedisSentinelPool.java
@@ -6,6 +6,8 @@
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
 import java.util.stream.Collectors;
 
 import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
@@ -28,7 +30,7 @@ public class JedisSentinelPool extends Pool {
 
   private volatile HostAndPort currentHostMaster;
   
-  private final Object initPoolLock = new Object();
+  private final Lock initPoolLock = new ReentrantLock(true);
 
   public JedisSentinelPool(String masterName, Set sentinels,
       final JedisClientConfig masterClientConfig, final JedisClientConfig sentinelClientConfig) {
@@ -213,7 +215,9 @@ public HostAndPort getCurrentHostMaster() {
   }
 
   private void initMaster(HostAndPort master) {
-    synchronized (initPoolLock) {
+    initPoolLock.lock();
+    
+    try {
       if (!master.equals(currentHostMaster)) {
         currentHostMaster = master;
         factory.setHostAndPort(currentHostMaster);
@@ -223,6 +227,8 @@ private void initMaster(HostAndPort master) {
 
         LOG.info("Created JedisSentinelPool to master at {}", master);
       }
+    } finally {
+      initPoolLock.unlock();
     }
   }
 
diff --git a/src/main/java/redis/clients/jedis/graph/GraphCommandObjects.java b/src/main/java/redis/clients/jedis/graph/GraphCommandObjects.java
index a9a49c90810..7496e6e9286 100644
--- a/src/main/java/redis/clients/jedis/graph/GraphCommandObjects.java
+++ b/src/main/java/redis/clients/jedis/graph/GraphCommandObjects.java
@@ -9,6 +9,8 @@
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.Function;
 
 import redis.clients.jedis.Builder;
@@ -106,9 +108,7 @@ private Builder getBuilder(String graphName) {
   }
 
   private void createBuilder(String graphName) {
-    synchronized (builders) {
-      builders.putIfAbsent(graphName, new ResultSetBuilder(new GraphCacheImpl(graphName)));
-    }
+    builders.computeIfAbsent(graphName, graphNameKey -> new ResultSetBuilder(new GraphCacheImpl(graphNameKey)));
   }
 
   private class GraphCacheImpl implements GraphCache {
@@ -144,6 +144,8 @@ private class GraphCacheList {
     private final String name;
     private final String query;
     private final List data = new CopyOnWriteArrayList<>();
+    
+    private final Lock dataLock = new ReentrantLock(true);
 
     /**
      *
@@ -164,14 +166,18 @@ public GraphCacheList(String name, String procedure) {
      */
     public String getCachedData(int index) {
       if (index >= data.size()) {
-        synchronized (data) {
+        dataLock.lock();
+        
+        try {
           if (index >= data.size()) {
             getProcedureInfo();
           }
+        } finally {
+          dataLock.unlock();
         }
       }
+      
       return data.get(index);
-
     }
 
     /**
diff --git a/src/main/java/redis/clients/jedis/mcf/CircuitBreakerFailoverBase.java b/src/main/java/redis/clients/jedis/mcf/CircuitBreakerFailoverBase.java
index 4ef383e6494..91ad29d9a06 100644
--- a/src/main/java/redis/clients/jedis/mcf/CircuitBreakerFailoverBase.java
+++ b/src/main/java/redis/clients/jedis/mcf/CircuitBreakerFailoverBase.java
@@ -1,6 +1,8 @@
 package redis.clients.jedis.mcf;
 
 import io.github.resilience4j.circuitbreaker.CircuitBreaker;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
 import redis.clients.jedis.annots.Experimental;
 import redis.clients.jedis.exceptions.JedisConnectionException;
 import redis.clients.jedis.providers.MultiClusterPooledConnectionProvider;
@@ -17,6 +19,7 @@
  */
 @Experimental
 public class CircuitBreakerFailoverBase implements AutoCloseable {
+    private final Lock lock = new ReentrantLock(true);
 
     protected final MultiClusterPooledConnectionProvider provider;
 
@@ -32,29 +35,34 @@ public void close() {
     /**
      * Functional interface wrapped in retry and circuit breaker logic to handle open circuit breaker failure scenarios
      */
-    protected synchronized void clusterFailover(CircuitBreaker circuitBreaker) {
+    protected void clusterFailover(CircuitBreaker circuitBreaker) {
+        lock.lock();
+        
+        try {
+            // Check state to handle race conditions since incrementActiveMultiClusterIndex() is non-idempotent
+            if (!CircuitBreaker.State.FORCED_OPEN.equals(circuitBreaker.getState())) {
 
-        // Check state to handle race conditions since incrementActiveMultiClusterIndex() is non-idempotent
-        if (!CircuitBreaker.State.FORCED_OPEN.equals(circuitBreaker.getState())) {
+                // Transitions state machine to a FORCED_OPEN state, stopping state transition, metrics and event publishing.
+                // To recover/transition from this forced state the user will need to manually failback
+                circuitBreaker.transitionToForcedOpenState();
 
-            // Transitions state machine to a FORCED_OPEN state, stopping state transition, metrics and event publishing.
-            // To recover/transition from this forced state the user will need to manually failback
-            circuitBreaker.transitionToForcedOpenState();
+                // Incrementing the activeMultiClusterIndex will allow subsequent calls to the executeCommand()
+                // to use the next cluster's connection pool - according to the configuration's prioritization/order
+                int activeMultiClusterIndex = provider.incrementActiveMultiClusterIndex();
 
-            // Incrementing the activeMultiClusterIndex will allow subsequent calls to the executeCommand()
-            // to use the next cluster's connection pool - according to the configuration's prioritization/order
-            int activeMultiClusterIndex = provider.incrementActiveMultiClusterIndex();
+                // Implementation is optionally provided during configuration. Typically, used for activeMultiClusterIndex persistence or custom logging
+                provider.runClusterFailoverPostProcessor(activeMultiClusterIndex);
+            }
 
-            // Implementation is optionally provided during configuration. Typically, used for activeMultiClusterIndex persistence or custom logging
-            provider.runClusterFailoverPostProcessor(activeMultiClusterIndex);
-        }
-
-        // Once the priority list is exhausted only a manual failback can open the circuit breaker so all subsequent operations will fail
-        else if (provider.isLastClusterCircuitBreakerForcedOpen()) {
-            throw new JedisConnectionException("Cluster/database endpoint could not failover since the MultiClusterClientConfig was not " +
-                                               "provided with an additional cluster/database endpoint according to its prioritized sequence. " +
-                                               "If applicable, consider failing back OR restarting with an available cluster/database endpoint");
+            // Once the priority list is exhausted only a manual failback can open the circuit breaker so all subsequent operations will fail
+            else if (provider.isLastClusterCircuitBreakerForcedOpen()) {
+                throw new JedisConnectionException("Cluster/database endpoint could not failover since the MultiClusterClientConfig was not " +
+                                                   "provided with an additional cluster/database endpoint according to its prioritized sequence. " +
+                                                   "If applicable, consider failing back OR restarting with an available cluster/database endpoint");
+            }
+        } finally {
+            lock.unlock();
         }
     }
 
-}
\ No newline at end of file
+}
diff --git a/src/main/java/redis/clients/jedis/providers/MultiClusterPooledConnectionProvider.java b/src/main/java/redis/clients/jedis/providers/MultiClusterPooledConnectionProvider.java
index 47b03c77733..9ddf8e810a0 100644
--- a/src/main/java/redis/clients/jedis/providers/MultiClusterPooledConnectionProvider.java
+++ b/src/main/java/redis/clients/jedis/providers/MultiClusterPooledConnectionProvider.java
@@ -13,6 +13,8 @@
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.Consumer;
 
 import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
@@ -54,6 +56,8 @@ public class MultiClusterPooledConnectionProvider implements ConnectionProvider
      * provided at startup via the MultiClusterClientConfig. All traffic will be routed according to this index.
      */
     private volatile Integer activeMultiClusterIndex = 1;
+    
+    private final Lock activeClusterIndexLock = new ReentrantLock(true);
 
     /**
      * Indicates the final cluster/database endpoint (connection pool), according to the pre-configured list
@@ -162,8 +166,9 @@ public int incrementActiveMultiClusterIndex() {
 
         // Field-level synchronization is used to avoid the edge case in which
         // setActiveMultiClusterIndex(int multiClusterIndex) is called at the same time
-        synchronized (activeMultiClusterIndex) {
-
+        activeClusterIndexLock.lock();
+        
+        try {
             String originalClusterName = getClusterCircuitBreaker().getName();
 
             // Only increment if it can pass this validation otherwise we will need to check for NULL in the data path
@@ -185,6 +190,8 @@ public int incrementActiveMultiClusterIndex() {
                 incrementActiveMultiClusterIndex();
 
             else log.warn("Cluster/database endpoint successfully updated from '{}' to '{}'", originalClusterName, circuitBreaker.getName());
+        } finally {
+            activeClusterIndexLock.unlock();
         }
 
         return activeMultiClusterIndex;
@@ -229,11 +236,13 @@ public void validateTargetConnection(int multiClusterIndex) {
      * Special care should be taken to confirm cluster/database availability AND
      * potentially cross-cluster replication BEFORE using this capability.
      */
-    public synchronized void setActiveMultiClusterIndex(int multiClusterIndex) {
+    public void setActiveMultiClusterIndex(int multiClusterIndex) {
 
         // Field-level synchronization is used to avoid the edge case in which
         // incrementActiveMultiClusterIndex() is called at the same time
-        synchronized (activeMultiClusterIndex) {
+        activeClusterIndexLock.lock();
+        
+        try {
 
             // Allows an attempt to reset the current cluster from a FORCED_OPEN to CLOSED state in the event that no failover is possible
             if (activeMultiClusterIndex == multiClusterIndex &&
@@ -256,6 +265,8 @@ public synchronized void setActiveMultiClusterIndex(int multiClusterIndex) {
 
             activeMultiClusterIndex = multiClusterIndex;
             lastClusterCircuitBreakerForcedOpen = false;
+        } finally {
+            activeClusterIndexLock.unlock();
         }
     }
 
diff --git a/src/main/java/redis/clients/jedis/providers/SentineledConnectionProvider.java b/src/main/java/redis/clients/jedis/providers/SentineledConnectionProvider.java
index 5058f07179a..f2f07464609 100644
--- a/src/main/java/redis/clients/jedis/providers/SentineledConnectionProvider.java
+++ b/src/main/java/redis/clients/jedis/providers/SentineledConnectionProvider.java
@@ -5,6 +5,8 @@
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
 
 import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
 import org.slf4j.Logger;
@@ -43,7 +45,7 @@ public class SentineledConnectionProvider implements ConnectionProvider {
 
   private final long subscribeRetryWaitTimeMillis;
 
-  private final Object initPoolLock = new Object();
+  private final Lock initPoolLock = new ReentrantLock(true);
 
   public SentineledConnectionProvider(String masterName, final JedisClientConfig masterClientConfig,
       Set sentinels, final JedisClientConfig sentinelClientConfig) {
@@ -95,7 +97,9 @@ public HostAndPort getCurrentMaster() {
   }
 
   private void initMaster(HostAndPort master) {
-    synchronized (initPoolLock) {
+    initPoolLock.lock();
+    
+    try {
       if (!master.equals(currentMaster)) {
         currentMaster = master;
 
@@ -114,6 +118,8 @@ private void initMaster(HostAndPort master) {
           existingPool.close();
         }
       }
+    } finally {
+      initPoolLock.unlock();
     }
   }
 

From 773651c896fc17195763ab37e4baf30253da6c28 Mon Sep 17 00:00:00 2001
From: zyfx595701088 <50442211+zyfx595701088@users.noreply.github.com>
Date: Tue, 16 Jul 2024 20:04:25 +0800
Subject: [PATCH 43/51] Modify the judgment that reads a response as empty to
 isEmpty method (#3888)

Co-authored-by: zhangshuai 
---
 src/main/java/redis/clients/jedis/util/RedisInputStream.java | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/main/java/redis/clients/jedis/util/RedisInputStream.java b/src/main/java/redis/clients/jedis/util/RedisInputStream.java
index a0dad9d4370..f7e320f1642 100644
--- a/src/main/java/redis/clients/jedis/util/RedisInputStream.java
+++ b/src/main/java/redis/clients/jedis/util/RedisInputStream.java
@@ -14,6 +14,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.math.BigInteger;
+
 import redis.clients.jedis.exceptions.JedisConnectionException;
 
 /**
@@ -84,7 +85,7 @@ public String readLine() {
     }
 
     final String reply = sb.toString();
-    if (reply.length() == 0) {
+    if (reply.isEmpty()) {
       throw new JedisConnectionException("It seems like server has closed the connection.");
     }
 

From 2274416b771c161f3f659ca70633a90376f3c42c Mon Sep 17 00:00:00 2001
From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com>
Date: Tue, 16 Jul 2024 20:45:50 +0600
Subject: [PATCH 44/51] JedisConnectionException contains HostAndPort from
 DefaultJedisSocketFactory (#3896)

---
 src/main/java/redis/clients/jedis/Connection.java               | 2 +-
 .../java/redis/clients/jedis/DefaultJedisSocketFactory.java     | 2 +-
 .../jedis/providers/MultiClusterPooledConnectionProvider.java   | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/main/java/redis/clients/jedis/Connection.java b/src/main/java/redis/clients/jedis/Connection.java
index f9fe5594829..9325de80d7c 100644
--- a/src/main/java/redis/clients/jedis/Connection.java
+++ b/src/main/java/redis/clients/jedis/Connection.java
@@ -343,7 +343,7 @@ protected void flush() {
 
   protected Object readProtocolWithCheckingBroken() {
     if (broken) {
-      throw new JedisConnectionException("Attempting to read from a broken connection");
+      throw new JedisConnectionException("Attempting to read from a broken connection.");
     }
 
     try {
diff --git a/src/main/java/redis/clients/jedis/DefaultJedisSocketFactory.java b/src/main/java/redis/clients/jedis/DefaultJedisSocketFactory.java
index a2d963e2214..c9ef6646ba6 100644
--- a/src/main/java/redis/clients/jedis/DefaultJedisSocketFactory.java
+++ b/src/main/java/redis/clients/jedis/DefaultJedisSocketFactory.java
@@ -60,7 +60,7 @@ private Socket connectToFirstSuccessfulHost(HostAndPort hostAndPort) throws Exce
       Collections.shuffle(hosts);
     }
 
-    JedisConnectionException jce = new JedisConnectionException("Failed to connect to any host resolved for DNS name.");
+    JedisConnectionException jce = new JedisConnectionException("Failed to connect to " + hostAndPort + ".");
     for (InetAddress host : hosts) {
       try {
         Socket socket = new Socket();
diff --git a/src/main/java/redis/clients/jedis/providers/MultiClusterPooledConnectionProvider.java b/src/main/java/redis/clients/jedis/providers/MultiClusterPooledConnectionProvider.java
index 9ddf8e810a0..eb443bca1e5 100644
--- a/src/main/java/redis/clients/jedis/providers/MultiClusterPooledConnectionProvider.java
+++ b/src/main/java/redis/clients/jedis/providers/MultiClusterPooledConnectionProvider.java
@@ -178,7 +178,7 @@ public int incrementActiveMultiClusterIndex() {
 
                 throw new JedisConnectionException("Cluster/database endpoint could not failover since the MultiClusterClientConfig was not " +
                                                    "provided with an additional cluster/database endpoint according to its prioritized sequence. " +
-                                                   "If applicable, consider failing back OR restarting with an available cluster/database endpoint");
+                                                   "If applicable, consider failing back OR restarting with an available cluster/database endpoint.");
             }
             else activeMultiClusterIndex++;
 

From 28e7c73ba6bb8532dd1397928a735d0fc7a43813 Mon Sep 17 00:00:00 2001
From: andy-stark-redis <164213578+andy-stark-redis@users.noreply.github.com>
Date: Wed, 17 Jul 2024 13:10:48 +0100
Subject: [PATCH 45/51] Json tabbed code sample (#3895)

Co-authored-by: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com>
---
 .../java/io/redis/examples/JsonExample.java   | 509 ++++++++++++++++++
 1 file changed, 509 insertions(+)
 create mode 100644 src/test/java/io/redis/examples/JsonExample.java

diff --git a/src/test/java/io/redis/examples/JsonExample.java b/src/test/java/io/redis/examples/JsonExample.java
new file mode 100644
index 00000000000..4fd635b6515
--- /dev/null
+++ b/src/test/java/io/redis/examples/JsonExample.java
@@ -0,0 +1,509 @@
+// EXAMPLE: json_tutorial
+// REMOVE_START
+package io.redis.examples;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.List;
+
+// REMOVE_END
+// HIDE_START
+import redis.clients.jedis.UnifiedJedis;
+import redis.clients.jedis.json.Path2;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+// HIDE_END
+
+// HIDE_START
+public class JsonExample {
+    @Test
+    public void run() {
+        UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379");
+// HIDE_END
+
+        //REMOVE_START
+        // Clear any keys here before using them in tests.
+        jedis.del("bike", "bike:1", "crashes", "newbike", "riders", "bikes:inventory");
+        //REMOVE_END
+
+        // STEP_START set_get
+        String res1 = jedis.jsonSet("bike", new Path2("$"), "\"Hyperion\"");
+        System.out.println(res1);   // >>> OK
+
+        Object res2 = jedis.jsonGet("bike", new Path2("$"));
+        System.out.println(res2);   // >>> ["Hyperion"]
+
+        List> res3 = jedis.jsonType("bike", new Path2("$"));
+        System.out.println(res3);   // >>> [class java.lang.String]
+        // STEP_END
+
+        // Tests for 'set_get' step.
+        // REMOVE_START
+        Assert.assertEquals("OK", res1);
+        Assert.assertEquals("[\"Hyperion\"]", res2.toString());
+        Assert.assertEquals("[class java.lang.String]", res3.toString());
+        // REMOVE_END
+
+
+        // STEP_START str
+        List res4 = jedis.jsonStrLen("bike", new Path2("$"));
+        System.out.println(res4);   // >>> [8]
+
+        List res5 = jedis.jsonStrAppend("bike", new Path2("$"), " (Enduro bikes)");
+        System.out.println(res5);   // >>> [23]
+
+        Object res6 = jedis.jsonGet("bike", new Path2("$"));
+        System.out.println(res6);   // >>> ["Hyperion (Enduro bikes)"]
+        // STEP_END
+
+        // Tests for 'str' step.
+        // REMOVE_START
+        Assert.assertEquals("[8]", res4.toString());
+        Assert.assertEquals("[23]", res5.toString());
+        Assert.assertEquals("[\"Hyperion (Enduro bikes)\"]", res6.toString());
+        // REMOVE_END
+
+
+        // STEP_START num
+        String res7 = jedis.jsonSet("crashes", new Path2("$"), 0);
+        System.out.println(res7);   // >>> OK
+
+        Object res8 = jedis.jsonNumIncrBy("crashes", new Path2("$"), 1);
+        System.out.println(res8);   // >>> [1]
+
+        Object res9 = jedis.jsonNumIncrBy("crashes", new Path2("$"), 1.5);
+        System.out.println(res9);   // >>> [2.5]
+
+        Object res10 = jedis.jsonNumIncrBy("crashes", new Path2("$"), -0.75);
+        System.out.println(res10);   // >>> [1.75]
+        // STEP_END
+
+        // Tests for 'num' step.
+        // REMOVE_START
+        Assert.assertEquals("OK", res7);
+        Assert.assertEquals("[1]", res8.toString());
+        Assert.assertEquals("[2.5]", res9.toString());
+        Assert.assertEquals("[1.75]", res10.toString());
+        // REMOVE_END
+
+
+        // STEP_START arr
+        String res11 = jedis.jsonSet("newbike", new Path2("$"),
+            new JSONArray()
+                .put("Deimos")
+                .put(new JSONObject().put("crashes", 0))
+                .put((Object) null)
+        );
+        System.out.println(res11);  // >>> OK
+        
+        Object res12 = jedis.jsonGet("newbike", new Path2("$"));
+        System.out.println(res12);  // >>> [["Deimos",{"crashes":0},null]]
+
+        Object res13 = jedis.jsonGet("newbike", new Path2("$[1].crashes"));
+        System.out.println(res13);  // >>> [0]
+
+        long res14 = jedis.jsonDel("newbike", new Path2("$.[-1]"));
+        System.out.println(res14);  // >>> 1
+
+        Object res15 = jedis.jsonGet("newbike", new Path2("$"));
+        System.out.println(res15);  // >>> [["Deimos",{"crashes":0}]]
+        // STEP_END
+
+        // Tests for 'arr' step.
+        // REMOVE_START
+        Assert.assertEquals("OK", res11);
+        Assert.assertEquals("[[\"Deimos\",{\"crashes\":0},null]]", res12.toString());
+        Assert.assertEquals("[0]", res13.toString());
+        Assert.assertEquals(1, res14);
+        Assert.assertEquals("[[\"Deimos\",{\"crashes\":0}]]", res15.toString());
+        // REMOVE_END
+
+
+        // STEP_START arr2
+        String res16 = jedis.jsonSet("riders", new Path2("$"), new JSONArray());
+        System.out.println(res16);  // >>> OK
+
+        List res17 = jedis.jsonArrAppendWithEscape("riders", new Path2("$"), "Norem");
+        System.out.println(res17);  // >>> [1]
+
+        Object res18 = jedis.jsonGet("riders", new Path2("$"));
+        System.out.println(res18);  // >>> [["Norem"]]
+
+        List res19 = jedis.jsonArrInsertWithEscape(
+            "riders", new Path2("$"), 1, "Prickett", "Royce", "Castilla"
+        );
+        System.out.println(res19);  // >>> [4]
+
+        Object res20 = jedis.jsonGet("riders", new Path2("$"));
+        System.out.println(res20);
+        // >>> [["Norem","Prickett","Royce","Castilla"]]
+        
+        List res21 = jedis.jsonArrTrim("riders", new Path2("$"), 1, 1);
+        System.out.println(res21);  // >>> [1]
+
+        Object res22 = jedis.jsonGet("riders", new Path2("$"));
+        System.out.println(res22);  // >>> [["Prickett"]]
+
+        Object res23 = jedis.jsonArrPop("riders", new Path2("$"));
+        System.out.println(res23);  // >>> [Prickett]
+
+        Object res24 = jedis.jsonArrPop("riders", new Path2("$"));
+        System.out.println(res24);  // >>> [null]
+        // STEP_END
+
+        // Tests for 'arr2' step.
+        // REMOVE_START
+        Assert.assertEquals("OK", res16);
+        Assert.assertEquals("[1]", res17.toString());
+        Assert.assertEquals("[[\"Norem\"]]", res18.toString());
+        Assert.assertEquals("[4]", res19.toString());
+        Assert.assertEquals("[[\"Norem\",\"Prickett\",\"Royce\",\"Castilla\"]]", res20.toString());
+        Assert.assertEquals("[1]", res21.toString());
+        Assert.assertEquals("[[\"Prickett\"]]", res22.toString());
+        Assert.assertEquals("[Prickett]", res23.toString());
+        Assert.assertEquals("[null]", res24.toString());
+        // REMOVE_END
+
+
+        // STEP_START obj
+        String res25 = jedis.jsonSet("bike:1", new Path2("$"),
+            new JSONObject()
+                .put("model", "Deimos")
+                .put("brand", "Ergonom")
+                .put("price", 4972)
+        );
+        System.out.println(res25);  // >>> OK
+
+        List res26 = jedis.jsonObjLen("bike:1", new Path2("$"));
+        System.out.println(res26);  // >>> [3]
+
+        List> res27 = jedis.jsonObjKeys("bike:1", new Path2("$"));
+        System.out.println(res27);  // >>> [[price, model, brand]]
+        // STEP_END
+
+        // Tests for 'obj' step.
+        // REMOVE_START
+        Assert.assertEquals("OK", res25);
+        Assert.assertEquals("[3]", res26.toString());
+        Assert.assertEquals("[[price, model, brand]]", res27.toString());
+        // REMOVE_END
+
+        // STEP_START set_bikes
+        String inventory_json = "{"
+        + "    \"inventory\": {"
+        + "        \"mountain_bikes\": ["
+        + "            {"
+        + "                \"id\": \"bike:1\","
+        + "                \"model\": \"Phoebe\","
+        + "                \"description\": \"This is a mid-travel trail slayer that is a "
+        + "fantastic daily driver or one bike quiver. The Shimano Claris 8-speed groupset "
+        + "gives plenty of gear range to tackle hills and there\u2019s room for mudguards "
+        + "and a rack too.  This is the bike for the rider who wants trail manners with "
+        + "low fuss ownership.\","
+        + "                \"price\": 1920,"
+        + "                \"specs\": {\"material\": \"carbon\", \"weight\": 13.1},"
+        + "                \"colors\": [\"black\", \"silver\"]"
+        + "            },"
+        + "            {"
+        + "                \"id\": \"bike:2\","
+        + "                \"model\": \"Quaoar\","
+        + "                \"description\": \"Redesigned for the 2020 model year, this "
+        + "bike impressed our testers and is the best all-around trail bike we've ever "
+        + "tested. The Shimano gear system effectively does away with an external cassette, "
+        + "so is super low maintenance in terms of wear and tear. All in all it's an "
+        + "impressive package for the price, making it very competitive.\","
+        + "                \"price\": 2072,"
+        + "                \"specs\": {\"material\": \"aluminium\", \"weight\": 7.9},"
+        + "                \"colors\": [\"black\", \"white\"]"
+        + "            },"
+        + "            {"
+        + "                \"id\": \"bike:3\","
+        + "                \"model\": \"Weywot\","
+        + "                \"description\": \"This bike gives kids aged six years and older "
+        + "a durable and uberlight mountain bike for their first experience on tracks and easy "
+        + "cruising through forests and fields. A set of powerful Shimano hydraulic disc brakes "
+        + "provide ample stopping ability. If you're after a budget option, this is one of the "
+        + "best bikes you could get.\","
+        + "                \"price\": 3264,"
+        + "                \"specs\": {\"material\": \"alloy\", \"weight\": 13.8}"
+        + "            }"
+        + "        ],"
+        + "        \"commuter_bikes\": ["
+        + "            {"
+        + "                \"id\": \"bike:4\","
+        + "                \"model\": \"Salacia\","
+        + "                \"description\": \"This bike is a great option for anyone who just "
+        + "wants a bike to get about on With a slick-shifting Claris gears from Shimano\u2019s, "
+        + "this is a bike which doesn\u2019t break the bank and delivers craved performance.  "
+        + "It\u2019s for the rider who wants both efficiency and capability.\","
+        + "                \"price\": 1475,"
+        + "                \"specs\": {\"material\": \"aluminium\", \"weight\": 16.6},"
+        + "                \"colors\": [\"black\", \"silver\"]"
+        + "            },"
+        + "            {"
+        + "                \"id\": \"bike:5\","
+        + "                \"model\": \"Mimas\","
+        + "                \"description\": \"A real joy to ride, this bike got very high scores "
+        + "in last years Bike of the year report. The carefully crafted 50-34 tooth chainset "
+        + "and 11-32 tooth cassette give an easy-on-the-legs bottom gear for climbing, and the "
+        + "high-quality Vittoria Zaffiro tires give balance and grip.It includes a low-step "
+        + "frame , our memory foam seat, bump-resistant shocks and conveniently placed thumb "
+        + "throttle. Put it all together and you get a bike that helps redefine what can be "
+        + "done for this price.\","
+        + "                \"price\": 3941,"
+        + "                \"specs\": {\"material\": \"alloy\", \"weight\": 11.6}"
+        + "            }"
+        + "        ]"
+        + "    }"
+        + "}";
+
+        String res28 = jedis.jsonSet("bikes:inventory", new Path2("$"), inventory_json);
+        System.out.println(res28);  // >>> OK
+        // STEP_END
+
+        // Tests for 'set_bikes' step.
+        // REMOVE_START
+        Assert.assertEquals("OK", res28);
+        // REMOVE_END
+
+
+        // STEP_START get_bikes
+        Object res29 = jedis.jsonGet("bikes:inventory", new Path2("$.inventory.*"));
+        System.out.println(res29);
+        // >>> [[{"specs":{"material":"carbon","weight":13.1},"price":1920, ...
+        // STEP_END
+
+        // Tests for 'get_bikes' step.
+        // REMOVE_START
+        Assert.assertEquals(
+            "[[{\"specs\":{\"material\":\"carbon\",\"weight\":13.1},\"price\":1920,"
+            + "\"description\":\"This is a mid-travel trail slayer that is a "
+            + "fantastic daily driver or one bike quiver. The Shimano Claris 8-speed "
+            + "groupset gives plenty of gear range to tackle hills and "
+            + "there\\u2019s room for mudguards and a rack too.  This is the bike "
+            + "for the rider who wants trail manners with low fuss "
+            + "ownership.\",\"model\":\"Phoebe\",\"id\":\"bike:1\",\"colors\":"
+            + "[\"black\",\"silver\"]},{\"specs\":{\"material\":\"aluminium\",\"weight\":7.9},"
+            + "\"price\":2072,\"description\":\"Redesigned for the 2020 model year, this "
+            + "bike impressed our testers and is the best all-around trail bike we've "
+            + "ever tested. The Shimano gear system effectively does away with an "
+            + "external cassette, so is super low maintenance in terms of wear and tear. "
+            + "All in all it's an impressive package for the price, making it very "
+            + "competitive.\",\"model\":\"Quaoar\",\"id\":\"bike:2\",\"colors\":"
+            + "[\"black\",\"white\"]},{\"specs\":{\"material\":\"alloy\",\"weight\":13.8},"
+            + "\"price\":3264,\"description\":\"This bike gives kids aged six years and "
+            + "older a durable and uberlight mountain bike for their first experience "
+            + "on tracks and easy cruising through forests and fields. A set of "
+            + "powerful Shimano hydraulic disc brakes provide ample stopping ability. "
+            + "If you're after a budget option, this is one of the best bikes you could "
+            + "get.\",\"model\":\"Weywot\",\"id\":\"bike:3\"}],[{\"specs\":"
+            + "{\"material\":\"aluminium\",\"weight\":16.6},\"price\":1475,\"description\":"
+            + "\"This bike is a great option for anyone who just wants a bike to get about "
+            + "on With a slick-shifting Claris gears from Shimano\\u2019s, this is a bike "
+            + "which doesn\\u2019t break the bank and delivers craved performance.  "
+            + "It\\u2019s for the rider who wants both efficiency and "
+            + "capability.\",\"model\":\"Salacia\",\"id\":\"bike:4\",\"colors\":"
+            + "[\"black\",\"silver\"]},{\"specs\":{\"material\":\"alloy\",\"weight\":11.6},"
+            + "\"price\":3941,\"description\":\"A real joy to ride, this bike got very "
+            + "high scores in last years Bike of the year report. The carefully crafted "
+            + "50-34 tooth chainset and 11-32 tooth cassette give an easy-on-the-legs "
+            + "bottom gear for climbing, and the high-quality Vittoria Zaffiro tires "
+            + "give balance and grip.It includes a low-step frame , our memory foam "
+            + "seat, bump-resistant shocks and conveniently placed thumb throttle. Put "
+            + "it all together and you get a bike that helps redefine what can be done "
+            + "for this price.\",\"model\":\"Mimas\",\"id\":\"bike:5\"}]]",
+             res29.toString()
+        );
+        // REMOVE_END
+
+
+        // STEP_START get_mtnbikes
+        Object res30 = jedis.jsonGet(
+            "bikes:inventory", new Path2("$.inventory.mountain_bikes[*].model")
+        );
+        System.out.println(res30);  // >>> ["Phoebe","Quaoar","Weywot"]
+
+        Object res31 = jedis.jsonGet(
+            "bikes:inventory", new Path2("$.inventory[\"mountain_bikes\"][*].model")
+        );
+        System.out.println(res31);  // >>> ["Phoebe","Quaoar","Weywot"]
+
+        Object res32 = jedis.jsonGet(
+            "bikes:inventory", new Path2("$..mountain_bikes[*].model")
+        );
+        System.out.println(res32);  // >>> ["Phoebe","Quaoar","Weywot"]
+        // STEP_END
+
+        // Tests for 'get_mtnbikes' step.
+        // REMOVE_START
+        Assert.assertEquals("[\"Phoebe\",\"Quaoar\",\"Weywot\"]", res30.toString());
+        Assert.assertEquals("[\"Phoebe\",\"Quaoar\",\"Weywot\"]", res31.toString());
+        Assert.assertEquals("[\"Phoebe\",\"Quaoar\",\"Weywot\"]", res32.toString());
+        // REMOVE_END
+
+
+        // STEP_START get_models
+        Object res33 = jedis.jsonGet("bikes:inventory", new Path2("$..model"));
+        System.out.println(res33);
+        // >>> ["Phoebe","Quaoar","Weywot","Salacia","Mimas"]
+        // STEP_END
+
+        // Tests for 'get_models' step.
+        // REMOVE_START
+        Assert.assertEquals("[\"Phoebe\",\"Quaoar\",\"Weywot\",\"Salacia\",\"Mimas\"]", res33.toString());
+        // REMOVE_END
+
+
+        // STEP_START get2mtnbikes
+        Object res34 = jedis.jsonGet(
+            "bikes:inventory", new Path2("$..mountain_bikes[0:2].model")
+        );
+        System.out.println(res34);  // >>> ["Phoebe","Quaoar"]
+        // STEP_END
+
+        // Tests for 'get2mtnbikes' step.
+        // REMOVE_START
+        Assert.assertEquals("[\"Phoebe\",\"Quaoar\"]", res34.toString());
+        // REMOVE_END
+
+
+        // STEP_START filter1
+        Object res35 = jedis.jsonGet(
+            "bikes:inventory",
+            new Path2("$..mountain_bikes[?(@.price < 3000 && @.specs.weight < 10)]")
+        );
+        System.out.println(res35);
+        // >>> [{"specs":{"material":"aluminium","weight":7.9},"price":2072,...
+        // STEP_END
+
+        // Tests for 'filter1' step.
+        // REMOVE_START
+        Assert.assertEquals(
+            "[{\"specs\":{\"material\":\"aluminium\",\"weight\":7.9},\"price\":2072,"
+            + "\"description\":\"Redesigned for the 2020 model year, this bike impressed "
+            + "our testers and is the best all-around trail bike we've ever tested. The "
+            + "Shimano gear system effectively does away with an external cassette, "
+            + "so is super low maintenance in terms of wear and tear. All in all it's an "
+            + "impressive package for the price, making it very competitive.\",\"model\":"
+            + "\"Quaoar\",\"id\":\"bike:2\",\"colors\":[\"black\",\"white\"]}]",
+            res35.toString()
+        );
+        // REMOVE_END
+
+
+        // STEP_START filter2
+        Object res36 = jedis.jsonGet(
+            "bikes:inventory", new Path2("$..[?(@.specs.material == 'alloy')].model")
+        );
+        System.out.println(res36);  // >>> ["Weywot","Mimas"]
+        // STEP_END
+
+        // Tests for 'filter2' step.
+        // REMOVE_START
+        Assert.assertEquals("[\"Weywot\",\"Mimas\"]", res36.toString());
+        // REMOVE_END
+
+
+        // STEP_START filter3
+        Object res37 = jedis.jsonGet(
+            "bikes:inventory", new Path2("$..[?(@.specs.material =~ '(?i)al')].model")
+        );
+        System.out.println(res37);
+        // >>> ["Quaoar","Weywot","Salacia","Mimas"]
+        // STEP_END
+
+        // Tests for 'filter3' step.
+        // REMOVE_START
+        Assert.assertEquals("[\"Quaoar\",\"Weywot\",\"Salacia\",\"Mimas\"]", res37.toString());
+        // REMOVE_END
+
+
+        // STEP_START filter4
+        jedis.jsonSet(
+            "bikes:inventory", new Path2("$.inventory.mountain_bikes[0].regex_pat"),
+            "\"(?i)al\""
+        );
+        jedis.jsonSet(
+            "bikes:inventory", new Path2("$.inventory.mountain_bikes[1].regex_pat"),
+            "\"(?i)al\""
+        );
+        jedis.jsonSet(
+            "bikes:inventory", new Path2("$.inventory.mountain_bikes[2].regex_pat"),
+            "\"(?i)al\""
+        );
+        
+        Object res38 = jedis.jsonGet(
+            "bikes:inventory",
+            new Path2("$.inventory.mountain_bikes[?(@.specs.material =~ @.regex_pat)].model")
+        );
+        System.out.println(res38);  // >>> ["Quaoar","Weywot"]
+        // STEP_END
+
+        // Tests for 'filter4' step.
+        // REMOVE_START
+        Assert.assertEquals("[\"Quaoar\",\"Weywot\"]", res38.toString());
+        // REMOVE_END
+
+
+        // STEP_START update_bikes
+        Object res39 = jedis.jsonGet("bikes:inventory", new Path2("$..price"));
+        System.out.println(res39);
+        // >>> [1920,2072,3264,1475,3941]
+
+        Object res40 = jedis.jsonNumIncrBy("bikes:inventory", new Path2("$..price"), -100);
+        System.out.println(res40);  // >>> [1820,1972,3164,1375,3841]
+
+        Object res41 = jedis.jsonNumIncrBy("bikes:inventory", new Path2("$..price"), 100);
+        System.out.println(res41);  // >>> [1920,2072,3264,1475,3941]
+        // STEP_END
+
+        // Tests for 'update_bikes' step.
+        // REMOVE_START
+        Assert.assertEquals("[1920,2072,3264,1475,3941]", res39.toString());
+        Assert.assertEquals("[1820,1972,3164,1375,3841]", res40.toString());
+        Assert.assertEquals("[1920,2072,3264,1475,3941]", res41.toString());
+        // REMOVE_END
+
+
+        // STEP_START update_filters1
+        jedis.jsonSet("bikes:inventory", new Path2("$.inventory.*[?(@.price<2000)].price"), 1500);
+        Object res42 = jedis.jsonGet("bikes:inventory", new Path2("$..price"));
+        System.out.println(res42);  // >>> [1500,2072,3264,1500,3941]
+        // STEP_END
+
+        // Tests for 'update_filters1' step.
+        // REMOVE_START
+        Assert.assertEquals("[1500,2072,3264,1500,3941]", res42.toString());
+        // REMOVE_END
+
+
+        // STEP_START update_filters2
+        List res43 = jedis.jsonArrAppendWithEscape(
+            "bikes:inventory", new Path2("$.inventory.*[?(@.price<2000)].colors"),
+            "\"pink\""
+        );
+        System.out.println(res43);  // >>> [3, 3]
+
+        Object res44 = jedis.jsonGet("bikes:inventory", new Path2("$..[*].colors"));
+        System.out.println(res44);
+        // >>> [["black","silver","\"pink\""],["black","white"],["black","silver","\"pink\""]]
+        // STEP_END
+
+        // Tests for 'update_filters2' step.
+        // REMOVE_START
+        Assert.assertEquals("[3, 3]", res43.toString());
+        Assert.assertEquals(
+            "[[\"black\",\"silver\",\"\\\"pink\\\"\"],[\"black\",\"white\"],"
+            + "[\"black\",\"silver\",\"\\\"pink\\\"\"]]",
+            res44.toString());
+        // REMOVE_END
+
+// HIDE_START
+        jedis.close();
+    }
+}
+// HIDE_END
+

From fc603d261d542859936125348f67537b46e9dba0 Mon Sep 17 00:00:00 2001
From: Igor Malinovskiy 
Date: Wed, 17 Jul 2024 14:43:35 +0200
Subject: [PATCH 46/51] Add Scenario tests (#3847)

* Add POC DMC restart test

* Cleanup

* More tests

* Add missing files

* Clean up scenario tests

* Address review suggestions
---
 pom.xml                                       |   6 +
 .../redis/clients/jedis/EndpointConfig.java   |   6 +-
 .../scenario/ClusterTopologyRefreshTest.java  | 100 ++++++++++
 .../scenario/ConnectionInterruptionTest.java  | 182 ++++++++++++++++++
 .../redis/clients/jedis/scenario/FakeApp.java |  65 +++++++
 .../jedis/scenario/FaultInjectionClient.java  | 124 ++++++++++++
 .../jedis/scenario/RecommendedSettings.java   |  31 +++
 7 files changed, 513 insertions(+), 1 deletion(-)
 create mode 100644 src/test/java/redis/clients/jedis/scenario/ClusterTopologyRefreshTest.java
 create mode 100644 src/test/java/redis/clients/jedis/scenario/ConnectionInterruptionTest.java
 create mode 100644 src/test/java/redis/clients/jedis/scenario/FakeApp.java
 create mode 100644 src/test/java/redis/clients/jedis/scenario/FaultInjectionClient.java
 create mode 100644 src/test/java/redis/clients/jedis/scenario/RecommendedSettings.java

diff --git a/pom.xml b/pom.xml
index cee45b01e9d..fef8874ecd8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -133,6 +133,12 @@
 			2.38.0 
 			test
 		
+		
+			org.apache.httpcomponents.client5
+			httpclient5-fluent
+			5.3.1
+			test
+		
 
 		
 		
diff --git a/src/test/java/redis/clients/jedis/EndpointConfig.java b/src/test/java/redis/clients/jedis/EndpointConfig.java
index 5cb322224dd..42a44a3c47e 100644
--- a/src/test/java/redis/clients/jedis/EndpointConfig.java
+++ b/src/test/java/redis/clients/jedis/EndpointConfig.java
@@ -1,6 +1,8 @@
 package redis.clients.jedis;
 
+import com.google.gson.FieldNamingPolicy;
 import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
 import com.google.gson.reflect.TypeToken;
 import redis.clients.jedis.util.JedisURIHelper;
 
@@ -118,7 +120,9 @@ protected String getURISchema(boolean tls) {
     }
 
     public static HashMap loadFromJSON(String filePath) throws Exception {
-        Gson gson = new Gson();
+        Gson gson = new GsonBuilder().setFieldNamingPolicy(
+            FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
+
         HashMap configs;
         try (FileReader reader = new FileReader(filePath)) {
             configs = gson.fromJson(reader, new TypeToken>() {
diff --git a/src/test/java/redis/clients/jedis/scenario/ClusterTopologyRefreshTest.java b/src/test/java/redis/clients/jedis/scenario/ClusterTopologyRefreshTest.java
new file mode 100644
index 00000000000..e4fc9a8b0aa
--- /dev/null
+++ b/src/test/java/redis/clients/jedis/scenario/ClusterTopologyRefreshTest.java
@@ -0,0 +1,100 @@
+package redis.clients.jedis.scenario;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import redis.clients.jedis.*;
+import redis.clients.jedis.providers.ClusterConnectionProvider;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+public class ClusterTopologyRefreshTest {
+
+  private static final Logger log = LoggerFactory.getLogger(ClusterTopologyRefreshTest.class);
+
+  private static EndpointConfig endpoint;
+
+  private final FaultInjectionClient faultClient = new FaultInjectionClient();
+
+  @BeforeClass
+  public static void beforeClass() {
+    try {
+      ClusterTopologyRefreshTest.endpoint = HostAndPorts.getRedisEndpoint("re-single-shard-oss-cluster");
+    } catch (IllegalArgumentException e) {
+      log.warn("Skipping test because no Redis endpoint is configured");
+      org.junit.Assume.assumeTrue(false);
+    }
+  }
+
+  @Test
+  public void testWithPool() {
+    Set jedisClusterNode = new HashSet<>();
+    jedisClusterNode.add(endpoint.getHostAndPort());
+
+    JedisClientConfig config = endpoint.getClientConfigBuilder()
+        .socketTimeoutMillis(RecommendedSettings.DEFAULT_TIMEOUT_MS)
+        .connectionTimeoutMillis(RecommendedSettings.DEFAULT_TIMEOUT_MS).build();
+
+
+    ClusterConnectionProvider provider = new ClusterConnectionProvider(jedisClusterNode, config, RecommendedSettings.poolConfig);
+    ClusterConnectionProvider spyProvider = spy(provider);
+
+    try (JedisCluster client = new JedisCluster(spyProvider,
+        RecommendedSettings.MAX_RETRIES, RecommendedSettings.MAX_TOTAL_RETRIES_DURATION)) {
+      assertEquals("Was this BDB used to run this test before?", 1,
+          client.getClusterNodes().size());
+
+      AtomicLong commandsExecuted = new AtomicLong();
+
+      // Start thread that imitates an application that uses the client
+      FakeApp fakeApp = new FakeApp(client, (UnifiedJedis c) -> {
+        long i = commandsExecuted.getAndIncrement();
+        client.set(String.valueOf(i), String.valueOf(i));
+        return true;
+      });
+
+      Thread t = new Thread(fakeApp);
+      t.start();
+
+      HashMap params = new HashMap<>();
+      params.put("bdb_id", endpoint.getBdbId());
+      params.put("actions", "[\"reshard\",\"failover\"]");
+
+      FaultInjectionClient.TriggerActionResponse actionResponse = null;
+
+      try {
+        log.info("Triggering Resharding and Failover");
+        actionResponse = faultClient.triggerAction("sequence_of_actions", params);
+      } catch (IOException e) {
+        fail("Fault Injection Server error:" + e.getMessage());
+      }
+
+      log.info("Action id: {}", actionResponse.getActionId());
+      fakeApp.setAction(actionResponse);
+
+      try {
+        t.join();
+      } catch (InterruptedException e) {
+        throw new RuntimeException(e);
+      }
+
+      assertTrue(fakeApp.capturedExceptions().isEmpty());
+
+      log.info("Commands executed: {}", commandsExecuted.get());
+      for (long i = 0; i < commandsExecuted.get(); i++) {
+        assertTrue(client.exists(String.valueOf(i)));
+      }
+
+      verify(spyProvider, atLeast(2)).renewSlotCache(any(Connection.class));
+    }
+  }
+
+}
diff --git a/src/test/java/redis/clients/jedis/scenario/ConnectionInterruptionTest.java b/src/test/java/redis/clients/jedis/scenario/ConnectionInterruptionTest.java
new file mode 100644
index 00000000000..ee584931ca6
--- /dev/null
+++ b/src/test/java/redis/clients/jedis/scenario/ConnectionInterruptionTest.java
@@ -0,0 +1,182 @@
+package redis.clients.jedis.scenario;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import redis.clients.jedis.*;
+import redis.clients.jedis.exceptions.JedisConnectionException;
+import redis.clients.jedis.providers.ConnectionProvider;
+import redis.clients.jedis.providers.PooledConnectionProvider;
+import redis.clients.jedis.util.SafeEncoder;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static org.junit.Assert.*;
+
+@RunWith(Parameterized.class)
+public class ConnectionInterruptionTest {
+
+  private static final Logger log = LoggerFactory.getLogger(ConnectionInterruptionTest.class);
+
+  private static EndpointConfig endpoint;
+
+  private final FaultInjectionClient faultClient = new FaultInjectionClient();
+
+  @Parameterized.Parameters
+  public static Iterable data() {
+    return Arrays.asList("dmc_restart", "network_failure");
+  }
+
+  @Parameterized.Parameter
+  public String triggerAction;
+
+  @BeforeClass
+  public static void beforeClass() {
+    try {
+      ConnectionInterruptionTest.endpoint = HostAndPorts.getRedisEndpoint("re-standalone");
+    } catch (IllegalArgumentException e) {
+      log.warn("Skipping test because no Redis endpoint is configured");
+      org.junit.Assume.assumeTrue(false);
+    }
+  }
+
+  @Test
+  public void testWithPool() {
+    ConnectionProvider connectionProvider = new PooledConnectionProvider(endpoint.getHostAndPort(),
+        endpoint.getClientConfigBuilder().build(), RecommendedSettings.poolConfig);
+
+    UnifiedJedis client = new UnifiedJedis(connectionProvider, RecommendedSettings.MAX_RETRIES,
+        RecommendedSettings.MAX_TOTAL_RETRIES_DURATION);
+    String keyName = "counter";
+    client.set(keyName, "0");
+    assertEquals("0", client.get(keyName));
+
+    AtomicLong commandsExecuted = new AtomicLong();
+
+    // Start thread that imitates an application that uses the client
+    FakeApp fakeApp = new FakeApp(client, (UnifiedJedis c) -> {
+      assertTrue(client.incr(keyName) > 0);
+      long currentCount = commandsExecuted.getAndIncrement();
+      log.info("Command executed {}", currentCount);
+      return true;
+    });
+    fakeApp.setKeepExecutingForSeconds(RecommendedSettings.DEFAULT_TIMEOUT_MS/1000 * 2);
+    Thread t = new Thread(fakeApp);
+    t.start();
+
+    HashMap params = new HashMap<>();
+    params.put("bdb_id", endpoint.getBdbId());
+
+    FaultInjectionClient.TriggerActionResponse actionResponse = null;
+
+    try {
+      log.info("Triggering {}", triggerAction);
+      actionResponse = faultClient.triggerAction(triggerAction, params);
+    } catch (IOException e) {
+      fail("Fault Injection Server error:" + e.getMessage());
+    }
+
+    log.info("Action id: {}", actionResponse.getActionId());
+    fakeApp.setAction(actionResponse);
+
+    try {
+      t.join();
+    } catch (InterruptedException e) {
+      throw new RuntimeException(e);
+    }
+
+    log.info("Commands executed: {}", commandsExecuted.get());
+    assertEquals(commandsExecuted.get(), Long.parseLong(client.get(keyName)));
+    assertTrue(fakeApp.capturedExceptions().isEmpty());
+
+    client.close();
+  }
+
+  @Test
+  public void testWithPubSub() {
+    ConnectionProvider connectionProvider = new PooledConnectionProvider(endpoint.getHostAndPort(),
+        endpoint.getClientConfigBuilder().build(), RecommendedSettings.poolConfig);
+
+    UnifiedJedis client = new UnifiedJedis(connectionProvider, RecommendedSettings.MAX_RETRIES,
+        RecommendedSettings.MAX_TOTAL_RETRIES_DURATION);
+
+    AtomicLong messagesSent = new AtomicLong();
+    AtomicLong messagesReceived = new AtomicLong();
+
+    final Thread subscriberThread = getSubscriberThread(messagesReceived, connectionProvider);
+
+    // Start thread that imitates a publisher that uses the client
+    FakeApp fakeApp = new FakeApp(client, (UnifiedJedis c) -> {
+      log.info("Publishing message");
+      long consumed = client.publish("test", String.valueOf(messagesSent.getAndIncrement()));
+      return consumed > 0;
+    });
+    fakeApp.setKeepExecutingForSeconds(10);
+    Thread t = new Thread(fakeApp);
+    t.start();
+
+    HashMap params = new HashMap<>();
+    params.put("bdb_id", endpoint.getBdbId());
+
+    FaultInjectionClient.TriggerActionResponse actionResponse = null;
+
+    try {
+      log.info("Triggering {}", triggerAction);
+      actionResponse = faultClient.triggerAction(triggerAction, params);
+    } catch (IOException e) {
+      fail("Fault Injection Server error:" + e.getMessage());
+    }
+
+    log.info("Action id: {}", actionResponse.getActionId());
+    fakeApp.setAction(actionResponse);
+
+    try {
+      t.join();
+    } catch (InterruptedException e) {
+      throw new RuntimeException(e);
+    }
+
+    if (subscriberThread.isAlive())
+      subscriberThread.interrupt();
+
+    assertEquals(messagesSent.get() - 1, messagesReceived.get());
+    assertTrue(fakeApp.capturedExceptions().isEmpty());
+
+    client.close();
+  }
+
+  private static Thread getSubscriberThread(AtomicLong messagesReceived,
+      ConnectionProvider connectionProvider) {
+    final JedisPubSubBase pubSub = new JedisPubSubBase() {
+
+      @Override
+      public void onMessage(String channel, String message) {
+        messagesReceived.incrementAndGet();
+        log.info("Received message: {}", message);
+      }
+
+      @Override
+      protected String encode(byte[] raw) {
+        return SafeEncoder.encode(raw);
+      }
+    };
+
+    final Thread subscriberThread = new Thread(() -> {
+      try {
+        pubSub.proceed(connectionProvider.getConnection(), "test");
+        fail("PubSub should have been interrupted");
+      } catch (JedisConnectionException e) {
+        log.info("Expected exception in Subscriber: {}", e.getMessage());
+        assertTrue(e.getMessage().contains("Unexpected end of stream."));
+      }
+    });
+    subscriberThread.start();
+    return subscriberThread;
+  }
+}
diff --git a/src/test/java/redis/clients/jedis/scenario/FakeApp.java b/src/test/java/redis/clients/jedis/scenario/FakeApp.java
new file mode 100644
index 00000000000..7e505862a24
--- /dev/null
+++ b/src/test/java/redis/clients/jedis/scenario/FakeApp.java
@@ -0,0 +1,65 @@
+package redis.clients.jedis.scenario;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import redis.clients.jedis.UnifiedJedis;
+import redis.clients.jedis.exceptions.JedisConnectionException;
+import redis.clients.jedis.exceptions.JedisException;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+
+public class FakeApp implements Runnable {
+
+  private static final Logger log = LoggerFactory.getLogger(FakeApp.class);
+
+  public void setKeepExecutingForSeconds(int keepExecutingForSeconds) {
+    this.keepExecutingForSeconds = keepExecutingForSeconds;
+  }
+
+  private int keepExecutingForSeconds = 60;
+
+  private FaultInjectionClient.TriggerActionResponse actionResponse = null;
+  private final UnifiedJedis client;
+  private final ExecutedAction action;
+  private List exceptions = new ArrayList<>();
+
+  @FunctionalInterface
+  public interface ExecutedAction {
+    boolean run(UnifiedJedis client);
+  }
+
+  public FakeApp(UnifiedJedis client, ExecutedAction action) {
+    this.client = client;
+    this.action = action;
+  }
+
+  public void setAction(FaultInjectionClient.TriggerActionResponse actionResponse) {
+    this.actionResponse = actionResponse;
+  }
+
+  public List capturedExceptions() {
+    return exceptions;
+  }
+
+  public void run() {
+    log.info("Starting FakeApp");
+
+    int checkEachSeconds = 5;
+    int timeoutSeconds = 120;
+
+    while (actionResponse == null || !actionResponse.isCompleted(
+        Duration.ofSeconds(checkEachSeconds), Duration.ofSeconds(keepExecutingForSeconds),
+        Duration.ofSeconds(timeoutSeconds))) {
+      try {
+        boolean success = action.run(client);
+
+        if (!success) break;
+      } catch (JedisConnectionException e) {
+        log.error("Error executing action", e);
+        exceptions.add(e);
+      }
+    }
+  }
+}
diff --git a/src/test/java/redis/clients/jedis/scenario/FaultInjectionClient.java b/src/test/java/redis/clients/jedis/scenario/FaultInjectionClient.java
new file mode 100644
index 00000000000..c4e1c5717bb
--- /dev/null
+++ b/src/test/java/redis/clients/jedis/scenario/FaultInjectionClient.java
@@ -0,0 +1,124 @@
+package redis.clients.jedis.scenario;
+
+import java.io.IOException;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.concurrent.TimeUnit;
+
+import com.google.gson.FieldNamingPolicy;
+import com.google.gson.GsonBuilder;
+import com.google.gson.reflect.TypeToken;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.fluent.Request;
+import com.google.gson.Gson;
+import org.apache.hc.client5.http.fluent.Response;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
+import org.apache.hc.core5.http.ContentType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FaultInjectionClient {
+
+  private static final String BASE_URL;
+
+  static {
+    BASE_URL = System.getenv().getOrDefault("FAULT_INJECTION_API_URL", "http://127.0.0.1:20324");
+  }
+
+  private static final Logger log = LoggerFactory.getLogger(FaultInjectionClient.class);
+
+  public static class TriggerActionResponse {
+    private final String actionId;
+
+    private Instant lastRequestTime = null;
+
+    private Instant completedAt = null;
+
+    private Instant firstRequestAt = null;
+
+    public TriggerActionResponse(String actionId) {
+      this.actionId = actionId;
+    }
+
+    public String getActionId() {
+      return actionId;
+    }
+
+    public boolean isCompleted(Duration checkInterval, Duration delayAfter, Duration timeout) {
+      if (completedAt != null) {
+        return Duration.between(completedAt, Instant.now()).compareTo(delayAfter) >= 0;
+      }
+
+      if (firstRequestAt != null && Duration.between(firstRequestAt, Instant.now())
+          .compareTo(timeout) >= 0) {
+        throw new RuntimeException("Timeout");
+      }
+
+      if (lastRequestTime == null || Duration.between(lastRequestTime, Instant.now())
+          .compareTo(checkInterval) >= 0) {
+        lastRequestTime = Instant.now();
+
+        if (firstRequestAt == null) {
+          firstRequestAt = lastRequestTime;
+        }
+
+        CloseableHttpClient httpClient = getHttpClient();
+
+        Request request = Request.get(BASE_URL + "/action/" + actionId);
+
+        try {
+          Response response = request.execute(httpClient);
+          String result = response.returnContent().asString();
+
+          log.info("Action status: {}", result);
+
+          if (result.contains("success")) {
+            completedAt = Instant.now();
+            return Duration.between(completedAt, Instant.now()).compareTo(delayAfter) >= 0;
+          }
+
+        } catch (IOException e) {
+          throw new RuntimeException("Fault injection proxy error ", e);
+        }
+      }
+      return false;
+    }
+  }
+
+  private static CloseableHttpClient getHttpClient() {
+    RequestConfig requestConfig = RequestConfig.custom()
+        .setConnectionRequestTimeout(5000, TimeUnit.MILLISECONDS)
+        .setResponseTimeout(5000, TimeUnit.MILLISECONDS).build();
+
+    return HttpClientBuilder.create()
+        .setDefaultRequestConfig(requestConfig).build();
+  }
+
+  public TriggerActionResponse triggerAction(String actionType, HashMap parameters)
+      throws IOException {
+    Gson gson = new GsonBuilder().setFieldNamingPolicy(
+        FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
+
+    HashMap payload = new HashMap<>();
+    payload.put("type", actionType);
+    payload.put("parameters", parameters);
+
+    String jsonString = gson.toJson(payload);
+
+    CloseableHttpClient httpClient = getHttpClient();
+    Request request = Request.post(BASE_URL + "/action");
+    request.bodyString(jsonString, ContentType.APPLICATION_JSON);
+
+    try {
+      String result = request.execute(httpClient).returnContent().asString();
+      return gson.fromJson(result, new TypeToken() {
+      }.getType());
+    } catch (IOException e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+}
diff --git a/src/test/java/redis/clients/jedis/scenario/RecommendedSettings.java b/src/test/java/redis/clients/jedis/scenario/RecommendedSettings.java
new file mode 100644
index 00000000000..aa1671ad9e3
--- /dev/null
+++ b/src/test/java/redis/clients/jedis/scenario/RecommendedSettings.java
@@ -0,0 +1,31 @@
+package redis.clients.jedis.scenario;
+
+import redis.clients.jedis.ConnectionPoolConfig;
+
+import java.time.Duration;
+
+public class RecommendedSettings {
+
+  public static ConnectionPoolConfig poolConfig;
+
+  static {
+    poolConfig = new ConnectionPoolConfig();
+    ConnectionPoolConfig poolConfig = new ConnectionPoolConfig();
+    poolConfig.setMaxTotal(8);
+    poolConfig.setMaxIdle(8);
+    poolConfig.setMinIdle(0);
+    poolConfig.setBlockWhenExhausted(true);
+    poolConfig.setMaxWait(Duration.ofSeconds(1));
+    poolConfig.setTestWhileIdle(true);
+    poolConfig.setTimeBetweenEvictionRuns(Duration.ofSeconds(1));
+  }
+
+  public static int MAX_RETRIES = 5;
+
+  public static Duration MAX_TOTAL_RETRIES_DURATION = Duration.ofSeconds(10);
+
+  public static int DEFAULT_TIMEOUT_MS = 5000;
+
+
+
+}

From bd14f2096a823bc7daf706b78beeeacd63220c47 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 25 Jul 2024 12:33:23 +0600
Subject: [PATCH 47/51] Bump jackson.version from 2.17.1 to 2.17.2 (#3902)

Bumps `jackson.version` from 2.17.1 to 2.17.2.

Updates `com.fasterxml.jackson.core:jackson-databind` from 2.17.1 to 2.17.2
- [Commits](https://github.com/FasterXML/jackson/commits)

Updates `com.fasterxml.jackson.datatype:jackson-datatype-jsr310` from 2.17.1 to 2.17.2

---
updated-dependencies:
- dependency-name: com.fasterxml.jackson.core:jackson-databind
  dependency-type: direct:development
  update-type: version-update:semver-patch
- dependency-name: com.fasterxml.jackson.datatype:jackson-datatype-jsr310
  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 fef8874ecd8..6cfd4a2a2d7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -49,7 +49,7 @@
 		redis.clients.jedis
 		1.7.36
 		1.7.1
-		2.17.1
+		2.17.2
 		3.2.5
 	
 

From 51266d5197774af511e7dce9bf7a056613d8b359 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 25 Jul 2024 12:33:36 +0600
Subject: [PATCH 48/51] Bump com.kohlschutter.junixsocket:junixsocket-core from
 2.9.1 to 2.10.0 (#3901)

Bumps [com.kohlschutter.junixsocket:junixsocket-core](https://github.com/kohlschutter/junixsocket) from 2.9.1 to 2.10.0.
- [Release notes](https://github.com/kohlschutter/junixsocket/releases)
- [Commits](https://github.com/kohlschutter/junixsocket/compare/junixsocket-2.9.1...junixsocket-2.10.0)

---
updated-dependencies:
- dependency-name: com.kohlschutter.junixsocket:junixsocket-core
  dependency-type: direct:development
  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 6cfd4a2a2d7..a8fa81fdfc2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -79,7 +79,7 @@
 		
 			com.kohlschutter.junixsocket
 			junixsocket-core
-			2.9.1
+			2.10.0
 			pom
 			test
 		

From 0b04243fdfc8caeb767ac8340aa86b0cf8daff47 Mon Sep 17 00:00:00 2001
From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com>
Date: Fri, 26 Jul 2024 14:03:19 +0600
Subject: [PATCH 49/51] [TEMPORARY] [TEST] Disable FT.CONFIG tests (#3907)

Disable FT.CONFIG tests
---
 .../modules/RedisModulesPipelineTest.java      | 18 ++++++++++--------
 .../jedis/modules/search/SearchConfigTest.java |  4 ++++
 2 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/src/test/java/redis/clients/jedis/modules/RedisModulesPipelineTest.java b/src/test/java/redis/clients/jedis/modules/RedisModulesPipelineTest.java
index db0ba8223c1..4c9ad92f85b 100644
--- a/src/test/java/redis/clients/jedis/modules/RedisModulesPipelineTest.java
+++ b/src/test/java/redis/clients/jedis/modules/RedisModulesPipelineTest.java
@@ -66,10 +66,11 @@ public void search() {
     Response explain = p.ftExplain(index, new Query("@title:title_val"));
     Response> explainCLI = p.ftExplainCLI(index, new Query("@title:title_val"));
     Response> info = p.ftInfo(index);
-    Response configSet = p.ftConfigSet("timeout", "100");
-    Response> configGet = p.ftConfigGet("*");
-    Response configSetIndex = p.ftConfigSet(index, "timeout", "100");
-    Response> configGetIndex = p.ftConfigGet(index, "*");
+//    // @org.junit.Ignore
+//    Response configSet = p.ftConfigSet("timeout", "100");
+//    Response> configGet = p.ftConfigGet("*");
+//    Response configSetIndex = p.ftConfigSet(index, "timeout", "100");
+//    Response> configGetIndex = p.ftConfigGet(index, "*");
     Response synUpdate = p.ftSynUpdate(index, "foo", "bar");
     Response>> synDump = p.ftSynDump(index);
 
@@ -85,10 +86,11 @@ public void search() {
     assertNotNull(explain.get());
     assertNotNull(explainCLI.get().get(0));
     assertEquals(index, info.get().get("index_name"));
-    assertEquals("OK", configSet.get());
-    assertEquals("100", configGet.get().get("TIMEOUT"));
-    assertEquals("OK", configSetIndex.get());
-    assertEquals("100", configGetIndex.get().get("TIMEOUT"));
+//    // @org.junit.Ignore
+//    assertEquals("OK", configSet.get());
+//    assertEquals("100", configGet.get().get("TIMEOUT"));
+//    assertEquals("OK", configSetIndex.get());
+//    assertEquals("100", configGetIndex.get().get("TIMEOUT"));
     assertEquals("OK", synUpdate.get());
     Map> expected = new HashMap<>();
     expected.put("bar", Collections.singletonList("foo"));
diff --git a/src/test/java/redis/clients/jedis/modules/search/SearchConfigTest.java b/src/test/java/redis/clients/jedis/modules/search/SearchConfigTest.java
index 4e93303a4a9..2f14e58be95 100644
--- a/src/test/java/redis/clients/jedis/modules/search/SearchConfigTest.java
+++ b/src/test/java/redis/clients/jedis/modules/search/SearchConfigTest.java
@@ -6,6 +6,7 @@
 import java.util.Collections;
 import java.util.Map;
 import org.junit.BeforeClass;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -30,6 +31,7 @@ public SearchConfigTest(RedisProtocol protocol) {
     super(protocol);
   }
 
+  @Ignore
   @Test
   public void config() {
     Map map = client.ftConfigGet("TIMEOUT");
@@ -42,6 +44,7 @@ public void config() {
     }
   }
 
+  @Ignore
   @Test
   public void configOnTimeout() {
     // confirm default
@@ -57,6 +60,7 @@ public void configOnTimeout() {
     }
   }
 
+  @Ignore
   @Test
   public void dialectConfig() {
     // confirm default

From 7b121c4f35ce5d733f157030974c1ee70ee2b710 Mon Sep 17 00:00:00 2001
From: Igor Malinovskiy 
Date: Fri, 26 Jul 2024 14:09:25 +0200
Subject: [PATCH 50/51] Added support for ADDSCORES argument in FT.AGGREGATE
 (#3908)

---
 .../clients/jedis/search/SearchProtocol.java    |  2 +-
 .../jedis/search/aggr/AggregationBuilder.java   |  5 +++++
 .../jedis/modules/search/AggregationTest.java   | 17 +++++++++++++++++
 3 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/src/main/java/redis/clients/jedis/search/SearchProtocol.java b/src/main/java/redis/clients/jedis/search/SearchProtocol.java
index 64482f4fbb2..17f5df1349d 100644
--- a/src/main/java/redis/clients/jedis/search/SearchProtocol.java
+++ b/src/main/java/redis/clients/jedis/search/SearchProtocol.java
@@ -56,7 +56,7 @@ public enum SearchKeyword implements Rawable {
     LANGUAGE_FIELD, SCORE, SCORE_FIELD, SCORER, PARAMS, AS, DIALECT, SLOP, TIMEOUT, INORDER,
     EXPANDER, MAXTEXTFIELDS, SKIPINITIALSCAN, WITHSUFFIXTRIE, NOSTEM, NOINDEX, PHONETIC, WEIGHT,
     CASESENSITIVE, LOAD, APPLY, GROUPBY, MAXIDLE, WITHCURSOR, DISTANCE, TERMS, INCLUDE, EXCLUDE,
-    SEARCH, AGGREGATE, QUERY, LIMITED, COUNT, REDUCE, INDEXMISSING, INDEXEMPTY;
+    SEARCH, AGGREGATE, QUERY, LIMITED, COUNT, REDUCE, INDEXMISSING, INDEXEMPTY, ADDSCORES;
 
     private final byte[] raw;
 
diff --git a/src/main/java/redis/clients/jedis/search/aggr/AggregationBuilder.java b/src/main/java/redis/clients/jedis/search/aggr/AggregationBuilder.java
index 7c8b5473392..ec478b33671 100644
--- a/src/main/java/redis/clients/jedis/search/aggr/AggregationBuilder.java
+++ b/src/main/java/redis/clients/jedis/search/aggr/AggregationBuilder.java
@@ -170,6 +170,11 @@ public AggregationBuilder timeout(long timeout) {
     return this;
   }
 
+  public AggregationBuilder addScores() {
+    aggrArgs.add(SearchKeyword.ADDSCORES);
+    return this;
+  }
+
   public AggregationBuilder params(Map params) {
     aggrArgs.add(SearchKeyword.PARAMS);
     aggrArgs.add(params.size() << 1);
diff --git a/src/test/java/redis/clients/jedis/modules/search/AggregationTest.java b/src/test/java/redis/clients/jedis/modules/search/AggregationTest.java
index 98e811472ed..ad960209e30 100644
--- a/src/test/java/redis/clients/jedis/modules/search/AggregationTest.java
+++ b/src/test/java/redis/clients/jedis/modules/search/AggregationTest.java
@@ -200,6 +200,23 @@ public void testAggregationBuilderVerbatim() {
     assertEquals(0, res.getTotalResults());
   }
 
+  @Test
+  public void testAggregationBuilderAddScores() {
+    Schema sc = new Schema();
+    sc.addSortableTextField("name", 1.0);
+    sc.addSortableNumericField("age");
+    client.ftCreate(index, IndexOptions.defaultOptions(), sc);
+    addDocument(new Document("data1").set("name", "Adam").set("age", 33));
+    addDocument(new Document("data2").set("name", "Sara").set("age", 44));
+
+    AggregationBuilder r = new AggregationBuilder("sara").addScores()
+        .apply("@__score * 100", "normalized_score").dialect(3);
+
+    AggregationResult res = client.ftAggregate(index, r);
+    assertEquals(2, res.getRow(0).getLong("__score"));
+    assertEquals(200, res.getRow(0).getLong("normalized_score"));
+  }
+
   @Test
   public void testAggregationBuilderTimeout() {
     Schema sc = new Schema();

From e14b8995099d472cc96d395c608876290a213134 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 29 Jul 2024 10:44:02 +0600
Subject: [PATCH 51/51] Bump org.apache.maven.plugins:maven-jar-plugin from
 3.4.1 to 3.4.2 (#3910)

Bumps [org.apache.maven.plugins:maven-jar-plugin](https://github.com/apache/maven-jar-plugin) from 3.4.1 to 3.4.2.
- [Release notes](https://github.com/apache/maven-jar-plugin/releases)
- [Commits](https://github.com/apache/maven-jar-plugin/compare/maven-jar-plugin-3.4.1...maven-jar-plugin-3.4.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-jar-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 a8fa81fdfc2..181fc6db127 100644
--- a/pom.xml
+++ b/pom.xml
@@ -278,7 +278,7 @@
 			
 			
 				maven-jar-plugin
-				3.4.1
+				3.4.2
 				
 					
 						${project.build.outputDirectory}/META-INF/MANIFEST.MF