mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-26 15:13:18 +01:00
Contact Discovery Service
This commit is contained in:
@@ -18,6 +18,7 @@ import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||
import org.whispersystems.textsecuregcm.mappers.RateLimitExceededExceptionMapper;
|
||||
import org.whispersystems.textsecuregcm.providers.TimeProvider;
|
||||
import org.whispersystems.textsecuregcm.sms.SmsSender;
|
||||
import org.whispersystems.textsecuregcm.sqs.ContactDiscoveryQueueSender;
|
||||
import org.whispersystems.textsecuregcm.storage.Account;
|
||||
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||
import org.whispersystems.textsecuregcm.storage.MessagesManager;
|
||||
@@ -49,6 +50,7 @@ public class AccountControllerTest {
|
||||
private RateLimiter rateLimiter = mock(RateLimiter.class );
|
||||
private RateLimiter pinLimiter = mock(RateLimiter.class );
|
||||
private SmsSender smsSender = mock(SmsSender.class );
|
||||
private ContactDiscoveryQueueSender cdsSender = mock(ContactDiscoveryQueueSender.class);
|
||||
private MessagesManager storedMessages = mock(MessagesManager.class );
|
||||
private TimeProvider timeProvider = mock(TimeProvider.class );
|
||||
private TurnTokenGenerator turnTokenGenerator = mock(TurnTokenGenerator.class);
|
||||
@@ -65,6 +67,7 @@ public class AccountControllerTest {
|
||||
accountsManager,
|
||||
rateLimiters,
|
||||
smsSender,
|
||||
cdsSender,
|
||||
storedMessages,
|
||||
turnTokenGenerator,
|
||||
new HashMap<>()))
|
||||
@@ -137,6 +140,7 @@ public class AccountControllerTest {
|
||||
assertThat(response.getStatus()).isEqualTo(204);
|
||||
|
||||
verify(accountsManager, times(1)).create(isA(Account.class));
|
||||
verify(cdsSender, times(1)).addRegisteredUser(eq(SENDER));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -282,4 +286,4 @@ public class AccountControllerTest {
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,10 +29,8 @@ import org.whispersystems.textsecuregcm.entities.DeviceResponse;
|
||||
import org.whispersystems.textsecuregcm.limits.RateLimiter;
|
||||
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||
import org.whispersystems.textsecuregcm.mappers.DeviceLimitExceededExceptionMapper;
|
||||
import org.whispersystems.textsecuregcm.storage.Account;
|
||||
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||
import org.whispersystems.textsecuregcm.storage.MessagesManager;
|
||||
import org.whispersystems.textsecuregcm.storage.PendingDevicesManager;
|
||||
import org.whispersystems.textsecuregcm.sqs.ContactDiscoveryQueueSender;
|
||||
import org.whispersystems.textsecuregcm.storage.*;
|
||||
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
||||
import org.whispersystems.textsecuregcm.util.VerificationCode;
|
||||
|
||||
@@ -55,10 +53,11 @@ public class DeviceControllerTest {
|
||||
public DumbVerificationDeviceController(PendingDevicesManager pendingDevices,
|
||||
AccountsManager accounts,
|
||||
MessagesManager messages,
|
||||
ContactDiscoveryQueueSender cdsSender,
|
||||
RateLimiters rateLimiters,
|
||||
Map<String, Integer> deviceConfiguration)
|
||||
{
|
||||
super(pendingDevices, accounts, messages, rateLimiters, deviceConfiguration);
|
||||
super(pendingDevices, accounts, messages, cdsSender, rateLimiters, deviceConfiguration);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -70,10 +69,12 @@ public class DeviceControllerTest {
|
||||
private PendingDevicesManager pendingDevicesManager = mock(PendingDevicesManager.class);
|
||||
private AccountsManager accountsManager = mock(AccountsManager.class );
|
||||
private MessagesManager messagesManager = mock(MessagesManager.class);
|
||||
private ContactDiscoveryQueueSender cdsSender = mock(ContactDiscoveryQueueSender.class);
|
||||
private RateLimiters rateLimiters = mock(RateLimiters.class );
|
||||
private RateLimiter rateLimiter = mock(RateLimiter.class );
|
||||
private Account account = mock(Account.class );
|
||||
private Account maxedAccount = mock(Account.class);
|
||||
private Device masterDevice = mock(Device.class);
|
||||
|
||||
private Map<String, Integer> deviceConfiguration = new HashMap<String, Integer>() {{
|
||||
|
||||
@@ -88,6 +89,7 @@ public class DeviceControllerTest {
|
||||
.addResource(new DumbVerificationDeviceController(pendingDevicesManager,
|
||||
accountsManager,
|
||||
messagesManager,
|
||||
cdsSender,
|
||||
rateLimiters,
|
||||
deviceConfiguration))
|
||||
.build();
|
||||
@@ -101,9 +103,13 @@ public class DeviceControllerTest {
|
||||
when(rateLimiters.getAllocateDeviceLimiter()).thenReturn(rateLimiter);
|
||||
when(rateLimiters.getVerifyDeviceLimiter()).thenReturn(rateLimiter);
|
||||
|
||||
when(masterDevice.getId()).thenReturn(1L);
|
||||
|
||||
when(account.getNextDeviceId()).thenReturn(42L);
|
||||
when(account.getNumber()).thenReturn(AuthHelper.VALID_NUMBER);
|
||||
// when(maxedAccount.getActiveDeviceCount()).thenReturn(6);
|
||||
when(account.getAuthenticatedDevice()).thenReturn(Optional.of(masterDevice));
|
||||
when(account.isActive()).thenReturn(false);
|
||||
|
||||
when(pendingDevicesManager.getCodeForNumber(AuthHelper.VALID_NUMBER)).thenReturn(Optional.of(new StoredVerificationCode("5678901", System.currentTimeMillis())));
|
||||
when(pendingDevicesManager.getCodeForNumber(AuthHelper.VALID_NUMBER_TWO)).thenReturn(Optional.of(new StoredVerificationCode("1112223", System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(31))));
|
||||
@@ -195,4 +201,16 @@ public class DeviceControllerTest {
|
||||
assertEquals(response.getStatus(), 422);
|
||||
verifyNoMoreInteractions(messagesManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeDeviceTest() throws Exception {
|
||||
Response response = resources.getJerseyTest()
|
||||
.target("/v1/devices/12345")
|
||||
.request()
|
||||
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
|
||||
.delete();
|
||||
|
||||
assertEquals(204, response.getStatus());
|
||||
verify(cdsSender).deleteRegisteredUser(eq(AuthHelper.VALID_NUMBER));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.whispersystems.textsecuregcm.tests.controllers;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
@@ -7,6 +8,10 @@ import org.junit.Test;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.whispersystems.dropwizard.simpleauth.AuthValueFactoryProvider;
|
||||
import org.whispersystems.textsecuregcm.auth.DirectoryCredentials;
|
||||
import org.whispersystems.textsecuregcm.auth.DirectoryCredentialsGenerator;
|
||||
import org.whispersystems.textsecuregcm.configuration.DirectoryConfiguration;
|
||||
import org.whispersystems.textsecuregcm.configuration.DirectoryClientConfiguration;
|
||||
import org.whispersystems.textsecuregcm.controllers.DirectoryController;
|
||||
import org.whispersystems.textsecuregcm.entities.ClientContactTokens;
|
||||
import org.whispersystems.textsecuregcm.limits.RateLimiter;
|
||||
@@ -24,15 +29,19 @@ import java.util.List;
|
||||
import io.dropwizard.testing.junit.ResourceTestRule;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.anyListOf;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Matchers.anyList;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class DirectoryControllerTest {
|
||||
|
||||
private final RateLimiters rateLimiters = mock(RateLimiters.class );
|
||||
private final RateLimiter rateLimiter = mock(RateLimiter.class );
|
||||
private final DirectoryManager directoryManager = mock(DirectoryManager.class);
|
||||
private final RateLimiters rateLimiters = mock(RateLimiters.class);
|
||||
private final RateLimiter rateLimiter = mock(RateLimiter.class);
|
||||
private final DirectoryManager directoryManager = mock(DirectoryManager.class);
|
||||
private final DirectoryCredentialsGenerator directoryCredentialsGenerator = mock(DirectoryCredentialsGenerator.class);
|
||||
|
||||
private final DirectoryCredentials validCredentials = new DirectoryCredentials("username", "password");
|
||||
|
||||
@Rule
|
||||
public final ResourceTestRule resources = ResourceTestRule.builder()
|
||||
@@ -40,7 +49,8 @@ public class DirectoryControllerTest {
|
||||
.addProvider(new AuthValueFactoryProvider.Binder())
|
||||
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
||||
.addResource(new DirectoryController(rateLimiters,
|
||||
directoryManager))
|
||||
directoryManager,
|
||||
directoryCredentialsGenerator))
|
||||
.build();
|
||||
|
||||
|
||||
@@ -56,6 +66,19 @@ public class DirectoryControllerTest {
|
||||
return response;
|
||||
}
|
||||
});
|
||||
when(directoryCredentialsGenerator.generateFor(eq(AuthHelper.VALID_NUMBER))).thenReturn(validCredentials);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAuthToken() {
|
||||
DirectoryCredentials token =
|
||||
resources.getJerseyTest()
|
||||
.target("/v1/directory/auth")
|
||||
.request()
|
||||
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
|
||||
.get(DirectoryCredentials.class);
|
||||
assertThat(token.getUsername()).isEqualTo(validCredentials.getUsername());
|
||||
assertThat(token.getPassword()).isEqualTo(validCredentials.getPassword());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
package org.whispersystems.textsecuregcm.tests.storage;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.whispersystems.textsecuregcm.entities.ClientContact;
|
||||
import org.whispersystems.textsecuregcm.entities.DirectoryReconciliationRequest;
|
||||
import org.whispersystems.textsecuregcm.entities.DirectoryReconciliationResponse;
|
||||
import org.whispersystems.textsecuregcm.storage.Account;
|
||||
import org.whispersystems.textsecuregcm.storage.Accounts;
|
||||
import org.whispersystems.textsecuregcm.storage.DirectoryManager;
|
||||
import org.whispersystems.textsecuregcm.storage.DirectoryManager.BatchOperationHandle;
|
||||
import org.whispersystems.textsecuregcm.storage.DirectoryReconciler;
|
||||
import org.whispersystems.textsecuregcm.storage.DirectoryReconciliationCache;
|
||||
import org.whispersystems.textsecuregcm.storage.DirectoryReconciliationClient;
|
||||
import org.whispersystems.textsecuregcm.util.Util;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.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;
|
||||
|
||||
public class DirectoryReconcilerTest {
|
||||
|
||||
private static final String VALID_NUMBER = "valid";
|
||||
private static final String INACTIVE_NUMBER = "inactive";
|
||||
|
||||
private static final long ACCOUNT_COUNT = 0L;
|
||||
private static final long INTERVAL_MS = 30_000L;
|
||||
|
||||
private final Account account = mock(Account.class);
|
||||
private final Account inactiveAccount = mock(Account.class);
|
||||
private final Accounts accounts = mock(Accounts.class);
|
||||
private final BatchOperationHandle batchOperationHandle = mock(BatchOperationHandle.class);
|
||||
private final DirectoryManager directoryManager = mock(DirectoryManager.class);
|
||||
private final DirectoryReconciliationClient reconciliationClient = mock(DirectoryReconciliationClient.class);
|
||||
private final DirectoryReconciliationCache reconciliationCache = mock(DirectoryReconciliationCache.class);
|
||||
private final DirectoryReconciler directoryReconciler = new DirectoryReconciler(reconciliationClient, reconciliationCache, directoryManager, accounts);
|
||||
|
||||
private final DirectoryReconciliationResponse successResponse = new DirectoryReconciliationResponse(DirectoryReconciliationResponse.Status.OK);
|
||||
private final DirectoryReconciliationResponse notFoundResponse = new DirectoryReconciliationResponse(DirectoryReconciliationResponse.Status.MISSING);
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
when(account.getNumber()).thenReturn(VALID_NUMBER);
|
||||
when(account.isActive()).thenReturn(true);
|
||||
when(account.isVideoSupported()).thenReturn(true);
|
||||
when(account.isVoiceSupported()).thenReturn(true);
|
||||
when(inactiveAccount.getNumber()).thenReturn(INACTIVE_NUMBER);
|
||||
when(inactiveAccount.isActive()).thenReturn(false);
|
||||
|
||||
when(directoryManager.startBatchOperation()).thenReturn(batchOperationHandle);
|
||||
|
||||
when(accounts.getAllFrom(anyInt())).thenReturn(Arrays.asList(account, inactiveAccount));
|
||||
when(accounts.getAllFrom(eq(VALID_NUMBER), anyInt())).thenReturn(Arrays.asList(inactiveAccount));
|
||||
when(accounts.getAllFrom(eq(INACTIVE_NUMBER), anyInt())).thenReturn(Collections.emptyList());
|
||||
when(accounts.getCount()).thenReturn(ACCOUNT_COUNT);
|
||||
|
||||
when(reconciliationClient.sendChunk(any())).thenReturn(successResponse);
|
||||
|
||||
when(reconciliationCache.getLastNumber()).thenReturn(Optional.absent());
|
||||
when(reconciliationCache.claimActiveWork(any(), anyLong())).thenReturn(true);
|
||||
when(reconciliationCache.isAccelerated()).thenReturn(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUncachedAccountCount() {
|
||||
when(reconciliationCache.getCachedAccountCount()).thenReturn(Optional.absent());
|
||||
|
||||
long accountCount = directoryReconciler.getAccountCount();
|
||||
|
||||
assertThat(accountCount).isEqualTo(ACCOUNT_COUNT);
|
||||
|
||||
verify(accounts, times(1)).getCount();
|
||||
|
||||
verify(reconciliationCache, times(1)).getCachedAccountCount();
|
||||
verify(reconciliationCache, times(1)).setCachedAccountCount(eq(ACCOUNT_COUNT));
|
||||
|
||||
verifyNoMoreInteractions(directoryManager);
|
||||
verifyNoMoreInteractions(accounts);
|
||||
verifyNoMoreInteractions(reconciliationClient);
|
||||
verifyNoMoreInteractions(reconciliationCache);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCachedAccountCount() {
|
||||
when(reconciliationCache.getCachedAccountCount()).thenReturn(Optional.of(ACCOUNT_COUNT));
|
||||
|
||||
long accountCount = directoryReconciler.getAccountCount();
|
||||
|
||||
assertThat(accountCount).isEqualTo(ACCOUNT_COUNT);
|
||||
|
||||
verify(reconciliationCache, times(1)).getCachedAccountCount();
|
||||
|
||||
verifyNoMoreInteractions(directoryManager);
|
||||
verifyNoMoreInteractions(accounts);
|
||||
verifyNoMoreInteractions(reconciliationClient);
|
||||
verifyNoMoreInteractions(reconciliationCache);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValid() {
|
||||
long delayMs = directoryReconciler.doPeriodicWork(INTERVAL_MS);
|
||||
|
||||
assertThat(delayMs).isLessThanOrEqualTo(INTERVAL_MS);
|
||||
|
||||
verify(accounts, times(1)).getAllFrom(anyInt());
|
||||
|
||||
ArgumentCaptor<DirectoryReconciliationRequest> request = ArgumentCaptor.forClass(DirectoryReconciliationRequest.class);
|
||||
verify(reconciliationClient, times(1)).sendChunk(request.capture());
|
||||
|
||||
assertThat(request.getValue().getFromNumber()).isNull();
|
||||
assertThat(request.getValue().getToNumber()).isEqualTo(INACTIVE_NUMBER);
|
||||
assertThat(request.getValue().getNumbers()).isEqualTo(Arrays.asList(VALID_NUMBER));
|
||||
|
||||
ArgumentCaptor<ClientContact> addedContact = ArgumentCaptor.forClass(ClientContact.class);
|
||||
verify(directoryManager, times(1)).startBatchOperation();
|
||||
verify(directoryManager, times(1)).add(eq(batchOperationHandle), addedContact.capture());
|
||||
verify(directoryManager, times(1)).remove(eq(batchOperationHandle), eq(INACTIVE_NUMBER));
|
||||
verify(directoryManager, times(1)).stopBatchOperation(eq(batchOperationHandle));
|
||||
|
||||
assertThat(addedContact.getValue().getToken()).isEqualTo(Util.getContactToken(VALID_NUMBER));
|
||||
|
||||
verify(reconciliationCache, times(1)).getLastNumber();
|
||||
verify(reconciliationCache, times(1)).setLastNumber(eq(Optional.of(INACTIVE_NUMBER)));
|
||||
verify(reconciliationCache, times(1)).isAccelerated();
|
||||
verify(reconciliationCache, times(2)).claimActiveWork(any(), anyLong());
|
||||
|
||||
verifyNoMoreInteractions(accounts);
|
||||
verifyNoMoreInteractions(directoryManager);
|
||||
verifyNoMoreInteractions(reconciliationClient);
|
||||
verifyNoMoreInteractions(reconciliationCache);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInProgress() {
|
||||
when(reconciliationCache.getLastNumber()).thenReturn(Optional.of(VALID_NUMBER));
|
||||
|
||||
long delayMs = directoryReconciler.doPeriodicWork(INTERVAL_MS);
|
||||
|
||||
assertThat(delayMs).isLessThanOrEqualTo(INTERVAL_MS);
|
||||
|
||||
verify(accounts, times(1)).getAllFrom(eq(VALID_NUMBER), anyInt());
|
||||
|
||||
ArgumentCaptor<DirectoryReconciliationRequest> request = ArgumentCaptor.forClass(DirectoryReconciliationRequest.class);
|
||||
verify(reconciliationClient, times(1)).sendChunk(request.capture());
|
||||
|
||||
assertThat(request.getValue().getFromNumber()).isEqualTo(VALID_NUMBER);
|
||||
assertThat(request.getValue().getToNumber()).isEqualTo(INACTIVE_NUMBER);
|
||||
assertThat(request.getValue().getNumbers()).isEqualTo(Collections.emptyList());
|
||||
|
||||
verify(directoryManager, times(1)).startBatchOperation();
|
||||
verify(directoryManager, times(1)).remove(eq(batchOperationHandle), eq(INACTIVE_NUMBER));
|
||||
verify(directoryManager, times(1)).stopBatchOperation(eq(batchOperationHandle));
|
||||
|
||||
verify(reconciliationCache, times(1)).getLastNumber();
|
||||
verify(reconciliationCache, times(1)).setLastNumber(eq(Optional.of(INACTIVE_NUMBER)));
|
||||
verify(reconciliationCache, times(1)).isAccelerated();
|
||||
verify(reconciliationCache, times(2)).claimActiveWork(any(), anyLong());
|
||||
|
||||
verifyNoMoreInteractions(accounts);
|
||||
verifyNoMoreInteractions(directoryManager);
|
||||
verifyNoMoreInteractions(reconciliationClient);
|
||||
verifyNoMoreInteractions(reconciliationCache);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLastChunk() {
|
||||
when(reconciliationCache.getLastNumber()).thenReturn(Optional.of(INACTIVE_NUMBER));
|
||||
|
||||
long delayMs = directoryReconciler.doPeriodicWork(INTERVAL_MS);
|
||||
|
||||
assertThat(delayMs).isLessThanOrEqualTo(INTERVAL_MS);
|
||||
|
||||
verify(accounts, times(1)).getAllFrom(eq(INACTIVE_NUMBER), anyInt());
|
||||
|
||||
ArgumentCaptor<DirectoryReconciliationRequest> request = ArgumentCaptor.forClass(DirectoryReconciliationRequest.class);
|
||||
verify(reconciliationClient, times(1)).sendChunk(request.capture());
|
||||
|
||||
assertThat(request.getValue().getFromNumber()).isEqualTo(INACTIVE_NUMBER);
|
||||
assertThat(request.getValue().getToNumber()).isNull();
|
||||
assertThat(request.getValue().getNumbers()).isEqualTo(Collections.emptyList());
|
||||
|
||||
verify(reconciliationCache, times(1)).getLastNumber();
|
||||
verify(reconciliationCache, times(1)).setLastNumber(eq(Optional.absent()));
|
||||
verify(reconciliationCache, times(1)).clearAccelerate();
|
||||
verify(reconciliationCache, times(1)).isAccelerated();
|
||||
verify(reconciliationCache, times(2)).claimActiveWork(any(), anyLong());
|
||||
|
||||
verifyNoMoreInteractions(accounts);
|
||||
verifyNoMoreInteractions(directoryManager);
|
||||
verifyNoMoreInteractions(reconciliationClient);
|
||||
verifyNoMoreInteractions(reconciliationCache);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotFound() {
|
||||
when(reconciliationClient.sendChunk(any())).thenReturn(notFoundResponse);
|
||||
|
||||
long delayMs = directoryReconciler.doPeriodicWork(INTERVAL_MS);
|
||||
|
||||
assertThat(delayMs).isLessThanOrEqualTo(INTERVAL_MS);
|
||||
|
||||
verify(accounts, times(1)).getAllFrom(anyInt());
|
||||
|
||||
ArgumentCaptor<DirectoryReconciliationRequest> request = ArgumentCaptor.forClass(DirectoryReconciliationRequest.class);
|
||||
verify(reconciliationClient, times(1)).sendChunk(request.capture());
|
||||
|
||||
assertThat(request.getValue().getFromNumber()).isNull();
|
||||
assertThat(request.getValue().getToNumber()).isEqualTo(INACTIVE_NUMBER);
|
||||
assertThat(request.getValue().getNumbers()).isEqualTo(Arrays.asList(VALID_NUMBER));
|
||||
|
||||
ArgumentCaptor<ClientContact> addedContact = ArgumentCaptor.forClass(ClientContact.class);
|
||||
verify(directoryManager, times(1)).startBatchOperation();
|
||||
verify(directoryManager, times(1)).add(eq(batchOperationHandle), addedContact.capture());
|
||||
verify(directoryManager, times(1)).remove(eq(batchOperationHandle), eq(INACTIVE_NUMBER));
|
||||
verify(directoryManager, times(1)).stopBatchOperation(eq(batchOperationHandle));
|
||||
|
||||
assertThat(addedContact.getValue().getToken()).isEqualTo(Util.getContactToken(VALID_NUMBER));
|
||||
|
||||
verify(reconciliationCache, times(1)).getLastNumber();
|
||||
verify(reconciliationCache, times(1)).setLastNumber(eq(Optional.absent()));
|
||||
verify(reconciliationCache, times(1)).clearAccelerate();
|
||||
verify(reconciliationCache, times(1)).claimActiveWork(any(), anyLong());
|
||||
|
||||
verifyNoMoreInteractions(accounts);
|
||||
verifyNoMoreInteractions(directoryManager);
|
||||
verifyNoMoreInteractions(reconciliationClient);
|
||||
verifyNoMoreInteractions(reconciliationCache);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user