Add configuration for TaskExecutor used by ClusterCommandsExecutor.
This change allows users to leverage the VirtualThread facilities and AsyncTaskExecutor implementations provided in and by the core Spring Framework as part of our Loom support theme. Closes #2594 Original pull request: #2669
This commit is contained in:
@@ -15,12 +15,16 @@
|
||||
*/
|
||||
package org.springframework.data.redis.connection.jedis;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import redis.clients.jedis.JedisClientConfig;
|
||||
import redis.clients.jedis.JedisCluster;
|
||||
import redis.clients.jedis.JedisPoolConfig;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
@@ -33,15 +37,25 @@ import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.data.redis.connection.ClusterCommandExecutor;
|
||||
import org.springframework.data.redis.connection.ClusterTopologyProvider;
|
||||
import org.springframework.data.redis.connection.RedisClusterConfiguration;
|
||||
import org.springframework.data.redis.connection.RedisPassword;
|
||||
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
|
||||
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory.State;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
|
||||
|
||||
import redis.clients.jedis.JedisClientConfig;
|
||||
import redis.clients.jedis.JedisCluster;
|
||||
import redis.clients.jedis.JedisPoolConfig;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link JedisConnectionFactory}.
|
||||
*
|
||||
@@ -335,24 +349,59 @@ class JedisConnectionFactoryUnitTests {
|
||||
assertThat(connectionFactory.isRunning()).isTrue();
|
||||
}
|
||||
|
||||
private JedisConnectionFactory initSpyedConnectionFactory(RedisSentinelConfiguration sentinelConfig,
|
||||
JedisPoolConfig poolConfig) {
|
||||
@Test // GH-2594
|
||||
void configuresCustomTaskExecutorCorrectly() {
|
||||
|
||||
AsyncTaskExecutor mockTaskExecutor = mock(AsyncTaskExecutor.class);
|
||||
ClusterTopologyProvider mockClusterTopologyProvider = mock(ClusterTopologyProvider.class);
|
||||
JedisCluster mockJedisCluster = mock(JedisCluster.class);
|
||||
|
||||
RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration();
|
||||
|
||||
clusterConfiguration.setAsyncTaskExecutor(mockTaskExecutor);
|
||||
|
||||
JedisConnectionFactory connectionFactory = initSpyedConnectionFactory(clusterConfiguration, null);
|
||||
|
||||
doReturn(false).when(connectionFactory).getUsePool();
|
||||
doReturn(mockJedisCluster).when(connectionFactory).createCluster();
|
||||
doReturn(mockClusterTopologyProvider).when(connectionFactory).createTopologyProvider(eq(mockJedisCluster));
|
||||
|
||||
connectionFactory.start();
|
||||
|
||||
assertThat(connectionFactory.isRunning()).isTrue();
|
||||
|
||||
ClusterCommandExecutor clusterCommandExecutor = connectionFactory.getClusterCommandExecutor();
|
||||
|
||||
assertThat(clusterCommandExecutor).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(clusterCommandExecutor, "executor")).isEqualTo(mockTaskExecutor);
|
||||
}
|
||||
|
||||
private JedisConnectionFactory initSpyedConnectionFactory(RedisSentinelConfiguration sentinelConfiguration,
|
||||
@Nullable JedisPoolConfig poolConfig) {
|
||||
|
||||
// we have to use a spy here as jedis would start connecting to redis sentinels when the pool is created.
|
||||
JedisConnectionFactory factorySpy = spy(new JedisConnectionFactory(sentinelConfig, poolConfig));
|
||||
doReturn(null).when(factorySpy).createRedisSentinelPool(any(RedisSentinelConfiguration.class));
|
||||
doReturn(null).when(factorySpy).createRedisPool();
|
||||
return factorySpy;
|
||||
JedisConnectionFactory connectionFactorySpy = spy(new JedisConnectionFactory(sentinelConfiguration, poolConfig));
|
||||
|
||||
doReturn(null).when(connectionFactorySpy)
|
||||
.createRedisSentinelPool(any(RedisSentinelConfiguration.class));
|
||||
|
||||
doReturn(null).when(connectionFactorySpy).createRedisPool();
|
||||
|
||||
return connectionFactorySpy;
|
||||
}
|
||||
|
||||
private JedisConnectionFactory initSpyedConnectionFactory(RedisClusterConfiguration clusterConfig,
|
||||
JedisPoolConfig poolConfig) {
|
||||
private JedisConnectionFactory initSpyedConnectionFactory(RedisClusterConfiguration clusterConfiguration,
|
||||
@Nullable JedisPoolConfig poolConfig) {
|
||||
|
||||
JedisCluster clusterMock = mock(JedisCluster.class);
|
||||
JedisConnectionFactory factorySpy = spy(new JedisConnectionFactory(clusterConfig));
|
||||
doReturn(clusterMock).when(factorySpy).createCluster(any(RedisClusterConfiguration.class),
|
||||
any(GenericObjectPoolConfig.class));
|
||||
doReturn(null).when(factorySpy).createRedisPool();
|
||||
return factorySpy;
|
||||
|
||||
JedisConnectionFactory connectionFactorySpy = spy(new JedisConnectionFactory(clusterConfiguration, poolConfig));
|
||||
|
||||
doReturn(clusterMock).when(connectionFactorySpy)
|
||||
.createCluster(any(RedisClusterConfiguration.class), any(GenericObjectPoolConfig.class));
|
||||
|
||||
doReturn(null).when(connectionFactorySpy).createRedisPool();
|
||||
|
||||
return connectionFactorySpy;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,12 +15,15 @@
|
||||
*/
|
||||
package org.springframework.data.redis.connection.lettuce;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.*;
|
||||
import static org.springframework.data.redis.connection.RedisConfiguration.*;
|
||||
import static org.springframework.data.redis.test.extension.LettuceTestClientResources.*;
|
||||
import static org.springframework.test.util.ReflectionTestUtils.*;
|
||||
import static org.springframework.data.redis.connection.ClusterTestVariables.CLUSTER_NODE_1;
|
||||
import static org.springframework.data.redis.connection.RedisConfiguration.WithHostAndPort;
|
||||
import static org.springframework.data.redis.test.extension.LettuceTestClientResources.getSharedClientResources;
|
||||
import static org.springframework.test.util.ReflectionTestUtils.getField;
|
||||
|
||||
import io.lettuce.core.AbstractRedisClient;
|
||||
import io.lettuce.core.ClientOptions;
|
||||
@@ -43,6 +46,7 @@ import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
@@ -50,8 +54,10 @@ import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.data.redis.ConnectionFactoryTracker;
|
||||
import org.springframework.data.redis.RedisConnectionFailureException;
|
||||
import org.springframework.data.redis.connection.ClusterCommandExecutor;
|
||||
import org.springframework.data.redis.connection.PoolException;
|
||||
import org.springframework.data.redis.connection.RedisClusterConfiguration;
|
||||
import org.springframework.data.redis.connection.RedisClusterConnection;
|
||||
@@ -63,9 +69,6 @@ import org.springframework.data.redis.connection.RedisSentinelConfiguration;
|
||||
import org.springframework.data.redis.connection.RedisSocketConfiguration;
|
||||
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
|
||||
import org.springframework.data.redis.test.extension.LettuceTestClientResources;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link LettuceConnectionFactory}.
|
||||
@@ -823,7 +826,7 @@ class LettuceConnectionFactoryUnitTests {
|
||||
ConnectionFactoryTracker.add(connectionFactory);
|
||||
|
||||
RedisClusterConnection clusterConnection = connectionFactory.getClusterConnection();
|
||||
assertThat(ReflectionTestUtils.getField(clusterConnection, "timeout")).isEqualTo(2000L);
|
||||
assertThat(getField(clusterConnection, "timeout")).isEqualTo(2000L);
|
||||
|
||||
clusterConnection.close();
|
||||
}
|
||||
@@ -839,7 +842,7 @@ class LettuceConnectionFactoryUnitTests {
|
||||
ConnectionFactoryTracker.add(connectionFactory);
|
||||
|
||||
RedisClusterConnection clusterConnection = connectionFactory.getClusterConnection();
|
||||
assertThat(ReflectionTestUtils.getField(clusterConnection, "timeout")).isEqualTo(2000L);
|
||||
assertThat(getField(clusterConnection, "timeout")).isEqualTo(2000L);
|
||||
|
||||
clusterConnection.close();
|
||||
}
|
||||
@@ -1250,8 +1253,8 @@ class LettuceConnectionFactoryUnitTests {
|
||||
.withNoCause());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createRedisConfigurationWithValidRedisUriString() {
|
||||
@Test // GH-2594
|
||||
void createRedisConfigurationWithValidRedisUriString() {
|
||||
|
||||
RedisConfiguration redisConfiguration =
|
||||
LettuceConnectionFactory.createRedisConfiguration("redis://skullbox:6789");
|
||||
@@ -1269,6 +1272,31 @@ class LettuceConnectionFactoryUnitTests {
|
||||
.isEqualTo(6789);
|
||||
}
|
||||
|
||||
@Test // GH-2594
|
||||
void configuresCustomTaskExecutorCorrectly() {
|
||||
|
||||
AsyncTaskExecutor mockTaskExecutor = mock(AsyncTaskExecutor.class);
|
||||
LettuceConnectionProvider mockConnectionProvider = mock(LettuceConnectionProvider.class);
|
||||
RedisClusterClient mockRedisClient = mock(RedisClusterClient.class);
|
||||
|
||||
RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration();
|
||||
|
||||
clusterConfiguration.setAsyncTaskExecutor(mockTaskExecutor);
|
||||
|
||||
LettuceConnectionFactory connectionFactory = spy(new LettuceConnectionFactory(clusterConfiguration));
|
||||
|
||||
doReturn(mockRedisClient).when(connectionFactory).createClient();
|
||||
doReturn(mockConnectionProvider).when(connectionFactory).createConnectionProvider(eq(mockRedisClient), any());
|
||||
|
||||
connectionFactory.start();
|
||||
|
||||
assertThat(connectionFactory.isRunning()).isTrue();
|
||||
|
||||
ClusterCommandExecutor clusterCommandExecutor = connectionFactory.getClusterCommandExecutor();
|
||||
|
||||
assertThat(getField(clusterCommandExecutor, "executor")).isEqualTo(mockTaskExecutor);
|
||||
}
|
||||
|
||||
static class CustomRedisConfiguration implements RedisConfiguration, WithHostAndPort {
|
||||
|
||||
private String hostName;
|
||||
|
||||
Reference in New Issue
Block a user