mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-21 20:28:06 +01:00
Make Backup methods synchronous
This commit is contained in:
@@ -12,6 +12,7 @@ import static org.assertj.core.api.Assertions.assertThatNoException;
|
||||
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.reset;
|
||||
@@ -64,7 +65,6 @@ import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||
import org.whispersystems.textsecuregcm.storage.Device;
|
||||
import org.whispersystems.textsecuregcm.storage.RedeemedReceiptsManager;
|
||||
import org.whispersystems.textsecuregcm.tests.util.ExperimentHelper;
|
||||
import org.whispersystems.textsecuregcm.util.CompletableFutureTestUtil;
|
||||
import org.whispersystems.textsecuregcm.util.TestClock;
|
||||
import org.whispersystems.textsecuregcm.util.TestRandomUtil;
|
||||
|
||||
@@ -107,19 +107,18 @@ public class BackupAuthManagerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void commitBackupId() {
|
||||
void commitBackupId() throws RateLimitExceededException {
|
||||
final BackupAuthManager authManager = create();
|
||||
|
||||
final Account account = mock(Account.class);
|
||||
when(account.getUuid()).thenReturn(aci);
|
||||
when(accountsManager.updateAsync(any(), any()))
|
||||
when(accountsManager.update(any(), any()))
|
||||
.thenAnswer(invocation -> {
|
||||
final Account a = invocation.getArgument(0);
|
||||
final Consumer<Account> updater = invocation.getArgument(1);
|
||||
|
||||
updater.accept(a);
|
||||
|
||||
return CompletableFuture.completedFuture(a);
|
||||
return a;
|
||||
});
|
||||
|
||||
final BackupAuthCredentialRequest messagesCredentialRequest = backupAuthTestUtil.getRequest(messagesBackupKey, aci);
|
||||
@@ -127,7 +126,7 @@ public class BackupAuthManagerTest {
|
||||
|
||||
authManager.commitBackupId(account, primaryDevice(),
|
||||
Optional.of(messagesCredentialRequest),
|
||||
Optional.of(mediaCredentialRequest)).join();
|
||||
Optional.of(mediaCredentialRequest));
|
||||
|
||||
verify(account).setBackupCredentialRequests(messagesCredentialRequest.serialize(),
|
||||
mediaCredentialRequest.serialize());
|
||||
@@ -138,13 +137,13 @@ public class BackupAuthManagerTest {
|
||||
void commitOnAnyBackupLevel(final BackupLevel backupLevel) {
|
||||
final BackupAuthManager authManager = create();
|
||||
final Account account = new MockAccountBuilder().backupLevel(backupLevel).build();
|
||||
when(accountsManager.updateAsync(any(), any())).thenReturn(CompletableFuture.completedFuture(account));
|
||||
when(accountsManager.update(any(), any())).thenReturn(account);
|
||||
|
||||
final ThrowableAssert.ThrowingCallable commit = () ->
|
||||
authManager.commitBackupId(account,
|
||||
primaryDevice(),
|
||||
Optional.of(backupAuthTestUtil.getRequest(messagesBackupKey, aci)),
|
||||
Optional.of(backupAuthTestUtil.getRequest(mediaBackupKey, aci))).join();
|
||||
Optional.of(backupAuthTestUtil.getRequest(mediaBackupKey, aci)));
|
||||
Assertions.assertThatNoException().isThrownBy(commit);
|
||||
}
|
||||
|
||||
@@ -152,13 +151,13 @@ public class BackupAuthManagerTest {
|
||||
void commitRequiresPrimary() {
|
||||
final BackupAuthManager authManager = create();
|
||||
final Account account = new MockAccountBuilder().build();
|
||||
when(accountsManager.updateAsync(any(), any())).thenReturn(CompletableFuture.completedFuture(account));
|
||||
when(accountsManager.update(any(), any())).thenReturn(account);
|
||||
|
||||
final ThrowableAssert.ThrowingCallable commit = () ->
|
||||
authManager.commitBackupId(account,
|
||||
linkedDevice(),
|
||||
Optional.of(backupAuthTestUtil.getRequest(messagesBackupKey, aci)),
|
||||
Optional.of(backupAuthTestUtil.getRequest(mediaBackupKey, aci))).join();
|
||||
Optional.of(backupAuthTestUtil.getRequest(mediaBackupKey, aci)));
|
||||
assertThatExceptionOfType(StatusRuntimeException.class)
|
||||
.isThrownBy(commit)
|
||||
.extracting(ex -> ex.getStatus().getCode())
|
||||
@@ -186,7 +185,7 @@ public class BackupAuthManagerTest {
|
||||
|
||||
final RedemptionRange range = range(Duration.ofDays(1));
|
||||
final List<BackupAuthManager.Credential> creds =
|
||||
authManager.getBackupAuthCredentials(account, credentialType, range(Duration.ofDays(1))).join();
|
||||
authManager.getBackupAuthCredentials(account, credentialType, range(Duration.ofDays(1)));
|
||||
|
||||
assertThat(creds).hasSize(2);
|
||||
assertThat(requestContext
|
||||
@@ -207,7 +206,7 @@ public class BackupAuthManagerTest {
|
||||
.mediaCredential(backupAuthTestUtil.getRequest(mediaBackupKey, aci))
|
||||
.build();
|
||||
|
||||
assertThat(authManager.getBackupAuthCredentials(account, credentialType, range(Duration.ofDays(1))).join())
|
||||
assertThat(authManager.getBackupAuthCredentials(account, credentialType, range(Duration.ofDays(1))))
|
||||
.hasSize(2);
|
||||
}
|
||||
|
||||
@@ -220,7 +219,7 @@ public class BackupAuthManagerTest {
|
||||
|
||||
assertThatExceptionOfType(StatusRuntimeException.class)
|
||||
.isThrownBy(() ->
|
||||
authManager.getBackupAuthCredentials(account, credentialType, range(Duration.ofDays(1))).join())
|
||||
authManager.getBackupAuthCredentials(account, credentialType, range(Duration.ofDays(1))))
|
||||
.extracting(ex -> ex.getStatus().getCode())
|
||||
.isEqualTo(Status.Code.NOT_FOUND);
|
||||
}
|
||||
@@ -245,7 +244,7 @@ public class BackupAuthManagerTest {
|
||||
.build();
|
||||
|
||||
final List<BackupAuthManager.Credential> creds = authManager.getBackupAuthCredentials(account,
|
||||
credentialType, range(Duration.ofDays(7))).join();
|
||||
credentialType, range(Duration.ofDays(7)));
|
||||
|
||||
assertThat(creds).hasSize(8);
|
||||
Instant redemptionTime = clock.instant().truncatedTo(ChronoUnit.DAYS);
|
||||
@@ -275,7 +274,7 @@ public class BackupAuthManagerTest {
|
||||
final List<BackupAuthManager.Credential> creds = authManager.getBackupAuthCredentials(
|
||||
account,
|
||||
BackupCredentialType.MESSAGES,
|
||||
range(RedemptionRange.MAX_REDEMPTION_DURATION)).join();
|
||||
range(RedemptionRange.MAX_REDEMPTION_DURATION));
|
||||
Instant redemptionTime = Instant.EPOCH;
|
||||
final BackupAuthCredentialRequestContext requestContext = BackupAuthCredentialRequestContext.create(
|
||||
messagesBackupKey, aci);
|
||||
@@ -311,15 +310,15 @@ public class BackupAuthManagerTest {
|
||||
.backupVoucher(null)
|
||||
.build();
|
||||
|
||||
when(accountsManager.updateAsync(any(), any())).thenReturn(CompletableFuture.completedFuture(updated));
|
||||
when(accountsManager.update(any(), any())).thenReturn(updated);
|
||||
|
||||
clock.pin(day2.plus(Duration.ofSeconds(1)));
|
||||
assertThat(authManager.getBackupAuthCredentials(account, BackupCredentialType.MESSAGES, range(Duration.ofDays(7))).join())
|
||||
assertThat(authManager.getBackupAuthCredentials(account, BackupCredentialType.MESSAGES, range(Duration.ofDays(7))))
|
||||
.hasSize(8);
|
||||
|
||||
@SuppressWarnings("unchecked") final ArgumentCaptor<Consumer<Account>> accountUpdater = ArgumentCaptor.forClass(
|
||||
Consumer.class);
|
||||
verify(accountsManager, times(1)).updateAsync(any(), accountUpdater.capture());
|
||||
verify(accountsManager, times(1)).update(any(), accountUpdater.capture());
|
||||
|
||||
// If the account is not expired when we go to update it, we shouldn't wipe it out
|
||||
final Account alreadyUpdated = mock(Account.class);
|
||||
@@ -343,11 +342,11 @@ public class BackupAuthManagerTest {
|
||||
.mediaCredential(Optional.of(new byte[0]))
|
||||
.build();
|
||||
clock.pin(Instant.EPOCH.plus(Duration.ofDays(1)));
|
||||
when(accountsManager.updateAsync(any(), any())).thenReturn(CompletableFuture.completedFuture(account));
|
||||
when(accountsManager.update(any(), any())).thenReturn(account);
|
||||
when(redeemedReceiptsManager.put(any(), eq(expirationTime.getEpochSecond()), eq(201L), eq(aci)))
|
||||
.thenReturn(CompletableFuture.completedFuture(true));
|
||||
authManager.redeemReceipt(account, receiptPresentation(201, expirationTime)).join();
|
||||
verify(accountsManager, times(1)).updateAsync(any(), any());
|
||||
authManager.redeemReceipt(account, receiptPresentation(201, expirationTime));
|
||||
verify(accountsManager, times(1)).update(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -361,7 +360,7 @@ public class BackupAuthManagerTest {
|
||||
.thenReturn(CompletableFuture.completedFuture(true));
|
||||
assertThatExceptionOfType(StatusRuntimeException.class)
|
||||
.isThrownBy(() ->
|
||||
authManager.redeemReceipt(account, receiptPresentation(201, expirationTime)).join())
|
||||
authManager.redeemReceipt(account, receiptPresentation(201, expirationTime)))
|
||||
.extracting(ex -> ex.getStatus().getCode())
|
||||
.isEqualTo(Status.Code.ABORTED);
|
||||
}
|
||||
@@ -379,13 +378,13 @@ public class BackupAuthManagerTest {
|
||||
.build();
|
||||
|
||||
clock.pin(Instant.EPOCH.plus(Duration.ofDays(1)));
|
||||
when(accountsManager.updateAsync(any(), any())).thenReturn(CompletableFuture.completedFuture(account));
|
||||
when(accountsManager.update(any(), any())).thenReturn(account);
|
||||
when(redeemedReceiptsManager.put(any(), eq(newExpirationTime.getEpochSecond()), eq(201L), eq(aci)))
|
||||
.thenReturn(CompletableFuture.completedFuture(true));
|
||||
authManager.redeemReceipt(account, receiptPresentation(201, newExpirationTime)).join();
|
||||
authManager.redeemReceipt(account, receiptPresentation(201, newExpirationTime));
|
||||
|
||||
final ArgumentCaptor<Consumer<Account>> updaterCaptor = ArgumentCaptor.captor();
|
||||
verify(accountsManager, times(1)).updateAsync(any(), updaterCaptor.capture());
|
||||
verify(accountsManager, times(1)).update(any(), updaterCaptor.capture());
|
||||
|
||||
updaterCaptor.getValue().accept(account);
|
||||
// Should select the voucher with the later expiration time
|
||||
@@ -398,7 +397,7 @@ public class BackupAuthManagerTest {
|
||||
clock.pin(expirationTime.plus(Duration.ofSeconds(1)));
|
||||
final BackupAuthManager authManager = create();
|
||||
assertThatExceptionOfType(StatusRuntimeException.class)
|
||||
.isThrownBy(() -> authManager.redeemReceipt(mock(Account.class), receiptPresentation(3, expirationTime)).join())
|
||||
.isThrownBy(() -> authManager.redeemReceipt(mock(Account.class), receiptPresentation(3, expirationTime)))
|
||||
.extracting(ex -> ex.getStatus().getCode())
|
||||
.isEqualTo(Status.Code.INVALID_ARGUMENT);
|
||||
verifyNoInteractions(accountsManager);
|
||||
@@ -413,7 +412,7 @@ public class BackupAuthManagerTest {
|
||||
final BackupAuthManager authManager = create();
|
||||
assertThatExceptionOfType(StatusRuntimeException.class)
|
||||
.isThrownBy(() ->
|
||||
authManager.redeemReceipt(mock(Account.class), receiptPresentation(level, expirationTime)).join())
|
||||
authManager.redeemReceipt(mock(Account.class), receiptPresentation(level, expirationTime)))
|
||||
.extracting(ex -> ex.getStatus().getCode())
|
||||
.isEqualTo(Status.Code.INVALID_ARGUMENT);
|
||||
verifyNoInteractions(accountsManager);
|
||||
@@ -425,7 +424,7 @@ public class BackupAuthManagerTest {
|
||||
final BackupAuthManager authManager = create();
|
||||
final ReceiptCredentialPresentation invalid = receiptPresentation(ServerSecretParams.generate(), 3L, Instant.EPOCH);
|
||||
assertThatExceptionOfType(StatusRuntimeException.class)
|
||||
.isThrownBy(() -> authManager.redeemReceipt(mock(Account.class), invalid).join())
|
||||
.isThrownBy(() -> authManager.redeemReceipt(mock(Account.class), invalid))
|
||||
.extracting(ex -> ex.getStatus().getCode())
|
||||
.isEqualTo(Status.Code.INVALID_ARGUMENT);
|
||||
verifyNoInteractions(accountsManager);
|
||||
@@ -433,7 +432,7 @@ public class BackupAuthManagerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void receiptAlreadyRedeemed() throws InvalidInputException, VerificationFailedException {
|
||||
void receiptAlreadyRedeemed() {
|
||||
final Instant expirationTime = Instant.EPOCH.plus(Duration.ofDays(1));
|
||||
final BackupAuthManager authManager = create();
|
||||
final Account account = new MockAccountBuilder()
|
||||
@@ -441,12 +440,12 @@ public class BackupAuthManagerTest {
|
||||
.build();
|
||||
|
||||
clock.pin(Instant.EPOCH.plus(Duration.ofDays(1)));
|
||||
when(accountsManager.updateAsync(any(), any())).thenReturn(CompletableFuture.completedFuture(account));
|
||||
when(accountsManager.update(any(), any())).thenReturn(account);
|
||||
when(redeemedReceiptsManager.put(any(), eq(expirationTime.getEpochSecond()), eq(201L), eq(aci)))
|
||||
.thenReturn(CompletableFuture.completedFuture(false));
|
||||
|
||||
final CompletableFuture<Void> result = authManager.redeemReceipt(account, receiptPresentation(201, expirationTime));
|
||||
assertThat(CompletableFutureTestUtil.assertFailsWithCause(StatusRuntimeException.class, result))
|
||||
assertThatExceptionOfType(StatusRuntimeException.class)
|
||||
.isThrownBy(() -> authManager.redeemReceipt(account, receiptPresentation(201, expirationTime)))
|
||||
.extracting(ex -> ex.getStatus().getCode())
|
||||
.isEqualTo(Status.Code.INVALID_ARGUMENT);
|
||||
verifyNoInteractions(accountsManager);
|
||||
@@ -484,8 +483,7 @@ public class BackupAuthManagerTest {
|
||||
? new Account.BackupVoucher(1, Instant.EPOCH.plus(Duration.ofSeconds(1)))
|
||||
: null)
|
||||
.build();
|
||||
final BackupAuthManager.BackupIdRotationLimit limit = authManager.checkBackupIdRotationLimit(account)
|
||||
.toCompletableFuture().join();
|
||||
final BackupAuthManager.BackupIdRotationLimit limit = authManager.checkBackupIdRotationLimit(account);
|
||||
final boolean expectHasPermits = !messageLimited && (!mediaLimited || !hasVoucher);
|
||||
final Duration expectedDuration = expectHasPermits ? Duration.ZERO : Duration.ofDays(1);
|
||||
assertThat(limit.hasPermitsRemaining()).isEqualTo(expectHasPermits);
|
||||
@@ -524,7 +522,7 @@ public class BackupAuthManagerTest {
|
||||
.backupVoucher(backupVoucher)
|
||||
.build();
|
||||
|
||||
when(accountsManager.updateAsync(any(), any())).thenReturn(CompletableFuture.completedFuture(account));
|
||||
when(accountsManager.update(any(), any())).thenReturn(account);
|
||||
|
||||
final Optional<BackupAuthCredentialRequest> newMessagesCredential = switch (messageChange) {
|
||||
case MATCH -> Optional.of(storedMessagesCredential);
|
||||
@@ -543,7 +541,7 @@ public class BackupAuthManagerTest {
|
||||
final boolean expectRateLimit = ((mediaChange == CredentialChangeType.MISMATCH) && rateLimitMediaBackupId && paid)
|
||||
|| ((messageChange == CredentialChangeType.MISMATCH) && rateLimitMessagesBackupId);
|
||||
final ThrowableAssert.ThrowingCallable commit = () ->
|
||||
authManager.commitBackupId(account, primaryDevice(), newMessagesCredential, newMediaCredential).join();
|
||||
authManager.commitBackupId(account, primaryDevice(), newMessagesCredential, newMediaCredential);
|
||||
|
||||
if (messageChange == CredentialChangeType.NO_UPDATE && mediaChange == CredentialChangeType.NO_UPDATE) {
|
||||
assertThatExceptionOfType(StatusRuntimeException.class)
|
||||
@@ -551,7 +549,7 @@ public class BackupAuthManagerTest {
|
||||
.extracting(ex -> ex.getStatus().getCode())
|
||||
.isEqualTo(Status.Code.INVALID_ARGUMENT);
|
||||
} else if (expectRateLimit) {
|
||||
assertThatException().isThrownBy(commit).withRootCauseInstanceOf(RateLimitExceededException.class);
|
||||
assertThatExceptionOfType(RateLimitExceededException.class).isThrownBy(commit);
|
||||
} else {
|
||||
assertThatNoException().isThrownBy(commit);
|
||||
}
|
||||
@@ -611,26 +609,29 @@ public class BackupAuthManagerTest {
|
||||
}
|
||||
|
||||
|
||||
private static RateLimiters rateLimiter(final UUID aci, boolean rateLimitBackupId,
|
||||
boolean rateLimitPaidMediaBackupId) {
|
||||
final RateLimiters limiters = mock(RateLimiters.class);
|
||||
private static RateLimiters rateLimiter(final UUID aci, boolean rateLimitBackupId, boolean rateLimitPaidMediaBackupId) {
|
||||
try {
|
||||
final RateLimiters limiters = mock(RateLimiters.class);
|
||||
|
||||
final RateLimiter allowLimiter = mock(RateLimiter.class);
|
||||
when(allowLimiter.hasAvailablePermitsAsync(eq(aci), anyLong())).thenReturn(CompletableFuture.completedFuture(true));
|
||||
when(allowLimiter.validateAsync(aci)).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(allowLimiter.config()).thenReturn(new RateLimiterConfig(1, Duration.ofDays(1), false));
|
||||
final RateLimiter allowLimiter = mock(RateLimiter.class);
|
||||
when(allowLimiter.hasAvailablePermitsAsync(eq(aci), anyLong())).thenReturn(
|
||||
CompletableFuture.completedFuture(true));
|
||||
when(allowLimiter.config()).thenReturn(new RateLimiterConfig(1, Duration.ofDays(1), false));
|
||||
|
||||
final RateLimiter denyLimiter = mock(RateLimiter.class);
|
||||
when(denyLimiter.hasAvailablePermitsAsync(eq(aci), anyLong())).thenReturn(CompletableFuture.completedFuture(false));
|
||||
when(denyLimiter.validateAsync(aci))
|
||||
.thenReturn(CompletableFuture.failedFuture(new RateLimitExceededException(null)));
|
||||
when(denyLimiter.config()).thenReturn(new RateLimiterConfig(1, Duration.ofDays(1), false));
|
||||
final RateLimiter denyLimiter = mock(RateLimiter.class);
|
||||
when(denyLimiter.hasAvailablePermitsAsync(eq(aci), anyLong())).thenReturn(
|
||||
CompletableFuture.completedFuture(false));
|
||||
doThrow(new RateLimitExceededException(null)).when(denyLimiter).validate(aci);
|
||||
when(denyLimiter.config()).thenReturn(new RateLimiterConfig(1, Duration.ofDays(1), false));
|
||||
|
||||
when(limiters.forDescriptor(RateLimiters.For.SET_BACKUP_ID))
|
||||
.thenReturn(rateLimitBackupId ? denyLimiter : allowLimiter);
|
||||
when(limiters.forDescriptor(RateLimiters.For.SET_PAID_MEDIA_BACKUP_ID))
|
||||
.thenReturn(rateLimitPaidMediaBackupId ? denyLimiter : allowLimiter);
|
||||
return limiters;
|
||||
when(limiters.forDescriptor(RateLimiters.For.SET_BACKUP_ID))
|
||||
.thenReturn(rateLimitBackupId ? denyLimiter : allowLimiter);
|
||||
when(limiters.forDescriptor(RateLimiters.For.SET_PAID_MEDIA_BACKUP_ID))
|
||||
.thenReturn(rateLimitPaidMediaBackupId ? denyLimiter : allowLimiter);
|
||||
return limiters;
|
||||
} catch (RateLimitExceededException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private RedemptionRange range(Duration length) {
|
||||
|
||||
@@ -76,6 +76,6 @@ public class BackupAuthTestUtil {
|
||||
});
|
||||
final RedemptionRange redemptionRange;
|
||||
redemptionRange = RedemptionRange.inclusive(clock, redemptionStart, redemptionEnd);
|
||||
return issuer.getBackupAuthCredentials(account, credentialType, redemptionRange).join();
|
||||
return issuer.getBackupAuthCredentials(account, credentialType, redemptionRange);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.times;
|
||||
@@ -230,11 +231,11 @@ public class BackupManagerTest {
|
||||
|
||||
final AuthenticatedBackupUser backupUser = backupUser(TestRandomUtil.nextBytes(16), BackupCredentialType.MESSAGES, backupLevel);
|
||||
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser).join();
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser);
|
||||
verify(tusCredentialGenerator, times(1))
|
||||
.generateUpload("%s/%s".formatted(backupUser.backupDir(), BackupManager.MESSAGE_BACKUP_NAME));
|
||||
|
||||
final BackupManager.BackupInfo info = backupManager.backupInfo(backupUser).join();
|
||||
final BackupManager.BackupInfo info = backupManager.backupInfo(backupUser);
|
||||
assertThat(info.backupSubdir()).isEqualTo(backupUser.backupDir()).isNotBlank();
|
||||
assertThat(info.messageBackupKey()).isEqualTo(BackupManager.MESSAGE_BACKUP_NAME);
|
||||
assertThat(info.mediaUsedSpace()).isEqualTo(Optional.empty());
|
||||
@@ -253,18 +254,17 @@ public class BackupManagerTest {
|
||||
final AuthenticatedBackupUser backupUser = backupUser(TestRandomUtil.nextBytes(16), BackupCredentialType.MEDIA, backupLevel);
|
||||
|
||||
assertThatExceptionOfType(StatusRuntimeException.class)
|
||||
.isThrownBy(() -> backupManager.createMessageBackupUploadDescriptor(backupUser).join())
|
||||
.isThrownBy(() -> backupManager.createMessageBackupUploadDescriptor(backupUser))
|
||||
.matches(exception -> exception.getStatus().getCode() == Status.UNAUTHENTICATED.getCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createTemporaryMediaAttachmentRateLimited() {
|
||||
public void createTemporaryMediaAttachmentRateLimited() throws RateLimitExceededException {
|
||||
final AuthenticatedBackupUser backupUser = backupUser(TestRandomUtil.nextBytes(16), BackupCredentialType.MEDIA, BackupLevel.PAID);
|
||||
when(mediaUploadLimiter.validateAsync(eq(BackupManager.rateLimitKey(backupUser))))
|
||||
.thenReturn(CompletableFuture.failedFuture(new RateLimitExceededException(null)));
|
||||
CompletableFutureTestUtil.assertFailsWithCause(
|
||||
RateLimitExceededException.class,
|
||||
backupManager.createTemporaryAttachmentUploadDescriptor(backupUser).toCompletableFuture());
|
||||
doThrow(new RateLimitExceededException(null))
|
||||
.when(mediaUploadLimiter).validate(eq(BackupManager.rateLimitKey(backupUser)));
|
||||
assertThatExceptionOfType(RateLimitExceededException.class)
|
||||
.isThrownBy(() -> backupManager.createTemporaryAttachmentUploadDescriptor(backupUser));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -297,11 +297,11 @@ public class BackupManagerTest {
|
||||
|
||||
// create backup at t=tstart
|
||||
testClock.pin(tstart);
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser).join();
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser);
|
||||
|
||||
// refresh at t=tnext
|
||||
testClock.pin(tnext);
|
||||
backupManager.ttlRefresh(backupUser).join();
|
||||
backupManager.ttlRefresh(backupUser);
|
||||
|
||||
checkExpectedExpirations(
|
||||
tnext.truncatedTo(ChronoUnit.DAYS),
|
||||
@@ -319,11 +319,11 @@ public class BackupManagerTest {
|
||||
|
||||
// create backup at t=tstart
|
||||
testClock.pin(tstart);
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser).join();
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser);
|
||||
|
||||
// create again at t=tnext
|
||||
testClock.pin(tnext);
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser).join();
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser);
|
||||
|
||||
checkExpectedExpirations(
|
||||
tnext.truncatedTo(ChronoUnit.DAYS),
|
||||
@@ -363,7 +363,7 @@ public class BackupManagerTest {
|
||||
backupManager.setPublicKey(
|
||||
presentation,
|
||||
keyPair.getPrivateKey().calculateSignature(presentation.serialize()),
|
||||
keyPair.getPublicKey()).join();
|
||||
keyPair.getPublicKey());
|
||||
|
||||
assertThatExceptionOfType(StatusRuntimeException.class)
|
||||
.isThrownBy(() -> backupManager.authenticateBackupUser(
|
||||
@@ -384,10 +384,10 @@ public class BackupManagerTest {
|
||||
final byte[] signature = keyPair.getPrivateKey().calculateSignature(presentation.serialize());
|
||||
|
||||
// haven't set a public key yet
|
||||
assertThat(CompletableFutureTestUtil.assertFailsWithCause(
|
||||
StatusRuntimeException.class,
|
||||
backupManager.authenticateBackupUser(presentation, signature, null))
|
||||
.getStatus().getCode())
|
||||
assertThatExceptionOfType(StatusRuntimeException.class)
|
||||
.isThrownBy(() -> backupManager.authenticateBackupUser(presentation, signature, null))
|
||||
.extracting(StatusRuntimeException::getStatus)
|
||||
.extracting(Status::getCode)
|
||||
.isEqualTo(Status.UNAUTHENTICATED.getCode());
|
||||
}
|
||||
|
||||
@@ -401,17 +401,17 @@ public class BackupManagerTest {
|
||||
final byte[] signature1 = keyPair1.getPrivateKey().calculateSignature(presentation.serialize());
|
||||
final byte[] signature2 = keyPair2.getPrivateKey().calculateSignature(presentation.serialize());
|
||||
|
||||
backupManager.setPublicKey(presentation, signature1, keyPair1.getPublicKey()).join();
|
||||
backupManager.setPublicKey(presentation, signature1, keyPair1.getPublicKey());
|
||||
|
||||
// shouldn't be able to set a different public key
|
||||
assertThat(CompletableFutureTestUtil.assertFailsWithCause(
|
||||
StatusRuntimeException.class,
|
||||
assertThatExceptionOfType(StatusRuntimeException.class).isThrownBy(() ->
|
||||
backupManager.setPublicKey(presentation, signature2, keyPair2.getPublicKey()))
|
||||
.getStatus().getCode())
|
||||
.extracting(StatusRuntimeException::getStatus)
|
||||
.extracting(Status::getCode)
|
||||
.isEqualTo(Status.UNAUTHENTICATED.getCode());
|
||||
|
||||
// should be able to set the same public key again (noop)
|
||||
backupManager.setPublicKey(presentation, signature1, keyPair1.getPublicKey()).join();
|
||||
backupManager.setPublicKey(presentation, signature1, keyPair1.getPublicKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -432,17 +432,17 @@ public class BackupManagerTest {
|
||||
.extracting(ex -> ex.getStatus().getCode())
|
||||
.isEqualTo(Status.UNAUTHENTICATED.getCode());
|
||||
|
||||
backupManager.setPublicKey(presentation, signature, keyPair.getPublicKey()).join();
|
||||
backupManager.setPublicKey(presentation, signature, keyPair.getPublicKey());
|
||||
|
||||
// shouldn't be able to authenticate with an invalid signature
|
||||
assertThat(CompletableFutureTestUtil.assertFailsWithCause(
|
||||
StatusRuntimeException.class,
|
||||
backupManager.authenticateBackupUser(presentation, wrongSignature, null))
|
||||
.getStatus().getCode())
|
||||
assertThatExceptionOfType(StatusRuntimeException.class)
|
||||
.isThrownBy(() -> backupManager.authenticateBackupUser(presentation, wrongSignature, null))
|
||||
.extracting(StatusRuntimeException::getStatus)
|
||||
.extracting(Status::getCode)
|
||||
.isEqualTo(Status.UNAUTHENTICATED.getCode());
|
||||
|
||||
// correct signature
|
||||
final AuthenticatedBackupUser user = backupManager.authenticateBackupUser(presentation, signature, null).join();
|
||||
final AuthenticatedBackupUser user = backupManager.authenticateBackupUser(presentation, signature, null);
|
||||
assertThat(user.backupId()).isEqualTo(presentation.getBackupId());
|
||||
assertThat(user.backupLevel()).isEqualTo(BackupLevel.FREE);
|
||||
}
|
||||
@@ -456,15 +456,15 @@ public class BackupManagerTest {
|
||||
backupKey, aci);
|
||||
final ECKeyPair keyPair = ECKeyPair.generate();
|
||||
final byte[] signature = keyPair.getPrivateKey().calculateSignature(oldCredential.serialize());
|
||||
backupManager.setPublicKey(oldCredential, signature, keyPair.getPublicKey()).join();
|
||||
backupManager.setPublicKey(oldCredential, signature, keyPair.getPublicKey());
|
||||
|
||||
// should be accepted the day before to forgive clock skew
|
||||
testClock.pin(Instant.ofEpochSecond(1));
|
||||
assertThatNoException().isThrownBy(() -> backupManager.authenticateBackupUser(oldCredential, signature, null).join());
|
||||
assertThatNoException().isThrownBy(() -> backupManager.authenticateBackupUser(oldCredential, signature, null));
|
||||
|
||||
// should be accepted the day after to forgive clock skew
|
||||
testClock.pin(Instant.ofEpochSecond(1).plus(Duration.ofDays(2)));
|
||||
assertThatNoException().isThrownBy(() -> backupManager.authenticateBackupUser(oldCredential, signature, null).join());
|
||||
assertThatNoException().isThrownBy(() -> backupManager.authenticateBackupUser(oldCredential, signature, null));
|
||||
|
||||
// should be rejected the day after that
|
||||
testClock.pin(Instant.ofEpochSecond(1).plus(Duration.ofDays(3)));
|
||||
@@ -713,8 +713,7 @@ public class BackupManagerTest {
|
||||
Optional.of("newCursor")
|
||||
)));
|
||||
|
||||
final BackupManager.ListMediaResult result = backupManager.list(backupUser, cursor, 17)
|
||||
.toCompletableFuture().join();
|
||||
final BackupManager.ListMediaResult result = backupManager.list(backupUser, cursor, 17);
|
||||
assertThat(result.media()).hasSize(1);
|
||||
assertThat(result.media().getFirst().cdn()).isEqualTo(13);
|
||||
assertThat(result.media().getFirst().key()).isEqualTo(
|
||||
@@ -733,7 +732,7 @@ public class BackupManagerTest {
|
||||
when(svrbClient.removeData(anyString())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
|
||||
// Deleting should swap the backupDir for the user
|
||||
backupManager.deleteEntireBackup(original).join();
|
||||
backupManager.deleteEntireBackup(original);
|
||||
verifyNoInteractions(remoteStorageManager);
|
||||
verify(svrbClient).removeData(HexFormat.of().formatHex(BackupsDb.hashedBackupId(original.backupId())));
|
||||
|
||||
@@ -747,7 +746,7 @@ public class BackupManagerTest {
|
||||
Collections.emptyList(),
|
||||
Optional.empty()
|
||||
)));
|
||||
backupManager.deleteEntireBackup(after).join();
|
||||
backupManager.deleteEntireBackup(after);
|
||||
verify(remoteStorageManager, times(1))
|
||||
.list(eq(after.backupDir() + "/"), eq(Optional.empty()), anyLong());
|
||||
|
||||
@@ -914,7 +913,7 @@ public class BackupManagerTest {
|
||||
.toList();
|
||||
for (int i = 0; i < backupUsers.size(); i++) {
|
||||
testClock.pin(days(i));
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUsers.get(i)).join();
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUsers.get(i));
|
||||
}
|
||||
|
||||
// set of backup-id hashes that should be expired (initially t=0)
|
||||
@@ -949,11 +948,11 @@ public class BackupManagerTest {
|
||||
|
||||
// refreshed media timestamp at t=5
|
||||
testClock.pin(days(5));
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser(backupId, BackupCredentialType.MESSAGES, BackupLevel.PAID)).join();
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser(backupId, BackupCredentialType.MESSAGES, BackupLevel.PAID));
|
||||
|
||||
// refreshed messages timestamp at t=6
|
||||
testClock.pin(days(6));
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser(backupId, BackupCredentialType.MESSAGES, BackupLevel.FREE)).join();
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser(backupId, BackupCredentialType.MESSAGES, BackupLevel.FREE));
|
||||
|
||||
Function<Instant, List<ExpiredBackup>> getExpired = time -> backupManager
|
||||
.getExpiredBackups(1, Schedulers.immediate(), time)
|
||||
@@ -974,7 +973,7 @@ public class BackupManagerTest {
|
||||
@EnumSource(mode = EnumSource.Mode.INCLUDE, names = {"MEDIA", "ALL"})
|
||||
public void expireBackup(ExpiredBackup.ExpirationType expirationType) {
|
||||
final AuthenticatedBackupUser backupUser = backupUser(TestRandomUtil.nextBytes(16), BackupCredentialType.MESSAGES, BackupLevel.PAID);
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser).join();
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser);
|
||||
|
||||
final String expectedPrefixToDelete = switch (expirationType) {
|
||||
case ALL -> backupUser.backupDir();
|
||||
@@ -1020,7 +1019,7 @@ public class BackupManagerTest {
|
||||
@Test
|
||||
public void deleteBackupPaginated() {
|
||||
final AuthenticatedBackupUser backupUser = backupUser(TestRandomUtil.nextBytes(16), BackupCredentialType.MESSAGES, BackupLevel.PAID);
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser).join();
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser);
|
||||
|
||||
final ExpiredBackup expiredBackup = expiredBackup(ExpiredBackup.ExpirationType.MEDIA, backupUser);
|
||||
final String mediaPrefix = expiredBackup.prefixToDelete() + "/";
|
||||
|
||||
@@ -8,6 +8,7 @@ package org.whispersystems.textsecuregcm.controllers;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -111,8 +112,8 @@ public class ArchiveControllerTest {
|
||||
reset(backupAuthManager);
|
||||
reset(backupManager);
|
||||
|
||||
when(accountsManager.getByAccountIdentifierAsync(AuthHelper.VALID_UUID))
|
||||
.thenReturn(CompletableFuture.completedFuture(Optional.of(AuthHelper.VALID_ACCOUNT)));
|
||||
when(accountsManager.getByAccountIdentifier(AuthHelper.VALID_UUID))
|
||||
.thenReturn(Optional.of(AuthHelper.VALID_ACCOUNT));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@@ -164,9 +165,7 @@ public class ArchiveControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setBackupId() {
|
||||
when(backupAuthManager.commitBackupId(any(), any(), any(), any())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
|
||||
public void setBackupId() throws RateLimitExceededException {
|
||||
final Response response = resources.getJerseyTest()
|
||||
.target("v1/archives/backupid")
|
||||
.request()
|
||||
@@ -184,9 +183,7 @@ public class ArchiveControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setBackupIdPartial() {
|
||||
when(backupAuthManager.commitBackupId(any(), any(), any(), any())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
|
||||
public void setBackupIdPartial() throws RateLimitExceededException {
|
||||
final Response response = resources.getJerseyTest()
|
||||
.target("v1/archives/backupid")
|
||||
.request()
|
||||
@@ -210,8 +207,7 @@ public class ArchiveControllerTest {
|
||||
})
|
||||
public void backupIdLimits(boolean hasPermits, long waitSeconds) {
|
||||
when(backupAuthManager.checkBackupIdRotationLimit(any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(
|
||||
new BackupAuthManager.BackupIdRotationLimit(hasPermits, Duration.ofSeconds(waitSeconds))));
|
||||
.thenReturn(new BackupAuthManager.BackupIdRotationLimit(hasPermits, Duration.ofSeconds(waitSeconds)));
|
||||
|
||||
final ArchiveController.BackupIdLimitResponse response = resources.getJerseyTest()
|
||||
.target("v1/archives/backupid/limits")
|
||||
@@ -233,7 +229,6 @@ public class ArchiveControllerTest {
|
||||
final ReceiptCredentialResponse rcr = serverOps.issueReceiptCredential(rcrc.getRequest(), 0L, 3L);
|
||||
final ReceiptCredential receiptCredential = clientOps.receiveReceiptCredential(rcrc, rcr);
|
||||
final ReceiptCredentialPresentation presentation = clientOps.createReceiptCredentialPresentation(receiptCredential);
|
||||
when(backupAuthManager.redeemReceipt(any(), any())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
|
||||
final Response response = resources.getJerseyTest()
|
||||
.target("v1/archives/redeem-receipt")
|
||||
@@ -248,8 +243,6 @@ public class ArchiveControllerTest {
|
||||
|
||||
@Test
|
||||
public void setBadPublicKey() throws VerificationFailedException {
|
||||
when(backupManager.setPublicKey(any(), any(), any())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
|
||||
final BackupAuthCredentialPresentation presentation = backupAuthTestUtil.getPresentation(
|
||||
BackupLevel.PAID, messagesBackupKey, aci);
|
||||
final Response response = resources.getJerseyTest()
|
||||
@@ -265,8 +258,6 @@ public class ArchiveControllerTest {
|
||||
|
||||
@Test
|
||||
public void setMissingPublicKey() throws VerificationFailedException {
|
||||
when(backupManager.setPublicKey(any(), any(), any())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
|
||||
final BackupAuthCredentialPresentation presentation = backupAuthTestUtil.getPresentation(
|
||||
BackupLevel.PAID, messagesBackupKey, aci);
|
||||
final Response response = resources.getJerseyTest()
|
||||
@@ -280,8 +271,6 @@ public class ArchiveControllerTest {
|
||||
|
||||
@Test
|
||||
public void setPublicKey() throws VerificationFailedException {
|
||||
when(backupManager.setPublicKey(any(), any(), any())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
|
||||
final BackupAuthCredentialPresentation presentation = backupAuthTestUtil.getPresentation(
|
||||
BackupLevel.PAID, messagesBackupKey, aci);
|
||||
final Response response = resources.getJerseyTest()
|
||||
@@ -312,20 +301,15 @@ public class ArchiveControllerTest {
|
||||
|
||||
public static Stream<Arguments> setBackupIdException() {
|
||||
return Stream.of(
|
||||
Arguments.of(new RateLimitExceededException(null), false, 429),
|
||||
Arguments.of(Status.INVALID_ARGUMENT.withDescription("async").asRuntimeException(), false, 400),
|
||||
Arguments.of(Status.INVALID_ARGUMENT.withDescription("sync").asRuntimeException(), true, 400)
|
||||
Arguments.of(new RateLimitExceededException(null), 429),
|
||||
Arguments.of(Status.INVALID_ARGUMENT.withDescription("test").asRuntimeException(), 400)
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource
|
||||
public void setBackupIdException(final Exception ex, final boolean sync, final int expectedStatus) {
|
||||
if (sync) {
|
||||
when(backupAuthManager.commitBackupId(any(), any(), any(), any())).thenThrow(ex);
|
||||
} else {
|
||||
when(backupAuthManager.commitBackupId(any(), any(), any(), any())).thenReturn(CompletableFuture.failedFuture(ex));
|
||||
}
|
||||
public void setBackupIdException(final Exception ex, final int expectedStatus) throws RateLimitExceededException {
|
||||
doThrow(ex).when(backupAuthManager).commitBackupId(any(), any(), any(), any());
|
||||
final Response response = resources.getJerseyTest()
|
||||
.target("v1/archives/backupid")
|
||||
.request()
|
||||
@@ -349,7 +333,7 @@ public class ArchiveControllerTest {
|
||||
|
||||
expectedCredentialsByType.forEach((credentialType, expectedCredentials) ->
|
||||
when(backupAuthManager.getBackupAuthCredentials(any(), eq(credentialType), eq(expectedRange)))
|
||||
.thenReturn(CompletableFuture.completedFuture(expectedCredentials)));
|
||||
.thenReturn(expectedCredentials));
|
||||
|
||||
final ArchiveController.BackupAuthCredentialsResponse credentialResponse = resources.getJerseyTest()
|
||||
.target("v1/archives/auth")
|
||||
@@ -405,9 +389,9 @@ public class ArchiveControllerTest {
|
||||
final BackupAuthCredentialPresentation presentation = backupAuthTestUtil.getPresentation(
|
||||
BackupLevel.PAID, messagesBackupKey, aci);
|
||||
when(backupManager.authenticateBackupUser(any(), any(), any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(backupUser(presentation.getBackupId(), BackupCredentialType.MESSAGES, BackupLevel.PAID)));
|
||||
when(backupManager.backupInfo(any())).thenReturn(CompletableFuture.completedFuture(new BackupManager.BackupInfo(
|
||||
1, "myBackupDir", "myMediaDir", "filename", Optional.empty())));
|
||||
.thenReturn(backupUser(presentation.getBackupId(), BackupCredentialType.MESSAGES, BackupLevel.PAID));
|
||||
when(backupManager.backupInfo(any()))
|
||||
.thenReturn(new BackupManager.BackupInfo(1, "myBackupDir", "myMediaDir", "filename", Optional.empty()));
|
||||
final ArchiveController.BackupInfoResponse response = resources.getJerseyTest()
|
||||
.target("v1/archives")
|
||||
.request()
|
||||
@@ -425,7 +409,7 @@ public class ArchiveControllerTest {
|
||||
final BackupAuthCredentialPresentation presentation = backupAuthTestUtil.getPresentation(
|
||||
BackupLevel.PAID, messagesBackupKey, aci);
|
||||
when(backupManager.authenticateBackupUser(any(), any(), any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(backupUser(presentation.getBackupId(), BackupCredentialType.MESSAGES, BackupLevel.PAID)));
|
||||
.thenReturn(backupUser(presentation.getBackupId(), BackupCredentialType.MESSAGES, BackupLevel.PAID));
|
||||
final byte[][] mediaIds = new byte[][]{TestRandomUtil.nextBytes(15), TestRandomUtil.nextBytes(15)};
|
||||
when(backupManager.copyToBackup(any(), any()))
|
||||
.thenReturn(Flux.just(
|
||||
@@ -470,7 +454,7 @@ public class ArchiveControllerTest {
|
||||
final BackupAuthCredentialPresentation presentation = backupAuthTestUtil.getPresentation(
|
||||
BackupLevel.PAID, messagesBackupKey, aci);
|
||||
when(backupManager.authenticateBackupUser(any(), any(), any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(backupUser(presentation.getBackupId(), BackupCredentialType.MESSAGES, BackupLevel.PAID)));
|
||||
.thenReturn(backupUser(presentation.getBackupId(), BackupCredentialType.MESSAGES, BackupLevel.PAID));
|
||||
|
||||
final byte[][] mediaIds = IntStream.range(0, 4).mapToObj(i -> TestRandomUtil.nextBytes(15)).toArray(byte[][]::new);
|
||||
when(backupManager.copyToBackup(any(), any()))
|
||||
@@ -528,7 +512,7 @@ public class ArchiveControllerTest {
|
||||
final BackupAuthCredentialPresentation presentation = backupAuthTestUtil.getPresentation(
|
||||
BackupLevel.PAID, messagesBackupKey, aci);
|
||||
when(backupManager.authenticateBackupUser(any(), any(), any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(backupUser(presentation.getBackupId(), BackupCredentialType.MESSAGES, BackupLevel.PAID)));
|
||||
.thenReturn(backupUser(presentation.getBackupId(), BackupCredentialType.MESSAGES, BackupLevel.PAID));
|
||||
final byte[][] mediaIds = new byte[][]{TestRandomUtil.nextBytes(15), TestRandomUtil.nextBytes(15)};
|
||||
final Response r = resources.getJerseyTest()
|
||||
.target("v1/archives/media/batch")
|
||||
@@ -561,17 +545,17 @@ public class ArchiveControllerTest {
|
||||
final BackupAuthCredentialPresentation presentation = backupAuthTestUtil.getPresentation(
|
||||
BackupLevel.PAID, messagesBackupKey, aci);
|
||||
when(backupManager.authenticateBackupUser(any(), any(), any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(backupUser(presentation.getBackupId(), BackupCredentialType.MESSAGES, BackupLevel.PAID)));
|
||||
.thenReturn(backupUser(presentation.getBackupId(), BackupCredentialType.MESSAGES, BackupLevel.PAID));
|
||||
|
||||
final byte[] mediaId = TestRandomUtil.nextBytes(15);
|
||||
final Optional<String> expectedCursor = cursorProvided ? Optional.of("myCursor") : Optional.empty();
|
||||
final Optional<String> returnedCursor = cursorReturned ? Optional.of("newCursor") : Optional.empty();
|
||||
|
||||
when(backupManager.list(any(), eq(expectedCursor), eq(17)))
|
||||
.thenReturn(CompletableFuture.completedFuture(new BackupManager.ListMediaResult(
|
||||
.thenReturn(new BackupManager.ListMediaResult(
|
||||
List.of(new BackupManager.StorageDescriptorWithLength(1, mediaId, 100)),
|
||||
returnedCursor
|
||||
)));
|
||||
));
|
||||
|
||||
WebTarget target = resources.getJerseyTest()
|
||||
.target("v1/archives/media/")
|
||||
@@ -596,7 +580,7 @@ public class ArchiveControllerTest {
|
||||
final BackupAuthCredentialPresentation presentation = backupAuthTestUtil.getPresentation(BackupLevel.PAID,
|
||||
messagesBackupKey, aci);
|
||||
when(backupManager.authenticateBackupUser(any(), any(), any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(backupUser(presentation.getBackupId(), BackupCredentialType.MESSAGES, BackupLevel.PAID)));
|
||||
.thenReturn(backupUser(presentation.getBackupId(), BackupCredentialType.MESSAGES, BackupLevel.PAID));
|
||||
|
||||
final ArchiveController.DeleteMedia deleteRequest = new ArchiveController.DeleteMedia(
|
||||
IntStream
|
||||
@@ -632,10 +616,9 @@ public class ArchiveControllerTest {
|
||||
final BackupAuthCredentialPresentation presentation =
|
||||
backupAuthTestUtil.getPresentation(BackupLevel.PAID, messagesBackupKey, aci);
|
||||
when(backupManager.authenticateBackupUser(any(), any(), any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(backupUser(presentation.getBackupId(), BackupCredentialType.MESSAGES, BackupLevel.PAID)));
|
||||
.thenReturn(backupUser(presentation.getBackupId(), BackupCredentialType.MESSAGES, BackupLevel.PAID));
|
||||
when(backupManager.createMessageBackupUploadDescriptor(any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(
|
||||
new BackupUploadDescriptor(3, "abc", Map.of("k", "v"), "example.org")));
|
||||
.thenReturn(new BackupUploadDescriptor(3, "abc", Map.of("k", "v"), "example.org"));
|
||||
|
||||
final WebTarget builder = resources.getJerseyTest().target("v1/archives/upload/form");
|
||||
final Response response = uploadLength
|
||||
@@ -658,14 +641,13 @@ public class ArchiveControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mediaUploadForm() throws VerificationFailedException {
|
||||
public void mediaUploadForm() throws VerificationFailedException, RateLimitExceededException {
|
||||
final BackupAuthCredentialPresentation presentation =
|
||||
backupAuthTestUtil.getPresentation(BackupLevel.PAID, messagesBackupKey, aci);
|
||||
when(backupManager.authenticateBackupUser(any(), any(), any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(backupUser(presentation.getBackupId(), BackupCredentialType.MESSAGES, BackupLevel.PAID)));
|
||||
.thenReturn(backupUser(presentation.getBackupId(), BackupCredentialType.MESSAGES, BackupLevel.PAID));
|
||||
when(backupManager.createTemporaryAttachmentUploadDescriptor(any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(
|
||||
new BackupUploadDescriptor(3, "abc", Map.of("k", "v"), "example.org")));
|
||||
.thenReturn(new BackupUploadDescriptor(3, "abc", Map.of("k", "v"), "example.org"));
|
||||
final ArchiveController.UploadDescriptorResponse desc = resources.getJerseyTest()
|
||||
.target("v1/archives/media/upload/form")
|
||||
.request()
|
||||
@@ -678,8 +660,7 @@ public class ArchiveControllerTest {
|
||||
assertThat(desc.signedUploadLocation()).isEqualTo("example.org");
|
||||
|
||||
// rate limit
|
||||
when(backupManager.createTemporaryAttachmentUploadDescriptor(any()))
|
||||
.thenReturn(CompletableFuture.failedFuture(new RateLimitExceededException(null)));
|
||||
when(backupManager.createTemporaryAttachmentUploadDescriptor(any())).thenThrow(new RateLimitExceededException(null));
|
||||
final Response response = resources.getJerseyTest()
|
||||
.target("v1/archives/media/upload/form")
|
||||
.request()
|
||||
@@ -694,7 +675,7 @@ public class ArchiveControllerTest {
|
||||
final BackupAuthCredentialPresentation presentation =
|
||||
backupAuthTestUtil.getPresentation(BackupLevel.PAID, messagesBackupKey, aci);
|
||||
when(backupManager.authenticateBackupUser(any(), any(), any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(backupUser(presentation.getBackupId(), BackupCredentialType.MESSAGES, BackupLevel.PAID)));
|
||||
.thenReturn(backupUser(presentation.getBackupId(), BackupCredentialType.MESSAGES, BackupLevel.PAID));
|
||||
when(backupManager.generateReadAuth(any(), eq(3))).thenReturn(Map.of("key", "value"));
|
||||
final ArchiveController.ReadAuthResponse response = resources.getJerseyTest()
|
||||
.target("v1/archives/auth/read")
|
||||
@@ -712,7 +693,7 @@ public class ArchiveControllerTest {
|
||||
final BackupAuthCredentialPresentation presentation =
|
||||
backupAuthTestUtil.getPresentation(BackupLevel.PAID, messagesBackupKey, aci);
|
||||
when(backupManager.authenticateBackupUser(any(), any(), any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(backupUser(presentation.getBackupId(), BackupCredentialType.MESSAGES, BackupLevel.PAID)));
|
||||
.thenReturn(backupUser(presentation.getBackupId(), BackupCredentialType.MESSAGES, BackupLevel.PAID));
|
||||
final ExternalServiceCredentials credentials = new ExternalServiceCredentials("username", "password");
|
||||
when(backupManager.generateSvrbAuth(any())).thenReturn(credentials);
|
||||
final ExternalServiceCredentials response = resources.getJerseyTest()
|
||||
@@ -751,8 +732,7 @@ public class ArchiveControllerTest {
|
||||
final BackupAuthCredentialPresentation presentation =
|
||||
backupAuthTestUtil.getPresentation(BackupLevel.PAID, messagesBackupKey, aci);
|
||||
when(backupManager.authenticateBackupUser(any(), any(), any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(backupUser(presentation.getBackupId(), BackupCredentialType.MESSAGES, BackupLevel.PAID)));
|
||||
when(backupManager.deleteEntireBackup(any())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
.thenReturn(backupUser(presentation.getBackupId(), BackupCredentialType.MESSAGES, BackupLevel.PAID));
|
||||
Response response = resources.getJerseyTest()
|
||||
.target("v1/archives/")
|
||||
.request()
|
||||
@@ -767,7 +747,7 @@ public class ArchiveControllerTest {
|
||||
final BackupAuthCredentialPresentation presentation = backupAuthTestUtil.getPresentation(
|
||||
BackupLevel.PAID, messagesBackupKey, aci);
|
||||
when(backupManager.authenticateBackupUser(any(), any(), any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(backupUser(presentation.getBackupId(), BackupCredentialType.MESSAGES, BackupLevel.PAID)));
|
||||
.thenReturn(backupUser(presentation.getBackupId(), BackupCredentialType.MESSAGES, BackupLevel.PAID));
|
||||
final Response r = resources.getJerseyTest()
|
||||
.target("v1/archives/media")
|
||||
.request()
|
||||
|
||||
@@ -29,7 +29,6 @@ import java.util.Base64;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import org.glassfish.jersey.server.ServerProperties;
|
||||
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -45,7 +44,6 @@ import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||
import org.whispersystems.textsecuregcm.mappers.CompletionExceptionMapper;
|
||||
import org.whispersystems.textsecuregcm.mappers.GrpcStatusRuntimeExceptionMapper;
|
||||
import org.whispersystems.textsecuregcm.mappers.RateLimitExceededExceptionMapper;
|
||||
import org.whispersystems.textsecuregcm.storage.Account;
|
||||
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||
import org.whispersystems.textsecuregcm.storage.devicecheck.AppleDeviceCheckManager;
|
||||
import org.whispersystems.textsecuregcm.storage.devicecheck.ChallengeNotFoundException;
|
||||
@@ -206,11 +204,6 @@ class DeviceCheckControllerTest {
|
||||
{"action": "backup", "challenge": "embeddedChallenge"}
|
||||
""";
|
||||
|
||||
when(backupAuthManager.extendBackupVoucher(any(), eq(new Account.BackupVoucher(
|
||||
REDEMPTION_LEVEL,
|
||||
clock.instant().plus(REDEMPTION_DURATION)))))
|
||||
.thenReturn(CompletableFuture.completedFuture(null));
|
||||
|
||||
final Response response = resources.getJerseyTest()
|
||||
.target("v1/devicecheck/assert")
|
||||
.queryParam("keyId", Base64.getUrlEncoder().encodeToString(keyId))
|
||||
|
||||
@@ -90,14 +90,13 @@ class BackupsAnonymousGrpcServiceTest extends
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
when(backupManager.authenticateBackupUser(any(), any(), any()))
|
||||
when(backupManager.authenticateBackupUserAsync(any(), any(), any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(
|
||||
backupUser(presentation.getBackupId(), BackupCredentialType.MESSAGES, BackupLevel.PAID)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void setPublicKey() {
|
||||
when(backupManager.setPublicKey(any(), any(), any())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
assertThatNoException().isThrownBy(() -> unauthenticatedServiceStub().setPublicKey(SetPublicKeyRequest.newBuilder()
|
||||
.setPublicKey(ByteString.copyFrom(ECKeyPair.generate().getPublicKey().serialize()))
|
||||
.setSignedPresentation(signedPresentation(presentation))
|
||||
@@ -106,7 +105,6 @@ class BackupsAnonymousGrpcServiceTest extends
|
||||
|
||||
@Test
|
||||
void setBadPublicKey() {
|
||||
when(backupManager.setPublicKey(any(), any(), any())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
assertThatExceptionOfType(StatusRuntimeException.class).isThrownBy(() ->
|
||||
unauthenticatedServiceStub().setPublicKey(SetPublicKeyRequest.newBuilder()
|
||||
.setPublicKey(ByteString.copyFromUtf8("aaaaa")) // Invalid public key
|
||||
@@ -214,8 +212,8 @@ class BackupsAnonymousGrpcServiceTest extends
|
||||
|
||||
@Test
|
||||
void getBackupInfo() {
|
||||
when(backupManager.backupInfo(any())).thenReturn(CompletableFuture.completedFuture(new BackupManager.BackupInfo(
|
||||
1, "myBackupDir", "myMediaDir", "filename", Optional.empty())));
|
||||
when(backupManager.backupInfo(any()))
|
||||
.thenReturn(new BackupManager.BackupInfo(1, "myBackupDir", "myMediaDir", "filename", Optional.empty()));
|
||||
|
||||
final GetBackupInfoResponse response = unauthenticatedServiceStub().getBackupInfo(GetBackupInfoRequest.newBuilder()
|
||||
.setSignedPresentation(signedPresentation(presentation))
|
||||
@@ -240,9 +238,9 @@ class BackupsAnonymousGrpcServiceTest extends
|
||||
final int limit = 17;
|
||||
|
||||
when(backupManager.list(any(), eq(expectedCursor), eq(limit)))
|
||||
.thenReturn(CompletableFuture.completedFuture(new BackupManager.ListMediaResult(
|
||||
.thenReturn(new BackupManager.ListMediaResult(
|
||||
List.of(new BackupManager.StorageDescriptorWithLength(1, mediaId, 100)),
|
||||
returnedCursor)));
|
||||
returnedCursor));
|
||||
|
||||
final ListMediaRequest.Builder request = ListMediaRequest.newBuilder()
|
||||
.setSignedPresentation(signedPresentation(presentation))
|
||||
@@ -280,10 +278,9 @@ class BackupsAnonymousGrpcServiceTest extends
|
||||
}
|
||||
|
||||
@Test
|
||||
void mediaUploadForm() {
|
||||
void mediaUploadForm() throws RateLimitExceededException {
|
||||
when(backupManager.createTemporaryAttachmentUploadDescriptor(any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(
|
||||
new BackupUploadDescriptor(3, "abc", Map.of("k", "v"), "example.org")));
|
||||
.thenReturn(new BackupUploadDescriptor(3, "abc", Map.of("k", "v"), "example.org"));
|
||||
final GetUploadFormRequest request = GetUploadFormRequest.newBuilder()
|
||||
.setMedia(GetUploadFormRequest.MediaUploadType.getDefaultInstance())
|
||||
.setSignedPresentation(signedPresentation(presentation))
|
||||
@@ -298,7 +295,7 @@ class BackupsAnonymousGrpcServiceTest extends
|
||||
// rate limit
|
||||
Duration duration = Duration.ofSeconds(10);
|
||||
when(backupManager.createTemporaryAttachmentUploadDescriptor(any()))
|
||||
.thenReturn(CompletableFuture.failedFuture(new RateLimitExceededException(duration)));
|
||||
.thenThrow(new RateLimitExceededException(duration));
|
||||
GrpcTestUtils.assertRateLimitExceeded(duration, () -> unauthenticatedServiceStub().getUploadForm(request));
|
||||
}
|
||||
|
||||
@@ -314,8 +311,7 @@ class BackupsAnonymousGrpcServiceTest extends
|
||||
@MethodSource
|
||||
public void messagesUploadForm(Optional<Long> uploadLength, boolean expectSuccess) {
|
||||
when(backupManager.createMessageBackupUploadDescriptor(any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(
|
||||
new BackupUploadDescriptor(3, "abc", Map.of("k", "v"), "example.org")));
|
||||
.thenReturn(new BackupUploadDescriptor(3, "abc", Map.of("k", "v"), "example.org"));
|
||||
final GetUploadFormRequest.MessagesUploadType.Builder builder = GetUploadFormRequest.MessagesUploadType.newBuilder();
|
||||
uploadLength.ifPresent(builder::setUploadLength);
|
||||
final GetUploadFormRequest request = GetUploadFormRequest.newBuilder()
|
||||
|
||||
@@ -8,6 +8,7 @@ package org.whispersystems.textsecuregcm.grpc;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
@@ -90,15 +91,14 @@ class BackupsGrpcServiceTest extends SimpleBaseGrpcTest<BackupsGrpcService, Back
|
||||
when(device.isPrimary()).thenReturn(true);
|
||||
when(accountsManager.getByAccountIdentifierAsync(AUTHENTICATED_ACI))
|
||||
.thenReturn(CompletableFuture.completedFuture(Optional.of(account)));
|
||||
when(accountsManager.getByAccountIdentifier(AUTHENTICATED_ACI))
|
||||
.thenReturn(Optional.of(account));
|
||||
when(account.getDevice(AUTHENTICATED_DEVICE_ID)).thenReturn(Optional.of(device));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void setBackupId() {
|
||||
when(backupAuthManager.commitBackupId(any(), any(), any(), any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(null));
|
||||
|
||||
void setBackupId() throws RateLimitExceededException {
|
||||
authenticatedServiceStub().setBackupId(
|
||||
SetBackupIdRequest.newBuilder()
|
||||
.setMediaBackupAuthCredentialRequest(ByteString.copyFrom(mediaAuthCredRequest.serialize()))
|
||||
@@ -111,10 +111,7 @@ class BackupsGrpcServiceTest extends SimpleBaseGrpcTest<BackupsGrpcService, Back
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {false, true})
|
||||
void setBackupIdPartial(boolean media) {
|
||||
when(backupAuthManager.commitBackupId(any(), any(), any(), any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(null));
|
||||
|
||||
void setBackupIdPartial(boolean media) throws RateLimitExceededException {
|
||||
final SetBackupIdRequest.Builder builder = SetBackupIdRequest.newBuilder();
|
||||
if (media) {
|
||||
builder.setMediaBackupAuthCredentialRequest(ByteString.copyFrom(mediaAuthCredRequest.serialize()));
|
||||
@@ -143,23 +140,17 @@ class BackupsGrpcServiceTest extends SimpleBaseGrpcTest<BackupsGrpcService, Back
|
||||
|
||||
public static Stream<Arguments> setBackupIdException() {
|
||||
return Stream.of(
|
||||
Arguments.of(new RateLimitExceededException(null), false, Status.RESOURCE_EXHAUSTED),
|
||||
Arguments.of(Status.INVALID_ARGUMENT.withDescription("async").asRuntimeException(), false,
|
||||
Status.INVALID_ARGUMENT),
|
||||
Arguments.of(Status.INVALID_ARGUMENT.withDescription("sync").asRuntimeException(), true,
|
||||
Arguments.of(new RateLimitExceededException(null), Status.RESOURCE_EXHAUSTED),
|
||||
Arguments.of(Status.INVALID_ARGUMENT.withDescription("test").asRuntimeException(),
|
||||
Status.INVALID_ARGUMENT)
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource
|
||||
void setBackupIdException(final Exception ex, final boolean sync, final Status expected) {
|
||||
if (sync) {
|
||||
when(backupAuthManager.commitBackupId(any(), any(), any(), any())).thenThrow(ex);
|
||||
} else {
|
||||
when(backupAuthManager.commitBackupId(any(), any(), any(), any()))
|
||||
.thenReturn(CompletableFuture.failedFuture(ex));
|
||||
}
|
||||
void setBackupIdException(final Exception ex, final Status expected)
|
||||
throws RateLimitExceededException {
|
||||
doThrow(ex).when(backupAuthManager).commitBackupId(any(), any(), any(), any());
|
||||
|
||||
GrpcTestUtils.assertStatusException(
|
||||
expected, () -> authenticatedServiceStub().setBackupId(SetBackupIdRequest.newBuilder()
|
||||
@@ -180,8 +171,6 @@ class BackupsGrpcServiceTest extends SimpleBaseGrpcTest<BackupsGrpcService, Back
|
||||
final ReceiptCredential receiptCredential = clientOps.receiveReceiptCredential(rcrc, rcr);
|
||||
final ReceiptCredentialPresentation presentation = clientOps.createReceiptCredentialPresentation(receiptCredential);
|
||||
|
||||
when(backupAuthManager.redeemReceipt(any(), any())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
|
||||
authenticatedServiceStub().redeemReceipt(RedeemReceiptRequest.newBuilder()
|
||||
.setPresentation(ByteString.copyFrom(presentation.serialize()))
|
||||
.build());
|
||||
@@ -203,7 +192,7 @@ class BackupsGrpcServiceTest extends SimpleBaseGrpcTest<BackupsGrpcService, Back
|
||||
|
||||
expectedCredentialsByType.forEach((credentialType, expectedCredentials) ->
|
||||
when(backupAuthManager.getBackupAuthCredentials(any(), eq(credentialType), eq(expectedRange)))
|
||||
.thenReturn(CompletableFuture.completedFuture(expectedCredentials)));
|
||||
.thenReturn(expectedCredentials));
|
||||
|
||||
final GetBackupAuthCredentialsResponse credentialResponse = authenticatedServiceStub().getBackupAuthCredentials(
|
||||
GetBackupAuthCredentialsRequest.newBuilder()
|
||||
|
||||
@@ -15,6 +15,7 @@ import io.grpc.inprocess.InProcessServerBuilder;
|
||||
import io.grpc.protobuf.StatusProto;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -120,6 +121,20 @@ class ErrorMappingInterceptorTest {
|
||||
client.echo(EchoRequest.getDefaultInstance()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mapWrappedIOExceptionsSimple() throws Exception {
|
||||
server = InProcessServerBuilder.forName("ErrorMappingInterceptorTest")
|
||||
.directExecutor()
|
||||
.addService(new SimpleEchoServiceErrorImpl(new CompletionException(new UncheckedIOException(new IOException("test")))))
|
||||
.intercept(new ErrorMappingInterceptor())
|
||||
.build()
|
||||
.start();
|
||||
|
||||
final EchoServiceGrpc.EchoServiceBlockingStub client = EchoServiceGrpc.newBlockingStub(channel);
|
||||
GrpcTestUtils.assertStatusException(Status.UNAVAILABLE, "UNAVAILABLE", () ->
|
||||
client.echo(EchoRequest.getDefaultInstance()));
|
||||
}
|
||||
|
||||
|
||||
static class ReactorEchoServiceErrorImpl extends ReactorEchoServiceGrpc.EchoServiceImplBase {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user