Add report message API

This commit is contained in:
Chris Eager
2021-05-13 17:19:34 -05:00
committed by GitHub
parent 03dac2bf7e
commit e320626c6e
14 changed files with 370 additions and 13 deletions

View File

@@ -22,6 +22,7 @@ import org.whispersystems.textsecuregcm.redis.AbstractRedisClusterTest;
import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
import org.whispersystems.textsecuregcm.storage.MessagesManager;
import org.whispersystems.textsecuregcm.storage.ReportMessageManager;
public class MessageControllerMetricsTest extends AbstractRedisClusterTest {
@@ -40,6 +41,7 @@ public class MessageControllerMetricsTest extends AbstractRedisClusterTest {
mock(ApnFallbackManager.class),
mock(DynamicConfigurationManager.class),
mock(RateLimitChallengeManager.class),
mock(ReportMessageManager.class),
getRedisCluster(),
mock(ScheduledExecutorService.class));
}

View File

@@ -68,7 +68,7 @@ public class MessagePersisterIntegrationTest extends AbstractRedisClusterTest {
notificationExecutorService = Executors.newSingleThreadExecutor();
messagesCache = new MessagesCache(getRedisCluster(), getRedisCluster(), notificationExecutorService);
messagesManager = new MessagesManager(messagesDynamoDb, messagesCache, mock(PushLatencyManager.class));
messagesManager = new MessagesManager(messagesDynamoDb, messagesCache, mock(PushLatencyManager.class), mock(ReportMessageManager.class));
messagePersister = new MessagePersister(messagesCache, messagesManager, accountsManager, dynamicConfigurationManager, PERSIST_DELAY);
account = mock(Account.class);

View File

@@ -0,0 +1,46 @@
package org.whispersystems.textsecuregcm.storage;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import java.util.UUID;
import org.junit.jupiter.api.Test;
import org.whispersystems.textsecuregcm.entities.MessageProtos.Envelope;
import org.whispersystems.textsecuregcm.metrics.PushLatencyManager;
class MessagesManagerTest {
private final MessagesDynamoDb messagesDynamoDb = mock(MessagesDynamoDb.class);
private final MessagesCache messagesCache = mock(MessagesCache.class);
private final PushLatencyManager pushLatencyManager = mock(PushLatencyManager.class);
private final ReportMessageManager reportMessageManager = mock(ReportMessageManager.class);
private final MessagesManager messagesManager = new MessagesManager(messagesDynamoDb, messagesCache,
pushLatencyManager, reportMessageManager);
@Test
void insert() {
final String sourceNumber = "+12025551212";
final Envelope message = Envelope.newBuilder()
.setSource(sourceNumber)
.setSourceUuid(UUID.randomUUID().toString())
.build();
final UUID destinationUuid = UUID.randomUUID();
messagesManager.insert(destinationUuid, 1L, message);
verify(reportMessageManager).store(eq(sourceNumber), any(UUID.class));
final Envelope syncMessage = Envelope.newBuilder(message)
.setSourceUuid(destinationUuid.toString())
.build();
messagesManager.insert(destinationUuid, 1L, syncMessage);
verifyNoMoreInteractions(reportMessageManager);
}
}

View File

@@ -0,0 +1,59 @@
package org.whispersystems.textsecuregcm.storage;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType;
import java.util.UUID;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.whispersystems.textsecuregcm.util.UUIDUtil;
class ReportMessageDynamoDbTest {
private ReportMessageDynamoDb reportMessageDynamoDb;
private static final String TABLE_NAME = "report_message_test";
@RegisterExtension
static DynamoDbExtension dynamoDbExtension = DynamoDbExtension.builder()
.tableName(TABLE_NAME)
.hashKey(ReportMessageDynamoDb.KEY_HASH)
.attributeDefinition(new AttributeDefinition(ReportMessageDynamoDb.KEY_HASH, ScalarAttributeType.B))
.build();
@BeforeEach
void setUp() {
this.reportMessageDynamoDb = new ReportMessageDynamoDb(dynamoDbExtension.getDynamoDB(), TABLE_NAME);
}
@Test
void testStore() {
final byte[] hash1 = UUIDUtil.toBytes(UUID.randomUUID());
final byte[] hash2 = UUIDUtil.toBytes(UUID.randomUUID());
assertAll("database should be empty",
() -> assertFalse(reportMessageDynamoDb.remove(hash1)),
() -> assertFalse(reportMessageDynamoDb.remove(hash2))
);
reportMessageDynamoDb.store(hash1);
reportMessageDynamoDb.store(hash2);
assertAll("both hashes should be found",
() -> assertTrue(reportMessageDynamoDb.remove(hash1)),
() -> assertTrue(reportMessageDynamoDb.remove(hash2))
);
assertAll( "database should be empty",
() -> assertFalse(reportMessageDynamoDb.remove(hash1)),
() -> assertFalse(reportMessageDynamoDb.remove(hash2))
);
}
}

View File

@@ -0,0 +1,59 @@
package org.whispersystems.textsecuregcm.storage;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import java.util.UUID;
import org.junit.jupiter.api.Test;
class ReportMessageManagerTest {
private final ReportMessageDynamoDb reportMessageDynamoDb = mock(ReportMessageDynamoDb.class);
private final MeterRegistry meterRegistry = new SimpleMeterRegistry();
private final ReportMessageManager reportMessageManager = new ReportMessageManager(reportMessageDynamoDb, meterRegistry);
@Test
void testStore() {
final UUID messageGuid = UUID.randomUUID();
final String number = "+15105551111";
assertThrows(NullPointerException.class, () -> reportMessageManager.store(null, messageGuid));
reportMessageManager.store(number, messageGuid);
verify(reportMessageDynamoDb).store(any());
}
@Test
void testReport() {
final String sourceNumber = "+15105551111";
final UUID messageGuid = UUID.randomUUID();
when(reportMessageDynamoDb.remove(any())).thenReturn(false);
reportMessageManager.report(sourceNumber, messageGuid);
assertEquals(0, getCounterTotal(ReportMessageManager.REPORT_COUNTER_NAME));
when(reportMessageDynamoDb.remove(any())).thenReturn(true);
reportMessageManager.report(sourceNumber, messageGuid);
assertEquals(1, getCounterTotal(ReportMessageManager.REPORT_COUNTER_NAME));
}
private double getCounterTotal(final String counterName) {
return meterRegistry.find(counterName).counters().stream()
.map(Counter::count)
.reduce(Double::sum)
.orElse(0.0);
}
}

View File

@@ -95,6 +95,7 @@ import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
import org.whispersystems.textsecuregcm.storage.MessagesManager;
import org.whispersystems.textsecuregcm.storage.ReportMessageManager;
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
import org.whispersystems.textsecuregcm.tests.util.RedisClusterHelper;
import org.whispersystems.textsecuregcm.util.ua.ClientPlatform;
@@ -127,6 +128,7 @@ class MessageControllerTest {
private static final ApnFallbackManager apnFallbackManager = mock(ApnFallbackManager.class);
private static final DynamicConfigurationManager dynamicConfigurationManager = mock(DynamicConfigurationManager.class);
private static final RateLimitChallengeManager rateLimitChallengeManager = mock(RateLimitChallengeManager.class);
private static final ReportMessageManager reportMessageManager = mock(ReportMessageManager.class);
private static final FaultTolerantRedisCluster metricsCluster = RedisClusterHelper.buildMockRedisCluster(redisCommands);
private static final ScheduledExecutorService receiptExecutor = mock(ScheduledExecutorService.class);
@@ -139,7 +141,8 @@ class MessageControllerTest {
.addProvider(new RateLimitChallengeExceptionMapper(rateLimitChallengeManager))
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource(new MessageController(rateLimiters, messageSender, receiptSender, accountsManager,
messagesManager, unsealedSenderRateLimiter, apnFallbackManager, dynamicConfigurationManager, rateLimitChallengeManager, metricsCluster, receiptExecutor))
messagesManager, unsealedSenderRateLimiter, apnFallbackManager, dynamicConfigurationManager,
rateLimitChallengeManager, reportMessageManager, metricsCluster, receiptExecutor))
.build();
@BeforeEach
@@ -198,6 +201,7 @@ class MessageControllerTest {
apnFallbackManager,
dynamicConfigurationManager,
rateLimitChallengeManager,
reportMessageManager,
metricsCluster,
receiptExecutor
);
@@ -602,4 +606,22 @@ class MessageControllerTest {
Arguments.of("fixtures/online_message_false_nested_property.json", false)
);
}
@Test
void testReportMessage() {
final String senderNumber = "+12125550001";
final UUID messageGuid = UUID.randomUUID();
final Response response =
resources.getJerseyTest()
.target(String.format("/v1/messages/report/%s/%s", senderNumber, messageGuid))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.post(null);
assertThat(response.getStatus(), is(equalTo(202)));
verify(reportMessageManager).report(senderNumber, messageGuid);
}
}

