Add test for Redis timeouts
This commit is contained in:
parent
463dd9d7d8
commit
457ecf145f
|
@ -7,6 +7,7 @@ package org.whispersystems.textsecuregcm.redis;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
@ -22,8 +23,11 @@ import io.lettuce.core.cluster.pubsub.StatefulRedisClusterPubSubConnection;
|
||||||
import io.lettuce.core.event.EventBus;
|
import io.lettuce.core.event.EventBus;
|
||||||
import io.lettuce.core.resource.ClientResources;
|
import io.lettuce.core.resource.ClientResources;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Nested;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
import org.whispersystems.textsecuregcm.configuration.CircuitBreakerConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.CircuitBreakerConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.RetryConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.RetryConfiguration;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
|
@ -38,7 +42,8 @@ class FaultTolerantRedisClusterTest {
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
final RedisClusterClient clusterClient = mock(RedisClusterClient.class);
|
final RedisClusterClient clusterClient = mock(RedisClusterClient.class);
|
||||||
final StatefulRedisClusterConnection<String, String> clusterConnection = mock(StatefulRedisClusterConnection.class);
|
final StatefulRedisClusterConnection<String, String> clusterConnection = mock(StatefulRedisClusterConnection.class);
|
||||||
final StatefulRedisClusterPubSubConnection<String, String> pubSubConnection = mock(StatefulRedisClusterPubSubConnection.class);
|
final StatefulRedisClusterPubSubConnection<String, String> pubSubConnection = mock(
|
||||||
|
StatefulRedisClusterPubSubConnection.class);
|
||||||
final ClientResources clientResources = mock(ClientResources.class);
|
final ClientResources clientResources = mock(ClientResources.class);
|
||||||
final EventBus eventBus = mock(EventBus.class);
|
final EventBus eventBus = mock(EventBus.class);
|
||||||
|
|
||||||
|
@ -97,6 +102,43 @@ class FaultTolerantRedisClusterTest {
|
||||||
.thenThrow(new RedisCommandTimeoutException())
|
.thenThrow(new RedisCommandTimeoutException())
|
||||||
.thenReturn("value");
|
.thenReturn("value");
|
||||||
|
|
||||||
assertThrows(RedisCommandTimeoutException.class, () -> faultTolerantCluster.withCluster(connection -> connection.sync().get("key")));
|
assertThrows(RedisCommandTimeoutException.class,
|
||||||
|
() -> faultTolerantCluster.withCluster(connection -> connection.sync().get("key")));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class WithRealCluster {
|
||||||
|
|
||||||
|
private static final Duration TIMEOUT = Duration.ofMillis(50);
|
||||||
|
|
||||||
|
private static final RetryConfiguration retryConfiguration = new RetryConfiguration();
|
||||||
|
|
||||||
|
static {
|
||||||
|
retryConfiguration.setMaxAttempts(1);
|
||||||
|
retryConfiguration.setWaitDuration(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
static final RedisClusterExtension REDIS_CLUSTER_EXTENSION = RedisClusterExtension.builder()
|
||||||
|
.retryConfiguration(retryConfiguration)
|
||||||
|
.timeout(TIMEOUT)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testTimeout() {
|
||||||
|
final FaultTolerantRedisCluster cluster = REDIS_CLUSTER_EXTENSION.getRedisCluster();
|
||||||
|
|
||||||
|
assertTimeoutPreemptively(Duration.ofSeconds(1), () -> {
|
||||||
|
final ExecutionException asyncException = assertThrows(ExecutionException.class,
|
||||||
|
() -> cluster.withCluster(connection -> connection.async().blpop(TIMEOUT.toMillis() * 2, "key")).get());
|
||||||
|
assertTrue(asyncException.getCause() instanceof RedisCommandTimeoutException);
|
||||||
|
|
||||||
|
assertThrows(RedisCommandTimeoutException.class,
|
||||||
|
() -> cluster.withCluster(connection -> connection.sync().blpop(TIMEOUT.toMillis() * 2, "key")));
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,14 +32,23 @@ import org.whispersystems.textsecuregcm.util.RedisClusterUtil;
|
||||||
import redis.embedded.RedisServer;
|
import redis.embedded.RedisServer;
|
||||||
import redis.embedded.exceptions.EmbeddedRedisException;
|
import redis.embedded.exceptions.EmbeddedRedisException;
|
||||||
|
|
||||||
public class RedisClusterExtension implements BeforeAllCallback, BeforeEachCallback, AfterAllCallback, AfterEachCallback {
|
public class RedisClusterExtension implements BeforeAllCallback, BeforeEachCallback, AfterAllCallback,
|
||||||
|
AfterEachCallback {
|
||||||
|
|
||||||
|
private static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(2);
|
||||||
private static final int NODE_COUNT = 2;
|
private static final int NODE_COUNT = 2;
|
||||||
|
|
||||||
private static final RedisServer[] CLUSTER_NODES = new RedisServer[NODE_COUNT];
|
private static final RedisServer[] CLUSTER_NODES = new RedisServer[NODE_COUNT];
|
||||||
|
|
||||||
|
private final Duration timeout;
|
||||||
|
private final RetryConfiguration retryConfiguration;
|
||||||
private FaultTolerantRedisCluster redisCluster;
|
private FaultTolerantRedisCluster redisCluster;
|
||||||
|
|
||||||
|
public RedisClusterExtension(final Duration timeout, final RetryConfiguration retryConfiguration) {
|
||||||
|
this.timeout = timeout;
|
||||||
|
this.retryConfiguration = retryConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static RedisClusterExtensionBuilder builder() {
|
public static RedisClusterExtensionBuilder builder() {
|
||||||
return new RedisClusterExtensionBuilder();
|
return new RedisClusterExtensionBuilder();
|
||||||
|
@ -78,9 +87,9 @@ public class RedisClusterExtension implements BeforeAllCallback, BeforeEachCallb
|
||||||
|
|
||||||
redisCluster = new FaultTolerantRedisCluster("test-cluster",
|
redisCluster = new FaultTolerantRedisCluster("test-cluster",
|
||||||
RedisClusterClient.create(urls.stream().map(RedisURI::create).collect(Collectors.toList())),
|
RedisClusterClient.create(urls.stream().map(RedisURI::create).collect(Collectors.toList())),
|
||||||
Duration.ofSeconds(2),
|
timeout,
|
||||||
new CircuitBreakerConfiguration(),
|
new CircuitBreakerConfiguration(),
|
||||||
new RetryConfiguration());
|
retryConfiguration);
|
||||||
|
|
||||||
redisCluster.useCluster(connection -> {
|
redisCluster.useCluster(connection -> {
|
||||||
boolean setAll = false;
|
boolean setAll = false;
|
||||||
|
@ -208,11 +217,24 @@ public class RedisClusterExtension implements BeforeAllCallback, BeforeEachCallb
|
||||||
|
|
||||||
public static class RedisClusterExtensionBuilder {
|
public static class RedisClusterExtensionBuilder {
|
||||||
|
|
||||||
|
private Duration timeout = DEFAULT_TIMEOUT;
|
||||||
|
private RetryConfiguration retryConfiguration = new RetryConfiguration();
|
||||||
|
|
||||||
private RedisClusterExtensionBuilder() {
|
private RedisClusterExtensionBuilder() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RedisClusterExtensionBuilder timeout(Duration timeout) {
|
||||||
|
this.timeout = timeout;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
RedisClusterExtensionBuilder retryConfiguration(RetryConfiguration retryConfiguration) {
|
||||||
|
this.retryConfiguration = retryConfiguration;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public RedisClusterExtension build() {
|
public RedisClusterExtension build() {
|
||||||
return new RedisClusterExtension();
|
return new RedisClusterExtension(timeout, retryConfiguration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue