mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-11-03 16:10:00 +00:00
Stop waiting for a room alias that the remote server never resolves (#7446)
Tapping a room alias whose server is down left the resolver screen on a spinner for as long as the screen stayed open, with no way forward other than going back. Bound the resolution with the ten second timeout already used when joining a room by address, so the retry dialog is shown instead. The fake client's resolve lambda becomes suspending so a server that never answers can be simulated.
This commit is contained in:
+9
-1
@@ -24,7 +24,10 @@ import io.element.android.libraries.matrix.api.core.RoomAlias
|
|||||||
import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
|
import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withTimeoutOrNull
|
||||||
|
import java.util.concurrent.TimeoutException
|
||||||
import kotlin.jvm.optionals.getOrElse
|
import kotlin.jvm.optionals.getOrElse
|
||||||
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
||||||
@AssistedInject
|
@AssistedInject
|
||||||
class RoomAliasResolverPresenter(
|
class RoomAliasResolverPresenter(
|
||||||
@@ -61,9 +64,14 @@ class RoomAliasResolverPresenter(
|
|||||||
|
|
||||||
private fun CoroutineScope.resolveAlias(resolveState: MutableState<AsyncData<ResolvedRoomAlias>>) = launch {
|
private fun CoroutineScope.resolveAlias(resolveState: MutableState<AsyncData<ResolvedRoomAlias>>) = launch {
|
||||||
suspend {
|
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()
|
.getOrThrow()
|
||||||
.getOrElse { throw RoomAliasResolverFailures.UnknownAlias }
|
.getOrElse { throw RoomAliasResolverFailures.UnknownAlias }
|
||||||
}.runCatchingUpdatingState(resolveState)
|
}.runCatchingUpdatingState(resolveState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const val ALIAS_RESOLVE_TIMEOUT_IN_SECONDS = 10
|
||||||
|
|||||||
+18
@@ -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.A_SERVER_LIST
|
||||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||||
import io.element.android.tests.testutils.WarmUpRule
|
import io.element.android.tests.testutils.WarmUpRule
|
||||||
|
import kotlinx.coroutines.awaitCancellation
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.util.Optional
|
import java.util.Optional
|
||||||
|
import java.util.concurrent.TimeoutException
|
||||||
|
|
||||||
class RoomAliasHelperPresenterTest {
|
class RoomAliasHelperPresenterTest {
|
||||||
@get:Rule
|
@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
|
@Test
|
||||||
fun `present - resolve alias error and retry`() = runTest {
|
fun `present - resolve alias error and retry`() = runTest {
|
||||||
val client = FakeMatrixClient(
|
val client = FakeMatrixClient(
|
||||||
|
|||||||
+1
-1
@@ -100,7 +100,7 @@ class FakeMatrixClient(
|
|||||||
override val roomMembershipObserver: RoomMembershipObserver = RoomMembershipObserver(),
|
override val roomMembershipObserver: RoomMembershipObserver = RoomMembershipObserver(),
|
||||||
private val homeserverCapabilitiesProvider: FakeHomeserverCapabilitiesProvider = FakeHomeserverCapabilitiesProvider(),
|
private val homeserverCapabilitiesProvider: FakeHomeserverCapabilitiesProvider = FakeHomeserverCapabilitiesProvider(),
|
||||||
private val accountManagementUrlResult: (AccountManagementAction?) -> Result<String?> = { lambdaError() },
|
private val accountManagementUrlResult: (AccountManagementAction?) -> Result<String?> = { lambdaError() },
|
||||||
private val resolveRoomAliasResult: (RoomAlias) -> Result<Optional<ResolvedRoomAlias>> = {
|
private val resolveRoomAliasResult: suspend (RoomAlias) -> Result<Optional<ResolvedRoomAlias>> = {
|
||||||
Result.success(
|
Result.success(
|
||||||
Optional.of(ResolvedRoomAlias(A_ROOM_ID, emptyList()))
|
Optional.of(ResolvedRoomAlias(A_ROOM_ID, emptyList()))
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user