Add call chain and mismatch check for push token timestamp

This commit is contained in:
Chris Eager 2021-05-26 16:41:32 -05:00 committed by Chris Eager
parent 50c4df4f45
commit 3e61b5c49d
2 changed files with 38 additions and 2 deletions

View File

@ -21,12 +21,16 @@ import io.micrometer.core.instrument.Metrics;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
import net.logstash.logback.argument.StructuredArguments;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.auth.AmbiguousIdentifier;
@ -464,6 +468,10 @@ public class AccountsManager {
if (!Objects.equals(databaseAccount.getMasterDevice().get().getSignedPreKey(), dynamoAccount.getMasterDevice().get().getSignedPreKey())) {
return Optional.of("masterDeviceSignedPreKey");
}
if (!Objects.equals(databaseAccount.getMasterDevice().get().getPushTimestamp(), dynamoAccount.getMasterDevice().get().getPushTimestamp())) {
return Optional.of("masterDevicePushTimestamp");
}
}
if (!serializedEquals(databaseAccount.getDevices(), dynamoAccount.getDevices())) {
@ -520,11 +528,26 @@ public class AccountsManager {
if (maybeUUid.isPresent()
&& dynamicConfigurationManager.getConfiguration().getAccountsDynamoDbMigrationConfiguration().isLogMismatches()) {
logger.info("Mismatched {} for {}", mismatchDescription, maybeUUid.get());
final String abbreviatedCallChain = getAbbreviatedCallChain(new RuntimeException().getStackTrace());
logger.info("Mismatched account data: {}", StructuredArguments.entries(Map.of(
"type", mismatchDescription,
"uuid", maybeUUid.get(),
"callChain", abbreviatedCallChain
)));
}
});
}
private String getAbbreviatedCallChain(final StackTraceElement[] stackTrace) {
return Arrays.stream(stackTrace)
.filter(stackTraceElement -> stackTraceElement.getClassName().contains("org.whispersystems"))
.filter(stackTraceElement -> !(stackTraceElement.getClassName().endsWith("AccountsManager") && stackTraceElement.getMethodName().contains("compare")))
.map(stackTraceElement -> StringUtils.substringAfterLast(stackTraceElement.getClassName(), ".") + ":" + stackTraceElement.getMethodName())
.collect(Collectors.joining(" -> "));
}
private static abstract class AccountComparisonMixin extends Account {
@JsonIgnore

View File

@ -385,7 +385,7 @@ class AccountsManagerTest {
}
@Test
void testCompareAccounts() {
void testCompareAccounts() throws Exception {
RedisAdvancedClusterCommands<String, String> commands = mock(RedisAdvancedClusterCommands.class);
FaultTolerantRedisCluster cacheCluster = RedisClusterHelper.buildMockRedisCluster(commands);
Accounts accounts = mock(Accounts.class);
@ -434,11 +434,24 @@ class AccountsManagerTest {
assertEquals(Optional.of("devices"), accountsManager.compareAccounts(Optional.of(a1), Optional.of(a2)));
device1.setName(null);
device1.setSignedPreKey(new SignedPreKey(1L, "123", "456"));
device2.setSignedPreKey(new SignedPreKey(2L, "123", "456"));
assertEquals(Optional.of("masterDeviceSignedPreKey"), accountsManager.compareAccounts(Optional.of(a1), Optional.of(a2)));
device1.setSignedPreKey(null);
device2.setSignedPreKey(null);
assertEquals(Optional.empty(), accountsManager.compareAccounts(Optional.of(a1), Optional.of(a2)));
device1.setApnId("123");
Thread.sleep(5);
device2.setApnId("123");
assertEquals(Optional.of("masterDevicePushTimestamp"), accountsManager.compareAccounts(Optional.of(a1), Optional.of(a2)));
a1.removeDevice(1L);
a2.removeDevice(1L);