DATAREDIS-315 - Polishing.

Update documentation and fix spelling in JavaDoc and reference documentation.

Allow node lookup by host/port and node Id to enable flexibility when passing references to Redis Cluster nodes. Parse multiple slot ranges for a cluster node and move CLUSTER NODES parser to Converters.

Use fixed line separator instead of OS-specific line separator, consolidate duplicate code, support clusterSetSlotStable with lettuce 3.4 and set lettuce driver shutdown timeout to zero for long running tests.

Original pull request: #158.
This commit is contained in:
Mark Paluch
2016-02-01 15:27:27 +01:00
parent c5047f40c6
commit c105cbb7b6
27 changed files with 427 additions and 161 deletions

View File

@@ -31,6 +31,7 @@ import redis.clients.jedis.Jedis;
* @author Jennifer Hickey
* @author Christoph Strobl
* @author Thomas Darimont
* @author Mark Paluch
*/
public class RedisTestProfileValueSource implements ProfileValueSource {
@@ -56,7 +57,6 @@ public class RedisTestProfileValueSource implements ProfileValueSource {
try {
jedis = new Jedis(SettingsUtils.getHost(), SettingsUtils.getPort(), 100);
// jedis.connect();
String info = jedis.info();
String versionString = (String) JedisConverters.stringToProps().convert(info).get("redis_version");

View File

@@ -51,6 +51,7 @@ import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor;
/**
* @author Christoph Strobl
* @author Mark Paluch
*/
@RunWith(MockitoJUnitRunner.class)
public class ClusterCommandExecutorUnitTests {
@@ -75,6 +76,9 @@ public class ClusterCommandExecutorUnitTests {
.listeningAt(CLUSTER_NODE_3_HOST, CLUSTER_NODE_3_PORT).serving(new SlotRange(10923, 16383))
.withId("3b9b8192a874fa8f1f09dbc0ee20afab5738eee7").promotedAs(NodeType.MASTER).linkState(LinkState.CONNECTED)
.build();
static final RedisClusterNode CLUSTER_NODE_2_LOOKUP = RedisClusterNode.newRedisClusterNode()
.withId("0f2ee5df45d18c50aca07228cc18b1da96fd5e84")
.build();
static final RedisClusterNode UNKNOWN_CLUSTER_NODE = new RedisClusterNode("8.8.8.8", 7379, null);
@@ -139,6 +143,28 @@ public class ClusterCommandExecutorUnitTests {
verify(con2, times(1)).theWheelWeavesAsTheWheelWills();
}
/**
* @see DATAREDIS-315
*/
@Test
public void executeCommandOnSingleNodeByHostAndPortShouldBeExecutedCorrectly() {
executor.executeCommandOnSingleNode(COMMAND_CALLBACK, new RedisClusterNode(CLUSTER_NODE_2_HOST, CLUSTER_NODE_2_PORT));
verify(con2, times(1)).theWheelWeavesAsTheWheelWills();
}
/**
* @see DATAREDIS-315
*/
@Test
public void executeCommandOnSingleNodeByNodeIdShouldBeExecutedCorrectly() {
executor.executeCommandOnSingleNode(COMMAND_CALLBACK, new RedisClusterNode(CLUSTER_NODE_2.id));
verify(con2, times(1)).theWheelWeavesAsTheWheelWills();
}
/**
* @see DATAREDIS-315
*/
@@ -184,7 +210,57 @@ public class ClusterCommandExecutorUnitTests {
* @see DATAREDIS-315
*/
@Test
public void executeCommandOnAllNodesShouldExecuteCommandOnEveryKnwonClusterNode() {
public void executeCommandAsyncOnNodesShouldExecuteCommandOnGivenNodesByHostAndPort() {
ClusterCommandExecutor executor = new ClusterCommandExecutor(new MockClusterNodeProvider(),
new MockClusterResourceProvider(), new PassThroughExceptionTranslationStrategy(exceptionConverter),
new ConcurrentTaskExecutor(new SyncTaskExecutor()));
executor.executeCommandAsyncOnNodes(COMMAND_CALLBACK, Arrays.asList(new RedisClusterNode(CLUSTER_NODE_1_HOST, CLUSTER_NODE_1_PORT),
new RedisClusterNode(CLUSTER_NODE_2_HOST, CLUSTER_NODE_2_PORT)));
verify(con1, times(1)).theWheelWeavesAsTheWheelWills();
verify(con2, times(1)).theWheelWeavesAsTheWheelWills();
verify(con3, never()).theWheelWeavesAsTheWheelWills();
}
/**
* @see DATAREDIS-315
*/
@Test
public void executeCommandAsyncOnNodesShouldExecuteCommandOnGivenNodesByNodeId() {
ClusterCommandExecutor executor = new ClusterCommandExecutor(new MockClusterNodeProvider(),
new MockClusterResourceProvider(), new PassThroughExceptionTranslationStrategy(exceptionConverter),
new ConcurrentTaskExecutor(new SyncTaskExecutor()));
executor.executeCommandAsyncOnNodes(COMMAND_CALLBACK, Arrays.asList(new RedisClusterNode(CLUSTER_NODE_1.id),
CLUSTER_NODE_2_LOOKUP));
verify(con1, times(1)).theWheelWeavesAsTheWheelWills();
verify(con2, times(1)).theWheelWeavesAsTheWheelWills();
verify(con3, never()).theWheelWeavesAsTheWheelWills();
}
/**
* @see DATAREDIS-315
*/
@Test(expected = IllegalArgumentException.class)
public void executeCommandAsyncOnNodesShouldFailOnGivenUnknownNodes() {
ClusterCommandExecutor executor = new ClusterCommandExecutor(new MockClusterNodeProvider(),
new MockClusterResourceProvider(), new PassThroughExceptionTranslationStrategy(exceptionConverter),
new ConcurrentTaskExecutor(new SyncTaskExecutor()));
executor.executeCommandAsyncOnNodes(COMMAND_CALLBACK, Arrays.asList(
new RedisClusterNode("unknown"), CLUSTER_NODE_2_LOOKUP));
}
/**
* @see DATAREDIS-315
*/
@Test
public void executeCommandOnAllNodesShouldExecuteCommandOnEveryKnownClusterNode() {
ClusterCommandExecutor executor = new ClusterCommandExecutor(new MockClusterNodeProvider(),
new MockClusterResourceProvider(), new PassThroughExceptionTranslationStrategy(exceptionConverter),

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* 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.
@@ -27,20 +27,20 @@ import org.springframework.data.redis.connection.RedisClusterNode;
import org.springframework.data.redis.connection.RedisClusterNode.Flag;
import org.springframework.data.redis.connection.RedisClusterNode.LinkState;
import org.springframework.data.redis.connection.RedisNode.NodeType;
import org.springframework.data.redis.connection.jedis.JedisConverters;
/**
* @author Christoph Strobl
* @author Mark Paluch
*/
public class ConvertersUnitTests {
private static final String CLUSTER_NODES_RESPONSE = "" //
+ "ef570f86c7b1a953846668debc177a3a16733420 127.0.0.1:6379 myself,master - 0 0 1 connected 0-5460"
+ System.getProperty("line.separator")
+ "0f2ee5df45d18c50aca07228cc18b1da96fd5e84 127.0.0.1:6380 master - 0 1427718161587 2 connected 5461-10922"
+ System.getProperty("line.separator")
+ "ef570f86c7b1a953846668debc177a3a16733420 127.0.0.1:6379 myself,master - 0 0 1 connected 0-5460 5602"
+ "\n"
+ "0f2ee5df45d18c50aca07228cc18b1da96fd5e84 127.0.0.1:6380 master - 0 1427718161587 2 connected 5461 5603-10922"
+ "\n"
+ "3b9b8192a874fa8f1f09dbc0ee20afab5738eee7 127.0.0.1:6381 master - 0 1427718161587 3 connected 10923-16383"
+ System.getProperty("line.separator")
+ "\n"
+ "8cad73f63eb996fedba89f041636f17d88cda075 127.0.0.1:7369 slave ef570f86c7b1a953846668debc177a3a16733420 0 1427718161587 1 connected";
private static final String CLUSTER_NODE_WITH_SINGLE_SLOT_RESPONSE = "ef570f86c7b1a953846668debc177a3a16733420 127.0.0.1:6379 myself,master - 0 0 1 connected 3456";
@@ -55,7 +55,7 @@ public class ConvertersUnitTests {
@Test
public void toSetOfRedisClusterNodesShouldConvertSingleStringNodesResponseCorrectly() {
Iterator<RedisClusterNode> nodes = JedisConverters.toSetOfRedisClusterNodes(CLUSTER_NODES_RESPONSE).iterator();
Iterator<RedisClusterNode> nodes = Converters.toSetOfRedisClusterNodes(CLUSTER_NODES_RESPONSE).iterator();
RedisClusterNode node = nodes.next(); // 127.0.0.1:6379
assertThat(node.getId(), is("ef570f86c7b1a953846668debc177a3a16733420"));
@@ -64,6 +64,8 @@ public class ConvertersUnitTests {
assertThat(node.getType(), is(NodeType.MASTER));
assertThat(node.getSlotRange().contains(0), is(true));
assertThat(node.getSlotRange().contains(5460), is(true));
assertThat(node.getSlotRange().contains(5461), is(false));
assertThat(node.getSlotRange().contains(5602), is(true));
assertThat(node.getFlags(), hasItems(Flag.MASTER, Flag.MYSELF));
assertThat(node.getLinkState(), is(LinkState.CONNECTED));
@@ -72,7 +74,9 @@ public class ConvertersUnitTests {
assertThat(node.getHost(), is("127.0.0.1"));
assertThat(node.getPort(), is(6380));
assertThat(node.getType(), is(NodeType.MASTER));
assertThat(node.getSlotRange().contains(5460), is(false));
assertThat(node.getSlotRange().contains(5461), is(true));
assertThat(node.getSlotRange().contains(5462), is(false));
assertThat(node.getSlotRange().contains(10922), is(true));
assertThat(node.getFlags(), hasItems(Flag.MASTER));
assertThat(node.getLinkState(), is(LinkState.CONNECTED));
@@ -102,9 +106,9 @@ public class ConvertersUnitTests {
* @see DATAREDIS-315
*/
@Test
public void toSetOfRedisClusterNodesShouldConvertNodesWihtSingleSlotCorrectly() {
public void toSetOfRedisClusterNodesShouldConvertNodesWithSingleSlotCorrectly() {
Iterator<RedisClusterNode> nodes = JedisConverters.toSetOfRedisClusterNodes(CLUSTER_NODE_WITH_SINGLE_SLOT_RESPONSE)
Iterator<RedisClusterNode> nodes = Converters.toSetOfRedisClusterNodes(CLUSTER_NODE_WITH_SINGLE_SLOT_RESPONSE)
.iterator();
RedisClusterNode node = nodes.next(); // 127.0.0.1:6379
@@ -121,7 +125,7 @@ public class ConvertersUnitTests {
@Test
public void toSetOfRedisClusterNodesShouldParseLinkStateAndDisconnectedCorrectly() {
Iterator<RedisClusterNode> nodes = JedisConverters.toSetOfRedisClusterNodes(
Iterator<RedisClusterNode> nodes = Converters.toSetOfRedisClusterNodes(
CLUSTER_NODE_WITH_FAIL_FLAG_AND_DISCONNECTED_LINK_STATE).iterator();
RedisClusterNode node = nodes.next();
@@ -140,7 +144,7 @@ public class ConvertersUnitTests {
@Test
public void toSetOfRedisClusterNodesShouldIgnoreImportingSlot() {
Iterator<RedisClusterNode> nodes = JedisConverters.toSetOfRedisClusterNodes(CLUSTER_NODE_IMPORTING_SLOT).iterator();
Iterator<RedisClusterNode> nodes = Converters.toSetOfRedisClusterNodes(CLUSTER_NODE_IMPORTING_SLOT).iterator();
RedisClusterNode node = nodes.next();
assertThat(node.getId(), is("ef570f86c7b1a953846668debc177a3a16733420"));

View File

@@ -59,6 +59,7 @@ import redis.clients.jedis.exceptions.JedisDataException;
/**
* @author Christoph Strobl
* @author Mark Paluch
*/
public class JedisClusterConnectionTests implements ClusterConnectionTests {

View File

@@ -35,7 +35,7 @@ import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.data.redis.ClusterStateFailureExeption;
import org.springframework.data.redis.ClusterStateFailureException;
import org.springframework.data.redis.connection.ClusterInfo;
import org.springframework.data.redis.connection.RedisClusterCommands.AddSlots;
import org.springframework.data.redis.connection.RedisClusterNode;
@@ -48,6 +48,7 @@ import redis.clients.jedis.exceptions.JedisConnectionException;
/**
* @author Christoph Strobl
* @author Mark Paluch
*/
@RunWith(MockitoJUnitRunner.class)
public class JedisClusterConnectionUnitTests {
@@ -55,20 +56,20 @@ public class JedisClusterConnectionUnitTests {
private static final String CLUSTER_NODES_RESPONSE = "" //
+ MASTER_NODE_1_ID + " " + CLUSTER_HOST + ":" + MASTER_NODE_1_PORT
+ " myself,master - 0 0 1 connected 0-5460"
+ System.getProperty("line.separator") + MASTER_NODE_2_ID + " " + CLUSTER_HOST + ":"
+ "\n" + MASTER_NODE_2_ID + " " + CLUSTER_HOST + ":"
+ MASTER_NODE_2_PORT
+ " master - 0 1427718161587 2 connected 5461-10922" + System.getProperty("line.separator")
+ " master - 0 1427718161587 2 connected 5461-10922" + "\n"
+ MASTER_NODE_2_ID
+ " " + CLUSTER_HOST + ":" + MASTER_NODE_3_PORT + " master - 0 1427718161587 3 connected 10923-16383";
static final String CLUSTER_INFO_RESPONSE = "cluster_state:ok" + System.getProperty("line.separator")
+ "cluster_slots_assigned:16384" + System.getProperty("line.separator") + "cluster_slots_ok:16384"
+ System.getProperty("line.separator") + "cluster_slots_pfail:0" + System.getProperty("line.separator")
+ "cluster_slots_fail:0" + System.getProperty("line.separator") + "cluster_known_nodes:4"
+ System.getProperty("line.separator") + "cluster_size:3" + System.getProperty("line.separator")
+ "cluster_current_epoch:30" + System.getProperty("line.separator") + "cluster_my_epoch:2"
+ System.getProperty("line.separator") + "cluster_stats_messages_sent:2560260"
+ System.getProperty("line.separator") + "cluster_stats_messages_received:2560086";
static final String CLUSTER_INFO_RESPONSE = "cluster_state:ok" + "\n"
+ "cluster_slots_assigned:16384" + "\n" + "cluster_slots_ok:16384"
+ "\n" + "cluster_slots_pfail:0" + "\n"
+ "cluster_slots_fail:0" + "\n" + "cluster_known_nodes:4"
+ "\n" + "cluster_size:3" + "\n"
+ "cluster_current_epoch:30" + "\n" + "cluster_my_epoch:2"
+ "\n" + "cluster_stats_messages_sent:2560260"
+ "\n" + "cluster_stats_messages_received:2560086";
JedisClusterConnection connection;
@@ -159,6 +160,7 @@ public class JedisClusterConnectionUnitTests {
connection.clusterReplicate(CLUSTER_NODE_1, CLUSTER_NODE_2);
verify(con2Mock, times(1)).clusterReplicate(CLUSTER_NODE_1.getId());
verify(con1Mock, times(1)).clusterNodes();
verifyZeroInteractions(con1Mock);
}
@@ -312,6 +314,7 @@ public class JedisClusterConnectionUnitTests {
connection.time(CLUSTER_NODE_2);
verify(con2Mock, times(1)).time();
verify(con1Mock, times(1)).clusterNodes();
verifyZeroInteractions(con1Mock, con3Mock);
}
@@ -347,7 +350,7 @@ public class JedisClusterConnectionUnitTests {
@Test
public void clusterTopologyProviderShouldCollectErrorsWhenLoadingNodes() {
expectedException.expect(ClusterStateFailureExeption.class);
expectedException.expect(ClusterStateFailureException.class);
expectedException.expectMessage("127.0.0.1:7379 failed: o.O");
expectedException.expectMessage("127.0.0.1:7380 failed: o.1");
expectedException.expectMessage("127.0.0.1:7381 failed: o.2");

View File

@@ -17,6 +17,8 @@ package org.springframework.data.redis.connection.lettuce;
import static org.junit.Assert.*;
import java.util.concurrent.TimeUnit;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.junit.After;
import org.junit.Ignore;
@@ -34,6 +36,7 @@ import com.lambdaworks.redis.RedisException;
* @author Jennifer Hickey
* @author Thomas Darimont
* @author Christoph Strobl
* @author Mark Paluch
*/
public class DefaultLettucePoolTests {
@@ -44,7 +47,7 @@ public class DefaultLettucePoolTests {
if (this.pool != null) {
if (this.pool.getClient() != null) {
this.pool.getClient().shutdown();
this.pool.getClient().shutdown(0, 0, TimeUnit.MILLISECONDS);
}
this.pool.destroy();

View File

@@ -33,7 +33,6 @@ import java.util.concurrent.TimeUnit;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.ClusterConnectionTests;
@@ -58,6 +57,7 @@ import com.lambdaworks.redis.cluster.RedisClusterClient;
/**
* @author Christoph Strobl
* @author Mark Paluch
*/
public class LettuceClusterConnectionTests implements ClusterConnectionTests {
@@ -2129,7 +2129,6 @@ public class LettuceClusterConnectionTests implements ClusterConnectionTests {
* @see DATAREDIS-315
*/
@Test
@Ignore("Should work in 3.4 but does not work in 3.3.2")
public void countKeysShouldReturnNumberOfKeysInSlot() {
nativeConnection.set(SAME_SLOT_KEY_1, VALUE_1);

View File

@@ -49,6 +49,7 @@ import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode.NodeFlag
/**
* @author Christoph Strobl
* @author Mark Paluch
*/
@RunWith(MockitoJUnitRunner.class)
public class LettuceClusterConnectionUnitTests {
@@ -116,7 +117,7 @@ public class LettuceClusterConnectionUnitTests {
}
@Override
public List<RedisClusterNode> clusterGetClusterNodes() {
public List<RedisClusterNode> clusterGetNodes() {
return Arrays.asList(CLUSTER_NODE_1, CLUSTER_NODE_2, CLUSTER_NODE_3);
}
};
@@ -306,12 +307,11 @@ public class LettuceClusterConnectionUnitTests {
* @see DATAREDIS-315
*/
@Test
@Ignore("Stable not available for lettuce")
public void clusterSetSlotStableShouldBeExecutedCorrectly() {
connection.clusterSetSlot(CLUSTER_NODE_1, 100, AddSlots.STABLE);
// verify(clusterConnection1Mock, times(1)).clusterSetSlotStable(eq(100));
verify(clusterConnection1Mock, times(1)).clusterSetSlotStable(eq(100));
}
/**

View File

@@ -46,6 +46,7 @@ public class LettuceConnectionTransactionIntegrationTests extends AbstractConnec
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.setShutdownTimeout(0);
factory2.setDatabase(1);
factory2.afterPropertiesSet();
StringRedisConnection conn2 = new DefaultStringRedisConnection(factory2.getConnection());

View File

@@ -54,6 +54,7 @@ public class LettuceSentinelIntegrationTests extends AbstractConnectionIntegrati
LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(SENTINEL_CONFIG);
lettuceConnectionFactory.setShareNativeConnection(false);
lettuceConnectionFactory.setShutdownTimeout(0);
lettuceConnectionFactory.afterPropertiesSet();
connectionFactory = lettuceConnectionFactory;

View File

@@ -27,6 +27,7 @@ import org.springframework.data.redis.core.script.DefaultScriptExecutor;
* Integration test of {@link DefaultScriptExecutor} with Lettuce.
*
* @author Thomas Darimont
* @author Mark Paluch
*/
public class LettuceDefaultScriptExecutorTests extends AbstractDefaultScriptExecutorTests {
@@ -36,6 +37,7 @@ public class LettuceDefaultScriptExecutorTests extends AbstractDefaultScriptExec
public void setup() {
connectionFactory = new LettuceConnectionFactory(SettingsUtils.getHost(), SettingsUtils.getPort());
connectionFactory.setShutdownTimeout(0);
connectionFactory.afterPropertiesSet();
}