feat(security&privacy) : fix tests after some rework landed

This commit is contained in:
ganfra 2025-01-28 21:08:14 +01:00
parent 82bbf2c83f
commit a8b3c7c5a7
5 changed files with 87 additions and 22 deletions

View file

@ -67,7 +67,10 @@ class IdentityChangeStatePresenterTest {
@Test @Test
fun `present - when the clear room emits identity change, the presenter does not emit new state`() = runTest { fun `present - when the clear room emits identity change, the presenter does not emit new state`() = runTest {
val room = FakeMatrixRoom(isEncrypted = false) val room = FakeMatrixRoom(
isEncrypted = false,
enableEncryptionResult = { Result.success(Unit) }
)
val presenter = createIdentityChangeStatePresenter(room) val presenter = createIdentityChangeStatePresenter(room)
presenter.test { presenter.test {
val initialState = awaitItem() val initialState = awaitItem()

View file

@ -1,8 +1,8 @@
/* /*
* Copyright 2025 New Vector Ltd. * Copyright 2025 New Vector Ltd.
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE in the repository root for full details. * Please see LICENSE files in the repository root for full details.
*/ */
package io.element.android.features.roomdetails.impl.securityandprivacy package io.element.android.features.roomdetails.impl.securityandprivacy

View file

@ -11,6 +11,7 @@ import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.StateEventType import io.element.android.libraries.matrix.api.room.StateEventType
import io.element.android.libraries.matrix.api.room.join.JoinRule
import io.element.android.libraries.matrix.test.AN_AVATAR_URL import io.element.android.libraries.matrix.test.AN_AVATAR_URL
import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_ROOM_NAME import io.element.android.libraries.matrix.test.A_ROOM_NAME
@ -29,9 +30,11 @@ fun aMatrixRoom(
isEncrypted: Boolean = true, isEncrypted: Boolean = true,
isPublic: Boolean = true, isPublic: Boolean = true,
isDirect: Boolean = false, isDirect: Boolean = false,
joinRule: JoinRule? = null,
notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService(), notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService(),
emitRoomInfo: Boolean = false, emitRoomInfo: Boolean = false,
canInviteResult: (UserId) -> Result<Boolean> = { lambdaError() }, canInviteResult: (UserId) -> Result<Boolean> = { lambdaError() },
canBanResult: (UserId) -> Result<Boolean> = { lambdaError() },
canSendStateResult: (UserId, StateEventType) -> Result<Boolean> = { _, _ -> lambdaError() }, canSendStateResult: (UserId, StateEventType) -> Result<Boolean> = { _, _ -> lambdaError() },
userDisplayNameResult: (UserId) -> Result<String?> = { lambdaError() }, userDisplayNameResult: (UserId) -> Result<String?> = { lambdaError() },
userAvatarUrlResult: () -> Result<String?> = { lambdaError() }, userAvatarUrlResult: () -> Result<String?> = { lambdaError() },
@ -51,6 +54,7 @@ fun aMatrixRoom(
isDirect = isDirect, isDirect = isDirect,
notificationSettingsService = notificationSettingsService, notificationSettingsService = notificationSettingsService,
canInviteResult = canInviteResult, canInviteResult = canInviteResult,
canBanResult = canBanResult,
canSendStateResult = canSendStateResult, canSendStateResult = canSendStateResult,
userDisplayNameResult = userDisplayNameResult, userDisplayNameResult = userDisplayNameResult,
userAvatarUrlResult = userAvatarUrlResult, userAvatarUrlResult = userAvatarUrlResult,
@ -70,6 +74,7 @@ fun aMatrixRoom(
avatarUrl = avatarUrl, avatarUrl = avatarUrl,
isDirect = isDirect, isDirect = isDirect,
isPublic = isPublic, isPublic = isPublic,
joinRule = joinRule,
) )
) )
} }

View file

@ -24,6 +24,7 @@ import io.element.android.features.roomdetails.impl.members.details.RoomMemberDe
import io.element.android.features.userprofile.shared.aUserProfileState import io.element.android.features.userprofile.shared.aUserProfileState
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.featureflag.api.FeatureFlagService
import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
@ -31,6 +32,7 @@ import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.room.RoomNotificationMode
import io.element.android.libraries.matrix.api.room.StateEventType import io.element.android.libraries.matrix.api.room.StateEventType
import io.element.android.libraries.matrix.api.room.join.JoinRule
import io.element.android.libraries.matrix.test.AN_AVATAR_URL import io.element.android.libraries.matrix.test.AN_AVATAR_URL
import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.AN_EVENT_ID
import io.element.android.libraries.matrix.test.A_ROOM_NAME import io.element.android.libraries.matrix.test.A_ROOM_NAME
@ -75,6 +77,12 @@ class RoomDetailsPresenterTest {
dispatchers: CoroutineDispatchers = testCoroutineDispatchers(), dispatchers: CoroutineDispatchers = testCoroutineDispatchers(),
notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService(), notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService(),
analyticsService: AnalyticsService = FakeAnalyticsService(), analyticsService: AnalyticsService = FakeAnalyticsService(),
featureFlagService: FeatureFlagService = FakeFeatureFlagService(
mapOf(
FeatureFlags.NotificationSettings.key to true,
FeatureFlags.Knock.key to false,
)
),
isPinnedMessagesFeatureEnabled: Boolean = true, isPinnedMessagesFeatureEnabled: Boolean = true,
): RoomDetailsPresenter { ): RoomDetailsPresenter {
val matrixClient = FakeMatrixClient(notificationSettingsService = notificationSettingsService) val matrixClient = FakeMatrixClient(notificationSettingsService = notificationSettingsService)
@ -89,9 +97,6 @@ class RoomDetailsPresenterTest {
) )
} }
} }
val featureFlagService = FakeFeatureFlagService(
mapOf(FeatureFlags.NotificationSettings.key to true)
)
return RoomDetailsPresenter( return RoomDetailsPresenter(
client = matrixClient, client = matrixClient,
room = room, room = room,
@ -133,6 +138,7 @@ class RoomDetailsPresenterTest {
assertThat(initialState.isEncrypted).isEqualTo(room.isEncrypted) assertThat(initialState.isEncrypted).isEqualTo(room.isEncrypted)
assertThat(initialState.canShowPinnedMessages).isTrue() assertThat(initialState.canShowPinnedMessages).isTrue()
assertThat(initialState.pinnedMessagesCount).isNull() assertThat(initialState.pinnedMessagesCount).isNull()
assertThat(initialState.canShowSecurityAndPrivacy).isFalse()
} }
} }
@ -270,8 +276,7 @@ class RoomDetailsPresenterTest {
when (stateEventType) { when (stateEventType) {
StateEventType.ROOM_TOPIC -> Result.success(true) StateEventType.ROOM_TOPIC -> Result.success(true)
StateEventType.ROOM_NAME -> Result.success(false) StateEventType.ROOM_NAME -> Result.success(false)
StateEventType.ROOM_AVATAR -> Result.failure(Throwable("Whelp")) else -> Result.failure(Throwable("Whelp"))
else -> lambdaError()
} }
}, },
canInviteResult = { Result.success(false) }, canInviteResult = { Result.success(false) },
@ -297,10 +302,10 @@ class RoomDetailsPresenterTest {
isDirect = true, isDirect = true,
canSendStateResult = { _, stateEventType -> canSendStateResult = { _, stateEventType ->
when (stateEventType) { when (stateEventType) {
StateEventType.ROOM_TOPIC -> Result.success(true) StateEventType.ROOM_TOPIC,
StateEventType.ROOM_NAME -> Result.success(true) StateEventType.ROOM_NAME,
StateEventType.ROOM_AVATAR -> Result.success(true) StateEventType.ROOM_AVATAR -> Result.success(true)
else -> lambdaError() else -> Result.failure(Throwable("Whelp"))
} }
}, },
canInviteResult = { Result.success(false) }, canInviteResult = { Result.success(false) },
@ -343,7 +348,7 @@ class RoomDetailsPresenterTest {
StateEventType.ROOM_AVATAR, StateEventType.ROOM_AVATAR,
StateEventType.ROOM_TOPIC, StateEventType.ROOM_TOPIC,
StateEventType.ROOM_NAME -> Result.success(true) StateEventType.ROOM_NAME -> Result.success(true)
else -> lambdaError() else -> Result.failure(Throwable("Whelp"))
} }
}, },
canInviteResult = { Result.success(true) }, canInviteResult = { Result.success(true) },
@ -376,10 +381,10 @@ class RoomDetailsPresenterTest {
val room = aMatrixRoom( val room = aMatrixRoom(
canSendStateResult = { _, stateEventType -> canSendStateResult = { _, stateEventType ->
when (stateEventType) { when (stateEventType) {
StateEventType.ROOM_TOPIC -> Result.success(true) StateEventType.ROOM_TOPIC,
StateEventType.ROOM_NAME -> Result.success(true) StateEventType.ROOM_NAME,
StateEventType.ROOM_AVATAR -> Result.success(true) StateEventType.ROOM_AVATAR -> Result.success(true)
else -> lambdaError() else -> Result.failure(Throwable("Whelp"))
} }
}, },
canInviteResult = { canInviteResult = {
@ -403,10 +408,10 @@ class RoomDetailsPresenterTest {
val room = aMatrixRoom( val room = aMatrixRoom(
canSendStateResult = { _, stateEventType -> canSendStateResult = { _, stateEventType ->
when (stateEventType) { when (stateEventType) {
StateEventType.ROOM_TOPIC -> Result.success(false) StateEventType.ROOM_TOPIC,
StateEventType.ROOM_NAME -> Result.success(false) StateEventType.ROOM_NAME,
StateEventType.ROOM_AVATAR -> Result.success(false) StateEventType.ROOM_AVATAR -> Result.success(false)
else -> lambdaError() else -> Result.failure(Throwable("Whelp"))
} }
}, },
canInviteResult = { canInviteResult = {
@ -432,7 +437,7 @@ class RoomDetailsPresenterTest {
StateEventType.ROOM_AVATAR, StateEventType.ROOM_AVATAR,
StateEventType.ROOM_NAME -> Result.success(true) StateEventType.ROOM_NAME -> Result.success(true)
StateEventType.ROOM_TOPIC -> Result.success(false) StateEventType.ROOM_TOPIC -> Result.success(false)
else -> lambdaError() else -> Result.failure(Throwable("Whelp"))
} }
}, },
canInviteResult = { canInviteResult = {
@ -458,7 +463,7 @@ class RoomDetailsPresenterTest {
StateEventType.ROOM_AVATAR, StateEventType.ROOM_AVATAR,
StateEventType.ROOM_TOPIC, StateEventType.ROOM_TOPIC,
StateEventType.ROOM_NAME -> Result.success(true) StateEventType.ROOM_NAME -> Result.success(true)
else -> lambdaError() else -> Result.failure(Throwable("Whelp"))
} }
}, },
canInviteResult = { canInviteResult = {
@ -632,4 +637,57 @@ class RoomDetailsPresenterTest {
cancelAndIgnoreRemainingEvents() cancelAndIgnoreRemainingEvents()
} }
} }
@Test
fun `present - show knock requests`() = runTest {
val room = aMatrixRoom(
emitRoomInfo = true,
canInviteResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canSendStateResult = { _, _ -> Result.success(true) },
joinRule = JoinRule.Knock,
)
val featureFlagService = FakeFeatureFlagService(
mapOf(FeatureFlags.Knock.key to false)
)
val presenter = createRoomDetailsPresenter(
room = room,
featureFlagService = featureFlagService,
)
presenter.test {
skipItems(1)
with(awaitItem()) {
assertThat(canShowKnockRequests).isFalse()
}
featureFlagService.setFeatureEnabled(FeatureFlags.Knock, true)
with(awaitItem()) {
assertThat(canShowKnockRequests).isTrue()
}
room.givenRoomInfo(aRoomInfo(joinRule = JoinRule.Private))
with(awaitItem()) {
assertThat(canShowKnockRequests).isFalse()
}
}
}
@Test
fun `present - show security and privacy`() = runTest {
val room = aMatrixRoom(
canInviteResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canSendStateResult = { _, _ -> Result.success(true) },
)
val featureFlagService = FakeFeatureFlagService()
val presenter = createRoomDetailsPresenter(room = room, featureFlagService = featureFlagService)
presenter.test {
skipItems(1)
with(awaitItem()) {
assertThat(canShowSecurityAndPrivacy).isFalse()
}
featureFlagService.setFeatureEnabled(FeatureFlags.Knock, true)
with(awaitItem()) {
assertThat(canShowSecurityAndPrivacy).isTrue()
}
}
}
} }

View file

@ -17,7 +17,6 @@ import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.isDm
import io.element.android.libraries.matrix.api.room.roomMembers import io.element.android.libraries.matrix.api.room.roomMembers
@Composable @Composable
@ -45,7 +44,7 @@ fun MatrixRoom.getDirectRoomMember(roomMembersState: MatrixRoomMembersState): St
derivedStateOf { derivedStateOf {
roomMembers roomMembers
?.filter { it.membership.isActive() } ?.filter { it.membership.isActive() }
?.takeIf { isDm } ?.takeIf { it.size == 2 && isDirect }
?.find { it.userId != sessionId } ?.find { it.userId != sessionId }
} }
} }