Skip to content

Commit

Permalink
Fix and add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Rawa committed Oct 13, 2023
1 parent 3eddf61 commit 8fa9266
Show file tree
Hide file tree
Showing 9 changed files with 554 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import io.mockk.verify
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import net.mullvad.mullvadvpn.compose.state.ConnectNotificationState
import net.mullvad.mullvadvpn.compose.state.ConnectUiState
import net.mullvad.mullvadvpn.compose.test.CIRCULAR_PROGRESS_INDICATOR
import net.mullvad.mullvadvpn.compose.test.CONNECT_BUTTON_TEST_TAG
Expand All @@ -24,6 +23,7 @@ import net.mullvad.mullvadvpn.compose.test.SELECT_LOCATION_BUTTON_TEST_TAG
import net.mullvad.mullvadvpn.model.GeoIpLocation
import net.mullvad.mullvadvpn.model.TunnelState
import net.mullvad.mullvadvpn.relaylist.RelayItem
import net.mullvad.mullvadvpn.repository.InAppNotification
import net.mullvad.mullvadvpn.ui.VersionInfo
import net.mullvad.mullvadvpn.viewmodel.ConnectViewModel
import net.mullvad.talpid.net.TransportProtocol
Expand Down Expand Up @@ -85,8 +85,7 @@ class ConnectScreenTest {
isTunnelInfoExpanded = false,
deviceName = "",
daysLeftUntilExpiry = null,
connectNotificationState =
ConnectNotificationState.ShowTunnelStateNotificationBlocked
inAppNotification = InAppNotification.TunnelStateBlocked
),
uiSideEffect = MutableSharedFlow<ConnectViewModel.UiSideEffect>().asSharedFlow()
)
Expand Down Expand Up @@ -122,8 +121,7 @@ class ConnectScreenTest {
isTunnelInfoExpanded = false,
deviceName = "",
daysLeftUntilExpiry = null,
connectNotificationState =
ConnectNotificationState.ShowTunnelStateNotificationBlocked
inAppNotification = InAppNotification.TunnelStateBlocked
),
uiSideEffect = MutableSharedFlow<ConnectViewModel.UiSideEffect>().asSharedFlow()
)
Expand Down Expand Up @@ -157,7 +155,7 @@ class ConnectScreenTest {
isTunnelInfoExpanded = false,
deviceName = "",
daysLeftUntilExpiry = null,
connectNotificationState = ConnectNotificationState.HideNotification
inAppNotification = null
),
uiSideEffect = MutableSharedFlow<ConnectViewModel.UiSideEffect>().asSharedFlow()
)
Expand Down Expand Up @@ -190,7 +188,7 @@ class ConnectScreenTest {
isTunnelInfoExpanded = false,
deviceName = "",
daysLeftUntilExpiry = null,
connectNotificationState = ConnectNotificationState.HideNotification
inAppNotification = null
),
uiSideEffect = MutableSharedFlow<ConnectViewModel.UiSideEffect>().asSharedFlow()
)
Expand Down Expand Up @@ -224,7 +222,7 @@ class ConnectScreenTest {
isTunnelInfoExpanded = false,
deviceName = "",
daysLeftUntilExpiry = null,
connectNotificationState = ConnectNotificationState.HideNotification
inAppNotification = null
),
uiSideEffect = MutableSharedFlow<ConnectViewModel.UiSideEffect>().asSharedFlow()
)
Expand Down Expand Up @@ -258,7 +256,7 @@ class ConnectScreenTest {
isTunnelInfoExpanded = false,
deviceName = "",
daysLeftUntilExpiry = null,
connectNotificationState = ConnectNotificationState.HideNotification
inAppNotification = null
),
uiSideEffect = MutableSharedFlow<ConnectViewModel.UiSideEffect>().asSharedFlow()
)
Expand Down Expand Up @@ -294,8 +292,8 @@ class ConnectScreenTest {
isTunnelInfoExpanded = false,
deviceName = "",
daysLeftUntilExpiry = null,
connectNotificationState =
ConnectNotificationState.ShowTunnelStateNotificationError(
inAppNotification =
InAppNotification.TunnelStateError(
ErrorState(ErrorStateCause.StartTunnelError, true)
)
),
Expand Down Expand Up @@ -334,9 +332,9 @@ class ConnectScreenTest {
isTunnelInfoExpanded = false,
deviceName = "",
daysLeftUntilExpiry = null,
connectNotificationState =
ConnectNotificationState.ShowTunnelStateNotificationError(
ErrorState(ErrorStateCause.StartTunnelError, false)
inAppNotification =
InAppNotification.TunnelStateError(
ErrorState(ErrorStateCause.StartTunnelError, true)
)
),
uiSideEffect = MutableSharedFlow<ConnectViewModel.UiSideEffect>().asSharedFlow()
Expand Down Expand Up @@ -371,8 +369,7 @@ class ConnectScreenTest {
isTunnelInfoExpanded = false,
deviceName = "",
daysLeftUntilExpiry = null,
connectNotificationState =
ConnectNotificationState.ShowTunnelStateNotificationBlocked
inAppNotification = InAppNotification.TunnelStateBlocked
),
uiSideEffect = MutableSharedFlow<ConnectViewModel.UiSideEffect>().asSharedFlow()
)
Expand Down Expand Up @@ -408,8 +405,7 @@ class ConnectScreenTest {
isTunnelInfoExpanded = false,
deviceName = "",
daysLeftUntilExpiry = null,
connectNotificationState =
ConnectNotificationState.ShowTunnelStateNotificationBlocked
inAppNotification = InAppNotification.TunnelStateBlocked
),
uiSideEffect = MutableSharedFlow<ConnectViewModel.UiSideEffect>().asSharedFlow()
)
Expand Down Expand Up @@ -445,7 +441,7 @@ class ConnectScreenTest {
isTunnelInfoExpanded = false,
deviceName = "",
daysLeftUntilExpiry = null,
connectNotificationState = ConnectNotificationState.HideNotification
inAppNotification = null
),
uiSideEffect = MutableSharedFlow<ConnectViewModel.UiSideEffect>().asSharedFlow(),
onSwitchLocationClick = mockedClickHandler
Expand Down Expand Up @@ -478,7 +474,7 @@ class ConnectScreenTest {
isTunnelInfoExpanded = false,
deviceName = "",
daysLeftUntilExpiry = null,
connectNotificationState = ConnectNotificationState.HideNotification
inAppNotification = null
),
uiSideEffect = MutableSharedFlow<ConnectViewModel.UiSideEffect>().asSharedFlow(),
onDisconnectClick = mockedClickHandler
Expand Down Expand Up @@ -511,7 +507,7 @@ class ConnectScreenTest {
isTunnelInfoExpanded = false,
deviceName = "",
daysLeftUntilExpiry = null,
connectNotificationState = ConnectNotificationState.HideNotification
inAppNotification = null
),
uiSideEffect = MutableSharedFlow<ConnectViewModel.UiSideEffect>().asSharedFlow(),
onReconnectClick = mockedClickHandler
Expand Down Expand Up @@ -543,7 +539,7 @@ class ConnectScreenTest {
isTunnelInfoExpanded = false,
deviceName = "",
daysLeftUntilExpiry = null,
connectNotificationState = ConnectNotificationState.HideNotification
inAppNotification = null
),
uiSideEffect = MutableSharedFlow<ConnectViewModel.UiSideEffect>().asSharedFlow(),
onConnectClick = mockedClickHandler
Expand Down Expand Up @@ -575,7 +571,7 @@ class ConnectScreenTest {
isTunnelInfoExpanded = false,
deviceName = "",
daysLeftUntilExpiry = null,
connectNotificationState = ConnectNotificationState.HideNotification
inAppNotification = null
),
uiSideEffect = MutableSharedFlow<ConnectViewModel.UiSideEffect>().asSharedFlow(),
onCancelClick = mockedClickHandler
Expand Down Expand Up @@ -608,7 +604,7 @@ class ConnectScreenTest {
isTunnelInfoExpanded = false,
deviceName = "",
daysLeftUntilExpiry = null,
connectNotificationState = ConnectNotificationState.HideNotification
inAppNotification = null
),
uiSideEffect = MutableSharedFlow<ConnectViewModel.UiSideEffect>().asSharedFlow(),
onToggleTunnelInfo = mockedClickHandler
Expand Down Expand Up @@ -648,7 +644,7 @@ class ConnectScreenTest {
isTunnelInfoExpanded = true,
deviceName = "",
daysLeftUntilExpiry = null,
connectNotificationState = ConnectNotificationState.HideNotification
inAppNotification = null
),
uiSideEffect = MutableSharedFlow<ConnectViewModel.UiSideEffect>().asSharedFlow()
)
Expand Down Expand Up @@ -687,8 +683,7 @@ class ConnectScreenTest {
isTunnelInfoExpanded = false,
deviceName = "",
daysLeftUntilExpiry = null,
connectNotificationState =
ConnectNotificationState.ShowVersionInfoNotification(versionInfo)
inAppNotification = InAppNotification.UpdateAvailable(versionInfo)
),
uiSideEffect = MutableSharedFlow<ConnectViewModel.UiSideEffect>().asSharedFlow()
)
Expand Down Expand Up @@ -725,8 +720,7 @@ class ConnectScreenTest {
isTunnelInfoExpanded = false,
deviceName = "",
daysLeftUntilExpiry = null,
connectNotificationState =
ConnectNotificationState.ShowVersionInfoNotification(versionInfo)
inAppNotification = InAppNotification.UnsupportedVersion(versionInfo)
),
uiSideEffect = MutableSharedFlow<ConnectViewModel.UiSideEffect>().asSharedFlow()
)
Expand Down Expand Up @@ -758,10 +752,9 @@ class ConnectScreenTest {
outAddress = "",
showLocation = false,
isTunnelInfoExpanded = false,
deviceName = null,
deviceName = "",
daysLeftUntilExpiry = null,
connectNotificationState =
ConnectNotificationState.ShowAccountExpiryNotification(expiryDate)
inAppNotification = InAppNotification.AccountExpiry(expiryDate)
),
uiSideEffect = MutableSharedFlow<ConnectViewModel.UiSideEffect>().asSharedFlow()
)
Expand Down Expand Up @@ -800,8 +793,7 @@ class ConnectScreenTest {
isTunnelInfoExpanded = false,
deviceName = "",
daysLeftUntilExpiry = null,
connectNotificationState =
ConnectNotificationState.ShowVersionInfoNotification(versionInfo)
inAppNotification = InAppNotification.UnsupportedVersion(versionInfo)
),
uiSideEffect = MutableSharedFlow<ConnectViewModel.UiSideEffect>().asSharedFlow()
)
Expand Down Expand Up @@ -834,8 +826,7 @@ class ConnectScreenTest {
isTunnelInfoExpanded = false,
deviceName = "",
daysLeftUntilExpiry = null,
connectNotificationState =
ConnectNotificationState.ShowAccountExpiryNotification(expiryDate)
inAppNotification = InAppNotification.AccountExpiry(expiryDate)
),
uiSideEffect = MutableSharedFlow<ConnectViewModel.UiSideEffect>().asSharedFlow()
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package net.mullvad.mullvadvpn.usecase

