mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-21 23:18:05 +01:00
Reconcile inactive and undiscoverable accounts when using v3 endpoints
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 Signal Messenger, LLC
|
||||
* Copyright 2013-2021 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
@@ -46,14 +46,13 @@ public class DirectoryQueueTest {
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("argumentsForTestRefreshRegisteredUser")
|
||||
void testRefreshRegisteredUser(final boolean accountEnabled, final boolean accountDiscoverableByPhoneNumber, final String expectedAction) {
|
||||
void testRefreshRegisteredUser(final boolean shouldBeVisibleInDirectory, final String expectedAction) {
|
||||
final DirectoryQueue directoryQueue = new DirectoryQueue(List.of("sqs://test"), sqsAsyncClient);
|
||||
|
||||
final Account account = mock(Account.class);
|
||||
when(account.getNumber()).thenReturn("+18005556543");
|
||||
when(account.getUuid()).thenReturn(UUID.randomUUID());
|
||||
when(account.isEnabled()).thenReturn(accountEnabled);
|
||||
when(account.isDiscoverableByPhoneNumber()).thenReturn(accountDiscoverableByPhoneNumber);
|
||||
when(account.shouldBeVisibleInDirectory()).thenReturn(shouldBeVisibleInDirectory);
|
||||
|
||||
directoryQueue.refreshAccount(account);
|
||||
|
||||
@@ -67,10 +66,8 @@ public class DirectoryQueueTest {
|
||||
@SuppressWarnings("unused")
|
||||
private static Stream<Arguments> argumentsForTestRefreshRegisteredUser() {
|
||||
return Stream.of(
|
||||
Arguments.of(true, true, "add"),
|
||||
Arguments.of(true, false, "delete"),
|
||||
Arguments.of(false, true, "delete"),
|
||||
Arguments.of(false, false, "delete"));
|
||||
Arguments.of(true, "add"),
|
||||
Arguments.of(false, "delete"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -80,8 +77,7 @@ public class DirectoryQueueTest {
|
||||
final Account account = mock(Account.class);
|
||||
when(account.getNumber()).thenReturn("+18005556543");
|
||||
when(account.getUuid()).thenReturn(UUID.randomUUID());
|
||||
when(account.isEnabled()).thenReturn(true);
|
||||
when(account.isDiscoverableByPhoneNumber()).thenReturn(true);
|
||||
when(account.shouldBeVisibleInDirectory()).thenReturn(true);
|
||||
|
||||
directoryQueue.refreshAccount(account);
|
||||
|
||||
@@ -104,8 +100,7 @@ public class DirectoryQueueTest {
|
||||
final Account account = mock(Account.class);
|
||||
when(account.getNumber()).thenReturn("+18005556543");
|
||||
when(account.getUuid()).thenReturn(UUID.randomUUID());
|
||||
when(account.isEnabled()).thenReturn(true);
|
||||
when(account.isDiscoverableByPhoneNumber()).thenReturn(true);
|
||||
when(account.shouldBeVisibleInDirectory()).thenReturn(true);
|
||||
|
||||
directoryQueue.refreshAccount(account);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 Signal Messenger, LLC
|
||||
* Copyright 2013-2021 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
@@ -617,14 +617,19 @@ class AccountsManagerTest {
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource
|
||||
void testUpdateDirectoryQueue(final boolean discoverableBeforeUpdate, final boolean discoverableAfterUpdate, final boolean expectRefresh) {
|
||||
void testUpdateDirectoryQueue(final boolean visibleBeforeUpdate, final boolean visibleAfterUpdate,
|
||||
final boolean expectRefresh) {
|
||||
final Account account = new Account("+14152222222", UUID.randomUUID(), new HashSet<>(), new byte[16]);
|
||||
|
||||
when(directoryQueue.isDiscoverable(any()))
|
||||
.thenReturn(discoverableBeforeUpdate)
|
||||
.thenReturn(discoverableAfterUpdate);
|
||||
// this sets up the appropriate result for Account#shouldBeVisibleInDirectory
|
||||
final Device device = new Device(Device.MASTER_ID, "device", "token", "salt", null, null, null, true, 1,
|
||||
new SignedPreKey(1, "key", "sig"), 0, 0,
|
||||
"OWT", 0, new DeviceCapabilities());
|
||||
account.addDevice(device);
|
||||
account.setDiscoverableByPhoneNumber(visibleBeforeUpdate);
|
||||
|
||||
final Account updatedAccount = accountsManager.update(account, a -> a.setProfileName("Hello I am a unit test"));
|
||||
final Account updatedAccount = accountsManager.update(account,
|
||||
a -> a.setDiscoverableByPhoneNumber(visibleAfterUpdate));
|
||||
|
||||
verify(directoryQueue, times(expectRefresh ? 1 : 0)).refreshAccount(updatedAccount);
|
||||
}
|
||||
|
||||
@@ -1,71 +1,92 @@
|
||||
/*
|
||||
* Copyright 2013-2020 Signal Messenger, LLC
|
||||
* Copyright 2013-2021 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.tests.storage;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
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 java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.whispersystems.textsecuregcm.entities.DirectoryReconciliationRequest;
|
||||
import org.whispersystems.textsecuregcm.entities.DirectoryReconciliationRequest.User;
|
||||
import org.whispersystems.textsecuregcm.entities.DirectoryReconciliationResponse;
|
||||
import org.whispersystems.textsecuregcm.storage.Account;
|
||||
import org.whispersystems.textsecuregcm.storage.AccountDatabaseCrawlerRestartException;
|
||||
import org.whispersystems.textsecuregcm.storage.DirectoryReconciler;
|
||||
import org.whispersystems.textsecuregcm.storage.DirectoryReconciliationClient;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
class DirectoryReconcilerTest {
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
public class DirectoryReconcilerTest {
|
||||
private static final UUID VALID_UUID = UUID.randomUUID();
|
||||
private static final String VALID_NUMBERRR = "+14152222222";
|
||||
private static final UUID INACTIVE_UUID = UUID.randomUUID();
|
||||
private static final String INACTIVE_NUMBERRR = "+14151111111";
|
||||
private static final UUID UNDISCOVERABLE_UUID = UUID.randomUUID();
|
||||
private static final UUID VALID_UUID = UUID.randomUUID();
|
||||
private static final String VALID_NUMBER = "+14152222222";
|
||||
private static final UUID UNDISCOVERABLE_UUID = UUID.randomUUID();
|
||||
private static final String UNDISCOVERABLE_NUMBER = "+14153333333";
|
||||
|
||||
private final Account activeAccount = mock(Account.class);
|
||||
private final Account inactiveAccount = mock(Account.class);
|
||||
private final Account undiscoverableAccount = mock(Account.class);
|
||||
private final DirectoryReconciliationClient reconciliationClient = mock(DirectoryReconciliationClient.class);
|
||||
private final DirectoryReconciler directoryReconciler = new DirectoryReconciler("test", reconciliationClient);
|
||||
private final Account visibleAccount = mock(Account.class);
|
||||
private final Account undiscoverableAccount = mock(Account.class);
|
||||
private final DirectoryReconciliationClient reconciliationClient = mock(DirectoryReconciliationClient.class);
|
||||
private final DirectoryReconciler directoryReconciler = new DirectoryReconciler("test", reconciliationClient);
|
||||
|
||||
private final DirectoryReconciliationResponse successResponse = new DirectoryReconciliationResponse(DirectoryReconciliationResponse.Status.OK);
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
when(activeAccount.getUuid()).thenReturn(VALID_UUID);
|
||||
when(activeAccount.isEnabled()).thenReturn(true);
|
||||
when(activeAccount.getNumber()).thenReturn(VALID_NUMBERRR);
|
||||
when(activeAccount.isDiscoverableByPhoneNumber()).thenReturn(true);
|
||||
when(inactiveAccount.getUuid()).thenReturn(INACTIVE_UUID);
|
||||
when(inactiveAccount.getNumber()).thenReturn(INACTIVE_NUMBERRR);
|
||||
when(inactiveAccount.isEnabled()).thenReturn(false);
|
||||
when(inactiveAccount.isDiscoverableByPhoneNumber()).thenReturn(true);
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
when(visibleAccount.getUuid()).thenReturn(VALID_UUID);
|
||||
when(visibleAccount.getNumber()).thenReturn(VALID_NUMBER);
|
||||
when(visibleAccount.shouldBeVisibleInDirectory()).thenReturn(true);
|
||||
when(undiscoverableAccount.getUuid()).thenReturn(UNDISCOVERABLE_UUID);
|
||||
when(undiscoverableAccount.getNumber()).thenReturn(UNDISCOVERABLE_NUMBER);
|
||||
when(undiscoverableAccount.isEnabled()).thenReturn(true);
|
||||
when(undiscoverableAccount.isDiscoverableByPhoneNumber()).thenReturn(false);
|
||||
when(undiscoverableAccount.shouldBeVisibleInDirectory()).thenReturn(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCrawlChunkValid() throws AccountDatabaseCrawlerRestartException {
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
public void testCrawlChunkValid(final boolean useV3Endpoints) throws AccountDatabaseCrawlerRestartException {
|
||||
directoryReconciler.setUseV3Endpoints(useV3Endpoints);
|
||||
|
||||
when(reconciliationClient.sendChunk(any())).thenReturn(successResponse);
|
||||
directoryReconciler.timeAndProcessCrawlChunk(Optional.of(VALID_UUID), Arrays.asList(activeAccount, inactiveAccount, undiscoverableAccount));
|
||||
when(reconciliationClient.sendChunkV3(any())).thenReturn(successResponse);
|
||||
when(reconciliationClient.delete(any())).thenReturn(successResponse);
|
||||
|
||||
ArgumentCaptor<DirectoryReconciliationRequest> request = ArgumentCaptor.forClass(DirectoryReconciliationRequest.class);
|
||||
verify(reconciliationClient, times(1)).sendChunk(request.capture());
|
||||
directoryReconciler.timeAndProcessCrawlChunk(Optional.of(VALID_UUID),
|
||||
Arrays.asList(visibleAccount, undiscoverableAccount));
|
||||
|
||||
assertThat(request.getValue().getFromUuid()).isEqualTo(VALID_UUID);
|
||||
assertThat(request.getValue().getToUuid()).isEqualTo(UNDISCOVERABLE_UUID);
|
||||
assertThat(request.getValue().getUsers()).isEqualTo(Arrays.asList(new DirectoryReconciliationRequest.User(VALID_UUID, VALID_NUMBERRR)));
|
||||
ArgumentCaptor<DirectoryReconciliationRequest> chunkRequest = ArgumentCaptor.forClass(
|
||||
DirectoryReconciliationRequest.class);
|
||||
if (useV3Endpoints) {
|
||||
verify(reconciliationClient, times(1)).sendChunkV3(chunkRequest.capture());
|
||||
} else {
|
||||
verify(reconciliationClient, times(1)).sendChunk(chunkRequest.capture());
|
||||
}
|
||||
|
||||
assertThat(chunkRequest.getValue().getFromUuid()).isEqualTo(VALID_UUID);
|
||||
assertThat(chunkRequest.getValue().getToUuid()).isEqualTo(UNDISCOVERABLE_UUID);
|
||||
assertThat(chunkRequest.getValue().getUsers()).isEqualTo(List.of(new User(VALID_UUID, VALID_NUMBER)));
|
||||
|
||||
if (useV3Endpoints) {
|
||||
|
||||
ArgumentCaptor<DirectoryReconciliationRequest> deletesRequest = ArgumentCaptor.forClass(DirectoryReconciliationRequest.class);
|
||||
verify(reconciliationClient, times(1)).delete(deletesRequest.capture());
|
||||
|
||||
assertThat(deletesRequest.getValue().getUsers()).isEqualTo(
|
||||
List.of(new User(UNDISCOVERABLE_UUID, UNDISCOVERABLE_NUMBER)));
|
||||
}
|
||||
|
||||
verifyNoMoreInteractions(reconciliationClient);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user