Add public methods for fetching accounts asynchronously
This commit is contained in:
parent
1b7a20619e
commit
41f61c66a3
|
@ -20,6 +20,7 @@ import io.lettuce.core.cluster.api.sync.RedisAdvancedClusterCommands;
|
|||
import io.micrometer.core.instrument.Metrics;
|
||||
import io.micrometer.core.instrument.Tags;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.time.Clock;
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
|
@ -39,6 +40,7 @@ import java.util.function.Supplier;
|
|||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Nullable;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.signal.libsignal.protocol.IdentityKey;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -58,7 +60,6 @@ import org.whispersystems.textsecuregcm.util.Constants;
|
|||
import org.whispersystems.textsecuregcm.util.DestinationDeviceValidator;
|
||||
import org.whispersystems.textsecuregcm.util.SystemMapper;
|
||||
import org.whispersystems.textsecuregcm.util.Util;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.ParallelFlux;
|
||||
import reactor.core.scheduler.Scheduler;
|
||||
|
||||
|
@ -89,7 +90,7 @@ public class AccountsManager {
|
|||
@VisibleForTesting
|
||||
public static final String USERNAME_EXPERIMENT_NAME = "usernames";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(AccountsManager.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(AccountsManager.class);
|
||||
|
||||
private final Accounts accounts;
|
||||
private final PhoneNumberIdentifiers phoneNumberIdentifiers;
|
||||
|
@ -686,6 +687,14 @@ public class AccountsManager {
|
|||
);
|
||||
}
|
||||
|
||||
public CompletableFuture<Optional<Account>> getByE164Async(final String number) {
|
||||
return checkRedisThenAccountsAsync(
|
||||
getByNumberTimer,
|
||||
() -> redisGetBySecondaryKeyAsync(getAccountMapKey(number), redisNumberGetTimer),
|
||||
() -> accounts.getByE164Async(number)
|
||||
);
|
||||
}
|
||||
|
||||
public Optional<Account> getByPhoneNumberIdentifier(final UUID pni) {
|
||||
return checkRedisThenAccounts(
|
||||
getByNumberTimer,
|
||||
|
@ -694,6 +703,14 @@ public class AccountsManager {
|
|||
);
|
||||
}
|
||||
|
||||
public CompletableFuture<Optional<Account>> getByPhoneNumberIdentifierAsync(final UUID pni) {
|
||||
return checkRedisThenAccountsAsync(
|
||||
getByNumberTimer,
|
||||
() -> redisGetBySecondaryKeyAsync(getAccountMapKey(pni.toString()), redisPniGetTimer),
|
||||
() -> accounts.getByPhoneNumberIdentifierAsync(pni)
|
||||
);
|
||||
}
|
||||
|
||||
public Optional<Account> getByUsernameLinkHandle(final UUID usernameLinkHandle) {
|
||||
return checkRedisThenAccounts(
|
||||
getByUsernameLinkHandleTimer,
|
||||
|
@ -718,6 +735,14 @@ public class AccountsManager {
|
|||
);
|
||||
}
|
||||
|
||||
public CompletableFuture<Optional<Account>> getByAccountIdentifierAsync(final UUID uuid) {
|
||||
return checkRedisThenAccountsAsync(
|
||||
getByUuidTimer,
|
||||
() -> redisGetByAccountIdentifierAsync(uuid),
|
||||
() -> accounts.getByAccountIdentifierAsync(uuid)
|
||||
);
|
||||
}
|
||||
|
||||
public UUID getPhoneNumberIdentifier(String e164) {
|
||||
return phoneNumberIdentifiers.getPhoneNumberIdentifier(e164);
|
||||
}
|
||||
|
@ -815,6 +840,36 @@ public class AccountsManager {
|
|||
}
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> redisSetAsync(final Account account) {
|
||||
final String accountJson;
|
||||
|
||||
try {
|
||||
accountJson = mapper.writeValueAsString(account);
|
||||
} catch (final JsonProcessingException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
|
||||
return cacheCluster.withCluster(connection -> CompletableFuture.allOf(
|
||||
connection.async().setex(
|
||||
getAccountMapKey(account.getPhoneNumberIdentifier().toString()), CACHE_TTL_SECONDS,
|
||||
account.getUuid().toString())
|
||||
.toCompletableFuture(),
|
||||
|
||||
connection.async()
|
||||
.setex(getAccountMapKey(account.getNumber()), CACHE_TTL_SECONDS, account.getUuid().toString())
|
||||
.toCompletableFuture(),
|
||||
|
||||
connection.async().setex(getAccountEntityKey(account.getUuid()), CACHE_TTL_SECONDS, accountJson)
|
||||
.toCompletableFuture(),
|
||||
|
||||
account.getUsernameHash()
|
||||
.map(usernameHash -> connection.async()
|
||||
.setex(getUsernameHashAccountMapKey(usernameHash), CACHE_TTL_SECONDS, account.getUuid().toString())
|
||||
.toCompletableFuture())
|
||||
.orElseGet(() -> CompletableFuture.completedFuture(null))
|
||||
));
|
||||
}
|
||||
|
||||
private Optional<Account> checkRedisThenAccounts(
|
||||
final Timer overallTimer,
|
||||
final Supplier<Optional<Account>> resolveFromRedis,
|
||||
|
@ -829,6 +884,23 @@ public class AccountsManager {
|
|||
}
|
||||
}
|
||||
|
||||
private CompletableFuture<Optional<Account>> checkRedisThenAccountsAsync(
|
||||
final Timer overallTimer,
|
||||
final Supplier<CompletableFuture<Optional<Account>>> resolveFromRedis,
|
||||
final Supplier<CompletableFuture<Optional<Account>>> resolveFromAccounts) {
|
||||
|
||||
@SuppressWarnings("resource") final Timer.Context timerContext = overallTimer.time();
|
||||
|
||||
return resolveFromRedis.get()
|
||||
.thenCompose(maybeAccountFromRedis -> maybeAccountFromRedis
|
||||
.map(accountFromRedis -> CompletableFuture.completedFuture(maybeAccountFromRedis))
|
||||
.orElseGet(() -> resolveFromAccounts.get()
|
||||
.thenCompose(maybeAccountFromAccounts -> maybeAccountFromAccounts
|
||||
.map(account -> redisSetAsync(account).thenApply(ignored -> maybeAccountFromAccounts))
|
||||
.orElseGet(() -> CompletableFuture.completedFuture(maybeAccountFromAccounts)))))
|
||||
.whenComplete((ignored, throwable) -> timerContext.close());
|
||||
}
|
||||
|
||||
private Optional<Account> redisGetBySecondaryKey(final String secondaryKey, final Timer timer) {
|
||||
try (final Timer.Context ignored = timer.time()) {
|
||||
return Optional.ofNullable(cacheCluster.withCluster(connection -> connection.sync().get(secondaryKey)))
|
||||
|
@ -843,12 +915,50 @@ public class AccountsManager {
|
|||
}
|
||||
}
|
||||
|
||||
private CompletableFuture<Optional<Account>> redisGetBySecondaryKeyAsync(final String secondaryKey, final Timer timer) {
|
||||
@SuppressWarnings("resource") final Timer.Context timerContext = timer.time();
|
||||
|
||||
return cacheCluster.withCluster(connection -> connection.async().get(secondaryKey))
|
||||
.thenCompose(nullableUuid -> {
|
||||
if (nullableUuid != null) {
|
||||
return getByAccountIdentifierAsync(UUID.fromString(nullableUuid));
|
||||
} else {
|
||||
return CompletableFuture.completedFuture(Optional.empty());
|
||||
}
|
||||
})
|
||||
.exceptionally(throwable -> {
|
||||
logger.warn("Failed to retrieve account from Redis", throwable);
|
||||
return Optional.empty();
|
||||
})
|
||||
.whenComplete((ignored, throwable) -> timerContext.close())
|
||||
.toCompletableFuture();
|
||||
}
|
||||
|
||||
private Optional<Account> redisGetByAccountIdentifier(UUID uuid) {
|
||||
try (Timer.Context ignored = redisUuidGetTimer.time()) {
|
||||
final String json = cacheCluster.withCluster(connection -> connection.sync().get(getAccountEntityKey(uuid)));
|
||||
|
||||
if (json != null) {
|
||||
Account account = mapper.readValue(json, Account.class);
|
||||
return parseAccountJson(json, uuid);
|
||||
} catch (final RedisException e) {
|
||||
logger.warn("Redis failure", e);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private CompletableFuture<Optional<Account>> redisGetByAccountIdentifierAsync(final UUID uuid) {
|
||||
return cacheCluster.withCluster(connection -> connection.async().get(getAccountEntityKey(uuid)))
|
||||
.thenApply(accountJson -> parseAccountJson(accountJson, uuid))
|
||||
.exceptionally(throwable -> {
|
||||
logger.warn("Failed to retrieve account from Redis", throwable);
|
||||
return Optional.empty();
|
||||
})
|
||||
.toCompletableFuture();
|
||||
}
|
||||
|
||||
private static Optional<Account> parseAccountJson(@Nullable final String accountJson, final UUID uuid) {
|
||||
try {
|
||||
if (StringUtils.isNotBlank(accountJson)) {
|
||||
Account account = mapper.readValue(accountJson, Account.class);
|
||||
account.setUuid(uuid);
|
||||
|
||||
if (account.getPhoneNumberIdentifier() == null) {
|
||||
|
@ -859,12 +969,9 @@ public class AccountsManager {
|
|||
}
|
||||
|
||||
return Optional.empty();
|
||||
} catch (IOException e) {
|
||||
} catch (final IOException e) {
|
||||
logger.warn("Deserialization error", e);
|
||||
return Optional.empty();
|
||||
} catch (RedisException e) {
|
||||
logger.warn("Redis failure", e);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
|
|||
import static org.mockito.Mockito.when;
|
||||
|
||||
import io.lettuce.core.RedisException;
|
||||
import io.lettuce.core.cluster.api.async.RedisAdvancedClusterAsyncCommands;
|
||||
import io.lettuce.core.cluster.api.sync.RedisAdvancedClusterCommands;
|
||||
import java.time.Clock;
|
||||
import java.time.Duration;
|
||||
|
@ -45,6 +46,7 @@ import java.util.stream.Collectors;
|
|||
import java.util.stream.Stream;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.Timeout;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
@ -67,8 +69,10 @@ import org.whispersystems.textsecuregcm.storage.Device.DeviceCapabilities;
|
|||
import org.whispersystems.textsecuregcm.tests.util.AccountsHelper;
|
||||
import org.whispersystems.textsecuregcm.tests.util.DevicesHelper;
|
||||
import org.whispersystems.textsecuregcm.tests.util.KeysHelper;
|
||||
import org.whispersystems.textsecuregcm.tests.util.MockRedisFuture;
|
||||
import org.whispersystems.textsecuregcm.tests.util.RedisClusterHelper;
|
||||
|
||||
@Timeout(value = 10, threadMode = Timeout.ThreadMode.SEPARATE_THREAD)
|
||||
class AccountsManagerTest {
|
||||
private static final String BASE_64_URL_USERNAME_HASH_1 = "9p6Tip7BFefFOJzv4kv4GyXEYsBVfk_WbjNejdlOvQE";
|
||||
private static final String BASE_64_URL_USERNAME_HASH_2 = "NLUom-CHwtemcdvOTTXdmXmzRIV7F05leS8lwkVK_vc";
|
||||
|
@ -86,6 +90,7 @@ class AccountsManagerTest {
|
|||
private Map<String, UUID> phoneNumberIdentifiersByE164;
|
||||
|
||||
private RedisAdvancedClusterCommands<String, String> commands;
|
||||
private RedisAdvancedClusterAsyncCommands<String, String> asyncCommands;
|
||||
private AccountsManager accountsManager;
|
||||
|
||||
private static final Answer<?> ACCOUNT_UPDATE_ANSWER = (answer) -> {
|
||||
|
@ -108,6 +113,9 @@ class AccountsManagerTest {
|
|||
//noinspection unchecked
|
||||
commands = mock(RedisAdvancedClusterCommands.class);
|
||||
|
||||
//noinspection unchecked
|
||||
asyncCommands = mock(RedisAdvancedClusterAsyncCommands.class);
|
||||
|
||||
doAnswer((Answer<Void>) invocation -> {
|
||||
final Account account = invocation.getArgument(0, Account.class);
|
||||
final String number = invocation.getArgument(1, String.class);
|
||||
|
@ -162,7 +170,10 @@ class AccountsManagerTest {
|
|||
accountsManager = new AccountsManager(
|
||||
accounts,
|
||||
phoneNumberIdentifiers,
|
||||
RedisClusterHelper.builder().stringCommands(commands).build(),
|
||||
RedisClusterHelper.builder()
|
||||
.stringCommands(commands)
|
||||
.stringAsyncCommands(asyncCommands)
|
||||
.build(),
|
||||
accountLockManager,
|
||||
deletedAccounts,
|
||||
keysManager,
|
||||
|
@ -199,6 +210,31 @@ class AccountsManagerTest {
|
|||
verifyNoInteractions(accounts);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAccountByNumberAsyncInCache() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
|
||||
when(asyncCommands.get(eq("AccountMap::+14152222222")))
|
||||
.thenReturn(MockRedisFuture.completedFuture(uuid.toString()));
|
||||
|
||||
when(asyncCommands.get(eq("Account3::" + uuid))).thenReturn(MockRedisFuture.completedFuture(
|
||||
"{\"number\": \"+14152222222\", \"pni\": \"de24dc73-fbd8-41be-a7d5-764c70d9da7e\"}"));
|
||||
|
||||
when(asyncCommands.setex(any(), anyLong(), any())).thenReturn(MockRedisFuture.completedFuture("OK"));
|
||||
|
||||
Optional<Account> account = accountsManager.getByE164Async("+14152222222").join();
|
||||
|
||||
assertTrue(account.isPresent());
|
||||
assertEquals(account.get().getNumber(), "+14152222222");
|
||||
assertEquals(UUID.fromString("de24dc73-fbd8-41be-a7d5-764c70d9da7e"), account.get().getPhoneNumberIdentifier());
|
||||
|
||||
verify(asyncCommands).get(eq("AccountMap::+14152222222"));
|
||||
verify(asyncCommands).get(eq("Account3::" + uuid));
|
||||
verifyNoMoreInteractions(asyncCommands);
|
||||
|
||||
verifyNoInteractions(accounts);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAccountByUuidInCache() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
|
@ -219,6 +255,28 @@ class AccountsManagerTest {
|
|||
verifyNoInteractions(accounts);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAccountByUuidInCacheAsync() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
|
||||
when(asyncCommands.get(eq("Account3::" + uuid))).thenReturn(MockRedisFuture.completedFuture(
|
||||
"{\"number\": \"+14152222222\", \"pni\": \"de24dc73-fbd8-41be-a7d5-764c70d9da7e\"}"));
|
||||
|
||||
when(asyncCommands.setex(any(), anyLong(), any())).thenReturn(MockRedisFuture.completedFuture("OK"));
|
||||
|
||||
Optional<Account> account = accountsManager.getByAccountIdentifierAsync(uuid).join();
|
||||
|
||||
assertTrue(account.isPresent());
|
||||
assertEquals(account.get().getNumber(), "+14152222222");
|
||||
assertEquals(account.get().getUuid(), uuid);
|
||||
assertEquals(UUID.fromString("de24dc73-fbd8-41be-a7d5-764c70d9da7e"), account.get().getPhoneNumberIdentifier());
|
||||
|
||||
verify(asyncCommands, times(1)).get(eq("Account3::" + uuid));
|
||||
verifyNoMoreInteractions(asyncCommands);
|
||||
|
||||
verifyNoInteractions(accounts);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetByPniInCache() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
|
@ -241,6 +299,32 @@ class AccountsManagerTest {
|
|||
verifyNoInteractions(accounts);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetByPniInCacheAsync() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
UUID pni = UUID.randomUUID();
|
||||
|
||||
when(asyncCommands.get(eq("AccountMap::" + pni)))
|
||||
.thenReturn(MockRedisFuture.completedFuture(uuid.toString()));
|
||||
|
||||
when(asyncCommands.get(eq("Account3::" + uuid))).thenReturn(MockRedisFuture.completedFuture(
|
||||
"{\"number\": \"+14152222222\", \"pni\": \"de24dc73-fbd8-41be-a7d5-764c70d9da7e\"}"));
|
||||
|
||||
when(asyncCommands.setex(any(), anyLong(), any())).thenReturn(MockRedisFuture.completedFuture("OK"));
|
||||
|
||||
Optional<Account> account = accountsManager.getByPhoneNumberIdentifierAsync(pni).join();
|
||||
|
||||
assertTrue(account.isPresent());
|
||||
assertEquals(account.get().getNumber(), "+14152222222");
|
||||
assertEquals(UUID.fromString("de24dc73-fbd8-41be-a7d5-764c70d9da7e"), account.get().getPhoneNumberIdentifier());
|
||||
|
||||
verify(asyncCommands).get(eq("AccountMap::" + pni));
|
||||
verify(asyncCommands).get(eq("Account3::" + uuid));
|
||||
verifyNoMoreInteractions(asyncCommands);
|
||||
|
||||
verifyNoInteractions(accounts);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetByUsernameHashInCache() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
|
@ -287,6 +371,32 @@ class AccountsManagerTest {
|
|||
verifyNoMoreInteractions(accounts);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAccountByNumberNotInCacheAsync() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
UUID pni = UUID.randomUUID();
|
||||
Account account = AccountsHelper.generateTestAccount("+14152222222", uuid, pni, new ArrayList<>(), new byte[16]);
|
||||
|
||||
when(asyncCommands.get(eq("AccountMap::+14152222222"))).thenReturn(MockRedisFuture.completedFuture(null));
|
||||
when(asyncCommands.setex(any(), anyLong(), any())).thenReturn(MockRedisFuture.completedFuture("OK"));
|
||||
when(accounts.getByE164Async(eq("+14152222222")))
|
||||
.thenReturn(MockRedisFuture.completedFuture(Optional.of(account)));
|
||||
|
||||
Optional<Account> retrieved = accountsManager.getByE164Async("+14152222222").join();
|
||||
|
||||
assertTrue(retrieved.isPresent());
|
||||
assertSame(retrieved.get(), account);
|
||||
|
||||
verify(asyncCommands).get(eq("AccountMap::+14152222222"));
|
||||
verify(asyncCommands).setex(eq("AccountMap::+14152222222"), anyLong(), eq(uuid.toString()));
|
||||
verify(asyncCommands).setex(eq("AccountMap::" + pni), anyLong(), eq(uuid.toString()));
|
||||
verify(asyncCommands).setex(eq("Account3::" + uuid), anyLong(), anyString());
|
||||
verifyNoMoreInteractions(asyncCommands);
|
||||
|
||||
verify(accounts).getByE164Async(eq("+14152222222"));
|
||||
verifyNoMoreInteractions(accounts);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAccountByUuidNotInCache() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
|
@ -311,6 +421,32 @@ class AccountsManagerTest {
|
|||
verifyNoMoreInteractions(accounts);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAccountByUuidNotInCacheAsync() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
UUID pni = UUID.randomUUID();
|
||||
Account account = AccountsHelper.generateTestAccount("+14152222222", uuid, pni, new ArrayList<>(), new byte[16]);
|
||||
|
||||
when(asyncCommands.get(eq("Account3::" + uuid))).thenReturn(MockRedisFuture.completedFuture(null));
|
||||
when(asyncCommands.setex(any(), anyLong(), any())).thenReturn(MockRedisFuture.completedFuture("OK"));
|
||||
when(accounts.getByAccountIdentifierAsync(eq(uuid)))
|
||||
.thenReturn(CompletableFuture.completedFuture(Optional.of(account)));
|
||||
|
||||
Optional<Account> retrieved = accountsManager.getByAccountIdentifierAsync(uuid).join();
|
||||
|
||||
assertTrue(retrieved.isPresent());
|
||||
assertSame(retrieved.get(), account);
|
||||
|
||||
verify(asyncCommands).get(eq("Account3::" + uuid));
|
||||
verify(asyncCommands).setex(eq("AccountMap::+14152222222"), anyLong(), eq(uuid.toString()));
|
||||
verify(asyncCommands).setex(eq("AccountMap::" + pni), anyLong(), eq(uuid.toString()));
|
||||
verify(asyncCommands).setex(eq("Account3::" + uuid), anyLong(), anyString());
|
||||
verifyNoMoreInteractions(asyncCommands);
|
||||
|
||||
verify(accounts).getByAccountIdentifierAsync(eq(uuid));
|
||||
verifyNoMoreInteractions(accounts);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAccountByPniNotInCache() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
|
@ -336,6 +472,33 @@ class AccountsManagerTest {
|
|||
verifyNoMoreInteractions(accounts);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAccountByPniNotInCacheAsync() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
UUID pni = UUID.randomUUID();
|
||||
|
||||
Account account = AccountsHelper.generateTestAccount("+14152222222", uuid, pni, new ArrayList<>(), new byte[16]);
|
||||
|
||||
when(asyncCommands.get(eq("AccountMap::" + pni))).thenReturn(MockRedisFuture.completedFuture(null));
|
||||
when(asyncCommands.setex(any(), anyLong(), any())).thenReturn(MockRedisFuture.completedFuture("OK"));
|
||||
when(accounts.getByPhoneNumberIdentifierAsync(pni))
|
||||
.thenReturn(CompletableFuture.completedFuture(Optional.of(account)));
|
||||
|
||||
Optional<Account> retrieved = accountsManager.getByPhoneNumberIdentifierAsync(pni).join();
|
||||
|
||||
assertTrue(retrieved.isPresent());
|
||||
assertSame(retrieved.get(), account);
|
||||
|
||||
verify(asyncCommands).get(eq("AccountMap::" + pni));
|
||||
verify(asyncCommands).setex(eq("AccountMap::" + pni), anyLong(), eq(uuid.toString()));
|
||||
verify(asyncCommands).setex(eq("AccountMap::+14152222222"), anyLong(), eq(uuid.toString()));
|
||||
verify(asyncCommands).setex(eq("Account3::" + uuid), anyLong(), anyString());
|
||||
verifyNoMoreInteractions(asyncCommands);
|
||||
|
||||
verify(accounts).getByPhoneNumberIdentifierAsync(pni);
|
||||
verifyNoMoreInteractions(accounts);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAccountByUsernameHashNotInCache() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
|
@ -386,6 +549,34 @@ class AccountsManagerTest {
|
|||
verifyNoMoreInteractions(accounts);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAccountByNumberBrokenCacheAsync() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
UUID pni = UUID.randomUUID();
|
||||
Account account = AccountsHelper.generateTestAccount("+14152222222", uuid, pni, new ArrayList<>(), new byte[16]);
|
||||
|
||||
when(asyncCommands.get(eq("AccountMap::+14152222222")))
|
||||
.thenReturn(MockRedisFuture.failedFuture(new RedisException("Connection lost!")));
|
||||
|
||||
when(asyncCommands.setex(any(), anyLong(), any())).thenReturn(MockRedisFuture.completedFuture("OK"));
|
||||
|
||||
when(accounts.getByE164Async(eq("+14152222222"))).thenReturn(CompletableFuture.completedFuture(Optional.of(account)));
|
||||
|
||||
Optional<Account> retrieved = accountsManager.getByE164Async("+14152222222").join();
|
||||
|
||||
assertTrue(retrieved.isPresent());
|
||||
assertSame(retrieved.get(), account);
|
||||
|
||||
verify(asyncCommands).get(eq("AccountMap::+14152222222"));
|
||||
verify(asyncCommands).setex(eq("AccountMap::+14152222222"), anyLong(), eq(uuid.toString()));
|
||||
verify(asyncCommands).setex(eq("AccountMap::" + pni), anyLong(), eq(uuid.toString()));
|
||||
verify(asyncCommands).setex(eq("Account3::" + uuid), anyLong(), anyString());
|
||||
verifyNoMoreInteractions(asyncCommands);
|
||||
|
||||
verify(accounts).getByE164Async(eq("+14152222222"));
|
||||
verifyNoMoreInteractions(accounts);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAccountByUuidBrokenCache() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
|
@ -410,6 +601,35 @@ class AccountsManagerTest {
|
|||
verifyNoMoreInteractions(accounts);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAccountByUuidBrokenCacheAsync() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
UUID pni = UUID.randomUUID();
|
||||
Account account = AccountsHelper.generateTestAccount("+14152222222", uuid, pni, new ArrayList<>(), new byte[16]);
|
||||
|
||||
when(asyncCommands.get(eq("Account3::" + uuid)))
|
||||
.thenReturn(MockRedisFuture.failedFuture(new RedisException("Connection lost!")));
|
||||
|
||||
when(asyncCommands.setex(any(), anyLong(), any())).thenReturn(MockRedisFuture.completedFuture("OK"));
|
||||
|
||||
when(accounts.getByAccountIdentifierAsync(eq(uuid)))
|
||||
.thenReturn(CompletableFuture.completedFuture(Optional.of(account)));
|
||||
|
||||
Optional<Account> retrieved = accountsManager.getByAccountIdentifierAsync(uuid).join();
|
||||
|
||||
assertTrue(retrieved.isPresent());
|
||||
assertSame(retrieved.get(), account);
|
||||
|
||||
verify(asyncCommands).get(eq("Account3::" + uuid));
|
||||
verify(asyncCommands).setex(eq("AccountMap::+14152222222"), anyLong(), eq(uuid.toString()));
|
||||
verify(asyncCommands).setex(eq("AccountMap::" + pni), anyLong(), eq(uuid.toString()));
|
||||
verify(asyncCommands).setex(eq("Account3::" + uuid), anyLong(), anyString());
|
||||
verifyNoMoreInteractions(asyncCommands);
|
||||
|
||||
verify(accounts).getByAccountIdentifierAsync(eq(uuid));
|
||||
verifyNoMoreInteractions(accounts);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAccountByPniBrokenCache() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
|
@ -435,6 +655,36 @@ class AccountsManagerTest {
|
|||
verifyNoMoreInteractions(accounts);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAccountByPniBrokenCacheAsync() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
UUID pni = UUID.randomUUID();
|
||||
|
||||
Account account = AccountsHelper.generateTestAccount("+14152222222", uuid, pni, new ArrayList<>(), new byte[16]);
|
||||
|
||||
when(asyncCommands.get(eq("AccountMap::" + pni)))
|
||||
.thenReturn(MockRedisFuture.failedFuture(new RedisException("OH NO")));
|
||||
|
||||
when(asyncCommands.setex(any(), anyLong(), any())).thenReturn(MockRedisFuture.completedFuture("OK"));
|
||||
|
||||
when(accounts.getByPhoneNumberIdentifierAsync(pni))
|
||||
.thenReturn(CompletableFuture.completedFuture(Optional.of(account)));
|
||||
|
||||
Optional<Account> retrieved = accountsManager.getByPhoneNumberIdentifierAsync(pni).join();
|
||||
|
||||
assertTrue(retrieved.isPresent());
|
||||
assertSame(retrieved.get(), account);
|
||||
|
||||
verify(asyncCommands).get(eq("AccountMap::" + pni));
|
||||
verify(asyncCommands).setex(eq("AccountMap::" + pni), anyLong(), eq(uuid.toString()));
|
||||
verify(asyncCommands).setex(eq("AccountMap::+14152222222"), anyLong(), eq(uuid.toString()));
|
||||
verify(asyncCommands).setex(eq("Account3::" + uuid), anyLong(), anyString());
|
||||
verifyNoMoreInteractions(asyncCommands);
|
||||
|
||||
verify(accounts).getByPhoneNumberIdentifierAsync(pni);
|
||||
verifyNoMoreInteractions(accounts);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAccountByUsernameBrokenCache() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
|
|
Loading…
Reference in New Issue