diff options
| author | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2023-05-30 13:05:30 +0200 |
|---|---|---|
| committer | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2023-06-07 17:51:06 +0200 |
| commit | 6b1c918efc3cb0ef02d6e4e058d1dfe25dce7b33 (patch) | |
| tree | 41feb4f2540d9e589cee8bbf1275269f6cb9ab44 /android/app/src | |
| parent | 07f1ecbeb787ce59812b59c0b7974cfc40e73071 (diff) | |
| download | mullvadvpn-6b1c918efc3cb0ef02d6e4e058d1dfe25dce7b33.tar.xz mullvadvpn-6b1c918efc3cb0ef02d6e4e058d1dfe25dce7b33.zip | |
Add tests for quantum resistant tunnel
Diffstat (limited to 'android/app/src')
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) + } + } +} |
