mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-22 02:18:05 +01:00
Retry attempts to get messages after a delay; close connections after a finite number of retries.
This commit is contained in:
committed by
Jon Chambers
parent
7509520883
commit
089b6b1644
@@ -28,6 +28,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;
|
||||
@@ -62,12 +63,9 @@ public class WebSocketConnectionIntegrationTest extends AbstractRedisClusterTest
|
||||
private Device device;
|
||||
private WebSocketClient webSocketClient;
|
||||
private WebSocketConnection webSocketConnection;
|
||||
private ScheduledExecutorService retrySchedulingExecutor;
|
||||
|
||||
private long serialTimestamp = System.currentTimeMillis();
|
||||
|
||||
@Before
|
||||
public void setupAccountsDao() {
|
||||
}
|
||||
private long serialTimestamp = System.currentTimeMillis();
|
||||
|
||||
@Before
|
||||
@Override
|
||||
@@ -80,6 +78,7 @@ public class WebSocketConnectionIntegrationTest extends AbstractRedisClusterTest
|
||||
account = mock(Account.class);
|
||||
device = mock(Device.class);
|
||||
webSocketClient = mock(WebSocketClient.class);
|
||||
retrySchedulingExecutor = Executors.newSingleThreadScheduledExecutor();
|
||||
|
||||
when(account.getNumber()).thenReturn("+18005551234");
|
||||
when(account.getUuid()).thenReturn(UUID.randomUUID());
|
||||
@@ -90,7 +89,8 @@ public class WebSocketConnectionIntegrationTest extends AbstractRedisClusterTest
|
||||
new MessagesManager(messagesDynamoDb, messagesCache, mock(PushLatencyManager.class)),
|
||||
account,
|
||||
device,
|
||||
webSocketClient);
|
||||
webSocketClient,
|
||||
retrySchedulingExecutor);
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -99,6 +99,9 @@ public class WebSocketConnectionIntegrationTest extends AbstractRedisClusterTest
|
||||
executorService.shutdown();
|
||||
executorService.awaitTermination(2, TimeUnit.SECONDS);
|
||||
|
||||
retrySchedulingExecutor.shutdown();
|
||||
retrySchedulingExecutor.awaitTermination(2, TimeUnit.SECONDS);
|
||||
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
|
||||
@@ -35,8 +35,11 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import io.lettuce.core.RedisException;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.eclipse.jetty.websocket.api.UpgradeRequest;
|
||||
import org.junit.Before;
|
||||
@@ -75,6 +78,7 @@ public class WebSocketConnectionTest {
|
||||
private UpgradeRequest upgradeRequest;
|
||||
private ReceiptSender receiptSender;
|
||||
private ApnFallbackManager apnFallbackManager;
|
||||
private ScheduledExecutorService retrySchedulingExecutor;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
@@ -85,13 +89,15 @@ public class WebSocketConnectionTest {
|
||||
upgradeRequest = mock(UpgradeRequest.class);
|
||||
receiptSender = mock(ReceiptSender.class);
|
||||
apnFallbackManager = mock(ApnFallbackManager.class);
|
||||
retrySchedulingExecutor = mock(ScheduledExecutorService.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCredentials() throws Exception {
|
||||
MessagesManager storedMessages = mock(MessagesManager.class);
|
||||
WebSocketAccountAuthenticator webSocketAuthenticator = new WebSocketAccountAuthenticator(accountAuthenticator);
|
||||
AuthenticatedConnectListener connectListener = new AuthenticatedConnectListener(receiptSender, storedMessages, mock(MessageSender.class), apnFallbackManager, mock(ClientPresenceManager.class));
|
||||
AuthenticatedConnectListener connectListener = new AuthenticatedConnectListener(receiptSender, storedMessages, mock(MessageSender.class), apnFallbackManager, mock(ClientPresenceManager.class),
|
||||
retrySchedulingExecutor);
|
||||
WebSocketSessionContext sessionContext = mock(WebSocketSessionContext.class);
|
||||
|
||||
when(accountAuthenticator.authenticate(eq(new BasicCredentials(VALID_USER, VALID_PASSWORD))))
|
||||
@@ -178,7 +184,7 @@ public class WebSocketConnectionTest {
|
||||
});
|
||||
|
||||
WebSocketConnection connection = new WebSocketConnection(receiptSender, storedMessages,
|
||||
account, device, client);
|
||||
account, device, client, retrySchedulingExecutor);
|
||||
|
||||
connection.start();
|
||||
verify(client, times(3)).sendRequest(eq("PUT"), eq("/api/v1/message"), ArgumentMatchers.nullable(List.class), ArgumentMatchers.<Optional<byte[]>>any());
|
||||
@@ -203,7 +209,7 @@ public class WebSocketConnectionTest {
|
||||
public void testOnlineSend() throws Exception {
|
||||
final MessagesManager messagesManager = mock(MessagesManager.class);
|
||||
final WebSocketClient client = mock(WebSocketClient.class);
|
||||
final WebSocketConnection connection = new WebSocketConnection(receiptSender, messagesManager, account, device, client);
|
||||
final WebSocketConnection connection = new WebSocketConnection(receiptSender, messagesManager, account, device, client, retrySchedulingExecutor);
|
||||
|
||||
final UUID accountUuid = UUID.randomUUID();
|
||||
|
||||
@@ -330,7 +336,7 @@ public class WebSocketConnectionTest {
|
||||
});
|
||||
|
||||
WebSocketConnection connection = new WebSocketConnection(receiptSender, storedMessages,
|
||||
account, device, client);
|
||||
account, device, client, retrySchedulingExecutor);
|
||||
|
||||
connection.start();
|
||||
|
||||
@@ -353,7 +359,7 @@ public class WebSocketConnectionTest {
|
||||
public void testProcessStoredMessageConcurrency() throws InterruptedException {
|
||||
final MessagesManager messagesManager = mock(MessagesManager.class);
|
||||
final WebSocketClient client = mock(WebSocketClient.class);
|
||||
final WebSocketConnection connection = new WebSocketConnection(receiptSender, messagesManager, account, device, client);
|
||||
final WebSocketConnection connection = new WebSocketConnection(receiptSender, messagesManager, account, device, client, retrySchedulingExecutor);
|
||||
|
||||
when(account.getNumber()).thenReturn("+18005551234");
|
||||
when(account.getUuid()).thenReturn(UUID.randomUUID());
|
||||
@@ -414,7 +420,7 @@ public class WebSocketConnectionTest {
|
||||
public void testProcessStoredMessagesMultiplePages() throws InterruptedException {
|
||||
final MessagesManager messagesManager = mock(MessagesManager.class);
|
||||
final WebSocketClient client = mock(WebSocketClient.class);
|
||||
final WebSocketConnection connection = new WebSocketConnection(receiptSender, messagesManager, account, device, client);
|
||||
final WebSocketConnection connection = new WebSocketConnection(receiptSender, messagesManager, account, device, client, retrySchedulingExecutor);
|
||||
|
||||
when(account.getNumber()).thenReturn("+18005551234");
|
||||
when(account.getUuid()).thenReturn(UUID.randomUUID());
|
||||
@@ -457,7 +463,7 @@ public class WebSocketConnectionTest {
|
||||
public void testProcessStoredMessagesContainsSenderUuid() throws InterruptedException {
|
||||
final MessagesManager messagesManager = mock(MessagesManager.class);
|
||||
final WebSocketClient client = mock(WebSocketClient.class);
|
||||
final WebSocketConnection connection = new WebSocketConnection(receiptSender, messagesManager, account, device, client);
|
||||
final WebSocketConnection connection = new WebSocketConnection(receiptSender, messagesManager, account, device, client, retrySchedulingExecutor);
|
||||
|
||||
when(account.getNumber()).thenReturn("+18005551234");
|
||||
when(account.getUuid()).thenReturn(UUID.randomUUID());
|
||||
@@ -507,7 +513,7 @@ public class WebSocketConnectionTest {
|
||||
public void testProcessStoredMessagesSingleEmptyCall() {
|
||||
final MessagesManager messagesManager = mock(MessagesManager.class);
|
||||
final WebSocketClient client = mock(WebSocketClient.class);
|
||||
final WebSocketConnection connection = new WebSocketConnection(receiptSender, messagesManager, account, device, client);
|
||||
final WebSocketConnection connection = new WebSocketConnection(receiptSender, messagesManager, account, device, client, retrySchedulingExecutor);
|
||||
|
||||
final UUID accountUuid = UUID.randomUUID();
|
||||
|
||||
@@ -536,7 +542,7 @@ public class WebSocketConnectionTest {
|
||||
public void testRequeryOnStateMismatch() throws InterruptedException {
|
||||
final MessagesManager messagesManager = mock(MessagesManager.class);
|
||||
final WebSocketClient client = mock(WebSocketClient.class);
|
||||
final WebSocketConnection connection = new WebSocketConnection(receiptSender, messagesManager, account, device, client);
|
||||
final WebSocketConnection connection = new WebSocketConnection(receiptSender, messagesManager, account, device, client, retrySchedulingExecutor);
|
||||
final UUID accountUuid = UUID.randomUUID();
|
||||
|
||||
when(account.getNumber()).thenReturn("+18005551234");
|
||||
@@ -583,7 +589,7 @@ public class WebSocketConnectionTest {
|
||||
public void testProcessCachedMessagesOnly() {
|
||||
final MessagesManager messagesManager = mock(MessagesManager.class);
|
||||
final WebSocketClient client = mock(WebSocketClient.class);
|
||||
final WebSocketConnection connection = new WebSocketConnection(receiptSender, messagesManager, account, device, client);
|
||||
final WebSocketConnection connection = new WebSocketConnection(receiptSender, messagesManager, account, device, client, retrySchedulingExecutor);
|
||||
|
||||
final UUID accountUuid = UUID.randomUUID();
|
||||
|
||||
@@ -615,7 +621,7 @@ public class WebSocketConnectionTest {
|
||||
public void testProcessDatabaseMessagesAfterPersist() {
|
||||
final MessagesManager messagesManager = mock(MessagesManager.class);
|
||||
final WebSocketClient client = mock(WebSocketClient.class);
|
||||
final WebSocketConnection connection = new WebSocketConnection(receiptSender, messagesManager, account, device, client);
|
||||
final WebSocketConnection connection = new WebSocketConnection(receiptSender, messagesManager, account, device, client, retrySchedulingExecutor);
|
||||
|
||||
final UUID accountUuid = UUID.randomUUID();
|
||||
|
||||
@@ -693,7 +699,7 @@ public class WebSocketConnectionTest {
|
||||
}
|
||||
});
|
||||
|
||||
WebSocketConnection connection = new WebSocketConnection(receiptSender, storedMessages, account, device, client);
|
||||
WebSocketConnection connection = new WebSocketConnection(receiptSender, storedMessages, account, device, client, retrySchedulingExecutor);
|
||||
|
||||
connection.start();
|
||||
verify(client, times(2)).sendRequest(eq("PUT"), eq("/api/v1/message"), ArgumentMatchers.nullable(List.class), ArgumentMatchers.<Optional<byte[]>>any());
|
||||
@@ -766,7 +772,7 @@ public class WebSocketConnectionTest {
|
||||
}
|
||||
});
|
||||
|
||||
WebSocketConnection connection = new WebSocketConnection(receiptSender, storedMessages, account, device, client);
|
||||
WebSocketConnection connection = new WebSocketConnection(receiptSender, storedMessages, account, device, client, retrySchedulingExecutor);
|
||||
|
||||
connection.start();
|
||||
verify(client, times(3)).sendRequest(eq("PUT"), eq("/api/v1/message"), ArgumentMatchers.nullable(List.class), ArgumentMatchers.<Optional<byte[]>>any());
|
||||
@@ -785,6 +791,37 @@ public class WebSocketConnectionTest {
|
||||
verify(client).close(anyInt(), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRetrieveMessageException() {
|
||||
MessagesManager storedMessages = mock(MessagesManager.class);
|
||||
|
||||
UUID accountUuid = UUID.randomUUID();
|
||||
|
||||
when(device.getId()).thenReturn(2L);
|
||||
|
||||
when(account.getAuthenticatedDevice()).thenReturn(Optional.of(device));
|
||||
when(account.getNumber()).thenReturn("+14152222222");
|
||||
when(account.getUuid()).thenReturn(accountUuid);
|
||||
|
||||
String userAgent = "Signal-Android/4.68.3";
|
||||
|
||||
when(storedMessages.getMessagesForDevice(account.getUuid(), device.getId(), userAgent, false))
|
||||
.thenThrow(new RedisException("OH NO"));
|
||||
|
||||
when(retrySchedulingExecutor.schedule(any(Runnable.class), anyLong(), any())).thenAnswer((Answer<ScheduledFuture<?>>) invocation -> {
|
||||
invocation.getArgument(0, Runnable.class).run();
|
||||
return mock(ScheduledFuture.class);
|
||||
});
|
||||
|
||||
final WebSocketClient client = mock(WebSocketClient.class);
|
||||
|
||||
WebSocketConnection connection = new WebSocketConnection(receiptSender, storedMessages, account, device, client, retrySchedulingExecutor);
|
||||
connection.start();
|
||||
|
||||
verify(retrySchedulingExecutor, times(WebSocketConnection.MAX_CONSECUTIVE_RETRIES)).schedule(any(Runnable.class), anyLong(), any());
|
||||
verify(client).close(eq(1011), anyString());
|
||||
}
|
||||
|
||||
private OutgoingMessageEntity createMessage(long id, boolean cached, String sender, UUID senderUuid, long timestamp, boolean receipt, String content) {
|
||||
return new OutgoingMessageEntity(id, cached, UUID.randomUUID(), receipt ? Envelope.Type.RECEIPT_VALUE : Envelope.Type.CIPHERTEXT_VALUE,
|
||||
null, timestamp, sender, senderUuid, 1, content.getBytes(), null, 0);
|
||||
|
||||
Reference in New Issue
Block a user