diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/CoreFailure.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/CoreFailure.kt index c8cfc039dfa..1a782822870 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/CoreFailure.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/CoreFailure.kt @@ -38,6 +38,10 @@ sealed interface CoreFailure { && this.kaliumException is KaliumException.InvalidRequestError && this.kaliumException.errorResponse.code == HttpStatusCode.NotFound.value + val hasUnreachableDomainsError: Boolean + get() = this is NetworkFailure.FederatedBackendFailure + && this.label == "federation-unreachable-domains-error" && this.domains.isNotEmpty() + /** * The attempted operation requires that this client is registered. */ @@ -106,7 +110,7 @@ sealed class NetworkFailure : CoreFailure { /** * Failure due to a federated backend context */ - object FederatedBackendFailure : NetworkFailure() + class FederatedBackendFailure(val label: String, val domains: List = emptyList()) : NetworkFailure() } interface MLSFailure : CoreFailure { @@ -151,7 +155,8 @@ internal inline fun wrapApiRequest(networkCall: () -> NetworkResponse< val exception = result.kException when { exception is KaliumException.FederationError -> { - Either.Left(NetworkFailure.FederatedBackendFailure) + val cause = exception.errorResponse.cause + Either.Left(NetworkFailure.FederatedBackendFailure(exception.errorResponse.label, cause?.domains.orEmpty())) } // todo SocketException is platform specific so need to wrap it in our own exceptions diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/AddingMembersFailureMapper.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/AddingMembersFailureMapper.kt new file mode 100644 index 00000000000..14326a0b03f --- /dev/null +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/AddingMembersFailureMapper.kt @@ -0,0 +1,58 @@ +/* + * Wire + * Copyright (C) 2023 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.logic.data.conversation + +import com.wire.kalium.logic.NetworkFailure +import com.wire.kalium.logic.data.user.UserId + +internal interface AddingMembersFailureMapper { + /** + * Will map the [initialUsersIds] and split accordingly excluding users with domain failures. + * @param initialUsersIds the list of users that were initially requested to be added to the conversation + * @param federatedBackendFailure the [NetworkFailure.FederatedBackendFailure] that contains the domains that failed + * @param previousUserIdsExcluded the previous attempt of list of users that cannot be added to the conversation + */ + fun mapToUsersRequestState( + initialUsersIds: List, + federatedBackendFailure: NetworkFailure.FederatedBackendFailure, + previousUserIdsExcluded: Set = emptySet(), + ): AddingMembersRequestState +} + +internal class AddingMembersFailureMapperImpl : AddingMembersFailureMapper { + override fun mapToUsersRequestState( + initialUsersIds: List, + federatedBackendFailure: NetworkFailure.FederatedBackendFailure, + previousUserIdsExcluded: Set + ): AddingMembersRequestState { + val domainsToExclude = federatedBackendFailure.domains + // splitting the initialUsersIds into users with failures[true] and users without failures[false] + val groupedUsersWithFailure = initialUsersIds.groupBy { + domainsToExclude.contains(it.domain) + } + return AddingMembersRequestState( + usersThatCanBeAdded = groupedUsersWithFailure[false]?.toSet().orEmpty(), + usersThatCannotBeAdded = groupedUsersWithFailure[true]?.toSet().orEmpty() + previousUserIdsExcluded + ) + } +} + +data class AddingMembersRequestState( + val usersThatCanBeAdded: Set, + val usersThatCannotBeAdded: Set, +) diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationGroupRepository.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationGroupRepository.kt index a8ef85384e3..59a8f6d9841 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationGroupRepository.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationGroupRepository.kt @@ -87,6 +87,7 @@ internal class ConversationGroupRepositoryImpl( private val conversationMapper: ConversationMapper = MapperProvider.conversationMapper(), private val eventMapper: EventMapper = MapperProvider.eventMapper(), private val protocolInfoMapper: ProtocolInfoMapper = MapperProvider.protocolInfoMapper(), + private val addingMembersFailureMapper: AddingMembersFailureMapper = MapperProvider.addingMembersFailureMapper(), ) : ConversationGroupRepository { override suspend fun createGroupConversation( @@ -140,7 +141,7 @@ internal class ConversationGroupRepositoryImpl( .flatMap { protocol -> when (protocol) { is ConversationEntity.ProtocolInfo.Proteus -> - addMembersToCloudAndStorage(userIdList, conversationId) + tryAddMembersToCloudAndStorage(userIdList, conversationId) is ConversationEntity.ProtocolInfo.MLS -> { mlsConversationRepository.addMemberToMLSGroup(GroupID(protocol.groupId), userIdList) @@ -174,20 +175,51 @@ internal class ConversationGroupRepositoryImpl( } } - private suspend fun addMembersToCloudAndStorage(userIdList: List, conversationId: ConversationId): Either = - wrapApiRequest { + private suspend fun tryAddMembersToCloudAndStorage( + userIdList: List, + conversationId: ConversationId, + previousUserIdsExcluded: Set = emptySet(), + ): Either { + val apiResult = wrapApiRequest { val users = userIdList.map { it.toApi() } val addParticipantRequest = AddConversationMembersRequest(users, ConversationDataSource.DEFAULT_MEMBER_ROLE) conversationApi.addMember( addParticipantRequest, conversationId.toApi() ) - }.onSuccess { response -> - if (response is ConversationMemberAddedResponse.Changed) { - memberJoinEventHandler.handle(eventMapper.conversationMemberJoin(LocalId.generate(), response.event, true)) + } + + return when (apiResult) { + is Either.Left -> { + if (apiResult.value.hasUnreachableDomainsError) { + val usersReqState = addingMembersFailureMapper.mapToUsersRequestState( + userIdList, + apiResult.value as NetworkFailure.FederatedBackendFailure, + previousUserIdsExcluded + ) + // retry adding, only with filtered available members to the conversation + tryAddMembersToCloudAndStorage( + usersReqState.usersThatCanBeAdded.toList(), conversationId, usersReqState.usersThatCannotBeAdded + ) + } else { + Either.Left(apiResult.value) + } + } + + is Either.Right -> { + if (apiResult.value is ConversationMemberAddedResponse.Changed) { + memberJoinEventHandler.handle( + eventMapper.conversationMemberJoin(LocalId.generate(), apiResult.value.event, true) + ) + } + if (previousUserIdsExcluded.isNotEmpty()) { + newGroupConversationSystemMessagesCreator.value.conversationFailedToAddMembers( + conversationId, previousUserIdsExcluded + ) + } + Either.Right(Unit) } - }.map { - Either.Right(Unit) } + } override suspend fun deleteMember( userId: UserId, diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/NewGroupConversationSystemMessagesCreator.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/NewGroupConversationSystemMessagesCreator.kt index 2e46853428f..d9f44d0cdfa 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/NewGroupConversationSystemMessagesCreator.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/NewGroupConversationSystemMessagesCreator.kt @@ -48,6 +48,11 @@ internal interface NewGroupConversationSystemMessagesCreator { conversationId: ConversationIDEntity, conversationResponse: ConversationResponse ): Either + + suspend fun conversationFailedToAddMembers( + conversationId: ConversationId, + userIdList: Set + ): Either } internal class NewGroupConversationSystemMessagesCreatorImpl( @@ -156,6 +161,23 @@ internal class NewGroupConversationSystemMessagesCreatorImpl( } } + override suspend fun conversationFailedToAddMembers( + conversationId: ConversationId, + userIdList: Set + ): Either { + val messageFailedToAddMembers = Message.System( + uuid4().toString(), + MessageContent.MemberChange.FailedToAdd(userIdList.toList()), + conversationId, + DateTimeUtil.currentIsoDateTimeString(), + selfUserId, + Message.Status.SENT, + Message.Visibility.VISIBLE, + expirationData = null + ) + return persistMessage(messageFailedToAddMembers) + } + private suspend fun createFailedToAddSystemMessage(conversationResponse: ConversationResponse) { if (conversationResponse.failedToAdd.isNotEmpty()) { val messageStartedWithFailedMembers = Message.System( diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/di/MapperProvider.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/di/MapperProvider.kt index 7f066d5426d..a2272cf11fc 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/di/MapperProvider.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/di/MapperProvider.kt @@ -33,6 +33,8 @@ import com.wire.kalium.logic.data.connection.ConnectionMapper import com.wire.kalium.logic.data.connection.ConnectionMapperImpl import com.wire.kalium.logic.data.connection.ConnectionStatusMapper import com.wire.kalium.logic.data.connection.ConnectionStatusMapperImpl +import com.wire.kalium.logic.data.conversation.AddingMembersFailureMapper +import com.wire.kalium.logic.data.conversation.AddingMembersFailureMapperImpl import com.wire.kalium.logic.data.conversation.ConversationMapper import com.wire.kalium.logic.data.conversation.ConversationMapperImpl import com.wire.kalium.logic.data.conversation.ConversationRoleMapper @@ -80,10 +82,10 @@ import com.wire.kalium.logic.data.prekey.PreKeyMapper import com.wire.kalium.logic.data.prekey.PreKeyMapperImpl import com.wire.kalium.logic.data.publicuser.PublicUserMapper import com.wire.kalium.logic.data.publicuser.PublicUserMapperImpl +import com.wire.kalium.logic.data.service.ServiceMapper import com.wire.kalium.logic.data.session.SessionMapper import com.wire.kalium.logic.data.session.SessionMapperImpl import com.wire.kalium.logic.data.session.SessionRepository -import com.wire.kalium.logic.data.service.ServiceMapper import com.wire.kalium.logic.data.team.TeamMapper import com.wire.kalium.logic.data.team.TeamMapperImpl import com.wire.kalium.logic.data.user.AvailabilityStatusMapper @@ -170,7 +172,7 @@ internal object MapperProvider { fun protocolInfoMapper(): ProtocolInfoMapper = ProtocolInfoMapperImpl() fun receiptModeMapper(): ReceiptModeMapper = ReceiptModeMapperImpl() fun sendMessagePartialFailureMapper(): SendMessagePartialFailureMapper = SendMessagePartialFailureMapperImpl() - fun serviceMapper(): ServiceMapper = ServiceMapper() + fun addingMembersFailureMapper(): AddingMembersFailureMapper = AddingMembersFailureMapperImpl() } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/auth/LoginUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/auth/LoginUseCase.kt index 81d420a3098..d75b7caf5da 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/auth/LoginUseCase.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/auth/LoginUseCase.kt @@ -136,7 +136,7 @@ internal class LoginUseCaseImpl internal constructor( when (it) { is NetworkFailure.ProxyError -> AuthenticationResult.Failure.SocketError is NetworkFailure.ServerMiscommunication -> handleServerMiscommunication(it, isEmail, cleanUserIdentifier) - is NetworkFailure.NoNetworkConnection, NetworkFailure.FederatedBackendFailure -> + is NetworkFailure.NoNetworkConnection, is NetworkFailure.FederatedBackendFailure -> AuthenticationResult.Failure.Generic(it) } }, { diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/conversation/AddingMembersFailureMapperTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/conversation/AddingMembersFailureMapperTest.kt new file mode 100644 index 00000000000..0e1f81791db --- /dev/null +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/conversation/AddingMembersFailureMapperTest.kt @@ -0,0 +1,70 @@ +/* + * Wire + * Copyright (C) 2023 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.logic.data.conversation + +import com.wire.kalium.logic.NetworkFailure +import com.wire.kalium.logic.framework.TestUser +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class AddingMembersFailureMapperTest { + + private val addingMembersFailureMapper = AddingMembersFailureMapperImpl() + + @Test + fun givenUsersIdsAndDomainsError_whenMapping_thenShouldSplitIntoValidAndNotValidUserIds() { + // When + val mappedRequestState = addingMembersFailureMapper.mapToUsersRequestState( + initialUsersIds = initialUserIdList, + federatedBackendFailure = NetworkFailure.FederatedBackendFailure("federated-label", unreachableDomains) + ) + + // Then + assertEquals(TestUser.OTHER_USER_ID, mappedRequestState.usersThatCanBeAdded.first()) + assertEquals(TestUser.OTHER_FEDERATED_USER_ID, mappedRequestState.usersThatCannotBeAdded.first()) + } + + @Test + fun givenUsersIdsADomainsErrorAndPreviousFailedIds_whenMapping_thenShouldSplitConsideringPreviousFailedIds() { + // When + val mappedRequestState = addingMembersFailureMapper.mapToUsersRequestState( + initialUsersIds = initialUserIdList, + federatedBackendFailure = NetworkFailure.FederatedBackendFailure("federated-label", unreachableDomains), + previousUserIdsExcluded = previousFailedIds + ) + + // Then + assertEquals(TestUser.OTHER_USER_ID, mappedRequestState.usersThatCanBeAdded.first()) + assertEquals(2, mappedRequestState.usersThatCannotBeAdded.size) + assertTrue { + mappedRequestState.usersThatCannotBeAdded.containsAll( + listOf( + TestUser.OTHER_FEDERATED_USER_ID, + TestUser.OTHER_FEDERATED_USER_ID_2 + ) + ) + } + } + + private companion object { + val initialUserIdList = listOf(TestUser.OTHER_USER_ID, TestUser.OTHER_FEDERATED_USER_ID) + val previousFailedIds = setOf(TestUser.OTHER_FEDERATED_USER_ID_2) + val unreachableDomains = listOf("otherDomain") + } +} diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/conversation/ConversationGroupRepositoryTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/conversation/ConversationGroupRepositoryTest.kt index 93f05f7cee0..4b3fb2337f9 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/conversation/ConversationGroupRepositoryTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/conversation/ConversationGroupRepositoryTest.kt @@ -40,6 +40,7 @@ import com.wire.kalium.logic.util.arrangment.dao.MemberDAOArrangement import com.wire.kalium.logic.util.arrangment.dao.MemberDAOArrangementImpl import com.wire.kalium.logic.util.shouldFail import com.wire.kalium.logic.util.shouldSucceed +import com.wire.kalium.logic.util.thenReturnSequentially import com.wire.kalium.network.api.base.authenticated.conversation.AddServiceRequest import com.wire.kalium.network.api.base.authenticated.conversation.ConvProtocol import com.wire.kalium.network.api.base.authenticated.conversation.ConvProtocol.MLS @@ -54,6 +55,7 @@ import com.wire.kalium.network.api.base.authenticated.conversation.guestroomlink import com.wire.kalium.network.api.base.authenticated.conversation.messagetimer.ConversationMessageTimerDTO import com.wire.kalium.network.api.base.authenticated.conversation.model.LimitedConversationInfo import com.wire.kalium.network.api.base.authenticated.notification.EventContentDTO +import com.wire.kalium.network.api.base.model.Cause import com.wire.kalium.network.api.base.model.ConversationAccessDTO import com.wire.kalium.network.api.base.model.ConversationAccessRoleDTO import com.wire.kalium.network.api.base.model.ErrorResponse @@ -69,6 +71,7 @@ import io.mockative.anything import io.mockative.eq import io.mockative.fun1 import io.mockative.given +import io.mockative.matching import io.mockative.mock import io.mockative.once import io.mockative.verify @@ -705,6 +708,54 @@ class ConversationGroupRepositoryTest { .wasNotInvoked() } + @Test + fun givenAConversationAndAPIFailsWithUnreachableDomains_whenAddingMembersToConversation_thenShouldRetryWithValidUsers() = + runTest { + val failedDomain = "unstableDomain1.com" + // given + val (arrangement, conversationGroupRepository) = Arrangement() + .withConversationDetailsById(TestConversation.CONVERSATION) + .withProtocolInfoById(PROTEUS_PROTOCOL_INFO) + .withFetchUsersIfUnknownByIdsSuccessful() + .withAddMemberAPIFailsFirstWithUnreachableThenSucceed( + arrayOf(FEDERATION_ERROR_UNREACHABLE_DOMAINS, API_SUCCESS_MEMBER_ADDED) + ) + .withSuccessfulHandleMemberJoinEvent() + .withInsertFailedToAddSystemMessageSuccess() + .arrange() + + // when + val expectedInitialUsers = listOf( + TestConversation.USER_1.copy(domain = failedDomain), TestUser.OTHER_FEDERATED_USER_ID + ) + conversationGroupRepository.addMembers(expectedInitialUsers, TestConversation.ID).shouldSucceed() + + // then + val expectedFullUserIdsForRequestCount = 2 + val expectedValidUsersCount = 1 + verify(arrangement.conversationApi) + .suspendFunction(arrangement.conversationApi::addMember) + .with(matching { + it.users.size == expectedFullUserIdsForRequestCount + }).wasInvoked(exactly = once) + + verify(arrangement.conversationApi) + .suspendFunction(arrangement.conversationApi::addMember) + .with(matching { + it.users.size == expectedValidUsersCount && it.users.first().domain != failedDomain + }).wasInvoked(exactly = once) + + verify(arrangement.memberJoinEventHandler) + .suspendFunction(arrangement.memberJoinEventHandler::handle) + .with(anything()) + .wasInvoked(exactly = once) + + verify(arrangement.newGroupConversationSystemMessagesCreator) + .suspendFunction(arrangement.newGroupConversationSystemMessagesCreator::conversationFailedToAddMembers) + .with(anything(), matching { it.size == expectedValidUsersCount }) + .wasInvoked(exactly = once) + } + private class Arrangement : MemberDAOArrangement by MemberDAOArrangementImpl() { @@ -1075,6 +1126,21 @@ class ConversationGroupRepositoryTest { .thenReturn(Either.Right(Unit)) } + fun withInsertFailedToAddSystemMessageSuccess(): Arrangement = apply { + given(newGroupConversationSystemMessagesCreator) + .suspendFunction(newGroupConversationSystemMessagesCreator::conversationFailedToAddMembers) + .whenInvokedWith(anything(), anything()) + .thenReturn(Either.Right(Unit)) + } + + fun withAddMemberAPIFailsFirstWithUnreachableThenSucceed(networkResponses: Array>) = + apply { + given(conversationApi) + .suspendFunction(conversationApi::addMember) + .whenInvokedWith(any(), any()) + .thenReturnSequentially(*networkResponses) + } + fun arrange() = this to conversationGroupRepository } @@ -1120,5 +1186,27 @@ class ConversationGroupRepositoryTest { mlsCipherSuiteTag = null, receiptMode = ReceiptMode.DISABLED ) + + val FEDERATION_ERROR_UNREACHABLE_DOMAINS = NetworkResponse.Error( + KaliumException.FederationError( + ErrorResponse( + HttpStatusCode.InternalServerError.value, + "remote backend unreachable", + "federation-unreachable-domains-error", + Cause( + "federation", + "unstableDomain1.com", + listOf("unstableDomain1.com", "unstableDomain2.com"), + "/some/path" + ) + ) + ) + ) + + val API_SUCCESS_MEMBER_ADDED = NetworkResponse.Success( + TestConversation.ADD_MEMBER_TO_CONVERSATION_SUCCESSFUL_RESPONSE, + mapOf(), + HttpStatusCode.OK.value + ) } } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/conversation/NewGroupConversationSystemMessagesCreatorTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/conversation/NewGroupConversationSystemMessagesCreatorTest.kt index 120d0cee5af..42f4fe01ac3 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/conversation/NewGroupConversationSystemMessagesCreatorTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/conversation/NewGroupConversationSystemMessagesCreatorTest.kt @@ -275,6 +275,24 @@ class NewGroupConversationSystemMessagesCreatorTest { .wasInvoked(once) } + @Test + fun givenConversation_whenPersistingAddingUsersFailure_ThenShouldCreateASystemMessageForThoseUsers() = + runTest { + val (arrangement, sysMessageCreator) = Arrangement() + .withPersistMessageSuccess() + .arrange() + + val result = sysMessageCreator.conversationFailedToAddMembers(TestConversation.ID, setOf(TestUser.OTHER.id)) + + result.shouldSucceed() + + verify(arrangement.persistMessage) + .suspendFunction(arrangement.persistMessage::invoke) + .with(matching { + (it.content is MessageContent.System && it.content is MessageContent.MemberChange.FailedToAdd) + }) + .wasInvoked(once) + } private class Arrangement { @Mock diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/prekey/MessageSendFailureHandlerTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/prekey/MessageSendFailureHandlerTest.kt index cfe4c3a6e7e..5f5baabe1c2 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/prekey/MessageSendFailureHandlerTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/prekey/MessageSendFailureHandlerTest.kt @@ -120,7 +120,7 @@ class MessageSendFailureHandlerTest { @Test fun givenFailedDueToFederationContextAvailability_whenHandlingMessageSendFailure_thenUpdateMessageStatusToFailedRemotely() = runTest { - val failure = NetworkFailure.FederatedBackendFailure + val failure = NetworkFailure.FederatedBackendFailure("error") val (arrangement, messageSendFailureHandler) = Arrangement() .withUpdateMessageStatusSuccess() .arrange() diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/GetMessageAssetUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/GetMessageAssetUseCaseTest.kt index 4721d8e61ed..0d08ae714fb 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/GetMessageAssetUseCaseTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/GetMessageAssetUseCaseTest.kt @@ -187,7 +187,7 @@ class GetMessageAssetUseCaseTest { // Given val someConversationId = ConversationId("some-conversation-id", "some-domain.com") val someMessageId = "some-message-id" - val federatedBackendFailure = NetworkFailure.FederatedBackendFailure + val federatedBackendFailure = NetworkFailure.FederatedBackendFailure("error") val (arrangement, getMessageAsset) = Arrangement() .withDownloadAssetErrorResponse(federatedBackendFailure) .withSuccessfulDownloadStatusUpdate() diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/GetPublicAssetUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/GetPublicAssetUseCaseTest.kt index 286249352f9..9ab11153251 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/GetPublicAssetUseCaseTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/GetPublicAssetUseCaseTest.kt @@ -152,7 +152,7 @@ class GetPublicAssetUseCaseTest { given(assetRepository) .suspendFunction(assetRepository::downloadPublicAsset) .whenInvokedWith(eq(assetKey.value), eq(assetKey.domain)) - .thenReturn(Either.Left(NetworkFailure.FederatedBackendFailure)) + .thenReturn(Either.Left(NetworkFailure.FederatedBackendFailure("error"))) given(userRepository) .suspendFunction(userRepository::removeUserBrokenAsset) diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/message/MessageSenderTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/message/MessageSenderTest.kt index 3b077ded5aa..ff9f9125c8d 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/message/MessageSenderTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/message/MessageSenderTest.kt @@ -1112,7 +1112,7 @@ class MessageSenderTest { ) ) ) - val FEDERATION_MESSAGE_FAILURE = NetworkFailure.FederatedBackendFailure + val FEDERATION_MESSAGE_FAILURE = NetworkFailure.FederatedBackendFailure("error") val TEST_CONTACT_CLIENT_1 = ClientId("clientId1") val TEST_CONTACT_CLIENT_2 = ClientId("clientId2") val TEST_CONTACT_CLIENT_3 = ClientId("clientId3") diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/framework/TestUser.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/framework/TestUser.kt index 5b4be51e7cb..50cc7dbf02c 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/framework/TestUser.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/framework/TestUser.kt @@ -47,6 +47,7 @@ object TestUser { val OTHER_USER_ID = USER_ID.copy(value = "otherValue") val OTHER_USER_ID_2 = USER_ID.copy(value = "otherValue2") val OTHER_FEDERATED_USER_ID = USER_ID.copy(value = "otherValue", "otherDomain") + val OTHER_FEDERATED_USER_ID_2 = USER_ID.copy(value = "otherValue2", "otherDomain2") val ENTITY_ID = QualifiedIDEntity(value, domain) val NETWORK_ID = com.wire.kalium.network.api.base.model.UserId( value = value, diff --git a/network/src/commonMain/kotlin/com/wire/kalium/network/api/base/model/ErrorResponse.kt b/network/src/commonMain/kotlin/com/wire/kalium/network/api/base/model/ErrorResponse.kt index 22e979d2762..cf939e33daf 100644 --- a/network/src/commonMain/kotlin/com/wire/kalium/network/api/base/model/ErrorResponse.kt +++ b/network/src/commonMain/kotlin/com/wire/kalium/network/api/base/model/ErrorResponse.kt @@ -34,6 +34,8 @@ data class ErrorResponse( @Serializable data class Cause( @SerialName("type") val type: String, + @Deprecated("deprecated in favour for `domains`", replaceWith = ReplaceWith("domains")) @SerialName("domain") val domain: String, + @SerialName("domains") val domains: List = emptyList(), @SerialName("path") val path: String, )