summaryrefslogtreecommitdiffhomepage
path: root/android/app/src
diff options
context:
space:
mode:
authorJonatan Rhodin <jonatan.rhodin@mullvad.net>2023-05-30 13:05:30 +0200
committerJonatan Rhodin <jonatan.rhodin@mullvad.net>2023-06-07 17:51:06 +0200
commit6b1c918efc3cb0ef02d6e4e058d1dfe25dce7b33 (patch)
tree41feb4f2540d9e589cee8bbf1275269f6cb9ab44 /android/app/src
parent07f1ecbeb787ce59812b59c0b7974cfc40e73071 (diff)
downloadmullvadvpn-6b1c918efc3cb0ef02d6e4e058d1dfe25dce7b33.tar.xz
mullvadvpn-6b1c918efc3cb0ef02d6e4e058d1dfe25dce7b33.zip
Add tests for quantum resistant tunnel
Diffstat (limited to 'android/app/src')
-rw-r--r--android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/Finders.kt19
-rw-r--r--android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreenTest.kt69
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/BaseCell.kt9
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SelectableCell.kt6
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreen.kt4
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/test/ComposeTestTagConstants.kt2
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelTest.kt95
7 files changed, 200 insertions, 4 deletions
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/Finders.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/Finders.kt
new file mode 100644
index 0000000000..26ba0d5f4b
--- /dev/null
+++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/Finders.kt
@@ -0,0 +1,19 @@
+package net.mullvad.mullvadvpn
+
+import androidx.compose.ui.test.SemanticsNodeInteraction
+import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
+import androidx.compose.ui.test.hasAnyChild
+import androidx.compose.ui.test.hasTestTag
+import androidx.compose.ui.test.hasText
+
+fun SemanticsNodeInteractionsProvider.onNodeWithTagAndChildrenText(
+ testTag: String,
+ text: String,
+ substring: Boolean = false,
+ ignoreCase: Boolean = false,
+ useUnmergedTree: Boolean = false
+): SemanticsNodeInteraction =
+ onNode(
+ hasTestTag(testTag).and(hasAnyChild(hasText(text, substring, ignoreCase))),
+ useUnmergedTree
+ )
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreenTest.kt
index 046e773bc7..728dce08d9 100644
--- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreenTest.kt
+++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreenTest.kt
@@ -19,7 +19,11 @@ import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import net.mullvad.mullvadvpn.compose.state.VpnSettingsUiState
import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_LAST_ITEM_TEST_TAG
+import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_QUANTUM_ITEM_OFF_TEST_TAG
+import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_QUANTUM_ITEM_ON_TEST_TAG
import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_TEST_TAG
+import net.mullvad.mullvadvpn.model.QuantumResistantState
+import net.mullvad.mullvadvpn.onNodeWithTagAndChildrenText
import net.mullvad.mullvadvpn.viewmodel.CustomDnsItem
import net.mullvad.mullvadvpn.viewmodel.StagedDns
import org.junit.Before
@@ -563,6 +567,71 @@ class VpnSettingsScreenTest {
composeTestRule.onNodeWithText("Submit").assertIsNotEnabled()
}
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testShowSelectedTunnelQuantumOption() {
+ // Arrange
+ composeTestRule.setContent {
+ VpnSettingsScreen(
+ uiState =
+ VpnSettingsUiState.DefaultUiState(quantumResistant = QuantumResistantState.On),
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
+ )
+ }
+ composeTestRule
+ .onNodeWithTag(LAZY_LIST_TEST_TAG)
+ .performScrollToNode(hasTestTag(LAZY_LIST_QUANTUM_ITEM_OFF_TEST_TAG))
+
+ // Assert
+ composeTestRule
+ .onNodeWithTagAndChildrenText(testTag = LAZY_LIST_QUANTUM_ITEM_ON_TEST_TAG, text = "On")
+ .assertExists()
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testSelectTunnelQuantumOption() {
+ // Arrange
+ val mockSelectQuantumResistantSettingListener: (QuantumResistantState) -> Unit =
+ mockk(relaxed = true)
+ composeTestRule.setContent {
+ VpnSettingsScreen(
+ uiState =
+ VpnSettingsUiState.DefaultUiState(
+ quantumResistant = QuantumResistantState.Auto,
+ ),
+ onSelectQuantumResistanceSetting = mockSelectQuantumResistantSettingListener,
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
+ )
+ }
+ composeTestRule
+ .onNodeWithTag(LAZY_LIST_TEST_TAG)
+ .performScrollToNode(hasTestTag(LAZY_LIST_QUANTUM_ITEM_OFF_TEST_TAG))
+
+ // Assert
+ composeTestRule
+ .onNodeWithTagAndChildrenText(testTag = LAZY_LIST_QUANTUM_ITEM_ON_TEST_TAG, text = "On")
+ .performClick()
+ verify(exactly = 1) {
+ mockSelectQuantumResistantSettingListener.invoke(QuantumResistantState.On)
+ }
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testShowTunnelQuantumInfo() {
+ // Arrange
+ composeTestRule.setContent {
+ VpnSettingsScreen(
+ uiState = VpnSettingsUiState.QuantumResistanceInfoDialogUiState(),
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
+ )
+ }
+
+ // Assert
+ composeTestRule.onNodeWithText("Got it!").assertExists()
+ }
+
companion object {
private const val LOCAL_DNS_SERVER_WARNING =
"The local DNS server will not work unless you enable " +
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/BaseCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/BaseCell.kt
index 58ab44daaa..afc21a8e1f 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/BaseCell.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/BaseCell.kt
@@ -17,6 +17,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
@@ -62,9 +63,13 @@ internal fun BaseCell(
subtitleModifier: Modifier = Modifier,
background: Color = MaterialTheme.colorScheme.primary,
startPadding: Dp = Dimens.cellStartPadding,
- endPadding: Dp = Dimens.cellEndPadding
+ endPadding: Dp = Dimens.cellEndPadding,
+ testTag: String = ""
) {
- Column(modifier = Modifier.fillMaxWidth().wrapContentHeight().background(background)) {
+ Column(
+ modifier =
+ Modifier.fillMaxWidth().wrapContentHeight().background(background).testTag(testTag)
+ ) {
val rowModifier =
Modifier.let {
if (isRowEnabled) {
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SelectableCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SelectableCell.kt
index 95272acf11..e9ba569d47 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SelectableCell.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SelectableCell.kt
@@ -49,7 +49,8 @@ fun SelectableCell(
startPadding: Dp = Dimens.cellStartPadding,
selectedColor: Color = MaterialTheme.colorScheme.surface,
backgroundColor: Color = MaterialTheme.colorScheme.secondaryContainer,
- onCellClicked: () -> Unit = {}
+ onCellClicked: () -> Unit = {},
+ testTag: String = ""
) {
BaseCell(
onCellClicked = onCellClicked,
@@ -61,6 +62,7 @@ fun SelectableCell(
backgroundColor
},
startPadding = startPadding,
- iconView = selectedIcon
+ iconView = selectedIcon,
+ testTag = testTag
)
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreen.kt
index 805801946d..83e0ea5921 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreen.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreen.kt
@@ -68,6 +68,8 @@ import net.mullvad.mullvadvpn.compose.dialog.QuantumResistanceInfoDialog
import net.mullvad.mullvadvpn.compose.extensions.itemWithDivider
import net.mullvad.mullvadvpn.compose.state.VpnSettingsUiState
import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_LAST_ITEM_TEST_TAG
+import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_QUANTUM_ITEM_OFF_TEST_TAG
+import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_QUANTUM_ITEM_ON_TEST_TAG
import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_TEST_TAG
import net.mullvad.mullvadvpn.compose.theme.AppTheme
import net.mullvad.mullvadvpn.compose.theme.Dimens
@@ -407,6 +409,7 @@ fun VpnSettingsScreen(
itemWithDivider {
SelectableCell(
title = stringResource(id = R.string.on),
+ testTag = LAZY_LIST_QUANTUM_ITEM_ON_TEST_TAG,
isSelected = uiState.quantumResistant == QuantumResistantState.On,
onCellClicked = { onSelectQuantumResistanceSetting(QuantumResistantState.On) }
)
@@ -414,6 +417,7 @@ fun VpnSettingsScreen(
itemWithDivider {
SelectableCell(
title = stringResource(id = R.string.off),
+ testTag = LAZY_LIST_QUANTUM_ITEM_OFF_TEST_TAG,
isSelected = uiState.quantumResistant == QuantumResistantState.Off,
onCellClicked = { onSelectQuantumResistanceSetting(QuantumResistantState.Off) }
)
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/test/ComposeTestTagConstants.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/test/ComposeTestTagConstants.kt
index 55251eb3ea..7f79cdbe03 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/test/ComposeTestTagConstants.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/test/ComposeTestTagConstants.kt
@@ -2,3 +2,5 @@ package net.mullvad.mullvadvpn.compose.test
const val LAZY_LIST_TEST_TAG = "lazy_list_test_tag"
const val LAZY_LIST_LAST_ITEM_TEST_TAG = "lazy_list_last_item_test_tag"
+const val LAZY_LIST_QUANTUM_ITEM_OFF_TEST_TAG = "lazy_list_quantum_item_off_test_tag"
+const val LAZY_LIST_QUANTUM_ITEM_ON_TEST_TAG = "lazy_list_quantum_item_on_test_tag"
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelTest.kt
new file mode 100644
index 0000000000..4478964d02
--- /dev/null
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelTest.kt
@@ -0,0 +1,95 @@
+package net.mullvad.mullvadvpn.viewmodel
+
+import android.content.res.Resources
+import androidx.lifecycle.viewModelScope
+import app.cash.turbine.test
+import io.mockk.every
+import io.mockk.mockk
+import io.mockk.unmockkAll
+import io.mockk.verify
+import kotlin.test.assertEquals
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import net.mullvad.mullvadvpn.TestCoroutineRule
+import net.mullvad.mullvadvpn.model.QuantumResistantState
+import net.mullvad.mullvadvpn.model.Settings
+import net.mullvad.mullvadvpn.model.TunnelOptions
+import net.mullvad.mullvadvpn.model.WireguardTunnelOptions
+import net.mullvad.mullvadvpn.repository.SettingsRepository
+import org.apache.commons.validator.routines.InetAddressValidator
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+
+class VpnSettingsViewModelTest {
+ @get:Rule val testCoroutineRule = TestCoroutineRule()
+
+ private val mockSettingsRepository: SettingsRepository = mockk()
+ private val mockInetAddressValidator: InetAddressValidator = mockk()
+ private val mockResources: Resources = mockk()
+
+ private val mockSettingsUpdate = MutableStateFlow<Settings?>(null)
+
+ private lateinit var viewModel: VpnSettingsViewModel
+
+ @Before
+ fun setUp() {
+ every { mockSettingsRepository.settingsUpdates } returns mockSettingsUpdate
+
+ viewModel =
+ VpnSettingsViewModel(
+ repository = mockSettingsRepository,
+ inetAddressValidator = mockInetAddressValidator,
+ resources = mockResources,
+ dispatcher = UnconfinedTestDispatcher()
+ )
+ }
+
+ @After
+ fun tearDown() {
+ viewModel.viewModelScope.coroutineContext.cancel()
+ unmockkAll()
+ }
+
+ @Test
+ fun test_select_quantum_resistant_state_select() = runTest {
+ val quantumResistantState = QuantumResistantState.On
+ every {
+ mockSettingsRepository.setWireguardQuantumResistant(quantumResistantState)
+ } returns Unit
+ viewModel.onSelectQuantumResistanceSetting(quantumResistantState)
+ verify(exactly = 1) {
+ mockSettingsRepository.setWireguardQuantumResistant(quantumResistantState)
+ }
+ }
+
+ @Test
+ fun test_update_quantum_resistant_default_state() = runTest {
+ val expectedResistantState = QuantumResistantState.Off
+ viewModel.uiState.test {
+ assertEquals(expectedResistantState, awaitItem().quantumResistant)
+ }
+ }
+
+ @Test
+ fun test_update_quantum_resistant_update_state() = runTest {
+ val defaultResistantState = QuantumResistantState.Off
+ val expectedResistantState = QuantumResistantState.On
+ val mockSettings: Settings = mockk(relaxed = true)
+ val mockTunnelOptions: TunnelOptions = mockk(relaxed = true)
+ val mockWireguardTunnelOptions: WireguardTunnelOptions = mockk(relaxed = true)
+
+ every { mockSettings.tunnelOptions } returns mockTunnelOptions
+ every { mockTunnelOptions.wireguard } returns mockWireguardTunnelOptions
+ every { mockWireguardTunnelOptions.quantumResistant } returns expectedResistantState
+
+ viewModel.uiState.test {
+ assertEquals(defaultResistantState, awaitItem().quantumResistant)
+ mockSettingsUpdate.value = mockSettings
+ assertEquals(expectedResistantState, awaitItem().quantumResistant)
+ }
+ }
+}