diff --git a/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverPresenter.kt b/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverPresenter.kt index 78be168e53..1ec0ce0691 100644 --- a/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverPresenter.kt +++ b/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverPresenter.kt @@ -24,7 +24,10 @@ import io.element.android.libraries.matrix.api.core.RoomAlias import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch +import kotlinx.coroutines.withTimeoutOrNull +import java.util.concurrent.TimeoutException import kotlin.jvm.optionals.getOrElse +import kotlin.time.Duration.Companion.seconds @AssistedInject class RoomAliasResolverPresenter( @@ -61,9 +64,14 @@ class RoomAliasResolverPresenter( private fun CoroutineScope.resolveAlias(resolveState: MutableState>) = launch { suspend { - matrixClient.resolveRoomAlias(roomAlias) + val result = withTimeoutOrNull(ALIAS_RESOLVE_TIMEOUT_IN_SECONDS.seconds) { + matrixClient.resolveRoomAlias(roomAlias) + } ?: throw TimeoutException("Timed out while resolving ${roomAlias.value}") + result .getOrThrow() .getOrElse { throw RoomAliasResolverFailures.UnknownAlias } }.runCatchingUpdatingState(resolveState) } } + +private const val ALIAS_RESOLVE_TIMEOUT_IN_SECONDS = 10 diff --git a/features/roomaliasresolver/impl/src/test/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasHelperPresenterTest.kt b/features/roomaliasresolver/impl/src/test/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasHelperPresenterTest.kt index df8b8058be..a50049446b 100644 --- a/features/roomaliasresolver/impl/src/test/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasHelperPresenterTest.kt +++ b/features/roomaliasresolver/impl/src/test/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasHelperPresenterTest.kt @@ -22,10 +22,12 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_SERVER_LIST import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.tests.testutils.WarmUpRule +import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test import java.util.Optional +import java.util.concurrent.TimeoutException class RoomAliasHelperPresenterTest { @get:Rule @@ -60,6 +62,22 @@ class RoomAliasHelperPresenterTest { } } + @Test + fun `present - a server that never answers ends up in an error state`() = runTest { + val client = FakeMatrixClient( + resolveRoomAliasResult = { awaitCancellation() } + ) + val presenter = createPresenter(matrixClient = client) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + assertThat(awaitItem().resolveState.isUninitialized()).isTrue() + assertThat(awaitItem().resolveState.isLoading()).isTrue() + val resultState = awaitItem() + assertThat(resultState.resolveState.errorOrNull()).isInstanceOf(TimeoutException::class.java) + } + } + @Test fun `present - resolve alias error and retry`() = runTest { val client = FakeMatrixClient( diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt index 201f8cbf28..6ba42270fe 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt @@ -100,7 +100,7 @@ class FakeMatrixClient( override val roomMembershipObserver: RoomMembershipObserver = RoomMembershipObserver(), private val homeserverCapabilitiesProvider: FakeHomeserverCapabilitiesProvider = FakeHomeserverCapabilitiesProvider(), private val accountManagementUrlResult: (AccountManagementAction?) -> Result = { lambdaError() }, - private val resolveRoomAliasResult: (RoomAlias) -> Result> = { + private val resolveRoomAliasResult: suspend (RoomAlias) -> Result> = { Result.success( Optional.of(ResolvedRoomAlias(A_ROOM_ID, emptyList())) )