diff options
Diffstat (limited to 'android/app/src/test')
6 files changed, 31 insertions, 240 deletions
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/AccountExpiryNotificationProviderTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/AccountExpiryNotificationProviderTest.kt deleted file mode 100644 index 9a3672515d..0000000000 --- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/AccountExpiryNotificationProviderTest.kt +++ /dev/null @@ -1,213 +0,0 @@ -package net.mullvad.mullvadvpn - -import app.cash.turbine.test -import io.mockk.MockKAnnotations -import io.mockk.every -import io.mockk.mockk -import io.mockk.unmockkAll -import java.time.Duration -import java.time.ZonedDateTime -import kotlin.test.assertEquals -import kotlin.test.assertTrue -import kotlin.time.Duration.Companion.minutes -import kotlin.time.Duration.Companion.seconds -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.test.advanceTimeBy -import kotlinx.coroutines.test.runTest -import net.mullvad.mullvadvpn.lib.common.test.TestCoroutineRule -import net.mullvad.mullvadvpn.lib.model.AccountData -import net.mullvad.mullvadvpn.lib.model.DeviceState -import net.mullvad.mullvadvpn.lib.model.Notification -import net.mullvad.mullvadvpn.lib.model.NotificationChannelId -import net.mullvad.mullvadvpn.lib.model.NotificationUpdate -import net.mullvad.mullvadvpn.lib.model.NotificationUpdate.Cancel -import net.mullvad.mullvadvpn.lib.model.NotificationUpdate.Notify -import net.mullvad.mullvadvpn.lib.shared.AccountRepository -import net.mullvad.mullvadvpn.lib.shared.DeviceRepository -import net.mullvad.mullvadvpn.service.notifications.accountexpiry.ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD -import net.mullvad.mullvadvpn.service.notifications.accountexpiry.AccountExpiryNotificationProvider -import org.junit.jupiter.api.AfterEach -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith - -@ExperimentalCoroutinesApi -@ExtendWith(TestCoroutineRule::class) -class AccountExpiryNotificationProviderTest { - - private lateinit var provider: AccountExpiryNotificationProvider - - private val accountData = MutableStateFlow<AccountData?>(null) - private val deviceState = MutableStateFlow<DeviceState?>(null) - private val isNewDevice = MutableStateFlow(true) - - @BeforeEach - fun setup() { - MockKAnnotations.init(this) - - val accountRepository = mockk<AccountRepository>(relaxed = true) - every { accountRepository.accountData } returns accountData - every { accountRepository.isNewAccount } returns isNewDevice - - val deviceRepository = mockk<DeviceRepository>(relaxed = true) - every { deviceRepository.deviceState } returns deviceState - - provider = - AccountExpiryNotificationProvider( - channelId = NotificationChannelId("channelId"), - accountRepository = accountRepository, - deviceRepository = deviceRepository, - ) - - deviceState.value = DeviceState.LoggedIn(mockk(relaxed = true), mockk(relaxed = true)) - isNewDevice.value = false - } - - @AfterEach - fun teardown() { - unmockkAll() - } - - @Test - fun `should not emit notification in initial state`() = runTest { - accountData.value = null - deviceState.value = null - isNewDevice.value = true - provider.notifications.test { expectNoEvents() } - } - - @Test - fun `should emit notification if expiry time is shorter than expiry warning threshold`() = - runTest { - setExpiry( - ZonedDateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD).minusDays(1) - ) - provider.notifications.test { - assertTrue(awaitItem() is Notify) - expectNoEvents() - } - } - - @Test - fun `should emit cancel notification if user account is new`() = runTest { - isNewDevice.value = true - setExpiry(ZonedDateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD).minusDays(1)) - provider.notifications.test { - assertTrue(awaitItem() is Cancel) - expectNoEvents() - } - } - - @Test - fun `should emit cancel notification if user account is logged out`() = runTest { - setIsLoggedIn(false) - setExpiry(ZonedDateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD).minusDays(1)) - provider.notifications.test { - assertTrue(awaitItem() is Cancel) - expectNoEvents() - - setIsLoggedIn(true) - assertTrue(awaitItem() is Notify) - expectNoEvents() - - setIsLoggedIn(false) - assertTrue(awaitItem() is Cancel) - expectNoEvents() - } - } - - @Test - fun `should emit zero duration notification when remaining time runs out`() = runTest { - setExpiry(ZonedDateTime.now().plus(Duration.ofSeconds(60))) - provider.notifications.test { - assertTrue(awaitItem() is Notify) - expectNoEvents() - - advanceTimeBy(59.seconds) - expectNoEvents() - - advanceTimeBy(2.seconds) - val item = getAccountExpiry(awaitItem()) - assertEquals(item.durationUntilExpiry, Duration.ZERO) - expectNoEvents() - } - } - - @Test - fun `should emit notification when update interval is passed`() = runTest { - setExpiry( - ZonedDateTime.now() - .plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD) - .minusDays(1) - .plusHours(1) - ) - provider.notifications.test { - assertTrue(awaitItem() is Notify) - expectNoEvents() - - advanceTimeBy(59.minutes) - expectNoEvents() - - advanceTimeBy(1.minutes + 1.seconds) - assertTrue(awaitItem() is Notify) - expectNoEvents() - } - } - - @Test - fun `should cancel existing notification if more time is added to account`() = runTest { - setExpiry(ZonedDateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD).minusDays(1)) - provider.notifications.test { - assertTrue(awaitItem() is Notify) - expectNoEvents() - - setExpiry( - ZonedDateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD).plusDays(1) - ) - assertTrue(awaitItem() is Cancel) - expectNoEvents() - } - } - - @Test - fun `should not cancel existing notification if too little time is added`() = runTest { - setExpiry(ZonedDateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD).minusDays(1)) - provider.notifications.test { - assertTrue(awaitItem() is Notify) - expectNoEvents() - - setExpiry( - ZonedDateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD).minusHours(1) - ) - assertTrue(awaitItem() is Notify) - expectNoEvents() - } - } - - private fun getAccountExpiry( - awaitItem: NotificationUpdate<Notification.AccountExpiry> - ): Notification.AccountExpiry = - when (awaitItem) { - is Cancel -> error("expected AccountExpiry, was Cancel") - is Notify -> awaitItem.value - } - - private fun setExpiry(expiryDateTime: ZonedDateTime): ZonedDateTime { - val expiry = AccountData(mockk(relaxed = true), expiryDateTime) - accountData.value = expiry - return expiryDateTime - } - - private fun setIsLoggedIn(isLoggedIn: Boolean) { - deviceState.value = - if (isLoggedIn) { - DeviceState.LoggedIn( - accountNumber = mockk(relaxed = true), - device = mockk(relaxed = true), - ) - } else { - DeviceState.LoggedOut - } - } -} diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/data/Extensions.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/data/Extensions.kt new file mode 100644 index 0000000000..eb7a98ed8b --- /dev/null +++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/data/Extensions.kt @@ -0,0 +1,12 @@ +package net.mullvad.mullvadvpn.data + +import io.mockk.mockk +import java.time.ZonedDateTime +import net.mullvad.mullvadvpn.lib.model.AccountData + +fun AccountData.Companion.mock(expiry: ZonedDateTime): AccountData = + AccountData( + id = mockk(relaxed = true), + accountNumber = mockk(relaxed = true), + expiryDate = expiry, + ) diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/AccountExpiryInAppNotificationUseCaseTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/AccountExpiryInAppNotificationUseCaseTest.kt index df7d561f84..0557cc5786 100644 --- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/AccountExpiryInAppNotificationUseCaseTest.kt +++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/AccountExpiryInAppNotificationUseCaseTest.kt @@ -15,12 +15,13 @@ import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.runTest +import net.mullvad.mullvadvpn.data.mock import net.mullvad.mullvadvpn.lib.common.test.TestCoroutineRule import net.mullvad.mullvadvpn.lib.model.AccountData import net.mullvad.mullvadvpn.lib.model.InAppNotification import net.mullvad.mullvadvpn.lib.shared.AccountRepository import net.mullvad.mullvadvpn.service.notifications.accountexpiry.ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD -import net.mullvad.mullvadvpn.service.notifications.accountexpiry.ACCOUNT_EXPIRY_IN_APP_NOTIFICATION_UPDATE_INTERVAL +import net.mullvad.mullvadvpn.service.notifications.accountexpiry.ACCOUNT_EXPIRY_NOTIFICATION_UPDATE_INTERVAL import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -103,7 +104,7 @@ class AccountExpiryInAppNotificationUseCaseTest { // Set expiry to to be in the final update interval. val inLastUpdate = ZonedDateTime.now() - .plus(ACCOUNT_EXPIRY_IN_APP_NOTIFICATION_UPDATE_INTERVAL) + .plus(ACCOUNT_EXPIRY_NOTIFICATION_UPDATE_INTERVAL) .minusSeconds(1) val expiry = setExpiry(inLastUpdate) @@ -113,9 +114,9 @@ class AccountExpiryInAppNotificationUseCaseTest { expectNoEvents() // Advance past the delay before the while loop: - advanceTimeBy(ACCOUNT_EXPIRY_IN_APP_NOTIFICATION_UPDATE_INTERVAL.toMillis()) + advanceTimeBy(ACCOUNT_EXPIRY_NOTIFICATION_UPDATE_INTERVAL.toMillis()) // Advance past the delay after the while loop: - advanceTimeBy(ACCOUNT_EXPIRY_IN_APP_NOTIFICATION_UPDATE_INTERVAL.toMillis()) + advanceTimeBy(ACCOUNT_EXPIRY_NOTIFICATION_UPDATE_INTERVAL.toMillis()) assertEquals(Duration.ZERO, getExpiryNotificationDuration(expectMostRecentItem())) expectNoEvents() @@ -128,7 +129,7 @@ class AccountExpiryInAppNotificationUseCaseTest { } private fun setExpiry(expiryDateTime: ZonedDateTime): ZonedDateTime { - val expiry = AccountData(mockk(relaxed = true), expiryDateTime) + val expiry = AccountData.mock(expiryDateTime) accountExpiry.value = expiry return expiryDateTime } diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/OutOfTimeUseCaseTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/OutOfTimeUseCaseTest.kt index 4fd3ba08d1..0fd1563169 100644 --- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/OutOfTimeUseCaseTest.kt +++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/OutOfTimeUseCaseTest.kt @@ -20,6 +20,7 @@ import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.setMain +import net.mullvad.mullvadvpn.data.mock import net.mullvad.mullvadvpn.lib.model.AccountData import net.mullvad.mullvadvpn.lib.model.AuthFailedError import net.mullvad.mullvadvpn.lib.model.ErrorState @@ -90,8 +91,7 @@ class OutOfTimeUseCaseTest { fun `tunnel is connected should emit false`() = scope.runTest { // Arrange - val expiredAccountExpiry = - AccountData(mockk(relaxed = true), ZonedDateTime.now().plusDays(1)) + val expiredAccountExpiry = AccountData.mock(ZonedDateTime.now().plusDays(1)) val tunnelStateChanges = listOf( TunnelState.Disconnected(), @@ -119,8 +119,7 @@ class OutOfTimeUseCaseTest { fun `account expiry that has expired should emit true`() = scope.runTest { // Arrange - val expiredAccountExpiry = - AccountData(mockk(relaxed = true), ZonedDateTime.now().minusDays(1)) + val expiredAccountExpiry = AccountData.mock(ZonedDateTime.now().minusDays(1)) // Act, Assert outOfTimeUseCase.isOutOfTime.test { assertEquals(null, awaitItem()) @@ -133,8 +132,7 @@ class OutOfTimeUseCaseTest { fun `account expiry that has not expired should emit false`() = scope.runTest { // Arrange - val notExpiredAccountExpiry = - AccountData(mockk(relaxed = true), ZonedDateTime.now().plusDays(1)) + val notExpiredAccountExpiry = AccountData.mock(ZonedDateTime.now().plusDays(1)) // Act, Assert outOfTimeUseCase.isOutOfTime.test { @@ -148,8 +146,7 @@ class OutOfTimeUseCaseTest { fun `account that expires without new expiry event should emit true`() = scope.runTest { // Arrange - val expiredAccountExpiry = - AccountData(mockk(relaxed = true), ZonedDateTime.now().plusSeconds(100)) + val expiredAccountExpiry = AccountData.mock(ZonedDateTime.now().plusSeconds(100)) // Act, Assert outOfTimeUseCase.isOutOfTime.test { // Initial event @@ -172,10 +169,8 @@ class OutOfTimeUseCaseTest { fun `account that is about to expire but is refilled should emit false`() = scope.runTest { // Arrange - val initialAccountExpiry = - AccountData(mockk(relaxed = true), ZonedDateTime.now().plusSeconds(100)) - val updatedExpiry = - AccountData(mockk(relaxed = true), initialAccountExpiry.expiryDate.plusDays(30)) + val initialAccountExpiry = AccountData.mock(ZonedDateTime.now().plusSeconds(100)) + val updatedExpiry = AccountData.mock(initialAccountExpiry.expiryDate.plusDays(30)) // Act, Assert outOfTimeUseCase.isOutOfTime.test { @@ -202,10 +197,8 @@ class OutOfTimeUseCaseTest { fun `expired account that is refilled should emit false`() = scope.runTest { // Arrange - val initialAccountExpiry = - AccountData(mockk(relaxed = true), ZonedDateTime.now().plusSeconds(100)) - val updatedExpiry = - AccountData(mockk(relaxed = true), initialAccountExpiry.expiryDate.plusDays(30)) + val initialAccountExpiry = AccountData.mock(ZonedDateTime.now().plusSeconds(100)) + val updatedExpiry = AccountData.mock(initialAccountExpiry.expiryDate.plusDays(30)) // Act, Assert outOfTimeUseCase.isOutOfTime.test { // Initial event diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModelTest.kt index a2be07e0a6..eeb848dc14 100644 --- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModelTest.kt +++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModelTest.kt @@ -24,6 +24,7 @@ import net.mullvad.mullvadvpn.compose.state.LoginState.Idle import net.mullvad.mullvadvpn.compose.state.LoginState.Loading import net.mullvad.mullvadvpn.compose.state.LoginState.Success import net.mullvad.mullvadvpn.compose.state.LoginUiState +import net.mullvad.mullvadvpn.data.mock import net.mullvad.mullvadvpn.lib.common.test.TestCoroutineRule import net.mullvad.mullvadvpn.lib.model.AccountData import net.mullvad.mullvadvpn.lib.model.AccountNumber @@ -133,9 +134,7 @@ class LoginViewModelTest { val sideEffects = loginViewModel.uiSideEffect.testIn(backgroundScope) coEvery { mockedAccountRepository.login(any()) } returns Unit.right() coEvery { mockedAccountRepository.accountData } returns - MutableStateFlow( - AccountData(mockk(relaxed = true), ZonedDateTime.now().plusDays(3)) - ) + MutableStateFlow(AccountData.mock(ZonedDateTime.now().plusDays(3))) // Act, Assert uiStates.skipDefaultItem() diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModelTest.kt index a96d59361a..f753a2e613 100644 --- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModelTest.kt +++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModelTest.kt @@ -15,6 +15,7 @@ import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.runTest import net.mullvad.mullvadvpn.compose.state.WelcomeUiState +import net.mullvad.mullvadvpn.data.mock import net.mullvad.mullvadvpn.lib.common.test.TestCoroutineRule import net.mullvad.mullvadvpn.lib.model.AccountData import net.mullvad.mullvadvpn.lib.model.AccountNumber @@ -149,9 +150,7 @@ class WelcomeViewModelTest { @Test fun `when user has added time then uiSideEffect should emit OpenConnectScreen`() = runTest { // Arrange - accountExpiryStateFlow.emit( - AccountData(mockk(relaxed = true), ZonedDateTime.now().plusDays(1)) - ) + accountExpiryStateFlow.emit(AccountData.mock(ZonedDateTime.now().plusDays(1))) // Act, Assert viewModel.uiSideEffect.test { |
