Refactor Lettuce connection handling in integration tests.

Reuse condition objects in command and version condition extensions.

Shut down ClientResources via ShutdownQueue and ensure shared client resources usage.

Add close support to our MethodArgumentsProvider. Reuse LettuceTestClientConfiguration for test client config settings.

Closes #2575
This commit is contained in:
Mark Paluch
2023-05-09 15:07:08 +02:00
parent 8c9af9d46a
commit 5e2b668dcc
20 changed files with 376 additions and 241 deletions

View File

@@ -43,7 +43,6 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.domain.Range.Bound;
@@ -119,7 +118,7 @@ public class JedisClusterConnectionTests implements ClusterConnectionTests {
}
@BeforeEach
void tearDown() throws IOException {
void beforeEach() throws IOException {
for (ConnectionPool pool : nativeConnection.getClusterNodes().values()) {
try (Jedis jedis = new Jedis(pool.getResource())) {

View File

@@ -16,6 +16,7 @@
package org.springframework.data.redis.connection.jedis.extension;
import java.io.Closeable;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;
@@ -25,7 +26,6 @@ import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolutionException;
import org.junit.jupiter.api.extension.ParameterResolver;
import org.springframework.data.redis.ConnectionFactoryTracker;
import org.springframework.data.redis.SettingsUtils;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
@@ -64,7 +64,7 @@ public class JedisConnectionFactoryExtension implements ParameterResolver {
CLIENT_CONFIGURATION);
factory.afterPropertiesSet();
ShutdownQueue.register(factory.toCloseable());
ShutdownQueue.register(factory);
return factory;
});
@@ -75,7 +75,7 @@ public class JedisConnectionFactoryExtension implements ParameterResolver {
CLIENT_CONFIGURATION);
factory.afterPropertiesSet();
ShutdownQueue.register(factory.toCloseable());
ShutdownQueue.register(factory);
return factory;
});
@@ -86,7 +86,7 @@ public class JedisConnectionFactoryExtension implements ParameterResolver {
CLIENT_CONFIGURATION);
factory.afterPropertiesSet();
ShutdownQueue.register(factory.toCloseable());
ShutdownQueue.register(factory);
return factory;
});
@@ -171,7 +171,7 @@ public class JedisConnectionFactoryExtension implements ParameterResolver {
}
static class ManagedJedisConnectionFactory extends JedisConnectionFactory
implements ConnectionFactoryTracker.Managed {
implements ConnectionFactoryTracker.Managed, Closeable {
private volatile boolean mayClose;
@@ -219,15 +219,14 @@ public class JedisConnectionFactoryExtension implements ParameterResolver {
return builder.toString();
}
Closeable toCloseable() {
return () -> {
try {
mayClose = true;
destroy();
} catch (Exception e) {
e.printStackTrace();
}
};
@Override
public void close() throws IOException {
try {
mayClose = true;
destroy();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

View File

@@ -24,7 +24,6 @@ import java.io.IOException;
import java.util.Collections;
import org.junit.jupiter.api.Test;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.RedisSentinelConnection;
@@ -88,8 +87,7 @@ class LettuceAclIntegrationTests {
// Note: As per https://github.com/redis/redis/issues/7708, Sentinel does not support ACL authentication yet.
LettuceClientConfiguration configuration = LettuceClientConfiguration.builder()
.clientResources(LettuceTestClientResources.getSharedClientResources())
LettuceClientConfiguration configuration = LettuceTestClientConfiguration.builder()
.clientOptions(ClientOptions.builder().protocolVersion(ProtocolVersion.RESP2).build()).build();
RedisSentinelConfiguration sentinelConfiguration = new RedisSentinelConfiguration("mymaster",

View File

@@ -41,7 +41,6 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.domain.Range.Bound;
@@ -144,6 +143,7 @@ public class LettuceClusterConnectionTests implements ClusterConnectionTests {
LettucePoolingClientConfiguration clientConfiguration = LettucePoolingClientConfiguration.builder() //
.clientResources(LettuceTestClientResources.getSharedClientResources()) //
.shutdownTimeout(Duration.ZERO) //
.shutdownQuietPeriod(Duration.ZERO) //
.build();
RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration();

View File

@@ -36,7 +36,6 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.data.redis.ConnectionFactoryTracker;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.data.redis.RedisSystemException;
@@ -238,7 +237,6 @@ class LettuceConnectionFactoryTests {
.getNativeConnection();
factory.resetConnection();
assertThat(factory.getConnection().getNativeConnection()).isNotSameAs(nativeConn);
nativeConn.getStatefulConnection().close();
}
@SuppressWarnings("unchecked")
@@ -352,7 +350,8 @@ class LettuceConnectionFactoryTests {
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
LettuceClientConfiguration configuration = LettucePoolingClientConfiguration.builder().poolConfig(poolConfig)
.clientResources(LettuceTestClientResources.getSharedClientResources()).shutdownTimeout(Duration.ZERO).build();
.clientResources(LettuceTestClientResources.getSharedClientResources()).shutdownTimeout(Duration.ZERO)
.shutdownQuietPeriod(Duration.ZERO).build();
LettuceConnectionFactory factory = new LettuceConnectionFactory(new RedisStandaloneConfiguration(), configuration);
factory.setShareNativeConnection(false);
@@ -431,8 +430,8 @@ class LettuceConnectionFactoryTests {
RedisStaticMasterReplicaConfiguration elastiCache = new RedisStaticMasterReplicaConfiguration(
SettingsUtils.getHost()).node(SettingsUtils.getHost(), SettingsUtils.getPort() + 1);
LettuceConnectionFactory factory = new LettuceConnectionFactory(elastiCache);
factory.setClientResources(LettuceTestClientResources.getSharedClientResources());
LettuceConnectionFactory factory = new LettuceConnectionFactory(elastiCache,
LettuceTestClientConfiguration.defaultConfiguration());
factory.afterPropertiesSet();
RedisConnection connection = factory.getConnection();
@@ -502,8 +501,8 @@ class LettuceConnectionFactoryTests {
@Test // DATAREDIS-576
void connectionAppliesClientName() {
LettuceClientConfiguration configuration = LettuceClientConfiguration.builder()
.clientResources(LettuceTestClientResources.getSharedClientResources()).clientName("clientName").build();
LettuceClientConfiguration configuration = LettuceTestClientConfiguration.builder().clientName("clientName")
.build();
LettuceConnectionFactory factory = new LettuceConnectionFactory(new RedisStandaloneConfiguration(), configuration);
factory.setShareNativeConnection(false);
@@ -536,8 +535,7 @@ class LettuceConnectionFactoryTests {
@Test // GH-2186
void shouldInitializeMasterReplicaConnectionsEagerly() {
LettuceClientConfiguration configuration = LettuceClientConfiguration.builder()
.clientResources(LettuceTestClientResources.getSharedClientResources()).build();
LettuceClientConfiguration configuration = LettuceTestClientConfiguration.builder().build();
RedisStaticMasterReplicaConfiguration elastiCache = new RedisStaticMasterReplicaConfiguration(
SettingsUtils.getHost()).node(SettingsUtils.getHost(), SettingsUtils.getPort() + 1);
@@ -557,8 +555,7 @@ class LettuceConnectionFactoryTests {
@EnabledOnRedisClusterAvailable
void shouldInitializeClusterConnectionsEagerly() {
LettuceClientConfiguration configuration = LettuceClientConfiguration.builder()
.clientResources(LettuceTestClientResources.getSharedClientResources()).build();
LettuceClientConfiguration configuration = LettuceTestClientConfiguration.builder().build();
LettuceConnectionFactory factory = new LettuceConnectionFactory(SettingsUtils.clusterConfiguration(),
configuration);

View File

@@ -48,7 +48,6 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatchers;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.data.redis.ConnectionFactoryTracker;
@@ -94,8 +93,8 @@ class LettuceConnectionFactoryUnitTests {
@Test // DATAREDIS-315
void shouldInitClientCorrectlyWhenClusterConfigPresent() {
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(clusterConfig);
connectionFactory.setClientResources(getSharedClientResources());
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(clusterConfig,
LettuceTestClientConfiguration.defaultConfiguration());
connectionFactory.afterPropertiesSet();
ConnectionFactoryTracker.add(connectionFactory);
@@ -128,7 +127,7 @@ class LettuceConnectionFactoryUnitTests {
RedisConfiguration redisConfiguration = new RedisStandaloneConfiguration("localhost", 16379);
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(redisConfiguration,
LettuceClientConfiguration.defaultConfiguration());
LettuceTestClientConfiguration.defaultConfiguration());
assertThat(connectionFactory.getPort()).isEqualTo(16379);
}
@@ -139,7 +138,7 @@ class LettuceConnectionFactoryUnitTests {
RedisConfiguration redisConfiguration = new CustomRedisConfiguration("localhost", 16379);
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(redisConfiguration,
LettuceClientConfiguration.defaultConfiguration());
LettuceTestClientConfiguration.defaultConfiguration());
assertThat(connectionFactory.getPort()).isEqualTo(16379);
assertThat(connectionFactory.getHostName()).isEqualTo("localhost");
@@ -151,7 +150,7 @@ class LettuceConnectionFactoryUnitTests {
RedisConfiguration redisConfiguration = new RedisStandaloneConfiguration("external");
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(redisConfiguration,
LettuceClientConfiguration.defaultConfiguration());
LettuceTestClientConfiguration.defaultConfiguration());
assertThat(connectionFactory.getHostName()).isEqualTo("external");
}
@@ -162,7 +161,7 @@ class LettuceConnectionFactoryUnitTests {
RedisConfiguration redisConfiguration = new CustomRedisConfiguration("external");
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(redisConfiguration,
LettuceClientConfiguration.defaultConfiguration());
LettuceTestClientConfiguration.defaultConfiguration());
assertThat(connectionFactory.getPort()).isEqualTo(6379);
assertThat(connectionFactory.getHostName()).isEqualTo("external");
@@ -172,8 +171,8 @@ class LettuceConnectionFactoryUnitTests {
@SuppressWarnings("unchecked")
void passwordShouldBeSetCorrectlyOnClusterClient() {
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(clusterConfig);
connectionFactory.setClientResources(getSharedClientResources());
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(clusterConfig,
LettuceTestClientConfiguration.defaultConfiguration());
connectionFactory.setPassword("o_O");
connectionFactory.afterPropertiesSet();
ConnectionFactoryTracker.add(connectionFactory);
@@ -195,8 +194,7 @@ class LettuceConnectionFactoryUnitTests {
clusterConfig.setUsername("foo");
clusterConfig.setPassword("bar");
LettuceClientConfiguration clientConfiguration = LettuceClientConfiguration.builder()
.clientResources(getSharedClientResources())
LettuceClientConfiguration clientConfiguration = LettuceTestClientConfiguration.builder()
.redisCredentialsProviderFactory(new RedisCredentialsProviderFactory() {}).build();
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(clusterConfig, clientConfiguration);
connectionFactory.afterPropertiesSet();
@@ -223,7 +221,7 @@ class LettuceConnectionFactoryUnitTests {
config.setUsername("foo");
config.setPassword("bar");
LettuceClientConfiguration clientConfiguration = LettuceClientConfiguration.builder()
LettuceClientConfiguration clientConfiguration = LettuceTestClientConfiguration.builder()
.clientResources(getSharedClientResources())
.redisCredentialsProviderFactory(new RedisCredentialsProviderFactory() {}).build();
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(config, clientConfiguration);
@@ -245,8 +243,8 @@ class LettuceConnectionFactoryUnitTests {
void passwordShouldNotBeSetOnSentinelClient() {
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(
new RedisSentinelConfiguration("mymaster", Collections.singleton("host:1234")));
connectionFactory.setClientResources(getSharedClientResources());
new RedisSentinelConfiguration("mymaster", Collections.singleton("host:1234")),
LettuceTestClientConfiguration.defaultConfiguration());
connectionFactory.setPassword("o_O");
connectionFactory.afterPropertiesSet();
ConnectionFactoryTracker.add(connectionFactory);
@@ -269,8 +267,8 @@ class LettuceConnectionFactoryUnitTests {
RedisSentinelConfiguration config = new RedisSentinelConfiguration("mymaster", Collections.singleton("host:1234"));
config.setSentinelPassword("sentinel-pwd");
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(config);
connectionFactory.setClientResources(getSharedClientResources());
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(config,
LettuceTestClientConfiguration.defaultConfiguration());
connectionFactory.setPassword("o_O");
connectionFactory.afterPropertiesSet();
ConnectionFactoryTracker.add(connectionFactory);
@@ -295,8 +293,7 @@ class LettuceConnectionFactoryUnitTests {
config.setPassword("data-pwd");
config.setSentinelPassword("sentinel-pwd");
LettuceClientConfiguration clientConfiguration = LettuceClientConfiguration.builder()
.clientResources(getSharedClientResources())
LettuceClientConfiguration clientConfiguration = LettuceTestClientConfiguration.builder()
.redisCredentialsProviderFactory(new RedisCredentialsProviderFactory() {}).build();
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(config, clientConfiguration);
@@ -328,8 +325,8 @@ class LettuceConnectionFactoryUnitTests {
RedisSentinelConfiguration config = new RedisSentinelConfiguration("mymaster", Collections.singleton("host:1234"));
config.setSentinelPassword("sentinel-pwd");
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(config);
connectionFactory.setClientResources(getSharedClientResources());
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(config,
LettuceTestClientConfiguration.defaultConfiguration());
connectionFactory.afterPropertiesSet();
ConnectionFactoryTracker.add(connectionFactory);
@@ -361,8 +358,8 @@ class LettuceConnectionFactoryUnitTests {
@Test // DATAREDIS-480
void sslOptionsShouldBeDisabledByDefaultOnClient() {
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory();
connectionFactory.setClientResources(getSharedClientResources());
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(new RedisStandaloneConfiguration(),
LettuceTestClientConfiguration.defaultConfiguration());
connectionFactory.afterPropertiesSet();
ConnectionFactoryTracker.add(connectionFactory);
@@ -382,9 +379,8 @@ class LettuceConnectionFactoryUnitTests {
@Test // DATAREDIS-476
void sslShouldBeSetCorrectlyOnClient() {
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory();
connectionFactory.setClientResources(getSharedClientResources());
connectionFactory.setUseSsl(true);
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(new RedisStandaloneConfiguration(),
LettuceTestClientConfiguration.builder().useSsl().build());
connectionFactory.afterPropertiesSet();
ConnectionFactoryTracker.add(connectionFactory);
@@ -402,9 +398,8 @@ class LettuceConnectionFactoryUnitTests {
@Test // DATAREDIS-480
void verifyPeerOptionShouldBeSetCorrectlyOnClient() {
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory();
connectionFactory.setClientResources(getSharedClientResources());
connectionFactory.setVerifyPeer(false);
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(new RedisStandaloneConfiguration(),
LettuceTestClientConfiguration.builder().useSsl().disablePeerVerification().build());
connectionFactory.afterPropertiesSet();
ConnectionFactoryTracker.add(connectionFactory);
@@ -420,9 +415,8 @@ class LettuceConnectionFactoryUnitTests {
@Test // DATAREDIS-480
void startTLSOptionShouldBeSetCorrectlyOnClient() {
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory();
connectionFactory.setClientResources(getSharedClientResources());
connectionFactory.setStartTls(true);
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(new RedisStandaloneConfiguration(),
LettuceTestClientConfiguration.builder().useSsl().startTls().build());
connectionFactory.afterPropertiesSet();
ConnectionFactoryTracker.add(connectionFactory);
@@ -440,9 +434,8 @@ class LettuceConnectionFactoryUnitTests {
RedisSentinelConfiguration sentinelConfiguration = new RedisSentinelConfiguration("myMaster",
Collections.singleton("localhost:1234"));
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(sentinelConfiguration);
connectionFactory.setClientResources(getSharedClientResources());
connectionFactory.setUseSsl(true);
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(sentinelConfiguration,
LettuceTestClientConfiguration.builder().useSsl().startTls().build());
connectionFactory.afterPropertiesSet();
ConnectionFactoryTracker.add(connectionFactory);
@@ -462,9 +455,8 @@ class LettuceConnectionFactoryUnitTests {
RedisSentinelConfiguration sentinelConfiguration = new RedisSentinelConfiguration("myMaster",
Collections.singleton("localhost:1234"));
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(sentinelConfiguration);
connectionFactory.setClientResources(getSharedClientResources());
connectionFactory.setVerifyPeer(false);
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(sentinelConfiguration,
LettuceTestClientConfiguration.builder().useSsl().disablePeerVerification().build());
connectionFactory.afterPropertiesSet();
ConnectionFactoryTracker.add(connectionFactory);
@@ -482,9 +474,8 @@ class LettuceConnectionFactoryUnitTests {
RedisSentinelConfiguration sentinelConfiguration = new RedisSentinelConfiguration("myMaster",
Collections.singleton("localhost:1234"));
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(sentinelConfiguration);
connectionFactory.setClientResources(getSharedClientResources());
connectionFactory.setStartTls(true);
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(sentinelConfiguration,
LettuceTestClientConfiguration.builder().useSsl().startTls().build());
connectionFactory.afterPropertiesSet();
ConnectionFactoryTracker.add(connectionFactory);
@@ -501,9 +492,8 @@ class LettuceConnectionFactoryUnitTests {
void sslShouldBeSetCorrectlyOnClusterClient() {
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(
new RedisClusterConfiguration().clusterNode(CLUSTER_NODE_1));
connectionFactory.setClientResources(getSharedClientResources());
connectionFactory.setUseSsl(true);
new RedisClusterConfiguration().clusterNode(CLUSTER_NODE_1),
LettuceTestClientConfiguration.builder().useSsl().build());
connectionFactory.afterPropertiesSet();
ConnectionFactoryTracker.add(connectionFactory);
@@ -521,9 +511,8 @@ class LettuceConnectionFactoryUnitTests {
void startTLSOptionShouldBeSetCorrectlyOnClusterClient() {
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(
new RedisClusterConfiguration().clusterNode(CLUSTER_NODE_1));
connectionFactory.setClientResources(getSharedClientResources());
connectionFactory.setStartTls(true);
new RedisClusterConfiguration().clusterNode(CLUSTER_NODE_1),
LettuceTestClientConfiguration.builder().useSsl().startTls().build());
connectionFactory.afterPropertiesSet();
ConnectionFactoryTracker.add(connectionFactory);
@@ -541,9 +530,8 @@ class LettuceConnectionFactoryUnitTests {
void verifyPeerTLSOptionShouldBeSetCorrectlyOnClusterClient() {
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(
new RedisClusterConfiguration().clusterNode(CLUSTER_NODE_1));
connectionFactory.setClientResources(getSharedClientResources());
connectionFactory.setVerifyPeer(true);
new RedisClusterConfiguration().clusterNode(CLUSTER_NODE_1),
LettuceTestClientConfiguration.builder().useSsl().startTls().build());
connectionFactory.afterPropertiesSet();
ConnectionFactoryTracker.add(connectionFactory);
@@ -560,8 +548,8 @@ class LettuceConnectionFactoryUnitTests {
@Test // DATAREDIS-682
void socketShouldBeSetOnStandaloneClient() {
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(new RedisSocketConfiguration());
connectionFactory.setClientResources(getSharedClientResources());
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(new RedisSocketConfiguration(),
LettuceTestClientConfiguration.defaultConfiguration());
connectionFactory.afterPropertiesSet();
ConnectionFactoryTracker.add(connectionFactory);
@@ -580,7 +568,7 @@ class LettuceConnectionFactoryUnitTests {
envConfig.setPassword(RedisPassword.of("foo"));
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(envConfig,
LettuceClientConfiguration.defaultConfiguration());
LettuceTestClientConfiguration.defaultConfiguration());
assertThat(connectionFactory.getPassword()).isEqualTo("foo");
}
@@ -592,7 +580,7 @@ class LettuceConnectionFactoryUnitTests {
envConfig.setPassword(RedisPassword.of("foo"));
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(envConfig,
LettuceClientConfiguration.defaultConfiguration());
LettuceTestClientConfiguration.defaultConfiguration());
connectionFactory.setPassword("bar");
assertThat(connectionFactory.getPassword()).isEqualTo("bar");
@@ -606,7 +594,7 @@ class LettuceConnectionFactoryUnitTests {
envConfig.setPassword(RedisPassword.of("foo"));
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(envConfig,
LettuceClientConfiguration.defaultConfiguration());
LettuceTestClientConfiguration.defaultConfiguration());
assertThat(connectionFactory.getPassword()).isEqualTo("foo");
}
@@ -618,7 +606,7 @@ class LettuceConnectionFactoryUnitTests {
envConfig.setPassword(RedisPassword.of("foo"));
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(envConfig,
LettuceClientConfiguration.defaultConfiguration());
LettuceTestClientConfiguration.defaultConfiguration());
connectionFactory.setPassword("bar");
assertThat(connectionFactory.getPassword()).isEqualTo("bar");
@@ -632,7 +620,7 @@ class LettuceConnectionFactoryUnitTests {
envConfig.setPassword(RedisPassword.of("foo"));
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(envConfig,
LettuceClientConfiguration.defaultConfiguration());
LettuceTestClientConfiguration.defaultConfiguration());
connectionFactory.setPassword("bar");
assertThat(connectionFactory.getPassword()).isEqualTo("bar");
@@ -646,7 +634,7 @@ class LettuceConnectionFactoryUnitTests {
envConfig.setPassword(RedisPassword.of("foo"));
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(envConfig,
LettuceClientConfiguration.defaultConfiguration());
LettuceTestClientConfiguration.defaultConfiguration());
assertThat(connectionFactory.getPassword()).isEqualTo("foo");
}
@@ -658,7 +646,7 @@ class LettuceConnectionFactoryUnitTests {
envConfig.setPassword(RedisPassword.of("foo"));
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(envConfig,
LettuceClientConfiguration.defaultConfiguration());
LettuceTestClientConfiguration.defaultConfiguration());
connectionFactory.setPassword("bar");
assertThat(connectionFactory.getPassword()).isEqualTo("bar");
@@ -672,7 +660,7 @@ class LettuceConnectionFactoryUnitTests {
envConfig.setDatabase(2);
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(envConfig,
LettuceClientConfiguration.defaultConfiguration());
LettuceTestClientConfiguration.defaultConfiguration());
assertThat(connectionFactory.getDatabase()).isEqualTo(2);
}
@@ -684,7 +672,7 @@ class LettuceConnectionFactoryUnitTests {
envConfig.setDatabase(2);
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(envConfig,
LettuceClientConfiguration.defaultConfiguration());
LettuceTestClientConfiguration.defaultConfiguration());
connectionFactory.setDatabase(3);
assertThat(connectionFactory.getDatabase()).isEqualTo(3);
@@ -698,7 +686,7 @@ class LettuceConnectionFactoryUnitTests {
envConfig.setDatabase(2);
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(envConfig,
LettuceClientConfiguration.defaultConfiguration());
LettuceTestClientConfiguration.defaultConfiguration());
assertThat(connectionFactory.getDatabase()).isEqualTo(2);
}
@@ -710,7 +698,7 @@ class LettuceConnectionFactoryUnitTests {
envConfig.setDatabase(2);
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(envConfig,
LettuceClientConfiguration.defaultConfiguration());
LettuceTestClientConfiguration.defaultConfiguration());
connectionFactory.setDatabase(3);
assertThat(connectionFactory.getDatabase()).isEqualTo(3);
@@ -724,7 +712,7 @@ class LettuceConnectionFactoryUnitTests {
envConfig.setDatabase(2);
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(envConfig,
LettuceClientConfiguration.defaultConfiguration());
LettuceTestClientConfiguration.defaultConfiguration());
connectionFactory.setDatabase(3);
assertThat(connectionFactory.getDatabase()).isEqualTo(3);
@@ -765,7 +753,7 @@ class LettuceConnectionFactoryUnitTests {
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(configuration,
LettuceClientConfiguration.defaultConfiguration());
LettuceTestClientConfiguration.defaultConfiguration());
assertThat(connectionFactory.getStandaloneConfiguration()).isEqualTo(configuration);
assertThat(connectionFactory.getSentinelConfiguration()).isNull();
@@ -777,7 +765,7 @@ class LettuceConnectionFactoryUnitTests {
RedisSocketConfiguration configuration = new RedisSocketConfiguration("/var/redis/socket");
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(configuration,
LettuceClientConfiguration.defaultConfiguration());
LettuceTestClientConfiguration.defaultConfiguration());
assertThat(connectionFactory.getStandaloneConfiguration()).isNotNull();
assertThat(connectionFactory.getSocketConfiguration()).isEqualTo(configuration);
@@ -790,7 +778,7 @@ class LettuceConnectionFactoryUnitTests {
RedisSentinelConfiguration configuration = new RedisSentinelConfiguration();
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(configuration,
LettuceClientConfiguration.defaultConfiguration());
LettuceTestClientConfiguration.defaultConfiguration());
assertThat(connectionFactory.getStandaloneConfiguration()).isNotNull();
assertThat(connectionFactory.getSentinelConfiguration()).isEqualTo(configuration);
@@ -802,7 +790,7 @@ class LettuceConnectionFactoryUnitTests {
RedisClusterConfiguration configuration = new RedisClusterConfiguration();
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(configuration,
LettuceClientConfiguration.defaultConfiguration());
LettuceTestClientConfiguration.defaultConfiguration());
assertThat(connectionFactory.getStandaloneConfiguration()).isNotNull();
assertThat(connectionFactory.getSentinelConfiguration()).isNull();
@@ -813,7 +801,7 @@ class LettuceConnectionFactoryUnitTests {
void shouldDenyChangesToImmutableClientConfiguration() {
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(new RedisStandaloneConfiguration(),
LettuceClientConfiguration.defaultConfiguration());
LettuceTestClientConfiguration.defaultConfiguration());
assertThatIllegalStateException().isThrownBy(() -> connectionFactory.setUseSsl(false));
}
@@ -839,8 +827,7 @@ class LettuceConnectionFactoryUnitTests {
void timeoutSetOnClientConfigShouldBePassedOnToClusterConnection() {
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(clusterConfig,
LettuceClientConfiguration.builder().commandTimeout(Duration.ofSeconds(2)).shutdownTimeout(Duration.ZERO)
.clientResources(getSharedClientResources()).build());
LettuceTestClientConfiguration.builder().commandTimeout(Duration.ofSeconds(2)).build());
connectionFactory.setShareNativeConnection(false);
connectionFactory.afterPropertiesSet();
@@ -861,7 +848,7 @@ class LettuceConnectionFactoryUnitTests {
.thenReturn(CompletableFuture.completedFuture(connectionMock));
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(clusterConfig,
LettuceClientConfiguration.defaultConfiguration()) {
LettuceTestClientConfiguration.defaultConfiguration()) {
@Override
protected AbstractRedisClient createClient() {
@@ -891,7 +878,7 @@ class LettuceConnectionFactoryUnitTests {
when(connectionMock.sync()).thenReturn(syncMock);
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(clusterConfig,
LettuceClientConfiguration.defaultConfiguration()) {
LettuceTestClientConfiguration.defaultConfiguration()) {
@Override
protected AbstractRedisClient createClient() {
@@ -920,7 +907,7 @@ class LettuceConnectionFactoryUnitTests {
when(connectionMock.closeAsync()).thenReturn(CompletableFuture.completedFuture(null));
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(clusterConfig,
LettuceClientConfiguration.defaultConfiguration()) {
LettuceTestClientConfiguration.defaultConfiguration()) {
@Override
protected AbstractRedisClient createClient() {
@@ -1008,8 +995,8 @@ class LettuceConnectionFactoryUnitTests {
RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration("mymaster",
Collections.singleton("host:1234"));
redisSentinelConfiguration.setDatabase(1);
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(redisSentinelConfiguration);
connectionFactory.setClientResources(getSharedClientResources());
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(redisSentinelConfiguration,
LettuceTestClientConfiguration.defaultConfiguration());
connectionFactory.setPassword("o_O");
connectionFactory.afterPropertiesSet();
ConnectionFactoryTracker.add(connectionFactory);
@@ -1029,7 +1016,7 @@ class LettuceConnectionFactoryUnitTests {
clusterConfiguration.clusterNode("localhost", 1234).setMaxRedirects(42);
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(clusterConfiguration,
LettuceClientConfiguration.builder().clientResources(getSharedClientResources()).build());
LettuceTestClientConfiguration.builder().build());
connectionFactory.afterPropertiesSet();
ConnectionFactoryTracker.add(connectionFactory);
@@ -1048,9 +1035,9 @@ class LettuceConnectionFactoryUnitTests {
RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration();
clusterConfiguration.clusterNode("localhost", 1234).setMaxRedirects(42);
LettuceClientConfiguration clientConfiguration = LettuceClientConfiguration.builder()
LettuceClientConfiguration clientConfiguration = LettuceTestClientConfiguration.builder()
.clientOptions(ClusterClientOptions.builder().validateClusterNodeMembership(false).build())
.clientResources(getSharedClientResources()).build();
.build();
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(clusterConfiguration,
clientConfiguration);

View File

@@ -21,12 +21,11 @@ import java.util.Arrays;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.redis.connection.AbstractConnectionPipelineIntegrationTests;
import org.springframework.data.redis.connection.DefaultStringRedisConnection;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.StringRedisConnection;
import org.springframework.data.redis.test.extension.LettuceTestClientResources;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@@ -54,8 +53,8 @@ public class LettuceConnectionPipelineIntegrationTests extends AbstractConnectio
actual.add(connection.move("foo", 1));
verifyResults(Arrays.asList(new Object[] { true, true }));
// Lettuce does not support select when using shared conn, use a new conn factory
LettuceConnectionFactory factory2 = new LettuceConnectionFactory();
factory2.setClientResources(LettuceTestClientResources.getSharedClientResources());
LettuceConnectionFactory factory2 = new LettuceConnectionFactory(new RedisStandaloneConfiguration(),
LettuceTestClientConfiguration.builder().build());
factory2.setDatabase(1);
factory2.afterPropertiesSet();
StringRedisConnection conn2 = new DefaultStringRedisConnection(factory2.getConnection());

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.data.redis.connection.lettuce;
import io.lettuce.core.AbstractRedisClient;
import io.lettuce.core.RedisClient;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;
@@ -24,14 +25,18 @@ import io.lettuce.core.cluster.api.sync.RedisAdvancedClusterCommands;
import io.lettuce.core.cluster.api.sync.RedisClusterCommands;
import io.lettuce.core.codec.StringCodec;
import java.io.Closeable;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import org.assertj.core.api.Assumptions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.data.redis.connection.lettuce.LettuceReactiveRedisConnection.ByteBufferCodec;
import org.springframework.data.redis.test.condition.RedisDetector;
import org.springframework.data.redis.test.extension.LettuceExtension;
@@ -97,37 +102,36 @@ public abstract class LettuceReactiveCommandsTestSupport {
List<Fixture> parameters = new ArrayList<>();
StandaloneConnectionProvider standaloneProvider = new StandaloneConnectionProvider(
extension.getInstance(RedisClient.class),
LettuceReactiveRedisConnection.CODEC);
extension.getInstance(RedisClient.class), LettuceReactiveRedisConnection.CODEC);
StandaloneConnectionProvider nativeConnectionProvider = new StandaloneConnectionProvider(
extension.getInstance(RedisClient.class),
StringCodec.UTF8);
extension.getInstance(RedisClient.class), StringCodec.UTF8);
StandaloneConnectionProvider nativeBinaryConnectionProvider = new StandaloneConnectionProvider(
extension.getInstance(RedisClient.class), ByteBufferCodec.INSTANCE);
parameters.add(
new Fixture(standaloneProvider, nativeConnectionProvider, nativeBinaryConnectionProvider, "Standalone"));
parameters.add(new Fixture(
new LettucePoolingConnectionProvider(standaloneProvider, LettucePoolingClientConfiguration.builder().build()),
nativeConnectionProvider, nativeBinaryConnectionProvider, "Pooling"));
/*parameters
.add(new Fixture(standaloneProvider, nativeConnectionProvider, nativeBinaryConnectionProvider, "Standalone"));*/
LettucePoolingClientConfiguration poolingClientConfiguration = LettucePoolingClientConfiguration.builder()
.shutdownQuietPeriod(Duration.ZERO).shutdownTimeout(Duration.ZERO).build();
parameters.add(new Fixture(new LettucePoolingConnectionProvider(standaloneProvider, poolingClientConfiguration),
new LettucePoolingConnectionProvider(nativeConnectionProvider, poolingClientConfiguration),
new LettucePoolingConnectionProvider(nativeBinaryConnectionProvider, poolingClientConfiguration), "Pooling"));
ClusterConnectionProvider clusterProvider = new ClusterConnectionProvider(
extension.getInstance(RedisClusterClient.class),
LettuceReactiveRedisConnection.CODEC);
extension.getInstance(RedisClusterClient.class), LettuceReactiveRedisConnection.CODEC);
ClusterConnectionProvider nativeClusterConnectionProvider = new ClusterConnectionProvider(
extension.getInstance(RedisClusterClient.class),
StringCodec.UTF8);
ClusterConnectionProvider nativeBinaryClusterConnectionProvider = new ClusterConnectionProvider(
extension.getInstance(RedisClusterClient.class), ByteBufferCodec.INSTANCE);
extension.getInstance(RedisClusterClient.class), StringCodec.UTF8);
ClusterConnectionProvider nativeBinaryClusterConnectionProvider = new ClusterConnectionProvider(
extension.getInstance(RedisClusterClient.class), ByteBufferCodec.INSTANCE);
parameters.add(new Fixture(clusterProvider, nativeClusterConnectionProvider,
nativeBinaryClusterConnectionProvider, "Cluster"));
parameters.add(new Fixture(new LettucePoolingConnectionProvider(clusterProvider, poolingClientConfiguration),
new LettucePoolingConnectionProvider(nativeClusterConnectionProvider, poolingClientConfiguration),
new LettucePoolingConnectionProvider(nativeBinaryClusterConnectionProvider, poolingClientConfiguration),
"Cluster"));
return parameters;
}
static class Fixture {
static class Fixture implements Closeable {
final LettuceConnectionProvider connectionProvider;
final LettuceConnectionProvider nativeConnectionProvider;
@@ -146,12 +150,34 @@ public abstract class LettuceReactiveCommandsTestSupport {
public String toString() {
return label;
}
@Override
public void close() throws IOException {
try {
if (connectionProvider instanceof DisposableBean) {
((DisposableBean) connectionProvider).destroy();
}
if (nativeConnectionProvider instanceof DisposableBean) {
((DisposableBean) nativeConnectionProvider).destroy();
}
if (nativeBinaryConnectionProvider instanceof DisposableBean) {
((DisposableBean) nativeBinaryConnectionProvider).destroy();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@BeforeEach
public void setUp() {
if (nativeConnectionProvider instanceof StandaloneConnectionProvider) {
AbstractRedisClient redisClient = ((RedisClientProvider) nativeConnectionProvider).getRedisClient();
if (redisClient instanceof RedisClient) {
nativeCommands = nativeConnectionProvider.getConnection(StatefulRedisConnection.class).sync();
nativeBinaryCommands = nativeBinaryConnectionProvider.getConnection(StatefulRedisConnection.class).sync();
@@ -160,11 +186,9 @@ public abstract class LettuceReactiveCommandsTestSupport {
Assumptions.assumeThat(RedisDetector.isClusterAvailable()).isTrue();
ClusterConnectionProvider clusterConnectionProvider = (ClusterConnectionProvider) nativeConnectionProvider;
nativeCommands = nativeConnectionProvider.getConnection(StatefulRedisClusterConnection.class).sync();
nativeBinaryCommands = nativeBinaryConnectionProvider.getConnection(StatefulRedisClusterConnection.class).sync();
this.connection = new LettuceReactiveRedisClusterConnection(connectionProvider,
clusterConnectionProvider.getRedisClient());
this.connection = new LettuceReactiveRedisClusterConnection(connectionProvider, (RedisClusterClient) redisClient);
}
}
@@ -181,6 +205,15 @@ public abstract class LettuceReactiveCommandsTestSupport {
if (nativeCommands instanceof RedisAdvancedClusterCommands) {
nativeConnectionProvider.release(((RedisAdvancedClusterCommands) nativeCommands).getStatefulConnection());
}
if (nativeBinaryCommands instanceof RedisCommands) {
nativeBinaryConnectionProvider.release(((RedisCommands) nativeBinaryCommands).getStatefulConnection());
}
if (nativeBinaryCommands instanceof RedisAdvancedClusterCommands) {
nativeBinaryConnectionProvider
.release(((RedisAdvancedClusterCommands) nativeBinaryCommands).getStatefulConnection());
}
}
if (connection != null) {

View File

@@ -558,7 +558,7 @@ public class LettuceReactiveZSetCommandsIntegrationTests extends LettuceReactive
@ParameterizedRedisTest // GH-2041
void zDiffShouldWorkCorrectly() {
assumeThat(connectionProvider).isInstanceOf(StandaloneConnectionProvider.class);
assumeThat(nativeCommands).isInstanceOf(io.lettuce.core.api.sync.RedisCommands.class);
nativeCommands.zadd(KEY_1, 1D, VALUE_1);
nativeCommands.zadd(KEY_1, 2D, VALUE_2);
@@ -584,7 +584,7 @@ public class LettuceReactiveZSetCommandsIntegrationTests extends LettuceReactive
@ParameterizedRedisTest // GH-2041
void zDiffStoreShouldWorkCorrectly() {
assumeThat(connectionProvider).isInstanceOf(StandaloneConnectionProvider.class);
assumeThat(nativeCommands).isInstanceOf(io.lettuce.core.api.sync.RedisCommands.class);
nativeCommands.zadd(KEY_1, 1D, VALUE_1);
nativeCommands.zadd(KEY_1, 2D, VALUE_2);
@@ -600,7 +600,7 @@ public class LettuceReactiveZSetCommandsIntegrationTests extends LettuceReactive
@ParameterizedRedisTest // GH-2042
void zInterShouldWorkCorrectly() {
assumeThat(connectionProvider).isInstanceOf(StandaloneConnectionProvider.class);
assumeThat(nativeCommands).isInstanceOf(io.lettuce.core.api.sync.RedisCommands.class);
nativeCommands.zadd(KEY_1, 1D, VALUE_1);
nativeCommands.zadd(KEY_1, 2D, VALUE_2);
@@ -626,7 +626,7 @@ public class LettuceReactiveZSetCommandsIntegrationTests extends LettuceReactive
@ParameterizedRedisTest // DATAREDIS-525
void zInterStoreShouldWorkCorrectly() {
assumeThat(connectionProvider).isInstanceOf(StandaloneConnectionProvider.class);
assumeThat(nativeCommands).isInstanceOf(io.lettuce.core.api.sync.RedisCommands.class);
nativeCommands.zadd(KEY_1, 1D, VALUE_1);
nativeCommands.zadd(KEY_1, 2D, VALUE_2);
@@ -642,7 +642,7 @@ public class LettuceReactiveZSetCommandsIntegrationTests extends LettuceReactive
@ParameterizedRedisTest // GH-2042
void zUnionShouldWorkCorrectly() {
assumeThat(connectionProvider).isInstanceOf(StandaloneConnectionProvider.class);
assumeThat(nativeCommands).isInstanceOf(io.lettuce.core.api.sync.RedisCommands.class);
nativeCommands.zadd(KEY_1, 1D, VALUE_1);
nativeCommands.zadd(KEY_1, 2D, VALUE_2);
@@ -669,7 +669,7 @@ public class LettuceReactiveZSetCommandsIntegrationTests extends LettuceReactive
@ParameterizedRedisTest // DATAREDIS-525
void zUnionStoreShouldWorkCorrectly() {
assumeThat(connectionProvider).isInstanceOf(StandaloneConnectionProvider.class);
assumeThat(nativeCommands).isInstanceOf(io.lettuce.core.api.sync.RedisCommands.class);
nativeCommands.zadd(KEY_1, 1D, VALUE_1);
nativeCommands.zadd(KEY_1, 2D, VALUE_2);

View File

@@ -28,7 +28,6 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.data.redis.ConnectionFactoryTracker;
import org.springframework.data.redis.connection.AbstractConnectionIntegrationTests;
import org.springframework.data.redis.connection.DefaultStringRedisConnection;
@@ -192,8 +191,7 @@ public class LettuceSentinelIntegrationTests extends AbstractConnectionIntegrati
@Test // DATAREDIS-576
void connectionAppliesClientName() {
LettuceClientConfiguration clientName = LettuceClientConfiguration.builder()
.clientResources(LettuceTestClientResources.getSharedClientResources()).clientName("clientName").build();
LettuceClientConfiguration clientName = LettuceTestClientConfiguration.builder().clientName("clientName").build();
LettuceConnectionFactory factory = new LettuceConnectionFactory(SENTINEL_CONFIG, clientName);
factory.afterPropertiesSet();

View File

@@ -34,14 +34,15 @@ public class LettuceTestClientConfiguration {
* @see LettuceTestClientResources#getSharedClientResources()
*/
public static LettuceClientConfigurationBuilder builder() {
return LettuceClientConfiguration.builder().shutdownTimeout(Duration.ZERO)
return LettuceClientConfiguration.builder().shutdownTimeout(Duration.ZERO).shutdownQuietPeriod(Duration.ZERO)
.clientResources(LettuceTestClientResources.getSharedClientResources());
}
/**
* @return a defaulted {@link LettuceClientConfiguration} for testing.
*/
public static LettuceClientConfiguration create() {
public static LettuceClientConfiguration defaultConfiguration() {
return builder().build();
}
}

View File

@@ -16,7 +16,9 @@
package org.springframework.data.redis.connection.lettuce.extension;
import java.io.Closeable;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
@@ -24,7 +26,6 @@ import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolutionException;
import org.junit.jupiter.api.extension.ParameterResolver;
import org.springframework.data.redis.ConnectionFactoryTracker;
import org.springframework.data.redis.SettingsUtils;
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
@@ -35,6 +36,7 @@ import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration.LettucePoolingClientConfigurationBuilder;
import org.springframework.data.redis.test.extension.LettuceTestClientResources;
import org.springframework.data.redis.test.extension.RedisCluster;
import org.springframework.data.redis.test.extension.RedisSentinel;
@@ -59,84 +61,87 @@ public class LettuceConnectionFactoryExtension implements ParameterResolver {
private static final Lazy<LettuceConnectionFactory> STANDALONE = Lazy.of(() -> {
LettuceClientConfiguration configuration = LettucePoolingClientConfiguration.builder()
.clientResources(LettuceTestClientResources.getSharedClientResources()).build();
LettuceClientConfiguration configuration = defaultPoolConfigBuilder().build();
ManagedLettuceConnectionFactory factory = new ManagedLettuceConnectionFactory(
SettingsUtils.standaloneConfiguration(),
configuration);
SettingsUtils.standaloneConfiguration(), configuration);
factory.afterPropertiesSet();
ShutdownQueue.register(factory.toCloseable());
ShutdownQueue.register(factory);
return factory;
});
private static final Lazy<LettuceConnectionFactory> SENTINEL = Lazy.of(() -> {
LettuceClientConfiguration configuration = LettucePoolingClientConfiguration.builder()
.clientResources(LettuceTestClientResources.getSharedClientResources()).build();
LettuceClientConfiguration configuration = defaultPoolConfigBuilder().build();
ManagedLettuceConnectionFactory factory = new ManagedLettuceConnectionFactory(SettingsUtils.sentinelConfiguration(),
configuration);
factory.afterPropertiesSet();
ShutdownQueue.register(factory.toCloseable());
ShutdownQueue.register(factory);
return factory;
});
private static final Lazy<LettuceConnectionFactory> CLUSTER = Lazy.of(() -> {
LettuceClientConfiguration configuration = LettucePoolingClientConfiguration.builder()
.clientResources(LettuceTestClientResources.getSharedClientResources()).build();
LettuceClientConfiguration configuration = defaultPoolConfigBuilder().build();
ManagedLettuceConnectionFactory factory = new ManagedLettuceConnectionFactory(SettingsUtils.clusterConfiguration(),
configuration);
factory.afterPropertiesSet();
ShutdownQueue.register(factory.toCloseable());
ShutdownQueue.register(factory);
return factory;
});
private static final Lazy<LettuceConnectionFactory> STANDALONE_UNPOOLED = Lazy.of(() -> {
LettuceClientConfiguration configuration = LettuceClientConfiguration.builder()
.clientResources(LettuceTestClientResources.getSharedClientResources()).build();
LettuceClientConfiguration configuration = defaultClientConfiguration();
ManagedLettuceConnectionFactory factory = new ManagedLettuceConnectionFactory(
SettingsUtils.standaloneConfiguration(),
configuration);
SettingsUtils.standaloneConfiguration(), configuration);
factory.afterPropertiesSet();
ShutdownQueue.register(factory.toCloseable());
ShutdownQueue.register(factory);
return factory;
});
private static final Lazy<LettuceConnectionFactory> SENTINEL_UNPOOLED = Lazy.of(() -> {
LettuceClientConfiguration configuration = LettuceClientConfiguration.builder()
.clientResources(LettuceTestClientResources.getSharedClientResources()).build();
LettuceClientConfiguration configuration = defaultClientConfiguration();
ManagedLettuceConnectionFactory factory = new ManagedLettuceConnectionFactory(SettingsUtils.sentinelConfiguration(),
configuration);
factory.afterPropertiesSet();
ShutdownQueue.register(factory.toCloseable());
ShutdownQueue.register(factory);
return factory;
});
private static final Lazy<LettuceConnectionFactory> CLUSTER_UNPOOLED = Lazy.of(() -> {
LettuceClientConfiguration configuration = LettuceClientConfiguration.builder()
.clientResources(LettuceTestClientResources.getSharedClientResources()).build();
LettuceClientConfiguration configuration = defaultClientConfiguration();
ManagedLettuceConnectionFactory factory = new ManagedLettuceConnectionFactory(SettingsUtils.clusterConfiguration(),
configuration);
factory.afterPropertiesSet();
ShutdownQueue.register(factory.toCloseable());
ShutdownQueue.register(factory);
return factory;
});
private static LettucePoolingClientConfigurationBuilder defaultPoolConfigBuilder() {
return LettucePoolingClientConfiguration.builder()
.clientResources(LettuceTestClientResources.getSharedClientResources()).shutdownTimeout(Duration.ZERO)
.shutdownQuietPeriod(Duration.ZERO);
}
private static LettuceClientConfiguration defaultClientConfiguration() {
return LettuceClientConfiguration.builder().clientResources(LettuceTestClientResources.getSharedClientResources())
.shutdownQuietPeriod(Duration.ZERO).shutdownQuietPeriod(Duration.ZERO).build();
}
private static final Map<Class<?>, Lazy<LettuceConnectionFactory>> pooledFactories;
private static final Map<Class<?>, Lazy<LettuceConnectionFactory>> unpooledFactories;
@@ -207,7 +212,7 @@ public class LettuceConnectionFactoryExtension implements ParameterResolver {
}
static class ManagedLettuceConnectionFactory extends LettuceConnectionFactory
implements ConnectionFactoryTracker.Managed {
implements ConnectionFactoryTracker.Managed, Closeable {
private volatile boolean mayClose;
@@ -257,15 +262,11 @@ public class LettuceConnectionFactoryExtension implements ParameterResolver {
return builder.toString();
}
Closeable toCloseable() {
return () -> {
try {
mayClose = true;
destroy();
} catch (Exception e) {
e.printStackTrace();
}
};
@Override
public void close() throws IOException {
mayClose = true;
destroy();
}
}
}

View File

@@ -15,18 +15,22 @@
*/
package org.springframework.data.redis.connection.lettuce.observability;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.SettingsUtils;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import io.lettuce.core.resource.ClientResources;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import io.micrometer.observation.ObservationRegistry;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.SettingsUtils;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.test.extension.ShutdownQueue;
/**
* @author Mark Paluch
*/
@@ -40,16 +44,21 @@ class TestConfig {
OBSERVATION_REGISTRY.observationConfig().observationHandler(new DefaultMeterObservationHandler(METER_REGISTRY));
}
@Bean(destroyMethod = "shutdown")
@Bean(destroyMethod = "timer")
ClientResources clientResources(ObservationRegistry observationRegistry) {
return ClientResources.builder().tracing(new MicrometerTracingAdapter(observationRegistry, "Redis", true))
.build();
ClientResources resources = ClientResources.builder()
.tracing(new MicrometerTracingAdapter(observationRegistry, "Redis", true)).build();
ShutdownQueue.register(() -> resources.shutdown(0, 0, TimeUnit.MILLISECONDS));
return resources;
}
@Bean
LettuceConnectionFactory connectionFactory(ClientResources clientResources) {
LettuceClientConfiguration clientConfiguration = LettuceClientConfiguration.builder()
.shutdownTimeout(Duration.ZERO).shutdownQuietPeriod(Duration.ZERO)
.clientResources(clientResources).build();
return new LettuceConnectionFactory(SettingsUtils.standaloneConfiguration(), clientConfiguration);

View File

@@ -29,7 +29,7 @@ import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.data.redis.DoubleObjectFactory;
import org.springframework.data.redis.ObjectFactory;
import org.springframework.data.redis.test.condition.EnabledIfLongRunningTest;
import org.springframework.data.redis.test.condition.EnabledOnCommand;
@@ -110,20 +110,20 @@ public class DefaultValueOperationsIntegrationTests<K, V> {
@ParameterizedRedisTest // DATAREDIS-247
void testIncrementDouble() {
assumeThat(valueFactory).isInstanceOf(DoubleObjectFactory.class);
K key = keyFactory.instance();
V value = valueFactory.instance();
Double value = (Double) valueFactory.instance();
assumeThat(value instanceof Double).isTrue();
valueOps.set(key, value);
valueOps.set(key, (V) value);
DecimalFormat twoDForm = (DecimalFormat) DecimalFormat.getInstance(Locale.US);
assertThat(valueOps.increment(key, 1.4)).isEqualTo(Double.valueOf(twoDForm.format((Double) value + 1.4)));
assertThat(valueOps.get(key)).isEqualTo(Double.valueOf(twoDForm.format((Double) value + 1.4)));
assertThat((Double) valueOps.get(key)).isBetween(value + 1.3, value + 1.4);
valueOps.increment(key, -10d);
assertThat(valueOps.get(key)).isEqualTo(Double.valueOf(twoDForm.format((Double) value + 1.4 - 10d)));
assertThat((Double) valueOps.get(key)).isBetween(value + 1.3 - 10, value + 1.4 - 10);
}
@ParameterizedRedisTest // DATAREDIS-784

View File

@@ -39,6 +39,8 @@ class EnabledOnCommandCondition implements ExecutionCondition {
private static final ConditionEvaluationResult ENABLED_BY_DEFAULT = enabled("@EnabledOnCommand is not present");
private static final ExtensionContext.Namespace NAMESPACE = ExtensionContext.Namespace.create(RedisConditions.class);
private final LettuceExtension lettuceExtension = new LettuceExtension();
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
@@ -51,11 +53,12 @@ class EnabledOnCommandCondition implements ExecutionCondition {
String command = optional.get().value();
ExtensionContext.Store store = context.getStore(NAMESPACE);
ExtensionContext.Store store = context.getRoot().getStore(NAMESPACE);
RedisConditions conditions = store.getOrComputeIfAbsent(RedisConditions.class, ignore -> {
StatefulRedisConnection connection = new LettuceExtension().resolve(context, StatefulRedisConnection.class);
return RedisConditions.of(connection);
try (StatefulRedisConnection connection = lettuceExtension.resolve(context, StatefulRedisConnection.class)) {
return RedisConditions.of(connection);
}
}, RedisConditions.class);
boolean hasCommand = conditions.hasCommand(command);

View File

@@ -36,8 +36,9 @@ import org.springframework.data.redis.test.extension.LettuceExtension;
class EnabledOnRedisVersionCondition implements ExecutionCondition {
private static final ConditionEvaluationResult ENABLED_BY_DEFAULT = enabled("@EnabledOnVersion is not present");
private static final ExtensionContext.Namespace NAMESPACE = ExtensionContext.Namespace
.create(EnabledOnRedisVersionCondition.class);
private static final ExtensionContext.Namespace NAMESPACE = ExtensionContext.Namespace.create(RedisConditions.class);
private final LettuceExtension lettuceExtension = new LettuceExtension();
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
@@ -52,11 +53,12 @@ class EnabledOnRedisVersionCondition implements ExecutionCondition {
String requiredVersion = optional.get().value();
ExtensionContext.Store store = context.getStore(NAMESPACE);
ExtensionContext.Store store = context.getRoot().getStore(NAMESPACE);
RedisConditions conditions = store.getOrComputeIfAbsent(RedisConditions.class, ignore -> {
StatefulRedisConnection connection = new LettuceExtension().resolve(context, StatefulRedisConnection.class);
return RedisConditions.of(connection);
try (StatefulRedisConnection connection = lettuceExtension.resolve(context, StatefulRedisConnection.class)) {
return RedisConditions.of(connection);
}
}, RedisConditions.class);
boolean versionMet = conditions.hasVersionGreaterOrEqualsTo(requiredVersion);

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.data.redis.test.extension;
import io.lettuce.core.AbstractRedisClient;
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.StatefulConnection;
@@ -27,6 +28,8 @@ import io.lettuce.core.protocol.ProtocolVersion;
import io.lettuce.core.pubsub.StatefulRedisPubSubConnection;
import io.lettuce.core.resource.ClientResources;
import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.util.Arrays;
@@ -48,7 +51,6 @@ import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolutionException;
import org.junit.jupiter.api.extension.ParameterResolver;
import org.springframework.core.ResolvableType;
import org.springframework.data.redis.SettingsUtils;
import org.springframework.data.util.Lazy;
@@ -80,7 +82,7 @@ import org.springframework.data.util.Lazy;
*
* <h3>Resource lifecycle</h3> This extension allocates resources lazily and stores them in its {@link ExtensionContext}
* {@link ExtensionContext.Store} for reuse across multiple tests. Client and {@link ClientResources} are allocated
* through{@link DefaultRedisClient} respective {@link TestClientResources} so shutdown is managed by the actual
* through default {@link RedisClient} respective {@link RedisClientSupplier} so shutdown is managed by the actual
* suppliers. Singleton connection resources are closed after the test class (test container) is finished.
*
* @author Mark Paluch
@@ -142,6 +144,17 @@ public class LettuceExtension implements ParameterResolver, AfterAllCallback, Af
return store.getOrComputeIfAbsent(parameter.getType(), it -> doGetInstance(parameterizedType));
}
@Override
public void afterEach(ExtensionContext context) {
ExtensionContext.Store store = getStore(context);
RedisClient redisClient = store.get(RedisClient.class, RedisClient.class);
if (redisClient != null) {
redisClient.setOptions(DEFAULT_OPTIONS);
}
}
@Override
public void afterAll(ExtensionContext context) {
@@ -158,17 +171,6 @@ public class LettuceExtension implements ParameterResolver, AfterAllCallback, Af
});
}
@Override
public void afterEach(ExtensionContext context) {
ExtensionContext.Store store = getStore(context);
RedisClient redisClient = store.get(RedisClient.class, RedisClient.class);
if (redisClient != null) {
redisClient.setOptions(DEFAULT_OPTIONS);
}
}
@SuppressWarnings("unchecked")
private static Supplier<Object> findSupplier(Type type) {
@@ -238,16 +240,25 @@ public class LettuceExtension implements ParameterResolver, AfterAllCallback, Af
}
}
record RedisClientCloseable(AbstractRedisClient client) implements Closeable {
@Override
public void close() throws IOException {
client.shutdown(0, 0, TimeUnit.MILLISECONDS);
}
}
enum RedisClientSupplier implements Supplier<RedisClient> {
INSTANCE;
final Lazy<RedisClient> lazy = Lazy.of(() -> {
RedisClient client = RedisClient.create(ClientResourcesSupplier.INSTANCE.get(),
RedisClient client = RedisClient.create(LettuceTestClientResources.getSharedClientResources(),
RedisURI.create(SettingsUtils.getHost(), SettingsUtils.getPort()));
client.setOptions(DEFAULT_OPTIONS);
ShutdownQueue.register(() -> client.shutdown(0, 0, TimeUnit.MILLISECONDS));
ShutdownQueue.register(new RedisClientCloseable(client));
return client;
});
@@ -262,11 +273,11 @@ public class LettuceExtension implements ParameterResolver, AfterAllCallback, Af
INSTANCE;
final Lazy<RedisClusterClient> lazy = Lazy.of(() -> {
RedisClusterClient client = RedisClusterClient.create(ClientResourcesSupplier.INSTANCE.get(),
RedisClusterClient client = RedisClusterClient.create(LettuceTestClientResources.getSharedClientResources(),
RedisURI.create(SettingsUtils.getHost(), SettingsUtils.getClusterPort()));
client.setOptions(DEFAULT_OPTIONS);
ShutdownQueue.register(() -> client.shutdown(0, 0, TimeUnit.MILLISECONDS));
ShutdownQueue.register(new RedisClientCloseable(client));
return client;
});

View File

@@ -21,8 +21,12 @@ import io.lettuce.core.resource.ClientResources;
import io.lettuce.core.resource.DefaultClientResources;
import reactor.core.publisher.Flux;
import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import org.springframework.core.Ordered;
/**
* Client-Resources suitable for testing. Every time a new {@link LettuceTestClientResources} instance is created, a
* {@link Runtime#addShutdownHook(Thread) shutdown hook} is added to close the client resources.
@@ -36,7 +40,13 @@ public class LettuceTestClientResources {
static {
SHARED_CLIENT_RESOURCES = DefaultClientResources.builder().eventBus(new EventBus() {
SHARED_CLIENT_RESOURCES = newClientResources();
ShutdownQueue.register(new SharedClientResources(SHARED_CLIENT_RESOURCES));
}
private static ClientResources newClientResources() {
return DefaultClientResources.builder().ioThreadPoolSize(4).computationThreadPoolSize(4).eventBus(new EventBus() {
@Override
public Flux<Event> get() {
return Flux.empty();
@@ -46,9 +56,7 @@ public class LettuceTestClientResources {
public void publish(Event event) {
}
})
.build();
ShutdownQueue.INSTANCE.register(() -> SHARED_CLIENT_RESOURCES.shutdown(0, 0, TimeUnit.MILLISECONDS));
}).build();
}
private LettuceTestClientResources() {}
@@ -59,4 +67,22 @@ public class LettuceTestClientResources {
public static ClientResources getSharedClientResources() {
return SHARED_CLIENT_RESOURCES;
}
static class SharedClientResources implements Ordered, Closeable {
private final ClientResources clientResources;
public SharedClientResources(ClientResources clientResources) {
this.clientResources = clientResources;
}
@Override
public void close() throws IOException {
clientResources.shutdown(0, 0, TimeUnit.MILLISECONDS);
}
@Override
public int getOrder() {
return HIGHEST_PRECEDENCE;
}
}
}

View File

@@ -20,6 +20,8 @@ import redis.clients.jedis.util.IOUtils;
import java.io.Closeable;
import java.util.LinkedList;
import org.springframework.core.OrderComparator;
/**
* Shutdown queue allowing ordered resource shutdown (LIFO).
*
@@ -31,22 +33,23 @@ public enum ShutdownQueue {
static {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
Runtime.getRuntime().addShutdownHook(new Thread(ShutdownQueue::close));
}
Closeable closeable;
while ((closeable = INSTANCE.closeables.pollLast()) != null) {
try {
closeable.close();
} catch (Exception o_O) {
// ignore
o_O.printStackTrace();
}
}
private static void close() {
Closeable closeable;
OrderComparator.sort(INSTANCE.closeables);
while ((closeable = INSTANCE.closeables.pollLast()) != null) {
try {
closeable.close();
} catch (Exception o_O) {
// ignore
o_O.printStackTrace();
}
});
}
}
private final LinkedList<Closeable> closeables = new LinkedList<>();
@@ -58,4 +61,5 @@ public enum ShutdownQueue {
public static void register(AutoCloseable closeable) {
INSTANCE.closeables.add(() -> IOUtils.closeQuietly(closeable));
}
}

View File

@@ -18,11 +18,15 @@ package org.springframework.data.redis.test.extension.parametrized;
import static java.lang.String.*;
import static org.junit.jupiter.params.provider.Arguments.*;
import java.io.Closeable;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.stream.Stream;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
import org.junit.jupiter.api.extension.ExtensionContext.Store;
import org.junit.jupiter.api.extension.ExtensionContext.Store.CloseableResource;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider;
import org.junit.jupiter.params.support.AnnotationConsumer;
@@ -31,12 +35,14 @@ import org.junit.platform.commons.util.CollectionUtils;
import org.junit.platform.commons.util.Preconditions;
import org.junit.platform.commons.util.ReflectionUtils;
import org.junit.platform.commons.util.StringUtils;
import org.springframework.data.redis.ConnectionFactoryTracker.Managed;
/**
* Copy of {@code org.junit.jupiter.params.provider.MethodArgumentsProvider}.
*/
class MethodArgumentsProvider implements ArgumentsProvider, AnnotationConsumer<MethodSource> {
private final static Namespace NAMESPACE = Namespace.create(MethodArgumentsProvider.class);
private String[] methodNames = new String[0];
@Override
@@ -46,12 +52,14 @@ class MethodArgumentsProvider implements ArgumentsProvider, AnnotationConsumer<M
@Override
public Stream<Arguments> provideArguments(ExtensionContext context) {
Store store = context.getRoot().getStore(NAMESPACE);
Object testInstance = context.getTestInstance().orElse(null);
// @formatter:off
return Arrays.stream(this.methodNames).map(factoryMethodName -> getMethod(context, factoryMethodName))
.map(method -> ReflectionUtils.invokeMethod(method, testInstance)).flatMap(CollectionUtils::toStream)
.map(method -> (CloseablePararmeters) store.getOrComputeIfAbsent(new SourceKey(method, testInstance),
key -> new CloseablePararmeters(ReflectionUtils.invokeMethod(method, testInstance), context)))
.map(CloseablePararmeters::parameters).flatMap(CollectionUtils::toStream)
.map(MethodArgumentsProvider::toArguments);
// @formatter:on
}
private Method getMethod(ExtensionContext context, String factoryMethodName) {
@@ -105,4 +113,64 @@ class MethodArgumentsProvider implements ArgumentsProvider, AnnotationConsumer<M
return arguments(item);
}
/**
* Key type for a method associated with a test instance.
*
* @param method
* @param instance
*/
record SourceKey(Method method, Object instance) {
}
/**
* Holder for parameters that can be closed using JUnit's built-in cleanup mechanism.
*
* @param parameters
* @param context
*/
record CloseablePararmeters(Object parameters, Object context) implements Store.CloseableResource {
@Override
public void close() {
close0(parameters);
}
private void close0(Object object) {
if (object instanceof Managed) {
return;
}
if (object instanceof CloseableResource) {
try {
((CloseableResource) object).close();
} catch (Throwable e) {
throw new RuntimeException(e);
}
return;
}
if (object instanceof Closeable) {
try {
((AutoCloseable) object).close();
} catch (Throwable e) {
throw new RuntimeException(e);
}
return;
}
if (object instanceof Arguments) {
close0(((Arguments) object).get());
}
if (object instanceof Object[]) {
Arrays.asList((Object[]) object).forEach(this::close0);
}
if (object instanceof Iterable<?>) {
((Iterable<Object>) object).forEach(this::close0);
}
}
}
}