mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-22 07:28:02 +01:00
Introduce common push notification interfaces/pathways
This commit is contained in:
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright 2013-2022 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.push;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.eatthepath.pushy.apns.ApnsClient;
|
||||
import com.eatthepath.pushy.apns.ApnsPushNotification;
|
||||
import com.eatthepath.pushy.apns.DeliveryPriority;
|
||||
import com.eatthepath.pushy.apns.PushNotificationResponse;
|
||||
import com.eatthepath.pushy.apns.util.SimpleApnsPushNotification;
|
||||
import com.eatthepath.pushy.apns.util.concurrent.PushNotificationFuture;
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.whispersystems.textsecuregcm.storage.Account;
|
||||
import org.whispersystems.textsecuregcm.storage.Device;
|
||||
import org.whispersystems.textsecuregcm.tests.util.SynchronousExecutorService;
|
||||
|
||||
class APNSenderTest {
|
||||
|
||||
private static final String DESTINATION_APN_ID = "foo";
|
||||
|
||||
private Account destinationAccount;
|
||||
private Device destinationDevice;
|
||||
|
||||
private ApnsClient apnsClient;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
destinationAccount = mock(Account.class);
|
||||
destinationDevice = mock(Device.class);
|
||||
|
||||
apnsClient = mock(ApnsClient.class);
|
||||
|
||||
when(destinationAccount.getDevice(1)).thenReturn(Optional.of(destinationDevice));
|
||||
when(destinationDevice.getApnId()).thenReturn(DESTINATION_APN_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSendVoip() {
|
||||
PushNotificationResponse<SimpleApnsPushNotification> response = mock(PushNotificationResponse.class);
|
||||
when(response.isAccepted()).thenReturn(true);
|
||||
|
||||
when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class)))
|
||||
.thenAnswer((Answer) invocationOnMock -> new MockPushNotificationFuture<>(invocationOnMock.getArgument(0), response));
|
||||
|
||||
RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient);
|
||||
PushNotification pushNotification = new PushNotification(DESTINATION_APN_ID, PushNotification.TokenType.APN_VOIP, PushNotification.NotificationType.NOTIFICATION, null, destinationAccount, destinationDevice);
|
||||
APNSender apnSender = new APNSender(new SynchronousExecutorService(), retryingApnsClient, "foo", false);
|
||||
|
||||
final SendPushNotificationResult result = apnSender.sendNotification(pushNotification).join();
|
||||
|
||||
ArgumentCaptor<SimpleApnsPushNotification> notification = ArgumentCaptor.forClass(SimpleApnsPushNotification.class);
|
||||
verify(apnsClient).sendNotification(notification.capture());
|
||||
|
||||
assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID);
|
||||
assertThat(notification.getValue().getExpiration()).isEqualTo(APNSender.MAX_EXPIRATION);
|
||||
assertThat(notification.getValue().getPayload()).isEqualTo(APNSender.APN_VOIP_NOTIFICATION_PAYLOAD);
|
||||
assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE);
|
||||
assertThat(notification.getValue().getTopic()).isEqualTo("foo.voip");
|
||||
|
||||
assertThat(result.accepted()).isTrue();
|
||||
assertThat(result.errorCode()).isNull();
|
||||
assertThat(result.unregistered()).isFalse();
|
||||
|
||||
verifyNoMoreInteractions(apnsClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSendApns() {
|
||||
PushNotificationResponse<SimpleApnsPushNotification> response = mock(PushNotificationResponse.class);
|
||||
when(response.isAccepted()).thenReturn(true);
|
||||
|
||||
when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class)))
|
||||
.thenAnswer((Answer) invocationOnMock -> new MockPushNotificationFuture<>(invocationOnMock.getArgument(0), response));
|
||||
|
||||
RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient);
|
||||
PushNotification pushNotification = new PushNotification(DESTINATION_APN_ID, PushNotification.TokenType.APN, PushNotification.NotificationType.NOTIFICATION, null, destinationAccount, destinationDevice);
|
||||
APNSender apnSender = new APNSender(new SynchronousExecutorService(), retryingApnsClient, "foo", false);
|
||||
|
||||
final SendPushNotificationResult result = apnSender.sendNotification(pushNotification).join();
|
||||
|
||||
ArgumentCaptor<SimpleApnsPushNotification> notification = ArgumentCaptor.forClass(SimpleApnsPushNotification.class);
|
||||
verify(apnsClient).sendNotification(notification.capture());
|
||||
|
||||
assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID);
|
||||
assertThat(notification.getValue().getExpiration()).isEqualTo(APNSender.MAX_EXPIRATION);
|
||||
assertThat(notification.getValue().getPayload()).isEqualTo(APNSender.APN_NSE_NOTIFICATION_PAYLOAD);
|
||||
assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE);
|
||||
assertThat(notification.getValue().getTopic()).isEqualTo("foo");
|
||||
|
||||
assertThat(result.accepted()).isTrue();
|
||||
assertThat(result.errorCode()).isNull();
|
||||
assertThat(result.unregistered()).isFalse();
|
||||
|
||||
verifyNoMoreInteractions(apnsClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUnregisteredUser() throws Exception {
|
||||
PushNotificationResponse<SimpleApnsPushNotification> response = mock(PushNotificationResponse.class);
|
||||
when(response.isAccepted()).thenReturn(false);
|
||||
when(response.getRejectionReason()).thenReturn(Optional.of("Unregistered"));
|
||||
|
||||
when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class)))
|
||||
.thenAnswer((Answer) invocationOnMock -> new MockPushNotificationFuture<>(invocationOnMock.getArgument(0), response));
|
||||
|
||||
|
||||
RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient);
|
||||
PushNotification pushNotification = new PushNotification(DESTINATION_APN_ID, PushNotification.TokenType.APN_VOIP, PushNotification.NotificationType.NOTIFICATION, null, destinationAccount, destinationDevice);
|
||||
APNSender apnSender = new APNSender(new SynchronousExecutorService(), retryingApnsClient, "foo", false);
|
||||
|
||||
when(destinationDevice.getApnId()).thenReturn(DESTINATION_APN_ID);
|
||||
when(destinationDevice.getPushTimestamp()).thenReturn(System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(11));
|
||||
|
||||
final SendPushNotificationResult result = apnSender.sendNotification(pushNotification).join();
|
||||
|
||||
ArgumentCaptor<SimpleApnsPushNotification> notification = ArgumentCaptor.forClass(SimpleApnsPushNotification.class);
|
||||
verify(apnsClient).sendNotification(notification.capture());
|
||||
|
||||
assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID);
|
||||
assertThat(notification.getValue().getExpiration()).isEqualTo(APNSender.MAX_EXPIRATION);
|
||||
assertThat(notification.getValue().getPayload()).isEqualTo(APNSender.APN_VOIP_NOTIFICATION_PAYLOAD);
|
||||
assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE);
|
||||
|
||||
assertThat(result.accepted()).isFalse();
|
||||
assertThat(result.errorCode()).isEqualTo("Unregistered");
|
||||
assertThat(result.unregistered()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGenericFailure() {
|
||||
ApnsClient apnsClient = mock(ApnsClient.class);
|
||||
|
||||
PushNotificationResponse<SimpleApnsPushNotification> response = mock(PushNotificationResponse.class);
|
||||
when(response.isAccepted()).thenReturn(false);
|
||||
when(response.getRejectionReason()).thenReturn(Optional.of("BadTopic"));
|
||||
|
||||
when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class)))
|
||||
.thenAnswer((Answer) invocationOnMock -> new MockPushNotificationFuture<>(invocationOnMock.getArgument(0), response));
|
||||
|
||||
RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient);
|
||||
PushNotification pushNotification = new PushNotification(DESTINATION_APN_ID, PushNotification.TokenType.APN_VOIP, PushNotification.NotificationType.NOTIFICATION, null, destinationAccount, destinationDevice);
|
||||
APNSender apnSender = new APNSender(new SynchronousExecutorService(), retryingApnsClient, "foo", false);
|
||||
|
||||
final SendPushNotificationResult result = apnSender.sendNotification(pushNotification).join();
|
||||
|
||||
ArgumentCaptor<SimpleApnsPushNotification> notification = ArgumentCaptor.forClass(SimpleApnsPushNotification.class);
|
||||
verify(apnsClient).sendNotification(notification.capture());
|
||||
|
||||
assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID);
|
||||
assertThat(notification.getValue().getExpiration()).isEqualTo(APNSender.MAX_EXPIRATION);
|
||||
assertThat(notification.getValue().getPayload()).isEqualTo(APNSender.APN_VOIP_NOTIFICATION_PAYLOAD);
|
||||
assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE);
|
||||
|
||||
assertThat(result.accepted()).isFalse();
|
||||
assertThat(result.errorCode()).isEqualTo("BadTopic");
|
||||
assertThat(result.unregistered()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure() {
|
||||
PushNotificationResponse<SimpleApnsPushNotification> response = mock(PushNotificationResponse.class);
|
||||
when(response.isAccepted()).thenReturn(true);
|
||||
|
||||
when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class)))
|
||||
.thenAnswer((Answer) invocationOnMock -> new MockPushNotificationFuture<>(invocationOnMock.getArgument(0), new IOException("lost connection")));
|
||||
|
||||
RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient);
|
||||
PushNotification pushNotification = new PushNotification(DESTINATION_APN_ID, PushNotification.TokenType.APN_VOIP, PushNotification.NotificationType.NOTIFICATION, null, destinationAccount, destinationDevice);
|
||||
APNSender apnSender = new APNSender(new SynchronousExecutorService(), retryingApnsClient, "foo", false);
|
||||
|
||||
assertThatThrownBy(() -> apnSender.sendNotification(pushNotification).join())
|
||||
.isInstanceOf(CompletionException.class)
|
||||
.hasCauseInstanceOf(IOException.class);
|
||||
|
||||
verify(apnsClient).sendNotification(any());
|
||||
|
||||
verifyNoMoreInteractions(apnsClient);
|
||||
}
|
||||
|
||||
private static class MockPushNotificationFuture <P extends ApnsPushNotification, V> extends PushNotificationFuture<P, V> {
|
||||
|
||||
MockPushNotificationFuture(final P pushNotification, final V response) {
|
||||
super(pushNotification);
|
||||
complete(response);
|
||||
}
|
||||
|
||||
MockPushNotificationFuture(final P pushNotification, final Exception exception) {
|
||||
super(pushNotification);
|
||||
completeExceptionally(exception);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -100,14 +100,14 @@ class ApnFallbackManagerTest {
|
||||
|
||||
assertEquals(1, worker.processNextSlot());
|
||||
|
||||
final ArgumentCaptor<ApnMessage> messageCaptor = ArgumentCaptor.forClass(ApnMessage.class);
|
||||
verify(apnSender).sendMessage(messageCaptor.capture());
|
||||
final ArgumentCaptor<PushNotification> notificationCaptor = ArgumentCaptor.forClass(PushNotification.class);
|
||||
verify(apnSender).sendNotification(notificationCaptor.capture());
|
||||
|
||||
final ApnMessage message = messageCaptor.getValue();
|
||||
final PushNotification pushNotification = notificationCaptor.getValue();
|
||||
|
||||
assertEquals(VOIP_APN_ID, message.getApnId());
|
||||
assertEquals(Optional.of(ACCOUNT_UUID), message.getUuid());
|
||||
assertEquals(DEVICE_ID, message.getDeviceId());
|
||||
assertEquals(VOIP_APN_ID, pushNotification.deviceToken());
|
||||
assertEquals(account, pushNotification.destination());
|
||||
assertEquals(device, pushNotification.destinationDevice());
|
||||
|
||||
assertEquals(0, worker.processNextSlot());
|
||||
}
|
||||
|
||||
@@ -5,8 +5,12 @@
|
||||
|
||||
package org.whispersystems.textsecuregcm.push;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
@@ -16,24 +20,18 @@ import com.google.firebase.messaging.FirebaseMessaging;
|
||||
import com.google.firebase.messaging.FirebaseMessagingException;
|
||||
import com.google.firebase.messaging.Message;
|
||||
import com.google.firebase.messaging.MessagingErrorCode;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.whispersystems.textsecuregcm.storage.Account;
|
||||
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||
import org.whispersystems.textsecuregcm.storage.Device;
|
||||
import org.whispersystems.textsecuregcm.tests.util.AccountsHelper;
|
||||
import org.whispersystems.textsecuregcm.tests.util.SynchronousExecutorService;
|
||||
import org.whispersystems.textsecuregcm.util.Util;
|
||||
|
||||
class FcmSenderTest {
|
||||
|
||||
private ExecutorService executorService;
|
||||
private AccountsManager accountsManager;
|
||||
private FirebaseMessaging firebaseMessaging;
|
||||
|
||||
private FcmSender fcmSender;
|
||||
@@ -41,10 +39,9 @@ class FcmSenderTest {
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
executorService = new SynchronousExecutorService();
|
||||
accountsManager = mock(AccountsManager.class);
|
||||
firebaseMessaging = mock(FirebaseMessaging.class);
|
||||
|
||||
fcmSender = new FcmSender(executorService, accountsManager, firebaseMessaging);
|
||||
fcmSender = new FcmSender(executorService, firebaseMessaging);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
@@ -57,35 +54,44 @@ class FcmSenderTest {
|
||||
|
||||
@Test
|
||||
void testSendMessage() {
|
||||
AccountsHelper.setupMockUpdate(accountsManager);
|
||||
|
||||
final GcmMessage message = new GcmMessage("foo", UUID.randomUUID(), 1, GcmMessage.Type.NOTIFICATION, Optional.empty());
|
||||
final PushNotification pushNotification = new PushNotification("foo", PushNotification.TokenType.FCM, PushNotification.NotificationType.NOTIFICATION, null, null, null);
|
||||
|
||||
final SettableApiFuture<String> sendFuture = SettableApiFuture.create();
|
||||
sendFuture.set("message-id");
|
||||
|
||||
when(firebaseMessaging.sendAsync(any())).thenReturn(sendFuture);
|
||||
|
||||
fcmSender.sendMessage(message);
|
||||
final SendPushNotificationResult result = fcmSender.sendNotification(pushNotification).join();
|
||||
|
||||
verify(firebaseMessaging).sendAsync(any(Message.class));
|
||||
assertTrue(result.accepted());
|
||||
assertNull(result.errorCode());
|
||||
assertFalse(result.unregistered());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSendUninstalled() {
|
||||
final UUID destinationUuid = UUID.randomUUID();
|
||||
final String gcmId = "foo";
|
||||
void testSendMessageRejected() {
|
||||
final PushNotification pushNotification = new PushNotification("foo", PushNotification.TokenType.FCM, PushNotification.NotificationType.NOTIFICATION, null, null, null);
|
||||
|
||||
final Account destinationAccount = mock(Account.class);
|
||||
final Device destinationDevice = mock(Device.class );
|
||||
final FirebaseMessagingException invalidArgumentException = mock(FirebaseMessagingException.class);
|
||||
when(invalidArgumentException.getMessagingErrorCode()).thenReturn(MessagingErrorCode.INVALID_ARGUMENT);
|
||||
|
||||
AccountsHelper.setupMockUpdate(accountsManager);
|
||||
final SettableApiFuture<String> sendFuture = SettableApiFuture.create();
|
||||
sendFuture.setException(invalidArgumentException);
|
||||
|
||||
when(destinationAccount.getDevice(1)).thenReturn(Optional.of(destinationDevice));
|
||||
when(accountsManager.getByAccountIdentifier(destinationUuid)).thenReturn(Optional.of(destinationAccount));
|
||||
when(destinationDevice.getGcmId()).thenReturn(gcmId);
|
||||
when(firebaseMessaging.sendAsync(any())).thenReturn(sendFuture);
|
||||
|
||||
final GcmMessage message = new GcmMessage(gcmId, destinationUuid, 1, GcmMessage.Type.NOTIFICATION, Optional.empty());
|
||||
final SendPushNotificationResult result = fcmSender.sendNotification(pushNotification).join();
|
||||
|
||||
verify(firebaseMessaging).sendAsync(any(Message.class));
|
||||
assertFalse(result.accepted());
|
||||
assertEquals("INVALID_ARGUMENT", result.errorCode());
|
||||
assertFalse(result.unregistered());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSendMessageUnregistered() {
|
||||
final PushNotification pushNotification = new PushNotification("foo", PushNotification.TokenType.FCM, PushNotification.NotificationType.NOTIFICATION, null, null, null);
|
||||
|
||||
final FirebaseMessagingException unregisteredException = mock(FirebaseMessagingException.class);
|
||||
when(unregisteredException.getMessagingErrorCode()).thenReturn(MessagingErrorCode.UNREGISTERED);
|
||||
@@ -95,11 +101,27 @@ class FcmSenderTest {
|
||||
|
||||
when(firebaseMessaging.sendAsync(any())).thenReturn(sendFuture);
|
||||
|
||||
fcmSender.sendMessage(message);
|
||||
final SendPushNotificationResult result = fcmSender.sendNotification(pushNotification).join();
|
||||
|
||||
verify(firebaseMessaging).sendAsync(any(Message.class));
|
||||
verify(accountsManager).getByAccountIdentifier(destinationUuid);
|
||||
verify(accountsManager).updateDevice(eq(destinationAccount), eq(1L), any());
|
||||
verify(destinationDevice).setUninstalledFeedbackTimestamp(Util.todayInMillis());
|
||||
assertFalse(result.accepted());
|
||||
assertEquals("UNREGISTERED", result.errorCode());
|
||||
assertTrue(result.unregistered());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSendMessageException() {
|
||||
final PushNotification pushNotification = new PushNotification("foo", PushNotification.TokenType.FCM, PushNotification.NotificationType.NOTIFICATION, null, null, null);
|
||||
|
||||
final SettableApiFuture<String> sendFuture = SettableApiFuture.create();
|
||||
sendFuture.setException(new IOException());
|
||||
|
||||
when(firebaseMessaging.sendAsync(any())).thenReturn(sendFuture);
|
||||
|
||||
final CompletionException completionException =
|
||||
assertThrows(CompletionException.class, () -> fcmSender.sendNotification(pushNotification).join());
|
||||
|
||||
verify(firebaseMessaging).sendAsync(any(Message.class));
|
||||
assertTrue(completionException.getCause() instanceof IOException);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,14 @@
|
||||
|
||||
package org.whispersystems.textsecuregcm.push;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
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.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -37,8 +39,7 @@ class MessageSenderTest {
|
||||
|
||||
private ClientPresenceManager clientPresenceManager;
|
||||
private MessagesManager messagesManager;
|
||||
private FcmSender fcmSender;
|
||||
private APNSender apnSender;
|
||||
private PushNotificationManager pushNotificationManager;
|
||||
private MessageSender messageSender;
|
||||
|
||||
private static final UUID ACCOUNT_UUID = UUID.randomUUID();
|
||||
@@ -53,13 +54,10 @@ class MessageSenderTest {
|
||||
|
||||
clientPresenceManager = mock(ClientPresenceManager.class);
|
||||
messagesManager = mock(MessagesManager.class);
|
||||
fcmSender = mock(FcmSender.class);
|
||||
apnSender = mock(APNSender.class);
|
||||
messageSender = new MessageSender(mock(ApnFallbackManager.class),
|
||||
clientPresenceManager,
|
||||
pushNotificationManager = mock(PushNotificationManager.class);
|
||||
messageSender = new MessageSender(clientPresenceManager,
|
||||
messagesManager,
|
||||
fcmSender,
|
||||
apnSender,
|
||||
pushNotificationManager,
|
||||
mock(PushLatencyManager.class));
|
||||
|
||||
when(account.getUuid()).thenReturn(ACCOUNT_UUID);
|
||||
@@ -80,8 +78,7 @@ class MessageSenderTest {
|
||||
|
||||
assertTrue(envelopeArgumentCaptor.getValue().getEphemeral());
|
||||
|
||||
verifyNoInteractions(fcmSender);
|
||||
verifyNoInteractions(apnSender);
|
||||
verifyNoInteractions(pushNotificationManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -92,8 +89,7 @@ class MessageSenderTest {
|
||||
messageSender.sendMessage(account, device, message, true);
|
||||
|
||||
verify(messagesManager, never()).insert(any(), anyLong(), any());
|
||||
verifyNoInteractions(fcmSender);
|
||||
verifyNoInteractions(apnSender);
|
||||
verifyNoInteractions(pushNotificationManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -110,8 +106,7 @@ class MessageSenderTest {
|
||||
|
||||
assertFalse(envelopeArgumentCaptor.getValue().getEphemeral());
|
||||
assertEquals(message, envelopeArgumentCaptor.getValue());
|
||||
verifyNoInteractions(fcmSender);
|
||||
verifyNoInteractions(apnSender);
|
||||
verifyNoInteractions(pushNotificationManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -122,8 +117,7 @@ class MessageSenderTest {
|
||||
messageSender.sendMessage(account, device, message, false);
|
||||
|
||||
verify(messagesManager).insert(ACCOUNT_UUID, DEVICE_ID, message);
|
||||
verify(fcmSender).sendMessage(any());
|
||||
verifyNoInteractions(apnSender);
|
||||
verify(pushNotificationManager).sendNewMessageNotification(account, device.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -134,8 +128,7 @@ class MessageSenderTest {
|
||||
messageSender.sendMessage(account, device, message, false);
|
||||
|
||||
verify(messagesManager).insert(ACCOUNT_UUID, DEVICE_ID, message);
|
||||
verifyNoInteractions(fcmSender);
|
||||
verify(apnSender).sendMessage(any());
|
||||
verify(pushNotificationManager).sendNewMessageNotification(account, device.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -143,11 +136,11 @@ class MessageSenderTest {
|
||||
when(clientPresenceManager.isPresent(ACCOUNT_UUID, DEVICE_ID)).thenReturn(false);
|
||||
when(device.getFetchesMessages()).thenReturn(true);
|
||||
|
||||
messageSender.sendMessage(account, device, message, false);
|
||||
doThrow(NotPushRegisteredException.class)
|
||||
.when(pushNotificationManager).sendNewMessageNotification(account, DEVICE_ID);
|
||||
|
||||
assertDoesNotThrow(() -> messageSender.sendMessage(account, device, message, false));
|
||||
verify(messagesManager).insert(ACCOUNT_UUID, DEVICE_ID, message);
|
||||
verifyNoInteractions(fcmSender);
|
||||
verifyNoInteractions(apnSender);
|
||||
}
|
||||
|
||||
private MessageProtos.Envelope generateRandomMessage() {
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright 2013-2022 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.push;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
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.when;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.whispersystems.textsecuregcm.storage.Account;
|
||||
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||
import org.whispersystems.textsecuregcm.storage.Device;
|
||||
import org.whispersystems.textsecuregcm.tests.util.AccountsHelper;
|
||||
import org.whispersystems.textsecuregcm.util.Util;
|
||||
|
||||
class PushNotificationManagerTest {
|
||||
|
||||
private AccountsManager accountsManager;
|
||||
private APNSender apnSender;
|
||||
private FcmSender fcmSender;
|
||||
private ApnFallbackManager apnFallbackManager;
|
||||
|
||||
private PushNotificationManager pushNotificationManager;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
accountsManager = mock(AccountsManager.class);
|
||||
apnSender = mock(APNSender.class);
|
||||
fcmSender = mock(FcmSender.class);
|
||||
apnFallbackManager = mock(ApnFallbackManager.class);
|
||||
|
||||
AccountsHelper.setupMockUpdate(accountsManager);
|
||||
|
||||
pushNotificationManager = new PushNotificationManager(accountsManager, apnSender, fcmSender, apnFallbackManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendNewMessageNotification() throws NotPushRegisteredException {
|
||||
final Account account = mock(Account.class);
|
||||
final Device device = mock(Device.class);
|
||||
|
||||
final String deviceToken = "token";
|
||||
|
||||
when(device.getId()).thenReturn(Device.MASTER_ID);
|
||||
when(device.getGcmId()).thenReturn(deviceToken);
|
||||
when(account.getDevice(Device.MASTER_ID)).thenReturn(Optional.of(device));
|
||||
|
||||
when(fcmSender.sendNotification(any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(new SendPushNotificationResult(true, null, false)));
|
||||
|
||||
pushNotificationManager.sendNewMessageNotification(account, Device.MASTER_ID);
|
||||
verify(fcmSender).sendNotification(new PushNotification(deviceToken, PushNotification.TokenType.FCM, PushNotification.NotificationType.NOTIFICATION, null, account, device));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendRegistrationChallengeNotification() {
|
||||
final String deviceToken = "token";
|
||||
final String challengeToken = "challenge";
|
||||
|
||||
when(apnSender.sendNotification(any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(new SendPushNotificationResult(true, null, false)));
|
||||
|
||||
pushNotificationManager.sendRegistrationChallengeNotification(deviceToken, PushNotification.TokenType.APN_VOIP, challengeToken);
|
||||
verify(apnSender).sendNotification(new PushNotification(deviceToken, PushNotification.TokenType.APN_VOIP, PushNotification.NotificationType.CHALLENGE, challengeToken, null, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendRateLimitChallengeNotification() throws NotPushRegisteredException {
|
||||
final Account account = mock(Account.class);
|
||||
final Device device = mock(Device.class);
|
||||
|
||||
final String deviceToken = "token";
|
||||
final String challengeToken = "challenge";
|
||||
|
||||
when(device.getId()).thenReturn(Device.MASTER_ID);
|
||||
when(device.getApnId()).thenReturn(deviceToken);
|
||||
when(account.getDevice(Device.MASTER_ID)).thenReturn(Optional.of(device));
|
||||
|
||||
when(apnSender.sendNotification(any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(new SendPushNotificationResult(true, null, false)));
|
||||
|
||||
pushNotificationManager.sendRateLimitChallengeNotification(account, challengeToken);
|
||||
verify(apnSender).sendNotification(new PushNotification(deviceToken, PushNotification.TokenType.APN, PushNotification.NotificationType.RATE_LIMIT_CHALLENGE, challengeToken, account, device));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSendNotification() {
|
||||
final Account account = mock(Account.class);
|
||||
final Device device = mock(Device.class);
|
||||
|
||||
when(device.getId()).thenReturn(Device.MASTER_ID);
|
||||
when(account.getDevice(Device.MASTER_ID)).thenReturn(Optional.of(device));
|
||||
|
||||
final PushNotification pushNotification = new PushNotification(
|
||||
"token", PushNotification.TokenType.FCM, PushNotification.NotificationType.NOTIFICATION, null, account, device);
|
||||
|
||||
when(fcmSender.sendNotification(pushNotification))
|
||||
.thenReturn(CompletableFuture.completedFuture(new SendPushNotificationResult(true, null, false)));
|
||||
|
||||
pushNotificationManager.sendNotification(pushNotification);
|
||||
|
||||
verify(fcmSender).sendNotification(pushNotification);
|
||||
verifyNoInteractions(apnSender);
|
||||
verify(accountsManager, never()).updateDevice(eq(account), eq(Device.MASTER_ID), any());
|
||||
verify(device, never()).setUninstalledFeedbackTimestamp(Util.todayInMillis());
|
||||
verifyNoInteractions(apnFallbackManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSendNotificationApnVoip() {
|
||||
final Account account = mock(Account.class);
|
||||
final Device device = mock(Device.class);
|
||||
|
||||
when(device.getId()).thenReturn(Device.MASTER_ID);
|
||||
when(account.getDevice(Device.MASTER_ID)).thenReturn(Optional.of(device));
|
||||
|
||||
final PushNotification pushNotification = new PushNotification(
|
||||
"token", PushNotification.TokenType.APN_VOIP, PushNotification.NotificationType.NOTIFICATION, null, account, device);
|
||||
|
||||
when(apnSender.sendNotification(pushNotification))
|
||||
.thenReturn(CompletableFuture.completedFuture(new SendPushNotificationResult(true, null, false)));
|
||||
|
||||
pushNotificationManager.sendNotification(pushNotification);
|
||||
|
||||
verify(apnSender).sendNotification(pushNotification);
|
||||
verifyNoInteractions(fcmSender);
|
||||
verify(accountsManager, never()).updateDevice(eq(account), eq(Device.MASTER_ID), any());
|
||||
verify(device, never()).setUninstalledFeedbackTimestamp(Util.todayInMillis());
|
||||
verify(apnFallbackManager).schedule(account, device);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSendNotificationUnregisteredFcm() {
|
||||
final Account account = mock(Account.class);
|
||||
final Device device = mock(Device.class);
|
||||
|
||||
when(device.getId()).thenReturn(Device.MASTER_ID);
|
||||
when(device.getGcmId()).thenReturn("token");
|
||||
when(account.getDevice(Device.MASTER_ID)).thenReturn(Optional.of(device));
|
||||
|
||||
final PushNotification pushNotification = new PushNotification(
|
||||
"token", PushNotification.TokenType.FCM, PushNotification.NotificationType.NOTIFICATION, null, account, device);
|
||||
|
||||
when(fcmSender.sendNotification(pushNotification))
|
||||
.thenReturn(CompletableFuture.completedFuture(new SendPushNotificationResult(false, null, true)));
|
||||
|
||||
pushNotificationManager.sendNotification(pushNotification);
|
||||
|
||||
verify(accountsManager).updateDevice(eq(account), eq(Device.MASTER_ID), any());
|
||||
verify(device).setUninstalledFeedbackTimestamp(Util.todayInMillis());
|
||||
verifyNoInteractions(apnSender);
|
||||
verifyNoInteractions(apnFallbackManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSendNotificationUnregisteredApn() {
|
||||
final Account account = mock(Account.class);
|
||||
final Device device = mock(Device.class);
|
||||
|
||||
when(device.getId()).thenReturn(Device.MASTER_ID);
|
||||
when(account.getDevice(Device.MASTER_ID)).thenReturn(Optional.of(device));
|
||||
|
||||
final PushNotification pushNotification = new PushNotification(
|
||||
"token", PushNotification.TokenType.APN_VOIP, PushNotification.NotificationType.NOTIFICATION, null, account, device);
|
||||
|
||||
when(apnSender.sendNotification(pushNotification))
|
||||
.thenReturn(CompletableFuture.completedFuture(new SendPushNotificationResult(false, null, true)));
|
||||
|
||||
pushNotificationManager.sendNotification(pushNotification);
|
||||
|
||||
verifyNoInteractions(fcmSender);
|
||||
verify(accountsManager, never()).updateDevice(eq(account), eq(Device.MASTER_ID), any());
|
||||
verify(device, never()).setUninstalledFeedbackTimestamp(Util.todayInMillis());
|
||||
verify(apnFallbackManager).cancel(account, device);
|
||||
}
|
||||
}
|
||||
@@ -80,10 +80,8 @@ import org.whispersystems.textsecuregcm.mappers.ImpossiblePhoneNumberExceptionMa
|
||||
import org.whispersystems.textsecuregcm.mappers.NonNormalizedPhoneNumberExceptionMapper;
|
||||
import org.whispersystems.textsecuregcm.mappers.NonNormalizedPhoneNumberResponse;
|
||||
import org.whispersystems.textsecuregcm.mappers.RateLimitExceededExceptionMapper;
|
||||
import org.whispersystems.textsecuregcm.push.APNSender;
|
||||
import org.whispersystems.textsecuregcm.push.ApnMessage;
|
||||
import org.whispersystems.textsecuregcm.push.FcmSender;
|
||||
import org.whispersystems.textsecuregcm.push.GcmMessage;
|
||||
import org.whispersystems.textsecuregcm.push.PushNotification;
|
||||
import org.whispersystems.textsecuregcm.push.PushNotificationManager;
|
||||
import org.whispersystems.textsecuregcm.recaptcha.RecaptchaClient;
|
||||
import org.whispersystems.textsecuregcm.sms.SmsSender;
|
||||
import org.whispersystems.textsecuregcm.sms.TwilioVerifyExperimentEnrollmentManager;
|
||||
@@ -147,8 +145,7 @@ class AccountControllerTest {
|
||||
private static Account senderHasStorage = mock(Account.class);
|
||||
private static Account senderTransfer = mock(Account.class);
|
||||
private static RecaptchaClient recaptchaClient = mock(RecaptchaClient.class);
|
||||
private static FcmSender fcmSender = mock(FcmSender.class);
|
||||
private static APNSender apnSender = mock(APNSender.class);
|
||||
private static PushNotificationManager pushNotificationManager = mock(PushNotificationManager.class);
|
||||
private static ChangeNumberManager changeNumberManager = mock(ChangeNumberManager.class);
|
||||
|
||||
private static DynamicConfigurationManager dynamicConfigurationManager = mock(DynamicConfigurationManager.class);
|
||||
@@ -179,8 +176,7 @@ class AccountControllerTest {
|
||||
turnTokenGenerator,
|
||||
Map.of(TEST_NUMBER, TEST_VERIFICATION_CODE),
|
||||
recaptchaClient,
|
||||
fcmSender,
|
||||
apnSender,
|
||||
pushNotificationManager,
|
||||
verifyExperimentEnrollmentManager,
|
||||
changeNumberManager,
|
||||
storageCredentialGenerator))
|
||||
@@ -322,8 +318,7 @@ class AccountControllerTest {
|
||||
senderHasStorage,
|
||||
senderTransfer,
|
||||
recaptchaClient,
|
||||
fcmSender,
|
||||
apnSender,
|
||||
pushNotificationManager,
|
||||
verifyExperimentEnrollmentManager,
|
||||
changeNumberManager);
|
||||
|
||||
@@ -339,14 +334,12 @@ class AccountControllerTest {
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
|
||||
ArgumentCaptor<GcmMessage> captor = ArgumentCaptor.forClass(GcmMessage.class);
|
||||
final ArgumentCaptor<String> challengeTokenCaptor = ArgumentCaptor.forClass(String.class);
|
||||
|
||||
verify(fcmSender, times(1)).sendMessage(captor.capture());
|
||||
assertThat(captor.getValue().getGcmId()).isEqualTo("mytoken");
|
||||
assertThat(captor.getValue().getData().isPresent()).isTrue();
|
||||
assertThat(captor.getValue().getData().get().length()).isEqualTo(32);
|
||||
verify(pushNotificationManager).sendRegistrationChallengeNotification(
|
||||
eq("mytoken"), eq(PushNotification.TokenType.FCM), challengeTokenCaptor.capture());
|
||||
|
||||
verifyNoMoreInteractions(apnSender);
|
||||
assertThat(challengeTokenCaptor.getValue().length()).isEqualTo(32);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -358,14 +351,12 @@ class AccountControllerTest {
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
|
||||
ArgumentCaptor<GcmMessage> captor = ArgumentCaptor.forClass(GcmMessage.class);
|
||||
final ArgumentCaptor<String> challengeTokenCaptor = ArgumentCaptor.forClass(String.class);
|
||||
|
||||
verify(fcmSender, times(1)).sendMessage(captor.capture());
|
||||
assertThat(captor.getValue().getGcmId()).isEqualTo("mytoken");
|
||||
assertThat(captor.getValue().getData().isPresent()).isTrue();
|
||||
assertThat(captor.getValue().getData().get().length()).isEqualTo(32);
|
||||
verify(pushNotificationManager).sendRegistrationChallengeNotification(
|
||||
eq("mytoken"), eq(PushNotification.TokenType.FCM), challengeTokenCaptor.capture());
|
||||
|
||||
verifyNoMoreInteractions(apnSender);
|
||||
assertThat(challengeTokenCaptor.getValue().length()).isEqualTo(32);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -377,16 +368,12 @@ class AccountControllerTest {
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
|
||||
ArgumentCaptor<ApnMessage> captor = ArgumentCaptor.forClass(ApnMessage.class);
|
||||
final ArgumentCaptor<String> challengeTokenCaptor = ArgumentCaptor.forClass(String.class);
|
||||
|
||||
verify(apnSender, times(1)).sendMessage(captor.capture());
|
||||
assertThat(captor.getValue().getApnId()).isEqualTo("mytoken");
|
||||
assertThat(captor.getValue().getChallengeData().isPresent()).isTrue();
|
||||
assertThat(captor.getValue().getChallengeData().get().length()).isEqualTo(32);
|
||||
assertThat(captor.getValue().getMessage()).contains("\"challenge\" : \"" + captor.getValue().getChallengeData().get() + "\"");
|
||||
assertThat(captor.getValue().isVoip()).isTrue();
|
||||
verify(pushNotificationManager).sendRegistrationChallengeNotification(
|
||||
eq("mytoken"), eq(PushNotification.TokenType.APN_VOIP), challengeTokenCaptor.capture());
|
||||
|
||||
verifyNoMoreInteractions(fcmSender);
|
||||
assertThat(challengeTokenCaptor.getValue().length()).isEqualTo(32);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -399,16 +386,12 @@ class AccountControllerTest {
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
|
||||
ArgumentCaptor<ApnMessage> captor = ArgumentCaptor.forClass(ApnMessage.class);
|
||||
final ArgumentCaptor<String> challengeTokenCaptor = ArgumentCaptor.forClass(String.class);
|
||||
|
||||
verify(apnSender, times(1)).sendMessage(captor.capture());
|
||||
assertThat(captor.getValue().getApnId()).isEqualTo("mytoken");
|
||||
assertThat(captor.getValue().getChallengeData().isPresent()).isTrue();
|
||||
assertThat(captor.getValue().getChallengeData().get().length()).isEqualTo(32);
|
||||
assertThat(captor.getValue().getMessage()).contains("\"challenge\" : \"" + captor.getValue().getChallengeData().get() + "\"");
|
||||
assertThat(captor.getValue().isVoip()).isTrue();
|
||||
verify(pushNotificationManager).sendRegistrationChallengeNotification(
|
||||
eq("mytoken"), eq(PushNotification.TokenType.APN_VOIP), challengeTokenCaptor.capture());
|
||||
|
||||
verifyNoMoreInteractions(fcmSender);
|
||||
assertThat(challengeTokenCaptor.getValue().length()).isEqualTo(32);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -421,16 +404,12 @@ class AccountControllerTest {
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
|
||||
ArgumentCaptor<ApnMessage> captor = ArgumentCaptor.forClass(ApnMessage.class);
|
||||
final ArgumentCaptor<String> challengeTokenCaptor = ArgumentCaptor.forClass(String.class);
|
||||
|
||||
verify(apnSender, times(1)).sendMessage(captor.capture());
|
||||
assertThat(captor.getValue().getApnId()).isEqualTo("mytoken");
|
||||
assertThat(captor.getValue().getChallengeData().isPresent()).isTrue();
|
||||
assertThat(captor.getValue().getChallengeData().get().length()).isEqualTo(32);
|
||||
assertThat(captor.getValue().getMessage()).contains("\"challenge\" : \"" + captor.getValue().getChallengeData().get() + "\"");
|
||||
assertThat(captor.getValue().isVoip()).isFalse();
|
||||
verify(pushNotificationManager).sendRegistrationChallengeNotification(
|
||||
eq("mytoken"), eq(PushNotification.TokenType.APN), challengeTokenCaptor.capture());
|
||||
|
||||
verifyNoMoreInteractions(fcmSender);
|
||||
assertThat(challengeTokenCaptor.getValue().length()).isEqualTo(32);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -443,8 +422,7 @@ class AccountControllerTest {
|
||||
assertThat(response.getStatus()).isEqualTo(400);
|
||||
assertThat(response.readEntity(String.class)).isBlank();
|
||||
|
||||
verifyNoMoreInteractions(fcmSender);
|
||||
verifyNoMoreInteractions(apnSender);
|
||||
verifyNoMoreInteractions(pushNotificationManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -462,8 +440,7 @@ class AccountControllerTest {
|
||||
assertThat(responseEntity.getOriginalNumber()).isEqualTo(number);
|
||||
assertThat(responseEntity.getNormalizedNumber()).isEqualTo("+447700900111");
|
||||
|
||||
verifyNoMoreInteractions(fcmSender);
|
||||
verifyNoMoreInteractions(apnSender);
|
||||
verifyNoMoreInteractions(pushNotificationManager);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
|
||||
@@ -1,415 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.tests.push;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.eatthepath.pushy.apns.ApnsClient;
|
||||
import com.eatthepath.pushy.apns.ApnsPushNotification;
|
||||
import com.eatthepath.pushy.apns.DeliveryPriority;
|
||||
import com.eatthepath.pushy.apns.PushNotificationResponse;
|
||||
import com.eatthepath.pushy.apns.util.SimpleApnsPushNotification;
|
||||
import com.eatthepath.pushy.apns.util.concurrent.PushNotificationFuture;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.whispersystems.textsecuregcm.push.APNSender;
|
||||
import org.whispersystems.textsecuregcm.push.ApnFallbackManager;
|
||||
import org.whispersystems.textsecuregcm.push.ApnMessage;
|
||||
import org.whispersystems.textsecuregcm.push.ApnMessage.Type;
|
||||
import org.whispersystems.textsecuregcm.push.RetryingApnsClient;
|
||||
import org.whispersystems.textsecuregcm.push.RetryingApnsClient.ApnResult;
|
||||
import org.whispersystems.textsecuregcm.storage.Account;
|
||||
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||
import org.whispersystems.textsecuregcm.storage.Device;
|
||||
import org.whispersystems.textsecuregcm.tests.util.SynchronousExecutorService;
|
||||
|
||||
class APNSenderTest {
|
||||
|
||||
private static final UUID DESTINATION_UUID = UUID.randomUUID();
|
||||
private static final String DESTINATION_APN_ID = "foo";
|
||||
|
||||
private final AccountsManager accountsManager = mock(AccountsManager.class);
|
||||
|
||||
private final Account destinationAccount = mock(Account.class);
|
||||
private final Device destinationDevice = mock(Device.class);
|
||||
private final ApnFallbackManager fallbackManager = mock(ApnFallbackManager.class);
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
when(destinationAccount.getDevice(1)).thenReturn(Optional.of(destinationDevice));
|
||||
when(destinationDevice.getApnId()).thenReturn(DESTINATION_APN_ID);
|
||||
when(accountsManager.getByAccountIdentifier(DESTINATION_UUID)).thenReturn(Optional.of(destinationAccount));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSendVoip() throws Exception {
|
||||
ApnsClient apnsClient = mock(ApnsClient.class);
|
||||
|
||||
PushNotificationResponse<SimpleApnsPushNotification> response = mock(PushNotificationResponse.class);
|
||||
when(response.isAccepted()).thenReturn(true);
|
||||
|
||||
when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class)))
|
||||
.thenAnswer((Answer) invocationOnMock -> new MockPushNotificationFuture<>(invocationOnMock.getArgument(0), response));
|
||||
|
||||
RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient);
|
||||
ApnMessage message = new ApnMessage(DESTINATION_APN_ID, DESTINATION_UUID, 1, true, Type.NOTIFICATION, Optional.empty());
|
||||
APNSender apnSender = new APNSender(new SynchronousExecutorService(), accountsManager, retryingApnsClient, "foo", false);
|
||||
|
||||
apnSender.setApnFallbackManager(fallbackManager);
|
||||
ListenableFuture<ApnResult> sendFuture = apnSender.sendMessage(message);
|
||||
ApnResult apnResult = sendFuture.get();
|
||||
|
||||
ArgumentCaptor<SimpleApnsPushNotification> notification = ArgumentCaptor.forClass(SimpleApnsPushNotification.class);
|
||||
verify(apnsClient, times(1)).sendNotification(notification.capture());
|
||||
|
||||
assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID);
|
||||
assertThat(notification.getValue().getExpiration()).isEqualTo(Instant.ofEpochMilli(ApnMessage.MAX_EXPIRATION));
|
||||
assertThat(notification.getValue().getPayload()).isEqualTo(ApnMessage.APN_VOIP_NOTIFICATION_PAYLOAD);
|
||||
assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE);
|
||||
assertThat(notification.getValue().getTopic()).isEqualTo("foo.voip");
|
||||
|
||||
assertThat(apnResult.getStatus()).isEqualTo(ApnResult.Status.SUCCESS);
|
||||
|
||||
verifyNoMoreInteractions(apnsClient);
|
||||
verifyNoMoreInteractions(accountsManager);
|
||||
verifyNoMoreInteractions(fallbackManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSendApns() throws Exception {
|
||||
ApnsClient apnsClient = mock(ApnsClient.class);
|
||||
|
||||
PushNotificationResponse<SimpleApnsPushNotification> response = mock(PushNotificationResponse.class);
|
||||
when(response.isAccepted()).thenReturn(true);
|
||||
|
||||
when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class)))
|
||||
.thenAnswer((Answer) invocationOnMock -> new MockPushNotificationFuture<>(invocationOnMock.getArgument(0), response));
|
||||
|
||||
RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient);
|
||||
ApnMessage message = new ApnMessage(DESTINATION_APN_ID, DESTINATION_UUID, 1, false, Type.NOTIFICATION, Optional.empty());
|
||||
APNSender apnSender = new APNSender(new SynchronousExecutorService(), accountsManager, retryingApnsClient, "foo", false);
|
||||
apnSender.setApnFallbackManager(fallbackManager);
|
||||
|
||||
ListenableFuture<ApnResult> sendFuture = apnSender.sendMessage(message);
|
||||
ApnResult apnResult = sendFuture.get();
|
||||
|
||||
ArgumentCaptor<SimpleApnsPushNotification> notification = ArgumentCaptor.forClass(SimpleApnsPushNotification.class);
|
||||
verify(apnsClient, times(1)).sendNotification(notification.capture());
|
||||
|
||||
assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID);
|
||||
assertThat(notification.getValue().getExpiration()).isEqualTo(Instant.ofEpochMilli(ApnMessage.MAX_EXPIRATION));
|
||||
assertThat(notification.getValue().getPayload()).isEqualTo(ApnMessage.APN_NSE_NOTIFICATION_PAYLOAD);
|
||||
assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE);
|
||||
assertThat(notification.getValue().getTopic()).isEqualTo("foo");
|
||||
|
||||
assertThat(apnResult.getStatus()).isEqualTo(ApnResult.Status.SUCCESS);
|
||||
|
||||
verifyNoMoreInteractions(apnsClient);
|
||||
verifyNoMoreInteractions(accountsManager);
|
||||
verifyNoMoreInteractions(fallbackManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUnregisteredUser() throws Exception {
|
||||
ApnsClient apnsClient = mock(ApnsClient.class);
|
||||
|
||||
PushNotificationResponse<SimpleApnsPushNotification> response = mock(PushNotificationResponse.class);
|
||||
when(response.isAccepted()).thenReturn(false);
|
||||
when(response.getRejectionReason()).thenReturn(Optional.of("Unregistered"));
|
||||
|
||||
when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class)))
|
||||
.thenAnswer((Answer) invocationOnMock -> new MockPushNotificationFuture<>(invocationOnMock.getArgument(0), response));
|
||||
|
||||
|
||||
RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient);
|
||||
ApnMessage message = new ApnMessage(DESTINATION_APN_ID, DESTINATION_UUID, 1, true, Type.NOTIFICATION, Optional.empty());
|
||||
APNSender apnSender = new APNSender(new SynchronousExecutorService(), accountsManager, retryingApnsClient, "foo", false);
|
||||
apnSender.setApnFallbackManager(fallbackManager);
|
||||
|
||||
when(destinationDevice.getApnId()).thenReturn(DESTINATION_APN_ID);
|
||||
when(destinationDevice.getPushTimestamp()).thenReturn(System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(11));
|
||||
|
||||
ListenableFuture<ApnResult> sendFuture = apnSender.sendMessage(message);
|
||||
ApnResult apnResult = sendFuture.get();
|
||||
|
||||
Thread.sleep(1000); // =(
|
||||
|
||||
ArgumentCaptor<SimpleApnsPushNotification> notification = ArgumentCaptor.forClass(SimpleApnsPushNotification.class);
|
||||
verify(apnsClient, times(1)).sendNotification(notification.capture());
|
||||
|
||||
assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID);
|
||||
assertThat(notification.getValue().getExpiration()).isEqualTo(Instant.ofEpochMilli(ApnMessage.MAX_EXPIRATION));
|
||||
assertThat(notification.getValue().getPayload()).isEqualTo(ApnMessage.APN_VOIP_NOTIFICATION_PAYLOAD);
|
||||
assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE);
|
||||
|
||||
assertThat(apnResult.getStatus()).isEqualTo(ApnResult.Status.NO_SUCH_USER);
|
||||
|
||||
verifyNoMoreInteractions(apnsClient);
|
||||
verify(accountsManager, times(1)).getByAccountIdentifier(eq(DESTINATION_UUID));
|
||||
verify(destinationAccount, times(1)).getDevice(1);
|
||||
verify(destinationDevice, times(1)).getApnId();
|
||||
verify(destinationDevice, times(1)).getPushTimestamp();
|
||||
// verify(destinationDevice, times(1)).setApnId(eq((String)null));
|
||||
// verify(destinationDevice, times(1)).setVoipApnId(eq((String)null));
|
||||
// verify(destinationDevice, times(1)).setFetchesMessages(eq(false));
|
||||
// verify(accountsManager, times(1)).update(eq(destinationAccount));
|
||||
verify(fallbackManager, times(1)).cancel(eq(destinationAccount), eq(destinationDevice));
|
||||
|
||||
verifyNoMoreInteractions(accountsManager);
|
||||
verifyNoMoreInteractions(fallbackManager);
|
||||
}
|
||||
|
||||
// @Test
|
||||
// public void testVoipUnregisteredUser() throws Exception {
|
||||
// ApnsClient apnsClient = mock(ApnsClient.class);
|
||||
//
|
||||
// PushNotificationResponse<SimpleApnsPushNotification> response = mock(PushNotificationResponse.class);
|
||||
// when(response.isAccepted()).thenReturn(false);
|
||||
// when(response.getRejectionReason()).thenReturn("Unregistered");
|
||||
//
|
||||
// DefaultPromise<PushNotificationResponse<SimpleApnsPushNotification>> result = new DefaultPromise<>(executor);
|
||||
// result.setSuccess(response);
|
||||
//
|
||||
// when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class)))
|
||||
// .thenReturn(result);
|
||||
//
|
||||
// RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient, 10);
|
||||
// ApnMessage message = new ApnMessage(DESTINATION_APN_ID, DESTINATION_NUMBER, 1, "message", true, 30);
|
||||
// APNSender apnSender = new APNSender(new SynchronousExecutorService(), accountsManager, retryingApnsClient, "foo", false);
|
||||
// apnSender.setApnFallbackManager(fallbackManager);
|
||||
//
|
||||
// when(destinationDevice.getApnId()).thenReturn("baz");
|
||||
// when(destinationDevice.getVoipApnId()).thenReturn(DESTINATION_APN_ID);
|
||||
// when(destinationDevice.getPushTimestamp()).thenReturn(System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(11));
|
||||
//
|
||||
// ListenableFuture<ApnResult> sendFuture = apnSender.sendMessage(message);
|
||||
// ApnResult apnResult = sendFuture.get();
|
||||
//
|
||||
// Thread.sleep(1000); // =(
|
||||
//
|
||||
// ArgumentCaptor<SimpleApnsPushNotification> notification = ArgumentCaptor.forClass(SimpleApnsPushNotification.class);
|
||||
// verify(apnsClient, times(1)).sendNotification(notification.capture());
|
||||
//
|
||||
// assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID);
|
||||
// assertThat(notification.getValue().getExpiration()).isEqualTo(new Date(30));
|
||||
// assertThat(notification.getValue().getPayload()).isEqualTo("message");
|
||||
// assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE);
|
||||
//
|
||||
// assertThat(apnResult.getStatus()).isEqualTo(ApnResult.Status.NO_SUCH_USER);
|
||||
//
|
||||
// verifyNoMoreInteractions(apnsClient);
|
||||
// verify(accountsManager, times(1)).get(eq(DESTINATION_NUMBER));
|
||||
// verify(destinationAccount, times(1)).getDevice(1);
|
||||
// verify(destinationDevice, times(1)).getApnId();
|
||||
// verify(destinationDevice, times(1)).getVoipApnId();
|
||||
// verify(destinationDevice, times(1)).getPushTimestamp();
|
||||
// verify(destinationDevice, times(1)).setApnId(eq((String)null));
|
||||
// verify(destinationDevice, times(1)).setVoipApnId(eq((String)null));
|
||||
// verify(destinationDevice, times(1)).setFetchesMessages(eq(false));
|
||||
// verify(accountsManager, times(1)).update(eq(destinationAccount));
|
||||
// verify(fallbackManager, times(1)).cancel(eq(new WebsocketAddress(DESTINATION_NUMBER, 1)));
|
||||
//
|
||||
// verifyNoMoreInteractions(accountsManager);
|
||||
// verifyNoMoreInteractions(fallbackManager);
|
||||
// }
|
||||
|
||||
@Test
|
||||
void testRecentUnregisteredUser() throws Exception {
|
||||
ApnsClient apnsClient = mock(ApnsClient.class);
|
||||
|
||||
PushNotificationResponse<SimpleApnsPushNotification> response = mock(PushNotificationResponse.class);
|
||||
when(response.isAccepted()).thenReturn(false);
|
||||
when(response.getRejectionReason()).thenReturn(Optional.of("Unregistered"));
|
||||
|
||||
when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class)))
|
||||
.thenAnswer((Answer) invocationOnMock -> new MockPushNotificationFuture<>(invocationOnMock.getArgument(0), response));
|
||||
|
||||
RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient);
|
||||
ApnMessage message = new ApnMessage(DESTINATION_APN_ID, DESTINATION_UUID, 1, true, Type.NOTIFICATION, Optional.empty());
|
||||
APNSender apnSender = new APNSender(new SynchronousExecutorService(), accountsManager, retryingApnsClient, "foo", false);
|
||||
apnSender.setApnFallbackManager(fallbackManager);
|
||||
|
||||
when(destinationDevice.getApnId()).thenReturn(DESTINATION_APN_ID);
|
||||
when(destinationDevice.getPushTimestamp()).thenReturn(System.currentTimeMillis());
|
||||
|
||||
ListenableFuture<ApnResult> sendFuture = apnSender.sendMessage(message);
|
||||
ApnResult apnResult = sendFuture.get();
|
||||
|
||||
Thread.sleep(1000); // =(
|
||||
|
||||
ArgumentCaptor<SimpleApnsPushNotification> notification = ArgumentCaptor.forClass(SimpleApnsPushNotification.class);
|
||||
verify(apnsClient, times(1)).sendNotification(notification.capture());
|
||||
|
||||
assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID);
|
||||
assertThat(notification.getValue().getExpiration()).isEqualTo(Instant.ofEpochMilli(ApnMessage.MAX_EXPIRATION));
|
||||
assertThat(notification.getValue().getPayload()).isEqualTo(ApnMessage.APN_VOIP_NOTIFICATION_PAYLOAD);
|
||||
assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE);
|
||||
|
||||
assertThat(apnResult.getStatus()).isEqualTo(ApnResult.Status.NO_SUCH_USER);
|
||||
|
||||
verifyNoMoreInteractions(apnsClient);
|
||||
verify(accountsManager, times(1)).getByAccountIdentifier(eq(DESTINATION_UUID));
|
||||
verify(destinationAccount, times(1)).getDevice(1);
|
||||
verify(destinationDevice, times(1)).getApnId();
|
||||
verify(destinationDevice, times(1)).getPushTimestamp();
|
||||
|
||||
verifyNoMoreInteractions(destinationDevice);
|
||||
verifyNoMoreInteractions(destinationAccount);
|
||||
verifyNoMoreInteractions(accountsManager);
|
||||
verifyNoMoreInteractions(fallbackManager);
|
||||
}
|
||||
|
||||
// @Test
|
||||
// public void testUnregisteredUserOldApnId() throws Exception {
|
||||
// ApnsClient apnsClient = mock(ApnsClient.class);
|
||||
//
|
||||
// PushNotificationResponse<SimpleApnsPushNotification> response = mock(PushNotificationResponse.class);
|
||||
// when(response.isAccepted()).thenReturn(false);
|
||||
// when(response.getRejectionReason()).thenReturn("Unregistered");
|
||||
//
|
||||
// DefaultPromise<PushNotificationResponse<SimpleApnsPushNotification>> result = new DefaultPromise<>(executor);
|
||||
// result.setSuccess(response);
|
||||
//
|
||||
// when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class)))
|
||||
// .thenReturn(result);
|
||||
//
|
||||
// RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient, 10);
|
||||
// ApnMessage message = new ApnMessage(DESTINATION_APN_ID, DESTINATION_NUMBER, 1, "message", true, 30);
|
||||
// APNSender apnSender = new APNSender(new SynchronousExecutorService(), accountsManager, retryingApnsClient, "foo", false);
|
||||
// apnSender.setApnFallbackManager(fallbackManager);
|
||||
//
|
||||
// when(destinationDevice.getApnId()).thenReturn("baz");
|
||||
// when(destinationDevice.getPushTimestamp()).thenReturn(System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(12));
|
||||
//
|
||||
// ListenableFuture<ApnResult> sendFuture = apnSender.sendMessage(message);
|
||||
// ApnResult apnResult = sendFuture.get();
|
||||
//
|
||||
// Thread.sleep(1000); // =(
|
||||
//
|
||||
// ArgumentCaptor<SimpleApnsPushNotification> notification = ArgumentCaptor.forClass(SimpleApnsPushNotification.class);
|
||||
// verify(apnsClient, times(1)).sendNotification(notification.capture());
|
||||
//
|
||||
// assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID);
|
||||
// assertThat(notification.getValue().getExpiration()).isEqualTo(new Date(30));
|
||||
// assertThat(notification.getValue().getPayload()).isEqualTo("message");
|
||||
// assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE);
|
||||
//
|
||||
// assertThat(apnResult.getStatus()).isEqualTo(ApnResult.Status.NO_SUCH_USER);
|
||||
//
|
||||
// verifyNoMoreInteractions(apnsClient);
|
||||
// verify(accountsManager, times(1)).get(eq(DESTINATION_NUMBER));
|
||||
// verify(destinationAccount, times(1)).getDevice(1);
|
||||
// verify(destinationDevice, times(2)).getApnId();
|
||||
// verify(destinationDevice, times(2)).getVoipApnId();
|
||||
//
|
||||
// verifyNoMoreInteractions(destinationDevice);
|
||||
// verifyNoMoreInteractions(destinationAccount);
|
||||
// verifyNoMoreInteractions(accountsManager);
|
||||
// verifyNoMoreInteractions(fallbackManager);
|
||||
// }
|
||||
|
||||
@Test
|
||||
void testGenericFailure() throws Exception {
|
||||
ApnsClient apnsClient = mock(ApnsClient.class);
|
||||
|
||||
PushNotificationResponse<SimpleApnsPushNotification> response = mock(PushNotificationResponse.class);
|
||||
when(response.isAccepted()).thenReturn(false);
|
||||
when(response.getRejectionReason()).thenReturn(Optional.of("BadTopic"));
|
||||
|
||||
when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class)))
|
||||
.thenAnswer((Answer) invocationOnMock -> new MockPushNotificationFuture<>(invocationOnMock.getArgument(0), response));
|
||||
|
||||
RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient);
|
||||
ApnMessage message = new ApnMessage(DESTINATION_APN_ID, DESTINATION_UUID, 1, true, Type.NOTIFICATION, Optional.empty());
|
||||
APNSender apnSender = new APNSender(new SynchronousExecutorService(), accountsManager, retryingApnsClient, "foo", false);
|
||||
apnSender.setApnFallbackManager(fallbackManager);
|
||||
|
||||
ListenableFuture<ApnResult> sendFuture = apnSender.sendMessage(message);
|
||||
ApnResult apnResult = sendFuture.get();
|
||||
|
||||
ArgumentCaptor<SimpleApnsPushNotification> notification = ArgumentCaptor.forClass(SimpleApnsPushNotification.class);
|
||||
verify(apnsClient, times(1)).sendNotification(notification.capture());
|
||||
|
||||
assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID);
|
||||
assertThat(notification.getValue().getExpiration()).isEqualTo(Instant.ofEpochMilli(ApnMessage.MAX_EXPIRATION));
|
||||
assertThat(notification.getValue().getPayload()).isEqualTo(ApnMessage.APN_VOIP_NOTIFICATION_PAYLOAD);
|
||||
assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE);
|
||||
|
||||
assertThat(apnResult.getStatus()).isEqualTo(ApnResult.Status.GENERIC_FAILURE);
|
||||
|
||||
verifyNoMoreInteractions(apnsClient);
|
||||
verifyNoMoreInteractions(accountsManager);
|
||||
verifyNoMoreInteractions(fallbackManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure() throws Exception {
|
||||
ApnsClient apnsClient = mock(ApnsClient.class);
|
||||
|
||||
PushNotificationResponse<SimpleApnsPushNotification> response = mock(PushNotificationResponse.class);
|
||||
when(response.isAccepted()).thenReturn(true);
|
||||
|
||||
when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class)))
|
||||
.thenAnswer((Answer) invocationOnMock -> new MockPushNotificationFuture<>(invocationOnMock.getArgument(0), new Exception("lost connection")));
|
||||
|
||||
RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient);
|
||||
ApnMessage message = new ApnMessage(DESTINATION_APN_ID, DESTINATION_UUID, 1, true, Type.NOTIFICATION, Optional.empty());
|
||||
APNSender apnSender = new APNSender(new SynchronousExecutorService(), accountsManager, retryingApnsClient, "foo", false);
|
||||
apnSender.setApnFallbackManager(fallbackManager);
|
||||
|
||||
ListenableFuture<ApnResult> sendFuture = apnSender.sendMessage(message);
|
||||
|
||||
try {
|
||||
sendFuture.get();
|
||||
throw new AssertionError();
|
||||
} catch (InterruptedException e) {
|
||||
throw new AssertionError(e);
|
||||
} catch (ExecutionException e) {
|
||||
// good
|
||||
}
|
||||
|
||||
ArgumentCaptor<SimpleApnsPushNotification> notification = ArgumentCaptor.forClass(SimpleApnsPushNotification.class);
|
||||
verify(apnsClient, times(1)).sendNotification(notification.capture());
|
||||
|
||||
assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID);
|
||||
assertThat(notification.getValue().getExpiration()).isEqualTo(Instant.ofEpochMilli(ApnMessage.MAX_EXPIRATION));
|
||||
assertThat(notification.getValue().getPayload()).isEqualTo(ApnMessage.APN_VOIP_NOTIFICATION_PAYLOAD);
|
||||
assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE);
|
||||
|
||||
verifyNoMoreInteractions(apnsClient);
|
||||
verifyNoMoreInteractions(accountsManager);
|
||||
verifyNoMoreInteractions(fallbackManager);
|
||||
}
|
||||
|
||||
private static class MockPushNotificationFuture <P extends ApnsPushNotification, V> extends PushNotificationFuture<P, V> {
|
||||
|
||||
MockPushNotificationFuture(final P pushNotification, final V response) {
|
||||
super(pushNotification);
|
||||
complete(response);
|
||||
}
|
||||
|
||||
MockPushNotificationFuture(final P pushNotification, final Exception exception) {
|
||||
super(pushNotification);
|
||||
completeExceptionally(exception);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -54,7 +54,7 @@ import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||
import org.whispersystems.textsecuregcm.entities.OutgoingMessageEntityList;
|
||||
import org.whispersystems.textsecuregcm.push.ApnFallbackManager;
|
||||
import org.whispersystems.textsecuregcm.push.ClientPresenceManager;
|
||||
import org.whispersystems.textsecuregcm.push.MessageSender;
|
||||
import org.whispersystems.textsecuregcm.push.PushNotificationManager;
|
||||
import org.whispersystems.textsecuregcm.push.ReceiptSender;
|
||||
import org.whispersystems.textsecuregcm.storage.Account;
|
||||
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||
@@ -104,7 +104,7 @@ class WebSocketConnectionTest {
|
||||
MessagesManager storedMessages = mock(MessagesManager.class);
|
||||
WebSocketAccountAuthenticator webSocketAuthenticator = new WebSocketAccountAuthenticator(accountAuthenticator);
|
||||
AuthenticatedConnectListener connectListener = new AuthenticatedConnectListener(receiptSender, storedMessages,
|
||||
mock(MessageSender.class), apnFallbackManager, mock(ClientPresenceManager.class),
|
||||
mock(PushNotificationManager.class), apnFallbackManager, mock(ClientPresenceManager.class),
|
||||
retrySchedulingExecutor);
|
||||
WebSocketSessionContext sessionContext = mock(WebSocketSessionContext.class);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user