diff --git a/pom.xml b/pom.xml
index fdfcb2ad02..c39aaa1bab 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.data
spring-data-redis
- 1.7.0.BUILD-SNAPSHOT
+ 1.7.0.DATAREDIS-462-SNAPSHOT
Spring Data Redis
diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePool.java b/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePool.java
index 14d7340cab..c1293bdee3 100644
--- a/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePool.java
+++ b/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePool.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2015 the original author or authors.
+ * Copyright 2013-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
import java.util.concurrent.TimeUnit;
+import com.lambdaworks.redis.resource.ClientResources;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
@@ -50,6 +51,7 @@ public class DefaultLettucePool implements LettucePool, InitializingBean {
private String password;
private long timeout = TimeUnit.MILLISECONDS.convert(60, TimeUnit.SECONDS);
private RedisSentinelConfiguration sentinelConfiguration;
+ private ClientResources clientResources;
/**
* Constructs a new DefaultLettucePool
instance with default settings.
@@ -101,7 +103,14 @@ public boolean isRedisSentinelAware() {
@SuppressWarnings({ "rawtypes" })
public void afterPropertiesSet() {
- this.client = new RedisClient(getRedisURI());
+
+ if(clientResources != null) {
+ this.client = RedisClient.create(clientResources, getRedisURI());
+ }
+ else {
+ this.client = RedisClient.create(getRedisURI());
+ }
+
client.setDefaultTimeout(timeout, TimeUnit.MILLISECONDS);
this.internalPool = new GenericObjectPool(new LettuceFactory(client, dbIndex), poolConfig);
}
@@ -273,6 +282,24 @@ public void setTimeout(long timeout) {
this.timeout = timeout;
}
+ /**
+ * Returns the client resources to reuse the client infrastructure.
+ * @return client resources
+ * @since 1.7
+ */
+ public ClientResources getClientResources() {
+ return clientResources;
+ }
+
+ /**
+ * Sets the client resources to reuse the client infrastructure.
+ * @param clientResources
+ * @since 1.7
+ */
+ public void setClientResources(ClientResources clientResources) {
+ this.clientResources = clientResources;
+ }
+
@SuppressWarnings("rawtypes")
private static class LettuceFactory extends BasePooledObjectFactory {
diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java
index 0915bf59c5..2b14ab961b 100644
--- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java
+++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java
@@ -20,6 +20,7 @@
import java.util.List;
import java.util.concurrent.TimeUnit;
+import com.lambdaworks.redis.resource.ClientResources;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.DisposableBean;
@@ -94,6 +95,7 @@ public class LettuceConnectionFactory implements InitializingBean, DisposableBea
private RedisSentinelConfiguration sentinelConfiguration;
private RedisClusterConfiguration clusterConfiguration;
private ClusterCommandExecutor clusterCommandExecutor;
+ private ClientResources clientResources;
/**
* Constructs a new LettuceConnectionFactory
instance with default settings.
@@ -377,6 +379,24 @@ public void setPassword(String password) {
this.password = password;
}
+ /**
+ * Returns the client resources to reuse the client infrastructure.
+ * @return client resources
+ * @since 1.7
+ */
+ public ClientResources getClientResources() {
+ return clientResources;
+ }
+
+ /**
+ * Sets the client resources to reuse the client infrastructure.
+ * @param clientResources
+ * @since 1.7
+ */
+ public void setClientResources(ClientResources clientResources) {
+ this.clientResources = clientResources;
+ }
+
/**
* Returns the shutdown timeout for shutting down the RedisClient (in milliseconds).
*
@@ -458,7 +478,11 @@ private AbstractRedisClient createRedisClient() {
if (isRedisSentinelAware()) {
RedisURI redisURI = getSentinelRedisURI();
- return new RedisClient(redisURI);
+ if(clientResources == null) {
+ return RedisClient.create(redisURI);
+ }
+
+ return RedisClient.create(clientResources, redisURI);
}
if (isClusterAware()) {
@@ -475,7 +499,13 @@ private AbstractRedisClient createRedisClient() {
initialUris.add(redisURI);
}
- RedisClusterClient clusterClient = new RedisClusterClient(initialUris);
+ RedisClusterClient clusterClient;
+ if(clientResources == null) {
+ clusterClient = RedisClusterClient.create(initialUris);
+ }
+ else {
+ clusterClient = RedisClusterClient.create(clientResources, initialUris);
+ }
this.clusterCommandExecutor = new ClusterCommandExecutor(
new LettuceClusterConnection.LettuceClusterTopologyProvider(clusterClient),
@@ -493,8 +523,11 @@ private AbstractRedisClient createRedisClient() {
builder.withPassword(password);
}
builder.withTimeout(timeout, TimeUnit.MILLISECONDS);
- RedisClient client = new RedisClient(builder.build());
- return client;
+ if(clientResources != null) {
+ return RedisClient.create(clientResources, builder.build());
+ }
+
+ return RedisClient.create(builder.build());
}
private RedisURI getSentinelRedisURI() {
diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnection.java
index 403da6b6f7..53acd0cc72 100644
--- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnection.java
+++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnection.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 the original author or authors.
+ * Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,8 @@
import com.lambdaworks.redis.RedisClient;
import com.lambdaworks.redis.RedisSentinelAsyncConnection;
+import com.lambdaworks.redis.RedisURI;
+import com.lambdaworks.redis.resource.ClientResources;
import org.springframework.data.redis.ExceptionTranslationStrategy;
import org.springframework.data.redis.FallbackExceptionTranslationStrategy;
import org.springframework.data.redis.connection.NamedNode;
@@ -51,12 +53,26 @@ public LettuceSentinelConnection(RedisNode sentinel) {
/**
* Creates a {@link LettuceSentinelConnection} with a client for the supplied {@code host} and {@code port}.
- * @param host hostname
+ * @param host hostname must not be {@literal null}
* @param port sentinel port
*/
public LettuceSentinelConnection(String host, int port) {
- Assert.notNull(host, "Cannot created LettuceSentinelConnection using 'null' as host.");
- redisClient = new RedisClient(host, port);
+ Assert.notNull(host, "Cannot create LettuceSentinelConnection using 'null' as host.");
+ redisClient = RedisClient.create(new RedisURI.Builder().redis(host, port).build());
+ init();
+ }
+
+ /**
+ * Creates a {@link LettuceSentinelConnection} with a client for the supplied {@code host} and {@code port} and reuse
+ * existing {@code clientResources}.
+ * @param clientResources must not be {@literal null}
+ * @param host hostname must not be {@literal null}
+ * @param port sentinel port
+ */
+ public LettuceSentinelConnection(ClientResources clientResources, String host, int port) {
+ Assert.notNull(clientResources, "Cannot create LettuceSentinelConnection using 'null' as ClientResources.");
+ Assert.notNull(host, "Cannot create LettuceSentinelConnection using 'null' as host.");
+ redisClient = RedisClient.create(clientResources, new RedisURI.Builder().redis(host, port).build());
init();
}
diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePoolTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePoolTests.java
index ca8b5ae3af..3c26ad7144 100644
--- a/src/test/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePoolTests.java
+++ b/src/test/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePoolTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2014 the original author or authors.
+ * Copyright 2013-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -57,6 +57,7 @@ public void tearDown() {
@Test
public void testGetResource() {
this.pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort());
+ this.pool.setClientResources(TestClientResources.get());
pool.afterPropertiesSet();
RedisAsyncConnection client = pool.getResource();
assertNotNull(client);
@@ -70,6 +71,7 @@ public void testGetResourcePoolExhausted() {
poolConfig.setMaxTotal(1);
poolConfig.setMaxWaitMillis(1);
this.pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort(), poolConfig);
+ this.pool.setClientResources(TestClientResources.get());
pool.afterPropertiesSet();
RedisAsyncConnection client = pool.getResource();
assertNotNull(client);
@@ -86,6 +88,7 @@ public void testGetResourceValidate() {
PoolConfig poolConfig = new PoolConfig();
poolConfig.setTestOnBorrow(true);
this.pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort(), poolConfig);
+ this.pool.setClientResources(TestClientResources.get());
pool.afterPropertiesSet();
RedisAsyncConnection client = pool.getResource();
assertNotNull(client);
@@ -95,6 +98,7 @@ public void testGetResourceValidate() {
@Test(expected = PoolException.class)
public void testGetResourceCreationUnsuccessful() throws Exception {
this.pool = new DefaultLettucePool(SettingsUtils.getHost(), 3333);
+ this.pool.setClientResources(TestClientResources.get());
pool.afterPropertiesSet();
pool.getResource();
}
@@ -105,6 +109,7 @@ public void testReturnResource() {
poolConfig.setMaxTotal(1);
poolConfig.setMaxWaitMillis(1);
this.pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort(), poolConfig);
+ this.pool.setClientResources(TestClientResources.get());
pool.afterPropertiesSet();
RedisAsyncConnection client = pool.getResource();
assertNotNull(client);
@@ -119,6 +124,7 @@ public void testReturnBrokenResource() {
poolConfig.setMaxTotal(1);
poolConfig.setMaxWaitMillis(1);
this.pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort(), poolConfig);
+ this.pool.setClientResources(TestClientResources.get());
pool.afterPropertiesSet();
RedisAsyncConnection client = pool.getResource();
assertNotNull(client);
@@ -136,6 +142,18 @@ public void testReturnBrokenResource() {
@Test
public void testCreateWithDbIndex() {
+ this.pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort());
+ this.pool.setClientResources(TestClientResources.get());
+ pool.setDatabase(1);
+ pool.afterPropertiesSet();
+ assertNotNull(pool.getResource());
+ }
+
+ /**
+ * @see DATAREDIS-462
+ */
+ @Test
+ public void poolWorksWithoutClientResources() {
this.pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort());
pool.setDatabase(1);
pool.afterPropertiesSet();
@@ -145,6 +163,7 @@ public void testCreateWithDbIndex() {
@Test(expected = PoolException.class)
public void testCreateWithDbIndexInvalid() {
this.pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort());
+ this.pool.setClientResources(TestClientResources.get());
pool.setDatabase(17);
pool.afterPropertiesSet();
pool.getResource();
@@ -153,6 +172,7 @@ public void testCreateWithDbIndexInvalid() {
@Test(expected = PoolException.class)
public void testCreateWithPasswordNoPassword() {
this.pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort());
+ this.pool.setClientResources(TestClientResources.get());
pool.setPassword("notthepassword");
pool.afterPropertiesSet();
pool.getResource();
@@ -162,6 +182,7 @@ public void testCreateWithPasswordNoPassword() {
@Test
public void testCreatePassword() {
this.pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort());
+ this.pool.setClientResources(TestClientResources.get());
pool.setPassword("foo");
pool.afterPropertiesSet();
RedisAsyncConnection conn = pool.getResource();
@@ -173,6 +194,7 @@ public void testCreatePassword() {
@Test(expected = PoolException.class)
public void testCreateInvalidPassword() {
this.pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort());
+ this.pool.setClientResources(TestClientResources.get());
pool.setPassword("bad");
pool.afterPropertiesSet();
pool.getResource();
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 9e70716492..e765dfbfa1 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
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 the original author or authors.
+ * Copyright 2015-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,9 +15,29 @@
*/
package org.springframework.data.redis.connection.lettuce;
-import static org.hamcrest.CoreMatchers.*;
-import static org.junit.Assert.*;
-import static org.springframework.data.redis.connection.ClusterTestVariables.*;
+import static org.hamcrest.CoreMatchers.endsWith;
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.CoreMatchers.hasItems;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.CoreMatchers.startsWith;
+import static org.junit.Assert.assertThat;
+import static org.springframework.data.redis.connection.ClusterTestVariables.CLUSTER_HOST;
+import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_1;
+import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_2;
+import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_3;
+import static org.springframework.data.redis.connection.ClusterTestVariables.MASTER_NODE_1_PORT;
+import static org.springframework.data.redis.connection.ClusterTestVariables.MASTER_NODE_2_PORT;
+import static org.springframework.data.redis.connection.ClusterTestVariables.MASTER_NODE_3_PORT;
+import static org.springframework.data.redis.connection.ClusterTestVariables.SAME_SLOT_KEY_1;
+import static org.springframework.data.redis.connection.ClusterTestVariables.SAME_SLOT_KEY_2;
+import static org.springframework.data.redis.connection.ClusterTestVariables.SAME_SLOT_KEY_3;
+import static org.springframework.data.redis.connection.ClusterTestVariables.SLAVEOF_NODE_1_PORT;
+import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_1;
+import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_2;
+import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_3;
import java.util.Collection;
import java.util.Collections;
@@ -82,8 +102,8 @@ public class LettuceClusterConnectionTests implements ClusterConnectionTests {
@Before
public void setUp() {
- client = new RedisClusterClient(Builder.redis(CLUSTER_HOST, MASTER_NODE_1_PORT)
- .withTimeout(100, TimeUnit.MILLISECONDS).build());
+ client = RedisClusterClient.create(TestClientResources.get(),
+ Builder.redis(CLUSTER_HOST, MASTER_NODE_1_PORT).withTimeout(100, TimeUnit.MILLISECONDS).build());
nativeConnection = client.connectCluster();
clusterConnection = new LettuceClusterConnection(client);
}
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 4c3fbdbf2c..dc39626a8c 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
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2015 the original author or authors.
+ * Copyright 2011-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
*/
package org.springframework.data.redis.connection.lettuce;
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsEqual.equalTo;
import static org.hamcrest.core.IsNull.*;
import static org.junit.Assert.*;
@@ -40,6 +42,7 @@
* @author Jennifer Hickey
* @author Thomas Darimont
* @author Christoph Strobl
+ * @author Mark Paluch
*/
public class LettuceConnectionFactoryTests {
@@ -51,6 +54,7 @@ public class LettuceConnectionFactoryTests {
public void setUp() {
factory = new LettuceConnectionFactory(SettingsUtils.getHost(), SettingsUtils.getPort());
+ factory.setClientResources(TestClientResources.get());
factory.afterPropertiesSet();
factory.setShutdownTimeout(0);
connection = new DefaultStringRedisConnection(factory.getConnection());
@@ -122,6 +126,7 @@ public void testValidateNoError() {
public void testSelectDb() {
LettuceConnectionFactory factory2 = new LettuceConnectionFactory(SettingsUtils.getHost(), SettingsUtils.getPort());
+ factory2.setClientResources(TestClientResources.get());
factory2.setShutdownTimeout(0);
factory2.setDatabase(1);
factory2.afterPropertiesSet();
@@ -224,6 +229,7 @@ public void testGetSharedConnectionNotShared() {
@Test
public void testCreateFactoryWithPool() {
DefaultLettucePool pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort());
+ pool.setClientResources(TestClientResources.get());
pool.afterPropertiesSet();
LettuceConnectionFactory factory2 = new LettuceConnectionFactory(pool);
factory2.setShutdownTimeout(0);
@@ -279,6 +285,7 @@ public void testConnectWithPassword() {
public void dbIndexShouldBePropagatedCorrectly() {
LettuceConnectionFactory factory = new LettuceConnectionFactory();
+ factory.setClientResources(TestClientResources.get());
factory.setDatabase(2);
factory.afterPropertiesSet();
@@ -297,4 +304,25 @@ public void dbIndexShouldBePropagatedCorrectly() {
connectionToDbIndex2.close();
}
}
+
+ /**
+ * @see DATAREDIS-462
+ */
+ @Test
+ public void factoryWorksWithoutClientResources() {
+
+ LettuceConnectionFactory factory = new LettuceConnectionFactory();
+ factory.setShutdownTimeout(0);
+ factory.afterPropertiesSet();
+
+ ConnectionFactoryTracker.add(factory);
+
+ StringRedisConnection connection = new DefaultStringRedisConnection(factory.getConnection());
+
+ try {
+ assertThat(connection.ping(), is(equalTo("PONG")));
+ } finally {
+ connection.close();
+ }
+ }
}
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 c78745656c..19f1da8e66 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
@@ -23,8 +23,10 @@
import java.util.concurrent.TimeUnit;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.springframework.data.redis.ConnectionFactoryTracker;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import com.lambdaworks.redis.AbstractRedisClient;
@@ -33,6 +35,7 @@
/**
* @author Christoph Strobl
+ * @author Mark Paluch
*/
public class LettuceConnectionFactoryUnitTests {
@@ -43,6 +46,11 @@ public void setUp() {
clusterConfig = new RedisClusterConfiguration().clusterNode("127.0.0.1", 6379).clusterNode("127.0.0.1", 6380);
}
+ @After
+ public void tearDown() throws Exception {
+ ConnectionFactoryTracker.cleanUp();
+ }
+
/**
* @see DATAREDIS-315
*/
@@ -50,7 +58,9 @@ public void setUp() {
public void shouldInitClientCorrectlyWhenClusterConfigPresent() {
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(clusterConfig);
+ connectionFactory.setClientResources(TestClientResources.get());
connectionFactory.afterPropertiesSet();
+ ConnectionFactoryTracker.add(connectionFactory);
assertThat(getField(connectionFactory, "client"), instanceOf(RedisClusterClient.class));
}
@@ -63,8 +73,10 @@ public void shouldInitClientCorrectlyWhenClusterConfigPresent() {
public void timeoutShouldBeSetCorrectlyOnClusterClient() {
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(clusterConfig);
+ connectionFactory.setClientResources(TestClientResources.get());
connectionFactory.setTimeout(1000);
connectionFactory.afterPropertiesSet();
+ ConnectionFactoryTracker.add(connectionFactory);
AbstractRedisClient client = (AbstractRedisClient) getField(connectionFactory, "client");
assertThat(client, instanceOf(RedisClusterClient.class));
@@ -85,8 +97,10 @@ public void timeoutShouldBeSetCorrectlyOnClusterClient() {
public void passwordShouldBeSetCorrectlyOnClusterClient() {
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(clusterConfig);
+ connectionFactory.setClientResources(TestClientResources.get());
connectionFactory.setPassword("o_O");
connectionFactory.afterPropertiesSet();
+ ConnectionFactoryTracker.add(connectionFactory);
AbstractRedisClient client = (AbstractRedisClient) getField(connectionFactory, "client");
assertThat(client, instanceOf(RedisClusterClient.class));
@@ -97,4 +111,20 @@ public void passwordShouldBeSetCorrectlyOnClusterClient() {
assertThat(uri.getPassword(), is(equalTo(connectionFactory.getPassword().toCharArray())));
}
}
+
+ /**
+ * @see DATAREDIS-462
+ */
+ @Test
+ @SuppressWarnings("unchecked")
+ public void clusterClientShouldInitializeWithoutClientResources() {
+
+ LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(clusterConfig);
+ connectionFactory.setShutdownTimeout(0);
+ connectionFactory.afterPropertiesSet();
+ ConnectionFactoryTracker.add(connectionFactory);
+
+ AbstractRedisClient client = (AbstractRedisClient) getField(connectionFactory, "client");
+ assertThat(client, instanceOf(RedisClusterClient.class));
+ }
}
diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionIntegrationTests.java
index 3b53b9b936..8c1129b799 100644
--- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionIntegrationTests.java
+++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2014 the original author or authors.
+ * Copyright 2011-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -59,6 +59,7 @@
* @author Thomas Darimont
* @author Christoph Strobl
* @author David Liu
+ * @author Mark Paluch
*/
@RunWith(RelaxedJUnit4ClassRunner.class)
@ContextConfiguration
@@ -138,6 +139,7 @@ public void testCloseBlockingOps() {
@Test
public void testClosePooledConnectionWithShared() {
DefaultLettucePool pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort());
+ pool.setClientResources(TestClientResources.get());
pool.afterPropertiesSet();
LettuceConnectionFactory factory2 = new LettuceConnectionFactory(pool);
factory2.setShutdownTimeout(0);
@@ -159,6 +161,7 @@ public void testClosePooledConnectionWithShared() {
@Test
public void testClosePooledConnectionNotShared() {
DefaultLettucePool pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort());
+ pool.setClientResources(TestClientResources.get());
pool.afterPropertiesSet();
LettuceConnectionFactory factory2 = new LettuceConnectionFactory(pool);
factory2.setShareNativeConnection(false);
@@ -178,6 +181,7 @@ public void testClosePooledConnectionNotShared() {
@Test
public void testCloseNonPooledConnectionNotShared() {
LettuceConnectionFactory factory2 = new LettuceConnectionFactory(SettingsUtils.getHost(), SettingsUtils.getPort());
+ factory2.setClientResources(TestClientResources.get());
factory2.setShutdownTimeout(0);
factory2.setShareNativeConnection(false);
factory2.afterPropertiesSet();
@@ -197,6 +201,7 @@ public void testCloseNonPooledConnectionNotShared() {
@Test
public void testCloseReturnBrokenResourceToPool() {
DefaultLettucePool pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort());
+ pool.setClientResources(TestClientResources.get());
pool.afterPropertiesSet();
LettuceConnectionFactory factory2 = new LettuceConnectionFactory(pool);
factory2.setShutdownTimeout(0);
@@ -218,6 +223,7 @@ public void testCloseReturnBrokenResourceToPool() {
@Test
public void testSelectNotShared() {
DefaultLettucePool pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort());
+ pool.setClientResources(TestClientResources.get());
pool.afterPropertiesSet();
LettuceConnectionFactory factory2 = new LettuceConnectionFactory(pool);
factory2.setShutdownTimeout(0);
@@ -246,6 +252,7 @@ public void run() {
// Use a different factory to get a non-shared native conn for blocking script
final LettuceConnectionFactory factory2 = new LettuceConnectionFactory(SettingsUtils.getHost(),
SettingsUtils.getPort());
+ factory2.setClientResources(TestClientResources.get());
factory2.setShutdownTimeout(0);
factory2.afterPropertiesSet();
DefaultStringRedisConnection conn2 = new DefaultStringRedisConnection(factory2.getConnection());
@@ -275,6 +282,7 @@ public void testMove() {
verifyResults(Arrays.asList(new Object[] { true }));
// Lettuce does not support select when using shared conn, use a new conn factory
LettuceConnectionFactory factory2 = new LettuceConnectionFactory();
+ factory2.setClientResources(TestClientResources.get());
factory2.setShutdownTimeout(0);
factory2.setDatabase(1);
factory2.afterPropertiesSet();
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 1b22323752..045eb1162a 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
@@ -65,6 +65,7 @@ public void run() {
// Use separate conn factory to avoid using the underlying shared native conn on blocking script
final LettuceConnectionFactory factory2 = new LettuceConnectionFactory(SettingsUtils.getHost(),
SettingsUtils.getPort());
+ factory2.setClientResources(TestClientResources.get());
factory2.afterPropertiesSet();
DefaultStringRedisConnection conn2 = new DefaultStringRedisConnection(factory2.getConnection());
try {
@@ -94,6 +95,7 @@ public void testMove() {
verifyResults(Arrays.asList(new Object[] { true }));
// Lettuce does not support select when using shared conn, use a new conn factory
LettuceConnectionFactory factory2 = new LettuceConnectionFactory();
+ factory2.setClientResources(TestClientResources.get());
factory2.setDatabase(1);
factory2.afterPropertiesSet();
StringRedisConnection conn2 = new DefaultStringRedisConnection(factory2.getConnection());
diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionTransactionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionTransactionIntegrationTests.java
index e6535e00c8..6b84125a2a 100644
--- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionTransactionIntegrationTests.java
+++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionTransactionIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2015 the original author or authors.
+ * Copyright 2011-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -46,6 +46,7 @@ public void testMove() {
verifyResults(Arrays.asList(new Object[] { true }));
// Lettuce does not support select when using shared conn, use a new conn factory
LettuceConnectionFactory factory2 = new LettuceConnectionFactory();
+ factory2.setClientResources(TestClientResources.get());
factory2.setShutdownTimeout(0);
factory2.setDatabase(1);
factory2.afterPropertiesSet();
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 6cac5d13cf..e472c213e5 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
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 the original author or authors.
+ * Copyright 2015-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@
package org.springframework.data.redis.connection.lettuce;
import static org.hamcrest.CoreMatchers.*;
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.*;
import java.util.Collection;
@@ -25,10 +27,13 @@
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.springframework.data.redis.ConnectionFactoryTracker;
import org.springframework.data.redis.connection.AbstractConnectionIntegrationTests;
+import org.springframework.data.redis.connection.DefaultStringRedisConnection;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.RedisSentinelConnection;
import org.springframework.data.redis.connection.RedisServer;
+import org.springframework.data.redis.connection.StringRedisConnection;
import org.springframework.data.redis.test.util.RedisSentinelRule;
/**
@@ -53,6 +58,7 @@ public class LettuceSentinelIntegrationTests extends AbstractConnectionIntegrati
public void setUp() {
LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(SENTINEL_CONFIG);
+ lettuceConnectionFactory.setClientResources(TestClientResources.get());
lettuceConnectionFactory.setShareNativeConnection(false);
lettuceConnectionFactory.setShutdownTimeout(0);
lettuceConnectionFactory.afterPropertiesSet();
@@ -94,4 +100,25 @@ public void shouldReadSlavesOfMastersCorrectly() {
assertThat(slaves, hasItems(SLAVE_0, SLAVE_1));
}
+ /**
+ * @see DATAREDIS-462
+ */
+ @Test
+ public void factoryWorksWithoutClientResources() {
+
+ LettuceConnectionFactory factory = new LettuceConnectionFactory(SENTINEL_CONFIG);
+ factory.setShutdownTimeout(0);
+ factory.afterPropertiesSet();
+
+ ConnectionFactoryTracker.add(factory);
+
+ StringRedisConnection connection = new DefaultStringRedisConnection(factory.getConnection());
+
+ try {
+ assertThat(connection.ping(), is(equalTo("PONG")));
+ } finally {
+ connection.close();
+ }
+ }
+
}
diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/TestClientResources.java b/src/test/java/org/springframework/data/redis/connection/lettuce/TestClientResources.java
new file mode 100644
index 0000000000..77f772b5b0
--- /dev/null
+++ b/src/test/java/org/springframework/data/redis/connection/lettuce/TestClientResources.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.data.redis.connection.lettuce;
+
+import java.util.concurrent.TimeUnit;
+
+import com.lambdaworks.redis.resource.ClientResources;
+import com.lambdaworks.redis.resource.DefaultClientResources;
+
+/**
+ * Client-Resources suitable for testing. Uses {@link TestEventLoopGroupProvider} to preserve the event loop groups
+ * between tests. Every time a new {@link TestClientResources} instance is created, a
+ * {@link Runtime#addShutdownHook(Thread) shutdown hook} is added to close the client resources.
+ *
+ * @author Mark Paluch
+ */
+public class TestClientResources {
+
+ private ClientResources resources = create();
+ private final static TestClientResources instance = new TestClientResources();
+
+ /**
+ * Prevent instances by others.
+ */
+ private TestClientResources() {}
+
+ private ClientResources create() {
+
+ final DefaultClientResources resources = new DefaultClientResources.Builder()
+ .eventLoopGroupProvider(new TestEventLoopGroupProvider()).build();
+
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ @Override
+ public void run() {
+ try {
+ resources.shutdown(0, 0, TimeUnit.MILLISECONDS).get(1, TimeUnit.SECONDS);
+ } catch (Exception o_O) {
+ // ignore
+ }
+ }
+ });
+
+ return resources;
+ }
+
+ /**
+ * @return the client resources.
+ */
+ public static ClientResources get() {
+ return instance.resources;
+ }
+}
diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/TestEventLoopGroupProvider.java b/src/test/java/org/springframework/data/redis/connection/lettuce/TestEventLoopGroupProvider.java
new file mode 100644
index 0000000000..338abb84d6
--- /dev/null
+++ b/src/test/java/org/springframework/data/redis/connection/lettuce/TestEventLoopGroupProvider.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.data.redis.connection.lettuce;
+
+import java.util.concurrent.TimeUnit;
+
+import com.lambdaworks.redis.resource.DefaultEventLoopGroupProvider;
+
+import io.netty.util.concurrent.DefaultPromise;
+import io.netty.util.concurrent.EventExecutorGroup;
+import io.netty.util.concurrent.ImmediateEventExecutor;
+import io.netty.util.concurrent.Promise;
+
+/**
+ * A {@link com.lambdaworks.redis.resource.EventLoopGroupProvider} suitable for testing. Preserves the event loop groups
+ * between tests. Every time a new {@link TestEventLoopGroupProvider} instance is created, a
+ * {@link Runtime#addShutdownHook(Thread) shutdown hook} is added to close the resources.
+ *
+ * @author Mark Paluch
+ */
+class TestEventLoopGroupProvider extends DefaultEventLoopGroupProvider {
+
+ public static final int NUMBER_OF_THREADS = 10;
+
+ public TestEventLoopGroupProvider() {
+
+ super(NUMBER_OF_THREADS);
+
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ @Override
+ public void run() {
+ try {
+ TestEventLoopGroupProvider.this.shutdown(0, 0, TimeUnit.MILLISECONDS).get(1, TimeUnit.SECONDS);
+ } catch (Exception o_O) {
+ // ignored
+ }
+ }
+ });
+ }
+
+ @Override
+ public Promise release(EventExecutorGroup eventLoopGroup, long quietPeriod, long timeout, TimeUnit unit) {
+
+ DefaultPromise result = new DefaultPromise(ImmediateEventExecutor.INSTANCE);
+ result.setSuccess(true);
+
+ return result;
+ }
+}
diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/TransactionalLettuceItegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/TransactionalLettuceItegrationTests.java
index 1880e28728..584fcedd23 100644
--- a/src/test/java/org/springframework/data/redis/connection/lettuce/TransactionalLettuceItegrationTests.java
+++ b/src/test/java/org/springframework/data/redis/connection/lettuce/TransactionalLettuceItegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 the original author or authors.
+ * Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@
/**
* @author Christoph Strobl
+ * @author Mark Paluch
*/
@ContextConfiguration(classes = { LettuceContextConfiguration.class })
public class TransactionalLettuceItegrationTests extends AbstractTransactionalTestBase {
@@ -35,6 +36,7 @@ public static class LettuceContextConfiguration extends RedisContextConfiguratio
public LettuceConnectionFactory redisConnectionFactory() {
LettuceConnectionFactory factory = new LettuceConnectionFactory();
+ factory.setClientResources(TestClientResources.get());
factory.setHostName("localhost");
factory.setPort(6379);
return factory;
diff --git a/src/test/java/org/springframework/data/redis/core/MultithreadedRedisTemplateTests.java b/src/test/java/org/springframework/data/redis/core/MultithreadedRedisTemplateTests.java
index 4eefdbc754..30c9641bdd 100644
--- a/src/test/java/org/springframework/data/redis/core/MultithreadedRedisTemplateTests.java
+++ b/src/test/java/org/springframework/data/redis/core/MultithreadedRedisTemplateTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2015 the original author or authors.
+ * Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,11 +32,13 @@
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
+import org.springframework.data.redis.connection.lettuce.TestClientResources;
import org.springframework.data.redis.connection.srp.SrpConnectionFactory;
/**
* @author Artem Bilian
* @author Christoph Strobl
+ * @author Mark Paluch
*/
@RunWith(Parameterized.class)
public class MultithreadedRedisTemplateTests {
@@ -61,6 +63,7 @@ public static Collection