mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-24 19:00:26 +01:00
Do not enqueue no-op read receipt jobs.
This commit is contained in:
committed by
mtang-signal
parent
cda029cd93
commit
4c9b5926b9
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user