Make KeysBackup test pass (still work to do)

This commit is contained in:
Benoit Marty 2020-02-21 17:58:04 +01:00
parent ccfa59ad31
commit d167ff9496
4 changed files with 184 additions and 395 deletions

View file

@ -41,16 +41,15 @@ import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue import org.junit.Assert.assertTrue
import java.util.Arrays
import java.util.HashMap import java.util.HashMap
import java.util.concurrent.CountDownLatch import java.util.concurrent.CountDownLatch
class CryptoTestHelper(val mTestHelper: CommonTestHelper) { class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
val messagesFromAlice: List<String> = Arrays.asList("0 - Hello I'm Alice!", "4 - Go!") private val messagesFromAlice: List<String> = listOf("0 - Hello I'm Alice!", "4 - Go!")
val messagesFromBob: List<String> = Arrays.asList("1 - Hello I'm Bob!", "2 - Isn't life grand?", "3 - Let's go to the opera.") private val messagesFromBob: List<String> = listOf("1 - Hello I'm Bob!", "2 - Isn't life grand?", "3 - Let's go to the opera.")
val defaultSessionParams = SessionTestParams(true) private val defaultSessionParams = SessionTestParams(true)
/** /**
* @return alice session * @return alice session
@ -58,34 +57,23 @@ class CryptoTestHelper(val mTestHelper: CommonTestHelper) {
fun doE2ETestWithAliceInARoom(): CryptoTestData { fun doE2ETestWithAliceInARoom(): CryptoTestData {
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, defaultSessionParams) val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, defaultSessionParams)
var roomId: String? = null val roomId = mTestHelper.doSync<String> {
val lock1 = CountDownLatch(1) aliceSession.createRoom(CreateRoomParams(name = "MyRoom"), it)
aliceSession.createRoom(CreateRoomParams(name = "MyRoom"), object : TestMatrixCallback<String>(lock1) {
override fun onSuccess(data: String) {
roomId = data
super.onSuccess(data)
} }
})
mTestHelper.await(lock1) val room = aliceSession.getRoom(roomId)!!
assertNotNull(roomId)
val room = aliceSession.getRoom(roomId!!)!! mTestHelper.doSync<Unit> {
room.enableEncryption(callback = it)
}
val lock2 = CountDownLatch(1) return CryptoTestData(aliceSession, roomId)
room.enableEncryption(callback = TestMatrixCallback(lock2))
mTestHelper.await(lock2)
return CryptoTestData(aliceSession, roomId!!)
} }
/** /**
* @return alice and bob sessions * @return alice and bob sessions
*/ */
fun doE2ETestWithAliceAndBobInARoom(): CryptoTestData { fun doE2ETestWithAliceAndBobInARoom(): CryptoTestData {
val statuses = HashMap<String, String>()
val cryptoTestData = doE2ETestWithAliceInARoom() val cryptoTestData = doE2ETestWithAliceInARoom()
val aliceSession = cryptoTestData.firstSession val aliceSession = cryptoTestData.firstSession
val aliceRoomId = cryptoTestData.roomId val aliceRoomId = cryptoTestData.roomId
@ -94,7 +82,7 @@ class CryptoTestHelper(val mTestHelper: CommonTestHelper) {
val bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, defaultSessionParams) val bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, defaultSessionParams)
val lock1 = CountDownLatch(2) val lock1 = CountDownLatch(1)
val bobRoomSummariesLive = runBlocking(Dispatchers.Main) { val bobRoomSummariesLive = runBlocking(Dispatchers.Main) {
bobSession.getRoomSummariesLive(roomSummaryQueryParams { }) bobSession.getRoomSummariesLive(roomSummaryQueryParams { })
@ -103,7 +91,6 @@ class CryptoTestHelper(val mTestHelper: CommonTestHelper) {
val newRoomObserver = object : Observer<List<RoomSummary>> { val newRoomObserver = object : Observer<List<RoomSummary>> {
override fun onChanged(t: List<RoomSummary>?) { override fun onChanged(t: List<RoomSummary>?) {
if (t?.isNotEmpty() == true) { if (t?.isNotEmpty() == true) {
statuses["onNewRoom"] = "onNewRoom"
lock1.countDown() lock1.countDown()
bobRoomSummariesLive.removeObserver(this) bobRoomSummariesLive.removeObserver(this)
} }
@ -114,26 +101,20 @@ class CryptoTestHelper(val mTestHelper: CommonTestHelper) {
bobRoomSummariesLive.observeForever(newRoomObserver) bobRoomSummariesLive.observeForever(newRoomObserver)
} }
aliceRoom.invite(bobSession.myUserId, callback = object : TestMatrixCallback<Unit>(lock1) { mTestHelper.doSync<Unit> {
override fun onSuccess(data: Unit) { aliceRoom.invite(bobSession.myUserId, callback = it)
statuses["invite"] = "invite"
super.onSuccess(data)
} }
})
mTestHelper.await(lock1) mTestHelper.await(lock1)
assertTrue(statuses.containsKey("invite") && statuses.containsKey("onNewRoom")) val lock = CountDownLatch(1)
val lock2 = CountDownLatch(2)
val roomJoinedObserver = object : Observer<List<RoomSummary>> { val roomJoinedObserver = object : Observer<List<RoomSummary>> {
override fun onChanged(t: List<RoomSummary>?) { override fun onChanged(t: List<RoomSummary>?) {
if (bobSession.getRoom(aliceRoomId) if (bobSession.getRoom(aliceRoomId)
?.getRoomMember(aliceSession.myUserId) ?.getRoomMember(aliceSession.myUserId)
?.membership == Membership.JOIN) { ?.membership == Membership.JOIN) {
statuses["AliceJoin"] = "AliceJoin" lock.countDown()
lock2.countDown()
bobRoomSummariesLive.removeObserver(this) bobRoomSummariesLive.removeObserver(this)
} }
} }
@ -143,19 +124,15 @@ class CryptoTestHelper(val mTestHelper: CommonTestHelper) {
bobRoomSummariesLive.observeForever(roomJoinedObserver) bobRoomSummariesLive.observeForever(roomJoinedObserver)
} }
bobSession.joinRoom(aliceRoomId, callback = TestMatrixCallback(lock2)) mTestHelper.doSync<Unit> { bobSession.joinRoom(aliceRoomId, callback = it) }
mTestHelper.await(lock2) mTestHelper.await(lock)
// Ensure bob can send messages to the room // Ensure bob can send messages to the room
// val roomFromBobPOV = bobSession.getRoom(aliceRoomId)!! // val roomFromBobPOV = bobSession.getRoom(aliceRoomId)!!
// assertNotNull(roomFromBobPOV.powerLevels) // assertNotNull(roomFromBobPOV.powerLevels)
// assertTrue(roomFromBobPOV.powerLevels.maySendMessage(bobSession.myUserId)) // assertTrue(roomFromBobPOV.powerLevels.maySendMessage(bobSession.myUserId))
assertTrue(statuses.toString() + "", statuses.containsKey("AliceJoin"))
// bobSession.dataHandler.removeListener(bobEventListener)
return CryptoTestData(aliceSession, aliceRoomId, bobSession) return CryptoTestData(aliceSession, aliceRoomId, bobSession)
} }
@ -237,7 +214,7 @@ class CryptoTestHelper(val mTestHelper: CommonTestHelper) {
val roomFromBobPOV = bobSession.getRoom(aliceRoomId)!! val roomFromBobPOV = bobSession.getRoom(aliceRoomId)!!
val roomFromAlicePOV = aliceSession.getRoom(aliceRoomId)!! val roomFromAlicePOV = aliceSession.getRoom(aliceRoomId)!!
var lock = CountDownLatch(1) val lock = CountDownLatch(1)
val bobEventsListener = object : Timeline.Listener { val bobEventsListener = object : Timeline.Listener {
override fun onTimelineFailure(throwable: Throwable) { override fun onTimelineFailure(throwable: Throwable) {
@ -249,63 +226,35 @@ class CryptoTestHelper(val mTestHelper: CommonTestHelper) {
} }
override fun onTimelineUpdated(snapshot: List<TimelineEvent>) { override fun onTimelineUpdated(snapshot: List<TimelineEvent>) {
val size = snapshot.filter { it.root.senderId != bobSession.myUserId && it.root.getClearType() == EventType.MESSAGE } val messages = snapshot.filter { it.root.getClearType() == EventType.MESSAGE }
.size .groupBy { it.root.senderId!! }
if (size == 3) { // Alice has sent 2 messages and Bob has sent 3 messages
if (messages[aliceSession.myUserId]?.size == 2 && messages[bobSession.myUserId]?.size == 3) {
lock.countDown() lock.countDown()
} }
} }
} }
val bobTimeline = roomFromBobPOV.createTimeline(null, TimelineSettings(10)) val bobTimeline = roomFromBobPOV.createTimeline(null, TimelineSettings(10))
bobTimeline.start()
bobTimeline.addListener(bobEventsListener) bobTimeline.addListener(bobEventsListener)
val results = HashMap<String, Any>()
// bobSession.dataHandler.addListener(object : MXEventListener() {
// override fun onToDeviceEvent(event: Event) {
// results["onToDeviceEvent"] = event
// lock.countDown()
// }
// })
// Alice sends a message // Alice sends a message
roomFromAlicePOV.sendTextMessage(messagesFromAlice[0]) roomFromAlicePOV.sendTextMessage(messagesFromAlice[0])
assertTrue(results.containsKey("onToDeviceEvent"))
// assertEquals(1, messagesReceivedByBobCount)
// Bob send a message // Bob send 3 messages
lock = CountDownLatch(1)
roomFromBobPOV.sendTextMessage(messagesFromBob[0]) roomFromBobPOV.sendTextMessage(messagesFromBob[0])
// android does not echo the messages sent from itself
// messagesReceivedByBobCount++
mTestHelper.await(lock)
// assertEquals(2, messagesReceivedByBobCount)
// Bob send a message
lock = CountDownLatch(1)
roomFromBobPOV.sendTextMessage(messagesFromBob[1]) roomFromBobPOV.sendTextMessage(messagesFromBob[1])
// android does not echo the messages sent from itself
// messagesReceivedByBobCount++
mTestHelper.await(lock)
// assertEquals(3, messagesReceivedByBobCount)
// Bob send a message
lock = CountDownLatch(1)
roomFromBobPOV.sendTextMessage(messagesFromBob[2]) roomFromBobPOV.sendTextMessage(messagesFromBob[2])
// android does not echo the messages sent from itself
// messagesReceivedByBobCount++
mTestHelper.await(lock)
// assertEquals(4, messagesReceivedByBobCount)
// Alice sends a message // Alice sends a message
lock = CountDownLatch(2)
roomFromAlicePOV.sendTextMessage(messagesFromAlice[1]) roomFromAlicePOV.sendTextMessage(messagesFromAlice[1])
mTestHelper.await(lock) mTestHelper.await(lock)
// assertEquals(5, messagesReceivedByBobCount)
bobTimeline.removeListener(bobEventsListener) bobTimeline.removeListener(bobEventsListener)
bobTimeline.dispose()
return cryptoTestData return cryptoTestData
} }

View file

@ -18,7 +18,6 @@ package im.vector.matrix.android.internal.crypto.keysbackup
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import im.vector.matrix.android.InstrumentedTest import im.vector.matrix.android.InstrumentedTest
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.listeners.ProgressListener import im.vector.matrix.android.api.listeners.ProgressListener
import im.vector.matrix.android.api.listeners.StepProgressListener import im.vector.matrix.android.api.listeners.StepProgressListener
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
@ -48,7 +47,6 @@ import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue import org.junit.Assert.assertTrue
import org.junit.Assert.fail
import org.junit.FixMethodOrder import org.junit.FixMethodOrder
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@ -58,7 +56,7 @@ import java.util.Collections
import java.util.concurrent.CountDownLatch import java.util.concurrent.CountDownLatch
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING) @FixMethodOrder(MethodSorters.JVM)
class KeysBackupTest : InstrumentedTest { class KeysBackupTest : InstrumentedTest {
private val mTestHelper = CommonTestHelper(context()) private val mTestHelper = CommonTestHelper(context())
@ -120,28 +118,15 @@ class KeysBackupTest : InstrumentedTest {
assertFalse(keysBackup.isEnabled) assertFalse(keysBackup.isEnabled)
val latch = CountDownLatch(1) val megolmBackupCreationInfo = mTestHelper.doSync<MegolmBackupCreationInfo> {
keysBackup.prepareKeysBackupVersion(null, null, it)
keysBackup.prepareKeysBackupVersion(null, null, object : MatrixCallback<MegolmBackupCreationInfo> {
override fun onSuccess(data: MegolmBackupCreationInfo) {
assertNotNull(data)
assertEquals(MXCRYPTO_ALGORITHM_MEGOLM_BACKUP, data.algorithm)
assertNotNull(data.authData)
assertNotNull(data.authData!!.publicKey)
assertNotNull(data.authData!!.signatures)
assertNotNull(data.recoveryKey)
latch.countDown()
} }
override fun onFailure(failure: Throwable) { assertEquals(MXCRYPTO_ALGORITHM_MEGOLM_BACKUP, megolmBackupCreationInfo.algorithm)
fail(failure.localizedMessage) assertNotNull(megolmBackupCreationInfo.authData)
assertNotNull(megolmBackupCreationInfo.authData!!.publicKey)
latch.countDown() assertNotNull(megolmBackupCreationInfo.authData!!.signatures)
} assertNotNull(megolmBackupCreationInfo.recoveryKey)
})
mTestHelper.await(latch)
stateObserver.stopAndCheckStates(null) stateObserver.stopAndCheckStates(null)
bobSession.close() bobSession.close()
@ -160,39 +145,16 @@ class KeysBackupTest : InstrumentedTest {
assertFalse(keysBackup.isEnabled) assertFalse(keysBackup.isEnabled)
var megolmBackupCreationInfo: MegolmBackupCreationInfo? = null val megolmBackupCreationInfo = mTestHelper.doSync<MegolmBackupCreationInfo> {
val latch = CountDownLatch(1) keysBackup.prepareKeysBackupVersion(null, null, it)
keysBackup.prepareKeysBackupVersion(null, null, object : MatrixCallback<MegolmBackupCreationInfo> {
override fun onSuccess(data: MegolmBackupCreationInfo) {
megolmBackupCreationInfo = data
latch.countDown()
} }
override fun onFailure(failure: Throwable) {
fail(failure.localizedMessage)
latch.countDown()
}
})
mTestHelper.await(latch)
assertNotNull(megolmBackupCreationInfo)
assertFalse(keysBackup.isEnabled) assertFalse(keysBackup.isEnabled)
val latch2 = CountDownLatch(1)
// Create the version // Create the version
keysBackup.createKeysBackupVersion(megolmBackupCreationInfo!!, object : TestMatrixCallback<KeysVersion>(latch2) { mTestHelper.doSync<KeysVersion> {
override fun onSuccess(data: KeysVersion) { keysBackup.createKeysBackupVersion(megolmBackupCreationInfo, it)
assertNotNull(data)
assertNotNull(data.version)
super.onSuccess(data)
} }
})
mTestHelper.await(latch2)
// Backup must be enable now // Backup must be enable now
assertTrue(keysBackup.isEnabled) assertTrue(keysBackup.isEnabled)
@ -259,18 +221,17 @@ class KeysBackupTest : InstrumentedTest {
assertEquals(2, nbOfKeys) assertEquals(2, nbOfKeys)
val latch = CountDownLatch(1)
var lastBackedUpKeysProgress = 0 var lastBackedUpKeysProgress = 0
mTestHelper.doSync<Unit> {
keysBackup.backupAllGroupSessions(object : ProgressListener { keysBackup.backupAllGroupSessions(object : ProgressListener {
override fun onProgress(progress: Int, total: Int) { override fun onProgress(progress: Int, total: Int) {
assertEquals(nbOfKeys, total) assertEquals(nbOfKeys, total)
lastBackedUpKeysProgress = progress lastBackedUpKeysProgress = progress
} }
}, TestMatrixCallback(latch)) }, it)
}
mTestHelper.await(latch)
assertEquals(nbOfKeys, lastBackedUpKeysProgress) assertEquals(nbOfKeys, lastBackedUpKeysProgress)
val backedUpKeys = cryptoTestData.firstSession.cryptoService().inboundGroupSessionsCount(true) val backedUpKeys = cryptoTestData.firstSession.cryptoService().inboundGroupSessionsCount(true)
@ -335,23 +296,17 @@ class KeysBackupTest : InstrumentedTest {
val testData = createKeysBackupScenarioWithPassword(null) val testData = createKeysBackupScenarioWithPassword(null)
// - Restore the e2e backup from the homeserver // - Restore the e2e backup from the homeserver
val latch2 = CountDownLatch(1) val importRoomKeysResult = mTestHelper.doSync<ImportRoomKeysResult> {
var importRoomKeysResult: ImportRoomKeysResult? = null
testData.aliceSession2.cryptoService().keysBackupService().restoreKeysWithRecoveryKey(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!, testData.aliceSession2.cryptoService().keysBackupService().restoreKeysWithRecoveryKey(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
testData.prepareKeysBackupDataResult.megolmBackupCreationInfo.recoveryKey, testData.prepareKeysBackupDataResult.megolmBackupCreationInfo.recoveryKey,
null, null,
null, null,
null, null,
object : TestMatrixCallback<ImportRoomKeysResult>(latch2) { it
override fun onSuccess(data: ImportRoomKeysResult) {
importRoomKeysResult = data
super.onSuccess(data)
}
}
) )
mTestHelper.await(latch2) }
checkRestoreSuccess(testData, importRoomKeysResult!!.totalNumberOfKeys, importRoomKeysResult!!.successfullyNumberOfImportedKeys) checkRestoreSuccess(testData, importRoomKeysResult.totalNumberOfKeys, importRoomKeysResult.successfullyNumberOfImportedKeys)
testData.cryptoTestData.close() testData.cryptoTestData.close()
} }
@ -383,23 +338,17 @@ class KeysBackupTest : InstrumentedTest {
assertTrue(unsentRequest != null || sentRequest != null) assertTrue(unsentRequest != null || sentRequest != null)
// - Restore the e2e backup from the homeserver // - Restore the e2e backup from the homeserver
val latch2 = CountDownLatch(1) val importRoomKeysResult = mTestHelper.doSync<ImportRoomKeysResult> {
var importRoomKeysResult: ImportRoomKeysResult? = null
testData.aliceSession2.cryptoService().keysBackupService().restoreKeysWithRecoveryKey(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!, testData.aliceSession2.cryptoService().keysBackupService().restoreKeysWithRecoveryKey(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
testData.prepareKeysBackupDataResult.megolmBackupCreationInfo.recoveryKey, testData.prepareKeysBackupDataResult.megolmBackupCreationInfo.recoveryKey,
null, null,
null, null,
null, null,
object : TestMatrixCallback<ImportRoomKeysResult>(latch2) { it
override fun onSuccess(data: ImportRoomKeysResult) {
importRoomKeysResult = data
super.onSuccess(data)
}
}
) )
mTestHelper.await(latch2) }
checkRestoreSuccess(testData, importRoomKeysResult!!.totalNumberOfKeys, importRoomKeysResult!!.successfullyNumberOfImportedKeys) checkRestoreSuccess(testData, importRoomKeysResult.totalNumberOfKeys, importRoomKeysResult.successfullyNumberOfImportedKeys)
// - There must be no more pending key share requests // - There must be no more pending key share requests
val unsentRequestAfterRestoration = cryptoStore2 val unsentRequestAfterRestoration = cryptoStore2
@ -437,13 +386,13 @@ class KeysBackupTest : InstrumentedTest {
assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state) assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state)
// - Trust the backup from the new device // - Trust the backup from the new device
val latch = CountDownLatch(1) mTestHelper.doSync<Unit> {
testData.aliceSession2.cryptoService().keysBackupService().trustKeysBackupVersion( testData.aliceSession2.cryptoService().keysBackupService().trustKeysBackupVersion(
testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!, testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
true, true,
TestMatrixCallback(latch) it
) )
mTestHelper.await(latch) }
// Wait for backup state to be ReadyToBackUp // Wait for backup state to be ReadyToBackUp
waitForKeysBackupToBeInState(testData.aliceSession2, KeysBackupState.ReadyToBackUp) waitForKeysBackupToBeInState(testData.aliceSession2, KeysBackupState.ReadyToBackUp)
@ -453,35 +402,20 @@ class KeysBackupTest : InstrumentedTest {
assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled)
// - Retrieve the last version from the server // - Retrieve the last version from the server
val latch2 = CountDownLatch(1) val keysVersionResult = mTestHelper.doSync<KeysVersionResult?> {
var keysVersionResult: KeysVersionResult? = null testData.aliceSession2.cryptoService().keysBackupService().getCurrentVersion(it)
testData.aliceSession2.cryptoService().keysBackupService().getCurrentVersion(
object : TestMatrixCallback<KeysVersionResult?>(latch2) {
override fun onSuccess(data: KeysVersionResult?) {
keysVersionResult = data
super.onSuccess(data)
} }
}
)
mTestHelper.await(latch2)
// - It must be the same // - It must be the same
assertEquals(testData.prepareKeysBackupDataResult.version, keysVersionResult!!.version) assertEquals(testData.prepareKeysBackupDataResult.version, keysVersionResult!!.version)
val latch3 = CountDownLatch(1) val keysBackupVersionTrust = mTestHelper.doSync<KeysBackupVersionTrust> {
var keysBackupVersionTrust: KeysBackupVersionTrust? = null testData.aliceSession2.cryptoService().keysBackupService().getKeysBackupTrust(keysVersionResult, it)
testData.aliceSession2.cryptoService().keysBackupService().getKeysBackupTrust(keysVersionResult!!,
object : TestMatrixCallback<KeysBackupVersionTrust>(latch3) {
override fun onSuccess(data: KeysBackupVersionTrust) {
keysBackupVersionTrust = data
super.onSuccess(data)
} }
})
mTestHelper.await(latch3)
// - It must be trusted and must have 2 signatures now // - It must be trusted and must have 2 signatures now
assertTrue(keysBackupVersionTrust!!.usable) assertTrue(keysBackupVersionTrust.usable)
assertEquals(2, keysBackupVersionTrust!!.signatures.size) assertEquals(2, keysBackupVersionTrust.signatures.size)
stateObserver.stopAndCheckStates(null) stateObserver.stopAndCheckStates(null)
testData.cryptoTestData.close() testData.cryptoTestData.close()
@ -511,13 +445,13 @@ class KeysBackupTest : InstrumentedTest {
assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state) assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state)
// - Trust the backup from the new device with the recovery key // - Trust the backup from the new device with the recovery key
val latch = CountDownLatch(1) mTestHelper.doSync<Unit> {
testData.aliceSession2.cryptoService().keysBackupService().trustKeysBackupVersionWithRecoveryKey( testData.aliceSession2.cryptoService().keysBackupService().trustKeysBackupVersionWithRecoveryKey(
testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!, testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
testData.prepareKeysBackupDataResult.megolmBackupCreationInfo.recoveryKey, testData.prepareKeysBackupDataResult.megolmBackupCreationInfo.recoveryKey,
TestMatrixCallback(latch) it
) )
mTestHelper.await(latch) }
// Wait for backup state to be ReadyToBackUp // Wait for backup state to be ReadyToBackUp
waitForKeysBackupToBeInState(testData.aliceSession2, KeysBackupState.ReadyToBackUp) waitForKeysBackupToBeInState(testData.aliceSession2, KeysBackupState.ReadyToBackUp)
@ -527,35 +461,20 @@ class KeysBackupTest : InstrumentedTest {
assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled)
// - Retrieve the last version from the server // - Retrieve the last version from the server
val latch2 = CountDownLatch(1) val keysVersionResult = mTestHelper.doSync<KeysVersionResult?> {
var keysVersionResult: KeysVersionResult? = null testData.aliceSession2.cryptoService().keysBackupService().getCurrentVersion(it)
testData.aliceSession2.cryptoService().keysBackupService().getCurrentVersion(
object : TestMatrixCallback<KeysVersionResult?>(latch2) {
override fun onSuccess(data: KeysVersionResult?) {
keysVersionResult = data
super.onSuccess(data)
} }
}
)
mTestHelper.await(latch2)
// - It must be the same // - It must be the same
assertEquals(testData.prepareKeysBackupDataResult.version, keysVersionResult!!.version) assertEquals(testData.prepareKeysBackupDataResult.version, keysVersionResult!!.version)
val latch3 = CountDownLatch(1) val keysBackupVersionTrust = mTestHelper.doSync<KeysBackupVersionTrust> {
var keysBackupVersionTrust: KeysBackupVersionTrust? = null testData.aliceSession2.cryptoService().keysBackupService().getKeysBackupTrust(keysVersionResult, it)
testData.aliceSession2.cryptoService().keysBackupService().getKeysBackupTrust(keysVersionResult!!,
object : TestMatrixCallback<KeysBackupVersionTrust>(latch3) {
override fun onSuccess(data: KeysBackupVersionTrust) {
keysBackupVersionTrust = data
super.onSuccess(data)
} }
})
mTestHelper.await(latch3)
// - It must be trusted and must have 2 signatures now // - It must be trusted and must have 2 signatures now
assertTrue(keysBackupVersionTrust!!.usable) assertTrue(keysBackupVersionTrust.usable)
assertEquals(2, keysBackupVersionTrust!!.signatures.size) assertEquals(2, keysBackupVersionTrust.signatures.size)
stateObserver.stopAndCheckStates(null) stateObserver.stopAndCheckStates(null)
testData.cryptoTestData.close() testData.cryptoTestData.close()
@ -626,13 +545,13 @@ class KeysBackupTest : InstrumentedTest {
assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state) assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state)
// - Trust the backup from the new device with the password // - Trust the backup from the new device with the password
val latch = CountDownLatch(1) mTestHelper.doSync<Unit> {
testData.aliceSession2.cryptoService().keysBackupService().trustKeysBackupVersionWithPassphrase( testData.aliceSession2.cryptoService().keysBackupService().trustKeysBackupVersionWithPassphrase(
testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!, testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
password, password,
TestMatrixCallback(latch) it
) )
mTestHelper.await(latch) }
// Wait for backup state to be ReadyToBackUp // Wait for backup state to be ReadyToBackUp
waitForKeysBackupToBeInState(testData.aliceSession2, KeysBackupState.ReadyToBackUp) waitForKeysBackupToBeInState(testData.aliceSession2, KeysBackupState.ReadyToBackUp)
@ -642,35 +561,20 @@ class KeysBackupTest : InstrumentedTest {
assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled)
// - Retrieve the last version from the server // - Retrieve the last version from the server
val latch2 = CountDownLatch(1) val keysVersionResult = mTestHelper.doSync<KeysVersionResult?> {
var keysVersionResult: KeysVersionResult? = null testData.aliceSession2.cryptoService().keysBackupService().getCurrentVersion(it)
testData.aliceSession2.cryptoService().keysBackupService().getCurrentVersion(
object : TestMatrixCallback<KeysVersionResult?>(latch2) {
override fun onSuccess(data: KeysVersionResult?) {
keysVersionResult = data
super.onSuccess(data)
} }
}
)
mTestHelper.await(latch2)
// - It must be the same // - It must be the same
assertEquals(testData.prepareKeysBackupDataResult.version, keysVersionResult!!.version) assertEquals(testData.prepareKeysBackupDataResult.version, keysVersionResult!!.version)
val latch3 = CountDownLatch(1) val keysBackupVersionTrust = mTestHelper.doSync<KeysBackupVersionTrust> {
var keysBackupVersionTrust: KeysBackupVersionTrust? = null testData.aliceSession2.cryptoService().keysBackupService().getKeysBackupTrust(keysVersionResult, it)
testData.aliceSession2.cryptoService().keysBackupService().getKeysBackupTrust(keysVersionResult!!,
object : TestMatrixCallback<KeysBackupVersionTrust>(latch3) {
override fun onSuccess(data: KeysBackupVersionTrust) {
keysBackupVersionTrust = data
super.onSuccess(data)
} }
})
mTestHelper.await(latch3)
// - It must be trusted and must have 2 signatures now // - It must be trusted and must have 2 signatures now
assertTrue(keysBackupVersionTrust!!.usable) assertTrue(keysBackupVersionTrust.usable)
assertEquals(2, keysBackupVersionTrust!!.signatures.size) assertEquals(2, keysBackupVersionTrust.signatures.size)
stateObserver.stopAndCheckStates(null) stateObserver.stopAndCheckStates(null)
testData.cryptoTestData.close() testData.cryptoTestData.close()
@ -764,10 +668,9 @@ class KeysBackupTest : InstrumentedTest {
val testData = createKeysBackupScenarioWithPassword(password) val testData = createKeysBackupScenarioWithPassword(password)
// - Restore the e2e backup with the password // - Restore the e2e backup with the password
val latch2 = CountDownLatch(1)
var importRoomKeysResult: ImportRoomKeysResult? = null
val steps = ArrayList<StepProgressListener.Step>() val steps = ArrayList<StepProgressListener.Step>()
val importRoomKeysResult = mTestHelper.doSync<ImportRoomKeysResult> {
testData.aliceSession2.cryptoService().keysBackupService().restoreKeyBackupWithPassword(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!, testData.aliceSession2.cryptoService().keysBackupService().restoreKeyBackupWithPassword(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
password, password,
null, null,
@ -777,14 +680,9 @@ class KeysBackupTest : InstrumentedTest {
steps.add(step) steps.add(step)
} }
}, },
object : TestMatrixCallback<ImportRoomKeysResult>(latch2) { it
override fun onSuccess(data: ImportRoomKeysResult) {
importRoomKeysResult = data
super.onSuccess(data)
}
}
) )
mTestHelper.await(latch2) }
// Check steps // Check steps
assertEquals(105, steps.size) assertEquals(105, steps.size)
@ -807,7 +705,7 @@ class KeysBackupTest : InstrumentedTest {
assertEquals(50, (steps[103] as StepProgressListener.Step.ImportingKey).progress) assertEquals(50, (steps[103] as StepProgressListener.Step.ImportingKey).progress)
assertEquals(100, (steps[104] as StepProgressListener.Step.ImportingKey).progress) assertEquals(100, (steps[104] as StepProgressListener.Step.ImportingKey).progress)
checkRestoreSuccess(testData, importRoomKeysResult!!.totalNumberOfKeys, importRoomKeysResult!!.successfullyNumberOfImportedKeys) checkRestoreSuccess(testData, importRoomKeysResult.totalNumberOfKeys, importRoomKeysResult.successfullyNumberOfImportedKeys)
testData.cryptoTestData.close() testData.cryptoTestData.close()
} }
@ -861,23 +759,17 @@ class KeysBackupTest : InstrumentedTest {
val testData = createKeysBackupScenarioWithPassword(password) val testData = createKeysBackupScenarioWithPassword(password)
// - Restore the e2e backup with the recovery key. // - Restore the e2e backup with the recovery key.
val latch2 = CountDownLatch(1) val importRoomKeysResult = mTestHelper.doSync<ImportRoomKeysResult> {
var importRoomKeysResult: ImportRoomKeysResult? = null
testData.aliceSession2.cryptoService().keysBackupService().restoreKeysWithRecoveryKey(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!, testData.aliceSession2.cryptoService().keysBackupService().restoreKeysWithRecoveryKey(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
testData.prepareKeysBackupDataResult.megolmBackupCreationInfo.recoveryKey, testData.prepareKeysBackupDataResult.megolmBackupCreationInfo.recoveryKey,
null, null,
null, null,
null, null,
object : TestMatrixCallback<ImportRoomKeysResult>(latch2) { it
override fun onSuccess(data: ImportRoomKeysResult) {
importRoomKeysResult = data
super.onSuccess(data)
}
}
) )
mTestHelper.await(latch2) }
checkRestoreSuccess(testData, importRoomKeysResult!!.totalNumberOfKeys, importRoomKeysResult!!.successfullyNumberOfImportedKeys) checkRestoreSuccess(testData, importRoomKeysResult.totalNumberOfKeys, importRoomKeysResult.successfullyNumberOfImportedKeys)
testData.cryptoTestData.close() testData.cryptoTestData.close()
} }
@ -932,39 +824,20 @@ class KeysBackupTest : InstrumentedTest {
prepareAndCreateKeysBackupData(keysBackup) prepareAndCreateKeysBackupData(keysBackup)
// Get key backup version from the home server // Get key backup version from the home server
var keysVersionResult: KeysVersionResult? = null val keysVersionResult = mTestHelper.doSync<KeysVersionResult?> {
val lock = CountDownLatch(1) keysBackup.getCurrentVersion(it)
keysBackup.getCurrentVersion(object : TestMatrixCallback<KeysVersionResult?>(lock) {
override fun onSuccess(data: KeysVersionResult?) {
keysVersionResult = data
super.onSuccess(data)
} }
})
mTestHelper.await(lock)
assertNotNull(keysVersionResult)
// - Check the returned KeyBackupVersion is trusted // - Check the returned KeyBackupVersion is trusted
val latch = CountDownLatch(1) val keysBackupVersionTrust = mTestHelper.doSync<KeysBackupVersionTrust> {
var keysBackupVersionTrust: KeysBackupVersionTrust? = null keysBackup.getKeysBackupTrust(keysVersionResult!!, it)
keysBackup.getKeysBackupTrust(keysVersionResult!!, object : MatrixCallback<KeysBackupVersionTrust> {
override fun onSuccess(data: KeysBackupVersionTrust) {
keysBackupVersionTrust = data
latch.countDown()
} }
override fun onFailure(failure: Throwable) {
super.onFailure(failure)
latch.countDown()
}
})
mTestHelper.await(latch)
assertNotNull(keysBackupVersionTrust) assertNotNull(keysBackupVersionTrust)
assertTrue(keysBackupVersionTrust!!.usable) assertTrue(keysBackupVersionTrust.usable)
assertEquals(1, keysBackupVersionTrust!!.signatures.size) assertEquals(1, keysBackupVersionTrust.signatures.size)
val signature = keysBackupVersionTrust!!.signatures[0] val signature = keysBackupVersionTrust.signatures[0]
assertTrue(signature.valid) assertTrue(signature.valid)
assertNotNull(signature.device) assertNotNull(signature.device)
assertEquals(cryptoTestData.firstSession.cryptoService().getMyDevice().deviceId, signature.deviceId) assertEquals(cryptoTestData.firstSession.cryptoService().getMyDevice().deviceId, signature.deviceId)
@ -1079,21 +952,17 @@ class KeysBackupTest : InstrumentedTest {
mTestHelper.await(latch0) mTestHelper.await(latch0)
// - Create a new backup with fake data on the homeserver, directly using the rest client // - Create a new backup with fake data on the homeserver, directly using the rest client
val latch = CountDownLatch(1)
val megolmBackupCreationInfo = mCryptoTestHelper.createFakeMegolmBackupCreationInfo() val megolmBackupCreationInfo = mCryptoTestHelper.createFakeMegolmBackupCreationInfo()
(keysBackup as DefaultKeysBackupService).createFakeKeysBackupVersion(megolmBackupCreationInfo, TestMatrixCallback(latch)) mTestHelper.doSync<KeysVersion> {
mTestHelper.await(latch) (keysBackup as DefaultKeysBackupService).createFakeKeysBackupVersion(megolmBackupCreationInfo, it)
}
// Reset the store backup status for keys // Reset the store backup status for keys
(cryptoTestData.firstSession.cryptoService().keysBackupService() as DefaultKeysBackupService).store.resetBackupMarkers() (cryptoTestData.firstSession.cryptoService().keysBackupService() as DefaultKeysBackupService).store.resetBackupMarkers()
// - Make alice back up all her keys again // - Make alice back up all her keys again
val latch2 = CountDownLatch(1) val latch2 = CountDownLatch(1)
keysBackup.backupAllGroupSessions(object : ProgressListener { keysBackup.backupAllGroupSessions(null, TestMatrixCallback(latch2, false))
override fun onProgress(progress: Int, total: Int) {
}
}, TestMatrixCallback(latch2, false))
mTestHelper.await(latch2) mTestHelper.await(latch2)
// -> That must fail and her backup state must be WrongBackUpVersion // -> That must fail and her backup state must be WrongBackUpVersion
@ -1129,12 +998,9 @@ class KeysBackupTest : InstrumentedTest {
prepareAndCreateKeysBackupData(keysBackup) prepareAndCreateKeysBackupData(keysBackup)
// Wait for keys backup to finish by asking again to backup keys. // Wait for keys backup to finish by asking again to backup keys.
val latch = CountDownLatch(1) mTestHelper.doSync<Unit> {
keysBackup.backupAllGroupSessions(object : ProgressListener { keysBackup.backupAllGroupSessions(null, it)
override fun onProgress(progress: Int, total: Int) {
} }
}, TestMatrixCallback(latch))
mTestHelper.await(latch)
val oldDeviceId = cryptoTestData.firstSession.sessionParams.credentials.deviceId!! val oldDeviceId = cryptoTestData.firstSession.sessionParams.credentials.deviceId!!
val oldKeyBackupVersion = keysBackup.currentBackupVersion val oldKeyBackupVersion = keysBackup.currentBackupVersion
@ -1178,7 +1044,7 @@ class KeysBackupTest : InstrumentedTest {
assertFalse(keysBackup2.isEnabled) assertFalse(keysBackup2.isEnabled)
// - Validate the old device from the new one // - Validate the old device from the new one
aliceSession2.cryptoService().setDeviceVerification(DeviceTrustLevel(false, true), aliceSession2.myUserId, oldDeviceId) aliceSession2.cryptoService().setDeviceVerification(DeviceTrustLevel(crossSigningVerified = false, locallyVerified = true), aliceSession2.myUserId, oldDeviceId)
// -> Backup should automatically enable on the new device // -> Backup should automatically enable on the new device
val latch4 = CountDownLatch(1) val latch4 = CountDownLatch(1)
@ -1198,9 +1064,9 @@ class KeysBackupTest : InstrumentedTest {
// -> It must use the same backup version // -> It must use the same backup version
assertEquals(oldKeyBackupVersion, aliceSession2.cryptoService().keysBackupService().currentBackupVersion) assertEquals(oldKeyBackupVersion, aliceSession2.cryptoService().keysBackupService().currentBackupVersion)
val latch5 = CountDownLatch(1) mTestHelper.doSync<Unit> {
aliceSession2.cryptoService().keysBackupService().backupAllGroupSessions(null, TestMatrixCallback(latch5)) aliceSession2.cryptoService().keysBackupService().backupAllGroupSessions(null, it)
mTestHelper.await(latch5) }
// -> It must success // -> It must success
assertTrue(aliceSession2.cryptoService().keysBackupService().isEnabled) assertTrue(aliceSession2.cryptoService().keysBackupService().isEnabled)
@ -1230,12 +1096,8 @@ class KeysBackupTest : InstrumentedTest {
assertTrue(keysBackup.isEnabled) assertTrue(keysBackup.isEnabled)
val latch = CountDownLatch(1)
// Delete the backup // Delete the backup
keysBackup.deleteBackup(keyBackupCreationInfo.version, TestMatrixCallback(latch)) mTestHelper.doSync<Unit> { keysBackup.deleteBackup(keyBackupCreationInfo.version, it) }
mTestHelper.await(latch)
// Backup is now disabled // Backup is now disabled
assertFalse(keysBackup.isEnabled) assertFalse(keysBackup.isEnabled)
@ -1280,49 +1142,26 @@ class KeysBackupTest : InstrumentedTest {
password: String? = null): PrepareKeysBackupDataResult { password: String? = null): PrepareKeysBackupDataResult {
val stateObserver = StateObserver(keysBackup) val stateObserver = StateObserver(keysBackup)
var megolmBackupCreationInfo: MegolmBackupCreationInfo? = null val megolmBackupCreationInfo = mTestHelper.doSync<MegolmBackupCreationInfo> {
val latch = CountDownLatch(1) keysBackup.prepareKeysBackupVersion(password, null, it)
keysBackup.prepareKeysBackupVersion(password, null, object : MatrixCallback<MegolmBackupCreationInfo> {
override fun onSuccess(data: MegolmBackupCreationInfo) {
megolmBackupCreationInfo = data
latch.countDown()
} }
override fun onFailure(failure: Throwable) {
fail(failure.localizedMessage)
latch.countDown()
}
})
mTestHelper.await(latch)
assertNotNull(megolmBackupCreationInfo) assertNotNull(megolmBackupCreationInfo)
assertFalse(keysBackup.isEnabled) assertFalse(keysBackup.isEnabled)
val latch2 = CountDownLatch(1)
// Create the version // Create the version
var version: String? = null val keysVersion = mTestHelper.doSync<KeysVersion> {
keysBackup.createKeysBackupVersion(megolmBackupCreationInfo!!, object : TestMatrixCallback<KeysVersion>(latch2) { keysBackup.createKeysBackupVersion(megolmBackupCreationInfo, it)
override fun onSuccess(data: KeysVersion) {
assertNotNull(data)
assertNotNull(data.version)
version = data.version
super.onSuccess(data)
} }
})
mTestHelper.await(latch2) assertNotNull(keysVersion.version)
// Backup must be enable now // Backup must be enable now
assertTrue(keysBackup.isEnabled) assertTrue(keysBackup.isEnabled)
assertNotNull(version)
stateObserver.stopAndCheckStates(null) stateObserver.stopAndCheckStates(null)
return PrepareKeysBackupDataResult(megolmBackupCreationInfo!!, version!!) return PrepareKeysBackupDataResult(megolmBackupCreationInfo, keysVersion.version!!)
} }
private fun assertKeysEquals(keys1: MegolmSessionData?, keys2: MegolmSessionData?) { private fun assertKeysEquals(keys1: MegolmSessionData?, keys2: MegolmSessionData?) {
@ -1369,16 +1208,16 @@ class KeysBackupTest : InstrumentedTest {
// - Do an e2e backup to the homeserver // - Do an e2e backup to the homeserver
val prepareKeysBackupDataResult = prepareAndCreateKeysBackupData(keysBackup, password) val prepareKeysBackupDataResult = prepareAndCreateKeysBackupData(keysBackup, password)
val latch = CountDownLatch(1)
var lastProgress = 0 var lastProgress = 0
var lastTotal = 0 var lastTotal = 0
mTestHelper.doSync<Unit> {
keysBackup.backupAllGroupSessions(object : ProgressListener { keysBackup.backupAllGroupSessions(object : ProgressListener {
override fun onProgress(progress: Int, total: Int) { override fun onProgress(progress: Int, total: Int) {
lastProgress = progress lastProgress = progress
lastTotal = total lastTotal = total
} }
}, TestMatrixCallback(latch)) }, it)
mTestHelper.await(latch) }
assertEquals(2, lastProgress) assertEquals(2, lastProgress)
assertEquals(2, lastTotal) assertEquals(2, lastTotal)
@ -1386,9 +1225,7 @@ class KeysBackupTest : InstrumentedTest {
val aliceUserId = cryptoTestData.firstSession.myUserId val aliceUserId = cryptoTestData.firstSession.myUserId
// Logout first Alice session, else they will share the same Crypto store and some tests may fail. // Logout first Alice session, else they will share the same Crypto store and some tests may fail.
val latch2 = CountDownLatch(1) mTestHelper.doSync<Unit> { cryptoTestData.firstSession.signOut(true, it) }
cryptoTestData.firstSession.signOut(true, TestMatrixCallback(latch2))
mTestHelper.await(latch2)
// - Log Alice on a new device // - Log Alice on a new device
val aliceSession2 = mTestHelper.logIntoAccount(aliceUserId, defaultSessionParamsWithInitialSync) val aliceSession2 = mTestHelper.logIntoAccount(aliceUserId, defaultSessionParamsWithInitialSync)

View file

@ -41,12 +41,12 @@ interface Timeline {
fun removeAllListeners() fun removeAllListeners()
/** /**
* This should be called before any other method after creating the timeline. It ensures the underlying database is open * This must be called before any other method after creating the timeline. It ensures the underlying database is open
*/ */
fun start() fun start()
/** /**
* This should be called when you don't need the timeline. It ensures the underlying database get closed. * This must be called when you don't need the timeline. It ensures the underlying database get closed.
*/ */
fun dispose() fun dispose()

View file

@ -27,6 +27,9 @@ interface TimelineService {
/** /**
* Instantiate a [Timeline] with an optional initial eventId, to be used with permalink. * Instantiate a [Timeline] with an optional initial eventId, to be used with permalink.
* You can also configure some settings with the [settings] param. * You can also configure some settings with the [settings] param.
*
* Important: the returned Timeline has to be started
*
* @param eventId the optional initial eventId. * @param eventId the optional initial eventId.
* @param settings settings to configure the timeline. * @param settings settings to configure the timeline.
* @return the instantiated timeline * @return the instantiated timeline