GetDeviceFullInfoListUseCase unit tests

This commit is contained in:
Maxime NATUREL 2022-09-06 14:47:18 +02:00
parent 7511d21a6f
commit 6394c7efde
4 changed files with 199 additions and 15 deletions

View File

@ -27,7 +27,6 @@ import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.flow.flow
import javax.inject.Inject import javax.inject.Inject
// TODO add unit tests
class GetDeviceFullInfoListUseCase @Inject constructor( class GetDeviceFullInfoListUseCase @Inject constructor(
private val activeSessionHolder: ActiveSessionHolder, private val activeSessionHolder: ActiveSessionHolder,
private val checkIfSessionIsInactiveUseCase: CheckIfSessionIsInactiveUseCase, private val checkIfSessionIsInactiveUseCase: CheckIfSessionIsInactiveUseCase,
@ -58,9 +57,9 @@ class GetDeviceFullInfoListUseCase @Inject constructor(
.sortedByDescending { it.lastSeenTs } .sortedByDescending { it.lastSeenTs }
.map { deviceInfo -> .map { deviceInfo ->
val cryptoDeviceInfo = cryptoList.firstOrNull { it.deviceId == deviceInfo.deviceId } val cryptoDeviceInfo = cryptoList.firstOrNull { it.deviceId == deviceInfo.deviceId }
val trustLevelForShield = getEncryptionTrustLevelForDeviceUseCase.execute(currentSessionCrossSigningInfo, cryptoDeviceInfo) val roomEncryptionTrustLevel = getEncryptionTrustLevelForDeviceUseCase.execute(currentSessionCrossSigningInfo, cryptoDeviceInfo)
val isInactive = checkIfSessionIsInactiveUseCase.execute(deviceInfo.lastSeenTs ?: 0) val isInactive = checkIfSessionIsInactiveUseCase.execute(deviceInfo.lastSeenTs ?: 0)
DeviceFullInfo(deviceInfo, cryptoDeviceInfo, trustLevelForShield, isInactive) DeviceFullInfo(deviceInfo, cryptoDeviceInfo, roomEncryptionTrustLevel, isInactive)
} }
} }
} }

View File

