Skip to content

Commit

Permalink
feat(mls-migration): ignore inactive clients when calculating support…
Browse files Browse the repository at this point in the history
…ed protocols #11 (#1904)

* test: add test cases for ignoring inactive clients when calculating supported protocols

* feat: add isActive computed property on Client model

* feat: ignore inactive clients when checking if all self clients are mls capable
  • Loading branch information
typfel committed Aug 16, 2023
1 parent 1f01908 commit 2f7adea
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ package com.wire.kalium.logic.data.client

import com.wire.kalium.cryptography.PreKeyCrypto
import com.wire.kalium.logic.data.conversation.ClientId
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import kotlin.time.Duration.Companion.days

data class RegisterClientParam(
val password: String?,
Expand Down Expand Up @@ -61,7 +63,11 @@ data class Client(
val model: String?,
val mlsPublicKeys: Map<String, String>?,
val isMLSCapable: Boolean
)
) {
companion object {
val INACTIVE_DURATION = 28.days
}
}

enum class ClientType {
Temporary,
Expand All @@ -87,3 +93,12 @@ data class OtherUserClient(
val isValid: Boolean,
val isVerified: Boolean
)

/**
* True if the client is considered to be in active use.
*
* A client is considered active if it has connected to the backend within
* the `INACTIVE_DURATION`.
*/
val Client.isActive: Boolean
get() = lastActive?.let { (Clock.System.now() - it) < Client.INACTIVE_DURATION } ?: false
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import com.wire.kalium.logic.NetworkFailure
import com.wire.kalium.logic.StorageFailure
import com.wire.kalium.logic.data.client.Client
import com.wire.kalium.logic.data.client.ClientRepository
import com.wire.kalium.logic.data.client.isActive
import com.wire.kalium.logic.data.featureConfig.FeatureConfigRepository
import com.wire.kalium.logic.data.featureConfig.MLSMigrationModel
import com.wire.kalium.logic.data.featureConfig.MLSModel
Expand Down Expand Up @@ -99,10 +100,10 @@ internal class UpdateSupportedProtocolsUseCaseImpl(
): Boolean {
val mlsIsSupported = mlsConfiguration.supportedProtocols.contains(SupportedProtocol.MLS)
val mlsMigrationHasEnded = migrationConfiguration.hasMigrationEnded()
val allSelfClientsAreMLSCapable = selfClients.all { it.isMLSCapable }
val allSelfClientsAreMLSCapable = selfClients.filter { it.isActive }.all { it.isMLSCapable }
kaliumLogger.d(
"mls is supported = $mlsIsSupported, " +
"all self clients are mls capable = $allSelfClientsAreMLSCapable " +
"all active self clients are mls capable = $allSelfClientsAreMLSCapable " +
"migration has ended = $mlsMigrationHasEnded"
)
return mlsIsSupported && (mlsMigrationHasEnded || allSelfClientsAreMLSCapable)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* 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.client

import com.wire.kalium.logic.framework.TestClient
import kotlinx.datetime.Clock
import kotlin.test.Test
import kotlin.test.assertFalse
import kotlin.test.assertTrue
import kotlin.time.Duration.Companion.days

class ClientTest {

@Test
fun givenLastActiveIsNull_thenIsActiveIsFalse() {
val client = TestClient.CLIENT.copy(
lastActive = null
)
assertFalse(client.isActive)
}

@Test
fun givenLastActiveIsOlderThanInactivityDuration_thenIsActiveIsFalse() {
val client = TestClient.CLIENT.copy(
lastActive = Clock.System.now() - (Client.INACTIVE_DURATION + 1.days)
)
assertFalse(client.isActive)
}

@Test
fun givenLastActiveIsNewerThanInactivityDuration_thenIsActiveIsTrue() {
val client = TestClient.CLIENT.copy(
lastActive = Clock.System.now() - (Client.INACTIVE_DURATION - 1.days)
)
assertTrue(client.isActive)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import io.mockative.once
import io.mockative.verify
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import kotlin.test.Test

Expand Down Expand Up @@ -129,15 +130,15 @@ class UpdateSupportedProtocolsUseCaseTest {
}

@Test
fun givenMlsIsSupportedAndAllClientsAreCapable_whenInvokingUseCase_thenMlsIsIncluded() = runTest {
fun givenMlsIsSupportedAndAllActiveClientsAreCapable_whenInvokingUseCase_thenMlsIsIncluded() = runTest {
val (arrangement, useCase) = Arrangement()
.withGetSelfUserSuccessful()
.withGetFeatureConfigurationSuccessful(
supportedProtocols = setOf(SupportedProtocol.MLS),
migrationConfiguration = ONGOING_MIGRATION_CONFIGURATION
)
.withGetSelfClientsSuccessful(clients = listOf(
TestClient.CLIENT.copy(isMLSCapable = true)
TestClient.CLIENT.copy(isMLSCapable = true, lastActive = Clock.System.now())
))
.withUpdateSupportedProtocolsSuccessful()
.arrange()
Expand All @@ -151,16 +152,39 @@ class UpdateSupportedProtocolsUseCaseTest {
}

@Test
fun givenMlsIsSupportedAndAllClientsAreNotCapable_whenInvokingUseCase_thenMlsIsNotIncluded() = runTest {
fun givenMlsIsSupportedAndAnInactiveClientIsNotMlsCapable_whenInvokingUseCase_thenMlsIsIncluded() = runTest {
val (arrangement, useCase) = Arrangement()
.withGetSelfUserSuccessful()
.withGetFeatureConfigurationSuccessful(
supportedProtocols = setOf(SupportedProtocol.MLS),
migrationConfiguration = ONGOING_MIGRATION_CONFIGURATION
)
.withGetSelfClientsSuccessful(clients = listOf(
TestClient.CLIENT.copy(isMLSCapable = true),
TestClient.CLIENT.copy(isMLSCapable = false)
TestClient.CLIENT.copy(isMLSCapable = true, lastActive = Clock.System.now()),
TestClient.CLIENT.copy(isMLSCapable = false, lastActive = Instant.DISTANT_PAST)
))
.withUpdateSupportedProtocolsSuccessful()
.arrange()

useCase.invoke()

verify(arrangement.userRepository)
.suspendFunction(arrangement.userRepository::updateSupportedProtocols)
.with(matching { it.contains(SupportedProtocol.MLS) })
.wasInvoked(exactly = once)
}

@Test
fun givenMlsIsSupportedAndAllActiveClientsAreNotCapable_whenInvokingUseCase_thenMlsIsNotIncluded() = runTest {
val (arrangement, useCase) = Arrangement()
.withGetSelfUserSuccessful()
.withGetFeatureConfigurationSuccessful(
supportedProtocols = setOf(SupportedProtocol.MLS),
migrationConfiguration = ONGOING_MIGRATION_CONFIGURATION
)
.withGetSelfClientsSuccessful(clients = listOf(
TestClient.CLIENT.copy(isMLSCapable = true, lastActive = Clock.System.now()),
TestClient.CLIENT.copy(isMLSCapable = false, lastActive = Clock.System.now())
))
.withUpdateSupportedProtocolsSuccessful()
.arrange()
Expand Down

0 comments on commit 2f7adea

Please sign in to comment.