diff options
| author | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2025-08-04 17:04:50 +0200 |
|---|---|---|
| committer | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2025-08-08 13:04:00 +0200 |
| commit | b82153a408f035155c5a26fb68fcaa09e428ca2c (patch) | |
| tree | eb8e89e724ea6ca5403c1c38dce4eb846702e823 /android/app/src/test | |
| parent | 6dee63b6cb3e7dbf9e0d6c77d20a3a6e0dba0de1 (diff) | |
| download | mullvadvpn-b82153a408f035155c5a26fb68fcaa09e428ca2c.tar.xz mullvadvpn-b82153a408f035155c5a26fb68fcaa09e428ca2c.zip | |
Replace select hop code with use cases
Also split the select hop code into select hop and modify multihop
Refactor relay list type
Diffstat (limited to 'android/app/src/test')
5 files changed, 67 insertions, 57 deletions
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/FilterChipUseCaseTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/FilterChipUseCaseTest.kt index ad1bc41a1b..69d40103a7 100644 --- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/FilterChipUseCaseTest.kt +++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/FilterChipUseCaseTest.kt @@ -5,6 +5,7 @@ import io.mockk.every import io.mockk.mockk import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.runTest +import net.mullvad.mullvadvpn.compose.state.MultihopRelayListType import net.mullvad.mullvadvpn.compose.state.RelayListType import net.mullvad.mullvadvpn.lib.common.test.assertLists import net.mullvad.mullvadvpn.lib.model.Constraint @@ -12,10 +13,8 @@ import net.mullvad.mullvadvpn.lib.model.Ownership import net.mullvad.mullvadvpn.lib.model.ProviderId import net.mullvad.mullvadvpn.lib.model.Providers import net.mullvad.mullvadvpn.lib.model.Settings -import net.mullvad.mullvadvpn.lib.model.WireguardConstraints import net.mullvad.mullvadvpn.repository.RelayListFilterRepository import net.mullvad.mullvadvpn.repository.SettingsRepository -import net.mullvad.mullvadvpn.repository.WireguardConstraintsRepository import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -24,13 +23,11 @@ class FilterChipUseCaseTest { private val mockRelayListFilterRepository: RelayListFilterRepository = mockk() private val mockProviderToOwnershipsUseCase: ProviderToOwnershipsUseCase = mockk() private val mockSettingRepository: SettingsRepository = mockk() - private val mockWireguardConstraintsRepository: WireguardConstraintsRepository = mockk() private val selectedOwnership = MutableStateFlow<Constraint<Ownership>>(Constraint.Any) private val selectedProviders = MutableStateFlow<Constraint<Providers>>(Constraint.Any) private val providerToOwnerships = MutableStateFlow<Map<ProviderId, Set<Ownership>>>(emptyMap()) private val settings = MutableStateFlow<Settings>(mockk(relaxed = true)) - private val wireguardConstraints = MutableStateFlow<WireguardConstraints>(mockk(relaxed = true)) private lateinit var filterChipUseCase: FilterChipUseCase @@ -40,21 +37,18 @@ class FilterChipUseCaseTest { every { mockRelayListFilterRepository.selectedProviders } returns selectedProviders every { mockProviderToOwnershipsUseCase() } returns providerToOwnerships every { mockSettingRepository.settingsUpdates } returns settings - every { mockWireguardConstraintsRepository.wireguardConstraints } returns - wireguardConstraints filterChipUseCase = FilterChipUseCase( relayListFilterRepository = mockRelayListFilterRepository, providerToOwnershipsUseCase = mockProviderToOwnershipsUseCase, settingsRepository = mockSettingRepository, - wireguardConstraintsRepository = mockWireguardConstraintsRepository, ) } @Test fun `when no filters are applied should return empty list`() = runTest { - filterChipUseCase(RelayListType.EXIT).test { assertLists(emptyList(), awaitItem()) } + filterChipUseCase(RelayListType.Single).test { assertLists(emptyList(), awaitItem()) } } @Test @@ -63,7 +57,7 @@ class FilterChipUseCaseTest { val expectedOwnership = Ownership.MullvadOwned selectedOwnership.value = Constraint.Only(expectedOwnership) - filterChipUseCase(RelayListType.EXIT).test { + filterChipUseCase(RelayListType.Single).test { assertLists(listOf(FilterChip.Ownership(expectedOwnership)), awaitItem()) } } @@ -79,7 +73,7 @@ class FilterChipUseCaseTest { ProviderId("2") to setOf(Ownership.Rented), ) - filterChipUseCase(RelayListType.EXIT).test { + filterChipUseCase(RelayListType.Single).test { assertLists(listOf(FilterChip.Provider(2)), awaitItem()) } } @@ -98,7 +92,7 @@ class FilterChipUseCaseTest { ProviderId("2") to setOf(Ownership.Rented), ) - filterChipUseCase(RelayListType.EXIT).test { + filterChipUseCase(RelayListType.Single).test { assertLists( listOf(FilterChip.Ownership(expectedOwnership), FilterChip.Provider(1)), awaitItem(), @@ -115,10 +109,8 @@ class FilterChipUseCaseTest { every { this@mockk.tunnelOptions.wireguard.daitaSettings.enabled } returns true every { tunnelOptions.wireguard.daitaSettings.directOnly } returns true } - wireguardConstraints.value = - mockk(relaxed = true) { every { isMultihopEnabled } returns false } - filterChipUseCase(RelayListType.EXIT).test { + filterChipUseCase(RelayListType.Single).test { assertLists(listOf(FilterChip.Daita), awaitItem()) } } @@ -132,14 +124,12 @@ class FilterChipUseCaseTest { every { tunnelOptions.wireguard.daitaSettings.enabled } returns true every { tunnelOptions.wireguard.daitaSettings.directOnly } returns false } - wireguardConstraints.value = - mockk(relaxed = true) { every { isMultihopEnabled } returns false } - filterChipUseCase(RelayListType.EXIT).test { assertLists(emptyList(), awaitItem()) } + filterChipUseCase(RelayListType.Single).test { assertLists(emptyList(), awaitItem()) } } @Test - fun `when Daita with direct only is enabled and multihop is enabled and relay list type is entry should return Daita filter chip`() = + fun `when Daita with direct only is enabled and relay list type is entry should return Daita filter chip`() = runTest { // Arrange settings.value = @@ -147,16 +137,14 @@ class FilterChipUseCaseTest { every { tunnelOptions.wireguard.daitaSettings.enabled } returns true every { tunnelOptions.wireguard.daitaSettings.directOnly } returns true } - wireguardConstraints.value = - mockk(relaxed = true) { every { isMultihopEnabled } returns true } - filterChipUseCase(RelayListType.ENTRY).test { + filterChipUseCase(RelayListType.Multihop(MultihopRelayListType.ENTRY)).test { assertLists(listOf(FilterChip.Daita), awaitItem()) } } @Test - fun `when Daita with direct only is enabled and multihop is enabled and relay list type is exit should return no filter`() = + fun `when Daita with direct only is enabled and relay list type is exit should return no filter`() = runTest { // Arrange settings.value = @@ -164,14 +152,14 @@ class FilterChipUseCaseTest { every { tunnelOptions.wireguard.daitaSettings.enabled } returns true every { tunnelOptions.wireguard.daitaSettings.directOnly } returns true } - wireguardConstraints.value = - mockk(relaxed = true) { every { isMultihopEnabled } returns true } - filterChipUseCase(RelayListType.EXIT).test { assertLists(emptyList(), awaitItem()) } + filterChipUseCase(RelayListType.Multihop(MultihopRelayListType.EXIT)).test { + assertLists(emptyList(), awaitItem()) + } } @Test - fun `when Daita without direct only is enabled and multihop is enabled and relay list type is exit should return no filter`() = + fun `when Daita without direct only is enabled and relay list type is exit should return no filter`() = runTest { // Arrange settings.value = @@ -179,10 +167,10 @@ class FilterChipUseCaseTest { every { tunnelOptions.wireguard.daitaSettings.enabled } returns true every { tunnelOptions.wireguard.daitaSettings.directOnly } returns false } - wireguardConstraints.value = - mockk(relaxed = true) { every { isMultihopEnabled } returns true } - filterChipUseCase(RelayListType.EXIT).test { assertLists(emptyList(), awaitItem()) } + filterChipUseCase(RelayListType.Multihop(MultihopRelayListType.EXIT)).test { + assertLists(emptyList(), awaitItem()) + } } @Test @@ -200,7 +188,7 @@ class FilterChipUseCaseTest { ) // Act, Assert - filterChipUseCase(RelayListType.EXIT).test { + filterChipUseCase(RelayListType.Single).test { assertLists( listOf(FilterChip.Ownership(expectedOwnership), FilterChip.Provider(1)), awaitItem(), diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/RecentsUseCaseTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/RecentsUseCaseTest.kt index f7699101d5..9623fffc7c 100644 --- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/RecentsUseCaseTest.kt +++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/RecentsUseCaseTest.kt @@ -8,6 +8,7 @@ import kotlin.test.assertNull import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.runTest +import net.mullvad.mullvadvpn.compose.state.MultihopRelayListType import net.mullvad.mullvadvpn.compose.state.RelayListType import net.mullvad.mullvadvpn.lib.model.CustomList import net.mullvad.mullvadvpn.lib.model.CustomListId @@ -118,13 +119,18 @@ class RecentsUseCaseTest { Recents.Enabled(listOf(singleHopRecent, multiHopRecent, filteredOutRecent)) } - every { customListsRelayItemUseCase(RelayListType.ENTRY) } returns - flowOf(listOf(entryCustomList)) - every { customListsRelayItemUseCase(RelayListType.EXIT) } returns flowOf(emptyList()) - every { filteredRelayListUseCase(RelayListType.ENTRY) } returns - flowOf(listOf(sweden, norway)) - every { filteredRelayListUseCase(RelayListType.EXIT) } returns - flowOf(listOf(sweden, norway)) + every { + customListsRelayItemUseCase(RelayListType.Multihop(MultihopRelayListType.ENTRY)) + } returns flowOf(listOf(entryCustomList)) + every { + customListsRelayItemUseCase(RelayListType.Multihop(MultihopRelayListType.EXIT)) + } returns flowOf(emptyList()) + every { + filteredRelayListUseCase(RelayListType.Multihop(MultihopRelayListType.ENTRY)) + } returns flowOf(listOf(sweden, norway)) + every { + filteredRelayListUseCase(RelayListType.Multihop(MultihopRelayListType.EXIT)) + } returns flowOf(listOf(sweden, norway)) useCase().test { val hops = awaitItem() diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SearchLocationViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SearchLocationViewModelTest.kt index ad0f87638f..8aa1e9b038 100644 --- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SearchLocationViewModelTest.kt +++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SearchLocationViewModelTest.kt @@ -20,11 +20,12 @@ import net.mullvad.mullvadvpn.lib.model.WireguardConstraints import net.mullvad.mullvadvpn.lib.ui.component.relaylist.RelayListItem import net.mullvad.mullvadvpn.repository.CustomListsRepository import net.mullvad.mullvadvpn.repository.RelayListFilterRepository -import net.mullvad.mullvadvpn.repository.RelayListRepository import net.mullvad.mullvadvpn.repository.WireguardConstraintsRepository import net.mullvad.mullvadvpn.usecase.FilterChip import net.mullvad.mullvadvpn.usecase.FilterChipUseCase import net.mullvad.mullvadvpn.usecase.FilteredRelayListUseCase +import net.mullvad.mullvadvpn.usecase.ModifyMultihopUseCase +import net.mullvad.mullvadvpn.usecase.SelectHopUseCase import net.mullvad.mullvadvpn.usecase.SelectedLocationUseCase import net.mullvad.mullvadvpn.usecase.customlists.CustomListActionUseCase import net.mullvad.mullvadvpn.usecase.customlists.CustomListsRelayItemUseCase @@ -39,7 +40,6 @@ import org.junit.jupiter.api.extension.ExtendWith class SearchLocationViewModelTest { private val mockWireguardConstraintsRepository: WireguardConstraintsRepository = mockk() - private val mockRelayListRepository: RelayListRepository = mockk() private val mockFilteredRelayListUseCase: FilteredRelayListUseCase = mockk() private val mockCustomListActionUseCase: CustomListActionUseCase = mockk() private val mockCustomListsRepository: CustomListsRepository = mockk() @@ -48,6 +48,8 @@ class SearchLocationViewModelTest { private val mockFilteredCustomListRelayItemsUseCase: FilterCustomListsRelayItemUseCase = mockk() private val mockSelectedLocationUseCase: SelectedLocationUseCase = mockk() private val mockCustomListsRelayItemUseCase: CustomListsRelayItemUseCase = mockk() + private val mockSelectHopUseCase: SelectHopUseCase = mockk() + private val mockModifyMultihopUseCase: ModifyMultihopUseCase = mockk() private val filteredRelayList = MutableStateFlow<List<RelayItem.Location.Country>>(emptyList()) private val selectedLocation = @@ -74,7 +76,6 @@ class SearchLocationViewModelTest { viewModel = SearchLocationViewModel( wireguardConstraintsRepository = mockWireguardConstraintsRepository, - relayListRepository = mockRelayListRepository, filteredRelayListUseCase = mockFilteredRelayListUseCase, customListActionUseCase = mockCustomListActionUseCase, customListsRepository = mockCustomListsRepository, @@ -83,8 +84,10 @@ class SearchLocationViewModelTest { filteredCustomListRelayItemsUseCase = mockFilteredCustomListRelayItemsUseCase, selectedLocationUseCase = mockSelectedLocationUseCase, customListsRelayItemUseCase = mockCustomListsRelayItemUseCase, + selectHopUseCase = mockSelectHopUseCase, + modifyMultihopUseCase = mockModifyMultihopUseCase, savedStateHandle = - SearchLocationNavArgs(relayListType = RelayListType.ENTRY).toSavedStateHandle(), + SearchLocationNavArgs(relayListType = RelayListType.Single).toSavedStateHandle(), ) } diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationListViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationListViewModelTest.kt index 1a54d15f95..3f9bfe751a 100644 --- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationListViewModelTest.kt +++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationListViewModelTest.kt @@ -73,7 +73,7 @@ class SelectLocationListViewModelTest { @Test fun `initial state should be loading`() = runTest { // Arrange - viewModel = createSelectLocationListViewModel(relayListType = RelayListType.ENTRY) + viewModel = createSelectLocationListViewModel(relayListType = RelayListType.Single) // Assert assertEquals(Lce.Loading(Unit), viewModel.uiState.value) @@ -82,7 +82,7 @@ class SelectLocationListViewModelTest { @Test fun `given filteredRelayList emits update uiState should contain new update`() = runTest { // Arrange - viewModel = createSelectLocationListViewModel(RelayListType.EXIT) + viewModel = createSelectLocationListViewModel(RelayListType.Single) filteredRelayList.value = testCountries val selectedId = testCountries.first().id selectedLocationFlow.value = RelayItemSelection.Single(Constraint.Only(selectedId)) @@ -107,7 +107,7 @@ class SelectLocationListViewModelTest { @Test fun `given relay is not selected all relay items should not be selected`() = runTest { // Arrange - viewModel = createSelectLocationListViewModel(RelayListType.EXIT) + viewModel = createSelectLocationListViewModel(RelayListType.Single) filteredRelayList.value = testCountries selectedLocationFlow.value = RelayItemSelection.Single(Constraint.Any) diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationViewModelTest.kt index e5804ffe61..e50cfb48a2 100644 --- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationViewModelTest.kt +++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationViewModelTest.kt @@ -17,6 +17,7 @@ import kotlinx.coroutines.test.runTest import net.mullvad.mullvadvpn.compose.communication.CustomListAction import net.mullvad.mullvadvpn.compose.communication.CustomListActionResultData import net.mullvad.mullvadvpn.compose.communication.LocationsChanged +import net.mullvad.mullvadvpn.compose.state.MultihopRelayListType import net.mullvad.mullvadvpn.compose.state.RelayListType import net.mullvad.mullvadvpn.compose.state.SelectLocationUiState import net.mullvad.mullvadvpn.lib.common.test.TestCoroutineRule @@ -25,7 +26,6 @@ import net.mullvad.mullvadvpn.lib.model.CustomList import net.mullvad.mullvadvpn.lib.model.CustomListId import net.mullvad.mullvadvpn.lib.model.CustomListName import net.mullvad.mullvadvpn.lib.model.GeoLocationId -import net.mullvad.mullvadvpn.lib.model.Hop import net.mullvad.mullvadvpn.lib.model.Ownership import net.mullvad.mullvadvpn.lib.model.Providers import net.mullvad.mullvadvpn.lib.model.RelayItem @@ -40,6 +40,9 @@ import net.mullvad.mullvadvpn.repository.SettingsRepository import net.mullvad.mullvadvpn.repository.WireguardConstraintsRepository import net.mullvad.mullvadvpn.usecase.FilterChip import net.mullvad.mullvadvpn.usecase.FilterChipUseCase +import net.mullvad.mullvadvpn.usecase.ModifyMultihopUseCase +import net.mullvad.mullvadvpn.usecase.MultihopChange +import net.mullvad.mullvadvpn.usecase.SelectHopUseCase import net.mullvad.mullvadvpn.usecase.customlists.CustomListActionUseCase import net.mullvad.mullvadvpn.util.Lc import org.junit.jupiter.api.AfterEach @@ -57,6 +60,8 @@ class SelectLocationViewModelTest { private val mockWireguardConstraintsRepository: WireguardConstraintsRepository = mockk() private val mockFilterChipUseCase: FilterChipUseCase = mockk() private val mockSettingsRepository: SettingsRepository = mockk() + private val mockSelectHopUseCase: SelectHopUseCase = mockk() + private val mockModifyMultihopUseCase: ModifyMultihopUseCase = mockk() private lateinit var viewModel: SelectLocationViewModel @@ -88,6 +93,8 @@ class SelectLocationViewModelTest { filterChipUseCase = mockFilterChipUseCase, wireguardConstraintsRepository = mockWireguardConstraintsRepository, settingsRepository = mockSettingsRepository, + modifyMultihopUseCase = mockModifyMultihopUseCase, + selectHopUseCase = mockSelectHopUseCase, ) } @@ -103,22 +110,22 @@ class SelectLocationViewModelTest { } @Test - fun `on selectRelay when relay list type is exit call uiSideEffect should emit CloseScreen and connect`() = + fun `on modifyMultihop when relay list type is exit call uiSideEffect should emit CloseScreen and connect`() = runTest { // Arrange val mockRelayItem: RelayItem.Location.Country = mockk() val relayItemId: GeoLocationId.Country = mockk(relaxed = true) + val multihopChange: MultihopChange = MultihopChange.Exit(mockRelayItem) every { mockRelayItem.id } returns relayItemId every { mockRelayItem.active } returns true - coEvery { mockRelayListRepository.updateSelectedRelayLocation(relayItemId) } returns - Unit.right() + coEvery { mockModifyMultihopUseCase.invoke(multihopChange) } returns Unit.right() // Act, Assert viewModel.uiSideEffect.test { - viewModel.selectHop(Hop.Single(mockRelayItem), RelayListType.EXIT) + viewModel.modifyMultihop(mockRelayItem, MultihopRelayListType.EXIT) // Await an empty item assertEquals(SelectLocationSideEffect.CloseScreen, awaitItem()) - coVerify { mockRelayListRepository.updateSelectedRelayLocation(relayItemId) } + coVerify { mockModifyMultihopUseCase.invoke(multihopChange) } } } @@ -128,26 +135,32 @@ class SelectLocationViewModelTest { // Arrange val mockRelayItem: RelayItem.Location.Country = mockk() val relayItemId: GeoLocationId.Country = mockk(relaxed = true) + val multihopChange = MultihopChange.Entry(mockRelayItem) every { mockRelayItem.active } returns true every { mockRelayItem.id } returns relayItemId - coEvery { mockWireguardConstraintsRepository.setEntryLocation(relayItemId) } returns - Unit.right() + coEvery { mockModifyMultihopUseCase.invoke(multihopChange) } returns Unit.right() // Act, Assert viewModel.uiState.test { awaitItem() // Default value - viewModel.selectRelayList(RelayListType.ENTRY) + viewModel.selectRelayList(MultihopRelayListType.ENTRY) // Assert relay list type is entry val firstState = awaitItem() assertIs<Lc.Content<SelectLocationUiState>>(firstState) - assertEquals(RelayListType.ENTRY, firstState.value.relayListType) + assertEquals( + RelayListType.Multihop(MultihopRelayListType.ENTRY), + firstState.value.relayListType, + ) // Select entry - viewModel.selectHop(Hop.Single(mockRelayItem), RelayListType.ENTRY) + viewModel.modifyMultihop(mockRelayItem, MultihopRelayListType.ENTRY) // Assert relay list type is exit val secondState = awaitItem() assertIs<Lc.Content<SelectLocationUiState>>(secondState) - assertEquals(RelayListType.EXIT, secondState.value.relayListType) - coVerify { mockWireguardConstraintsRepository.setEntryLocation(relayItemId) } + assertEquals( + RelayListType.Multihop(MultihopRelayListType.EXIT), + secondState.value.relayListType, + ) + coVerify { mockModifyMultihopUseCase.invoke(multihopChange) } } } |