View File

@@ -47,6 +47,7 @@ import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.storage.MessagesCache;
import org.whispersystems.textsecuregcm.storage.MessagesDynamoDb;
import org.whispersystems.textsecuregcm.storage.MessagesManager;
import org.whispersystems.textsecuregcm.storage.ReportMessageManager;
import org.whispersystems.textsecuregcm.tests.util.MessagesDynamoDbRule;
import org.whispersystems.websocket.WebSocketClient;
import org.whispersystems.websocket.messages.WebSocketResponseMessage;
@@ -59,6 +60,7 @@ public class WebSocketConnectionIntegrationTest extends AbstractRedisClusterTest
private ExecutorService executorService;
private MessagesDynamoDb messagesDynamoDb;
private MessagesCache messagesCache;
private ReportMessageManager reportMessageManager;
private Account account;
private Device device;
private WebSocketClient webSocketClient;
@@ -75,6 +77,7 @@ public class WebSocketConnectionIntegrationTest extends AbstractRedisClusterTest
executorService = Executors.newSingleThreadExecutor();
messagesCache = new MessagesCache(getRedisCluster(), getRedisCluster(), executorService);
messagesDynamoDb = new MessagesDynamoDb(messagesDynamoDbRule.getDynamoDB(), MessagesDynamoDbRule.TABLE_NAME, Duration.ofDays(7));
reportMessageManager = mock(ReportMessageManager.class);
account = mock(Account.class);
device = mock(Device.class);
webSocketClient = mock(WebSocketClient.class);
@@ -86,7 +89,7 @@ public class WebSocketConnectionIntegrationTest extends AbstractRedisClusterTest
webSocketConnection = new WebSocketConnection(
mock(ReceiptSender.class),
new MessagesManager(messagesDynamoDb, messagesCache, mock(PushLatencyManager.class)),
new MessagesManager(messagesDynamoDb, messagesCache, mock(PushLatencyManager.class), reportMessageManager),
account,
device,
webSocketClient,