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