ClusterClientBuilderTest.java
package redis.clients.jedis.builders;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import redis.clients.jedis.CommandObject;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.args.Rawable;
import redis.clients.jedis.executors.CommandExecutor;
import redis.clients.jedis.json.JsonObjectMapper;
import redis.clients.jedis.json.Path2;
import redis.clients.jedis.providers.ConnectionProvider;
import redis.clients.jedis.search.FTSearchParams;
@ExtendWith(MockitoExtension.class)
class ClusterClientBuilderTest {
@Mock
CommandExecutor exec;
@Mock
ConnectionProvider provider;
@Captor
ArgumentCaptor<CommandObject<?>> cap;
private static List<String> argsToStrings(CommandObject<?> co) {
List<String> out = new ArrayList<>();
for (Rawable r : co.getArguments()) {
out.add(new String(r.getRaw(), StandardCharsets.UTF_8));
}
return out;
}
private static Set<HostAndPort> someNodes() {
Set<HostAndPort> nodes = new HashSet<>();
nodes.add(new HostAndPort("127.0.0.1", 7000));
return nodes;
}
@Test
void clusterNodesEmptyShouldThrow() {
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
() -> new JedisCluster.Builder() {
}.nodes(new HashSet<>()).build());
assertThat(ex.getMessage(),
containsString("At least one cluster node must be specified for cluster mode"));
}
@Test
void negativeMaxTotalRetriesDurationShouldThrow() {
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
() -> new JedisCluster.Builder() {
}.nodes(someNodes()).maxTotalRetriesDuration(Duration.ofMillis(-1)).build());
assertThat(ex.getMessage(),
containsString("Max total retries duration cannot be negative for cluster mode"));
}
@Test
void negativeTopologyRefreshShouldThrow() {
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
() -> new JedisCluster.Builder() {
}.nodes(someNodes()).topologyRefreshPeriod(Duration.ofMillis(-1)).build());
assertThat(ex.getMessage(),
containsString("Topology refresh period cannot be negative for cluster mode"));
}
@Test
void buildWithPositiveDurationsAndConfig_usesProvidedExecAndProvider() {
try (JedisCluster client = JedisCluster.builder().nodes(someNodes())
.clientConfig(redis.clients.jedis.DefaultJedisClientConfig.builder().build()).maxAttempts(3)
.maxTotalRetriesDuration(Duration.ofMillis(10)).topologyRefreshPeriod(Duration.ofMillis(50))
.connectionProvider(provider).commandExecutor(exec).build()) {
client.ping();
}
verify(exec, atLeastOnce()).broadcastCommand(cap.capture());
assertThat(argsToStrings(cap.getValue()).get(0), containsString("PING"));
}
@Test
void nodesNotProvidedShouldThrow() {
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
() -> new JedisCluster.Builder() {
}.build());
assertThat(ex.getMessage(),
containsString("At least one cluster node must be specified for cluster mode"));
}
@Test
void searchDialectZeroShouldThrow() {
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
() -> JedisCluster.builder().searchDialect(0));
assertThat(ex.getMessage(), containsString("DIALECT=0 cannot be set."));
}
@Test
void keyPreprocessorAppliedInCluster() {
try (
JedisCluster client = JedisCluster.builder().nodes(someNodes()).connectionProvider(provider)
.commandExecutor(exec).keyPreProcessor(k -> "prefix:" + k).build()) {
client.set("k", "v");
verify(exec).executeCommand(cap.capture());
List<String> args = argsToStrings(cap.getValue());
// SET prefix:k v
assertThat(args.get(0), containsString("SET"));
assertEquals("prefix:k", args.get(1));
assertEquals("v", args.get(2));
}
}
@Test
void jsonObjectMapperAppliedInCluster() {
JsonObjectMapper mapper = Mockito.mock(JsonObjectMapper.class);
when(mapper.toJson(Mockito.any())).thenReturn("JSON:obj");
try (JedisCluster client = JedisCluster.builder().nodes(someNodes())
.connectionProvider(provider).commandExecutor(exec).jsonObjectMapper(mapper).build()) {
client.jsonSetWithEscape("k", Path2.ROOT_PATH, Collections.singletonMap("a", 1));
verify(exec).executeCommand(cap.capture());
List<String> args = argsToStrings(cap.getValue());
// JSON.SET k $ JSON:obj
assertEquals("JSON.SET", args.get(0));
assertEquals("k", args.get(1));
assertEquals("$", args.get(2));
assertEquals("JSON:obj", args.get(3));
}
}
@Test
void searchDialectAppliedInCluster() {
try (JedisCluster client = JedisCluster.builder().nodes(someNodes())
.connectionProvider(provider).commandExecutor(exec).searchDialect(3).build()) {
client.ftSearch("idx", "q", new FTSearchParams());
verify(exec, atLeastOnce()).executeCommand(cap.capture());
List<String> args = argsToStrings(cap.getValue());
// FT.SEARCH idx q DIALECT 3
assertEquals("FT.SEARCH", args.get(0));
assertEquals("idx", args.get(1));
assertEquals("q", args.get(2));
assertEquals("DIALECT", args.get(3));
assertEquals("3", args.get(4));
}
}
}