mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-21 02:37:59 +01:00
Restore Redis retries for select operations
This commit is contained in:
@@ -14,6 +14,7 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -39,8 +40,10 @@ class DisconnectionRequestManagerTest {
|
||||
void setUp() {
|
||||
grpcClientConnectionManager = mock(GrpcClientConnectionManager.class);
|
||||
|
||||
disconnectionRequestManager =
|
||||
new DisconnectionRequestManager(REDIS_EXTENSION.getRedisClient(), grpcClientConnectionManager, Runnable::run);
|
||||
disconnectionRequestManager = new DisconnectionRequestManager(REDIS_EXTENSION.getRedisClient(),
|
||||
grpcClientConnectionManager,
|
||||
Runnable::run,
|
||||
mock(ScheduledExecutorService.class));
|
||||
|
||||
disconnectionRequestManager.start();
|
||||
}
|
||||
|
||||
@@ -19,10 +19,13 @@ import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
@@ -36,6 +39,7 @@ import org.whispersystems.textsecuregcm.util.TestClock;
|
||||
class DynamicRateLimiterTest {
|
||||
|
||||
private ClusterLuaScript validateRateLimitScript;
|
||||
private ScheduledExecutorService retryExecutor;
|
||||
|
||||
private static final TestClock CLOCK = TestClock.pinned(Instant.now());
|
||||
|
||||
@@ -44,10 +48,17 @@ class DynamicRateLimiterTest {
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws IOException {
|
||||
retryExecutor = Executors.newSingleThreadScheduledExecutor();
|
||||
|
||||
validateRateLimitScript = ClusterLuaScript.fromResource(
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(), "lua/validate_rate_limit.lua", ScriptOutputType.INTEGER);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
retryExecutor.shutdown();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
void validate(final boolean failOpen) {
|
||||
@@ -56,6 +67,7 @@ class DynamicRateLimiterTest {
|
||||
() -> new RateLimiterConfig(1, Duration.ofHours(1), failOpen),
|
||||
validateRateLimitScript,
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
retryExecutor,
|
||||
CLOCK);
|
||||
|
||||
final String key = RandomStringUtils.insecure().nextAlphanumeric(16);
|
||||
@@ -72,6 +84,7 @@ class DynamicRateLimiterTest {
|
||||
() -> new RateLimiterConfig(1, Duration.ofHours(1), failOpen),
|
||||
validateRateLimitScript,
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
retryExecutor,
|
||||
CLOCK);
|
||||
|
||||
final String key = RandomStringUtils.insecure().nextAlphanumeric(16);
|
||||
@@ -94,6 +107,7 @@ class DynamicRateLimiterTest {
|
||||
() -> new RateLimiterConfig(1, Duration.ofHours(1), failOpen),
|
||||
failingScript,
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
retryExecutor,
|
||||
CLOCK);
|
||||
|
||||
final String key = RandomStringUtils.insecure().nextAlphanumeric(16);
|
||||
@@ -116,6 +130,7 @@ class DynamicRateLimiterTest {
|
||||
() -> new RateLimiterConfig(1, Duration.ofHours(1), failOpen),
|
||||
failingScript,
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
retryExecutor,
|
||||
CLOCK);
|
||||
|
||||
final String key = RandomStringUtils.insecure().nextAlphanumeric(16);
|
||||
@@ -138,6 +153,7 @@ class DynamicRateLimiterTest {
|
||||
() -> new RateLimiterConfig(1, refillRate.get(), false),
|
||||
validateRateLimitScript,
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
retryExecutor,
|
||||
CLOCK);
|
||||
|
||||
final String key = RandomStringUtils.insecure().nextAlphanumeric(16);
|
||||
@@ -161,6 +177,7 @@ class DynamicRateLimiterTest {
|
||||
() -> new RateLimiterConfig(1, refillRate.get(), false),
|
||||
validateRateLimitScript,
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
retryExecutor,
|
||||
CLOCK);
|
||||
|
||||
final String key = RandomStringUtils.insecure().nextAlphanumeric(16);
|
||||
@@ -187,6 +204,7 @@ class DynamicRateLimiterTest {
|
||||
() -> new RateLimiterConfig(bucketSize.get(), Duration.ofMinutes(1), false),
|
||||
validateRateLimitScript,
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
retryExecutor,
|
||||
CLOCK);
|
||||
|
||||
final String key = RandomStringUtils.insecure().nextAlphanumeric(16);
|
||||
@@ -211,6 +229,7 @@ class DynamicRateLimiterTest {
|
||||
() -> new RateLimiterConfig(bucketSize.get(), Duration.ofMinutes(1), false),
|
||||
validateRateLimitScript,
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
retryExecutor,
|
||||
CLOCK);
|
||||
|
||||
final String key = RandomStringUtils.insecure().nextAlphanumeric(16);
|
||||
@@ -238,6 +257,7 @@ class DynamicRateLimiterTest {
|
||||
() -> new RateLimiterConfig(1, Duration.ofMinutes(1), failOpen.get()),
|
||||
failingScript,
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
retryExecutor,
|
||||
CLOCK);
|
||||
|
||||
final String key = RandomStringUtils.insecure().nextAlphanumeric(16);
|
||||
@@ -260,6 +280,7 @@ class DynamicRateLimiterTest {
|
||||
() -> new RateLimiterConfig(1, Duration.ofMinutes(1), failOpen.get()),
|
||||
failingScript,
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
retryExecutor,
|
||||
CLOCK);
|
||||
|
||||
final String key = RandomStringUtils.insecure().nextAlphanumeric(16);
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
@@ -65,6 +66,7 @@ public class RateLimitersLuaScriptTest {
|
||||
dynamicConfig,
|
||||
RateLimiters.defaultScript(redisCluster),
|
||||
redisCluster,
|
||||
mock(ScheduledExecutorService.class),
|
||||
Clock.systemUTC());
|
||||
|
||||
final RateLimiter rateLimiter = limiters.forDescriptor(descriptor);
|
||||
@@ -84,6 +86,7 @@ public class RateLimitersLuaScriptTest {
|
||||
dynamicConfig,
|
||||
RateLimiters.defaultScript(redisCluster),
|
||||
redisCluster,
|
||||
mock(ScheduledExecutorService.class),
|
||||
Clock.systemUTC());
|
||||
|
||||
final RateLimiter rateLimiter = limiters.forDescriptor(descriptor);
|
||||
@@ -138,6 +141,7 @@ public class RateLimitersLuaScriptTest {
|
||||
dynamicConfig,
|
||||
RateLimiters.defaultScript(redisCluster),
|
||||
redisCluster,
|
||||
mock(ScheduledExecutorService.class),
|
||||
Clock.systemUTC());
|
||||
when(redisCluster.withCluster(any())).thenThrow(new RedisException("fail"));
|
||||
final RateLimiter rateLimiter = limiters.forDescriptor(descriptor);
|
||||
|
||||
@@ -13,6 +13,7 @@ import static org.mockito.Mockito.when;
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
||||
import org.whispersystems.textsecuregcm.redis.ClusterLuaScript;
|
||||
@@ -36,7 +37,7 @@ public class RateLimitersTest {
|
||||
private final MutableClock clock = MockUtils.mutableClock(0);
|
||||
|
||||
@Test
|
||||
public void testValidateDuplicates() throws Exception {
|
||||
public void testValidateDuplicates() {
|
||||
final TestDescriptor td1 = new TestDescriptor("id1");
|
||||
final TestDescriptor td2 = new TestDescriptor("id2");
|
||||
final TestDescriptor td3 = new TestDescriptor("id3");
|
||||
@@ -47,6 +48,7 @@ public class RateLimitersTest {
|
||||
dynamicConfig,
|
||||
validateScript,
|
||||
redisCluster,
|
||||
mock(ScheduledExecutorService.class),
|
||||
clock) {});
|
||||
|
||||
new BaseRateLimiters<>(
|
||||
@@ -54,12 +56,13 @@ public class RateLimitersTest {
|
||||
dynamicConfig,
|
||||
validateScript,
|
||||
redisCluster,
|
||||
mock(ScheduledExecutorService.class),
|
||||
clock) {};
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUnchangingConfiguration() {
|
||||
final RateLimiters rateLimiters = new RateLimiters(dynamicConfig, validateScript, redisCluster, clock);
|
||||
final RateLimiters rateLimiters = new RateLimiters(dynamicConfig, validateScript, redisCluster, mock(ScheduledExecutorService.class), clock);
|
||||
final RateLimiter limiter = rateLimiters.getRateLimitResetLimiter();
|
||||
final RateLimiterConfig expected = RateLimiters.For.RATE_LIMIT_RESET.defaultConfig();
|
||||
assertEquals(expected, limiter.config());
|
||||
@@ -78,7 +81,7 @@ public class RateLimitersTest {
|
||||
|
||||
when(configuration.getLimits()).thenReturn(limitsConfigMap);
|
||||
|
||||
final RateLimiters rateLimiters = new RateLimiters(dynamicConfig, validateScript, redisCluster, clock);
|
||||
final RateLimiters rateLimiters = new RateLimiters(dynamicConfig, validateScript, redisCluster, mock(ScheduledExecutorService.class), clock);
|
||||
final RateLimiter limiter = rateLimiters.getRateLimitResetLimiter();
|
||||
|
||||
limitsConfigMap.put(RateLimiters.For.RATE_LIMIT_RESET.id(), initialRateLimiterConfig);
|
||||
@@ -104,7 +107,7 @@ public class RateLimitersTest {
|
||||
|
||||
when(configuration.getLimits()).thenReturn(mapForDynamic);
|
||||
|
||||
final RateLimiters rateLimiters = new RateLimiters(dynamicConfig, validateScript, redisCluster, clock);
|
||||
final RateLimiters rateLimiters = new RateLimiters(dynamicConfig, validateScript, redisCluster, mock(ScheduledExecutorService.class), clock);
|
||||
final RateLimiter limiter = rateLimiters.forDescriptor(descriptor);
|
||||
|
||||
// test only default is present
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -90,7 +91,7 @@ class PushNotificationSchedulerTest {
|
||||
.thenReturn(CompletableFuture.completedFuture(new SendPushNotificationResult(true, Optional.empty(), false, Optional.empty())));
|
||||
|
||||
pushNotificationScheduler = new PushNotificationScheduler(REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
apnSender, fcmSender, accountsManager, clock, 1, 1);
|
||||
apnSender, fcmSender, accountsManager, clock, 1, 1, mock(ScheduledExecutorService.class));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@@ -267,7 +268,7 @@ class PushNotificationSchedulerTest {
|
||||
final AccountsManager accountsManager = mock(AccountsManager.class);
|
||||
|
||||
pushNotificationScheduler = new PushNotificationScheduler(redisCluster, apnSender, fcmSender,
|
||||
accountsManager, dedicatedThreadCount, 1);
|
||||
accountsManager, dedicatedThreadCount, 1, mock(ScheduledExecutorService.class));
|
||||
|
||||
pushNotificationScheduler.start();
|
||||
pushNotificationScheduler.stop();
|
||||
|
||||
@@ -173,6 +173,7 @@ public class AccountCreationDeletionIntegrationTest {
|
||||
clientPublicKeysManager,
|
||||
executor,
|
||||
executor,
|
||||
executor,
|
||||
CLOCK,
|
||||
"link-device-secret".getBytes(StandardCharsets.UTF_8),
|
||||
dynamicConfigurationManager);
|
||||
|
||||
@@ -161,6 +161,7 @@ class AccountsManagerChangeNumberIntegrationTest {
|
||||
clientPublicKeysManager,
|
||||
executor,
|
||||
executor,
|
||||
executor,
|
||||
mock(Clock.class),
|
||||
"link-device-secret".getBytes(StandardCharsets.UTF_8),
|
||||
dynamicConfigurationManager);
|
||||
|
||||
@@ -140,6 +140,7 @@ class AccountsManagerConcurrentModificationIntegrationTest {
|
||||
mock(ClientPublicKeysManager.class),
|
||||
mock(Executor.class),
|
||||
mock(ScheduledExecutorService.class),
|
||||
mock(ScheduledExecutorService.class),
|
||||
mock(Clock.class),
|
||||
"link-device-secret".getBytes(StandardCharsets.UTF_8),
|
||||
dynamicConfigurationManager
|
||||
|
||||
@@ -78,6 +78,7 @@ public class AccountsManagerDeviceTransferIntegrationTest {
|
||||
mock(ClientPublicKeysManager.class),
|
||||
mock(ExecutorService.class),
|
||||
mock(ScheduledExecutorService.class),
|
||||
mock(ScheduledExecutorService.class),
|
||||
Clock.systemUTC(),
|
||||
"link-device-secret".getBytes(StandardCharsets.UTF_8),
|
||||
mock(DynamicConfigurationManager.class));
|
||||
|
||||
@@ -260,6 +260,7 @@ class AccountsManagerTest {
|
||||
clientPublicKeysManager,
|
||||
mock(Executor.class),
|
||||
mock(ScheduledExecutorService.class),
|
||||
mock(ScheduledExecutorService.class),
|
||||
CLOCK,
|
||||
LINK_DEVICE_SECRET,
|
||||
dynamicConfigurationManager);
|
||||
|
||||
@@ -165,6 +165,7 @@ class AccountsManagerUsernameIntegrationTest {
|
||||
mock(ClientPublicKeysManager.class),
|
||||
Executors.newSingleThreadExecutor(),
|
||||
Executors.newSingleThreadScheduledExecutor(),
|
||||
Executors.newSingleThreadScheduledExecutor(),
|
||||
mock(Clock.class),
|
||||
"link-device-secret".getBytes(StandardCharsets.UTF_8),
|
||||
dynamicConfigurationManager);
|
||||
|
||||
@@ -77,7 +77,7 @@ public class AddRemoveDeviceIntegrationTest {
|
||||
static final S3LocalStackExtension S3_EXTENSION = new S3LocalStackExtension("testbucket");
|
||||
|
||||
private ExecutorService accountLockExecutor;
|
||||
private ScheduledExecutorService messagePollExecutor;
|
||||
private ScheduledExecutorService scheduledExecutorService;
|
||||
|
||||
private KeysManager keysManager;
|
||||
private ClientPublicKeysManager clientPublicKeysManager;
|
||||
@@ -123,7 +123,7 @@ public class AddRemoveDeviceIntegrationTest {
|
||||
DynamoDbExtensionSchema.Tables.USED_LINK_DEVICE_TOKENS.tableName());
|
||||
|
||||
accountLockExecutor = Executors.newSingleThreadExecutor();
|
||||
messagePollExecutor = mock(ScheduledExecutorService.class);
|
||||
scheduledExecutorService = mock(ScheduledExecutorService.class);
|
||||
|
||||
final AccountLockManager accountLockManager = new AccountLockManager(DYNAMO_DB_EXTENSION.getDynamoDbClient(),
|
||||
DynamoDbExtensionSchema.Tables.DELETED_ACCOUNTS_LOCK.tableName());
|
||||
@@ -172,7 +172,8 @@ public class AddRemoveDeviceIntegrationTest {
|
||||
mock(RegistrationRecoveryPasswordsManager.class),
|
||||
clientPublicKeysManager,
|
||||
accountLockExecutor,
|
||||
messagePollExecutor,
|
||||
scheduledExecutorService,
|
||||
scheduledExecutorService,
|
||||
clock,
|
||||
"link-device-secret".getBytes(StandardCharsets.UTF_8),
|
||||
dynamicConfigurationManager);
|
||||
@@ -635,7 +636,7 @@ public class AddRemoveDeviceIntegrationTest {
|
||||
.thenReturn(CompletableFuture.completedFuture(Optional.empty()));
|
||||
clock.pin(Instant.ofEpochMilli(10_000));
|
||||
// Run any scheduled job right away
|
||||
when(messagePollExecutor.schedule(any(Runnable.class), anyLong(), any())).thenAnswer(x -> {
|
||||
when(scheduledExecutorService.schedule(any(Runnable.class), anyLong(), any())).thenAnswer(x -> {
|
||||
x.getArgument(0, Runnable.class).run();
|
||||
return null;
|
||||
});
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
@@ -84,7 +85,7 @@ class MessagePersisterIntegrationTest {
|
||||
final AccountsManager accountsManager = mock(AccountsManager.class);
|
||||
|
||||
messagesCache = new MessagesCache(REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
messageDeliveryScheduler, messageDeletionExecutorService, Clock.systemUTC(), experimentEnrollmentManager);
|
||||
messageDeliveryScheduler, messageDeletionExecutorService, mock(ScheduledExecutorService.class), Clock.systemUTC(), experimentEnrollmentManager);
|
||||
messagesManager = new MessagesManager(messagesDynamoDb, messagesCache, mock(RedisMessageAvailabilityManager.class),
|
||||
mock(ReportMessageManager.class), messageDeletionExecutorService, Clock.systemUTC());
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ class MessagePersisterTest {
|
||||
resubscribeRetryExecutorService = Executors.newSingleThreadScheduledExecutor();
|
||||
messageDeliveryScheduler = Schedulers.newBoundedElastic(10, 10_000, "messageDelivery");
|
||||
messagesCache = new MessagesCache(REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
messageDeliveryScheduler, sharedExecutorService, Clock.systemUTC(), mock(ExperimentEnrollmentManager.class));
|
||||
messageDeliveryScheduler, sharedExecutorService, mock(ScheduledExecutorService.class), Clock.systemUTC(), mock(ExperimentEnrollmentManager.class));
|
||||
messagePersister = new MessagePersister(messagesCache, messagesManager, accountsManager,
|
||||
dynamicConfigurationManager, PERSIST_DELAY, 1);
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.whispersystems.textsecuregcm.entities.MessageProtos;
|
||||
@@ -32,7 +33,8 @@ class MessagesCacheGetItemsScriptTest {
|
||||
@Test
|
||||
void testCacheGetItemsScript() throws Exception {
|
||||
final MessagesCacheInsertScript insertScript = new MessagesCacheInsertScript(
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster());
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
mock(ScheduledExecutorService.class));
|
||||
|
||||
final UUID destinationUuid = UUID.randomUUID();
|
||||
final byte deviceId = 1;
|
||||
|
||||
@@ -8,6 +8,7 @@ package org.whispersystems.textsecuregcm.storage;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
@@ -16,6 +17,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
@@ -32,7 +34,7 @@ class MessagesCacheInsertScriptTest {
|
||||
@Test
|
||||
void testCacheInsertScript() throws Exception {
|
||||
final MessagesCacheInsertScript insertScript =
|
||||
new MessagesCacheInsertScript(REDIS_CLUSTER_EXTENSION.getRedisCluster());
|
||||
new MessagesCacheInsertScript(REDIS_CLUSTER_EXTENSION.getRedisCluster(), mock(ScheduledExecutorService.class));
|
||||
|
||||
final UUID destinationUuid = UUID.randomUUID();
|
||||
final byte deviceId = 1;
|
||||
@@ -41,7 +43,7 @@ class MessagesCacheInsertScriptTest {
|
||||
.setServerGuid(UUID.randomUUID().toString())
|
||||
.build();
|
||||
|
||||
insertScript.executeAsync(destinationUuid, deviceId, envelope1).join();
|
||||
insertScript.executeAsync(destinationUuid, deviceId, envelope1).toCompletableFuture().join();
|
||||
|
||||
assertEquals(List.of(EnvelopeUtil.compress(envelope1)), getStoredMessages(destinationUuid, deviceId));
|
||||
|
||||
@@ -50,12 +52,12 @@ class MessagesCacheInsertScriptTest {
|
||||
.setServerGuid(UUID.randomUUID().toString())
|
||||
.build();
|
||||
|
||||
insertScript.executeAsync(destinationUuid, deviceId, envelope2).join();
|
||||
insertScript.executeAsync(destinationUuid, deviceId, envelope2).toCompletableFuture().join();
|
||||
|
||||
assertEquals(List.of(EnvelopeUtil.compress(envelope1), EnvelopeUtil.compress(envelope2)),
|
||||
getStoredMessages(destinationUuid, deviceId));
|
||||
|
||||
insertScript.executeAsync(destinationUuid, deviceId, envelope1).join();
|
||||
insertScript.executeAsync(destinationUuid, deviceId, envelope1).toCompletableFuture().join();
|
||||
|
||||
assertEquals(List.of(EnvelopeUtil.compress(envelope1), EnvelopeUtil.compress(envelope2)),
|
||||
getStoredMessages(destinationUuid, deviceId),
|
||||
@@ -89,12 +91,13 @@ class MessagesCacheInsertScriptTest {
|
||||
final byte deviceId = 1;
|
||||
|
||||
final MessagesCacheInsertScript insertScript =
|
||||
new MessagesCacheInsertScript(REDIS_CLUSTER_EXTENSION.getRedisCluster());
|
||||
new MessagesCacheInsertScript(REDIS_CLUSTER_EXTENSION.getRedisCluster(), mock(ScheduledExecutorService.class));
|
||||
|
||||
assertFalse(insertScript.executeAsync(destinationUuid, deviceId, MessageProtos.Envelope.newBuilder()
|
||||
.setServerTimestamp(Instant.now().getEpochSecond())
|
||||
.setServerGuid(UUID.randomUUID().toString())
|
||||
.build())
|
||||
.toCompletableFuture()
|
||||
.join());
|
||||
|
||||
final FaultTolerantPubSubClusterConnection<byte[], byte[]> pubSubClusterConnection =
|
||||
@@ -107,6 +110,7 @@ class MessagesCacheInsertScriptTest {
|
||||
.setServerTimestamp(Instant.now().getEpochSecond())
|
||||
.setServerGuid(UUID.randomUUID().toString())
|
||||
.build())
|
||||
.toCompletableFuture()
|
||||
.join());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,17 +9,18 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import io.lettuce.core.RedisCommandExecutionException;
|
||||
import io.lettuce.core.RedisException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import io.lettuce.core.RedisException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
@@ -40,11 +41,11 @@ class MessagesCacheInsertSharedMultiRecipientPayloadAndViewsScriptTest {
|
||||
void testInsert(final int count, final Map<ServiceIdentifier, List<Byte>> destinations) throws Exception {
|
||||
|
||||
final MessagesCacheInsertSharedMultiRecipientPayloadAndViewsScript insertMrmScript = new MessagesCacheInsertSharedMultiRecipientPayloadAndViewsScript(
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster());
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(), mock(ScheduledExecutorService.class));
|
||||
|
||||
final byte[] sharedMrmKey = MessagesCache.getSharedMrmKey(UUID.randomUUID());
|
||||
insertMrmScript.executeAsync(sharedMrmKey,
|
||||
MessagesCacheTest.generateRandomMrmMessage(destinations)).join();
|
||||
MessagesCacheTest.generateRandomMrmMessage(destinations)).toCompletableFuture().join();
|
||||
|
||||
final int totalDevices = destinations.values().stream().mapToInt(List::size).sum();
|
||||
final long hashFieldCount = REDIS_CLUSTER_EXTENSION.getRedisCluster()
|
||||
@@ -83,16 +84,18 @@ class MessagesCacheInsertSharedMultiRecipientPayloadAndViewsScriptTest {
|
||||
@Test
|
||||
void testInsertDuplicateKey() throws Exception {
|
||||
final MessagesCacheInsertSharedMultiRecipientPayloadAndViewsScript insertMrmScript = new MessagesCacheInsertSharedMultiRecipientPayloadAndViewsScript(
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster());
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(), mock(ScheduledExecutorService.class));
|
||||
|
||||
final byte[] sharedMrmKey = MessagesCache.getSharedMrmKey(UUID.randomUUID());
|
||||
insertMrmScript.executeAsync(sharedMrmKey,
|
||||
MessagesCacheTest.generateRandomMrmMessage(new AciServiceIdentifier(UUID.randomUUID()), Device.PRIMARY_ID)).join();
|
||||
MessagesCacheTest.generateRandomMrmMessage(new AciServiceIdentifier(UUID.randomUUID()), Device.PRIMARY_ID))
|
||||
.toCompletableFuture()
|
||||
.join();
|
||||
|
||||
final CompletionException completionException = assertThrows(CompletionException.class,
|
||||
() -> insertMrmScript.executeAsync(sharedMrmKey,
|
||||
MessagesCacheTest.generateRandomMrmMessage(new AciServiceIdentifier(UUID.randomUUID()),
|
||||
Device.PRIMARY_ID)).join());
|
||||
Device.PRIMARY_ID)).toCompletableFuture().join());
|
||||
|
||||
assertInstanceOf(RedisException.class, completionException.getCause());
|
||||
assertTrue(completionException.getCause().getMessage()
|
||||
|
||||
@@ -6,10 +6,12 @@
|
||||
package org.whispersystems.textsecuregcm.storage;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
@@ -25,7 +27,8 @@ class MessagesCacheRemoveByGuidScriptTest {
|
||||
@Test
|
||||
void testCacheRemoveByGuid() throws Exception {
|
||||
final MessagesCacheInsertScript insertScript = new MessagesCacheInsertScript(
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster());
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
mock(ScheduledExecutorService.class));
|
||||
|
||||
final UUID destinationUuid = UUID.randomUUID();
|
||||
final byte deviceId = 1;
|
||||
@@ -38,10 +41,12 @@ class MessagesCacheRemoveByGuidScriptTest {
|
||||
insertScript.executeAsync(destinationUuid, deviceId, envelope1);
|
||||
|
||||
final MessagesCacheRemoveByGuidScript removeByGuidScript = new MessagesCacheRemoveByGuidScript(
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster());
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(), mock(ScheduledExecutorService.class));
|
||||
|
||||
final List<byte[]> removedMessages = removeByGuidScript.execute(destinationUuid, deviceId,
|
||||
List.of(serverGuid)).get(1, TimeUnit.SECONDS);
|
||||
final List<byte[]> removedMessages =
|
||||
removeByGuidScript.execute(destinationUuid, deviceId, List.of(serverGuid))
|
||||
.toCompletableFuture()
|
||||
.get(1, TimeUnit.SECONDS);
|
||||
|
||||
assertEquals(1, removedMessages.size());
|
||||
|
||||
|
||||
@@ -6,12 +6,14 @@
|
||||
package org.whispersystems.textsecuregcm.storage;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.whispersystems.textsecuregcm.entities.MessageProtos;
|
||||
@@ -26,7 +28,8 @@ class MessagesCacheRemoveQueueScriptTest {
|
||||
@Test
|
||||
void testCacheRemoveQueueScript() throws Exception {
|
||||
final MessagesCacheInsertScript insertScript = new MessagesCacheInsertScript(
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster());
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
mock(ScheduledExecutorService.class));
|
||||
|
||||
final UUID destinationUuid = UUID.randomUUID();
|
||||
final byte deviceId = 1;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package org.whispersystems.textsecuregcm.storage;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import io.lettuce.core.cluster.SlotHash;
|
||||
import java.time.Duration;
|
||||
@@ -15,6 +16,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
@@ -38,10 +40,12 @@ class MessagesCacheRemoveRecipientViewFromMrmDataScriptTest {
|
||||
void testUpdateSingleKey(final Map<ServiceIdentifier, List<Byte>> destinations) throws Exception {
|
||||
|
||||
final MessagesCacheInsertSharedMultiRecipientPayloadAndViewsScript insertMrmScript = new MessagesCacheInsertSharedMultiRecipientPayloadAndViewsScript(
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster());
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(), mock(ScheduledExecutorService.class));
|
||||
|
||||
final byte[] sharedMrmKey = MessagesCache.getSharedMrmKey(UUID.randomUUID());
|
||||
insertMrmScript.executeAsync(sharedMrmKey, MessagesCacheTest.generateRandomMrmMessage(destinations)).join();
|
||||
insertMrmScript.executeAsync(sharedMrmKey, MessagesCacheTest.generateRandomMrmMessage(destinations))
|
||||
.toCompletableFuture()
|
||||
.join();
|
||||
|
||||
final MessagesCacheRemoveRecipientViewFromMrmDataScript removeRecipientViewFromMrmDataScript = new MessagesCacheRemoveRecipientViewFromMrmDataScript(
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster());
|
||||
@@ -99,11 +103,11 @@ class MessagesCacheRemoveRecipientViewFromMrmDataScriptTest {
|
||||
for (int i = 0; i < keyCount; i++) {
|
||||
|
||||
final MessagesCacheInsertSharedMultiRecipientPayloadAndViewsScript insertMrmScript = new MessagesCacheInsertSharedMultiRecipientPayloadAndViewsScript(
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster());
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(), mock(ScheduledExecutorService.class));
|
||||
|
||||
final byte[] sharedMrmKey = MessagesCache.getSharedMrmKey(UUID.randomUUID());
|
||||
insertMrmScript.executeAsync(sharedMrmKey,
|
||||
MessagesCacheTest.generateRandomMrmMessage(serviceIdentifier, deviceId)).join();
|
||||
MessagesCacheTest.generateRandomMrmMessage(serviceIdentifier, deviceId)).toCompletableFuture().join();
|
||||
|
||||
sharedMrmKeys.add(sharedMrmKey);
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ class MessagesCacheTest {
|
||||
resubscribeRetryExecutorService = Executors.newSingleThreadScheduledExecutor();
|
||||
messageDeliveryScheduler = Schedulers.newBoundedElastic(10, 10_000, "messageDelivery");
|
||||
messagesCache = new MessagesCache(REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
messageDeliveryScheduler, sharedExecutorService, Clock.systemUTC(), mock(ExperimentEnrollmentManager.class));
|
||||
messageDeliveryScheduler, sharedExecutorService, mock(ScheduledExecutorService.class), Clock.systemUTC(), mock(ExperimentEnrollmentManager.class));
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
@@ -194,17 +194,6 @@ class MessagesCacheTest {
|
||||
assertEquals(messagesToPreserve, get(DESTINATION_UUID, DESTINATION_DEVICE_ID, messageCount));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHasMessagesAsync() {
|
||||
assertFalse(messagesCache.hasMessagesAsync(DESTINATION_UUID, DESTINATION_DEVICE_ID).join());
|
||||
|
||||
final UUID messageGuid = UUID.randomUUID();
|
||||
final MessageProtos.Envelope message = generateRandomMessage(messageGuid, true);
|
||||
messagesCache.insert(messageGuid, DESTINATION_UUID, DESTINATION_DEVICE_ID, message).join();
|
||||
|
||||
assertTrue(messagesCache.hasMessagesAsync(DESTINATION_UUID, DESTINATION_DEVICE_ID).join());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getOldestTimestamp() {
|
||||
final int messageCount = 100;
|
||||
@@ -300,7 +289,7 @@ class MessagesCacheTest {
|
||||
}
|
||||
|
||||
final MessagesCache messagesCache = new MessagesCache(REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
messageDeliveryScheduler, sharedExecutorService, cacheClock, mock(ExperimentEnrollmentManager.class));
|
||||
messageDeliveryScheduler, sharedExecutorService, mock(ScheduledExecutorService.class), cacheClock, mock(ExperimentEnrollmentManager.class));
|
||||
|
||||
final List<MessageProtos.Envelope> actualMessages = Flux.from(
|
||||
messagesCache.get(DESTINATION_UUID, DESTINATION_DEVICE_ID))
|
||||
@@ -624,7 +613,7 @@ class MessagesCacheTest {
|
||||
messageDeliveryScheduler = Schedulers.newBoundedElastic(10, 10_000, "messageDelivery");
|
||||
|
||||
messagesCache = new MessagesCache(mockCluster, messageDeliveryScheduler,
|
||||
Executors.newSingleThreadExecutor(), Clock.systemUTC(), mock(ExperimentEnrollmentManager.class));
|
||||
Executors.newSingleThreadExecutor(), mock(ScheduledExecutorService.class), Clock.systemUTC(), mock(ExperimentEnrollmentManager.class));
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
||||
@@ -12,7 +12,6 @@ import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -186,31 +185,6 @@ class MessagesManagerTest {
|
||||
any());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({
|
||||
"false, false, false",
|
||||
"false, true, true",
|
||||
"true, false, true",
|
||||
"true, true, true"
|
||||
})
|
||||
void mayHaveMessages(final boolean hasCachedMessages, final boolean hasPersistedMessages, final boolean expectMayHaveMessages) {
|
||||
final UUID accountIdentifier = UUID.randomUUID();
|
||||
final Device device = mock(Device.class);
|
||||
when(device.getId()).thenReturn(Device.PRIMARY_ID);
|
||||
|
||||
when(messagesCache.hasMessagesAsync(accountIdentifier, Device.PRIMARY_ID))
|
||||
.thenReturn(CompletableFuture.completedFuture(hasCachedMessages));
|
||||
|
||||
when(messagesDynamoDb.mayHaveMessages(accountIdentifier, device))
|
||||
.thenReturn(CompletableFuture.completedFuture(hasPersistedMessages));
|
||||
|
||||
if (hasCachedMessages) {
|
||||
verifyNoInteractions(messagesDynamoDb);
|
||||
}
|
||||
|
||||
assertEquals(expectMayHaveMessages, messagesManager.mayHaveMessages(accountIdentifier, device).join());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({
|
||||
",,",
|
||||
|
||||
@@ -26,6 +26,7 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.Timeout;
|
||||
@@ -67,7 +68,7 @@ public class ProfilesManagerTest {
|
||||
profiles = mock(Profiles.class);
|
||||
s3Client = mock(S3AsyncClient.class);
|
||||
|
||||
profilesManager = new ProfilesManager(profiles, cacheCluster, s3Client, BUCKET);
|
||||
profilesManager = new ProfilesManager(profiles, cacheCluster, mock(ScheduledExecutorService.class), s3Client, BUCKET);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -25,6 +25,7 @@ import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
@@ -85,7 +86,7 @@ class RedisDynamoDbMessagePublisherTest {
|
||||
mock(ExperimentEnrollmentManager.class));
|
||||
|
||||
messagesCache = new MessagesCache(REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
messageDeliveryScheduler, sharedExecutorService, Clock.systemUTC(), mock(ExperimentEnrollmentManager.class));
|
||||
messageDeliveryScheduler, sharedExecutorService, mock(ScheduledExecutorService.class), Clock.systemUTC(), mock(ExperimentEnrollmentManager.class));
|
||||
|
||||
redisMessageAvailabilityManager = mock(RedisMessageAvailabilityManager.class);
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
@@ -101,7 +102,7 @@ class WebSocketConnectionIntegrationTest {
|
||||
dynamicConfigurationManager = mock(DynamicConfigurationManager.class);
|
||||
when(dynamicConfigurationManager.getConfiguration()).thenReturn(new DynamicConfiguration());
|
||||
messagesCache = new MessagesCache(REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
messageDeliveryScheduler, sharedExecutorService, Clock.systemUTC(), mock(ExperimentEnrollmentManager.class));
|
||||
messageDeliveryScheduler, sharedExecutorService, mock(ScheduledExecutorService.class), Clock.systemUTC(), mock(ExperimentEnrollmentManager.class));
|
||||
messagesDynamoDb = new MessagesDynamoDb(DYNAMO_DB_EXTENSION.getDynamoDbClient(),
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbAsyncClient(), Tables.MESSAGES.tableName(), Duration.ofDays(7),
|
||||
sharedExecutorService, mock(ExperimentEnrollmentManager.class));
|
||||
|
||||
Reference in New Issue
Block a user