Do not enqueue no-op read receipt jobs.
This commit is contained in:
parent
cda029cd93
commit
4c9b5926b9
5 changed files with 313 additions and 362 deletions
|
@ -98,6 +98,10 @@ public class SendReadReceiptJob extends BaseJob {
|
|||
* maximum size.
|
||||
*/
|
||||
public static void enqueue(long threadId, @NonNull RecipientId recipientId, List<MarkedMessageInfo> markedMessageInfos) {
|
||||
if (!TextSecurePreferences.isReadReceiptsEnabled(AppDependencies.getApplication())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (recipientId.equals(Recipient.self().getId())) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,247 +0,0 @@
|
|||
package org.thoughtcrime.securesms.dependencies;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.signal.core.util.concurrent.DeadlockDetector;
|
||||
import org.signal.libsignal.net.Network;
|
||||
import org.signal.libsignal.zkgroup.profiles.ClientZkProfileOperations;
|
||||
import org.signal.libsignal.zkgroup.receipts.ClientZkReceiptOperations;
|
||||
import org.thoughtcrime.securesms.billing.GooglePlayBillingApi;
|
||||
import org.thoughtcrime.securesms.components.TypingStatusRepository;
|
||||
import org.thoughtcrime.securesms.components.TypingStatusSender;
|
||||
import org.thoughtcrime.securesms.crypto.storage.SignalServiceDataStoreImpl;
|
||||
import org.thoughtcrime.securesms.database.DatabaseObserver;
|
||||
import org.thoughtcrime.securesms.database.PendingRetryReceiptCache;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||
import org.thoughtcrime.securesms.megaphone.MegaphoneRepository;
|
||||
import org.thoughtcrime.securesms.messages.IncomingMessageObserver;
|
||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.thoughtcrime.securesms.payments.Payments;
|
||||
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipientCache;
|
||||
import org.thoughtcrime.securesms.revealable.ViewOnceMessageManager;
|
||||
import org.thoughtcrime.securesms.service.DeletedCallEventManager;
|
||||
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
|
||||
import org.thoughtcrime.securesms.service.ExpiringStoriesManager;
|
||||
import org.thoughtcrime.securesms.service.PendingRetryReceiptManager;
|
||||
import org.thoughtcrime.securesms.service.ScheduledMessageManager;
|
||||
import org.thoughtcrime.securesms.service.TrimThreadsByDateManager;
|
||||
import org.thoughtcrime.securesms.service.webrtc.SignalCallManager;
|
||||
import org.thoughtcrime.securesms.shakereport.ShakeToReport;
|
||||
import org.thoughtcrime.securesms.util.AppForegroundObserver;
|
||||
import org.thoughtcrime.securesms.util.EarlyMessageCache;
|
||||
import org.thoughtcrime.securesms.util.FrameRateTracker;
|
||||
import org.thoughtcrime.securesms.video.exo.GiphyMp4Cache;
|
||||
import org.thoughtcrime.securesms.video.exo.SimpleExoPlayerPool;
|
||||
import org.thoughtcrime.securesms.webrtc.audio.AudioManagerCompat;
|
||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
||||
import org.whispersystems.signalservice.api.SignalServiceDataStore;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.SignalWebSocket;
|
||||
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
|
||||
import org.whispersystems.signalservice.api.services.CallLinksService;
|
||||
import org.whispersystems.signalservice.api.services.DonationsService;
|
||||
import org.whispersystems.signalservice.api.services.ProfileService;
|
||||
import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public class MockApplicationDependencyProvider implements AppDependencies.Provider {
|
||||
@Override
|
||||
public @NonNull GroupsV2Operations provideGroupsV2Operations(@NonNull SignalServiceConfiguration signalServiceConfiguration) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull SignalServiceAccountManager provideSignalServiceAccountManager(@NonNull SignalServiceConfiguration signalServiceConfiguration, @NonNull GroupsV2Operations groupsV2Operations) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull SignalServiceMessageSender provideSignalServiceMessageSender(@NonNull SignalWebSocket signalWebSocket, @NonNull SignalServiceDataStore protocolStore, @NonNull SignalServiceConfiguration signalServiceConfiguration) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull SignalServiceMessageReceiver provideSignalServiceMessageReceiver(@NonNull SignalServiceConfiguration signalServiceConfiguration) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull SignalServiceNetworkAccess provideSignalServiceNetworkAccess() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull LiveRecipientCache provideRecipientCache() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull JobManager provideJobManager() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull FrameRateTracker provideFrameRateTracker() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull MegaphoneRepository provideMegaphoneRepository() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull EarlyMessageCache provideEarlyMessageCache() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull MessageNotifier provideMessageNotifier() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull IncomingMessageObserver provideIncomingMessageObserver() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull TrimThreadsByDateManager provideTrimThreadsByDateManager() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull ViewOnceMessageManager provideViewOnceMessageManager() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull ExpiringStoriesManager provideExpiringStoriesManager() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull ExpiringMessageManager provideExpiringMessageManager() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull DeletedCallEventManager provideDeletedCallEventManager() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull TypingStatusRepository provideTypingStatusRepository() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull TypingStatusSender provideTypingStatusSender() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull DatabaseObserver provideDatabaseObserver() {
|
||||
return mock(DatabaseObserver.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Payments providePayments(@NonNull SignalServiceAccountManager signalServiceAccountManager) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull ShakeToReport provideShakeToReport() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull AppForegroundObserver provideAppForegroundObserver() {
|
||||
return mock(AppForegroundObserver.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull SignalCallManager provideSignalCallManager() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull PendingRetryReceiptManager providePendingRetryReceiptManager() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull PendingRetryReceiptCache providePendingRetryReceiptCache() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull SignalWebSocket provideSignalWebSocket(@NonNull Supplier<SignalServiceConfiguration> signalServiceConfigurationSupplier, @NonNull Supplier<Network> libSignalNetworkSupplier) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull SignalServiceDataStoreImpl provideProtocolStore() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull GiphyMp4Cache provideGiphyMp4Cache() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull SimpleExoPlayerPool provideExoPlayerPool() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull AudioManagerCompat provideAndroidCallAudioManager() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull DonationsService provideDonationsService(@NonNull SignalServiceConfiguration signalServiceConfiguration, @NonNull GroupsV2Operations groupsV2Operations) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NonNull @Override public CallLinksService provideCallLinksService(@NonNull SignalServiceConfiguration signalServiceConfiguration, @NonNull GroupsV2Operations groupsV2Operations) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull ProfileService provideProfileService(@NonNull ClientZkProfileOperations profileOperations, @NonNull SignalServiceMessageReceiver signalServiceMessageReceiver, @NonNull SignalWebSocket signalWebSocket) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull DeadlockDetector provideDeadlockDetector() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull ClientZkReceiptOperations provideClientZkReceiptOperations(@NonNull SignalServiceConfiguration signalServiceConfiguration) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull ScheduledMessageManager provideScheduledMessageManager() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Network provideLibsignalNetwork(@NonNull SignalServiceConfiguration config) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull GooglePlayBillingApi provideBillingApi() {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,205 @@
|
|||
package org.thoughtcrime.securesms.dependencies
|
||||
|
||||
import io.mockk.mockk
|
||||
import org.mockito.Mockito
|
||||
import org.signal.core.util.concurrent.DeadlockDetector
|
||||
import org.signal.libsignal.net.Network
|
||||
import org.signal.libsignal.zkgroup.profiles.ClientZkProfileOperations
|
||||
import org.signal.libsignal.zkgroup.receipts.ClientZkReceiptOperations
|
||||
import org.thoughtcrime.securesms.billing.GooglePlayBillingApi
|
||||
import org.thoughtcrime.securesms.components.TypingStatusRepository
|
||||
import org.thoughtcrime.securesms.components.TypingStatusSender
|
||||
import org.thoughtcrime.securesms.crypto.storage.SignalServiceDataStoreImpl
|
||||
import org.thoughtcrime.securesms.database.DatabaseObserver
|
||||
import org.thoughtcrime.securesms.database.PendingRetryReceiptCache
|
||||
import org.thoughtcrime.securesms.jobmanager.JobManager
|
||||
import org.thoughtcrime.securesms.megaphone.MegaphoneRepository
|
||||
import org.thoughtcrime.securesms.messages.IncomingMessageObserver
|
||||
import org.thoughtcrime.securesms.notifications.MessageNotifier
|
||||
import org.thoughtcrime.securesms.payments.Payments
|
||||
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipientCache
|
||||
import org.thoughtcrime.securesms.revealable.ViewOnceMessageManager
|
||||
import org.thoughtcrime.securesms.service.DeletedCallEventManager
|
||||
import org.thoughtcrime.securesms.service.ExpiringMessageManager
|
||||
import org.thoughtcrime.securesms.service.ExpiringStoriesManager
|
||||
import org.thoughtcrime.securesms.service.PendingRetryReceiptManager
|
||||
import org.thoughtcrime.securesms.service.ScheduledMessageManager
|
||||
import org.thoughtcrime.securesms.service.TrimThreadsByDateManager
|
||||
import org.thoughtcrime.securesms.service.webrtc.SignalCallManager
|
||||
import org.thoughtcrime.securesms.shakereport.ShakeToReport
|
||||
import org.thoughtcrime.securesms.util.AppForegroundObserver
|
||||
import org.thoughtcrime.securesms.util.EarlyMessageCache
|
||||
import org.thoughtcrime.securesms.util.FrameRateTracker
|
||||
import org.thoughtcrime.securesms.video.exo.GiphyMp4Cache
|
||||
import org.thoughtcrime.securesms.video.exo.SimpleExoPlayerPool
|
||||
import org.thoughtcrime.securesms.webrtc.audio.AudioManagerCompat
|
||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager
|
||||
import org.whispersystems.signalservice.api.SignalServiceDataStore
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender
|
||||
import org.whispersystems.signalservice.api.SignalWebSocket
|
||||
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations
|
||||
import org.whispersystems.signalservice.api.services.CallLinksService
|
||||
import org.whispersystems.signalservice.api.services.DonationsService
|
||||
import org.whispersystems.signalservice.api.services.ProfileService
|
||||
import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration
|
||||
import java.util.function.Supplier
|
||||
|
||||
class MockApplicationDependencyProvider : AppDependencies.Provider {
|
||||
override fun provideGroupsV2Operations(signalServiceConfiguration: SignalServiceConfiguration): GroupsV2Operations {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideSignalServiceAccountManager(signalServiceConfiguration: SignalServiceConfiguration, groupsV2Operations: GroupsV2Operations): SignalServiceAccountManager {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideSignalServiceMessageSender(signalWebSocket: SignalWebSocket, protocolStore: SignalServiceDataStore, signalServiceConfiguration: SignalServiceConfiguration): SignalServiceMessageSender {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideSignalServiceMessageReceiver(signalServiceConfiguration: SignalServiceConfiguration): SignalServiceMessageReceiver {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideSignalServiceNetworkAccess(): SignalServiceNetworkAccess {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideRecipientCache(): LiveRecipientCache {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideJobManager(): JobManager {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideFrameRateTracker(): FrameRateTracker {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideMegaphoneRepository(): MegaphoneRepository {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideEarlyMessageCache(): EarlyMessageCache {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideMessageNotifier(): MessageNotifier {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideIncomingMessageObserver(): IncomingMessageObserver {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideTrimThreadsByDateManager(): TrimThreadsByDateManager {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideViewOnceMessageManager(): ViewOnceMessageManager {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideExpiringStoriesManager(): ExpiringStoriesManager {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideExpiringMessageManager(): ExpiringMessageManager {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideDeletedCallEventManager(): DeletedCallEventManager {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideTypingStatusRepository(): TypingStatusRepository {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideTypingStatusSender(): TypingStatusSender {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideDatabaseObserver(): DatabaseObserver {
|
||||
return Mockito.mock(DatabaseObserver::class.java)
|
||||
}
|
||||
|
||||
override fun providePayments(signalServiceAccountManager: SignalServiceAccountManager): Payments {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideShakeToReport(): ShakeToReport {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideAppForegroundObserver(): AppForegroundObserver {
|
||||
return Mockito.mock(AppForegroundObserver::class.java)
|
||||
}
|
||||
|
||||
override fun provideSignalCallManager(): SignalCallManager {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun providePendingRetryReceiptManager(): PendingRetryReceiptManager {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun providePendingRetryReceiptCache(): PendingRetryReceiptCache {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideSignalWebSocket(signalServiceConfigurationSupplier: Supplier<SignalServiceConfiguration>, libSignalNetworkSupplier: Supplier<Network>): SignalWebSocket {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideProtocolStore(): SignalServiceDataStoreImpl {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideGiphyMp4Cache(): GiphyMp4Cache {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideExoPlayerPool(): SimpleExoPlayerPool {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideAndroidCallAudioManager(): AudioManagerCompat {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideDonationsService(signalServiceConfiguration: SignalServiceConfiguration, groupsV2Operations: GroupsV2Operations): DonationsService {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideCallLinksService(signalServiceConfiguration: SignalServiceConfiguration, groupsV2Operations: GroupsV2Operations): CallLinksService {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideProfileService(profileOperations: ClientZkProfileOperations, signalServiceMessageReceiver: SignalServiceMessageReceiver, signalWebSocket: SignalWebSocket): ProfileService {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideDeadlockDetector(): DeadlockDetector {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideClientZkReceiptOperations(signalServiceConfiguration: SignalServiceConfiguration): ClientZkReceiptOperations {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideScheduledMessageManager(): ScheduledMessageManager {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideLibsignalNetwork(config: SignalServiceConfiguration): Network {
|
||||
return mockk()
|
||||
}
|
||||
|
||||
override fun provideBillingApi(): GooglePlayBillingApi {
|
||||
return mockk()
|
||||
}
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
package org.thoughtcrime.securesms.notifications;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.signal.libsignal.protocol.util.Pair;
|
||||
import org.thoughtcrime.securesms.database.MessageTable;
|
||||
import org.thoughtcrime.securesms.database.model.MessageId;
|
||||
import org.thoughtcrime.securesms.database.model.StoryType;
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies;
|
||||
import org.thoughtcrime.securesms.jobmanager.JsonJobData;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceReadUpdateJob;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class MarkReadReceiverTest {
|
||||
|
||||
@Rule
|
||||
public MockitoRule rule = MockitoJUnit.rule();
|
||||
|
||||
@Mock
|
||||
private MockedStatic<AppDependencies> applicationDependenciesMockedStatic;
|
||||
|
||||
@Mock
|
||||
private MockedStatic<Recipient> recipientMockedStatic;
|
||||
|
||||
private final Context mockContext = mock(Context.class);
|
||||
private final JobManager mockJobManager = mock(JobManager.class);
|
||||
private final Recipient mockSelf = mock(Recipient.class);
|
||||
private final List<Job> jobs = new LinkedList<>();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
applicationDependenciesMockedStatic.when(AppDependencies::getJobManager).thenReturn(mockJobManager);
|
||||
doAnswer((Answer<Void>) invocation -> {
|
||||
jobs.add((Job) invocation.getArguments()[0]);
|
||||
return null;
|
||||
}).when(mockJobManager).add(any());
|
||||
recipientMockedStatic.when(Recipient::self).thenReturn(mockSelf);
|
||||
when(mockSelf.getId()).thenReturn(RecipientId.from(-1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenMultipleThreadsWithMultipleMessagesEach_whenIProcess_thenIProperlyGroupByThreadAndRecipient() {
|
||||
// GIVEN
|
||||
List<RecipientId> recipients = Stream.range(1L, 4L).map(RecipientId::from).toList();
|
||||
List<Long> threads = Stream.range(4L, 7L).toList();
|
||||
int expected = recipients.size() * threads.size() + 1;
|
||||
|
||||
List<MessageTable.MarkedMessageInfo> infoList = Stream.of(threads)
|
||||
.flatMap(threadId -> Stream.of(recipients)
|
||||
.map(recipientId -> createMarkedMessageInfo(threadId, recipientId)))
|
||||
.toList();
|
||||
|
||||
List<MessageTable.MarkedMessageInfo> duplicatedList = Util.concatenatedList(infoList, infoList);
|
||||
|
||||
// WHEN
|
||||
MarkReadReceiver.process(duplicatedList);
|
||||
|
||||
// THEN
|
||||
assertEquals("Should have 10 total jobs, including MultiDeviceReadUpdateJob", expected, jobs.size());
|
||||
|
||||
Set<Pair<Long, String>> threadRecipientPairs = new HashSet<>();
|
||||
Stream.of(jobs).forEach(job -> {
|
||||
if (job instanceof MultiDeviceReadUpdateJob) {
|
||||
return;
|
||||
}
|
||||
|
||||
JsonJobData data = JsonJobData.deserialize(job.serialize());
|
||||
|
||||
long threadId = data.getLong("thread");
|
||||
String recipientId = data.getString("recipient");
|
||||
long[] messageIds = data.getLongArray("message_ids");
|
||||
|
||||
assertEquals("Each job should contain two messages.", 2, messageIds.length);
|
||||
assertTrue("Each thread recipient pair should only exist once.", threadRecipientPairs.add(new Pair<>(threadId, recipientId)));
|
||||
});
|
||||
|
||||
assertEquals("Should have 9 total combinations.", 9, threadRecipientPairs.size());
|
||||
}
|
||||
|
||||
private MessageTable.MarkedMessageInfo createMarkedMessageInfo(long threadId, @NonNull RecipientId recipientId) {
|
||||
return new MessageTable.MarkedMessageInfo(threadId,
|
||||
new MessageTable.SyncMessageId(recipientId, 0),
|
||||
new MessageId(1),
|
||||
new MessageTable.ExpirationInfo(0, 0, 0, false),
|
||||
StoryType.NONE);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
package org.thoughtcrime.securesms.notifications
|
||||
|
||||
import android.app.Application
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import io.mockk.every
|
||||
import io.mockk.mockkObject
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.unmockkAll
|
||||
import org.junit.After
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.signal.libsignal.protocol.util.Pair
|
||||
import org.thoughtcrime.securesms.database.MessageTable.ExpirationInfo
|
||||
import org.thoughtcrime.securesms.database.MessageTable.MarkedMessageInfo
|
||||
import org.thoughtcrime.securesms.database.MessageTable.SyncMessageId
|
||||
import org.thoughtcrime.securesms.database.model.MessageId
|
||||
import org.thoughtcrime.securesms.database.model.StoryType
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
import org.thoughtcrime.securesms.dependencies.MockApplicationDependencyProvider
|
||||
import org.thoughtcrime.securesms.jobmanager.Job
|
||||
import org.thoughtcrime.securesms.jobmanager.JobManager
|
||||
import org.thoughtcrime.securesms.jobmanager.JsonJobData
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceReadUpdateJob
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import java.util.LinkedList
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(manifest = Config.NONE, application = Application::class)
|
||||
class MarkReadReceiverTest {
|
||||
|
||||
private val jobs: MutableList<Job> = LinkedList()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
if (!AppDependencies.isInitialized) {
|
||||
AppDependencies.init(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
MockApplicationDependencyProvider()
|
||||
)
|
||||
}
|
||||
|
||||
val jobManager: JobManager = AppDependencies.jobManager
|
||||
every { jobManager.add(capture(jobs)) } returns Unit
|
||||
|
||||
mockkObject(Recipient)
|
||||
every { Recipient.self() } returns Recipient()
|
||||
|
||||
mockkStatic(TextSecurePreferences::class)
|
||||
every { TextSecurePreferences.isReadReceiptsEnabled(any()) } returns true
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
unmockkAll()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenMultipleThreadsWithMultipleMessagesEach_whenIProcess_thenIProperlyGroupByThreadAndRecipient() {
|
||||
// GIVEN
|
||||
val recipients = (1L until 4L).map { id -> RecipientId.from(id) }
|
||||
val threads = (4L until 7L).toList()
|
||||
val expected = recipients.size * threads.size + 1
|
||||
val infoList = threads.map { threadId -> recipients.map { recipientId -> createMarkedMessageInfo(threadId, recipientId) } }.flatten()
|
||||
|
||||
// WHEN
|
||||
MarkReadReceiver.process(infoList + infoList)
|
||||
|
||||
// THEN
|
||||
Assert.assertEquals("Should have 10 total jobs, including MultiDeviceReadUpdateJob", expected.toLong(), jobs.size.toLong())
|
||||
|
||||
val threadRecipientPairs: MutableSet<Pair<Long, String>> = HashSet()
|
||||
jobs.forEach { job ->
|
||||
if (job is MultiDeviceReadUpdateJob) {
|
||||
return@forEach
|
||||
}
|
||||
val data = JsonJobData.deserialize(job.serialize())
|
||||
|
||||
val threadId = data.getLong("thread")
|
||||
val recipientId = data.getString("recipient")
|
||||
val messageIds = data.getLongArray("message_ids")
|
||||
|
||||
Assert.assertEquals("Each job should contain two messages.", 2, messageIds.size.toLong())
|
||||
Assert.assertTrue("Each thread recipient pair should only exist once.", threadRecipientPairs.add(Pair(threadId, recipientId)))
|
||||
}
|
||||
|
||||
Assert.assertEquals("Should have 9 total combinations.", 9, threadRecipientPairs.size.toLong())
|
||||
}
|
||||
|
||||
private fun createMarkedMessageInfo(threadId: Long, recipientId: RecipientId): MarkedMessageInfo {
|
||||
return MarkedMessageInfo(
|
||||
threadId,
|
||||
SyncMessageId(recipientId, 0),
|
||||
MessageId(1),
|
||||
ExpirationInfo(0, 0, 0, false),
|
||||
StoryType.NONE
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue