diff options
| author | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2023-08-16 08:28:05 +0200 |
|---|---|---|
| committer | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2023-09-06 09:07:53 +0200 |
| commit | 8cfe2faac5a275de7a553ca26bee9e0ea58fd0f8 (patch) | |
| tree | bfd4aa86d1d40bb0d775bfcb239945621728f9b0 | |
| parent | 7e8158b02b5ba5af654c3d705d29dee1e65b74ef (diff) | |
| download | mullvadvpn-8cfe2faac5a275de7a553ca26bee9e0ea58fd0f8.tar.xz mullvadvpn-8cfe2faac5a275de7a553ca26bee9e0ea58fd0f8.zip | |
Add unit tests for notification state
| -rw-r--r-- | android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModelTest.kt | 153 |
1 files changed, 128 insertions, 25 deletions
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModelTest.kt index a621e80ff2..d8ec2b26f7 100644 --- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModelTest.kt +++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModelTest.kt @@ -2,6 +2,7 @@ package net.mullvad.mullvadvpn.viewmodel import androidx.lifecycle.viewModelScope import app.cash.turbine.test +import io.mockk.coEvery import io.mockk.every import io.mockk.mockk import io.mockk.mockkStatic @@ -9,26 +10,35 @@ import io.mockk.slot import io.mockk.unmockkAll import io.mockk.verify import kotlin.test.assertEquals +import kotlin.test.assertIs import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.runTest +import net.mullvad.mullvadvpn.compose.state.ConnectNotificationState import net.mullvad.mullvadvpn.compose.state.ConnectUiState import net.mullvad.mullvadvpn.lib.common.test.TestCoroutineRule +import net.mullvad.mullvadvpn.model.AccountExpiry import net.mullvad.mullvadvpn.model.GeoIpLocation import net.mullvad.mullvadvpn.model.TunnelState import net.mullvad.mullvadvpn.relaylist.RelayCountry import net.mullvad.mullvadvpn.relaylist.RelayItem +import net.mullvad.mullvadvpn.repository.AccountRepository import net.mullvad.mullvadvpn.ui.VersionInfo import net.mullvad.mullvadvpn.ui.serviceconnection.AppVersionInfoCache +import net.mullvad.mullvadvpn.ui.serviceconnection.AuthTokenCache import net.mullvad.mullvadvpn.ui.serviceconnection.ConnectionProxy import net.mullvad.mullvadvpn.ui.serviceconnection.LocationInfoCache import net.mullvad.mullvadvpn.ui.serviceconnection.RelayListListener import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionContainer import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionManager import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionState +import net.mullvad.mullvadvpn.ui.serviceconnection.authTokenCache import net.mullvad.mullvadvpn.ui.serviceconnection.connectionProxy import net.mullvad.mullvadvpn.util.appVersionCallbackFlow +import net.mullvad.talpid.tunnel.ErrorState import net.mullvad.talpid.util.EventNotifier +import org.joda.time.DateTime +import org.joda.time.ReadableInstant import org.junit.After import org.junit.Before import org.junit.Rule @@ -48,9 +58,10 @@ class ConnectViewModelTest { currentVersion = null, upgradeVersion = null, isOutdated = false, - isSupported = false + isSupported = true ) ) + private val accountExpiryState = MutableStateFlow<AccountExpiry>(AccountExpiry.Missing) // Service connections private val mockServiceConnectionContainer: ServiceConnectionContainer = mockk() @@ -60,6 +71,9 @@ class ConnectViewModelTest { private val mockConnectionProxy: ConnectionProxy = mockk() private val mockLocation: GeoIpLocation = mockk(relaxed = true) + // Account Repository + private val mockAccountRepository: AccountRepository = mockk() + // Captures private val locationSlot = slot<((GeoIpLocation?) -> Unit)>() private val relaySlot = slot<(List<RelayCountry>, RelayItem?) -> Unit>() @@ -84,6 +98,8 @@ class ConnectViewModelTest { every { mockServiceConnectionContainer.appVersionInfoCache } returns mockAppVersionInfoCache every { mockServiceConnectionContainer.connectionProxy } returns mockConnectionProxy + every { mockAccountRepository.accountExpiryState } returns accountExpiryState + every { mockConnectionProxy.onUiStateChange } returns eventNotifierTunnelUiState every { mockConnectionProxy.onStateChange } returns eventNotifierTunnelRealState @@ -94,7 +110,12 @@ class ConnectViewModelTest { every { mockRelayListListener.onRelayCountriesChange = capture(relaySlot) } answers {} every { mockAppVersionInfoCache.onUpdate = any() } answers {} - viewModel = ConnectViewModel(mockServiceConnectionManager) + viewModel = + ConnectViewModel( + serviceConnectionManager = mockServiceConnectionManager, + accountRepository = mockAccountRepository, + isVersionInfoNotificationEnabled = true + ) } @After @@ -160,29 +181,6 @@ class ConnectViewModelTest { } @Test - fun testAppVersionInfoUpdate() = - runTest(testCoroutineRule.testDispatcher) { - val versionInfoTestItem = - VersionInfo( - currentVersion = "1.0", - upgradeVersion = "2.0", - isOutdated = false, - isSupported = false - ) - - viewModel.uiState.test { - assertEquals(ConnectUiState.INITIAL, awaitItem()) - serviceConnectionState.value = - ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer) - locationSlot.captured.invoke(mockLocation) - relaySlot.captured.invoke(mockk(), mockk()) - versionInfo.value = versionInfoTestItem - val result = awaitItem() - assertEquals(versionInfoTestItem, result.versionInfo) - } - } - - @Test fun testRelayItemUpdate() = runTest(testCoroutineRule.testDispatcher) { val relayTestItem = @@ -258,6 +256,111 @@ class ConnectViewModelTest { verify { mockConnectionProxy.disconnect() } } + @Test + fun testBlockingNotificationState() = + runTest(testCoroutineRule.testDispatcher) { + // Arrange + val expectedConnectNotificationState = + ConnectNotificationState.ShowTunnelStateNotificationBlocked + val tunnelUiState = TunnelState.Connecting(null, null) + + // Act, Assert + viewModel.uiState.test { + assertEquals(ConnectUiState.INITIAL, awaitItem()) + serviceConnectionState.value = + ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer) + locationSlot.captured.invoke(mockLocation) + relaySlot.captured.invoke(mockk(), mockk()) + eventNotifierTunnelUiState.notify(tunnelUiState) + val result = awaitItem() + assertEquals(expectedConnectNotificationState, result.connectNotificationState) + } + } + + @Test + fun testErrorNotificationState() = + runTest(testCoroutineRule.testDispatcher) { + // Arrange + val mockErrorState: ErrorState = mockk() + val expectedConnectNotificationState = + ConnectNotificationState.ShowTunnelStateNotificationError(mockErrorState) + val tunnelUiState = TunnelState.Error(mockErrorState) + + // Act, Assert + viewModel.uiState.test { + assertEquals(ConnectUiState.INITIAL, awaitItem()) + serviceConnectionState.value = + ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer) + locationSlot.captured.invoke(mockLocation) + relaySlot.captured.invoke(mockk(), mockk()) + eventNotifierTunnelUiState.notify(tunnelUiState) + val result = awaitItem() + assertEquals(expectedConnectNotificationState, result.connectNotificationState) + } + } + + @Test + fun testVersionInfoNotificationState() = + runTest(testCoroutineRule.testDispatcher) { + // Arrange + val mockVersionInfo: VersionInfo = mockk() + val expectedConnectNotificationState = + ConnectNotificationState.ShowVersionInfoNotification(mockVersionInfo) + every { mockVersionInfo.isOutdated } returns true + + // Act, Assert + viewModel.uiState.test { + assertEquals(ConnectUiState.INITIAL, awaitItem()) + serviceConnectionState.value = + ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer) + locationSlot.captured.invoke(mockLocation) + relaySlot.captured.invoke(mockk(), mockk()) + versionInfo.value = mockVersionInfo + val result = awaitItem() + assertEquals(expectedConnectNotificationState, result.connectNotificationState) + } + } + + @Test + fun testAccountExpiryNotificationState() = + runTest(testCoroutineRule.testDispatcher) { + // Arrange + val mockDateTime: DateTime = mockk() + val expectedConnectNotificationState = + ConnectNotificationState.ShowAccountExpiryNotification(mockDateTime) + every { mockDateTime.isBefore(any<ReadableInstant>()) } returns true + + // Act, Assert + viewModel.uiState.test { + assertEquals(ConnectUiState.INITIAL, awaitItem()) + serviceConnectionState.value = + ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer) + locationSlot.captured.invoke(mockLocation) + relaySlot.captured.invoke(mockk(), mockk()) + accountExpiryState.value = AccountExpiry.Available(mockDateTime) + val result = awaitItem() + assertEquals(expectedConnectNotificationState, result.connectNotificationState) + } + } + + @Test + fun testOnShowAccountClick() = + runTest(testCoroutineRule.testDispatcher) { + // Arrange + val mockToken = "4444 5555 6666 7777" + val mockAuthTokenCache: AuthTokenCache = mockk(relaxed = true) + every { mockServiceConnectionManager.authTokenCache() } returns mockAuthTokenCache + coEvery { mockAuthTokenCache.fetchAuthToken() } returns mockToken + + // Act, Assert + viewModel.viewActions.test { + viewModel.onManageAccountClick() + val action = awaitItem() + assertIs<ConnectViewModel.ViewAction.OpenAccountManagementPageInBrowser>(action) + assertEquals(mockToken, action.token) + } + } + companion object { private const val CACHE_EXTENSION_CLASS = "net.mullvad.mullvadvpn.util.CacheExtensionsKt" private const val SERVICE_CONNECTION_MANAGER_EXTENSIONS = |
