mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-21 02:37:59 +01:00
Add plumbing to roll out binary service IDs/UUIDs on envelopes to internal users
This commit is contained in:
@@ -5,9 +5,21 @@
|
||||
|
||||
package org.whispersystems.textsecuregcm.storage;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.whispersystems.textsecuregcm.entities.MessageProtos;
|
||||
import org.whispersystems.textsecuregcm.experiment.ExperimentEnrollmentManager;
|
||||
import org.whispersystems.textsecuregcm.grpc.ServiceIdentifierUtil;
|
||||
import org.whispersystems.textsecuregcm.identity.AciServiceIdentifier;
|
||||
import org.whispersystems.textsecuregcm.identity.IdentityType;
|
||||
@@ -16,15 +28,15 @@ import org.whispersystems.textsecuregcm.identity.ServiceIdentifier;
|
||||
import org.whispersystems.textsecuregcm.util.TestRandomUtil;
|
||||
import org.whispersystems.textsecuregcm.util.UUIDUtil;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class EnvelopeUtilTest {
|
||||
|
||||
@Test
|
||||
void compressExpand() {
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
void compressExpand(final boolean includeBinaryServiceIdentifiers) {
|
||||
final ExperimentEnrollmentManager experimentEnrollmentManager = mock(ExperimentEnrollmentManager.class);
|
||||
when(experimentEnrollmentManager.isEnrolled(any(UUID.class), eq(EnvelopeUtil.INCLUDE_BINARY_SERVICE_ID_EXPERIMENT_NAME)))
|
||||
.thenReturn(includeBinaryServiceIdentifiers);
|
||||
|
||||
{
|
||||
final MessageProtos.Envelope compressibleFieldsNullMessage = generateRandomMessageBuilder().build();
|
||||
final MessageProtos.Envelope compressed = EnvelopeUtil.compress(compressibleFieldsNullMessage);
|
||||
@@ -38,7 +50,7 @@ class EnvelopeUtilTest {
|
||||
assertFalse(compressed.hasUpdatedPni());
|
||||
assertFalse(compressed.hasUpdatedPniBinary());
|
||||
|
||||
final MessageProtos.Envelope expanded = EnvelopeUtil.expand(compressed);
|
||||
final MessageProtos.Envelope expanded = EnvelopeUtil.expand(compressed, experimentEnrollmentManager);
|
||||
|
||||
assertFalse(expanded.hasSourceServiceId());
|
||||
assertFalse(expanded.hasSourceServiceIdBinary());
|
||||
@@ -76,22 +88,31 @@ class EnvelopeUtilTest {
|
||||
|
||||
assertEquals(compressed, EnvelopeUtil.compress(compressed), "Double compression should make no changes");
|
||||
|
||||
final MessageProtos.Envelope expanded = EnvelopeUtil.expand(compressed);
|
||||
final MessageProtos.Envelope expanded = EnvelopeUtil.expand(compressed, experimentEnrollmentManager);
|
||||
|
||||
assertEquals(sourceServiceId.toServiceIdentifierString(), expanded.getSourceServiceId());
|
||||
assertFalse(expanded.hasSourceServiceIdBinary());
|
||||
assertEquals(destinationServiceId.toServiceIdentifierString(), expanded.getDestinationServiceId());
|
||||
assertFalse(expanded.hasDestinationServiceIdBinary());
|
||||
assertEquals(serverGuid.toString(), expanded.getServerGuid());
|
||||
assertFalse(expanded.hasServerGuidBinary());
|
||||
assertEquals(updatedPni.toString(), expanded.getUpdatedPni());
|
||||
assertEquals(UUIDUtil.toByteString(updatedPni), expanded.getUpdatedPniBinary());
|
||||
|
||||
assertEquals(expanded, EnvelopeUtil.expand(expanded), "Double expansion should make no changes");
|
||||
if (includeBinaryServiceIdentifiers) {
|
||||
assertEquals(ServiceIdentifierUtil.toCompactByteString(sourceServiceId), expanded.getSourceServiceIdBinary());
|
||||
assertEquals(ServiceIdentifierUtil.toCompactByteString(destinationServiceId), expanded.getDestinationServiceIdBinary());
|
||||
assertEquals(UUIDUtil.toByteString(serverGuid), expanded.getServerGuidBinary());
|
||||
} else {
|
||||
assertFalse(expanded.hasSourceServiceIdBinary());
|
||||
assertFalse(expanded.hasDestinationServiceIdBinary());
|
||||
assertFalse(expanded.hasServerGuidBinary());
|
||||
}
|
||||
|
||||
assertEquals(expanded, EnvelopeUtil.expand(expanded, experimentEnrollmentManager),
|
||||
"Double expansion should make no changes");
|
||||
|
||||
// Expanded envelopes include both representations of the `updatedPni` field
|
||||
assertEquals(compressibleFieldsExpandedMessage.toBuilder().setUpdatedPniBinary(UUIDUtil.toByteString(updatedPni)).build(),
|
||||
expanded);
|
||||
assertTrue(expanded.hasUpdatedPni());
|
||||
assertTrue(expanded.hasUpdatedPniBinary());
|
||||
assertEquals(UUID.fromString(expanded.getUpdatedPni()), UUIDUtil.fromByteString(expanded.getUpdatedPniBinary()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
||||
import org.whispersystems.textsecuregcm.entities.MessageProtos;
|
||||
import org.whispersystems.textsecuregcm.experiment.ExperimentEnrollmentManager;
|
||||
import org.whispersystems.textsecuregcm.push.MessageAvailabilityListener;
|
||||
import org.whispersystems.textsecuregcm.push.RedisMessageAvailabilityManager;
|
||||
import org.whispersystems.textsecuregcm.redis.RedisClusterExtension;
|
||||
@@ -59,6 +60,7 @@ class MessagePersisterIntegrationTest {
|
||||
private RedisMessageAvailabilityManager redisMessageAvailabilityManager;
|
||||
private MessagePersister messagePersister;
|
||||
private Account account;
|
||||
private ExperimentEnrollmentManager experimentEnrollmentManager;
|
||||
|
||||
private static final Duration PERSIST_DELAY = Duration.ofMinutes(10);
|
||||
|
||||
@@ -75,13 +77,14 @@ class MessagePersisterIntegrationTest {
|
||||
|
||||
messageDeliveryScheduler = Schedulers.newBoundedElastic(10, 10_000, "messageDelivery");
|
||||
messageDeletionExecutorService = Executors.newSingleThreadExecutor();
|
||||
experimentEnrollmentManager = mock(ExperimentEnrollmentManager.class);
|
||||
final MessagesDynamoDb messagesDynamoDb = new MessagesDynamoDb(DYNAMO_DB_EXTENSION.getDynamoDbClient(),
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbAsyncClient(), Tables.MESSAGES.tableName(), Duration.ofDays(14),
|
||||
messageDeletionExecutorService);
|
||||
messageDeletionExecutorService, experimentEnrollmentManager);
|
||||
final AccountsManager accountsManager = mock(AccountsManager.class);
|
||||
|
||||
messagesCache = new MessagesCache(REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
messageDeliveryScheduler, messageDeletionExecutorService, Clock.systemUTC());
|
||||
messageDeliveryScheduler, messageDeletionExecutorService, Clock.systemUTC(), experimentEnrollmentManager);
|
||||
messagesManager = new MessagesManager(messagesDynamoDb, messagesCache, mock(RedisMessageAvailabilityManager.class),
|
||||
mock(ReportMessageManager.class), messageDeletionExecutorService, Clock.systemUTC());
|
||||
|
||||
@@ -185,7 +188,7 @@ class MessagePersisterIntegrationTest {
|
||||
dynamoDB.scan(ScanRequest.builder().tableName(Tables.MESSAGES.tableName()).build()).items().stream()
|
||||
.map(item -> {
|
||||
try {
|
||||
return MessagesDynamoDb.convertItemToEnvelope(item);
|
||||
return MessagesDynamoDb.convertItemToEnvelope(item, experimentEnrollmentManager);
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
fail("Could not parse stored message", e);
|
||||
return null;
|
||||
|
||||
@@ -53,6 +53,7 @@ import org.mockito.stubbing.Answer;
|
||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicMessagePersisterConfiguration;
|
||||
import org.whispersystems.textsecuregcm.entities.MessageProtos;
|
||||
import org.whispersystems.textsecuregcm.experiment.ExperimentEnrollmentManager;
|
||||
import org.whispersystems.textsecuregcm.identity.IdentityType;
|
||||
import org.whispersystems.textsecuregcm.redis.RedisClusterExtension;
|
||||
import org.whispersystems.textsecuregcm.tests.util.DevicesHelper;
|
||||
@@ -115,7 +116,7 @@ class MessagePersisterTest {
|
||||
resubscribeRetryExecutorService = Executors.newSingleThreadScheduledExecutor();
|
||||
messageDeliveryScheduler = Schedulers.newBoundedElastic(10, 10_000, "messageDelivery");
|
||||
messagesCache = new MessagesCache(REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
messageDeliveryScheduler, sharedExecutorService, Clock.systemUTC());
|
||||
messageDeliveryScheduler, sharedExecutorService, Clock.systemUTC(), mock(ExperimentEnrollmentManager.class));
|
||||
messagePersister = new MessagePersister(messagesCache, messagesManager, accountsManager,
|
||||
dynamicConfigurationManager, PERSIST_DELAY, 1);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ package org.whispersystems.textsecuregcm.storage;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import io.lettuce.core.RedisCommandExecutionException;
|
||||
import io.lettuce.core.ScriptOutputType;
|
||||
@@ -19,6 +20,7 @@ import java.util.UUID;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.whispersystems.textsecuregcm.entities.MessageProtos;
|
||||
import org.whispersystems.textsecuregcm.experiment.ExperimentEnrollmentManager;
|
||||
import org.whispersystems.textsecuregcm.redis.ClusterLuaScript;
|
||||
import org.whispersystems.textsecuregcm.redis.RedisClusterExtension;
|
||||
|
||||
@@ -51,7 +53,8 @@ class MessagesCacheGetItemsScriptTest {
|
||||
assertNotNull(messageAndScores);
|
||||
assertEquals(2, messageAndScores.size());
|
||||
final MessageProtos.Envelope resultEnvelope =
|
||||
EnvelopeUtil.expand(MessageProtos.Envelope.parseFrom(messageAndScores.getFirst()));
|
||||
EnvelopeUtil.expand(MessageProtos.Envelope.parseFrom(messageAndScores.getFirst()),
|
||||
mock(ExperimentEnrollmentManager.class));
|
||||
|
||||
assertEquals(serverGuid, resultEnvelope.getServerGuid());
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.signal.libsignal.protocol.SealedSenderMultiRecipientMessage;
|
||||
import org.whispersystems.textsecuregcm.entities.MessageProtos;
|
||||
import org.whispersystems.textsecuregcm.experiment.ExperimentEnrollmentManager;
|
||||
import org.whispersystems.textsecuregcm.identity.AciServiceIdentifier;
|
||||
import org.whispersystems.textsecuregcm.identity.ServiceIdentifier;
|
||||
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisClusterClient;
|
||||
@@ -106,7 +107,7 @@ class MessagesCacheTest {
|
||||
resubscribeRetryExecutorService = Executors.newSingleThreadScheduledExecutor();
|
||||
messageDeliveryScheduler = Schedulers.newBoundedElastic(10, 10_000, "messageDelivery");
|
||||
messagesCache = new MessagesCache(REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
messageDeliveryScheduler, sharedExecutorService, Clock.systemUTC());
|
||||
messageDeliveryScheduler, sharedExecutorService, Clock.systemUTC(), mock(ExperimentEnrollmentManager.class));
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
@@ -299,7 +300,7 @@ class MessagesCacheTest {
|
||||
}
|
||||
|
||||
final MessagesCache messagesCache = new MessagesCache(REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
messageDeliveryScheduler, sharedExecutorService, cacheClock);
|
||||
messageDeliveryScheduler, sharedExecutorService, cacheClock, mock(ExperimentEnrollmentManager.class));
|
||||
|
||||
final List<MessageProtos.Envelope> actualMessages = Flux.from(
|
||||
messagesCache.get(DESTINATION_UUID, DESTINATION_DEVICE_ID))
|
||||
@@ -623,7 +624,7 @@ class MessagesCacheTest {
|
||||
messageDeliveryScheduler = Schedulers.newBoundedElastic(10, 10_000, "messageDelivery");
|
||||
|
||||
messagesCache = new MessagesCache(mockCluster, messageDeliveryScheduler,
|
||||
Executors.newSingleThreadExecutor(), Clock.systemUTC());
|
||||
Executors.newSingleThreadExecutor(), Clock.systemUTC(), mock(ExperimentEnrollmentManager.class));
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package org.whispersystems.textsecuregcm.storage;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import java.time.Duration;
|
||||
@@ -26,6 +27,7 @@ import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.whispersystems.textsecuregcm.entities.MessageProtos;
|
||||
import org.whispersystems.textsecuregcm.experiment.ExperimentEnrollmentManager;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Tables;
|
||||
import org.whispersystems.textsecuregcm.tests.util.DevicesHelper;
|
||||
import org.whispersystems.textsecuregcm.tests.util.MessageHelper;
|
||||
@@ -84,7 +86,7 @@ class MessagesDynamoDbTest {
|
||||
messageDeletionExecutorService = Executors.newSingleThreadExecutor();
|
||||
messagesDynamoDb = new MessagesDynamoDb(DYNAMO_DB_EXTENSION.getDynamoDbClient(),
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbAsyncClient(), Tables.MESSAGES.tableName(), Duration.ofDays(14),
|
||||
messageDeletionExecutorService);
|
||||
messageDeletionExecutorService, mock(ExperimentEnrollmentManager.class));
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
import org.whispersystems.textsecuregcm.entities.MessageProtos;
|
||||
import org.whispersystems.textsecuregcm.experiment.ExperimentEnrollmentManager;
|
||||
import org.whispersystems.textsecuregcm.identity.AciServiceIdentifier;
|
||||
import org.whispersystems.textsecuregcm.identity.ServiceIdentifier;
|
||||
import org.whispersystems.textsecuregcm.push.RedisMessageAvailabilityManager;
|
||||
@@ -80,10 +81,11 @@ class RedisDynamoDbMessagePublisherTest {
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbAsyncClient(),
|
||||
DynamoDbExtensionSchema.Tables.MESSAGES.tableName(),
|
||||
Duration.ofDays(14),
|
||||
sharedExecutorService);
|
||||
sharedExecutorService,
|
||||
mock(ExperimentEnrollmentManager.class));
|
||||
|
||||
messagesCache = new MessagesCache(REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
messageDeliveryScheduler, sharedExecutorService, Clock.systemUTC());
|
||||
messageDeliveryScheduler, sharedExecutorService, Clock.systemUTC(), mock(ExperimentEnrollmentManager.class));
|
||||
|
||||
redisMessageAvailabilityManager = mock(RedisMessageAvailabilityManager.class);
|
||||
|
||||
|
||||
@@ -101,10 +101,10 @@ class WebSocketConnectionIntegrationTest {
|
||||
dynamicConfigurationManager = mock(DynamicConfigurationManager.class);
|
||||
when(dynamicConfigurationManager.getConfiguration()).thenReturn(new DynamicConfiguration());
|
||||
messagesCache = new MessagesCache(REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
messageDeliveryScheduler, sharedExecutorService, Clock.systemUTC());
|
||||
messageDeliveryScheduler, sharedExecutorService, Clock.systemUTC(), mock(ExperimentEnrollmentManager.class));
|
||||
messagesDynamoDb = new MessagesDynamoDb(DYNAMO_DB_EXTENSION.getDynamoDbClient(),
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbAsyncClient(), Tables.MESSAGES.tableName(), Duration.ofDays(7),
|
||||
sharedExecutorService);
|
||||
sharedExecutorService, mock(ExperimentEnrollmentManager.class));
|
||||
redisMessageAvailabilityManager = new RedisMessageAvailabilityManager(REDIS_CLUSTER_EXTENSION.getRedisCluster(), sharedExecutorService, sharedExecutorService);
|
||||
reportMessageManager = mock(ReportMessageManager.class);
|
||||
account = mock(Account.class);
|
||||
|
||||
Reference in New Issue
Block a user