From fc1d88f5bb0b46f37cd42828b22e8c776635035c Mon Sep 17 00:00:00 2001 From: Jon Chambers Date: Tue, 16 Jun 2020 10:56:17 -0400 Subject: [PATCH] Read exclusively from the cache cluster. --- .../textsecuregcm/WhisperServerService.java | 9 +- .../textsecuregcm/limits/RateLimiter.java | 10 +- .../storage/AccountDatabaseCrawlerCache.java | 22 +-- .../storage/AccountsManager.java | 33 +--- .../storage/ActiveUserCounter.java | 13 +- .../storage/PendingAccountsManager.java | 9 +- .../storage/PendingDevicesManager.java | 9 +- .../storage/ProfilesManager.java | 18 +- .../storage/UsernamesManager.java | 55 +++--- .../workers/DeleteUserCommand.java | 15 +- .../tests/storage/AccountsManagerTest.java | 186 +++++++++--------- .../tests/storage/ActiveUserCounterTest.java | 75 ++++--- .../tests/storage/ProfilesManagerTest.java | 79 ++++---- .../tests/storage/UsernamesManagerTest.java | 168 ++++++++-------- 14 files changed, 315 insertions(+), 386 deletions(-) diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java b/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java index 13418fbc9..2152563bb 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java @@ -77,7 +77,6 @@ import org.whispersystems.textsecuregcm.controllers.SecureBackupController; import org.whispersystems.textsecuregcm.controllers.SecureStorageController; import org.whispersystems.textsecuregcm.controllers.StickerController; import org.whispersystems.textsecuregcm.controllers.VoiceVerificationController; -import org.whispersystems.textsecuregcm.experiment.Experiment; import org.whispersystems.textsecuregcm.filters.TimestampResponseFilter; import org.whispersystems.textsecuregcm.limits.RateLimiters; import org.whispersystems.textsecuregcm.liquibase.NameableMigrationsBundle; @@ -291,9 +290,9 @@ public class WhisperServerService extends Application cacheCluster.withReadCluster(connection -> connection.sync().get(bucketName))); + try { + final String serialized = cacheCluster.withReadCluster(connection -> connection.sync().get(getBucketName(key))); if (serialized != null) { return LeakyBucket.fromSerialized(mapper, serialized); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/storage/AccountDatabaseCrawlerCache.java b/service/src/main/java/org/whispersystems/textsecuregcm/storage/AccountDatabaseCrawlerCache.java index 5eaa5b374..c247b53ff 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/storage/AccountDatabaseCrawlerCache.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/storage/AccountDatabaseCrawlerCache.java @@ -20,11 +20,11 @@ import io.lettuce.core.ScriptOutputType; import io.lettuce.core.SetArgs; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.whispersystems.textsecuregcm.experiment.Experiment; import org.whispersystems.textsecuregcm.redis.ClusterLuaScript; import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster; import org.whispersystems.textsecuregcm.redis.LuaScript; import org.whispersystems.textsecuregcm.redis.ReplicatedJedisPool; +import redis.clients.jedis.Jedis; import java.io.IOException; import java.util.Arrays; @@ -32,8 +32,6 @@ import java.util.List; import java.util.Optional; import java.util.UUID; -import redis.clients.jedis.Jedis; - @SuppressWarnings("OptionalUsedAsFieldOrParameterType") public class AccountDatabaseCrawlerCache { @@ -49,8 +47,6 @@ public class AccountDatabaseCrawlerCache { private final FaultTolerantRedisCluster cacheCluster; private final LuaScript unlockScript; private final ClusterLuaScript unlockClusterScript; - private final Experiment isAcceleratedExperiment = new Experiment("RedisCluster", "AccountDatabaseCrawlerCache", "isAccelerated"); - private final Experiment getLastUuidExperiment = new Experiment("RedisCluster", "AccountDatabaseCrawlerCache", "getLastUuid"); public AccountDatabaseCrawlerCache(ReplicatedJedisPool jedisPool, FaultTolerantRedisCluster cacheCluster) throws IOException { this.jedisPool = jedisPool; @@ -67,12 +63,7 @@ public class AccountDatabaseCrawlerCache { } public boolean isAccelerated() { - try (Jedis jedis = jedisPool.getWriteResource()) { - final String accelerated = jedis.get(ACCELERATE_KEY); - isAcceleratedExperiment.compareSupplierResult(accelerated, () -> cacheCluster.withReadCluster(connection -> connection.sync().get(ACCELERATE_KEY))); - - return "1".equals(accelerated); - } + return "1".equals(cacheCluster.withReadCluster(connection -> connection.sync().get(ACCELERATE_KEY))); } public boolean claimActiveWork(String workerId, long ttlMs) { @@ -101,13 +92,10 @@ public class AccountDatabaseCrawlerCache { } public Optional getLastUuid() { - try (Jedis jedis = jedisPool.getWriteResource()) { - String lastUuidString = jedis.get(LAST_UUID_KEY); - getLastUuidExperiment.compareSupplierResult(lastUuidString, () -> cacheCluster.withWriteCluster(connection -> connection.sync().get(LAST_UUID_KEY))); + final String lastUuidString = cacheCluster.withWriteCluster(connection -> connection.sync().get(LAST_UUID_KEY)); - if (lastUuidString == null) return Optional.empty(); - else return Optional.of(UUID.fromString(lastUuidString)); - } + if (lastUuidString == null) return Optional.empty(); + else return Optional.of(UUID.fromString(lastUuidString)); } public void setLastUuid(Optional lastUuid) { diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/storage/AccountsManager.java b/service/src/main/java/org/whispersystems/textsecuregcm/storage/AccountsManager.java index 37814fdef..a9388ba69 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/storage/AccountsManager.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/storage/AccountsManager.java @@ -22,13 +22,13 @@ import com.codahale.metrics.SharedMetricRegistries; import com.codahale.metrics.Timer; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import io.lettuce.core.RedisException; import io.lettuce.core.cluster.api.async.RedisAdvancedClusterAsyncCommands; import io.lettuce.core.cluster.api.sync.RedisAdvancedClusterCommands; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.whispersystems.textsecuregcm.auth.AmbiguousIdentifier; import org.whispersystems.textsecuregcm.entities.ClientContact; -import org.whispersystems.textsecuregcm.experiment.Experiment; import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster; import org.whispersystems.textsecuregcm.redis.ReplicatedJedisPool; import org.whispersystems.textsecuregcm.util.Constants; @@ -42,7 +42,6 @@ import java.util.UUID; import static com.codahale.metrics.MetricRegistry.name; import redis.clients.jedis.Jedis; -import redis.clients.jedis.exceptions.JedisException; public class AccountsManager { @@ -63,15 +62,13 @@ public class AccountsManager { private final FaultTolerantRedisCluster cacheCluster; private final DirectoryManager directory; private final ObjectMapper mapper; - private final Experiment redisClusterExperiment; - public AccountsManager(Accounts accounts, DirectoryManager directory, ReplicatedJedisPool cacheClient, FaultTolerantRedisCluster cacheCluster, Experiment redisClusterExperiment) { + public AccountsManager(Accounts accounts, DirectoryManager directory, ReplicatedJedisPool cacheClient, FaultTolerantRedisCluster cacheCluster) { this.accounts = accounts; this.directory = directory; this.cacheClient = cacheClient; this.cacheCluster = cacheCluster; this.mapper = SystemMapper.getMapper(); - this.redisClusterExperiment = redisClusterExperiment; } public boolean create(Account account) { @@ -174,37 +171,23 @@ public class AccountsManager { } private Optional redisGet(String number) { - try (Jedis jedis = cacheClient.getReadResource(); - Timer.Context ignored = redisNumberGetTimer.time()) - { - final String key = getAccountMapKey(number); + try (Timer.Context ignored = redisNumberGetTimer.time()) { + final String uuid = cacheCluster.withReadCluster(connection -> connection.sync().get(getAccountMapKey(number))); - String uuid = jedis.get(key); - redisClusterExperiment.compareSupplierResult(uuid, () -> cacheCluster.withReadCluster(connection -> connection.sync().get(key))); - - if (uuid != null) return redisGet(jedis, UUID.fromString(uuid)); + if (uuid != null) return redisGet(UUID.fromString(uuid)); else return Optional.empty(); } catch (IllegalArgumentException e) { logger.warn("Deserialization error", e); return Optional.empty(); - } catch (JedisException e) { + } catch (RedisException e) { logger.warn("Redis failure", e); return Optional.empty(); } } private Optional redisGet(UUID uuid) { - try (Jedis jedis = cacheClient.getReadResource()) { - return redisGet(jedis, uuid); - } - } - - private Optional redisGet(Jedis jedis, UUID uuid) { try (Timer.Context ignored = redisUuidGetTimer.time()) { - final String key = getAccountEntityKey(uuid); - - String json = jedis.get(key); - redisClusterExperiment.compareSupplierResult(json, () -> cacheCluster.withReadCluster(connection -> connection.sync().get(key))); + final String json = cacheCluster.withReadCluster(connection -> connection.sync().get(getAccountEntityKey(uuid))); if (json != null) { Account account = mapper.readValue(json, Account.class); @@ -217,7 +200,7 @@ public class AccountsManager { } catch (IOException e) { logger.warn("Deserialization error", e); return Optional.empty(); - } catch (JedisException e) { + } catch (RedisException e) { logger.warn("Redis failure", e); return Optional.empty(); } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/storage/ActiveUserCounter.java b/service/src/main/java/org/whispersystems/textsecuregcm/storage/ActiveUserCounter.java index 40a480ecd..7b5c51a8c 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/storage/ActiveUserCounter.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/storage/ActiveUserCounter.java @@ -21,7 +21,6 @@ import com.codahale.metrics.MetricRegistry; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.whispersystems.textsecuregcm.entities.ActiveUserTally; -import org.whispersystems.textsecuregcm.experiment.Experiment; import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster; import org.whispersystems.textsecuregcm.redis.ReplicatedJedisPool; import org.whispersystems.textsecuregcm.util.SystemMapper; @@ -52,14 +51,12 @@ public class ActiveUserCounter extends AccountDatabaseCrawlerListener { private final ReplicatedJedisPool jedisPool; private final FaultTolerantRedisCluster cacheCluster; private final ObjectMapper mapper; - private final Experiment redisClusterExperiment; - public ActiveUserCounter(MetricsFactory metricsFactory, ReplicatedJedisPool jedisPool, FaultTolerantRedisCluster cacheCluster, Experiment redisClusterExperiment) { + public ActiveUserCounter(MetricsFactory metricsFactory, ReplicatedJedisPool jedisPool, FaultTolerantRedisCluster cacheCluster) { this.metricsFactory = metricsFactory; this.jedisPool = jedisPool; this.cacheCluster = cacheCluster; this.mapper = SystemMapper.getMapper(); - this.redisClusterExperiment = redisClusterExperiment; } @Override @@ -164,8 +161,7 @@ public class ActiveUserCounter extends AccountDatabaseCrawlerListener { private void incrementTallies(UUID fromUuid, Map platformIncrements, Map countryIncrements) { try (Jedis jedis = jedisPool.getWriteResource()) { - String tallyValue = jedis.get(TALLY_KEY); - redisClusterExperiment.compareSupplierResult(tallyValue, () -> cacheCluster.withReadCluster(connection -> connection.sync().get(TALLY_KEY))); + final String tallyValue = cacheCluster.withReadCluster(connection -> connection.sync().get(TALLY_KEY)); ActiveUserTally activeUserTally; @@ -208,9 +204,8 @@ public class ActiveUserCounter extends AccountDatabaseCrawlerListener { } private ActiveUserTally getFinalTallies() { - try (Jedis jedis = jedisPool.getReadResource()) { - final String tallyJson = jedis.get(TALLY_KEY); - redisClusterExperiment.compareSupplierResult(tallyJson, () -> cacheCluster.withReadCluster(connection -> connection.sync().get(TALLY_KEY))); + try { + final String tallyJson = cacheCluster.withReadCluster(connection -> connection.sync().get(TALLY_KEY)); return mapper.readValue(tallyJson, ActiveUserTally.class); } catch (IOException e) { diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/storage/PendingAccountsManager.java b/service/src/main/java/org/whispersystems/textsecuregcm/storage/PendingAccountsManager.java index 447d4056f..2e514c476 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/storage/PendingAccountsManager.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/storage/PendingAccountsManager.java @@ -21,7 +21,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.whispersystems.textsecuregcm.auth.StoredVerificationCode; -import org.whispersystems.textsecuregcm.experiment.Experiment; import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster; import org.whispersystems.textsecuregcm.redis.ReplicatedJedisPool; import org.whispersystems.textsecuregcm.util.SystemMapper; @@ -41,7 +40,6 @@ public class PendingAccountsManager { private final ReplicatedJedisPool cacheClient; private final FaultTolerantRedisCluster cacheCluster; private final ObjectMapper mapper; - private final Experiment redisClusterExperiment = new Experiment("RedisCluster", "PendingAccountsManager"); public PendingAccountsManager(PendingAccounts pendingAccounts, ReplicatedJedisPool cacheClient, FaultTolerantRedisCluster cacheCluster) { @@ -85,11 +83,8 @@ public class PendingAccountsManager { } private Optional memcacheGet(String number) { - try (Jedis jedis = cacheClient.getReadResource()) { - final String key = CACHE_PREFIX + number; - - String json = jedis.get(key); - redisClusterExperiment.compareSupplierResult(json, () -> cacheCluster.withReadCluster(connection -> connection.sync().get(key))); + try { + final String json = cacheCluster.withReadCluster(connection -> connection.sync().get(CACHE_PREFIX + number)); if (json == null) return Optional.empty(); else return Optional.of(mapper.readValue(json, StoredVerificationCode.class)); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/storage/PendingDevicesManager.java b/service/src/main/java/org/whispersystems/textsecuregcm/storage/PendingDevicesManager.java index 7346fe99b..bae914779 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/storage/PendingDevicesManager.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/storage/PendingDevicesManager.java @@ -21,7 +21,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.whispersystems.textsecuregcm.auth.StoredVerificationCode; -import org.whispersystems.textsecuregcm.experiment.Experiment; import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster; import org.whispersystems.textsecuregcm.redis.ReplicatedJedisPool; import org.whispersystems.textsecuregcm.util.SystemMapper; @@ -41,7 +40,6 @@ public class PendingDevicesManager { private final ReplicatedJedisPool cacheClient; private final FaultTolerantRedisCluster cacheCluster; private final ObjectMapper mapper; - private final Experiment redisClusterExperiment = new Experiment("RedisCluster", "PendingDevicesManager"); public PendingDevicesManager(PendingDevices pendingDevices, ReplicatedJedisPool cacheClient, FaultTolerantRedisCluster cacheCluster) { this.pendingDevices = pendingDevices; @@ -84,11 +82,8 @@ public class PendingDevicesManager { } private Optional memcacheGet(String number) { - try (Jedis jedis = cacheClient.getReadResource()) { - final String key = CACHE_PREFIX + number; - - String json = jedis.get(key); - redisClusterExperiment.compareSupplierResult(json, () -> cacheCluster.withReadCluster(connection -> connection.sync().get(key))); + try { + final String json = cacheCluster.withReadCluster(connection -> connection.sync().get(CACHE_PREFIX + number)); if (json == null) return Optional.empty(); else return Optional.of(mapper.readValue(json, StoredVerificationCode.class)); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/storage/ProfilesManager.java b/service/src/main/java/org/whispersystems/textsecuregcm/storage/ProfilesManager.java index 2ca278dc2..26c814361 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/storage/ProfilesManager.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/storage/ProfilesManager.java @@ -2,9 +2,9 @@ package org.whispersystems.textsecuregcm.storage; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import io.lettuce.core.RedisException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.whispersystems.textsecuregcm.experiment.Experiment; import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster; import org.whispersystems.textsecuregcm.redis.ReplicatedJedisPool; import org.whispersystems.textsecuregcm.util.SystemMapper; @@ -14,7 +14,6 @@ import java.util.Optional; import java.util.UUID; import redis.clients.jedis.Jedis; -import redis.clients.jedis.exceptions.JedisException; public class ProfilesManager { @@ -26,14 +25,12 @@ public class ProfilesManager { private final ReplicatedJedisPool cacheClient; private final FaultTolerantRedisCluster cacheCluster; private final ObjectMapper mapper; - private final Experiment redisClusterExperiment; - public ProfilesManager(Profiles profiles, ReplicatedJedisPool cacheClient, FaultTolerantRedisCluster cacheCluster, Experiment redisClusterExperiment) { - this.profiles = profiles; + public ProfilesManager(Profiles profiles, ReplicatedJedisPool cacheClient, FaultTolerantRedisCluster cacheCluster) { this.cacheClient = cacheClient; + this.profiles = profiles; this.cacheCluster = cacheCluster; this.mapper = SystemMapper.getMapper(); - this.redisClusterExperiment = redisClusterExperiment; } public void set(UUID uuid, VersionedProfile versionedProfile) { @@ -70,18 +67,15 @@ public class ProfilesManager { } private Optional memcacheGet(UUID uuid, String version) { - try (Jedis jedis = cacheClient.getReadResource()) { - final String key = CACHE_PREFIX + uuid.toString(); - - String json = jedis.hget(key, version); - redisClusterExperiment.compareSupplierResult(json, () -> cacheCluster.withReadCluster(connection -> connection.sync().hget(key, version))); + try { + final String json = cacheCluster.withReadCluster(connection -> connection.sync().hget(CACHE_PREFIX + uuid.toString(), version)); if (json == null) return Optional.empty(); else return Optional.of(mapper.readValue(json, VersionedProfile.class)); } catch (IOException e) { logger.warn("Error deserializing value...", e); return Optional.empty(); - } catch (JedisException e) { + } catch (RedisException e) { logger.warn("Redis exception", e); return Optional.empty(); } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/storage/UsernamesManager.java b/service/src/main/java/org/whispersystems/textsecuregcm/storage/UsernamesManager.java index b9a1c7d62..e542c4744 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/storage/UsernamesManager.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/storage/UsernamesManager.java @@ -3,10 +3,10 @@ package org.whispersystems.textsecuregcm.storage; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.SharedMetricRegistries; import com.codahale.metrics.Timer; +import io.lettuce.core.RedisException; import io.lettuce.core.cluster.api.sync.RedisAdvancedClusterCommands; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.whispersystems.textsecuregcm.experiment.Experiment; import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster; import org.whispersystems.textsecuregcm.redis.ReplicatedJedisPool; import org.whispersystems.textsecuregcm.util.Constants; @@ -36,14 +36,12 @@ public class UsernamesManager { private final ReservedUsernames reservedUsernames; private final ReplicatedJedisPool cacheClient; private final FaultTolerantRedisCluster cacheCluster; - private final Experiment redisClusterExperiment; - public UsernamesManager(Usernames usernames, ReservedUsernames reservedUsernames, ReplicatedJedisPool cacheClient, FaultTolerantRedisCluster cacheCluster, Experiment redisClusterExperiment) { + public UsernamesManager(Usernames usernames, ReservedUsernames reservedUsernames, ReplicatedJedisPool cacheClient, FaultTolerantRedisCluster cacheCluster) { this.usernames = usernames; this.reservedUsernames = reservedUsernames; this.cacheClient = cacheClient; this.cacheCluster = cacheCluster; - this.redisClusterExperiment = redisClusterExperiment; } public boolean put(UUID uuid, String username) { @@ -116,59 +114,50 @@ public class UsernamesManager { } private void redisSet(UUID uuid, String username, boolean required) { - try (Jedis jedis = cacheClient.getWriteResource(); - Timer.Context ignored = redisSetTimer.time()) - { - final String uuidMapKey = getUuidMapKey(uuid); - final String usernameMapKey = getUsernameMapKey(username); - - final Optional maybeOldUsername = Optional.ofNullable(jedis.get(uuidMapKey)); - maybeOldUsername.ifPresent(oldUsername -> jedis.del(getUsernameMapKey(oldUsername))); - - jedis.set(uuidMapKey, username); - jedis.set(usernameMapKey, uuid.toString()); + final String uuidMapKey = getUuidMapKey(uuid); + final String usernameMapKey = getUsernameMapKey(username); + try (Timer.Context ignored = redisSetTimer.time()) { cacheCluster.useWriteCluster(connection -> { final RedisAdvancedClusterCommands commands = connection.sync(); + final Optional maybeOldUsername = Optional.ofNullable(commands.get(uuidMapKey)); + maybeOldUsername.ifPresent(oldUsername -> commands.del(getUsernameMapKey(oldUsername))); commands.set(uuidMapKey, username); commands.set(usernameMapKey, uuid.toString()); + + try (final Jedis jedis = cacheClient.getWriteResource()) { + maybeOldUsername.ifPresent(oldUsername -> jedis.del(getUsernameMapKey(oldUsername))); + + jedis.set(uuidMapKey, username); + jedis.set(usernameMapKey, uuid.toString()); + } }); - } catch (JedisException e) { + } catch (JedisException | RedisException e) { if (required) throw e; - else logger.warn("Ignoring jedis failure", e); + else logger.warn("Ignoring Redis failure", e); } } private Optional redisGet(String username) { - try (Jedis jedis = cacheClient.getReadResource(); - Timer.Context ignored = redisUsernameGetTimer.time()) - { - final String key = getUsernameMapKey(username); - - String result = jedis.get(key); - redisClusterExperiment.compareSupplierResult(result, () -> cacheCluster.withReadCluster(connection -> connection.sync().get(key))); + try (Timer.Context ignored = redisUsernameGetTimer.time()) { + final String result = cacheCluster.withReadCluster(connection -> connection.sync().get(getUsernameMapKey(username))); if (result == null) return Optional.empty(); else return Optional.of(UUID.fromString(result)); - } catch (JedisException e) { + } catch (RedisException e) { logger.warn("Redis get failure", e); return Optional.empty(); } } private Optional redisGet(UUID uuid) { - try (Jedis jedis = cacheClient.getReadResource(); - Timer.Context ignored = redisUuidGetTimer.time()) - { - final String key = getUuidMapKey(uuid); - - final String result = jedis.get(key); - redisClusterExperiment.compareSupplierResult(result, () -> cacheCluster.withReadCluster(connection -> connection.sync().get(key))); + try (Timer.Context ignored = redisUuidGetTimer.time()) { + final String result = cacheCluster.withReadCluster(connection -> connection.sync().get(getUuidMapKey(uuid))); return Optional.ofNullable(result); - } catch (JedisException e) { + } catch (RedisException e) { logger.warn("Redis get failure", e); return Optional.empty(); } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/workers/DeleteUserCommand.java b/service/src/main/java/org/whispersystems/textsecuregcm/workers/DeleteUserCommand.java index 4d842a73b..cd46d7ca2 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/workers/DeleteUserCommand.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/workers/DeleteUserCommand.java @@ -1,8 +1,10 @@ package org.whispersystems.textsecuregcm.workers; import com.fasterxml.jackson.databind.DeserializationFeature; -import io.lettuce.core.RedisURI; -import io.lettuce.core.cluster.RedisClusterClient; +import io.dropwizard.Application; +import io.dropwizard.cli.EnvironmentCommand; +import io.dropwizard.jdbi3.JdbiFactory; +import io.dropwizard.setup.Environment; import net.sourceforge.argparse4j.inf.Namespace; import net.sourceforge.argparse4j.inf.Subparser; import org.jdbi.v3.core.Jdbi; @@ -10,7 +12,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.whispersystems.textsecuregcm.WhisperServerConfiguration; import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials; -import org.whispersystems.textsecuregcm.experiment.Experiment; import org.whispersystems.textsecuregcm.providers.RedisClientFactory; import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster; import org.whispersystems.textsecuregcm.redis.ReplicatedJedisPool; @@ -25,12 +26,6 @@ import org.whispersystems.textsecuregcm.util.Base64; import java.security.SecureRandom; import java.util.Optional; -import java.util.stream.Collectors; - -import io.dropwizard.Application; -import io.dropwizard.cli.EnvironmentCommand; -import io.dropwizard.jdbi3.JdbiFactory; -import io.dropwizard.setup.Environment; public class DeleteUserCommand extends EnvironmentCommand { @@ -78,7 +73,7 @@ public class DeleteUserCommand extends EnvironmentCommand account = accountsManager.get(user); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/AccountsManagerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/AccountsManagerTest.java index acfd754d2..c0e8b9c43 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/AccountsManagerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/AccountsManagerTest.java @@ -1,13 +1,16 @@ package org.whispersystems.textsecuregcm.tests.storage; +import io.lettuce.core.RedisException; +import io.lettuce.core.cluster.api.sync.RedisAdvancedClusterCommands; import org.junit.Test; -import org.whispersystems.textsecuregcm.experiment.Experiment; import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster; import org.whispersystems.textsecuregcm.redis.ReplicatedJedisPool; import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.Accounts; import org.whispersystems.textsecuregcm.storage.AccountsManager; import org.whispersystems.textsecuregcm.storage.DirectoryManager; +import org.whispersystems.textsecuregcm.tests.util.RedisClusterHelper; +import redis.clients.jedis.Jedis; import java.util.HashSet; import java.util.Optional; @@ -17,54 +20,58 @@ import static junit.framework.TestCase.assertSame; import static junit.framework.TestCase.assertTrue; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.*; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.exceptions.JedisException; +import static org.mockito.Mockito.anyString; +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 AccountsManagerTest { @Test public void testGetAccountByNumberInCache() { - ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class ); - Jedis jedis = mock(Jedis.class ); - FaultTolerantRedisCluster cacheCluster = mock(FaultTolerantRedisCluster.class); - Accounts accounts = mock(Accounts.class ); - DirectoryManager directoryManager = mock(DirectoryManager.class ); + RedisAdvancedClusterCommands commands = mock(RedisAdvancedClusterCommands.class); + FaultTolerantRedisCluster cacheCluster = RedisClusterHelper.buildMockRedisCluster(commands); + Accounts accounts = mock(Accounts.class); + DirectoryManager directoryManager = mock(DirectoryManager.class); + + ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class); + when(cacheClient.getWriteResource()).thenReturn(mock(Jedis.class)); UUID uuid = UUID.randomUUID(); - when(cacheClient.getReadResource()).thenReturn(jedis); - when(jedis.get(eq("AccountMap::+14152222222"))).thenReturn(uuid.toString()); - when(jedis.get(eq("Account3::" + uuid.toString()))).thenReturn("{\"number\": \"+14152222222\", \"name\": \"test\"}"); + when(commands.get(eq("AccountMap::+14152222222"))).thenReturn(uuid.toString()); + when(commands.get(eq("Account3::" + uuid.toString()))).thenReturn("{\"number\": \"+14152222222\", \"name\": \"test\"}"); - AccountsManager accountsManager = new AccountsManager(accounts, directoryManager, cacheClient, cacheCluster, mock(Experiment.class)); + AccountsManager accountsManager = new AccountsManager(accounts, directoryManager, cacheClient, cacheCluster); Optional account = accountsManager.get("+14152222222"); assertTrue(account.isPresent()); assertEquals(account.get().getNumber(), "+14152222222"); assertEquals(account.get().getProfileName(), "test"); - verify(jedis, times(1)).get(eq("AccountMap::+14152222222")); - verify(jedis, times(1)).get(eq("Account3::" + uuid.toString())); - verify(jedis, times(1)).close(); - verifyNoMoreInteractions(jedis); + verify(commands, times(1)).get(eq("AccountMap::+14152222222")); + verify(commands, times(1)).get(eq("Account3::" + uuid.toString())); + verifyNoMoreInteractions(commands); verifyNoMoreInteractions(accounts); } @Test public void testGetAccountByUuidInCache() { - ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class ); - Jedis jedis = mock(Jedis.class ); - FaultTolerantRedisCluster cacheCluster = mock(FaultTolerantRedisCluster.class); - Accounts accounts = mock(Accounts.class ); - DirectoryManager directoryManager = mock(DirectoryManager.class ); + RedisAdvancedClusterCommands commands = mock(RedisAdvancedClusterCommands.class); + FaultTolerantRedisCluster cacheCluster = RedisClusterHelper.buildMockRedisCluster(commands); + Accounts accounts = mock(Accounts.class); + DirectoryManager directoryManager = mock(DirectoryManager.class); + + ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class); + when(cacheClient.getWriteResource()).thenReturn(mock(Jedis.class)); UUID uuid = UUID.randomUUID(); - when(cacheClient.getReadResource()).thenReturn(jedis); - when(jedis.get(eq("Account3::" + uuid.toString()))).thenReturn("{\"number\": \"+14152222222\", \"name\": \"test\"}"); + when(commands.get(eq("Account3::" + uuid.toString()))).thenReturn("{\"number\": \"+14152222222\", \"name\": \"test\"}"); - AccountsManager accountsManager = new AccountsManager(accounts, directoryManager, cacheClient, cacheCluster, mock(Experiment.class)); + AccountsManager accountsManager = new AccountsManager(accounts, directoryManager, cacheClient, cacheCluster); Optional account = accountsManager.get(uuid); assertTrue(account.isPresent()); @@ -72,39 +79,37 @@ public class AccountsManagerTest { assertEquals(account.get().getUuid(), uuid); assertEquals(account.get().getProfileName(), "test"); - verify(jedis, times(1)).get(eq("Account3::" + uuid.toString())); - verify(jedis, times(1)).close(); - verifyNoMoreInteractions(jedis); + verify(commands, times(1)).get(eq("Account3::" + uuid.toString())); + verifyNoMoreInteractions(commands); verifyNoMoreInteractions(accounts); } @Test public void testGetAccountByNumberNotInCache() { - ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class ); - Jedis jedis = mock(Jedis.class ); - FaultTolerantRedisCluster cacheCluster = mock(FaultTolerantRedisCluster.class); - Accounts accounts = mock(Accounts.class ); - DirectoryManager directoryManager = mock(DirectoryManager.class ); - UUID uuid = UUID.randomUUID(); - Account account = new Account("+14152222222", uuid, new HashSet<>(), new byte[16]); + RedisAdvancedClusterCommands commands = mock(RedisAdvancedClusterCommands.class); + FaultTolerantRedisCluster cacheCluster = RedisClusterHelper.buildMockRedisCluster(commands); + Accounts accounts = mock(Accounts.class); + DirectoryManager directoryManager = mock(DirectoryManager.class); + UUID uuid = UUID.randomUUID(); + Account account = new Account("+14152222222", uuid, new HashSet<>(), new byte[16]); - when(cacheClient.getReadResource()).thenReturn(jedis); - when(cacheClient.getWriteResource()).thenReturn(jedis); - when(jedis.get(eq("AccountMap::+14152222222"))).thenReturn(null); + ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class); + when(cacheClient.getWriteResource()).thenReturn(mock(Jedis.class)); + + when(commands.get(eq("AccountMap::+14152222222"))).thenReturn(null); when(accounts.get(eq("+14152222222"))).thenReturn(Optional.of(account)); - AccountsManager accountsManager = new AccountsManager(accounts, directoryManager, cacheClient, cacheCluster, mock(Experiment.class)); + AccountsManager accountsManager = new AccountsManager(accounts, directoryManager, cacheClient, cacheCluster); Optional retrieved = accountsManager.get("+14152222222"); assertTrue(retrieved.isPresent()); assertSame(retrieved.get(), account); - verify(jedis, times(1)).get(eq("AccountMap::+14152222222")); - verify(jedis, times(1)).set(eq("AccountMap::+14152222222"), eq(uuid.toString())); - verify(jedis, times(1)).set(eq("Account3::" + uuid.toString()), anyString()); - verify(jedis, times(2)).close(); - verifyNoMoreInteractions(jedis); + verify(commands, times(1)).get(eq("AccountMap::+14152222222")); + verify(commands, times(1)).set(eq("AccountMap::+14152222222"), eq(uuid.toString())); + verify(commands, times(1)).set(eq("Account3::" + uuid.toString()), anyString()); + verifyNoMoreInteractions(commands); verify(accounts, times(1)).get(eq("+14152222222")); verifyNoMoreInteractions(accounts); @@ -112,30 +117,29 @@ public class AccountsManagerTest { @Test public void testGetAccountByUuidNotInCache() { - ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class ); - Jedis jedis = mock(Jedis.class ); - FaultTolerantRedisCluster cacheCluster = mock(FaultTolerantRedisCluster.class); - Accounts accounts = mock(Accounts.class ); - DirectoryManager directoryManager = mock(DirectoryManager.class ); - UUID uuid = UUID.randomUUID(); - Account account = new Account("+14152222222", uuid, new HashSet<>(), new byte[16]); + RedisAdvancedClusterCommands commands = mock(RedisAdvancedClusterCommands.class); + FaultTolerantRedisCluster cacheCluster = RedisClusterHelper.buildMockRedisCluster(commands); + Accounts accounts = mock(Accounts.class); + DirectoryManager directoryManager = mock(DirectoryManager.class); + UUID uuid = UUID.randomUUID(); + Account account = new Account("+14152222222", uuid, new HashSet<>(), new byte[16]); - when(cacheClient.getReadResource()).thenReturn(jedis); - when(cacheClient.getWriteResource()).thenReturn(jedis); - when(jedis.get(eq("Account3::" + uuid))).thenReturn(null); + ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class); + when(cacheClient.getWriteResource()).thenReturn(mock(Jedis.class)); + + when(commands.get(eq("Account3::" + uuid))).thenReturn(null); when(accounts.get(eq(uuid))).thenReturn(Optional.of(account)); - AccountsManager accountsManager = new AccountsManager(accounts, directoryManager, cacheClient, cacheCluster, mock(Experiment.class)); + AccountsManager accountsManager = new AccountsManager(accounts, directoryManager, cacheClient, cacheCluster); Optional retrieved = accountsManager.get(uuid); assertTrue(retrieved.isPresent()); assertSame(retrieved.get(), account); - verify(jedis, times(1)).get(eq("Account3::" + uuid)); - verify(jedis, times(1)).set(eq("AccountMap::+14152222222"), eq(uuid.toString())); - verify(jedis, times(1)).set(eq("Account3::" + uuid.toString()), anyString()); - verify(jedis, times(2)).close(); - verifyNoMoreInteractions(jedis); + verify(commands, times(1)).get(eq("Account3::" + uuid)); + verify(commands, times(1)).set(eq("AccountMap::+14152222222"), eq(uuid.toString())); + verify(commands, times(1)).set(eq("Account3::" + uuid.toString()), anyString()); + verifyNoMoreInteractions(commands); verify(accounts, times(1)).get(eq(uuid)); verifyNoMoreInteractions(accounts); @@ -143,30 +147,29 @@ public class AccountsManagerTest { @Test public void testGetAccountByNumberBrokenCache() { - ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class ); - Jedis jedis = mock(Jedis.class ); - FaultTolerantRedisCluster cacheCluster = mock(FaultTolerantRedisCluster.class); - Accounts accounts = mock(Accounts.class ); - DirectoryManager directoryManager = mock(DirectoryManager.class ); - UUID uuid = UUID.randomUUID(); - Account account = new Account("+14152222222", uuid, new HashSet<>(), new byte[16]); + RedisAdvancedClusterCommands commands = mock(RedisAdvancedClusterCommands.class); + FaultTolerantRedisCluster cacheCluster = RedisClusterHelper.buildMockRedisCluster(commands); + Accounts accounts = mock(Accounts.class); + DirectoryManager directoryManager = mock(DirectoryManager.class); + UUID uuid = UUID.randomUUID(); + Account account = new Account("+14152222222", uuid, new HashSet<>(), new byte[16]); - when(cacheClient.getReadResource()).thenReturn(jedis); - when(cacheClient.getWriteResource()).thenReturn(jedis); - when(jedis.get(eq("AccountMap::+14152222222"))).thenThrow(new JedisException("Connection lost!")); + ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class); + when(cacheClient.getWriteResource()).thenReturn(mock(Jedis.class)); + + when(commands.get(eq("AccountMap::+14152222222"))).thenThrow(new RedisException("Connection lost!")); when(accounts.get(eq("+14152222222"))).thenReturn(Optional.of(account)); - AccountsManager accountsManager = new AccountsManager(accounts, directoryManager, cacheClient, cacheCluster, mock(Experiment.class)); + AccountsManager accountsManager = new AccountsManager(accounts, directoryManager, cacheClient, cacheCluster); Optional retrieved = accountsManager.get("+14152222222"); assertTrue(retrieved.isPresent()); assertSame(retrieved.get(), account); - verify(jedis, times(1)).get(eq("AccountMap::+14152222222")); - verify(jedis, times(1)).set(eq("AccountMap::+14152222222"), eq(uuid.toString())); - verify(jedis, times(1)).set(eq("Account3::" + uuid.toString()), anyString()); - verify(jedis, times(2)).close(); - verifyNoMoreInteractions(jedis); + verify(commands, times(1)).get(eq("AccountMap::+14152222222")); + verify(commands, times(1)).set(eq("AccountMap::+14152222222"), eq(uuid.toString())); + verify(commands, times(1)).set(eq("Account3::" + uuid.toString()), anyString()); + verifyNoMoreInteractions(commands); verify(accounts, times(1)).get(eq("+14152222222")); verifyNoMoreInteractions(accounts); @@ -174,30 +177,29 @@ public class AccountsManagerTest { @Test public void testGetAccountByUuidBrokenCache() { - ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class ); - Jedis jedis = mock(Jedis.class ); - FaultTolerantRedisCluster cacheCluster = mock(FaultTolerantRedisCluster.class); - Accounts accounts = mock(Accounts.class ); - DirectoryManager directoryManager = mock(DirectoryManager.class ); - UUID uuid = UUID.randomUUID(); - Account account = new Account("+14152222222", uuid, new HashSet<>(), new byte[16]); + RedisAdvancedClusterCommands commands = mock(RedisAdvancedClusterCommands.class); + FaultTolerantRedisCluster cacheCluster = RedisClusterHelper.buildMockRedisCluster(commands); + Accounts accounts = mock(Accounts.class); + DirectoryManager directoryManager = mock(DirectoryManager.class); + UUID uuid = UUID.randomUUID(); + Account account = new Account("+14152222222", uuid, new HashSet<>(), new byte[16]); - when(cacheClient.getReadResource()).thenReturn(jedis); - when(cacheClient.getWriteResource()).thenReturn(jedis); - when(jedis.get(eq("Account3::" + uuid))).thenThrow(new JedisException("Connection lost!")); + ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class); + when(cacheClient.getWriteResource()).thenReturn(mock(Jedis.class)); + + when(commands.get(eq("Account3::" + uuid))).thenThrow(new RedisException("Connection lost!")); when(accounts.get(eq(uuid))).thenReturn(Optional.of(account)); - AccountsManager accountsManager = new AccountsManager(accounts, directoryManager, cacheClient, cacheCluster, mock(Experiment.class)); + AccountsManager accountsManager = new AccountsManager(accounts, directoryManager, cacheClient, cacheCluster); Optional retrieved = accountsManager.get(uuid); assertTrue(retrieved.isPresent()); assertSame(retrieved.get(), account); - verify(jedis, times(1)).get(eq("Account3::" + uuid)); - verify(jedis, times(1)).set(eq("AccountMap::+14152222222"), eq(uuid.toString())); - verify(jedis, times(1)).set(eq("Account3::" + uuid.toString()), anyString()); - verify(jedis, times(2)).close(); - verifyNoMoreInteractions(jedis); + verify(commands, times(1)).get(eq("Account3::" + uuid)); + verify(commands, times(1)).set(eq("AccountMap::+14152222222"), eq(uuid.toString())); + verify(commands, times(1)).set(eq("Account3::" + uuid.toString()), anyString()); + verifyNoMoreInteractions(commands); verify(accounts, times(1)).get(eq(uuid)); verifyNoMoreInteractions(accounts); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/ActiveUserCounterTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/ActiveUserCounterTest.java index beb7af7c7..c7e517eab 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/ActiveUserCounterTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/ActiveUserCounterTest.java @@ -17,14 +17,14 @@ package org.whispersystems.textsecuregcm.tests.storage; -import org.whispersystems.textsecuregcm.experiment.Experiment; +import io.lettuce.core.cluster.api.sync.RedisAdvancedClusterCommands; import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster; import org.whispersystems.textsecuregcm.redis.ReplicatedJedisPool; import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.ActiveUserCounter; import org.whispersystems.textsecuregcm.storage.AccountDatabaseCrawlerRestartException; import org.whispersystems.textsecuregcm.storage.Device; -import org.whispersystems.textsecuregcm.util.Util; +import org.whispersystems.textsecuregcm.tests.util.RedisClusterHelper; import com.google.common.collect.ImmutableList; import io.dropwizard.metrics.MetricsFactory; @@ -38,7 +38,6 @@ import java.util.concurrent.TimeUnit; import java.util.Optional; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -66,12 +65,13 @@ public class ActiveUserCounterTest { private final Account iosAccount = mock(Account.class); private final Account noDeviceAccount = mock(Account.class); - private final Jedis jedis = mock(Jedis.class); - private final ReplicatedJedisPool jedisPool = mock(ReplicatedJedisPool.class); - private final FaultTolerantRedisCluster cacheCluster = mock(FaultTolerantRedisCluster.class); - private final MetricsFactory metricsFactory = mock(MetricsFactory.class); + private final RedisAdvancedClusterCommands commands = mock(RedisAdvancedClusterCommands.class); + private final FaultTolerantRedisCluster cacheCluster = RedisClusterHelper.buildMockRedisCluster(commands); + private final MetricsFactory metricsFactory = mock(MetricsFactory.class); - private final ActiveUserCounter activeUserCounter = new ActiveUserCounter(metricsFactory, jedisPool, cacheCluster, mock(Experiment.class)); + private final ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class); + + private final ActiveUserCounter activeUserCounter = new ActiveUserCounter(metricsFactory, cacheClient, cacheCluster); @Before public void setup() { @@ -99,20 +99,18 @@ public class ActiveUserCounterTest { when(noDeviceAccount.getMasterDevice()).thenReturn(Optional.ofNullable(null)); when(noDeviceAccount.getNumber()).thenReturn(ACCOUNT_NUMBER_NODEVICE); - when(jedis.get(any(String.class))).thenReturn("{\"fromNumber\":\"+\",\"platforms\":{},\"countries\":{}}"); - when(jedisPool.getWriteResource()).thenReturn(jedis); - when(jedisPool.getReadResource()).thenReturn(jedis); + when(commands.get(any(String.class))).thenReturn("{\"fromNumber\":\"+\",\"platforms\":{},\"countries\":{}}"); when(metricsFactory.getReporters()).thenReturn(ImmutableList.of()); + when(cacheClient.getWriteResource()).thenReturn(mock(Jedis.class)); } @Test public void testCrawlStart() { activeUserCounter.onCrawlStart(); - verify(jedisPool, times(1)).getWriteResource(); - verify(jedis, times(1)).del(any(String.class)); - verify(jedis, times(1)).close(); + verify(cacheCluster, times(1)).useWriteCluster(any()); + verify(commands, times(1)).del(any(String.class)); verifyZeroInteractions(iosDevice); verifyZeroInteractions(iosAccount); @@ -120,17 +118,16 @@ public class ActiveUserCounterTest { verifyZeroInteractions(androidAccount); verifyZeroInteractions(noDeviceAccount); verifyZeroInteractions(metricsFactory); - verifyNoMoreInteractions(jedis); - verifyNoMoreInteractions(jedisPool); + verifyNoMoreInteractions(commands); + verifyNoMoreInteractions(cacheCluster); } @Test public void testCrawlEnd() { activeUserCounter.onCrawlEnd(Optional.empty()); - verify(jedisPool, times(1)).getReadResource(); - verify(jedis, times(1)).get(any(String.class)); - verify(jedis, times(1)).close(); + verify(cacheCluster, times(1)).withReadCluster(any()); + verify(commands, times(1)).get(any(String.class)); verify(metricsFactory, times(1)).getReporters(); @@ -141,8 +138,8 @@ public class ActiveUserCounterTest { verifyZeroInteractions(noDeviceAccount); verifyNoMoreInteractions(metricsFactory); - verifyNoMoreInteractions(jedis); - verifyNoMoreInteractions(jedisPool); + verifyNoMoreInteractions(commands); + verifyNoMoreInteractions(cacheCluster); } @@ -157,10 +154,10 @@ public class ActiveUserCounterTest { verify(iosDevice, times(1)).getApnId(); verify(iosDevice, times(0)).getGcmId(); - verify(jedisPool, times(1)).getWriteResource(); - verify(jedis, times(1)).get(any(String.class)); - verify(jedis, times(1)).set(any(String.class), eq("{\"fromUuid\":\""+UUID_IOS.toString()+"\",\"platforms\":{\"ios\":[1,1,1,1,1]},\"countries\":{\"1\":[1,1,1,1,1]}}")); - verify(jedis, times(1)).close(); + verify(cacheCluster, times(1)).withReadCluster(any()); + verify(cacheCluster, times(1)).useWriteCluster(any()); + verify(commands, times(1)).get(any(String.class)); + verify(commands, times(1)).set(any(String.class), eq("{\"fromUuid\":\""+UUID_IOS.toString()+"\",\"platforms\":{\"ios\":[1,1,1,1,1]},\"countries\":{\"1\":[1,1,1,1,1]}}")); verify(metricsFactory, times(0)).getReporters(); @@ -171,8 +168,8 @@ public class ActiveUserCounterTest { verifyNoMoreInteractions(iosDevice); verifyNoMoreInteractions(iosAccount); - verifyNoMoreInteractions(jedis); - verifyNoMoreInteractions(jedisPool); + verifyNoMoreInteractions(commands); + verifyNoMoreInteractions(cacheCluster); } @Test @@ -181,10 +178,10 @@ public class ActiveUserCounterTest { verify(noDeviceAccount, times(1)).getMasterDevice(); - verify(jedisPool, times(1)).getWriteResource(); - verify(jedis, times(1)).get(eq(TALLY_KEY)); - verify(jedis, times(1)).set(any(String.class), eq("{\"fromUuid\":\""+UUID_NODEVICE+"\",\"platforms\":{},\"countries\":{}}")); - verify(jedis, times(1)).close(); + verify(cacheCluster, times(1)).withReadCluster(any()); + verify(cacheCluster, times(1)).useWriteCluster(any()); + verify(commands, times(1)).get(eq(TALLY_KEY)); + verify(commands, times(1)).set(any(String.class), eq("{\"fromUuid\":\""+UUID_NODEVICE+"\",\"platforms\":{},\"countries\":{}}")); verify(metricsFactory, times(0)).getReporters(); @@ -195,8 +192,8 @@ public class ActiveUserCounterTest { verifyZeroInteractions(noDeviceAccount); verifyZeroInteractions(metricsFactory); - verifyNoMoreInteractions(jedis); - verifyNoMoreInteractions(jedisPool); + verifyNoMoreInteractions(commands); + verifyNoMoreInteractions(cacheCluster); } @Test @@ -217,10 +214,10 @@ public class ActiveUserCounterTest { verify(androidDevice, times(1)).getApnId(); verify(androidDevice, times(1)).getGcmId(); - verify(jedisPool, times(1)).getWriteResource(); - verify(jedis, times(1)).get(eq(TALLY_KEY)); - verify(jedis, times(1)).set(any(String.class), eq("{\"fromUuid\":\""+UUID_IOS+"\",\"platforms\":{\"android\":[0,0,0,1,1],\"ios\":[1,1,1,1,1]},\"countries\":{\"55\":[0,0,0,1,1],\"1\":[1,1,1,1,1]}}")); - verify(jedis, times(1)).close(); + verify(cacheCluster, times(1)).withReadCluster(any()); + verify(cacheCluster, times(1)).useWriteCluster(any()); + verify(commands, times(1)).get(eq(TALLY_KEY)); + verify(commands, times(1)).set(any(String.class), eq("{\"fromUuid\":\""+UUID_IOS+"\",\"platforms\":{\"android\":[0,0,0,1,1],\"ios\":[1,1,1,1,1]},\"countries\":{\"55\":[0,0,0,1,1],\"1\":[1,1,1,1,1]}}")); verify(metricsFactory, times(0)).getReporters(); @@ -231,8 +228,8 @@ public class ActiveUserCounterTest { verifyNoMoreInteractions(androidDevice); verifyNoMoreInteractions(androidAccount); verifyNoMoreInteractions(noDeviceAccount); - verifyNoMoreInteractions(jedis); - verifyNoMoreInteractions(jedisPool); + verifyNoMoreInteractions(commands); + verifyNoMoreInteractions(cacheCluster); } } diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/ProfilesManagerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/ProfilesManagerTest.java index aaf0c9e9f..e6ff48ffb 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/ProfilesManagerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/ProfilesManagerTest.java @@ -1,13 +1,16 @@ package org.whispersystems.textsecuregcm.tests.storage; +import io.lettuce.core.RedisException; +import io.lettuce.core.cluster.api.sync.RedisAdvancedClusterCommands; import org.junit.Test; -import org.whispersystems.textsecuregcm.experiment.Experiment; import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster; import org.whispersystems.textsecuregcm.redis.ReplicatedJedisPool; import org.whispersystems.textsecuregcm.storage.Profiles; import org.whispersystems.textsecuregcm.storage.ProfilesManager; import org.whispersystems.textsecuregcm.storage.VersionedProfile; +import org.whispersystems.textsecuregcm.tests.util.RedisClusterHelper; import org.whispersystems.textsecuregcm.util.Base64; +import redis.clients.jedis.Jedis; import java.util.Optional; import java.util.UUID; @@ -18,25 +21,28 @@ import static org.assertj.core.api.Java6Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.*; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.exceptions.JedisException; +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 ProfilesManagerTest { @Test public void testGetProfileInCache() { - ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class); - Jedis jedis = mock(Jedis.class ); - Profiles profiles = mock(Profiles.class ); - FaultTolerantRedisCluster cacheCluster = mock(FaultTolerantRedisCluster.class); + RedisAdvancedClusterCommands commands = mock(RedisAdvancedClusterCommands.class); + FaultTolerantRedisCluster cacheCluster = RedisClusterHelper.buildMockRedisCluster(commands); + Profiles profiles = mock(Profiles.class); + + ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class); + when(cacheClient.getWriteResource()).thenReturn(mock(Jedis.class)); UUID uuid = UUID.randomUUID(); - when(cacheClient.getReadResource()).thenReturn(jedis); - when(jedis.hget(eq("profiles::" + uuid.toString()), eq("someversion"))).thenReturn("{\"version\": \"someversion\", \"name\": \"somename\", \"avatar\": \"someavatar\", \"commitment\":\"" + Base64.encodeBytes("somecommitment".getBytes()) + "\"}"); + when(commands.hget(eq("profiles::" + uuid.toString()), eq("someversion"))).thenReturn("{\"version\": \"someversion\", \"name\": \"somename\", \"avatar\": \"someavatar\", \"commitment\":\"" + Base64.encodeBytes("somecommitment".getBytes()) + "\"}"); - ProfilesManager profilesManager = new ProfilesManager(profiles, cacheClient, cacheCluster, mock(Experiment.class)); + ProfilesManager profilesManager = new ProfilesManager(profiles, cacheClient, cacheCluster); Optional profile = profilesManager.get(uuid, "someversion"); assertTrue(profile.isPresent()); @@ -44,37 +50,35 @@ public class ProfilesManagerTest { assertEquals(profile.get().getAvatar(), "someavatar"); assertThat(profile.get().getCommitment()).isEqualTo("somecommitment".getBytes()); - verify(jedis, times(1)).hget(eq("profiles::" + uuid.toString()), eq("someversion")); - verify(jedis, times(1)).close(); - verifyNoMoreInteractions(jedis); + verify(commands, times(1)).hget(eq("profiles::" + uuid.toString()), eq("someversion")); + verifyNoMoreInteractions(commands); verifyNoMoreInteractions(profiles); } @Test public void testGetProfileNotInCache() { - ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class); - Jedis jedis = mock(Jedis.class ); - Profiles profiles = mock(Profiles.class ); - FaultTolerantRedisCluster cacheCluster = mock(FaultTolerantRedisCluster.class); + RedisAdvancedClusterCommands commands = mock(RedisAdvancedClusterCommands.class); + FaultTolerantRedisCluster cacheCluster = RedisClusterHelper.buildMockRedisCluster(commands); + Profiles profiles = mock(Profiles.class); + + ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class); + when(cacheClient.getWriteResource()).thenReturn(mock(Jedis.class)); UUID uuid = UUID.randomUUID(); VersionedProfile profile = new VersionedProfile("someversion", "somename", "someavatar", "somecommitment".getBytes()); - when(cacheClient.getReadResource()).thenReturn(jedis); - when(cacheClient.getWriteResource()).thenReturn(jedis); - when(jedis.hget(eq("profiles::" + uuid.toString()), eq("someversion"))).thenReturn(null); + when(commands.hget(eq("profiles::" + uuid.toString()), eq("someversion"))).thenReturn(null); when(profiles.get(eq(uuid), eq("someversion"))).thenReturn(Optional.of(profile)); - ProfilesManager profilesManager = new ProfilesManager(profiles, cacheClient, cacheCluster, mock(Experiment.class)); + ProfilesManager profilesManager = new ProfilesManager(profiles, cacheClient, cacheCluster); Optional retrieved = profilesManager.get(uuid, "someversion"); assertTrue(retrieved.isPresent()); assertSame(retrieved.get(), profile); - verify(jedis, times(1)).hget(eq("profiles::" + uuid.toString()), eq("someversion")); - verify(jedis, times(1)).hset(eq("profiles::" + uuid.toString()), eq("someversion"), anyString()); - verify(jedis, times(2)).close(); - verifyNoMoreInteractions(jedis); + verify(commands, times(1)).hget(eq("profiles::" + uuid.toString()), eq("someversion")); + verify(commands, times(1)).hset(eq("profiles::" + uuid.toString()), eq("someversion"), anyString()); + verifyNoMoreInteractions(commands); verify(profiles, times(1)).get(eq(uuid), eq("someversion")); verifyNoMoreInteractions(profiles); @@ -82,29 +86,28 @@ public class ProfilesManagerTest { @Test public void testGetProfileBrokenCache() { - ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class); - Jedis jedis = mock(Jedis.class ); - Profiles profiles = mock(Profiles.class ); - FaultTolerantRedisCluster cacheCluster = mock(FaultTolerantRedisCluster.class); + RedisAdvancedClusterCommands commands = mock(RedisAdvancedClusterCommands.class); + FaultTolerantRedisCluster cacheCluster = RedisClusterHelper.buildMockRedisCluster(commands); + Profiles profiles = mock(Profiles.class); + + ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class); + when(cacheClient.getWriteResource()).thenReturn(mock(Jedis.class)); UUID uuid = UUID.randomUUID(); VersionedProfile profile = new VersionedProfile("someversion", "somename", "someavatar", "somecommitment".getBytes()); - when(cacheClient.getReadResource()).thenReturn(jedis); - when(cacheClient.getWriteResource()).thenReturn(jedis); - when(jedis.hget(eq("profiles::" + uuid.toString()), eq("someversion"))).thenThrow(new JedisException("Connection lost")); + when(commands.hget(eq("profiles::" + uuid.toString()), eq("someversion"))).thenThrow(new RedisException("Connection lost")); when(profiles.get(eq(uuid), eq("someversion"))).thenReturn(Optional.of(profile)); - ProfilesManager profilesManager = new ProfilesManager(profiles, cacheClient, cacheCluster, mock(Experiment.class)); + ProfilesManager profilesManager = new ProfilesManager(profiles, cacheClient, cacheCluster); Optional retrieved = profilesManager.get(uuid, "someversion"); assertTrue(retrieved.isPresent()); assertSame(retrieved.get(), profile); - verify(jedis, times(1)).hget(eq("profiles::" + uuid.toString()), eq("someversion")); - verify(jedis, times(1)).hset(eq("profiles::" + uuid.toString()), eq("someversion"), anyString()); - verify(jedis, times(2)).close(); - verifyNoMoreInteractions(jedis); + verify(commands, times(1)).hget(eq("profiles::" + uuid.toString()), eq("someversion")); + verify(commands, times(1)).hset(eq("profiles::" + uuid.toString()), eq("someversion"), anyString()); + verifyNoMoreInteractions(commands); verify(profiles, times(1)).get(eq(uuid), eq("someversion")); verifyNoMoreInteractions(profiles); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/UsernamesManagerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/UsernamesManagerTest.java index b3b09ca39..e2fd4f7bc 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/UsernamesManagerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/UsernamesManagerTest.java @@ -1,12 +1,15 @@ package org.whispersystems.textsecuregcm.tests.storage; +import io.lettuce.core.RedisException; +import io.lettuce.core.cluster.api.sync.RedisAdvancedClusterCommands; import org.junit.Test; -import org.whispersystems.textsecuregcm.experiment.Experiment; import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster; import org.whispersystems.textsecuregcm.redis.ReplicatedJedisPool; import org.whispersystems.textsecuregcm.storage.ReservedUsernames; import org.whispersystems.textsecuregcm.storage.Usernames; import org.whispersystems.textsecuregcm.storage.UsernamesManager; +import org.whispersystems.textsecuregcm.tests.util.RedisClusterHelper; +import redis.clients.jedis.Jedis; import java.util.Optional; import java.util.UUID; @@ -15,91 +18,91 @@ import static junit.framework.TestCase.assertSame; import static junit.framework.TestCase.assertTrue; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.*; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.exceptions.JedisException; +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 UsernamesManagerTest { @Test public void testGetByUsernameInCache() { - ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class); - Jedis jedis = mock(Jedis.class); - FaultTolerantRedisCluster cacheCluster = mock(FaultTolerantRedisCluster.class); - Usernames usernames = mock(Usernames.class); - ReservedUsernames reserved = mock(ReservedUsernames.class); + RedisAdvancedClusterCommands commands = mock(RedisAdvancedClusterCommands.class); + FaultTolerantRedisCluster cacheCluster = RedisClusterHelper.buildMockRedisCluster(commands); + Usernames usernames = mock(Usernames.class); + ReservedUsernames reserved = mock(ReservedUsernames.class); + + ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class); + when(cacheClient.getWriteResource()).thenReturn(mock(Jedis.class)); UUID uuid = UUID.randomUUID(); - when(cacheClient.getReadResource()).thenReturn(jedis); - when(jedis.get(eq("UsernameByUsername::n00bkiller"))).thenReturn(uuid.toString()); + when(commands.get(eq("UsernameByUsername::n00bkiller"))).thenReturn(uuid.toString()); - UsernamesManager usernamesManager = new UsernamesManager(usernames, reserved, cacheClient, cacheCluster, mock(Experiment.class)); + UsernamesManager usernamesManager = new UsernamesManager(usernames, reserved, cacheClient, cacheCluster); Optional retrieved = usernamesManager.get("n00bkiller"); assertTrue(retrieved.isPresent()); assertEquals(retrieved.get(), uuid); - verify(jedis, times(1)).get(eq("UsernameByUsername::n00bkiller")); - verify(jedis, times(1)).close(); - verifyNoMoreInteractions(jedis); + verify(commands, times(1)).get(eq("UsernameByUsername::n00bkiller")); + verifyNoMoreInteractions(commands); verifyNoMoreInteractions(usernames); } @Test public void testGetByUuidInCache() { - ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class); - Jedis jedis = mock(Jedis.class); - FaultTolerantRedisCluster cacheCluster = mock(FaultTolerantRedisCluster.class); - Usernames usernames = mock(Usernames.class); - ReservedUsernames reserved = mock(ReservedUsernames.class); + RedisAdvancedClusterCommands commands = mock(RedisAdvancedClusterCommands.class); + FaultTolerantRedisCluster cacheCluster = RedisClusterHelper.buildMockRedisCluster(commands); + Usernames usernames = mock(Usernames.class); + ReservedUsernames reserved = mock(ReservedUsernames.class); + + ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class); + when(cacheClient.getWriteResource()).thenReturn(mock(Jedis.class)); UUID uuid = UUID.randomUUID(); - when(cacheClient.getReadResource()).thenReturn(jedis); - when(jedis.get(eq("UsernameByUuid::" + uuid.toString()))).thenReturn("n00bkiller"); + when(commands.get(eq("UsernameByUuid::" + uuid.toString()))).thenReturn("n00bkiller"); - UsernamesManager usernamesManager = new UsernamesManager(usernames, reserved, cacheClient, cacheCluster, mock(Experiment.class)); + UsernamesManager usernamesManager = new UsernamesManager(usernames, reserved, cacheClient, cacheCluster); Optional retrieved = usernamesManager.get(uuid); assertTrue(retrieved.isPresent()); assertEquals(retrieved.get(), "n00bkiller"); - verify(jedis, times(1)).get(eq("UsernameByUuid::" + uuid.toString())); - verify(jedis, times(1)).close(); - verifyNoMoreInteractions(jedis); + verify(commands, times(1)).get(eq("UsernameByUuid::" + uuid.toString())); + verifyNoMoreInteractions(commands); verifyNoMoreInteractions(usernames); } @Test public void testGetByUsernameNotInCache() { - ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class); - Jedis jedis = mock(Jedis.class); - FaultTolerantRedisCluster cacheCluster = mock(FaultTolerantRedisCluster.class); - Usernames usernames = mock(Usernames.class); - ReservedUsernames reserved = mock(ReservedUsernames.class); + RedisAdvancedClusterCommands commands = mock(RedisAdvancedClusterCommands.class); + FaultTolerantRedisCluster cacheCluster = RedisClusterHelper.buildMockRedisCluster(commands); + Usernames usernames = mock(Usernames.class); + ReservedUsernames reserved = mock(ReservedUsernames.class); - UUID uuid = UUID.randomUUID(); + ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class); + when(cacheClient.getWriteResource()).thenReturn(mock(Jedis.class)); + UUID uuid = UUID.randomUUID(); - when(cacheClient.getReadResource()).thenReturn(jedis); - when(cacheClient.getWriteResource()).thenReturn(jedis); - when(jedis.get(eq("UsernameByUsername::n00bkiller"))).thenReturn(null); + when(commands.get(eq("UsernameByUsername::n00bkiller"))).thenReturn(null); when(usernames.get(eq("n00bkiller"))).thenReturn(Optional.of(uuid)); - UsernamesManager usernamesManager = new UsernamesManager(usernames, reserved, cacheClient, cacheCluster, mock(Experiment.class)); + UsernamesManager usernamesManager = new UsernamesManager(usernames, reserved, cacheClient, cacheCluster); Optional retrieved = usernamesManager.get("n00bkiller"); assertTrue(retrieved.isPresent()); assertSame(retrieved.get(), uuid); - verify(jedis, times(1)).get(eq("UsernameByUsername::n00bkiller")); - verify(jedis, times(1)).set(eq("UsernameByUsername::n00bkiller"), eq(uuid.toString())); - verify(jedis, times(1)).set(eq("UsernameByUuid::" + uuid.toString()), eq("n00bkiller")); - verify(jedis, times(1)).get(eq("UsernameByUuid::" + uuid.toString())); - verify(jedis, times(2)).close(); - verifyNoMoreInteractions(jedis); + verify(commands, times(1)).get(eq("UsernameByUsername::n00bkiller")); + verify(commands, times(1)).set(eq("UsernameByUsername::n00bkiller"), eq(uuid.toString())); + verify(commands, times(1)).set(eq("UsernameByUuid::" + uuid.toString()), eq("n00bkiller")); + verify(commands, times(1)).get(eq("UsernameByUuid::" + uuid.toString())); + verifyNoMoreInteractions(commands); verify(usernames, times(1)).get(eq("n00bkiller")); verifyNoMoreInteractions(usernames); @@ -107,30 +110,29 @@ public class UsernamesManagerTest { @Test public void testGetByUuidNotInCache() { - ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class); - Jedis jedis = mock(Jedis.class); - FaultTolerantRedisCluster cacheCluster = mock(FaultTolerantRedisCluster.class); - Usernames usernames = mock(Usernames.class); - ReservedUsernames reserved = mock(ReservedUsernames.class); + RedisAdvancedClusterCommands commands = mock(RedisAdvancedClusterCommands.class); + FaultTolerantRedisCluster cacheCluster = RedisClusterHelper.buildMockRedisCluster(commands); + Usernames usernames = mock(Usernames.class); + ReservedUsernames reserved = mock(ReservedUsernames.class); + + ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class); + when(cacheClient.getWriteResource()).thenReturn(mock(Jedis.class)); UUID uuid = UUID.randomUUID(); - when(cacheClient.getReadResource()).thenReturn(jedis); - when(cacheClient.getWriteResource()).thenReturn(jedis); - when(jedis.get(eq("UsernameByUuid::" + uuid.toString()))).thenReturn(null); + when(commands.get(eq("UsernameByUuid::" + uuid.toString()))).thenReturn(null); when(usernames.get(eq(uuid))).thenReturn(Optional.of("n00bkiller")); - UsernamesManager usernamesManager = new UsernamesManager(usernames, reserved, cacheClient, cacheCluster, mock(Experiment.class)); + UsernamesManager usernamesManager = new UsernamesManager(usernames, reserved, cacheClient, cacheCluster); Optional retrieved = usernamesManager.get(uuid); assertTrue(retrieved.isPresent()); assertEquals(retrieved.get(), "n00bkiller"); - verify(jedis, times(2)).get(eq("UsernameByUuid::" + uuid)); - verify(jedis, times(1)).set(eq("UsernameByUuid::" + uuid), eq("n00bkiller")); - verify(jedis, times(1)).set(eq("UsernameByUsername::n00bkiller"), eq(uuid.toString())); - verify(jedis, times(2)).close(); - verifyNoMoreInteractions(jedis); + verify(commands, times(2)).get(eq("UsernameByUuid::" + uuid)); + verify(commands, times(1)).set(eq("UsernameByUuid::" + uuid), eq("n00bkiller")); + verify(commands, times(1)).set(eq("UsernameByUsername::n00bkiller"), eq(uuid.toString())); + verifyNoMoreInteractions(commands); verify(usernames, times(1)).get(eq(uuid)); verifyNoMoreInteractions(usernames); @@ -138,31 +140,30 @@ public class UsernamesManagerTest { @Test public void testGetByUsernameBrokenCache() { - ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class); - Jedis jedis = mock(Jedis.class); - FaultTolerantRedisCluster cacheCluster = mock(FaultTolerantRedisCluster.class); - Usernames usernames = mock(Usernames.class); - ReservedUsernames reserved = mock(ReservedUsernames.class); + RedisAdvancedClusterCommands commands = mock(RedisAdvancedClusterCommands.class); + FaultTolerantRedisCluster cacheCluster = RedisClusterHelper.buildMockRedisCluster(commands); + Usernames usernames = mock(Usernames.class); + ReservedUsernames reserved = mock(ReservedUsernames.class); + + ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class); + when(cacheClient.getWriteResource()).thenReturn(mock(Jedis.class)); UUID uuid = UUID.randomUUID(); - when(cacheClient.getReadResource()).thenReturn(jedis); - when(cacheClient.getWriteResource()).thenReturn(jedis); - when(jedis.get(eq("UsernameByUsername::n00bkiller"))).thenThrow(new JedisException("Connection lost!")); + when(commands.get(eq("UsernameByUsername::n00bkiller"))).thenThrow(new RedisException("Connection lost!")); when(usernames.get(eq("n00bkiller"))).thenReturn(Optional.of(uuid)); - UsernamesManager usernamesManager = new UsernamesManager(usernames, reserved, cacheClient, cacheCluster, mock(Experiment.class)); + UsernamesManager usernamesManager = new UsernamesManager(usernames, reserved, cacheClient, cacheCluster); Optional retrieved = usernamesManager.get("n00bkiller"); assertTrue(retrieved.isPresent()); assertEquals(retrieved.get(), uuid); - verify(jedis, times(1)).get(eq("UsernameByUsername::n00bkiller")); - verify(jedis, times(1)).set(eq("UsernameByUsername::n00bkiller"), eq(uuid.toString())); - verify(jedis, times(1)).set(eq("UsernameByUuid::" + uuid.toString()), eq("n00bkiller")); - verify(jedis, times(1)).get(eq("UsernameByUuid::" + uuid.toString())); - verify(jedis, times(2)).close(); - verifyNoMoreInteractions(jedis); + verify(commands, times(1)).get(eq("UsernameByUsername::n00bkiller")); + verify(commands, times(1)).set(eq("UsernameByUsername::n00bkiller"), eq(uuid.toString())); + verify(commands, times(1)).set(eq("UsernameByUuid::" + uuid.toString()), eq("n00bkiller")); + verify(commands, times(1)).get(eq("UsernameByUuid::" + uuid.toString())); + verifyNoMoreInteractions(commands); verify(usernames, times(1)).get(eq("n00bkiller")); verifyNoMoreInteractions(usernames); @@ -170,28 +171,27 @@ public class UsernamesManagerTest { @Test public void testGetAccountByUuidBrokenCache() { - ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class); - Jedis jedis = mock(Jedis.class); - FaultTolerantRedisCluster cacheCluster = mock(FaultTolerantRedisCluster.class); - Usernames usernames = mock(Usernames.class); - ReservedUsernames reserved = mock(ReservedUsernames.class); + RedisAdvancedClusterCommands commands = mock(RedisAdvancedClusterCommands.class); + FaultTolerantRedisCluster cacheCluster = RedisClusterHelper.buildMockRedisCluster(commands); + Usernames usernames = mock(Usernames.class); + ReservedUsernames reserved = mock(ReservedUsernames.class); - UUID uuid = UUID.randomUUID(); + ReplicatedJedisPool cacheClient = mock(ReplicatedJedisPool.class); + when(cacheClient.getWriteResource()).thenReturn(mock(Jedis.class)); - when(cacheClient.getReadResource()).thenReturn(jedis); - when(cacheClient.getWriteResource()).thenReturn(jedis); - when(jedis.get(eq("UsernameByUuid::" + uuid))).thenThrow(new JedisException("Connection lost!")); + UUID uuid = UUID.randomUUID(); + + when(commands.get(eq("UsernameByUuid::" + uuid))).thenThrow(new RedisException("Connection lost!")); when(usernames.get(eq(uuid))).thenReturn(Optional.of("n00bkiller")); - UsernamesManager usernamesManager = new UsernamesManager(usernames, reserved, cacheClient, cacheCluster, mock(Experiment.class)); + UsernamesManager usernamesManager = new UsernamesManager(usernames, reserved, cacheClient, cacheCluster); Optional retrieved = usernamesManager.get(uuid); assertTrue(retrieved.isPresent()); assertEquals(retrieved.get(), "n00bkiller"); - verify(jedis, times(2)).get(eq("UsernameByUuid::" + uuid)); - verify(jedis, times(2)).close(); - verifyNoMoreInteractions(jedis); + verify(commands, times(2)).get(eq("UsernameByUuid::" + uuid)); + verifyNoMoreInteractions(commands); verify(usernames, times(1)).get(eq(uuid)); verifyNoMoreInteractions(usernames);