diff --git a/pom.xml b/pom.xml
index 507b76dd15..e98ea6a08d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.data
spring-data-redis
- 3.3.0-SNAPSHOT
+ 3.3.0-GH-2888-SNAPSHOT
Spring Data Redis
Spring Data module for Redis
diff --git a/src/main/antora/modules/ROOT/pages/redis/cluster.adoc b/src/main/antora/modules/ROOT/pages/redis/cluster.adoc
index 0ad017e144..6b35ae5d3f 100644
--- a/src/main/antora/modules/ROOT/pages/redis/cluster.adoc
+++ b/src/main/antora/modules/ROOT/pages/redis/cluster.adoc
@@ -129,3 +129,6 @@ clusterOps.shutdown(NODE_7379); <1>
<1> Shut down node at 7379 and cross fingers there is a replica in place that can take over.
====
+
+NOTE: Redis Cluster pipelining is currently only supported throug the Lettuce driver except for the following commands when using cross-slot keys: `rename`, `renameNX`, `sort`, `bLPop`, `bRPop`, `rPopLPush`, `bRPopLPush`, `info`, `sMove`, `sInter`, `sInterStore`, `sUnion`, `sUnionStore`, `sDiff`, `sDiffStore`.
+Same-slot keys are fully supported.
diff --git a/src/main/antora/modules/ROOT/pages/redis/pipelining.adoc b/src/main/antora/modules/ROOT/pages/redis/pipelining.adoc
index 8a4d70665a..7e5ddd0541 100644
--- a/src/main/antora/modules/ROOT/pages/redis/pipelining.adoc
+++ b/src/main/antora/modules/ROOT/pages/redis/pipelining.adoc
@@ -20,7 +20,9 @@ List results = stringRedisTemplate.executePipelined(
});
----
-The preceding example runs a bulk right pop of items from a queue in a pipeline. The `results` `List` contains all of the popped items. `RedisTemplate` uses its value, hash key, and hash value serializers to deserialize all results before returning, so the returned items in the preceding example are Strings. There are additional `executePipelined` methods that let you pass a custom serializer for pipelined results.
+The preceding example runs a bulk right pop of items from a queue in a pipeline.
+The `results` `List` contains all the popped items. `RedisTemplate` uses its value, hash key, and hash value serializers to deserialize all results before returning, so the returned items in the preceding example are Strings.
+There are additional `executePipelined` methods that let you pass a custom serializer for pipelined results.
Note that the value returned from the `RedisCallback` is required to be `null`, as this value is discarded in favor of returning the results of the pipelined commands.
@@ -35,3 +37,7 @@ factory.setPipeliningFlushPolicy(PipeliningFlushPolicy.buffered(3)); <1>
----
<1> Buffer locally and flush after every 3rd command.
====
+
+NOTE: Pipelining is limited to Redis Standalone.
+Redis Cluster is currently only supported through the Lettuce driver except for the following commands when using cross-slot keys: `rename`, `renameNX`, `sort`, `bLPop`, `bRPop`, `rPopLPush`, `bRPopLPush`, `info`, `sMove`, `sInter`, `sInterStore`, `sUnion`, `sUnionStore`, `sDiff`, `sDiffStore`.
+Same-slot keys are fully supported.
diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterKeyCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterKeyCommands.java
index dc4fbc54da..ae3d3b2e49 100644
--- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterKeyCommands.java
+++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterKeyCommands.java
@@ -18,11 +18,8 @@
import io.lettuce.core.KeyScanCursor;
import io.lettuce.core.ScanArgs;
-import java.util.Collection;
-import java.util.HashSet;
import java.util.List;
import java.util.Set;
-import java.util.concurrent.ThreadLocalRandom;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.redis.connection.ClusterSlotHashUtil;
@@ -50,47 +47,6 @@ class LettuceClusterKeyCommands extends LettuceKeyCommands {
this.connection = connection;
}
- @Override
- public byte[] randomKey() {
-
- List nodes = connection.clusterGetNodes();
- Set inspectedNodes = new HashSet<>(nodes.size());
-
- do {
-
- RedisClusterNode node = nodes.get(ThreadLocalRandom.current().nextInt(nodes.size()));
-
- while (inspectedNodes.contains(node)) {
- node = nodes.get(ThreadLocalRandom.current().nextInt(nodes.size()));
- }
- inspectedNodes.add(node);
- byte[] key = randomKey(node);
-
- if (key != null && key.length > 0) {
- return key;
- }
- } while (nodes.size() != inspectedNodes.size());
-
- return null;
- }
-
- @Override
- public Set keys(byte[] pattern) {
-
- Assert.notNull(pattern, "Pattern must not be null");
-
- Collection> keysPerNode = connection.getClusterCommandExecutor()
- .executeCommandOnAllNodes((LettuceClusterCommandCallback>) connection -> connection.keys(pattern))
- .resultsAsList();
-
- Set keys = new HashSet<>();
-
- for (List keySet : keysPerNode) {
- keys.addAll(keySet);
- }
- return keys;
- }
-
@Override
public void rename(byte[] oldKey, byte[] newKey) {
diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterServerCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterServerCommands.java
index bab772c478..6d2e66cda0 100644
--- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterServerCommands.java
+++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterServerCommands.java
@@ -18,7 +18,6 @@
import io.lettuce.core.api.sync.RedisServerCommands;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -34,7 +33,6 @@
import org.springframework.data.redis.connection.lettuce.LettuceClusterConnection.LettuceClusterCommandCallback;
import org.springframework.data.redis.core.types.RedisClientInfo;
import org.springframework.util.Assert;
-import org.springframework.util.CollectionUtils;
/**
* @author Mark Paluch
@@ -71,37 +69,11 @@ public void save(RedisClusterNode node) {
executeCommandOnSingleNode(RedisServerCommands::save, node);
}
- @Override
- public Long dbSize() {
-
- Collection dbSizes = executeCommandOnAllNodes(RedisServerCommands::dbsize).resultsAsList();
-
- if (CollectionUtils.isEmpty(dbSizes)) {
- return 0L;
- }
-
- Long size = 0L;
- for (Long value : dbSizes) {
- size += value;
- }
- return size;
- }
-
@Override
public Long dbSize(RedisClusterNode node) {
return executeCommandOnSingleNode(RedisServerCommands::dbsize, node).getValue();
}
- @Override
- public void flushDb() {
- executeCommandOnAllNodes(RedisServerCommands::flushdb);
- }
-
- @Override
- public void flushDb(FlushOption option) {
- executeCommandOnAllNodes(it -> it.flushdb(LettuceConverters.toFlushMode(option)));
- }
-
@Override
public void flushDb(RedisClusterNode node) {
executeCommandOnSingleNode(RedisServerCommands::flushdb, node);
@@ -112,16 +84,6 @@ public void flushDb(RedisClusterNode node, FlushOption option) {
executeCommandOnSingleNode(it -> it.flushdb(LettuceConverters.toFlushMode(option)), node);
}
- @Override
- public void flushAll() {
- executeCommandOnAllNodes(RedisServerCommands::flushall);
- }
-
- @Override
- public void flushAll(FlushOption option) {
- executeCommandOnAllNodes(it -> it.flushall(LettuceConverters.toFlushMode(option)));
- }
-
@Override
public void flushAll(RedisClusterNode node) {
executeCommandOnSingleNode(RedisServerCommands::flushall, node);
diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterStringCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterStringCommands.java
index c1be6421a5..4b6ae60f04 100644
--- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterStringCommands.java
+++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterStringCommands.java
@@ -15,11 +15,6 @@
*/
package org.springframework.data.redis.connection.lettuce;
-import java.util.Map;
-
-import org.springframework.data.redis.connection.ClusterSlotHashUtil;
-import org.springframework.util.Assert;
-
/**
* @author Christoph Strobl
* @author Mark Paluch
@@ -31,21 +26,4 @@ class LettuceClusterStringCommands extends LettuceStringCommands {
super(connection);
}
- @Override
- public Boolean mSetNX(Map tuples) {
-
- Assert.notNull(tuples, "Tuples must not be null");
-
- if (ClusterSlotHashUtil.isSameSlotForAllKeys(tuples.keySet().toArray(new byte[tuples.keySet().size()][]))) {
- return super.mSetNX(tuples);
- }
-
- boolean result = true;
- for (Map.Entry entry : tuples.entrySet()) {
- if (!setNX(entry.getKey(), entry.getValue()) && result) {
- result = false;
- }
- }
- return result;
- }
}
diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java
index 93f78151b3..c3ecbde730 100644
--- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java
+++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java
@@ -49,7 +49,9 @@
import java.util.List;
import java.util.Map;
import java.util.Queue;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
@@ -102,8 +104,8 @@
*/
public class LettuceConnection extends AbstractRedisConnection {
- private static final ExceptionTranslationStrategy EXCEPTION_TRANSLATION =
- new FallbackExceptionTranslationStrategy(LettuceExceptionConverter.INSTANCE);
+ private static final ExceptionTranslationStrategy EXCEPTION_TRANSLATION = new FallbackExceptionTranslationStrategy(
+ LettuceExceptionConverter.INSTANCE);
static final RedisCodec CODEC = ByteArrayCodec.INSTANCE;
@@ -189,8 +191,8 @@ public LettuceConnection(@Nullable StatefulRedisConnection share
/**
* Creates a new {@link LettuceConnection}.
*
- * @param sharedConnection A native connection that is shared with other {@link LettuceConnection}s.
- * Should not be used for transactions or blocking operations.
+ * @param sharedConnection A native connection that is shared with other {@link LettuceConnection}s. Should not be
+ * used for transactions or blocking operations.
* @param timeout The connection timeout (in milliseconds)
* @param client The {@link RedisClient} to use when making pub/sub connections.
* @param defaultDbIndex The db index to use along with {@link RedisClient} when establishing a dedicated connection.
@@ -209,8 +211,8 @@ public LettuceConnection(@Nullable StatefulRedisConnection share
/**
* Creates a new {@link LettuceConnection}.
*
- * @param sharedConnection A native connection that is shared with other {@link LettuceConnection}s.
- * Should not be used for transactions or blocking operations.
+ * @param sharedConnection A native connection that is shared with other {@link LettuceConnection}s. Should not be
+ * used for transactions or blocking operations.
* @param connectionProvider connection provider to obtain and release native connections.
* @param timeout The connection timeout (in milliseconds)
* @param defaultDbIndex The db index to use along with {@link RedisClient} when establishing a dedicated connection.
@@ -225,8 +227,8 @@ public LettuceConnection(@Nullable StatefulRedisConnection share
/**
* Creates a new {@link LettuceConnection}.
*
- * @param sharedConnection A native connection that is shared with other {@link LettuceConnection}s.
- * Should not be used for transactions or blocking operations.
+ * @param sharedConnection A native connection that is shared with other {@link LettuceConnection}s. Should not be
+ * used for transactions or blocking operations.
* @param connectionProvider connection provider to obtain and release native connections.
* @param timeout The connection timeout (in milliseconds)
* @param defaultDbIndex The db index to use along with {@link RedisClient} when establishing a dedicated connection.
@@ -453,24 +455,19 @@ private LettuceInvoker doInvoke(RedisClusterAsyncCommands connec
LettuceResult newLettuceResult(Future resultHolder, Converter converter) {
- return LettuceResultBuilder.forResponse(resultHolder)
- .mappedWith(converter)
- .convertPipelineAndTxResults(this.convertPipelineAndTxResults)
- .build();
+ return LettuceResultBuilder. forResponse(resultHolder).mappedWith(converter)
+ .convertPipelineAndTxResults(this.convertPipelineAndTxResults).build();
}
LettuceResult newLettuceResult(Future resultHolder, Converter converter,
Supplier defaultValue) {
- return LettuceResultBuilder.forResponse(resultHolder)
- .mappedWith(converter)
- .convertPipelineAndTxResults(this.convertPipelineAndTxResults)
- .defaultNullTo(defaultValue)
- .build();
+ return LettuceResultBuilder. forResponse(resultHolder).mappedWith(converter)
+ .convertPipelineAndTxResults(this.convertPipelineAndTxResults).defaultNullTo(defaultValue).build();
}
LettuceResult newLettuceStatusResult(Future resultHolder) {
- return LettuceResultBuilder.forResponse(resultHolder).buildStatusResult();
+ return LettuceResultBuilder. forResponse(resultHolder).buildStatusResult();
}
void pipeline(LettuceResult, ?> result) {
@@ -583,7 +580,7 @@ public List closePipeline() {
pipeliningFlushState = null;
isPipelined = false;
- List> futures = new ArrayList<>(ppline.size());
+ List> futures = new ArrayList<>(ppline.size());
for (LettuceResult, ?> result : ppline) {
futures.add(result.getResultHolder());
@@ -600,10 +597,24 @@ public List closePipeline() {
if (done) {
for (LettuceResult, ?> result : ppline) {
- if (result.getResultHolder().getOutput().hasError()) {
+ CompletableFuture> resultHolder = result.getResultHolder();
+ if (resultHolder.isCompletedExceptionally()) {
+
+ String message;
+ if (resultHolder instanceof io.lettuce.core.protocol.RedisCommand, ?, ?> rc) {
+ message = rc.getOutput().getError();
+ } else {
+ try {
+ resultHolder.get();
+ message = "";
+ } catch (InterruptedException ignore) {
+ message = "";
+ } catch (ExecutionException e) {
+ message = e.getCause().getMessage();
+ }
+ }
- Exception exception = new InvalidDataAccessApiUsageException(result.getResultHolder()
- .getOutput().getError());
+ Exception exception = new InvalidDataAccessApiUsageException(message);
// remember only the first error
if (problem == null) {
@@ -684,8 +695,8 @@ public List exec() {
LettuceTransactionResultConverter resultConverter = new LettuceTransactionResultConverter(
new LinkedList<>(txResults), exceptionConverter);
- pipeline(newLettuceResult(exec, source ->
- resultConverter.convert(LettuceConverters.transactionResultUnwrapper().convert(source))));
+ pipeline(newLettuceResult(exec,
+ source -> resultConverter.convert(LettuceConverters.transactionResultUnwrapper().convert(source))));
return null;
}
@@ -837,8 +848,7 @@ T failsafeReadScanValues(List> source, @SuppressWarnings("rawtypes") @Null
try {
return (T) (converter != null ? converter.convert(source) : source);
- } catch (IndexOutOfBoundsException ignore) {
- }
+ } catch (IndexOutOfBoundsException ignore) {}
return null;
}
diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceResult.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceResult.java
index 86cbd8c93f..4c0a825c85 100644
--- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceResult.java
+++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceResult.java
@@ -15,8 +15,7 @@
*/
package org.springframework.data.redis.connection.lettuce;
-import io.lettuce.core.protocol.RedisCommand;
-
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import java.util.function.Supplier;
@@ -34,7 +33,7 @@
* @since 2.1
*/
@SuppressWarnings("rawtypes")
-class LettuceResult extends FutureResult> {
+class LettuceResult extends FutureResult> {
private final boolean convertPipelineAndTxResults;
@@ -51,7 +50,7 @@ class LettuceResult extends FutureResult> {
LettuceResult(Future resultHolder, Supplier defaultReturnValue, boolean convertPipelineAndTxResults,
@Nullable Converter converter) {
- super((RedisCommand) resultHolder, converter, defaultReturnValue);
+ super((CompletableFuture) resultHolder, converter, defaultReturnValue);
this.convertPipelineAndTxResults = convertPipelineAndTxResults;
}
@@ -59,7 +58,7 @@ class LettuceResult extends FutureResult> {
@Override
@SuppressWarnings("unchecked")
public T get() {
- return (T) getResultHolder().getOutput().get();
+ return (T) getResultHolder().join();
}
@Override
diff --git a/src/test/java/org/springframework/data/redis/connection/ClusterTestVariables.java b/src/test/java/org/springframework/data/redis/connection/ClusterTestVariables.java
index 0ecd097bab..cb33e10de2 100644
--- a/src/test/java/org/springframework/data/redis/connection/ClusterTestVariables.java
+++ b/src/test/java/org/springframework/data/redis/connection/ClusterTestVariables.java
@@ -25,6 +25,7 @@ public abstract class ClusterTestVariables {
public static final String KEY_1 = "key1";
public static final String KEY_2 = "key2";
public static final String KEY_3 = "key3";
+ public static final String KEY_4 = "key4";
public static final String VALUE_1 = "value1";
public static final String VALUE_2 = "value2";
diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java
index 2fea39cc94..67c9b066ba 100644
--- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java
+++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java
@@ -83,6 +83,7 @@ public class LettuceClusterConnectionTests implements ClusterConnectionTests {
private static final byte[] KEY_1_BYTES = LettuceConverters.toBytes(KEY_1);
private static final byte[] KEY_2_BYTES = LettuceConverters.toBytes(KEY_2);
private static final byte[] KEY_3_BYTES = LettuceConverters.toBytes(KEY_3);
+ private static final byte[] KEY_4_BYTES = LettuceConverters.toBytes(KEY_4);
private static final byte[] SAME_SLOT_KEY_1_BYTES = LettuceConverters.toBytes(SAME_SLOT_KEY_1);
private static final byte[] SAME_SLOT_KEY_2_BYTES = LettuceConverters.toBytes(SAME_SLOT_KEY_2);
@@ -91,6 +92,7 @@ public class LettuceClusterConnectionTests implements ClusterConnectionTests {
private static final byte[] VALUE_1_BYTES = LettuceConverters.toBytes(VALUE_1);
private static final byte[] VALUE_2_BYTES = LettuceConverters.toBytes(VALUE_2);
private static final byte[] VALUE_3_BYTES = LettuceConverters.toBytes(VALUE_3);
+ private static final byte[] VALUE_4_BYTES = LettuceConverters.toBytes(VALUE_4);
private static final GeoLocation ARIGENTO = new GeoLocation<>("arigento", POINT_ARIGENTO);
private static final GeoLocation CATANIA = new GeoLocation<>("catania", POINT_CATANIA);
@@ -179,7 +181,34 @@ void shouldCreateClusterConnectionWithPooling() {
} finally {
factory.destroy();
}
+ }
+
+ @Test // GH-2888
+ void shouldPipelineAdvancedClusterApi() {
+
+ LettuceConnectionFactory factory = createConnectionFactory();
+
+ ConnectionVerifier.create(factory) //
+ .execute(connection -> {
+ connection.set(KEY_1_BYTES, VALUE_1_BYTES);
+ connection.set(KEY_2_BYTES, VALUE_2_BYTES);
+ connection.set(KEY_4_BYTES, VALUE_4_BYTES);
+
+ connection.openPipeline();
+ connection.keyCommands().randomKey();
+ connection.stringCommands().mGet(KEY_1_BYTES, KEY_2_BYTES);
+
+ List objects = connection.closePipeline();
+
+ assertThat(objects).hasSize(2);
+ assertThat(objects).element(0).isInstanceOf(byte[].class);
+ assertThat(objects).element(1).isInstanceOf(List.class);
+
+ List mget = (List) objects.get(1);
+ assertThat(mget).containsExactly(VALUE_1_BYTES, VALUE_2_BYTES);
+
+ }).verifyAndClose();
}
@Test // DATAREDIS-315
@@ -2821,13 +2850,13 @@ void bitFieldIncrByWithOverflowShouldWorkCorrectly() {
assertThat(clusterConnection.stringCommands().bitField(LettuceConverters.toBytes(KEY_1),
create().incr(unsigned(2)).valueAt(BitFieldSubCommands.Offset.offset(102L)).overflow(FAIL).by(1L)))
- .containsExactly(1L);
+ .containsExactly(1L);
assertThat(clusterConnection.stringCommands().bitField(LettuceConverters.toBytes(KEY_1),
create().incr(unsigned(2)).valueAt(BitFieldSubCommands.Offset.offset(102L)).overflow(FAIL).by(1L)))
- .containsExactly(2L);
+ .containsExactly(2L);
assertThat(clusterConnection.stringCommands().bitField(LettuceConverters.toBytes(KEY_1),
create().incr(unsigned(2)).valueAt(BitFieldSubCommands.Offset.offset(102L)).overflow(FAIL).by(1L)))
- .containsExactly(3L);
+ .containsExactly(3L);
assertThat(clusterConnection.stringCommands().bitField(LettuceConverters.toBytes(KEY_1),
create().incr(unsigned(2)).valueAt(BitFieldSubCommands.Offset.offset(102L)).overflow(FAIL).by(1L))).isNotNull();
}
@@ -2837,7 +2866,7 @@ void bitfieldShouldAllowMultipleSubcommands() {
assertThat(clusterConnection.stringCommands().bitField(LettuceConverters.toBytes(KEY_1),
create().incr(signed(5)).valueAt(BitFieldSubCommands.Offset.offset(100L)).by(1L).get(unsigned(4)).valueAt(0L)))
- .containsExactly(1L, 0L);
+ .containsExactly(1L, 0L);
}
@Test // DATAREDIS-562
@@ -2847,13 +2876,13 @@ void bitfieldShouldWorkUsingNonZeroBasedOffset() {
clusterConnection.stringCommands().bitField(LettuceConverters.toBytes(KEY_1),
create().set(INT_8).valueAt(BitFieldSubCommands.Offset.offset(0L).multipliedByTypeLength()).to(100L)
.set(INT_8).valueAt(BitFieldSubCommands.Offset.offset(1L).multipliedByTypeLength()).to(200L)))
- .containsExactly(0L, 0L);
+ .containsExactly(0L, 0L);
assertThat(
clusterConnection.stringCommands()
.bitField(LettuceConverters.toBytes(KEY_1),
create().get(INT_8).valueAt(BitFieldSubCommands.Offset.offset(0L).multipliedByTypeLength()).get(INT_8)
- .valueAt(BitFieldSubCommands.Offset.offset(1L).multipliedByTypeLength()))).containsExactly(100L,
- -56L);
+ .valueAt(BitFieldSubCommands.Offset.offset(1L).multipliedByTypeLength())))
+ .containsExactly(100L, -56L);
}
@Test // DATAREDIS-1103
@@ -2864,7 +2893,7 @@ void setKeepTTL() {
assertThat(
clusterConnection.stringCommands().set(KEY_1_BYTES, VALUE_2_BYTES, Expiration.keepTtl(), SetOption.upsert()))
- .isTrue();
+ .isTrue();
assertThat(nativeConnection.ttl(KEY_1)).isCloseTo(expireSeconds, Offset.offset(5L));
assertThat(nativeConnection.get(KEY_1)).isEqualTo(VALUE_2);
diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionUnitTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionUnitTests.java
index 8f1803d17d..25fd46d783 100644
--- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionUnitTests.java
+++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionUnitTests.java
@@ -18,7 +18,6 @@
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import static org.springframework.data.redis.connection.ClusterTestVariables.*;
-import static org.springframework.data.redis.test.util.MockitoUtils.*;
import io.lettuce.core.RedisFuture;
import io.lettuce.core.RedisURI;
@@ -46,6 +45,7 @@
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
+
import org.springframework.data.redis.connection.ClusterCommandExecutor;
import org.springframework.data.redis.connection.ClusterNodeResourceProvider;
import org.springframework.data.redis.connection.ClusterTopologyProvider;
@@ -193,22 +193,6 @@ void isClosedShouldReturnConnectionStateCorrectly() {
assertThat(connection.isClosed()).isTrue();
}
- @Test // DATAREDIS-315
- void keysShouldBeRunOnAllClusterNodes() {
-
- when(clusterConnection1Mock.keys(any(byte[].class))).thenReturn(Collections. emptyList());
- when(clusterConnection2Mock.keys(any(byte[].class))).thenReturn(Collections. emptyList());
- when(clusterConnection3Mock.keys(any(byte[].class))).thenReturn(Collections. emptyList());
-
- byte[] pattern = LettuceConverters.toBytes("*");
-
- connection.keys(pattern);
-
- verify(clusterConnection1Mock, times(1)).keys(pattern);
- verify(clusterConnection2Mock, times(1)).keys(pattern);
- verify(clusterConnection3Mock, times(1)).keys(pattern);
- }
-
@Test // DATAREDIS-315
void keysShouldOnlyBeRunOnDedicatedNodeWhenPinned() {
@@ -223,38 +207,6 @@ void keysShouldOnlyBeRunOnDedicatedNodeWhenPinned() {
verify(clusterConnection3Mock, never()).keys(pattern);
}
- @Test // DATAREDIS-315
- void randomKeyShouldReturnAnyKeyFromRandomNode() {
-
- when(clusterConnection1Mock.randomkey()).thenReturn(KEY_1_BYTES);
- when(clusterConnection2Mock.randomkey()).thenReturn(KEY_2_BYTES);
- when(clusterConnection3Mock.randomkey()).thenReturn(KEY_3_BYTES);
-
- assertThat(connection.randomKey()).isIn(KEY_1_BYTES, KEY_2_BYTES, KEY_3_BYTES);
- verifyInvocationsAcross("randomkey", times(1), clusterConnection1Mock, clusterConnection2Mock,
- clusterConnection3Mock);
- }
-
- @Test // DATAREDIS-315
- void randomKeyShouldReturnKeyWhenAvailableOnAnyNode() {
-
- when(clusterConnection3Mock.randomkey()).thenReturn(KEY_3_BYTES);
-
- for (int i = 0; i < 100; i++) {
- assertThat(connection.randomKey()).isEqualTo(KEY_3_BYTES);
- }
- }
-
- @Test // DATAREDIS-315
- void randomKeyShouldReturnNullWhenNoKeysPresentOnAllNodes() {
-
- when(clusterConnection1Mock.randomkey()).thenReturn(null);
- when(clusterConnection2Mock.randomkey()).thenReturn(null);
- when(clusterConnection3Mock.randomkey()).thenReturn(null);
-
- assertThat(connection.randomKey()).isNull();
- }
-
@Test // DATAREDIS-315
void clusterSetSlotImportingShouldBeExecutedCorrectly() {
diff --git a/src/test/java/org/springframework/data/redis/core/RedisTemplateIntegrationTests.java b/src/test/java/org/springframework/data/redis/core/RedisTemplateIntegrationTests.java
index 93fc2fff45..bbc18c6f0e 100644
--- a/src/test/java/org/springframework/data/redis/core/RedisTemplateIntegrationTests.java
+++ b/src/test/java/org/springframework/data/redis/core/RedisTemplateIntegrationTests.java
@@ -361,8 +361,7 @@ public Object execute(RedisOperations operations) throws DataAccessException {
try {
// Await EXEC completion as it's executed on a dedicated connection.
Thread.sleep(100);
- } catch (InterruptedException ignore) {
- }
+ } catch (InterruptedException ignore) {}
operations.opsForValue().set(key1, value1);
operations.opsForValue().get(key1);
@@ -673,7 +672,16 @@ void testRandomKey() {
K key1 = keyFactory.instance();
V value1 = valueFactory.instance();
redisTemplate.opsForValue().set(key1, value1);
- assertThat(redisTemplate.randomKey()).isEqualTo(key1);
+
+ for (int i = 0; i < 20; i++) {
+
+ K k = redisTemplate.randomKey();
+ if (k == null) {
+ continue;
+ }
+
+ assertThat(k).isEqualTo(key1);
+ }
}
@ParameterizedRedisTest
@@ -723,8 +731,7 @@ public List execute(RedisOperations operations) throws DataAccessExcepti
th.start();
try {
th.join();
- } catch (InterruptedException ignore) {
- }
+ } catch (InterruptedException ignore) {}
operations.multi();
operations.opsForValue().set(key1, value3);
@@ -756,8 +763,7 @@ public List execute(RedisOperations operations) throws DataAccessExcepti
th.start();
try {
th.join();
- } catch (InterruptedException ignore) {
- }
+ } catch (InterruptedException ignore) {}
operations.unwatch();
operations.multi();
@@ -794,8 +800,7 @@ public List execute(RedisOperations operations) throws DataAccessExcepti
th.start();
try {
th.join();
- } catch (InterruptedException ignore) {
- }
+ } catch (InterruptedException ignore) {}
operations.multi();
operations.opsForValue().set(key1, value3);