summaryrefslogtreecommitdiffhomepage
path: root/android/app/src
diff options
context:
space:
mode:
Diffstat (limited to 'android/app/src')
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModelTest.kt222
1 files changed, 222 insertions, 0 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
new file mode 100644
index 0000000000..8c101e97a8
--- /dev/null
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModelTest.kt
@@ -0,0 +1,222 @@
+package net.mullvad.mullvadvpn.viewmodel
+
+import androidx.lifecycle.viewModelScope
+import app.cash.turbine.test
+import io.mockk.every
+import io.mockk.mockk
+import io.mockk.mockkStatic
+import io.mockk.slot
+import io.mockk.unmockkAll
+import kotlin.test.assertEquals
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.test.runTest
+import net.mullvad.mullvadvpn.TestCoroutineRule
+import net.mullvad.mullvadvpn.compose.state.ConnectUiState
+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.relaylist.RelayList
+import net.mullvad.mullvadvpn.ui.VersionInfo
+import net.mullvad.mullvadvpn.ui.serviceconnection.AppVersionInfoCache
+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.util.appVersionCallbackFlow
+import net.mullvad.talpid.util.EventNotifier
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+
+class ConnectViewModelTest {
+ @get:Rule val testCoroutineRule = TestCoroutineRule()
+
+ private val mockServiceConnectionManager: ServiceConnectionManager = mockk()
+ private lateinit var viewModel: ConnectViewModel
+
+ private val serviceConnectionState =
+ MutableStateFlow<ServiceConnectionState>(ServiceConnectionState.Disconnected)
+ private val versionInfo =
+ MutableStateFlow(
+ VersionInfo(
+ currentVersion = null,
+ upgradeVersion = null,
+ isOutdated = false,
+ isSupported = false
+ )
+ )
+
+ // Service connections
+ private val mockServiceConnectionContainer: ServiceConnectionContainer = mockk()
+ private val mockLocationInfoCache: LocationInfoCache = mockk(relaxUnitFun = true)
+ private val mockRelayListListener: RelayListListener = mockk(relaxUnitFun = true)
+ private lateinit var mockAppVersionInfoCache: AppVersionInfoCache
+ private val mockConnectionProxy: ConnectionProxy = mockk()
+
+ // Captures
+ private val locationSlot = slot<((GeoIpLocation?) -> Unit)>()
+ private val relaySlot = slot<(RelayList, RelayItem?) -> Unit>()
+
+ // Event notifiers
+ private val eventNotifierTunnelUiState = EventNotifier<TunnelState>(TunnelState.Disconnected)
+ private val eventNotifierTunnelRealState = EventNotifier<TunnelState>(TunnelState.Disconnected)
+
+ @Before
+ fun setup() {
+ mockkStatic(CACHE_EXTENSION_CLASS)
+
+ mockAppVersionInfoCache =
+ mockk<AppVersionInfoCache>().apply {
+ every { appVersionCallbackFlow() } returns versionInfo
+ }
+
+ every { mockServiceConnectionManager.connectionState } returns serviceConnectionState
+ every { mockServiceConnectionContainer.locationInfoCache } returns mockLocationInfoCache
+ every { mockServiceConnectionContainer.relayListListener } returns mockRelayListListener
+ every { mockServiceConnectionContainer.appVersionInfoCache } returns mockAppVersionInfoCache
+ every { mockServiceConnectionContainer.connectionProxy } returns mockConnectionProxy
+
+ every { mockConnectionProxy.onUiStateChange } returns eventNotifierTunnelUiState
+ every { mockConnectionProxy.onStateChange } returns eventNotifierTunnelRealState
+ // Listeners
+ every { mockLocationInfoCache.onNewLocation = capture(locationSlot) } answers {}
+ every { mockRelayListListener.onRelayListChange = capture(relaySlot) } answers {}
+ every { mockAppVersionInfoCache.onUpdate = any() } answers {}
+
+ viewModel = ConnectViewModel(mockServiceConnectionManager)
+ }
+
+ @After
+ fun teardown() {
+ viewModel.viewModelScope.coroutineContext.cancel()
+ unmockkAll()
+ }
+
+ @Test
+ fun testInitialState() = runTest {
+ viewModel.uiState.test { assertEquals(ConnectUiState.INITIAL, awaitItem()) }
+ }
+
+ @Test
+ fun testTunnelInfoExpandedUpdate() =
+ runTest(testCoroutineRule.testDispatcher) {
+ val expectedResult = true
+
+ viewModel.uiState.test {
+ assertEquals(ConnectUiState.INITIAL, awaitItem())
+ serviceConnectionState.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+ locationSlot.captured.invoke(mockk())
+ relaySlot.captured.invoke(mockk(), mockk())
+ viewModel.toggleTunnelInfoExpansion()
+ val result = awaitItem()
+ assertEquals(expectedResult, result.isTunnelInfoExpanded)
+ }
+ }
+
+ @Test
+ fun testTunnelRealStateUpdate() =
+ runTest(testCoroutineRule.testDispatcher) {
+ val tunnelRealStateTestItem = TunnelState.Connected(mockk(), mockk())
+
+ viewModel.uiState.test {
+ assertEquals(ConnectUiState.INITIAL, awaitItem())
+ serviceConnectionState.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+ locationSlot.captured.invoke(mockk())
+ relaySlot.captured.invoke(mockk(), mockk())
+ eventNotifierTunnelRealState.notify(tunnelRealStateTestItem)
+ val result = awaitItem()
+ assertEquals(tunnelRealStateTestItem, result.tunnelRealState)
+ }
+ }
+
+ @Test
+ fun testTunnelUiStateUpdate() =
+ runTest(testCoroutineRule.testDispatcher) {
+ val tunnelUiStateTestItem = TunnelState.Connected(mockk(), mockk())
+
+ viewModel.uiState.test {
+ assertEquals(ConnectUiState.INITIAL, awaitItem())
+ serviceConnectionState.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+ locationSlot.captured.invoke(mockk())
+ relaySlot.captured.invoke(mockk(), mockk())
+ eventNotifierTunnelUiState.notify(tunnelUiStateTestItem)
+ val result = awaitItem()
+ assertEquals(tunnelUiStateTestItem, result.tunnelUiState)
+ }
+ }
+
+ @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(mockk())
+ relaySlot.captured.invoke(mockk(), mockk())
+ versionInfo.value = versionInfoTestItem
+ val result = awaitItem()
+ assertEquals(versionInfoTestItem, result.versionInfo)
+ }
+ }
+
+ @Test
+ fun testRelayItemUpdate() =
+ runTest(testCoroutineRule.testDispatcher) {
+ val relayTestItem =
+ RelayCountry(name = "Name", code = "Code", expanded = false, cities = emptyList())
+
+ viewModel.uiState.test {
+ assertEquals(ConnectUiState.INITIAL, awaitItem())
+ serviceConnectionState.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+ locationSlot.captured.invoke(mockk())
+ relaySlot.captured.invoke(mockk(), relayTestItem)
+ val result = awaitItem()
+ assertEquals(relayTestItem, result.relayLocation)
+ }
+ }
+
+ @Test
+ fun testLocationUpdate() =
+ runTest(testCoroutineRule.testDispatcher) {
+ val locationTestItem =
+ GeoIpLocation(
+ ipv4 = mockk(),
+ ipv6 = mockk(),
+ country = "Sweden",
+ city = "Gothenburg",
+ hostname = "Host"
+ )
+
+ viewModel.uiState.test {
+ assertEquals(ConnectUiState.INITIAL, awaitItem())
+ serviceConnectionState.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+ locationSlot.captured.invoke(locationTestItem)
+ relaySlot.captured.invoke(mockk(), mockk())
+ val result = awaitItem()
+ assertEquals(locationTestItem, result.location)
+ }
+ }
+
+ companion object {
+ private const val CACHE_EXTENSION_CLASS = "net.mullvad.mullvadvpn.util.CacheExtensionsKt"
+ }
+}