From 57b24c5be38d26fe4fb7a152b28e618e20bfcff8 Mon Sep 17 00:00:00 2001 From: bono007 Date: Sun, 11 Jul 2021 23:30:46 -0500 Subject: [PATCH 1/4] Add convenience factory method to convert RedisURI to RedisConfiguration Fixes gh-2116 --- .../lettuce/LettuceConnectionFactory.java | 71 ++++++++-- .../connection/lettuce/LettuceConverters.java | 121 +++++++++++++++++- 2 files changed, 173 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java index e04f45bac7..349ff4f227 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java @@ -15,7 +15,16 @@ */ package org.springframework.data.redis.connection.lettuce; -import static org.springframework.data.redis.connection.lettuce.LettuceConnection.*; +import java.nio.ByteBuffer; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import java.util.stream.Collectors; import io.lettuce.core.AbstractRedisClient; import io.lettuce.core.ClientOptions; @@ -30,18 +39,6 @@ import io.lettuce.core.cluster.api.StatefulRedisClusterConnection; import io.lettuce.core.codec.RedisCodec; import io.lettuce.core.resource.ClientResources; - -import java.nio.ByteBuffer; -import java.time.Duration; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.TimeUnit; -import java.util.function.Consumer; -import java.util.stream.Collectors; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -52,17 +49,37 @@ import org.springframework.data.redis.ExceptionTranslationStrategy; import org.springframework.data.redis.PassThroughExceptionTranslationStrategy; import org.springframework.data.redis.RedisConnectionFailureException; -import org.springframework.data.redis.connection.*; +import org.springframework.data.redis.connection.ClusterCommandExecutor; +import org.springframework.data.redis.connection.ClusterTopologyProvider; +import org.springframework.data.redis.connection.Pool; +import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory; +import org.springframework.data.redis.connection.RedisClusterConfiguration; +import org.springframework.data.redis.connection.RedisClusterConnection; +import org.springframework.data.redis.connection.RedisConfiguration; import org.springframework.data.redis.connection.RedisConfiguration.ClusterConfiguration; import org.springframework.data.redis.connection.RedisConfiguration.DomainSocketConfiguration; import org.springframework.data.redis.connection.RedisConfiguration.WithDatabaseIndex; import org.springframework.data.redis.connection.RedisConfiguration.WithPassword; +import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.RedisNode; +import org.springframework.data.redis.connection.RedisPassword; +import org.springframework.data.redis.connection.RedisSentinelConfiguration; +import org.springframework.data.redis.connection.RedisSentinelConnection; +import org.springframework.data.redis.connection.RedisSocketConfiguration; +import org.springframework.data.redis.connection.RedisStandaloneConfiguration; +import org.springframework.data.redis.connection.RedisStaticMasterReplicaConfiguration; import org.springframework.data.util.Optionals; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; +import static org.springframework.data.redis.connection.lettuce.LettuceConnection.CODEC; +import static org.springframework.data.redis.connection.lettuce.LettuceConnection.LettucePoolConnectionProvider; +import static org.springframework.data.redis.connection.lettuce.LettuceConnection.PipeliningFlushPolicy; + /** * Connection factory creating Lettuce-based connections. *

@@ -279,6 +296,32 @@ public LettuceConnectionFactory(RedisClusterConfiguration clusterConfiguration, this.configuration = clusterConfiguration; } + /** + * Converts a {@link RedisURI} into its corresponding {@link RedisConfiguration} according to the following: + *

+ * + * @param redisURI the connection info in the format of a RedisURI + * @return an appropriate {@link RedisConfiguration} instance representing the Redis URI. + */ + public static RedisConfiguration redisConfigurationFromRedisUri(RedisURI redisURI) { + + Assert.notNull(redisURI, "RedisURI must not be null"); + + if (!ObjectUtils.isEmpty(redisURI.getSentinels())) { + return LettuceConverters.redisUriToSentinelConfiguration(redisURI); + } + + if (!ObjectUtils.isEmpty(redisURI.getSocket())) { + return LettuceConverters.redisUriToSocketConfiguration(redisURI); + } + + return LettuceConverters.redisUriToStandaloneConfiguration(redisURI); + } + /* * (non-Javadoc) * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java index 811893d7c6..72fe3fb06a 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java @@ -15,16 +15,43 @@ */ package org.springframework.data.redis.connection.lettuce; -import io.lettuce.core.*; -import io.lettuce.core.cluster.models.partitions.Partitions; -import io.lettuce.core.cluster.models.partitions.RedisClusterNode.NodeFlag; - import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import io.lettuce.core.BitFieldArgs; +import io.lettuce.core.GeoArgs; +import io.lettuce.core.GeoCoordinates; +import io.lettuce.core.GeoWithin; +import io.lettuce.core.GetExArgs; +import io.lettuce.core.KeyScanArgs; +import io.lettuce.core.KeyValue; +import io.lettuce.core.LMoveArgs; +import io.lettuce.core.Limit; +import io.lettuce.core.Range; +import io.lettuce.core.RedisURI; +import io.lettuce.core.ScanArgs; +import io.lettuce.core.ScoredValue; +import io.lettuce.core.ScriptOutputType; +import io.lettuce.core.SetArgs; +import io.lettuce.core.SortArgs; +import io.lettuce.core.TransactionResult; +import io.lettuce.core.cluster.models.partitions.Partitions; +import io.lettuce.core.cluster.models.partitions.RedisClusterNode.NodeFlag; + import org.springframework.core.convert.converter.Converter; import org.springframework.dao.DataAccessException; import org.springframework.data.geo.Distance; @@ -44,6 +71,7 @@ import org.springframework.data.redis.connection.RedisClusterNode.Flag; import org.springframework.data.redis.connection.RedisClusterNode.LinkState; import org.springframework.data.redis.connection.RedisClusterNode.SlotRange; +import org.springframework.data.redis.connection.RedisConfiguration; import org.springframework.data.redis.connection.RedisGeoCommands.DistanceUnit; import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation; import org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs; @@ -54,6 +82,8 @@ import org.springframework.data.redis.connection.RedisPassword; import org.springframework.data.redis.connection.RedisSentinelConfiguration; import org.springframework.data.redis.connection.RedisServer; +import org.springframework.data.redis.connection.RedisSocketConfiguration; +import org.springframework.data.redis.connection.RedisStandaloneConfiguration; import org.springframework.data.redis.connection.RedisStringCommands.SetOption; import org.springframework.data.redis.connection.RedisZSetCommands; import org.springframework.data.redis.connection.RedisZSetCommands.Range.Boundary; @@ -85,6 +115,7 @@ * @author Mark Paluch * @author Ninad Divadkar * @author dengliming + * @author Chris Bono */ public abstract class LettuceConverters extends Converters { @@ -535,6 +566,86 @@ public static RedisURI sentinelConfigurationToRedisURI(RedisSentinelConfiguratio return builder.build(); } + /** + * Converts a {@link RedisURI} to its corresponding {@link RedisSentinelConfiguration}. + * + * @param redisURI the uri containing the Redis Sentinel connection info + * @return a {@link RedisSentinelConfiguration} representing the Redis Sentinel information in the Redis URI. + * @since 2.6 + */ + public static RedisSentinelConfiguration redisUriToSentinelConfiguration(RedisURI redisURI) { + + Assert.notNull(redisURI, "RedisURI is required"); + Assert.hasText(redisURI.getSentinelMasterId(), "RedisURI must have sentinelMasterId param set"); + + RedisSentinelConfiguration sentinelConfiguration = new RedisSentinelConfiguration(); + sentinelConfiguration.setMaster(redisURI.getSentinelMasterId()); + sentinelConfiguration.setDatabase(redisURI.getDatabase()); + + for (RedisURI sentinelNodeRedisUri : redisURI.getSentinels()) { + RedisNode sentinelNode = new RedisNode(sentinelNodeRedisUri.getHost(), sentinelNodeRedisUri.getPort()); + if (sentinelNodeRedisUri.getPassword() != null) { + sentinelConfiguration.setSentinelPassword(sentinelNodeRedisUri.getPassword()); + } + sentinelConfiguration.addSentinel(sentinelNode); + } + + applyAuthentication(redisURI, sentinelConfiguration); + + return sentinelConfiguration; + } + + /** + * Converts a {@link RedisURI} to its corresponding {@link RedisSocketConfiguration}. + * + * @param redisURI the uri containing the Redis connection info using a local unix domain socket + * @return a {@link RedisSocketConfiguration} representing the connection information in the Redis URI. + * @since 2.6 + */ + public static RedisSocketConfiguration redisUriToSocketConfiguration(RedisURI redisURI) { + + Assert.notNull(redisURI, "RedisURI is required"); + Assert.hasText(redisURI.getSocket(), "RedisURI must have socket path set"); + + RedisSocketConfiguration socketConfiguration = new RedisSocketConfiguration(); + socketConfiguration.setSocket(redisURI.getSocket()); + socketConfiguration.setDatabase(redisURI.getDatabase()); + + applyAuthentication(redisURI, socketConfiguration); + + return socketConfiguration; + } + + /** + * Converts a {@link RedisURI} to its corresponding {@link RedisStandaloneConfiguration}. + * + * @param redisURI the uri containing the Redis connection info + * @return a {@link RedisStandaloneConfiguration} representing the connection information in the Redis URI. + * @since 2.6 + */ + public static RedisStandaloneConfiguration redisUriToStandaloneConfiguration(RedisURI redisURI) { + + Assert.notNull(redisURI, "RedisURI is required"); + + RedisStandaloneConfiguration standaloneConfiguration = new RedisStandaloneConfiguration(); + standaloneConfiguration.setHostName(redisURI.getHost()); + standaloneConfiguration.setPort(redisURI.getPort()); + standaloneConfiguration.setDatabase(redisURI.getDatabase()); + + applyAuthentication(redisURI, standaloneConfiguration); + + return standaloneConfiguration; + } + + private static void applyAuthentication(RedisURI redisURI, RedisConfiguration.WithAuthentication redisConfiguration) { + if (StringUtils.hasText(redisURI.getUsername())) { + redisConfiguration.setUsername(redisURI.getUsername()); + } + if (redisURI.getPassword() != null) { + redisConfiguration.setPassword(redisURI.getPassword()); + } + } + public static byte[] toBytes(@Nullable String source) { if (source == null) { return null; From a81b49a96b7e11bc139cebab09b804e5d476284e Mon Sep 17 00:00:00 2001 From: bono007 Date: Sun, 11 Jul 2021 23:37:45 -0500 Subject: [PATCH 2/4] Added author to LettuceConnectionFactory --- .../data/redis/connection/lettuce/LettuceConnectionFactory.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java index 349ff4f227..0e319c64fa 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java @@ -114,6 +114,7 @@ * @author Ruben Cervilla * @author Luis De Bello * @author Andrea Como + * @author Chris Bono */ public class LettuceConnectionFactory implements InitializingBean, DisposableBean, RedisConnectionFactory, ReactiveRedisConnectionFactory { From 59eeb788921b3c75398c2f05848da7b41772cba0 Mon Sep 17 00:00:00 2001 From: bono007 Date: Mon, 12 Jul 2021 08:26:11 -0500 Subject: [PATCH 3/4] Updates from code review - fix formatting - package protect new methods - rename factory method --- .../lettuce/LettuceConnectionFactory.java | 48 ++++++---------- .../connection/lettuce/LettuceConverters.java | 57 +++---------------- 2 files changed, 25 insertions(+), 80 deletions(-) diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java index 0e319c64fa..9eca99886f 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java @@ -15,16 +15,7 @@ */ package org.springframework.data.redis.connection.lettuce; -import java.nio.ByteBuffer; -import java.time.Duration; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.TimeUnit; -import java.util.function.Consumer; -import java.util.stream.Collectors; +import static org.springframework.data.redis.connection.lettuce.LettuceConnection.*; import io.lettuce.core.AbstractRedisClient; import io.lettuce.core.ClientOptions; @@ -39,6 +30,18 @@ import io.lettuce.core.cluster.api.StatefulRedisClusterConnection; import io.lettuce.core.codec.RedisCodec; import io.lettuce.core.resource.ClientResources; + +import java.nio.ByteBuffer; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import java.util.stream.Collectors; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -49,26 +52,11 @@ import org.springframework.data.redis.ExceptionTranslationStrategy; import org.springframework.data.redis.PassThroughExceptionTranslationStrategy; import org.springframework.data.redis.RedisConnectionFailureException; -import org.springframework.data.redis.connection.ClusterCommandExecutor; -import org.springframework.data.redis.connection.ClusterTopologyProvider; -import org.springframework.data.redis.connection.Pool; -import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory; -import org.springframework.data.redis.connection.RedisClusterConfiguration; -import org.springframework.data.redis.connection.RedisClusterConnection; -import org.springframework.data.redis.connection.RedisConfiguration; +import org.springframework.data.redis.connection.*; import org.springframework.data.redis.connection.RedisConfiguration.ClusterConfiguration; import org.springframework.data.redis.connection.RedisConfiguration.DomainSocketConfiguration; import org.springframework.data.redis.connection.RedisConfiguration.WithDatabaseIndex; import org.springframework.data.redis.connection.RedisConfiguration.WithPassword; -import org.springframework.data.redis.connection.RedisConnection; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.connection.RedisNode; -import org.springframework.data.redis.connection.RedisPassword; -import org.springframework.data.redis.connection.RedisSentinelConfiguration; -import org.springframework.data.redis.connection.RedisSentinelConnection; -import org.springframework.data.redis.connection.RedisSocketConfiguration; -import org.springframework.data.redis.connection.RedisStandaloneConfiguration; -import org.springframework.data.redis.connection.RedisStaticMasterReplicaConfiguration; import org.springframework.data.util.Optionals; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -76,10 +64,6 @@ import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; -import static org.springframework.data.redis.connection.lettuce.LettuceConnection.CODEC; -import static org.springframework.data.redis.connection.lettuce.LettuceConnection.LettucePoolConnectionProvider; -import static org.springframework.data.redis.connection.lettuce.LettuceConnection.PipeliningFlushPolicy; - /** * Connection factory creating Lettuce-based connections. *

@@ -298,7 +282,7 @@ public LettuceConnectionFactory(RedisClusterConfiguration clusterConfiguration, } /** - * Converts a {@link RedisURI} into its corresponding {@link RedisConfiguration} according to the following: + * Creates a {@link RedisConfiguration} based on a {@link RedisURI} according to the following: *

    *
  • If {@code redisURI} has sentinel info a {@link RedisSentinelConfiguration} is returned
  • *
  • If {@code redisURI} has socket info a {@link RedisSocketConfiguration} is returned
  • @@ -308,7 +292,7 @@ public LettuceConnectionFactory(RedisClusterConfiguration clusterConfiguration, * @param redisURI the connection info in the format of a RedisURI * @return an appropriate {@link RedisConfiguration} instance representing the Redis URI. */ - public static RedisConfiguration redisConfigurationFromRedisUri(RedisURI redisURI) { + public static RedisConfiguration createRedisConfiguration(RedisURI redisURI) { Assert.notNull(redisURI, "RedisURI must not be null"); diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java index 72fe3fb06a..7a10de24b1 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java @@ -15,43 +15,16 @@ */ package org.springframework.data.redis.connection.lettuce; +import io.lettuce.core.*; +import io.lettuce.core.cluster.models.partitions.Partitions; +import io.lettuce.core.cluster.models.partitions.RedisClusterNode.NodeFlag; + import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; +import java.util.*; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import io.lettuce.core.BitFieldArgs; -import io.lettuce.core.GeoArgs; -import io.lettuce.core.GeoCoordinates; -import io.lettuce.core.GeoWithin; -import io.lettuce.core.GetExArgs; -import io.lettuce.core.KeyScanArgs; -import io.lettuce.core.KeyValue; -import io.lettuce.core.LMoveArgs; -import io.lettuce.core.Limit; -import io.lettuce.core.Range; -import io.lettuce.core.RedisURI; -import io.lettuce.core.ScanArgs; -import io.lettuce.core.ScoredValue; -import io.lettuce.core.ScriptOutputType; -import io.lettuce.core.SetArgs; -import io.lettuce.core.SortArgs; -import io.lettuce.core.TransactionResult; -import io.lettuce.core.cluster.models.partitions.Partitions; -import io.lettuce.core.cluster.models.partitions.RedisClusterNode.NodeFlag; - import org.springframework.core.convert.converter.Converter; import org.springframework.dao.DataAccessException; import org.springframework.data.geo.Distance; @@ -60,36 +33,24 @@ import org.springframework.data.geo.Metric; import org.springframework.data.geo.Metrics; import org.springframework.data.geo.Point; -import org.springframework.data.redis.connection.BitFieldSubCommands; +import org.springframework.data.redis.connection.*; import org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldGet; import org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldIncrBy; import org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldIncrBy.Overflow; import org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldSet; import org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldSubCommand; -import org.springframework.data.redis.connection.DefaultTuple; -import org.springframework.data.redis.connection.RedisClusterNode; import org.springframework.data.redis.connection.RedisClusterNode.Flag; import org.springframework.data.redis.connection.RedisClusterNode.LinkState; import org.springframework.data.redis.connection.RedisClusterNode.SlotRange; -import org.springframework.data.redis.connection.RedisConfiguration; import org.springframework.data.redis.connection.RedisGeoCommands.DistanceUnit; import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation; import org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs; import org.springframework.data.redis.connection.RedisListCommands.Direction; import org.springframework.data.redis.connection.RedisListCommands.Position; -import org.springframework.data.redis.connection.RedisNode; import org.springframework.data.redis.connection.RedisNode.NodeType; -import org.springframework.data.redis.connection.RedisPassword; -import org.springframework.data.redis.connection.RedisSentinelConfiguration; -import org.springframework.data.redis.connection.RedisServer; -import org.springframework.data.redis.connection.RedisSocketConfiguration; -import org.springframework.data.redis.connection.RedisStandaloneConfiguration; import org.springframework.data.redis.connection.RedisStringCommands.SetOption; -import org.springframework.data.redis.connection.RedisZSetCommands; import org.springframework.data.redis.connection.RedisZSetCommands.Range.Boundary; import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; -import org.springframework.data.redis.connection.ReturnType; -import org.springframework.data.redis.connection.SortParameters; import org.springframework.data.redis.connection.SortParameters.Order; import org.springframework.data.redis.connection.convert.Converters; import org.springframework.data.redis.connection.convert.ListConverter; @@ -573,7 +534,7 @@ public static RedisURI sentinelConfigurationToRedisURI(RedisSentinelConfiguratio * @return a {@link RedisSentinelConfiguration} representing the Redis Sentinel information in the Redis URI. * @since 2.6 */ - public static RedisSentinelConfiguration redisUriToSentinelConfiguration(RedisURI redisURI) { + static RedisSentinelConfiguration redisUriToSentinelConfiguration(RedisURI redisURI) { Assert.notNull(redisURI, "RedisURI is required"); Assert.hasText(redisURI.getSentinelMasterId(), "RedisURI must have sentinelMasterId param set"); @@ -602,7 +563,7 @@ public static RedisSentinelConfiguration redisUriToSentinelConfiguration(RedisUR * @return a {@link RedisSocketConfiguration} representing the connection information in the Redis URI. * @since 2.6 */ - public static RedisSocketConfiguration redisUriToSocketConfiguration(RedisURI redisURI) { + static RedisSocketConfiguration redisUriToSocketConfiguration(RedisURI redisURI) { Assert.notNull(redisURI, "RedisURI is required"); Assert.hasText(redisURI.getSocket(), "RedisURI must have socket path set"); @@ -623,7 +584,7 @@ public static RedisSocketConfiguration redisUriToSocketConfiguration(RedisURI re * @return a {@link RedisStandaloneConfiguration} representing the connection information in the Redis URI. * @since 2.6 */ - public static RedisStandaloneConfiguration redisUriToStandaloneConfiguration(RedisURI redisURI) { + static RedisStandaloneConfiguration redisUriToStandaloneConfiguration(RedisURI redisURI) { Assert.notNull(redisURI, "RedisURI is required"); From 46278707f2675cde742e9b38467ba54a08496e79 Mon Sep 17 00:00:00 2001 From: bono007 Date: Mon, 12 Jul 2021 22:59:56 -0500 Subject: [PATCH 4/4] Add unit tests --- .../connection/lettuce/LettuceConverters.java | 6 +- ...toryCreateRedisConfigurationUnitTests.java | 193 ++++++++++++++++++ 2 files changed, 196 insertions(+), 3 deletions(-) create mode 100644 src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryCreateRedisConfigurationUnitTests.java diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java index 7a10de24b1..e1740e68ab 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java @@ -537,10 +537,11 @@ public static RedisURI sentinelConfigurationToRedisURI(RedisSentinelConfiguratio static RedisSentinelConfiguration redisUriToSentinelConfiguration(RedisURI redisURI) { Assert.notNull(redisURI, "RedisURI is required"); - Assert.hasText(redisURI.getSentinelMasterId(), "RedisURI must have sentinelMasterId param set"); RedisSentinelConfiguration sentinelConfiguration = new RedisSentinelConfiguration(); - sentinelConfiguration.setMaster(redisURI.getSentinelMasterId()); + if (!ObjectUtils.isEmpty(redisURI.getSentinelMasterId())) { + sentinelConfiguration.setMaster(redisURI.getSentinelMasterId()); + } sentinelConfiguration.setDatabase(redisURI.getDatabase()); for (RedisURI sentinelNodeRedisUri : redisURI.getSentinels()) { @@ -566,7 +567,6 @@ static RedisSentinelConfiguration redisUriToSentinelConfiguration(RedisURI redis static RedisSocketConfiguration redisUriToSocketConfiguration(RedisURI redisURI) { Assert.notNull(redisURI, "RedisURI is required"); - Assert.hasText(redisURI.getSocket(), "RedisURI must have socket path set"); RedisSocketConfiguration socketConfiguration = new RedisSocketConfiguration(); socketConfiguration.setSocket(redisURI.getSocket()); diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryCreateRedisConfigurationUnitTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryCreateRedisConfigurationUnitTests.java new file mode 100644 index 0000000000..e14f54df03 --- /dev/null +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryCreateRedisConfigurationUnitTests.java @@ -0,0 +1,193 @@ +/* + * Copyright 2015-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.redis.connection.lettuce; + +import static org.assertj.core.api.Assertions.*; + +import io.lettuce.core.RedisURI; + +import org.assertj.core.api.recursive.comparison.RecursiveComparisonConfiguration; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import org.springframework.data.redis.connection.RedisConfiguration; +import org.springframework.data.redis.connection.RedisNode; +import org.springframework.data.redis.connection.RedisSentinelConfiguration; +import org.springframework.data.redis.connection.RedisSocketConfiguration; +import org.springframework.data.redis.connection.RedisStandaloneConfiguration; + +/** + * Unit tests for the {@link LettuceConnectionFactory#createRedisConfiguration(RedisURI)} factory method. + * + * @author Chris Bono + */ +class LettuceConnectionFactoryCreateRedisConfigurationUnitTests { + + @Test + void requiresRedisURI() { + assertThatThrownBy(() -> LettuceConnectionFactory.createRedisConfiguration(null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("RedisURI must not be null"); + } + + @Nested // GH-2117 + class CreateRedisSentinelConfiguration { + + @Test + void minimalFieldsSetOnRedisURI() { + RedisURI redisURI = RedisURI.create("redis-sentinel://myserver?sentinelMasterId=5150"); + RedisSentinelConfiguration expectedSentinelConfiguration = new RedisSentinelConfiguration(); + expectedSentinelConfiguration.setMaster("5150"); + expectedSentinelConfiguration.addSentinel(new RedisNode("myserver", 26379)); + + RedisConfiguration sentinelConfiguration = LettuceConnectionFactory.createRedisConfiguration(redisURI); + + assertThat(sentinelConfiguration).usingRecursiveComparison(sentinelCompareConfig()) + .isInstanceOf(RedisSentinelConfiguration.class) + .isEqualTo(expectedSentinelConfiguration); + } + + @Test + void allFieldsSetOnRedisURI() { + RedisURI redisURI = RedisURI.create("redis-sentinel://fooUser:fooPass@myserver1:111,myserver2:222/7?sentinelMasterId=5150"); + // Set the passwords directly on the sentinels so that it gets picked up by converter + char[] sentinelPass = "changeme".toCharArray(); + redisURI.getSentinels().forEach(sentinelRedisUri -> sentinelRedisUri.setPassword(sentinelPass)); + RedisSentinelConfiguration expectedSentinelConfiguration = new RedisSentinelConfiguration(); + expectedSentinelConfiguration.setMaster("5150"); + expectedSentinelConfiguration.setDatabase(7); + expectedSentinelConfiguration.setUsername("fooUser"); + expectedSentinelConfiguration.setPassword("fooPass"); + expectedSentinelConfiguration.setSentinelPassword(sentinelPass); + expectedSentinelConfiguration.addSentinel(new RedisNode("myserver1", 111)); + expectedSentinelConfiguration.addSentinel(new RedisNode("myserver2", 222)); + + RedisConfiguration sentinelConfiguration = LettuceConnectionFactory.createRedisConfiguration(redisURI); + + assertThat(sentinelConfiguration).usingRecursiveComparison(sentinelCompareConfig()) + .isInstanceOf(RedisSentinelConfiguration.class) + .isEqualTo(expectedSentinelConfiguration); + } + + // RedisSentinelConfiguration does not provide equals impl + private RecursiveComparisonConfiguration sentinelCompareConfig() { + return RecursiveComparisonConfiguration.builder().withComparedFields( + "master", + "username", + "password", + "sentinelPassword", + "database", + "sentinels") + .build(); + } + } + + @Nested // GH-2117 + class CreateRedisSocketConfiguration { + + @Test + void minimalFieldsSetOnRedisURI() { + RedisURI redisURI = RedisURI.builder() + .socket("mysocket") + .build(); + RedisSocketConfiguration expectedSocketConfiguration = new RedisSocketConfiguration(); + expectedSocketConfiguration.setSocket("mysocket"); + + RedisConfiguration socketConfiguration = LettuceConnectionFactory.createRedisConfiguration(redisURI); + + assertThat(socketConfiguration).usingRecursiveComparison(socketCompareConfig()) + .isInstanceOf(RedisSocketConfiguration.class) + .isEqualTo(expectedSocketConfiguration); + } + + @Test + void allFieldsSetOnRedisURI() { + RedisURI redisURI = RedisURI.builder() + .socket("mysocket") + .withAuthentication("fooUser", "fooPass".toCharArray()) + .withDatabase(7) + .build(); + RedisSocketConfiguration expectedSocketConfiguration = new RedisSocketConfiguration(); + expectedSocketConfiguration.setSocket("mysocket"); + expectedSocketConfiguration.setUsername("fooUser"); + expectedSocketConfiguration.setPassword("fooPass"); + expectedSocketConfiguration.setDatabase(7); + + RedisConfiguration socketConfiguration = LettuceConnectionFactory.createRedisConfiguration(redisURI); + + assertThat(socketConfiguration).usingRecursiveComparison(socketCompareConfig()) + .isInstanceOf(RedisSocketConfiguration.class) + .isEqualTo(expectedSocketConfiguration); + } + + // RedisSocketConfiguration does not provide equals impl + private RecursiveComparisonConfiguration socketCompareConfig() { + return RecursiveComparisonConfiguration.builder().withComparedFields( + "socket", + "username", + "password", + "database") + .build(); + } + } + + @Nested // GH-2117 + class CreateRedisStandaloneConfiguration { + + @Test + void minimalFieldsSetOnRedisURI() { + RedisURI redisURI = RedisURI.create("redis://myserver"); + RedisStandaloneConfiguration expectedStandaloneConfiguration = new RedisStandaloneConfiguration(); + expectedStandaloneConfiguration.setHostName("myserver"); + + RedisConfiguration StandaloneConfiguration = LettuceConnectionFactory.createRedisConfiguration(redisURI); + + assertThat(StandaloneConfiguration).usingRecursiveComparison(standaloneCompareConfig()) + .isInstanceOf(RedisStandaloneConfiguration.class) + .isEqualTo(expectedStandaloneConfiguration); + } + + @Test + void allFieldsSetOnRedisURI() { + RedisURI redisURI = RedisURI.create("redis://fooUser:fooPass@myserver1:111/7"); + RedisStandaloneConfiguration expectedStandaloneConfiguration = new RedisStandaloneConfiguration(); + expectedStandaloneConfiguration.setHostName("myserver1"); + expectedStandaloneConfiguration.setPort(111); + expectedStandaloneConfiguration.setDatabase(7); + expectedStandaloneConfiguration.setUsername("fooUser"); + expectedStandaloneConfiguration.setPassword("fooPass"); + + RedisConfiguration StandaloneConfiguration = LettuceConnectionFactory.createRedisConfiguration(redisURI); + + assertThat(StandaloneConfiguration).usingRecursiveComparison(standaloneCompareConfig()) + .isInstanceOf(RedisStandaloneConfiguration.class) + .isEqualTo(expectedStandaloneConfiguration); + + } + + // RedisStandaloneConfiguration does not provide equals impl + private RecursiveComparisonConfiguration standaloneCompareConfig() { + return RecursiveComparisonConfiguration.builder().withComparedFields( + "host", + "port", + "username", + "password", + "database") + .build(); + } + } + +}