kopia lustrzana https://github.com/ryukoposting/Signal-Android
293 wiersze
9.6 KiB
Kotlin
293 wiersze
9.6 KiB
Kotlin
package org.thoughtcrime.securesms.database
|
|
|
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
|
import org.hamcrest.MatcherAssert.assertThat
|
|
import org.hamcrest.Matchers.`is`
|
|
import org.hamcrest.Matchers.notNullValue
|
|
import org.hamcrest.Matchers.nullValue
|
|
import org.junit.Before
|
|
import org.junit.Test
|
|
import org.junit.runner.RunWith
|
|
import org.signal.core.util.Hex
|
|
import org.signal.libsignal.zkgroup.groups.GroupMasterKey
|
|
import org.thoughtcrime.securesms.database.model.databaseprotos.DecryptedGroupV2Context
|
|
import org.thoughtcrime.securesms.database.model.databaseprotos.addMember
|
|
import org.thoughtcrime.securesms.database.model.databaseprotos.addRequestingMember
|
|
import org.thoughtcrime.securesms.database.model.databaseprotos.deleteRequestingMember
|
|
import org.thoughtcrime.securesms.database.model.databaseprotos.groupChange
|
|
import org.thoughtcrime.securesms.database.model.databaseprotos.groupContext
|
|
import org.thoughtcrime.securesms.groups.GroupId
|
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
|
import org.thoughtcrime.securesms.recipients.RecipientId
|
|
import org.thoughtcrime.securesms.sms.IncomingGroupUpdateMessage
|
|
import org.thoughtcrime.securesms.sms.IncomingTextMessage
|
|
import org.whispersystems.signalservice.api.push.ACI
|
|
import org.whispersystems.signalservice.api.push.PNI
|
|
import org.whispersystems.signalservice.api.push.ServiceId
|
|
import java.util.Optional
|
|
import java.util.UUID
|
|
|
|
@Suppress("ClassName", "TestFunctionName")
|
|
@RunWith(AndroidJUnit4::class)
|
|
class SmsDatabaseTest_collapseJoinRequestEventsIfPossible {
|
|
|
|
private lateinit var recipients: RecipientTable
|
|
private lateinit var sms: SmsTable
|
|
|
|
private val localAci = ACI.from(UUID.randomUUID())
|
|
private val localPni = PNI.from(UUID.randomUUID())
|
|
|
|
private var wallClock: Long = 1000
|
|
|
|
private lateinit var alice: RecipientId
|
|
private lateinit var bob: RecipientId
|
|
|
|
@Before
|
|
fun setUp() {
|
|
recipients = SignalDatabase.recipients
|
|
sms = SignalDatabase.sms
|
|
|
|
SignalStore.account().setAci(localAci)
|
|
SignalStore.account().setPni(localPni)
|
|
|
|
alice = recipients.getOrInsertFromServiceId(aliceServiceId)
|
|
bob = recipients.getOrInsertFromServiceId(bobServiceId)
|
|
}
|
|
|
|
/**
|
|
* Do nothing if no previous messages.
|
|
*/
|
|
@Test
|
|
fun noPreviousMessage() {
|
|
val result = sms.collapseJoinRequestEventsIfPossible(
|
|
1,
|
|
groupUpdateMessage(
|
|
sender = alice,
|
|
groupContext = groupContext(masterKey = masterKey) {
|
|
change = groupChange(editor = aliceServiceId) {
|
|
deleteRequestingMember(aliceServiceId)
|
|
}
|
|
}
|
|
)
|
|
)
|
|
|
|
assertThat("result is null when not collapsing", result.orElse(null), nullValue())
|
|
}
|
|
|
|
/**
|
|
* Do nothing if previous message is text.
|
|
*/
|
|
@Test
|
|
fun previousTextMesssage() {
|
|
val threadId = sms.insertMessageInbox(smsMessage(sender = alice, body = "What up")).get().threadId
|
|
|
|
val result = sms.collapseJoinRequestEventsIfPossible(
|
|
threadId,
|
|
groupUpdateMessage(
|
|
sender = alice,
|
|
groupContext = groupContext(masterKey = masterKey) {
|
|
change = groupChange(editor = aliceServiceId) {
|
|
deleteRequestingMember(aliceServiceId)
|
|
}
|
|
}
|
|
)
|
|
)
|
|
|
|
assertThat("result is null when not collapsing", result.orElse(null), nullValue())
|
|
}
|
|
|
|
/**
|
|
* Do nothing if previous is unrelated group change.
|
|
*/
|
|
@Test
|
|
fun previousUnrelatedGroupChange() {
|
|
val threadId = sms.insertMessageInbox(
|
|
groupUpdateMessage(
|
|
sender = alice,
|
|
groupContext = groupContext(masterKey = masterKey) {
|
|
change = groupChange(editor = aliceServiceId) {
|
|
addMember(bobServiceId)
|
|
}
|
|
}
|
|
)
|
|
).get().threadId
|
|
|
|
val result = sms.collapseJoinRequestEventsIfPossible(
|
|
threadId,
|
|
groupUpdateMessage(
|
|
sender = alice,
|
|
groupContext = groupContext(masterKey = masterKey) {
|
|
change = groupChange(editor = aliceServiceId) {
|
|
deleteRequestingMember(aliceServiceId)
|
|
}
|
|
}
|
|
)
|
|
)
|
|
|
|
assertThat("result is null when not collapsing", result.orElse(null), nullValue())
|
|
}
|
|
|
|
/**
|
|
* Do nothing if previous join request is from a different recipient.
|
|
*/
|
|
@Test
|
|
fun previousJoinRequestFromADifferentRecipient() {
|
|
val threadId = sms.insertMessageInbox(
|
|
groupUpdateMessage(
|
|
sender = bob,
|
|
groupContext = groupContext(masterKey = masterKey) {
|
|
change = groupChange(editor = bobServiceId) {
|
|
deleteRequestingMember(bobServiceId)
|
|
}
|
|
}
|
|
)
|
|
).get().threadId
|
|
|
|
val result = sms.collapseJoinRequestEventsIfPossible(
|
|
threadId,
|
|
groupUpdateMessage(
|
|
sender = alice,
|
|
groupContext = groupContext(masterKey = masterKey) {
|
|
change = groupChange(editor = aliceServiceId) {
|
|
deleteRequestingMember(aliceServiceId)
|
|
}
|
|
}
|
|
)
|
|
)
|
|
|
|
assertThat("result is null when not collapsing", result.orElse(null), nullValue())
|
|
}
|
|
|
|
/**
|
|
* Collapse if previous is join request from same.
|
|
*/
|
|
@Test
|
|
fun previousJoinRequestCollapse() {
|
|
val latestMessage: MessageTable.InsertResult = sms.insertMessageInbox(
|
|
groupUpdateMessage(
|
|
sender = alice,
|
|
groupContext = groupContext(masterKey = masterKey) {
|
|
change = groupChange(editor = aliceServiceId) {
|
|
addRequestingMember(aliceServiceId)
|
|
}
|
|
}
|
|
)
|
|
).get()
|
|
|
|
val result = sms.collapseJoinRequestEventsIfPossible(
|
|
latestMessage.threadId,
|
|
groupUpdateMessage(
|
|
sender = alice,
|
|
groupContext = groupContext(masterKey = masterKey) {
|
|
change = groupChange(editor = aliceServiceId) {
|
|
deleteRequestingMember(aliceServiceId)
|
|
}
|
|
}
|
|
)
|
|
)
|
|
|
|
assertThat("result is not null when collapsing", result.orElse(null), notNullValue())
|
|
assertThat("result message id should be same as latest message", result.get().messageId, `is`(latestMessage.messageId))
|
|
}
|
|
|
|
/**
|
|
* Collapse if previous is join request from same, and leave second previous alone if text.
|
|
*/
|
|
@Test
|
|
fun previousJoinThenTextCollapse() {
|
|
val secondLatestMessage = sms.insertMessageInbox(smsMessage(sender = alice, body = "What up")).get()
|
|
|
|
val latestMessage: MessageTable.InsertResult = sms.insertMessageInbox(
|
|
groupUpdateMessage(
|
|
sender = alice,
|
|
groupContext = groupContext(masterKey = masterKey) {
|
|
change = groupChange(editor = aliceServiceId) {
|
|
addRequestingMember(aliceServiceId)
|
|
}
|
|
}
|
|
)
|
|
).get()
|
|
|
|
assert(secondLatestMessage.threadId == latestMessage.threadId)
|
|
|
|
val result = sms.collapseJoinRequestEventsIfPossible(
|
|
latestMessage.threadId,
|
|
groupUpdateMessage(
|
|
sender = alice,
|
|
groupContext = groupContext(masterKey = masterKey) {
|
|
change = groupChange(editor = aliceServiceId) {
|
|
deleteRequestingMember(aliceServiceId)
|
|
}
|
|
}
|
|
)
|
|
)
|
|
|
|
assertThat("result is not null when collapsing", result.orElse(null), notNullValue())
|
|
assertThat("result message id should be same as latest message", result.get().messageId, `is`(latestMessage.messageId))
|
|
}
|
|
|
|
/**
|
|
* Collapse "twice" is previous is a join request and second previous is already collapsed join/delete from the same recipient.
|
|
*/
|
|
@Test
|
|
fun previousCollapseAndJoinRequestDoubleCollapse() {
|
|
val secondLatestMessage: MessageTable.InsertResult = sms.insertMessageInbox(
|
|
groupUpdateMessage(
|
|
sender = alice,
|
|
groupContext = groupContext(masterKey = masterKey) {
|
|
change = groupChange(editor = aliceServiceId) {
|
|
addRequestingMember(aliceServiceId)
|
|
deleteRequestingMember(aliceServiceId)
|
|
}
|
|
}
|
|
)
|
|
).get()
|
|
|
|
val latestMessage: MessageTable.InsertResult = sms.insertMessageInbox(
|
|
groupUpdateMessage(
|
|
sender = alice,
|
|
groupContext = groupContext(masterKey = masterKey) {
|
|
change = groupChange(editor = aliceServiceId) {
|
|
addRequestingMember(aliceServiceId)
|
|
}
|
|
}
|
|
)
|
|
).get()
|
|
|
|
assert(secondLatestMessage.threadId == latestMessage.threadId)
|
|
|
|
val result = sms.collapseJoinRequestEventsIfPossible(
|
|
latestMessage.threadId,
|
|
groupUpdateMessage(
|
|
sender = alice,
|
|
groupContext = groupContext(masterKey = masterKey) {
|
|
change = groupChange(editor = aliceServiceId) {
|
|
deleteRequestingMember(aliceServiceId)
|
|
}
|
|
}
|
|
)
|
|
)
|
|
|
|
assertThat("result is not null when collapsing", result.orElse(null), notNullValue())
|
|
assertThat("result message id should be same as second latest message", result.get().messageId, `is`(secondLatestMessage.messageId))
|
|
assertThat("latest message should be deleted", sms.getMessageRecordOrNull(latestMessage.messageId), nullValue())
|
|
}
|
|
|
|
private fun smsMessage(sender: RecipientId, body: String? = ""): IncomingTextMessage {
|
|
wallClock++
|
|
return IncomingTextMessage(sender, 1, wallClock, wallClock, wallClock, body, Optional.of(groupId), 0, true, null)
|
|
}
|
|
|
|
private fun groupUpdateMessage(sender: RecipientId, groupContext: DecryptedGroupV2Context): IncomingGroupUpdateMessage {
|
|
return IncomingGroupUpdateMessage(smsMessage(sender, null), groupContext)
|
|
}
|
|
|
|
companion object {
|
|
private val aliceServiceId: ServiceId = ACI.from(UUID.fromString("3436efbe-5a76-47fa-a98a-7e72c948a82e"))
|
|
private val bobServiceId: ServiceId = ACI.from(UUID.fromString("8de7f691-0b60-4a68-9cd9-ed2f8453f9ed"))
|
|
|
|
private val masterKey = GroupMasterKey(Hex.fromStringCondensed("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"))
|
|
private val groupId = GroupId.v2(masterKey)
|
|
}
|
|
}
|