From 444b290863314dd92c5b9b50e3ee0efd263949b9 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Fri, 5 Jun 2015 11:24:40 +0200 Subject: [PATCH] DATAREDIS-348 - Polishing. Fixed connection problems leaving sockets open. Added missing JUnit rules for Sentinels. Added missing author information update, license header and Javadoc. Upgraded test script to use Redis 3.0.2. Upgrade test script to shut down Redis in case of test errors. Added Redis 3.0 to TestProfileValueSource. Enabled ZRANGEBYLEX tests for lettuce. Original pull request: #144. Related pull request: #104. --- Makefile | 4 +- src/asciidoc/reference/redis.adoc | 23 +++--- .../lettuce/AuthenticatingRedisClient.java | 7 +- .../lettuce/DefaultLettucePool.java | 13 ++- .../connection/lettuce/LettuceConnection.java | 4 + .../lettuce/LettuceConnectionFactory.java | 23 ++++-- .../connection/lettuce/LettuceConverters.java | 2 +- .../redis/RedisTestProfileValueSource.java | 49 +++++++---- .../data/redis/SettingsUtils.java | 2 +- .../AbstractConnectionIntegrationTests.java | 82 ++++++++++++++----- .../JedisConnectionIntegrationTests.java | 34 -------- .../LettuceConnectionIntegrationTests.java | 3 + ...uceConnectionPipelineIntegrationTests.java | 3 +- ...ConnectionTransactionIntegrationTests.java | 3 +- .../LettuceConnectionUnitTestSuite.java | 8 +- .../LettuceSentinelConnectionUnitTests.java | 23 +----- .../LettuceSentinelIntegrationTests.java | 51 +++++------- .../collections/AbstractRedisMapTests.java | 6 +- .../test/util/MinimumRedisVersionRule.java | 53 ++++++++---- .../data/redis/test/util/RedisClientRule.java | 11 ++- .../redis/test/util/RedisSentinelRule.java | 11 ++- .../data/redis/test.properties | 2 +- 22 files changed, 226 insertions(+), 191 deletions(-) diff --git a/Makefile b/Makefile index b0fc23f62..2c12485b2 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -REDIS_VERSION:=2.8.19 +REDIS_VERSION:=3.0.2 ####### # Redis @@ -95,5 +95,5 @@ stop: redis-stop sentinel-stop test: $(MAKE) start sleep 2 - $(PWD)/gradlew clean build -DrunLongTests=true -S + -$(PWD)/gradlew clean build -DrunLongTests=true -S $(MAKE) stop diff --git a/src/asciidoc/reference/redis.adoc b/src/asciidoc/reference/redis.adoc index db571b7fd..6c7deca6c 100644 --- a/src/asciidoc/reference/redis.adoc +++ b/src/asciidoc/reference/redis.adoc @@ -169,12 +169,25 @@ NOTE: Please note that currently only http://github.com/xetorthio/jedis[Jedis] a [source,java] ---- +/** + * jedis + */ @Bean public RedisConnectionFactory jedisConnectionFactory() { RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration() .master("mymaster") .sentinel("127.0.0.1", 26379) .sentinel("127.0.0.1", 26380); return new JedisConnectionFactory(sentinelConfig); } + +/** + * lettuce + */ +@Bean +public RedisConnectionFactory lettuceConnectionFactory() { + RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration().master("mymaster") + .sentinel("127.0.0.1", 26379) .sentinel("127.0.0.1", 26380); + return new LettuceConnectionFactory(sentinelConfig); +} ---- [TIP] @@ -185,16 +198,6 @@ public RedisConnectionFactory jedisConnectionFactory() { - `spring.redis.sentinel.master`: name of the master node. - `spring.redis.sentinel.nodes`: Comma delimited list of host:port pairs. ==== -======= -[source,java] ----- -@Bean -public RedisConnectionFactory lettuceConnectionFactory() { - RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration() .master("mymaster") - .sentinel("127.0.0.1", 26379) .sentinel("127.0.0.1", 26380); - return new LettuceConnectionFactory(sentinelConfig); -} ----- Sometimes direct interaction with the one of the Sentinels is required. Using `RedisConnectionFactory.getSentinelConnection()` or `RedisConnection.getSentinelCommands()` gives you access to the first active Sentinel configured. diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/AuthenticatingRedisClient.java b/src/main/java/org/springframework/data/redis/connection/lettuce/AuthenticatingRedisClient.java index 309a0795f..e37a5151d 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/AuthenticatingRedisClient.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/AuthenticatingRedisClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2013-2015 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. @@ -18,6 +18,7 @@ package org.springframework.data.redis.connection.lettuce; import com.lambdaworks.redis.RedisAsyncConnection; import com.lambdaworks.redis.RedisClient; import com.lambdaworks.redis.RedisConnection; +import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.pubsub.RedisPubSubConnection; @@ -25,7 +26,9 @@ import com.lambdaworks.redis.pubsub.RedisPubSubConnection; * Extension of {@link RedisClient} that calls auth on all new connections using the supplied credentials * * @author Jennifer Hickey - * @deprecated Use password in RedisURI + * @author Mar Paluch + * @author Christoph Strobl + * @deprecated since 1.6 - Please use {@link RedisURI#setPassword(String)} */ @Deprecated public class AuthenticatingRedisClient extends RedisClient { 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 449a27fd5..14d7340ca 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-2014 the original author or authors. + * Copyright 2013-2015 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,7 +17,6 @@ package org.springframework.data.redis.connection.lettuce; import java.util.concurrent.TimeUnit; -import com.lambdaworks.redis.RedisURI; import org.apache.commons.pool2.BasePooledObjectFactory; import org.apache.commons.pool2.PooledObject; import org.apache.commons.pool2.impl.DefaultPooledObject; @@ -30,6 +29,7 @@ import org.springframework.util.Assert; import com.lambdaworks.redis.RedisAsyncConnection; import com.lambdaworks.redis.RedisClient; +import com.lambdaworks.redis.RedisURI; /** * Default implementation of {@link LettucePool}. @@ -72,6 +72,7 @@ public class DefaultLettucePool implements LettucePool, InitializingBean { * based on sentinels. * * @param sentinelConfiguration The Sentinel configuration + * @since 1.6 */ public DefaultLettucePool(RedisSentinelConfiguration sentinelConfiguration) { this.sentinelConfiguration = sentinelConfiguration; @@ -92,7 +93,7 @@ public class DefaultLettucePool implements LettucePool, InitializingBean { /** * @return true when {@link RedisSentinelConfiguration} is present. - * @since 1.5 + * @since 1.6 */ public boolean isRedisSentinelAware() { return sentinelConfiguration != null; @@ -106,12 +107,11 @@ public class DefaultLettucePool implements LettucePool, InitializingBean { } /** - * * @return a RedisURI pointing either to a single Redis host or containing a set of sentinels. */ private RedisURI getRedisURI() { - if(isRedisSentinelAware()) { + if (isRedisSentinelAware()) { return LettuceConverters.sentinelConfigurationToRedisURI(sentinelConfiguration); } @@ -120,7 +120,7 @@ public class DefaultLettucePool implements LettucePool, InitializingBean { private RedisURI createSimpleHostRedisURI() { RedisURI.Builder builder = RedisURI.Builder.redis(hostName, port); - if(password != null) { + if (password != null) { builder.withPassword(password); } builder.withTimeout(timeout, TimeUnit.MILLISECONDS); @@ -162,7 +162,6 @@ public class DefaultLettucePool implements LettucePool, InitializingBean { } /** - * * @return The Redis client */ public RedisClient getClient() { diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java index 6a5fb5145..773d337d7 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java @@ -3568,6 +3568,10 @@ public class LettuceConnection extends AbstractRedisConnection { return RedisURI.Builder.redis(node.getHost(), node.getPort()).build(); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.AbstractRedisConnection#getSentinelConnection(org.springframework.data.redis.connection.RedisNode) + */ @Override protected RedisSentinelConnection getSentinelConnection(RedisNode sentinel) { RedisSentinelAsyncConnection connection = client.connectSentinelAsync(getRedisURI(sentinel)); 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 73fe212f9..4296d6b78 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 @@ -1,5 +1,5 @@ /* - * Copyright 2011-2014 the original author or authors. + * Copyright 2011-2015 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. @@ -18,9 +18,6 @@ package org.springframework.data.redis.connection.lettuce; import java.util.concurrent.TimeUnit; -import com.lambdaworks.redis.LettuceFutures; -import com.lambdaworks.redis.RedisFuture; -import com.lambdaworks.redis.RedisURI; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.DisposableBean; @@ -36,9 +33,12 @@ import org.springframework.data.redis.connection.RedisSentinelConfiguration; import org.springframework.data.redis.connection.RedisSentinelConnection; import org.springframework.util.Assert; +import com.lambdaworks.redis.LettuceFutures; import com.lambdaworks.redis.RedisAsyncConnection; import com.lambdaworks.redis.RedisClient; import com.lambdaworks.redis.RedisException; +import com.lambdaworks.redis.RedisFuture; +import com.lambdaworks.redis.RedisURI; /** * Connection factory creating Lettuce-based connections. @@ -55,6 +55,7 @@ import com.lambdaworks.redis.RedisException; * @author Costin Leau * @author Jennifer Hickey * @author Thomas Darimont + * @author Mark Paluch */ public class LettuceConnectionFactory implements InitializingBean, DisposableBean, RedisConnectionFactory { @@ -98,7 +99,7 @@ public class LettuceConnectionFactory implements InitializingBean, DisposableBea * Constructs a new {@link LettuceConnectionFactory} instance using the given {@link RedisSentinelConfiguration} * * @param sentinelConfiguration - * @since 1.5 + * @since 1.6 */ public LettuceConnectionFactory(RedisSentinelConfiguration sentinelConfiguration) { this.sentinelConfiguration = sentinelConfiguration; @@ -156,11 +157,11 @@ public class LettuceConnectionFactory implements InitializingBean, DisposableBea try { RedisFuture ping = connection.ping(); LettuceFutures.awaitAll(timeout, TimeUnit.MILLISECONDS, ping); - if(PING_REPLY.equalsIgnoreCase(ping.get())) { + if (PING_REPLY.equalsIgnoreCase(ping.get())) { valid = true; } } catch (Exception e) { - log.debug("Validation failed", e); + log.debug("Validation failed", e); } } @@ -313,7 +314,9 @@ public class LettuceConnectionFactory implements InitializingBean, DisposableBea /** * Returns the shutdown timeout for shutting down the RedisClient (in milliseconds). + * * @return shutdown timeout + * @since 1.6 */ public long getShutdownTimeout() { return shutdownTimeout; @@ -321,7 +324,9 @@ public class LettuceConnectionFactory implements InitializingBean, DisposableBea /** * Sets the shutdown timeout for shutting down the RedisClient (in milliseconds). + * * @param shutdownTimeout the shutdown timeout + * @since 1.6 */ public void setShutdownTimeout(long shutdownTimeout) { this.shutdownTimeout = shutdownTimeout; @@ -379,7 +384,7 @@ public class LettuceConnectionFactory implements InitializingBean, DisposableBea private RedisClient createRedisClient() { - if(isRedisSentinelAware()) { + if (isRedisSentinelAware()) { RedisURI redisURI = getSentinelRedisURI(); return new RedisClient(redisURI); } @@ -389,7 +394,7 @@ public class LettuceConnectionFactory implements InitializingBean, DisposableBea } RedisURI.Builder builder = RedisURI.Builder.redis(hostName, port); - if(password != null) { + if (password != null) { builder.withPassword(password); } builder.withTimeout(timeout, TimeUnit.MILLISECONDS); diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java index 73360394f..4649bd41d 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2013-2015 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. diff --git a/src/test/java/org/springframework/data/redis/RedisTestProfileValueSource.java b/src/test/java/org/springframework/data/redis/RedisTestProfileValueSource.java index e49601241..33a7ecfcb 100644 --- a/src/test/java/org/springframework/data/redis/RedisTestProfileValueSource.java +++ b/src/test/java/org/springframework/data/redis/RedisTestProfileValueSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2014 the original author or authors. + * Copyright 2011-2015 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,10 +15,13 @@ */ package org.springframework.data.redis; -import org.springframework.data.redis.connection.RedisConnection; -import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; +import java.io.IOException; + +import org.springframework.data.redis.connection.jedis.JedisConverters; import org.springframework.test.annotation.ProfileValueSource; +import redis.clients.jedis.Jedis; + /** * Implementation of {@link ProfileValueSource} that handles profile value name "redisVersion" by checking the current * version of Redis. 2.4.x will be returned as "2.4" and 2.6.x will be returned as "2.6". Any other version found will @@ -34,6 +37,7 @@ public class RedisTestProfileValueSource implements ProfileValueSource { private static final String REDIS_24 = "2.4"; private static final String REDIS_26 = "2.6"; private static final String REDIS_28 = "2.8"; + private static final String REDIS_30 = "3.0"; private static final String REDIS_VERSION_KEY = "redisVersion"; private static RedisTestProfileValueSource INSTANCE; @@ -46,22 +50,35 @@ public class RedisTestProfileValueSource implements ProfileValueSource { private static Version tryDetectRedisVersionOrReturn(Version fallbackVersion) { + Version version = fallbackVersion; + + Jedis jedis = new Jedis(SettingsUtils.getHost(), SettingsUtils.getPort(), 100); try { - JedisConnectionFactory factory = new JedisConnectionFactory(); - factory.afterPropertiesSet(); - RedisConnection connection = factory.getConnection(); - Version redisVersion = RedisVersionUtils.getRedisVersion(connection); + jedis.connect(); + String info = jedis.info(); + String versionString = (String) JedisConverters.stringToProps().convert(info).get("redis_version"); - connection.close(); - factory.destroy(); + version = RedisVersionUtils.parseVersion(versionString); + } finally { + + try { + // force socket to be closed + jedis.getClient().quit(); + jedis.getClient().getSocket().close(); + try { + // need to wait a bit + Thread.sleep(100); + } catch (InterruptedException e) { + // just ignore it + } + } catch (IOException e1) { + // ignore as well + } + jedis.close(); - return redisVersion; - } catch (Exception ex) { - System.err.println("Couldn't detect redis version!"); } - - return fallbackVersion; + return version; } public RedisTestProfileValueSource() { @@ -74,6 +91,10 @@ public class RedisTestProfileValueSource implements ProfileValueSource { return System.getProperty(key); } + if (redisVersion.compareTo(RedisVersionUtils.parseVersion(REDIS_30)) >= 0) { + return REDIS_30; + } + if (redisVersion.compareTo(RedisVersionUtils.parseVersion(REDIS_28)) >= 0) { return REDIS_28; } diff --git a/src/test/java/org/springframework/data/redis/SettingsUtils.java b/src/test/java/org/springframework/data/redis/SettingsUtils.java index 268f021bb..4e5d59fbb 100644 --- a/src/test/java/org/springframework/data/redis/SettingsUtils.java +++ b/src/test/java/org/springframework/data/redis/SettingsUtils.java @@ -25,7 +25,7 @@ public abstract class SettingsUtils { private static final Properties SETTINGS; static { - DEFAULTS.put("host", "localhost"); + DEFAULTS.put("host", "127.0.0.1"); DEFAULTS.put("port", "6379"); SETTINGS = new Properties(DEFAULTS); diff --git a/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java index ab1ca031f..d37731a50 100644 --- a/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2014 the original author or authors. + * Copyright 2011-2015 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. @@ -41,6 +41,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.hamcrest.core.IsNot; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.internal.AssumptionViolatedException; import org.springframework.beans.factory.annotation.Autowired; @@ -52,6 +53,7 @@ import org.springframework.data.redis.TestCondition; import org.springframework.data.redis.connection.RedisListCommands.Position; import org.springframework.data.redis.connection.RedisStringCommands.BitOperation; import org.springframework.data.redis.connection.RedisZSetCommands.Aggregate; +import org.springframework.data.redis.connection.RedisZSetCommands.Range; import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; import org.springframework.data.redis.connection.SortParameters.Order; import org.springframework.data.redis.connection.StringRedisConnection.StringTuple; @@ -62,6 +64,9 @@ import org.springframework.data.redis.core.types.RedisClientInfo; import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.data.redis.test.util.RedisClientRule; +import org.springframework.data.redis.test.util.RedisDriver; +import org.springframework.data.redis.test.util.WithRedisDriver; import org.springframework.test.annotation.IfProfileValue; import org.springframework.test.annotation.ProfileValueSourceConfiguration; @@ -88,8 +93,15 @@ public abstract class AbstractConnectionIntegrationTests { protected RedisConnection byteConnection; + public @Rule RedisClientRule clientRule = new RedisClientRule() { + public RedisConnectionFactory getConnectionFactory() { + return connectionFactory; + } + }; + @Before public void setUp() { + byteConnection = connectionFactory.getConnection(); connection = new DefaultStringRedisConnection(byteConnection); ((DefaultStringRedisConnection) connection).setDeserializePipelineAndTxResults(true); @@ -2072,12 +2084,9 @@ public abstract class AbstractConnectionIntegrationTests { */ @Test @IfProfileValue(name = "redisVersion", value = "2.8.9+") + @WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE }) public void pfAddShouldAddToNonExistingKeyCorrectly() { - if (!ConnectionUtils.isJedis(connectionFactory) && !ConnectionUtils.isLettuce(connectionFactory)) { - throw new AssumptionViolatedException("PFADD is only available for jedis and lettuce"); - } - actual.add(connection.pfAdd("hll", "a", "b", "c")); List results = getResults(); @@ -2089,12 +2098,9 @@ public abstract class AbstractConnectionIntegrationTests { */ @Test @IfProfileValue(name = "redisVersion", value = "2.8.9+") + @WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE }) public void pfAddShouldReturnZeroWhenValueAlreadyExists() { - if (!ConnectionUtils.isJedis(connectionFactory) && !ConnectionUtils.isLettuce(connectionFactory)) { - throw new AssumptionViolatedException("PFADD is only available for jedis and lettuce"); - } - actual.add(connection.pfAdd("hll", "a", "b", "c")); actual.add(connection.pfAdd("hll2", "c", "d", "e")); actual.add(connection.pfAdd("hll2", "e")); @@ -2110,12 +2116,9 @@ public abstract class AbstractConnectionIntegrationTests { */ @Test @IfProfileValue(name = "redisVersion", value = "2.8.9+") + @WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE }) public void pfCountShouldReturnCorrectly() { - if (!ConnectionUtils.isJedis(connectionFactory) && !ConnectionUtils.isLettuce(connectionFactory)) { - throw new AssumptionViolatedException("PFADD is only available for jedis and lettuce"); - } - actual.add(connection.pfAdd("hll", "a", "b", "c")); actual.add(connection.pfCount("hll")); @@ -2129,12 +2132,9 @@ public abstract class AbstractConnectionIntegrationTests { */ @Test @IfProfileValue(name = "redisVersion", value = "2.8.9+") + @WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE }) public void pfCountWithMultipleKeysShouldReturnCorrectly() { - if (!ConnectionUtils.isJedis(connectionFactory) && !ConnectionUtils.isLettuce(connectionFactory)) { - throw new AssumptionViolatedException("PFADD is only available for jedis and lettuce"); - } - actual.add(connection.pfAdd("hll", "a", "b", "c")); actual.add(connection.pfAdd("hll2", "d", "e", "f")); actual.add(connection.pfCount("hll", "hll2")); @@ -2150,15 +2150,53 @@ public abstract class AbstractConnectionIntegrationTests { */ @Test(expected = IllegalArgumentException.class) @IfProfileValue(name = "redisVersion", value = "2.8.9+") + @WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE }) public void pfCountWithNullKeysShouldThrowIllegalArgumentException() { - - if (!ConnectionUtils.isJedis(connectionFactory) && !ConnectionUtils.isLettuce(connectionFactory)) { - throw new AssumptionViolatedException("PFADD is only available for jedis and lettuce"); - } - actual.add(connection.pfCount((String[]) null)); } + /** + * @see DATAREDIS-378 + */ + @SuppressWarnings("unchecked") + @Test + @IfProfileValue(name = "redisVersion", value = "2.9.0+") + @WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE }) + public void zRangeByLexTest() { + + actual.add(connection.zAdd("myzset", 0, "a")); + actual.add(connection.zAdd("myzset", 0, "b")); + actual.add(connection.zAdd("myzset", 0, "c")); + actual.add(connection.zAdd("myzset", 0, "d")); + actual.add(connection.zAdd("myzset", 0, "e")); + actual.add(connection.zAdd("myzset", 0, "f")); + actual.add(connection.zAdd("myzset", 0, "g")); + + actual.add(connection.zRangeByLex("myzset", Range.range().lte("c"))); + actual.add(connection.zRangeByLex("myzset", Range.range().lt("c"))); + actual.add(connection.zRangeByLex("myzset", Range.range().gte("aaa").lt("g"))); + actual.add(connection.zRangeByLex("myzset", Range.range().gte("e"))); + + List results = getResults(); + + Set values = (Set) results.get(7); + + assertThat(values, hasItems("a", "b", "c")); + assertThat(values, not(hasItems("d", "e", "f", "g"))); + + values = (Set) results.get(8); + assertThat(values, hasItems("a", "b")); + assertThat(values, not(hasItem("c"))); + + values = (Set) results.get(9); + assertThat(values, hasItems("b", "c", "d", "e", "f")); + assertThat(values, not(hasItems("a", "g"))); + + values = (Set) results.get(10); + assertThat(values, hasItems("e", "f", "g")); + assertThat(values, not(hasItems("a", "b", "c", "d"))); + } + protected void verifyResults(List expected) { assertEquals(expected, getResults()); } diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionIntegrationTests.java index 4a1ee5a08..01d2e01b4 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionIntegrationTests.java @@ -43,7 +43,6 @@ import org.springframework.data.redis.connection.Message; import org.springframework.data.redis.connection.MessageListener; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisSentinelConfiguration; -import org.springframework.data.redis.connection.RedisZSetCommands.Range; import org.springframework.data.redis.connection.ReturnType; import org.springframework.data.redis.connection.StringRedisConnection.StringTuple; import org.springframework.data.redis.test.util.RedisSentinelRule; @@ -417,37 +416,4 @@ public class JedisConnectionIntegrationTests extends AbstractConnectionIntegrati assertEquals("two", new String(zRangeByScore.iterator().next())); } - - /** - * @see DATAREDIS-378 - */ - @Test - @IfProfileValue(name = "redisVersion", value = "2.9+") - public void zRangeByLexTest() { - - connection.zAdd("myzset", 0, "a"); - connection.zAdd("myzset", 0, "b"); - connection.zAdd("myzset", 0, "c"); - connection.zAdd("myzset", 0, "d"); - connection.zAdd("myzset", 0, "e"); - connection.zAdd("myzset", 0, "f"); - connection.zAdd("myzset", 0, "g"); - - Set values = connection.zRangeByLex("myzset", Range.range().lte("c")); - - assertThat(values, hasItems("a", "b", "c")); - assertThat(values, not(hasItems("d", "e", "f", "g"))); - - values = connection.zRangeByLex("myzset", Range.range().lt("c")); - assertThat(values, hasItems("a", "b")); - assertThat(values, not(hasItem("c"))); - - values = connection.zRangeByLex("myzset", Range.range().gte("aaa").lt("g")); - assertThat(values, hasItems("b", "c", "d", "e", "f")); - assertThat(values, not(hasItems("a", "g"))); - - values = connection.zRangeByLex("myzset", Range.range().gte("e")); - assertThat(values, hasItems("e", "f", "g")); - assertThat(values, not(hasItems("a", "b", "c", "d"))); - } } 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 622e79848..3b53b9b93 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 @@ -29,6 +29,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.hamcrest.core.AllOf; import org.hamcrest.core.IsCollectionContaining; import org.hamcrest.core.IsInstanceOf; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.dao.DataAccessException; @@ -63,6 +64,8 @@ import com.lambdaworks.redis.RedisAsyncConnection; @ContextConfiguration public class LettuceConnectionIntegrationTests extends AbstractConnectionIntegrationTests { + public @Rule RedisSentinelRule sentinelRule = RedisSentinelRule.withDefaultConfig().dynamicModeSelection(); + @Test @IfProfileValue(name = "runLongTests", value = "true") public void testMultiThreadsOneBlocking() throws Exception { 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 3f19493be..1b2232375 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 @@ -1,5 +1,5 @@ /* - * Copyright 2011-2014 the original author or authors. + * Copyright 2011-2015 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. @@ -42,6 +42,7 @@ import org.springframework.test.context.ContextConfiguration; * @author Jennifer Hickey * @author Thomas Darimont * @author Christoph Strobl + * @author Mark Paluch */ @RunWith(RelaxedJUnit4ClassRunner.class) @ContextConfiguration("LettuceConnectionIntegrationTests-context.xml") 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 d4eba631d..38fcc60fc 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-2014 the original author or authors. + * Copyright 2011-2015 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. @@ -33,6 +33,7 @@ import org.springframework.test.context.ContextConfiguration; * @author Jennifer Hickey * @author Thomas Darimont * @author Christoph Strobl + * @author Mark Paluch */ @RunWith(RelaxedJUnit4ClassRunner.class) @ContextConfiguration("LettuceConnectionIntegrationTests-context.xml") diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionUnitTestSuite.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionUnitTestSuite.java index 707ee36a0..5719a18e7 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionUnitTestSuite.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionUnitTestSuite.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2015 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,8 +15,7 @@ */ package org.springframework.data.redis.connection.lettuce; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.*; import static org.mockito.Mockito.*; import java.lang.reflect.InvocationTargetException; @@ -37,6 +36,7 @@ import com.lambdaworks.redis.codec.RedisCodec; /** * @author Christoph Strobl + * @author Mark Paluch */ @RunWith(Suite.class) @Suite.SuiteClasses({ LettuceConnectionUnitTests.class, LettucePipelineConnectionUnitTests.class }) @@ -87,8 +87,6 @@ public class LettuceConnectionUnitTestSuite { } /** - * <<<<<<< HEAD - * * @see DATAREDIS-267 */ @Test diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnectionUnitTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnectionUnitTests.java index b821991b4..86fc1afb3 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnectionUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnectionUnitTests.java @@ -15,7 +15,7 @@ */ package org.springframework.data.redis.connection.lettuce; -import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.*; import static org.mockito.Mockito.*; import java.util.List; @@ -29,9 +29,6 @@ import org.mockito.runners.MockitoJUnitRunner; import org.springframework.data.redis.connection.RedisNode; import org.springframework.data.redis.connection.RedisNode.RedisNodeBuilder; import org.springframework.data.redis.connection.RedisServer; -import org.springframework.data.redis.connection.jedis.JedisSentinelConnection; - -import redis.clients.jedis.Jedis; import com.lambdaworks.redis.RedisClient; import com.lambdaworks.redis.RedisFuture; @@ -45,8 +42,9 @@ import com.lambdaworks.redis.RedisSentinelAsyncConnection; public class LettuceSentinelConnectionUnitTests { public static final String MASTER_ID = "mymaster"; + private @Mock RedisClient redisClientMock; - + private @Mock RedisSentinelAsyncConnection connectionMock; private @Mock RedisFuture>> redisFutureMock; @@ -68,21 +66,6 @@ public class LettuceSentinelConnectionUnitTests { verify(redisClientMock, times(1)).connectSentinelAsync(); } - /** - * @see DATAREDIS-348 - */ - @SuppressWarnings("resource") - @Test - public void shouldNotConnectIfAlreadyConnected() { - - Jedis yetAnotherJedisMock = mock(Jedis.class); - when(yetAnotherJedisMock.isConnected()).thenReturn(true); - - new JedisSentinelConnection(yetAnotherJedisMock); - - verify(yetAnotherJedisMock, never()).connect(); - } - /** * @see DATAREDIS-348 */ 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 8ec068115..67cb38835 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 2014 the original author or authors. + * Copyright 2015 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. @@ -21,51 +21,41 @@ import static org.junit.Assert.*; import java.util.Collection; import java.util.List; -import org.junit.*; -import org.springframework.dao.InvalidDataAccessApiUsageException; -import org.springframework.data.redis.connection.*; -import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.springframework.data.redis.connection.AbstractConnectionIntegrationTests; +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.test.util.RedisSentinelRule; -import org.springframework.test.annotation.IfProfileValue; /** - * @author Christoph Strobl - * @author Thomas Darimont * @author Mark Paluch + * @author Christoph Strobl */ public class LettuceSentinelIntegrationTests extends AbstractConnectionIntegrationTests { - + private static final String MASTER_NAME = "mymaster"; private static final RedisServer SENTINEL_0 = new RedisServer("127.0.0.1", 26379); private static final RedisServer SENTINEL_1 = new RedisServer("127.0.0.1", 26380); - + private static final RedisServer SLAVE_0 = new RedisServer("127.0.0.1", 6380); private static final RedisServer SLAVE_1 = new RedisServer("127.0.0.1", 6381); - + private static final RedisSentinelConfiguration SENTINEL_CONFIG = new RedisSentinelConfiguration() // - .master(MASTER_NAME) - .sentinel(SENTINEL_0) - .sentinel(SENTINEL_1); + .master(MASTER_NAME).sentinel(SENTINEL_0).sentinel(SENTINEL_1); public @Rule RedisSentinelRule sentinelRule = RedisSentinelRule.forConfig(SENTINEL_CONFIG).oneActive(); - private static LettuceConnectionFactory lettuceConnectionFactory; + @Before + public void setUp() { - @BeforeClass - public static void beforeClass(){ LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(SENTINEL_CONFIG); lettuceConnectionFactory.setShareNativeConnection(false); lettuceConnectionFactory.afterPropertiesSet(); - LettuceSentinelIntegrationTests.lettuceConnectionFactory = lettuceConnectionFactory; - } - @AfterClass - public static void afterClass(){ - LettuceSentinelIntegrationTests.lettuceConnectionFactory.destroy(); - } - - @Before - public void setUp() { connectionFactory = lettuceConnectionFactory; super.setUp(); } @@ -73,6 +63,7 @@ public class LettuceSentinelIntegrationTests extends AbstractConnectionIntegrati @After public void tearDown() { super.tearDown(); + ((LettuceConnectionFactory) connectionFactory).destroy(); } /** @@ -83,9 +74,9 @@ public class LettuceSentinelIntegrationTests extends AbstractConnectionIntegrati List servers = (List) connectionFactory.getSentinelConnection().masters(); assertThat(servers.size(), is(1)); - assertThat(servers.get(0).getName(),is(MASTER_NAME)); + assertThat(servers.get(0).getName(), is(MASTER_NAME)); } - + /** * @see DATAREDIS-348 */ @@ -93,10 +84,10 @@ public class LettuceSentinelIntegrationTests extends AbstractConnectionIntegrati public void shouldReadSlavesOfMastersCorrectly() { RedisSentinelConnection sentinelConnection = connectionFactory.getSentinelConnection(); - + List servers = (List) sentinelConnection.masters(); assertThat(servers.size(), is(1)); - + Collection slaves = sentinelConnection.slaves(servers.get(0)); assertThat(slaves.size(), is(2)); assertThat(slaves, hasItems(SLAVE_0, SLAVE_1)); diff --git a/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisMapTests.java b/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisMapTests.java index d6e2f5297..cf540b0cb 100644 --- a/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisMapTests.java +++ b/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisMapTests.java @@ -44,7 +44,6 @@ import org.springframework.data.redis.DoubleAsStringObjectFactory; import org.springframework.data.redis.LongAsStringObjectFactory; import org.springframework.data.redis.ObjectFactory; import org.springframework.data.redis.RedisSystemException; -import org.springframework.data.redis.RedisVersionUtils; import org.springframework.data.redis.connection.ConnectionUtils; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisConnectionFactory; @@ -220,7 +219,6 @@ public abstract class AbstractRedisMapTests { map.put(k1, v1); try { Long value = map.increment(k1, 1); - System.out.println("Value is " + value); } catch (InvalidDataAccessApiUsageException ex) { // expected } catch (RedisSystemException ex) { @@ -238,9 +236,9 @@ public abstract class AbstractRedisMapTests { } @Test + @IfProfileValue(name = "redisVersion", value = "2.6+") public void testIncrementDouble() { - assumeTrue(RedisVersionUtils.atLeast("2.6", template.getConnectionFactory().getConnection()) - && valueFactory instanceof DoubleAsStringObjectFactory); + assumeTrue(valueFactory instanceof DoubleAsStringObjectFactory); K k1 = getKey(); V v1 = getValue(); map.put(k1, v1); diff --git a/src/test/java/org/springframework/data/redis/test/util/MinimumRedisVersionRule.java b/src/test/java/org/springframework/data/redis/test/util/MinimumRedisVersionRule.java index 9cc28c785..1ce20f3e1 100644 --- a/src/test/java/org/springframework/data/redis/test/util/MinimumRedisVersionRule.java +++ b/src/test/java/org/springframework/data/redis/test/util/MinimumRedisVersionRule.java @@ -15,6 +15,8 @@ */ package org.springframework.data.redis.test.util; +import java.io.IOException; + import org.junit.internal.AssumptionViolatedException; import org.junit.rules.TestRule; import org.junit.runner.Description; @@ -22,12 +24,12 @@ import org.junit.runners.model.Statement; import org.springframework.data.redis.RedisVersionUtils; import org.springframework.data.redis.SettingsUtils; import org.springframework.data.redis.Version; -import org.springframework.data.redis.connection.RedisConnection; -import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; -import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.connection.jedis.JedisConverters; import org.springframework.test.annotation.IfProfileValue; import org.springframework.util.StringUtils; +import redis.clients.jedis.Jedis; + /** * {@link MinimumRedisVersionRule} is a custom {@link TestRule} validating {@literal redisVersion} given in * {@link IfProfileValue} against used redis server version. @@ -38,29 +40,46 @@ import org.springframework.util.StringUtils; public class MinimumRedisVersionRule implements TestRule { private static final String PROFILE_NAME = "redisVersion"; - private Version redisVersion; + private static final Version redisVersion; - public MinimumRedisVersionRule() { - this.redisVersion = readServerVersion(); + public MinimumRedisVersionRule() {} + + static { + redisVersion = readServerVersion(); } - private Version readServerVersion() { + private static synchronized Version readServerVersion() { - JedisConnectionFactory connectionFactory = new JedisConnectionFactory(); - connectionFactory.setHostName(SettingsUtils.getHost()); - connectionFactory.setPort(SettingsUtils.getPort()); - connectionFactory.setTimeout(100); - - connectionFactory.afterPropertiesSet(); - RedisConnection connection = connectionFactory.getConnection(); + Jedis jedis = new Jedis(SettingsUtils.getHost(), SettingsUtils.getPort()); Version version = Version.UNKNOWN; try { - version = RedisVersionUtils.getRedisVersion(connection); - connection.close(); + + jedis.connect(); + String info = jedis.info(); + String versionString = (String) JedisConverters.stringToProps().convert(info).get("redis_version"); + + version = RedisVersionUtils.parseVersion(versionString); } finally { - connectionFactory.destroy(); + try { + + jedis.disconnect(); + if (jedis.getClient().getSocket().isConnected()) { + // force socket to be closed + jedis.getClient().getSocket().close(); + try { + // need to wait a bit + Thread.sleep(100); + } catch (InterruptedException e) { + // just ignore it + } + } + + } catch (IOException e1) { + // ignore as well + } + jedis.close(); } return version; diff --git a/src/test/java/org/springframework/data/redis/test/util/RedisClientRule.java b/src/test/java/org/springframework/data/redis/test/util/RedisClientRule.java index aecdf6ae1..3f4901e49 100644 --- a/src/test/java/org/springframework/data/redis/test/util/RedisClientRule.java +++ b/src/test/java/org/springframework/data/redis/test/util/RedisClientRule.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2015 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. @@ -43,15 +43,14 @@ public abstract class RedisClientRule implements TestRule { if (withRedisDriver != null && redisConnectionFactory != null) { - boolean valid = true; for (RedisDriver driver : withRedisDriver.value()) { - valid &= driver.matches(redisConnectionFactory); - - if (!valid) { - throw new AssumptionViolatedException("not a vaild redis connection for driver: " + driver); + if (driver.matches(redisConnectionFactory)) { + base.evaluate(); + return; } } + throw new AssumptionViolatedException("not a vaild redis connection for driver: " + redisConnectionFactory); } base.evaluate(); diff --git a/src/test/java/org/springframework/data/redis/test/util/RedisSentinelRule.java b/src/test/java/org/springframework/data/redis/test/util/RedisSentinelRule.java index 147f6c423..86680ee3a 100644 --- a/src/test/java/org/springframework/data/redis/test/util/RedisSentinelRule.java +++ b/src/test/java/org/springframework/data/redis/test/util/RedisSentinelRule.java @@ -161,8 +161,9 @@ public class RedisSentinelRule implements TestRule { jedis = new Jedis(node.getHost(), node.getPort()); jedis.connect(); jedis.ping(); - } catch (Exception e) { + return true; + } catch (Exception e) { return false; } finally { @@ -170,14 +171,16 @@ public class RedisSentinelRule implements TestRule { try { jedis.disconnect(); + if (jedis.getClient().getSocket().isConnected()) { + jedis.getClient().getSocket().close(); + Thread.sleep(100); + } + jedis.close(); } catch (Exception e) { - e.printStackTrace(); } } } - - return true; } } diff --git a/src/test/resources/org/springframework/data/redis/test.properties b/src/test/resources/org/springframework/data/redis/test.properties index ea1fbe81a..40b884246 100644 --- a/src/test/resources/org/springframework/data/redis/test.properties +++ b/src/test/resources/org/springframework/data/redis/test.properties @@ -1,3 +1,3 @@ # redis connection properties -host=localhost +host=127.0.0.1 port=6379 \ No newline at end of file