mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-27 21:24:42 +00:00
Convert GroupTable to kotlin.
Also required converting some tests to mockk.
This commit is contained in:
@@ -13,6 +13,7 @@ import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedString
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedTimer
|
||||
import org.signal.storageservice.protos.groups.local.EnabledState
|
||||
import org.thoughtcrime.securesms.database.model.GroupRecord
|
||||
import org.thoughtcrime.securesms.groups.GroupId
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupHistoryEntry
|
||||
@@ -99,7 +100,7 @@ class GroupChangeData(private val revision: Int, private val groupOperations: Gr
|
||||
class GroupStateTestData(private val masterKey: GroupMasterKey, private val groupOperations: GroupsV2Operations.GroupOperations? = null) {
|
||||
|
||||
var localState: DecryptedGroup? = null
|
||||
var groupRecord: Optional<GroupTable.GroupRecord> = Optional.empty()
|
||||
var groupRecord: Optional<GroupRecord> = Optional.empty()
|
||||
var serverState: DecryptedGroup? = null
|
||||
var changeSet: ChangeSet? = null
|
||||
var groupChange: GroupChange? = null
|
||||
@@ -172,9 +173,9 @@ fun groupRecord(
|
||||
avatarDigest: ByteArray = ByteArray(0),
|
||||
mms: Boolean = false,
|
||||
distributionId: DistributionId? = null
|
||||
): Optional<GroupTable.GroupRecord> {
|
||||
): Optional<GroupRecord> {
|
||||
return Optional.of(
|
||||
GroupTable.GroupRecord(
|
||||
GroupRecord(
|
||||
id,
|
||||
recipientId,
|
||||
decryptedGroup.title,
|
||||
|
||||
@@ -4,6 +4,10 @@ package org.thoughtcrime.securesms.groups
|
||||
|
||||
import android.app.Application
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.slot
|
||||
import io.mockk.verify
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.hamcrest.Matchers
|
||||
import org.hamcrest.Matchers.`is`
|
||||
@@ -11,9 +15,6 @@ import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.Mockito.mock
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.signal.core.util.Hex
|
||||
@@ -71,8 +72,6 @@ class GroupManagerV2Test_edit {
|
||||
private lateinit var sendGroupUpdateHelper: GroupManagerV2.SendGroupUpdateHelper
|
||||
private lateinit var groupOperations: GroupsV2Operations.GroupOperations
|
||||
|
||||
private lateinit var patchedDecryptedGroup: ArgumentCaptor<DecryptedGroup>
|
||||
|
||||
private lateinit var manager: GroupManagerV2
|
||||
|
||||
@get:Rule
|
||||
@@ -87,17 +86,15 @@ class GroupManagerV2Test_edit {
|
||||
|
||||
val clientZkOperations = ClientZkOperations(server.getServerPublicParams())
|
||||
|
||||
groupTable = mock(GroupTable::class.java)
|
||||
groupsV2API = mock(GroupsV2Api::class.java)
|
||||
groupTable = mockk()
|
||||
groupsV2API = mockk()
|
||||
groupsV2Operations = GroupsV2Operations(clientZkOperations, 1000)
|
||||
groupsV2Authorization = mock(GroupsV2Authorization::class.java)
|
||||
groupsV2StateProcessor = mock(GroupsV2StateProcessor::class.java)
|
||||
groupCandidateHelper = mock(GroupCandidateHelper::class.java)
|
||||
sendGroupUpdateHelper = mock(GroupManagerV2.SendGroupUpdateHelper::class.java)
|
||||
groupsV2Authorization = mockk(relaxed = true)
|
||||
groupsV2StateProcessor = mockk()
|
||||
groupCandidateHelper = mockk()
|
||||
sendGroupUpdateHelper = mockk()
|
||||
groupOperations = groupsV2Operations.forGroup(groupSecretParams)
|
||||
|
||||
patchedDecryptedGroup = ArgumentCaptor.forClass(DecryptedGroup::class.java)
|
||||
|
||||
manager = GroupManagerV2(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
groupTable,
|
||||
@@ -115,12 +112,11 @@ class GroupManagerV2Test_edit {
|
||||
val data = GroupStateTestData(masterKey, groupOperations)
|
||||
data.init()
|
||||
|
||||
Mockito.doReturn(data.groupRecord).`when`(groupTable).getGroup(groupId)
|
||||
Mockito.doReturn(data.groupRecord.get()).`when`(groupTable).requireGroup(groupId)
|
||||
|
||||
Mockito.doReturn(GroupManagerV2.RecipientAndThread(Recipient.UNKNOWN, 1)).`when`(sendGroupUpdateHelper).sendGroupUpdate(Mockito.eq(masterKey), Mockito.any(), Mockito.any(), Mockito.anyBoolean())
|
||||
|
||||
Mockito.doReturn(data.groupChange!!).`when`(groupsV2API).patchGroup(Mockito.any(), Mockito.any(), Mockito.any())
|
||||
every { groupTable.getGroup(groupId) } returns data.groupRecord
|
||||
every { groupTable.requireGroup(groupId) } returns data.groupRecord.get()
|
||||
every { groupTable.update(any<GroupId.V2>(), any()) } returns Unit
|
||||
every { sendGroupUpdateHelper.sendGroupUpdate(masterKey, any(), any(), any()) } returns GroupManagerV2.RecipientAndThread(Recipient.UNKNOWN, 1)
|
||||
every { groupsV2API.patchGroup(any(), any(), any()) } returns data.groupChange!!
|
||||
}
|
||||
|
||||
private fun editGroup(perform: GroupManagerV2.GroupEditor.() -> Unit) {
|
||||
@@ -128,8 +124,9 @@ class GroupManagerV2Test_edit {
|
||||
}
|
||||
|
||||
private fun then(then: (DecryptedGroup) -> Unit) {
|
||||
Mockito.verify(groupTable).update(Mockito.eq(groupId), patchedDecryptedGroup.capture())
|
||||
then(patchedDecryptedGroup.value)
|
||||
val decryptedGroupArg = slot<DecryptedGroup>()
|
||||
verify { groupTable.update(groupId, capture(decryptedGroupArg)) }
|
||||
then(decryptedGroupArg.captured)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -2,6 +2,10 @@ package org.thoughtcrime.securesms.groups.v2.processing
|
||||
|
||||
import android.app.Application
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.verify
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.hamcrest.Matchers.both
|
||||
import org.hamcrest.Matchers.hasItem
|
||||
@@ -13,18 +17,6 @@ import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.ArgumentMatchers.anyLong
|
||||
import org.mockito.ArgumentMatchers.eq
|
||||
import org.mockito.Mockito.any
|
||||
import org.mockito.Mockito.doCallRealMethod
|
||||
import org.mockito.Mockito.doReturn
|
||||
import org.mockito.Mockito.isA
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.Mockito.reset
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.kotlin.anyOrNull
|
||||
import org.mockito.kotlin.doNothing
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.signal.core.util.Hex.fromStringCondensed
|
||||
@@ -48,6 +40,7 @@ import org.thoughtcrime.securesms.database.setNewTitle
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.groups.GroupId
|
||||
import org.thoughtcrime.securesms.groups.GroupsV2Authorization
|
||||
import org.thoughtcrime.securesms.jobmanager.JobManager
|
||||
import org.thoughtcrime.securesms.jobs.RequestGroupV2InfoJob
|
||||
import org.thoughtcrime.securesms.logging.CustomSignalProtocolLogger
|
||||
import org.thoughtcrime.securesms.testutil.SystemOutLogger
|
||||
@@ -77,6 +70,7 @@ class GroupsV2StateProcessorTest {
|
||||
private lateinit var groupsV2API: GroupsV2Api
|
||||
private lateinit var groupsV2Authorization: GroupsV2Authorization
|
||||
private lateinit var profileAndMessageHelper: GroupsV2StateProcessor.ProfileAndMessageHelper
|
||||
private lateinit var jobManager: JobManager
|
||||
|
||||
private lateinit var processor: GroupsV2StateProcessor.StateProcessorForGroup
|
||||
|
||||
@@ -88,25 +82,29 @@ class GroupsV2StateProcessorTest {
|
||||
Log.initialize(SystemOutLogger())
|
||||
SignalProtocolLoggerProvider.setProvider(CustomSignalProtocolLogger())
|
||||
|
||||
groupTable = mock(GroupTable::class.java)
|
||||
recipientTable = mock(RecipientTable::class.java)
|
||||
groupsV2API = mock(GroupsV2Api::class.java)
|
||||
groupsV2Authorization = mock(GroupsV2Authorization::class.java)
|
||||
profileAndMessageHelper = mock(GroupsV2StateProcessor.ProfileAndMessageHelper::class.java)
|
||||
groupTable = mockk(relaxed = true)
|
||||
recipientTable = mockk()
|
||||
groupsV2API = mockk()
|
||||
groupsV2Authorization = mockk(relaxed = true)
|
||||
profileAndMessageHelper = mockk(relaxed = true)
|
||||
jobManager = mockk(relaxed = true)
|
||||
|
||||
mockkStatic(ApplicationDependencies::class)
|
||||
every { ApplicationDependencies.getJobManager() } returns jobManager
|
||||
|
||||
processor = GroupsV2StateProcessor.StateProcessorForGroup(serviceIds, ApplicationProvider.getApplicationContext(), groupTable, groupsV2API, groupsV2Authorization, masterKey, profileAndMessageHelper)
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
reset(ApplicationDependencies.getJobManager())
|
||||
// reset(ApplicationDependencies.getJobManager())
|
||||
}
|
||||
|
||||
private fun given(init: GroupStateTestData.() -> Unit) {
|
||||
val data = givenData(init)
|
||||
|
||||
doReturn(data.groupRecord).`when`(groupTable).getGroup(any(GroupId.V2::class.java))
|
||||
doReturn(!data.groupRecord.isPresent).`when`(groupTable).isUnknownGroup(any())
|
||||
every { groupTable.getGroup(any<GroupId.V2>()) } returns data.groupRecord
|
||||
every { groupTable.isUnknownGroup(any()) } returns !data.groupRecord.isPresent
|
||||
|
||||
data.serverState?.let { serverState ->
|
||||
val testPartial = object : PartialDecryptedGroup(null, serverState, null, null) {
|
||||
@@ -114,12 +112,13 @@ class GroupsV2StateProcessorTest {
|
||||
return serverState
|
||||
}
|
||||
}
|
||||
doReturn(testPartial).`when`(groupsV2API).getPartialDecryptedGroup(any(), any())
|
||||
doReturn(serverState).`when`(groupsV2API).getGroup(any(), any())
|
||||
|
||||
every { groupsV2API.getPartialDecryptedGroup(any(), any()) } returns testPartial
|
||||
every { groupsV2API.getGroup(any(), any()) } returns serverState
|
||||
}
|
||||
|
||||
data.changeSet?.let { changeSet ->
|
||||
doReturn(changeSet.toApiResponse()).`when`(groupsV2API).getGroupHistoryPage(any(), eq(data.requestedRevision), any(), eq(data.includeFirst))
|
||||
every { groupsV2API.getGroupHistoryPage(any(), data.requestedRevision, any(), data.includeFirst) } returns changeSet.toApiResponse()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,15 +305,14 @@ class GroupsV2StateProcessorTest {
|
||||
apiCallParameters(2, true)
|
||||
}
|
||||
|
||||
doReturn(true).`when`(groupTable).isUnknownGroup(any())
|
||||
every { groupTable.isUnknownGroup(any()) } returns true
|
||||
|
||||
val result = processor.updateLocalGroupToRevision(2, 0, DecryptedGroupChange.getDefaultInstance())
|
||||
|
||||
assertThat("local should update to revision added", result.groupState, `is`(GroupsV2StateProcessor.GroupState.GROUP_UPDATED))
|
||||
assertThat("revision matches peer revision added", result.latestServer!!.revision, `is`(2))
|
||||
assertThat("title matches that as it was in revision added", result.latestServer!!.title, `is`("Baking Signal for Science"))
|
||||
|
||||
verify(ApplicationDependencies.getJobManager()).add(isA(RequestGroupV2InfoJob::class.java))
|
||||
verify { jobManager.add(ofType(RequestGroupV2InfoJob::class)) }
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -406,7 +404,7 @@ class GroupsV2StateProcessorTest {
|
||||
assertThat("local should update to server", result.groupState, `is`(GroupsV2StateProcessor.GroupState.GROUP_UPDATED))
|
||||
assertThat("revision matches revision approved at", result.latestServer!!.revision, `is`(3))
|
||||
assertThat("title matches revision approved at", result.latestServer!!.title, `is`("Beam me up"))
|
||||
verify(ApplicationDependencies.getJobManager()).add(isA(RequestGroupV2InfoJob::class.java))
|
||||
verify { jobManager.add(ofType(RequestGroupV2InfoJob::class)) }
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -458,7 +456,7 @@ class GroupsV2StateProcessorTest {
|
||||
}
|
||||
}
|
||||
}
|
||||
doReturn(secondApiCallChangeSet.changeSet!!.toApiResponse()).`when`(groupsV2API).getGroupHistoryPage(any(), eq(100), any(), eq(true))
|
||||
every { groupsV2API.getGroupHistoryPage(any(), 100, any(), true) } returns secondApiCallChangeSet.changeSet!!.toApiResponse()
|
||||
|
||||
val result = processor.updateLocalGroupToRevision(GroupsV2StateProcessor.LATEST, 0, null)
|
||||
|
||||
@@ -474,10 +472,11 @@ class GroupsV2StateProcessorTest {
|
||||
fun missedMemberAddResolvesWithMultipleRevisionUpdate() {
|
||||
val secondOther = member(ServiceId.from(UUID.randomUUID()))
|
||||
|
||||
val updateMessageContextCapture = ArgumentCaptor.forClass(DecryptedGroupV2Context::class.java)
|
||||
profileAndMessageHelper.masterKey = masterKey
|
||||
doCallRealMethod().`when`(profileAndMessageHelper).insertUpdateMessages(anyLong(), anyOrNull(), any())
|
||||
doNothing().`when`(profileAndMessageHelper).storeMessage(updateMessageContextCapture.capture(), anyLong())
|
||||
|
||||
val updateMessageContextArgs = mutableListOf<DecryptedGroupV2Context>()
|
||||
every { profileAndMessageHelper.insertUpdateMessages(any(), any(), any()) } answers { callOriginal() }
|
||||
every { profileAndMessageHelper.storeMessage(capture(updateMessageContextArgs), any()) } returns Unit
|
||||
|
||||
given {
|
||||
localState(
|
||||
@@ -513,8 +512,7 @@ class GroupsV2StateProcessorTest {
|
||||
assertThat("local should update to server", result.groupState, `is`(GroupsV2StateProcessor.GroupState.GROUP_UPDATED))
|
||||
assertThat("members contains second other", result.latestServer!!.membersList, hasItem(secondOther))
|
||||
|
||||
val allUpdateMessageContexts = updateMessageContextCapture.allValues
|
||||
assertThat("group update messages contains new member add", allUpdateMessageContexts.map { it.change.newMembersList }, hasItem(hasItem(secondOther)))
|
||||
assertThat("group update messages contains new member add", updateMessageContextArgs.map { it.change.newMembersList }, hasItem(hasItem(secondOther)))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -525,10 +523,11 @@ class GroupsV2StateProcessorTest {
|
||||
fun missedMemberAddResolvesWithForcedUpdate() {
|
||||
val secondOther = member(ServiceId.from(UUID.randomUUID()))
|
||||
|
||||
val updateMessageContextCapture = ArgumentCaptor.forClass(DecryptedGroupV2Context::class.java)
|
||||
profileAndMessageHelper.masterKey = masterKey
|
||||
doCallRealMethod().`when`(profileAndMessageHelper).insertUpdateMessages(anyLong(), anyOrNull(), any())
|
||||
doNothing().`when`(profileAndMessageHelper).storeMessage(updateMessageContextCapture.capture(), anyLong())
|
||||
|
||||
val updateMessageContextArgs = mutableListOf<DecryptedGroupV2Context>()
|
||||
every { profileAndMessageHelper.insertUpdateMessages(any(), any(), any()) } answers { callOriginal() }
|
||||
every { profileAndMessageHelper.storeMessage(capture(updateMessageContextArgs), any()) } returns Unit
|
||||
|
||||
given {
|
||||
localState(
|
||||
@@ -548,12 +547,11 @@ class GroupsV2StateProcessorTest {
|
||||
assertThat("members contains second other", result.latestServer!!.membersList, hasItem(secondOther))
|
||||
assertThat("title should be updated", result.latestServer!!.title, `is`("Changed"))
|
||||
|
||||
val allUpdateMessageContexts = updateMessageContextCapture.allValues
|
||||
assertThat("group update messages contains new member add", allUpdateMessageContexts.map { it.change.newMembersList }, hasItem(hasItem(secondOther)))
|
||||
assertThat("group update messages contains new member add", updateMessageContextArgs.map { it.change.newMembersList }, hasItem(hasItem(secondOther)))
|
||||
|
||||
assertThat(
|
||||
"group update messages contains title change",
|
||||
allUpdateMessageContexts.map { it.change.newTitle },
|
||||
updateMessageContextArgs.map { it.change.newTitle },
|
||||
hasItem(both<DecryptedString>(notNullValue()).and(hasProperty("value", `is`("Changed"))))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.jobmanager.migrations;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.thoughtcrime.securesms.database.GroupTable;
|
||||
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||
import org.thoughtcrime.securesms.groups.GroupId;
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobMigration;
|
||||
@@ -34,7 +35,7 @@ public class SenderKeyDistributionSendJobRecipientMigrationTest {
|
||||
.putBlobAsString("group_id", GROUP_ID.getDecodedId())
|
||||
.build());
|
||||
|
||||
GroupTable.GroupRecord mockGroup = mock(GroupTable.GroupRecord.class);
|
||||
GroupRecord mockGroup = mock(GroupRecord.class);
|
||||
when(mockGroup.getRecipientId()).thenReturn(RecipientId.from(2));
|
||||
when(mockDatabase.getGroup(GROUP_ID)).thenReturn(Optional.of(mockGroup));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user