From 5e2b668dccbf185aa55161f6cb2fda813fd14f5b Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 9 May 2023 15:07:08 +0200 Subject: [PATCH] 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 --- .../jedis/JedisClusterConnectionTests.java | 3 +- .../JedisConnectionFactoryExtension.java | 27 ++-- .../lettuce/LettuceAclIntegrationTests.java | 4 +- .../LettuceClusterConnectionTests.java | 2 +- .../LettuceConnectionFactoryTests.java | 19 +-- .../LettuceConnectionFactoryUnitTests.java | 143 ++++++++---------- ...uceConnectionPipelineIntegrationTests.java | 7 +- .../LettuceReactiveCommandsTestSupport.java | 79 +++++++--- ...eReactiveZSetCommandsIntegrationTests.java | 12 +- .../LettuceSentinelIntegrationTests.java | 4 +- .../LettuceTestClientConfiguration.java | 5 +- .../LettuceConnectionFactoryExtension.java | 67 ++++---- .../lettuce/observability/TestConfig.java | 27 ++-- ...efaultValueOperationsIntegrationTests.java | 14 +- .../condition/EnabledOnCommandCondition.java | 9 +- .../EnabledOnRedisVersionCondition.java | 12 +- .../test/extension/LettuceExtension.java | 45 +++--- .../extension/LettuceTestClientResources.java | 34 ++++- .../redis/test/extension/ShutdownQueue.java | 30 ++-- .../parametrized/MethodArgumentsProvider.java | 74 ++++++++- 20 files changed, 376 insertions(+), 241 deletions(-) diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisClusterConnectionTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisClusterConnectionTests.java index b0469ffc8..78ffeb756 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisClusterConnectionTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisClusterConnectionTests.java @@ -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())) { diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/extension/JedisConnectionFactoryExtension.java b/src/test/java/org/springframework/data/redis/connection/jedis/extension/JedisConnectionFactoryExtension.java index 133a903f0..bba8ce1fb 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/extension/JedisConnectionFactoryExtension.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/extension/JedisConnectionFactoryExtension.java @@ -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(); + } } } } diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceAclIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceAclIntegrationTests.java index 7eec02fcb..612ed0919 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceAclIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceAclIntegrationTests.java @@ -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", diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java index 0f2ad5154..59f5bc608 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java @@ -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(); diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryTests.java index fea1ebb1b..1be106f79 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryTests.java @@ -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); diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryUnitTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryUnitTests.java index 529942d31..2c8356b34 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryUnitTests.java @@ -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); diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineIntegrationTests.java index fb803caa4..8fc9e52cc 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineIntegrationTests.java @@ -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()); diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveCommandsTestSupport.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveCommandsTestSupport.java index e34612a3b..1ba37c1c4 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveCommandsTestSupport.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveCommandsTestSupport.java @@ -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 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) { diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommandsIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommandsIntegrationTests.java index 11638caac..040216b0d 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommandsIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommandsIntegrationTests.java @@ -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); diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelIntegrationTests.java index c983dd8a5..539138169 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelIntegrationTests.java @@ -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(); diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceTestClientConfiguration.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceTestClientConfiguration.java index 6c48d123f..504ffec79 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceTestClientConfiguration.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceTestClientConfiguration.java @@ -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(); } + } diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/extension/LettuceConnectionFactoryExtension.java b/src/test/java/org/springframework/data/redis/connection/lettuce/extension/LettuceConnectionFactoryExtension.java index d9ec302e2..b11dfed22 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/extension/LettuceConnectionFactoryExtension.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/extension/LettuceConnectionFactoryExtension.java @@ -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 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 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 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 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 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 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, Lazy> pooledFactories; private static final Map, Lazy> 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(); } } } diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/observability/TestConfig.java b/src/test/java/org/springframework/data/redis/connection/lettuce/observability/TestConfig.java index dc9802f86..d6def0d93 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/observability/TestConfig.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/observability/TestConfig.java @@ -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); diff --git a/src/test/java/org/springframework/data/redis/core/DefaultValueOperationsIntegrationTests.java b/src/test/java/org/springframework/data/redis/core/DefaultValueOperationsIntegrationTests.java index f0716130b..d45e3ec13 100644 --- a/src/test/java/org/springframework/data/redis/core/DefaultValueOperationsIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/core/DefaultValueOperationsIntegrationTests.java @@ -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 { @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 diff --git a/src/test/java/org/springframework/data/redis/test/condition/EnabledOnCommandCondition.java b/src/test/java/org/springframework/data/redis/test/condition/EnabledOnCommandCondition.java index 49bf4d394..d2f28c293 100644 --- a/src/test/java/org/springframework/data/redis/test/condition/EnabledOnCommandCondition.java +++ b/src/test/java/org/springframework/data/redis/test/condition/EnabledOnCommandCondition.java @@ -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); diff --git a/src/test/java/org/springframework/data/redis/test/condition/EnabledOnRedisVersionCondition.java b/src/test/java/org/springframework/data/redis/test/condition/EnabledOnRedisVersionCondition.java index 5fa92eb9c..5a082873b 100644 --- a/src/test/java/org/springframework/data/redis/test/condition/EnabledOnRedisVersionCondition.java +++ b/src/test/java/org/springframework/data/redis/test/condition/EnabledOnRedisVersionCondition.java @@ -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); diff --git a/src/test/java/org/springframework/data/redis/test/extension/LettuceExtension.java b/src/test/java/org/springframework/data/redis/test/extension/LettuceExtension.java index ab5416bcc..1c7018765 100644 --- a/src/test/java/org/springframework/data/redis/test/extension/LettuceExtension.java +++ b/src/test/java/org/springframework/data/redis/test/extension/LettuceExtension.java @@ -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; * *

Resource lifecycle

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 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 { INSTANCE; final Lazy 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 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; }); diff --git a/src/test/java/org/springframework/data/redis/test/extension/LettuceTestClientResources.java b/src/test/java/org/springframework/data/redis/test/extension/LettuceTestClientResources.java index 88a85785d..03a0c396f 100644 --- a/src/test/java/org/springframework/data/redis/test/extension/LettuceTestClientResources.java +++ b/src/test/java/org/springframework/data/redis/test/extension/LettuceTestClientResources.java @@ -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 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; + } + } } diff --git a/src/test/java/org/springframework/data/redis/test/extension/ShutdownQueue.java b/src/test/java/org/springframework/data/redis/test/extension/ShutdownQueue.java index 7251e9553..2841216c3 100644 --- a/src/test/java/org/springframework/data/redis/test/extension/ShutdownQueue.java +++ b/src/test/java/org/springframework/data/redis/test/extension/ShutdownQueue.java @@ -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 closeables = new LinkedList<>(); @@ -58,4 +61,5 @@ public enum ShutdownQueue { public static void register(AutoCloseable closeable) { INSTANCE.closeables.add(() -> IOUtils.closeQuietly(closeable)); } + } diff --git a/src/test/java/org/springframework/data/redis/test/extension/parametrized/MethodArgumentsProvider.java b/src/test/java/org/springframework/data/redis/test/extension/parametrized/MethodArgumentsProvider.java index 89b5700da..b0306ca6a 100644 --- a/src/test/java/org/springframework/data/redis/test/extension/parametrized/MethodArgumentsProvider.java +++ b/src/test/java/org/springframework/data/redis/test/extension/parametrized/MethodArgumentsProvider.java @@ -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 { + 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 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) { + ((Iterable) object).forEach(this::close0); + } + } + } + }