resurrect unwedge test + cleaning

This commit is contained in:
Valere 2022-03-01 17:13:52 +01:00
parent 078ed1b2d1
commit b7bf39b99a
6 changed files with 16 additions and 156 deletions

View file

@ -1,148 +0,0 @@
/*
* Copyright 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.crypto
import android.util.Log
import androidx.test.filters.LargeTest
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.common.CommonTestHelper
import org.matrix.android.sdk.common.CryptoTestHelper
import org.matrix.android.sdk.common.SessionTestParams
import org.matrix.android.sdk.common.TestConstants
import java.util.concurrent.Executors
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.random.Random
@RunWith(JUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
@LargeTest
class ConcurrentDecryptionTest : InstrumentedTest {
private val commonTestHelper = CommonTestHelper(context())
private val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
@Test
fun testConcurrentDecrypt() {
// val res = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
// =============================
// ARRANGE
// =============================
val aliceSession = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
val bobSession = commonTestHelper.createAccount(TestConstants.USER_BOB, SessionTestParams(true))
cryptoTestHelper.initializeCrossSigning(bobSession)
val bobSession2 = commonTestHelper.logIntoAccount(bobSession.myUserId, SessionTestParams(true))
bobSession2.cryptoService().verificationService().markedLocallyAsManuallyVerified(bobSession.myUserId, bobSession.sessionParams.deviceId ?: "")
bobSession.cryptoService().verificationService().markedLocallyAsManuallyVerified(bobSession.myUserId, bobSession2.sessionParams.deviceId ?: "")
val roomId = cryptoTestHelper.createDM(aliceSession, bobSession)
val roomAlicePOV = aliceSession.getRoom(roomId)!!
// =============================
// ACT
// =============================
val timelineEvent = commonTestHelper.sendTextMessage(roomAlicePOV, "Hello Bob", 1).first()
val secondEvent = commonTestHelper.sendTextMessage(roomAlicePOV, "Hello Bob 2", 1).first()
val thirdEvent = commonTestHelper.sendTextMessage(roomAlicePOV, "Hello Bob 3", 1).first()
val forthEvent = commonTestHelper.sendTextMessage(roomAlicePOV, "Hello Bob 4", 1).first()
// await for bob unverified session to get the message
commonTestHelper.waitWithLatch { latch ->
commonTestHelper.retryPeriodicallyWithLatch(latch) {
bobSession.getRoom(roomId)?.getTimeLineEvent(forthEvent.eventId) != null
}
}
val eventBobPOV = bobSession.getRoom(roomId)?.getTimeLineEvent(timelineEvent.eventId)!!
val secondEventBobPOV = bobSession.getRoom(roomId)?.getTimeLineEvent(secondEvent.eventId)!!
val thirdEventBobPOV = bobSession.getRoom(roomId)?.getTimeLineEvent(thirdEvent.eventId)!!
val forthEventBobPOV = bobSession.getRoom(roomId)?.getTimeLineEvent(forthEvent.eventId)!!
// let's try to decrypt concurrently and check that we are not getting exceptions
val dispatcher = Executors
.newFixedThreadPool(100)
.asCoroutineDispatcher()
val coroutineScope = CoroutineScope(SupervisorJob() + dispatcher)
val eventList = listOf(eventBobPOV, secondEventBobPOV, thirdEventBobPOV, forthEventBobPOV)
val atomicAsError = AtomicBoolean()
val deff = mutableListOf<Deferred<Any>>()
val cryptoService = bobSession.cryptoService()
coroutineScope.launch {
for (spawn in 1..100) {
delay((Random.nextFloat() * 1000).toLong())
aliceSession.cryptoService().requestRoomKeyForEvent(eventList.random().root)
}
}
for (spawn in 1..8000) {
eventList.random().let { event ->
coroutineScope.async {
try {
cryptoService.decryptEvent(event.root, "")
Log.d("#TEST", "[$spawn] Decrypt Success ${event.eventId} :${Thread.currentThread().name}")
} catch (failure: Throwable) {
atomicAsError.set(true)
Log.e("#TEST", "Failed to decrypt $spawn/${event.eventId} :$failure")
}
}.let {
deff.add(it)
}
}
}
coroutineScope.launch {
for (spawn in 1..100) {
delay((Random.nextFloat() * 1000).toLong())
bobSession.cryptoService().requestRoomKeyForEvent(eventList.random().root)
}
}
commonTestHelper.runBlockingTest(10 * 60_000) {
deff.awaitAll()
delay(10_000)
assert(!atomicAsError.get())
// There should be no errors
}
coroutineScope.cancel()
commonTestHelper.signOutAndClose(aliceSession)
commonTestHelper.signOutAndClose(bobSession)
commonTestHelper.signOutAndClose(bobSession2)
}
}

View file

@ -21,7 +21,6 @@ import org.amshove.kluent.shouldBe
import org.junit.Assert
import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@ -85,7 +84,6 @@ class UnwedgingTest : InstrumentedTest {
* -> This is automatically fixed after SDKs restarted the olm session
*/
@Test
@Ignore("This test will be ignored until it is fixed")
fun testUnwedging() {
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
@ -94,9 +92,7 @@ class UnwedgingTest : InstrumentedTest {
val bobSession = cryptoTestData.secondSession!!
val aliceCryptoStore = (aliceSession.cryptoService() as DefaultCryptoService).cryptoStoreForTesting
// bobSession.cryptoService().setWarnOnUnknownDevices(false)
// aliceSession.cryptoService().setWarnOnUnknownDevices(false)
val olmDevice = (aliceSession.cryptoService() as DefaultCryptoService).olmDeviceForTest
val roomFromBobPOV = bobSession.getRoom(aliceRoomId)!!
val roomFromAlicePOV = aliceSession.getRoom(aliceRoomId)!!
@ -175,6 +171,7 @@ class UnwedgingTest : InstrumentedTest {
Timber.i("## CRYPTO | testUnwedging: wedge the session now. Set crypto state like after the first message")
aliceCryptoStore.storeSession(OlmSessionWrapper(deserializeFromRealm<OlmSession>(oldSession)!!), bobSession.cryptoService().getMyDevice().identityKey()!!)
olmDevice.clearOlmSessionCache()
Thread.sleep(6_000)
// Force new session, and key share

View file

@ -1372,6 +1372,9 @@ internal class DefaultCryptoService @Inject constructor(
@VisibleForTesting
val cryptoStoreForTesting = cryptoStore
@VisibleForTesting
val olmDeviceForTest = olmDevice
companion object {
const val CRYPTO_MIN_FORCE_SESSION_PERIOD_MILLIS = 3_600_000 // one hour
}

View file

@ -195,8 +195,7 @@ internal class EventDecryptor @Inject constructor(
val sessionToUse = ensureOlmSessionsForDevicesAction.handle(deviceList, true)
Timber.tag(loggerTag.value).d("Unwedging, found ${sessionToUse.map.size} to send dummy to")
// Now send a blank message on that session so the other side knows about it.
// (The keyshare request is sent in the clear so that won't do)
// Now send a dummy message on that session so the other side knows about it.
val payloadJson = mapOf(
"type" to EventType.DUMMY
)

View file

@ -16,6 +16,7 @@
package org.matrix.android.sdk.internal.crypto
import androidx.annotation.VisibleForTesting
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import org.matrix.android.sdk.api.extensions.tryOrNull
@ -924,4 +925,9 @@ internal class MXOlmDevice @Inject constructor(
fun hasInboundSessionKeys(roomId: String, senderKey: String, sessionId: String): Boolean {
return runCatching { getInboundGroupSession(sessionId, senderKey, roomId) }.isSuccess
}
@VisibleForTesting
fun clearOlmSessionCache() {
olmSessionStore.clear()
}
}

View file

@ -16,6 +16,7 @@
package org.matrix.android.sdk.internal.crypto.actions
import org.matrix.android.sdk.api.logger.LoggerTag
import org.matrix.android.sdk.api.session.events.model.Content
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_OLM
import org.matrix.android.sdk.internal.crypto.MXOlmDevice
@ -28,6 +29,8 @@ import org.matrix.android.sdk.internal.util.convertToUTF8
import timber.log.Timber
import javax.inject.Inject
private val loggerTag = LoggerTag("MessageEncrypter", LoggerTag.CRYPTO)
internal class MessageEncrypter @Inject constructor(
@UserId
private val userId: String,
@ -66,7 +69,7 @@ internal class MessageEncrypter @Inject constructor(
val sessionId = olmDevice.getSessionId(deviceKey)
if (!sessionId.isNullOrEmpty()) {
Timber.v("Using sessionid $sessionId for device $deviceKey")
Timber.tag(loggerTag.value).d("Using sessionid $sessionId for device $deviceKey")
payloadJson["recipient"] = deviceInfo.userId
payloadJson["recipient_keys"] = mapOf("ed25519" to deviceInfo.fingerprint()!!)