From 5c6fee08fd3b8495397584a44cb72cb393a826b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Mart=C3=ADn?= Date: Tue, 16 Dec 2025 16:53:24 +0100 Subject: [PATCH] Fix tests --- .../appnav/di/MatrixSessionCacheTest.kt | 72 ++++++++++++------- .../libraries/core/coroutine/ChildScopeOf.kt | 10 ++- .../matrix/impl/room/RustBaseRoomTest.kt | 2 +- 3 files changed, 54 insertions(+), 30 deletions(-) diff --git a/appnav/src/test/kotlin/io/element/android/appnav/di/MatrixSessionCacheTest.kt b/appnav/src/test/kotlin/io/element/android/appnav/di/MatrixSessionCacheTest.kt index 56c20f7a1d..36fa471dd0 100644 --- a/appnav/src/test/kotlin/io/element/android/appnav/di/MatrixSessionCacheTest.kt +++ b/appnav/src/test/kotlin/io/element/android/appnav/di/MatrixSessionCacheTest.kt @@ -19,29 +19,31 @@ import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.services.appnavstate.test.FakeAppForegroundStateService import io.element.android.tests.testutils.testCoroutineDispatchers import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Test +@OptIn(ExperimentalCoroutinesApi::class) class MatrixSessionCacheTest { @Test fun `test getOrNull`() = runTest { - val fakeAuthenticationService = FakeMatrixAuthenticationService() - val matrixSessionCache = MatrixSessionCache(fakeAuthenticationService, createSyncOrchestratorFactory()) + val matrixSessionCache = createMatrixSessionCache() assertThat(matrixSessionCache.getOrNull(A_SESSION_ID)).isNull() } @Test fun `test getSyncOrchestratorOrNull`() = runTest { val fakeAuthenticationService = FakeMatrixAuthenticationService() - val matrixSessionCache = MatrixSessionCache(fakeAuthenticationService, createSyncOrchestratorFactory()) + val matrixSessionCache = createMatrixSessionCache(fakeAuthenticationService) // With no matrix client there is no sync orchestrator assertThat(matrixSessionCache.getOrNull(A_SESSION_ID)).isNull() assertThat(matrixSessionCache.getSyncOrchestrator(A_SESSION_ID)).isNull() // But as soon as we receive a client, we can get the sync orchestrator - val fakeMatrixClient = FakeMatrixClient(sessionCoroutineScope = backgroundScope) + val fakeMatrixClient = FakeMatrixClient(sessionCoroutineScope = backgroundScope, userIdServerNameLambda = { A_SESSION_ID.value }) fakeAuthenticationService.givenMatrixClient(fakeMatrixClient) assertThat(matrixSessionCache.getOrRestore(A_SESSION_ID).getOrNull()).isEqualTo(fakeMatrixClient) assertThat(matrixSessionCache.getSyncOrchestrator(A_SESSION_ID)).isNotNull() @@ -50,8 +52,8 @@ class MatrixSessionCacheTest { @Test fun `test getOrRestore`() = runTest { val fakeAuthenticationService = FakeMatrixAuthenticationService() - val matrixSessionCache = MatrixSessionCache(fakeAuthenticationService, createSyncOrchestratorFactory()) - val fakeMatrixClient = FakeMatrixClient(sessionCoroutineScope = backgroundScope) + val matrixSessionCache = createMatrixSessionCache(fakeAuthenticationService) + val fakeMatrixClient = FakeMatrixClient(sessionCoroutineScope = backgroundScope, userIdServerNameLambda = { A_SESSION_ID.value }) fakeAuthenticationService.givenMatrixClient(fakeMatrixClient) assertThat(matrixSessionCache.getOrNull(A_SESSION_ID)).isNull() assertThat(matrixSessionCache.getOrRestore(A_SESSION_ID).getOrNull()).isEqualTo(fakeMatrixClient) @@ -63,8 +65,8 @@ class MatrixSessionCacheTest { @Test fun `test remove`() = runTest { val fakeAuthenticationService = FakeMatrixAuthenticationService() - val matrixSessionCache = MatrixSessionCache(fakeAuthenticationService, createSyncOrchestratorFactory()) - val fakeMatrixClient = FakeMatrixClient(sessionCoroutineScope = backgroundScope) + val matrixSessionCache = createMatrixSessionCache(fakeAuthenticationService) + val fakeMatrixClient = FakeMatrixClient(sessionCoroutineScope = backgroundScope, userIdServerNameLambda = { A_SESSION_ID.value }) fakeAuthenticationService.givenMatrixClient(fakeMatrixClient) assertThat(matrixSessionCache.getOrRestore(A_SESSION_ID).getOrNull()).isEqualTo(fakeMatrixClient) assertThat(matrixSessionCache.getOrNull(A_SESSION_ID)).isEqualTo(fakeMatrixClient) @@ -76,8 +78,8 @@ class MatrixSessionCacheTest { @Test fun `test remove all`() = runTest { val fakeAuthenticationService = FakeMatrixAuthenticationService() - val matrixSessionCache = MatrixSessionCache(fakeAuthenticationService, createSyncOrchestratorFactory()) - val fakeMatrixClient = FakeMatrixClient(sessionCoroutineScope = backgroundScope) + val matrixSessionCache = createMatrixSessionCache(fakeAuthenticationService) + val fakeMatrixClient = FakeMatrixClient(sessionCoroutineScope = backgroundScope, userIdServerNameLambda = { A_SESSION_ID.value }) fakeAuthenticationService.givenMatrixClient(fakeMatrixClient) assertThat(matrixSessionCache.getOrRestore(A_SESSION_ID).getOrNull()).isEqualTo(fakeMatrixClient) assertThat(matrixSessionCache.getOrNull(A_SESSION_ID)).isEqualTo(fakeMatrixClient) @@ -89,8 +91,8 @@ class MatrixSessionCacheTest { @Test fun `test save and restore`() = runTest { val fakeAuthenticationService = FakeMatrixAuthenticationService() - val matrixSessionCache = MatrixSessionCache(fakeAuthenticationService, createSyncOrchestratorFactory()) - val fakeMatrixClient = FakeMatrixClient(sessionCoroutineScope = backgroundScope) + val matrixSessionCache = createMatrixSessionCache(fakeAuthenticationService) + val fakeMatrixClient = FakeMatrixClient(sessionCoroutineScope = backgroundScope, userIdServerNameLambda = { A_SESSION_ID.value }) fakeAuthenticationService.givenMatrixClient(fakeMatrixClient) matrixSessionCache.getOrRestore(A_SESSION_ID) val savedStateMap = MutableSavedStateMapImpl { true } @@ -109,29 +111,45 @@ class MatrixSessionCacheTest { @Test fun `test AuthenticationService listenToNewMatrixClients emits a Client value and we save it`() = runTest { val fakeAuthenticationService = FakeMatrixAuthenticationService() - val matrixSessionCache = MatrixSessionCache(fakeAuthenticationService, createSyncOrchestratorFactory()) + val matrixSessionCache = createMatrixSessionCache(fakeAuthenticationService, createSyncOrchestratorFactory()) assertThat(matrixSessionCache.getOrNull(A_SESSION_ID)).isNull() - fakeAuthenticationService.givenMatrixClient(FakeMatrixClient(sessionId = A_SESSION_ID, sessionCoroutineScope = backgroundScope)) val loginSucceeded = fakeAuthenticationService.login("user", "pass") assertThat(loginSucceeded.isSuccess).isTrue() + + runCurrent() + assertThat(matrixSessionCache.getOrNull(A_SESSION_ID)).isNotNull() } - private fun TestScope.createSyncOrchestratorFactory() = object : SyncOrchestrator.Factory { - override fun create( - syncService: SyncService, - sessionCoroutineScope: CoroutineScope, - ): SyncOrchestrator { - return SyncOrchestrator( - syncService = syncService, - sessionCoroutineScope = sessionCoroutineScope, - appForegroundStateService = FakeAppForegroundStateService(), - networkMonitor = FakeNetworkMonitor(), - dispatchers = testCoroutineDispatchers(), - analyticsService = FakeAnalyticsService(), - ) + private fun TestScope.createMatrixSessionCache( + authenticationService: FakeMatrixAuthenticationService = FakeMatrixAuthenticationService(), + syncOrchestratorFactory: SyncOrchestrator.Factory = createSyncOrchestratorFactory(), + analyticsService: FakeAnalyticsService = FakeAnalyticsService(), + ) = MatrixSessionCache( + authenticationService = authenticationService, + syncOrchestratorFactory = syncOrchestratorFactory, + analyticsService = analyticsService, + ) + + private fun TestScope.createSyncOrchestratorFactory(): SyncOrchestrator.Factory { + val dispatchers = testCoroutineDispatchers() + + return object : SyncOrchestrator.Factory { + override fun create( + syncService: SyncService, + sessionCoroutineScope: CoroutineScope, + ): SyncOrchestrator { + return SyncOrchestrator( + syncService = syncService, + sessionCoroutineScope = sessionCoroutineScope, + appForegroundStateService = FakeAppForegroundStateService(), + networkMonitor = FakeNetworkMonitor(), + dispatchers = dispatchers, + analyticsService = FakeAnalyticsService(), + ) + } } } } diff --git a/libraries/core/src/main/kotlin/io/element/android/libraries/core/coroutine/ChildScopeOf.kt b/libraries/core/src/main/kotlin/io/element/android/libraries/core/coroutine/ChildScopeOf.kt index 1fba021530..46831a2698 100644 --- a/libraries/core/src/main/kotlin/io/element/android/libraries/core/coroutine/ChildScopeOf.kt +++ b/libraries/core/src/main/kotlin/io/element/android/libraries/core/coroutine/ChildScopeOf.kt @@ -14,6 +14,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.job import kotlinx.coroutines.plus +import kotlinx.coroutines.test.TestScope /** * Create a child scope of the current scope. @@ -28,6 +29,11 @@ fun CoroutineScope.childScope( dispatcher: CoroutineDispatcher, name: String, ): CoroutineScope = run { - val supervisorJob = SupervisorJob(parent = coroutineContext.job) - this + dispatcher + supervisorJob + CoroutineName(name) + if (this is TestScope) { + // Special case for tests: we can't start a coroutine with a different SupervisorJob + this + } else { + val supervisorJob = SupervisorJob(parent = coroutineContext.job) + this + dispatcher + supervisorJob + CoroutineName(name) + } } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/RustBaseRoomTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/RustBaseRoomTest.kt index 9c8feef2dc..851f64c230 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/RustBaseRoomTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/RustBaseRoomTest.kt @@ -175,7 +175,7 @@ class RustBaseRoomTest { ), roomMembershipObserver = roomMembershipObserver, // Not using backgroundScope here, but the test scope - sessionCoroutineScope = this, + sessionCoroutineScope = backgroundScope, roomInfoMapper = RoomInfoMapper(), initialRoomInfo = initialRoomInfo, )