@ -17,6 +17,7 @@
package im.vector.app.features.settings.devices.v2 package im.vector.app.features.settings.devices.v2
import im.vector.app.test.fakes.FakeActiveSessionHolder import im.vector.app.test.fakes.FakeActiveSessionHolder
import im.vector.app.test.fakes.FakeSession
import im.vector.app.test.test import im.vector.app.test.test
import im.vector.app.test.testDispatcher import im.vector.app.test.testDispatcher
import io.mockk.every import io.mockk.every
@ -30,11 +31,8 @@ import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.matrix.android.sdk.api.auth.data.SessionParams import org.matrix.android.sdk.api.auth.data.SessionParams
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
import org.matrix.android.sdk.api.util.toOptional import org.matrix.android.sdk.api.util.toOptional
import org.matrix.android.sdk.flow.FlowSession
import org.matrix.android.sdk.flow.flow
private const val A_DEVICE_ID = "device-id" private const val A_DEVICE_ID = "device-id"
@ -59,7 +57,7 @@ class GetCurrentSessionCrossSigningInfoUseCaseTest {
@Test @Test
fun `given the active session and existing cross signing info when getting these info then the result is correct`() = runTest(testDispatcher) { fun `given the active session and existing cross signing info when getting these info then the result is correct`() = runTest(testDispatcher) {
val fakeSession = givenSession(A_DEVICE_ID) val fakeSession = givenSession(A_DEVICE_ID)
val fakeFlowSession = givenFlowSession(fakeSession) val fakeFlowSession = fakeSession.givenFlowSession()
val isCrossSigningVerified = true val isCrossSigningVerified = true
val mxCrossSigningInfo = givenMxCrossSigningInfo(isCrossSigningVerified) val mxCrossSigningInfo = givenMxCrossSigningInfo(isCrossSigningVerified)
every { fakeFlowSession.liveCrossSigningInfo(any()) } returns flowOf(mxCrossSigningInfo.toOptional()) every { fakeFlowSession.liveCrossSigningInfo(any()) } returns flowOf(mxCrossSigningInfo.toOptional())
@ -80,7 +78,7 @@ class GetCurrentSessionCrossSigningInfoUseCaseTest {
@Test @Test
fun `given the active session and no existing cross signing info when getting these info then the result is correct`() = runTest(testDispatcher) { fun `given the active session and no existing cross signing info when getting these info then the result is correct`() = runTest(testDispatcher) {
val fakeSession = givenSession(A_DEVICE_ID) val fakeSession = givenSession(A_DEVICE_ID)
val fakeFlowSession = givenFlowSession(fakeSession) val fakeFlowSession = fakeSession.givenFlowSession()
val mxCrossSigningInfo = null val mxCrossSigningInfo = null
every { fakeFlowSession.liveCrossSigningInfo(any()) } returns flowOf(mxCrossSigningInfo.toOptional()) every { fakeFlowSession.liveCrossSigningInfo(any()) } returns flowOf(mxCrossSigningInfo.toOptional())
val expectedResult = CurrentSessionCrossSigningInfo( val expectedResult = CurrentSessionCrossSigningInfo(
@ -108,7 +106,7 @@ class GetCurrentSessionCrossSigningInfoUseCaseTest {
.finish() .finish()
} }
private fun givenSession(deviceId: String): Session { private fun givenSession(deviceId: String): FakeSession {
val sessionParams = mockk<SessionParams>() val sessionParams = mockk<SessionParams>()
every { sessionParams.deviceId } returns deviceId every { sessionParams.deviceId } returns deviceId
@ -118,12 +116,6 @@ class GetCurrentSessionCrossSigningInfoUseCaseTest {
return fakeSession return fakeSession
} }
private fun givenFlowSession(session: Session): FlowSession {
val fakeFlowSession = mockk<FlowSession>()
every { session.flow() } returns fakeFlowSession
return fakeFlowSession
}
private fun givenMxCrossSigningInfo(isTrusted: Boolean) = mockk<MXCrossSigningInfo>() private fun givenMxCrossSigningInfo(isTrusted: Boolean) = mockk<MXCrossSigningInfo>()
.also { .also {
every { it.isTrusted() } returns isTrusted every { it.isTrusted() } returns isTrusted

View File

@ -0,0 +1,182 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.features.settings.devices.v2
import im.vector.app.features.settings.devices.v2.list.CheckIfSessionIsInactiveUseCase
import im.vector.app.test.fakes.FakeActiveSessionHolder
import im.vector.app.test.test
import im.vector.app.test.testDispatcher
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.unmockkAll
import io.mockk.verify
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
private const val A_DEVICE_ID_1 = "device-id-1"
private const val A_DEVICE_ID_2 = "device-id-2"
private const val A_DEVICE_ID_3 = "device-id-3"
private const val A_TIMESTAMP_1 = 100L
private const val A_TIMESTAMP_2 = 200L
private const val A_TIMESTAMP_3 = 300L
class GetDeviceFullInfoListUseCaseTest {
private val fakeActiveSessionHolder = FakeActiveSessionHolder()
private val checkIfSessionIsInactiveUseCase = mockk<CheckIfSessionIsInactiveUseCase>()
private val getEncryptionTrustLevelForDeviceUseCase = mockk<GetEncryptionTrustLevelForDeviceUseCase>()
private val getCurrentSessionCrossSigningInfoUseCase = mockk<GetCurrentSessionCrossSigningInfoUseCase>()
private val getDeviceFullInfoListUseCase = GetDeviceFullInfoListUseCase(
activeSessionHolder = fakeActiveSessionHolder.instance,
checkIfSessionIsInactiveUseCase = checkIfSessionIsInactiveUseCase,
getEncryptionTrustLevelForDeviceUseCase = getEncryptionTrustLevelForDeviceUseCase,
getCurrentSessionCrossSigningInfoUseCase = getCurrentSessionCrossSigningInfoUseCase,
)
@Before
fun setUp() {
mockkStatic("org.matrix.android.sdk.flow.FlowSessionKt")
}
@After
fun tearDown() {
unmockkAll()
}
@Test
fun `given active session when getting list of device full info then the result list is correct and sorted in descending order`() = runTest(testDispatcher) {
// Given
val currentSessionCrossSigningInfo = givenCurrentSessionCrossSigningInfo()
val fakeFlowSession = fakeActiveSessionHolder.fakeSession.givenFlowSession()
val cryptoDeviceInfo1 = givenACryptoDeviceInfo(A_DEVICE_ID_1)
val cryptoDeviceInfo2 = givenACryptoDeviceInfo(A_DEVICE_ID_2)
val cryptoDeviceInfo3 = givenACryptoDeviceInfo(A_DEVICE_ID_3)
val cryptoDeviceInfoList = listOf(cryptoDeviceInfo1, cryptoDeviceInfo2, cryptoDeviceInfo3)
every { fakeFlowSession.liveUserCryptoDevices(any()) } returns flowOf(cryptoDeviceInfoList)
val deviceInfo1 = givenADevicesInfo(
deviceId = A_DEVICE_ID_1,
lastSeenTs = A_TIMESTAMP_1,
isInactive = true,
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted,
cryptoDeviceInfo = cryptoDeviceInfo1
)
val deviceInfo2 = givenADevicesInfo(
deviceId = A_DEVICE_ID_2,
lastSeenTs = A_TIMESTAMP_2,
isInactive = false,
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted,
cryptoDeviceInfo = cryptoDeviceInfo2
)
val deviceInfo3 = givenADevicesInfo(
deviceId = A_DEVICE_ID_3,
lastSeenTs = A_TIMESTAMP_3,
isInactive = false,
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Warning,
cryptoDeviceInfo = cryptoDeviceInfo3
)
val deviceInfoList = listOf(deviceInfo1, deviceInfo2, deviceInfo3)
every { fakeFlowSession.liveMyDevicesInfo() } returns flowOf(deviceInfoList)
val expectedResult1 = DeviceFullInfo(
deviceInfo = deviceInfo1,
cryptoDeviceInfo = cryptoDeviceInfo1,
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted,
isInactive = true
)
val expectedResult2 = DeviceFullInfo(
deviceInfo = deviceInfo2,
cryptoDeviceInfo = cryptoDeviceInfo2,
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted,
isInactive = false
)
val expectedResult3 = DeviceFullInfo(
deviceInfo = deviceInfo3,
cryptoDeviceInfo = cryptoDeviceInfo3,
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Warning,
isInactive = false
)
val expectedResult = listOf(expectedResult3, expectedResult2, expectedResult1)
// When
val result = getDeviceFullInfoListUseCase.execute()
.test(this)
// Then
result.assertValues(expectedResult)
.finish()
verify {
getCurrentSessionCrossSigningInfoUseCase.execute()
fakeFlowSession.liveUserCryptoDevices(fakeActiveSessionHolder.fakeSession.myUserId)
fakeFlowSession.liveMyDevicesInfo()
getEncryptionTrustLevelForDeviceUseCase.execute(currentSessionCrossSigningInfo, cryptoDeviceInfo1)
getEncryptionTrustLevelForDeviceUseCase.execute(currentSessionCrossSigningInfo, cryptoDeviceInfo2)
getEncryptionTrustLevelForDeviceUseCase.execute(currentSessionCrossSigningInfo, cryptoDeviceInfo3)
checkIfSessionIsInactiveUseCase.execute(A_TIMESTAMP_1)
checkIfSessionIsInactiveUseCase.execute(A_TIMESTAMP_2)
checkIfSessionIsInactiveUseCase.execute(A_TIMESTAMP_3)
}
}
@Test
fun `given no active session when getting list then the result is empty`() = runTest(testDispatcher) {
// Given
fakeActiveSessionHolder.givenGetSafeActiveSessionReturns(null)
// When
val result = getDeviceFullInfoListUseCase.execute()
.test(this)
// Then
result.assertNoValues()
.finish()
}
private fun givenCurrentSessionCrossSigningInfo(): CurrentSessionCrossSigningInfo {
val currentSessionCrossSigningInfo = mockk<CurrentSessionCrossSigningInfo>()
every { getCurrentSessionCrossSigningInfoUseCase.execute() } returns flowOf(currentSessionCrossSigningInfo)
return currentSessionCrossSigningInfo
}
private fun givenACryptoDeviceInfo(deviceId: String): CryptoDeviceInfo {
val cryptoDeviceInfo = mockk<CryptoDeviceInfo>()
every { cryptoDeviceInfo.deviceId } returns deviceId
return cryptoDeviceInfo
}
private fun givenADevicesInfo(
deviceId: String,
lastSeenTs: Long,
isInactive: Boolean,
roomEncryptionTrustLevel: RoomEncryptionTrustLevel,
cryptoDeviceInfo: CryptoDeviceInfo,
): DeviceInfo {
val deviceInfo = mockk<DeviceInfo>()
every { deviceInfo.deviceId } returns deviceId
every { deviceInfo.lastSeenTs } returns lastSeenTs
every { getEncryptionTrustLevelForDeviceUseCase.execute(any(), cryptoDeviceInfo) } returns roomEncryptionTrustLevel
every { checkIfSessionIsInactiveUseCase.execute(lastSeenTs) } returns isInactive
return deviceInfo
}
}

View File

@ -32,6 +32,8 @@ import org.matrix.android.sdk.api.session.getRoomSummary
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService
import org.matrix.android.sdk.api.session.profile.ProfileService import org.matrix.android.sdk.api.session.profile.ProfileService
import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.flow.FlowSession
import org.matrix.android.sdk.flow.flow
class FakeSession( class FakeSession(
val fakeCryptoService: FakeCryptoService = FakeCryptoService(), val fakeCryptoService: FakeCryptoService = FakeCryptoService(),
@ -76,6 +78,15 @@ class FakeSession(
every { this@FakeSession.sessionParams } returns sessionParams every { this@FakeSession.sessionParams } returns sessionParams
} }
/**
* Do not forget to call mockkStatic("org.matrix.android.sdk.flow.FlowSessionKt") in the setup method of the tests.
*/
fun givenFlowSession(): FlowSession {
val fakeFlowSession = mockk<FlowSession>()
every { flow() } returns fakeFlowSession
return fakeFlowSession
}
companion object { companion object {
fun withRoomSummary(roomSummary: RoomSummary) = FakeSession().apply { fun withRoomSummary(roomSummary: RoomSummary) = FakeSession().apply {