From c59878988b910a9a97672fb8a08842f6214dfb39 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 22 Jan 2026 17:09:54 +0100 Subject: [PATCH] First try to resolve the room before checking for the alias validity. Fixes #5611 --- .../JoinRoomByAddressPresenter.kt | 16 ++- .../JoinBaseRoomByAddressPresenterTest.kt | 102 ++++++++++++++++++ 2 files changed, 115 insertions(+), 3 deletions(-) diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressPresenter.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressPresenter.kt index bda1e054e4..74cabfab91 100644 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressPresenter.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressPresenter.kt @@ -113,7 +113,7 @@ class JoinRoomByAddressPresenter( // debounce the room address resolution delay(300) val roomAlias = tryOrNull { RoomAlias(fullAddress) } - if (roomAlias != null && roomAliasHelper.isRoomAliasValid(roomAlias)) { + if (roomAlias != null) { onChange(RoomAddressState.Resolving) onChange(client.resolveRoomAddress(roomAlias)) } else { @@ -130,11 +130,21 @@ class JoinRoomByAddressPresenter( if (resolved.isPresent) { RoomAddressState.RoomFound(resolved.get()) } else { - RoomAddressState.RoomNotFound + roomAlias.toInvalidOrNotFound() } }, - onFailure = { _ -> RoomAddressState.RoomNotFound } + onFailure = { _ -> + roomAlias.toInvalidOrNotFound() + } ) } ?: RoomAddressState.RoomNotFound } + + private fun RoomAlias.toInvalidOrNotFound(): RoomAddressState { + return if (roomAliasHelper.isRoomAliasValid(this)) { + RoomAddressState.RoomNotFound + } else { + RoomAddressState.Invalid + } + } } diff --git a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressPresenterTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressPresenterTest.kt index 74c43d683e..649af024b9 100644 --- a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressPresenterTest.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressPresenterTest.kt @@ -21,6 +21,7 @@ import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.test import kotlinx.coroutines.test.runTest import org.junit.Test +import java.util.Optional class JoinBaseRoomByAddressPresenterTest { @Test @@ -58,6 +59,107 @@ class JoinBaseRoomByAddressPresenterTest { } } + @Test + fun `present - invalid address - but room exists`() = runTest { + val presenter = createJoinRoomByAddressPresenter( + roomAliasHelper = FakeRoomAliasHelper( + isRoomAliasValidLambda = { + // The SDK still return false, but we have a room for this alias + false + } + ) + ) + presenter.test { + with(awaitItem()) { + eventSink(JoinRoomByAddressEvents.UpdateAddress("#ö:invalid.org")) + } + with(awaitItem()) { + assertThat(address).isEqualTo("#ö:invalid.org") + assertThat(addressState).isEqualTo(RoomAddressState.Unknown) + eventSink(JoinRoomByAddressEvents.Continue) + } + // The address should not be marked as valid + with(awaitItem()) { + assertThat(address).isEqualTo("#ö:invalid.org") + assertThat(addressState).isEqualTo(RoomAddressState.Resolving) + } + with(awaitItem()) { + assertThat(address).isEqualTo("#ö:invalid.org") + assertThat(addressState).isInstanceOf(RoomAddressState.RoomFound::class.java) + } + } + } + + @Test + fun `present - invalid address - room does not exist`() = runTest { + val presenter = createJoinRoomByAddressPresenter( + roomAliasHelper = FakeRoomAliasHelper( + isRoomAliasValidLambda = { + // The SDK return false + false + } + ), + matrixClient = FakeMatrixClient( + resolveRoomAliasResult = { + Result.success(Optional.empty()) + } + ) + ) + presenter.test { + with(awaitItem()) { + eventSink(JoinRoomByAddressEvents.UpdateAddress("#ö:invalid.org")) + } + with(awaitItem()) { + assertThat(address).isEqualTo("#ö:invalid.org") + assertThat(addressState).isEqualTo(RoomAddressState.Unknown) + eventSink(JoinRoomByAddressEvents.Continue) + } + // The address should not be marked as valid + with(awaitItem()) { + assertThat(address).isEqualTo("#ö:invalid.org") + assertThat(addressState).isEqualTo(RoomAddressState.Resolving) + } + with(awaitItem()) { + assertThat(address).isEqualTo("#ö:invalid.org") + assertThat(addressState).isEqualTo(RoomAddressState.Invalid) + } + } + } + + @Test + fun `present - invalid address - failure to resolve the room`() = runTest { + val presenter = createJoinRoomByAddressPresenter( + roomAliasHelper = FakeRoomAliasHelper( + isRoomAliasValidLambda = { + // The SDK still return false, but we have a room for this alias + false + } + ), + matrixClient = FakeMatrixClient( + resolveRoomAliasResult = { Result.failure(RuntimeException()) } + ) + ) + presenter.test { + with(awaitItem()) { + eventSink(JoinRoomByAddressEvents.UpdateAddress("#ö:invalid.org")) + } + with(awaitItem()) { + assertThat(address).isEqualTo("#ö:invalid.org") + assertThat(addressState).isEqualTo(RoomAddressState.Unknown) + eventSink(JoinRoomByAddressEvents.Continue) + } + // The address should not be marked as valid + with(awaitItem()) { + assertThat(address).isEqualTo("#ö:invalid.org") + assertThat(addressState).isEqualTo(RoomAddressState.Resolving) + } + with(awaitItem()) { + assertThat(address).isEqualTo("#ö:invalid.org") + assertThat(addressState).isEqualTo(RoomAddressState.Invalid) + } + } + } + @Test fun `present - room found`() = runTest { val openRoomLambda = lambdaRecorder, Unit> { _, _ -> }