import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import net.mullvad.mullvadvpn.repository.DeviceRepository
import net.mullvad.mullvadvpn.repository.InAppNotification

class NewDeviceNotificationUseCase(private val deviceRepository: DeviceRepository) {
private val _mutableShowNewDeviceNotification = MutableStateFlow(false)

fun notifications() =
combine(
deviceRepository.deviceState.map { it.deviceName() }.distinctUntilChanged(),
_mutableShowNewDeviceNotification
) { deviceName, newDeviceCreated ->
if (newDeviceCreated && deviceName != null) {
InAppNotification.NewDevice(deviceName)
} else null
}
.map(::listOfNotNull)
.distinctUntilChanged()

fun newDeviceCreated() {
_mutableShowNewDeviceNotification.value = true
}

fun clearNewDeviceCreatedNotification() {
_mutableShowNewDeviceNotification.value = false
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
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 kotlin.test.assertEquals
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.runTest
import net.mullvad.mullvadvpn.lib.common.test.TestCoroutineRule
import net.mullvad.mullvadvpn.repository.InAppNotification
import net.mullvad.mullvadvpn.repository.InAppNotificationController
import net.mullvad.mullvadvpn.usecase.AccountExpiryNotificationUseCase
import net.mullvad.mullvadvpn.usecase.NewDeviceNotificationUseCase
import net.mullvad.mullvadvpn.usecase.TunnelStateNotificationUseCase
import net.mullvad.mullvadvpn.usecase.VersionNotificationUseCase
import net.mullvad.talpid.tunnel.ErrorState
import org.joda.time.DateTime
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test

class InAppNotificationControllerTest {
@get:Rule val testCoroutineRule = TestCoroutineRule()

private lateinit var inAppNotificationController: InAppNotificationController
private val accountExpiryNotifications = MutableStateFlow(emptyList<InAppNotification>())
private val newDeviceNotifications = MutableStateFlow(emptyList<InAppNotification.NewDevice>())
private val versionNotifications = MutableStateFlow(emptyList<InAppNotification>())
private val tunnelStateNotifications = MutableStateFlow(emptyList<InAppNotification>())

private lateinit var job: Job

@Before
fun setup() {
MockKAnnotations.init(this)

val accountExpiryNotificationUseCase: AccountExpiryNotificationUseCase = mockk()
val newDeviceNotificationUseCase: NewDeviceNotificationUseCase = mockk()
val versionNotificationUseCase: VersionNotificationUseCase = mockk()
val tunnelStateNotificationUseCase: TunnelStateNotificationUseCase = mockk()
every { accountExpiryNotificationUseCase.notifications() } returns
accountExpiryNotifications
every { newDeviceNotificationUseCase.notifications() } returns newDeviceNotifications
every { versionNotificationUseCase.notifications() } returns versionNotifications
every { tunnelStateNotificationUseCase.notifications() } returns tunnelStateNotifications
job = Job()

inAppNotificationController =
InAppNotificationController(
accountExpiryNotificationUseCase,
newDeviceNotificationUseCase,
versionNotificationUseCase,
tunnelStateNotificationUseCase,
CoroutineScope(job + testCoroutineRule.testDispatcher)
)
}

@After
fun teardown() {
job.cancel()
unmockkAll()
}

@Test
fun `ensure all notifications have the right priority`() = runTest {
val newDevice = InAppNotification.NewDevice("")
newDeviceNotifications.value = listOf(newDevice)

val errorState: ErrorState = mockk()
val tunnelStateBlocked = InAppNotification.TunnelStateBlocked
val tunnelStateError = InAppNotification.TunnelStateError(errorState)
tunnelStateNotifications.value = listOf(tunnelStateBlocked, tunnelStateError)

val unsupportedVersion = InAppNotification.UnsupportedVersion(mockk())
val updateAvailable = InAppNotification.UpdateAvailable(mockk())
versionNotifications.value = listOf(unsupportedVersion, updateAvailable)

val accountExpiry = InAppNotification.AccountExpiry(DateTime.now())
accountExpiryNotifications.value = listOf(accountExpiry)

inAppNotificationController.notifications.test {
val notifications = awaitItem()

assertEquals(
listOf(
tunnelStateError,
tunnelStateBlocked,
unsupportedVersion,
accountExpiry,
newDevice,
updateAvailable,
),
notifications
)
}
}
}
Loading

0 comments on commit 8fa9266

Please sign in to comment.