Skip to content

Commit

Permalink
Add shadowsocks unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Pururun committed Sep 17, 2024
1 parent 95cd7d3 commit 15c889c
Show file tree
Hide file tree
Showing 3 changed files with 196 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package net.mullvad.mullvadvpn.viewmodel

import app.cash.turbine.test
import arrow.core.right
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.test.runTest
import net.mullvad.mullvadvpn.lib.common.test.TestCoroutineRule
import net.mullvad.mullvadvpn.lib.common.test.assertLists
import net.mullvad.mullvadvpn.lib.model.Constraint
import net.mullvad.mullvadvpn.lib.model.Port
import net.mullvad.mullvadvpn.lib.model.PortRange
import net.mullvad.mullvadvpn.lib.model.Settings
import net.mullvad.mullvadvpn.repository.RelayListRepository
import net.mullvad.mullvadvpn.repository.SettingsRepository
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith

@ExtendWith(TestCoroutineRule::class)
class ShadowsocksSettingsViewModelTest {

private val mockSettingsRepository: SettingsRepository = mockk()
private val mockRelayListRepository: RelayListRepository = mockk()

private val settingsFlow = MutableStateFlow<Settings?>(null)
private val portRangesFlow = MutableStateFlow<List<PortRange>>(emptyList())

private lateinit var viewModel: ShadowsocksSettingsViewModel

@BeforeEach
fun setUp() {
every { mockSettingsRepository.settingsUpdates } returns settingsFlow
every { mockRelayListRepository.shadowsocksPortRanges } returns portRangesFlow

viewModel =
ShadowsocksSettingsViewModel(
settingsRepository = mockSettingsRepository,
relayListRepository = mockRelayListRepository,
)
}

@Test
fun `uiState should reflect latest port value from settings`() = runTest {
// Arrange
val mockSettings: Settings = mockk()
val port = Port(123)
every { mockSettings.obfuscationSettings.shadowsocks.port } returns Constraint.Only(port)

settingsFlow.update { mockSettings }

// Act, Assert
viewModel.uiState.test {
// Check result
val result = awaitItem().port
assertEquals(Constraint.Only(port), result)
}
}

@Test
fun `uiState should reflect latest port range value from relay list`() = runTest {
// Arrange
val mockSettings: Settings = mockk()
val port = Port(123)
every { mockSettings.obfuscationSettings.shadowsocks.port } returns Constraint.Only(port)
val mockPortRange: List<PortRange> = listOf(mockk())

portRangesFlow.update { mockPortRange }
settingsFlow.update { mockSettings }

// Act, Assert
viewModel.uiState.test {
// Check result
val result = awaitItem().validPortRanges
assertLists(mockPortRange, result)
}
}

@Test
fun `when onObfuscationPortSelected is called should call repository`() {
// Arrange
val port = Constraint.Only(Port(123))
coEvery { mockSettingsRepository.setCustomShadowsocksObfuscationPort(port) } returns
Unit.right()

// Act
viewModel.onObfuscationPortSelected(port)

// Assert
coVerify { mockSettingsRepository.setCustomShadowsocksObfuscationPort(port) }
}

@Test
fun `when reset custom port is called should reset custom port`() = runTest {
// Arrange
val mockSettings: Settings = mockk()
val port = Port(123) // Needs to be not in SHADOWSOCKS_PRESET_PORTS
every { mockSettings.obfuscationSettings.shadowsocks.port } returns Constraint.Only(port)
coEvery {
mockSettingsRepository.setCustomShadowsocksObfuscationPort(Constraint.Any)
} returns Unit.right()

settingsFlow.update { mockSettings }

// Act, Assert
viewModel.uiState.test {
val startState = awaitItem()
assertEquals(port, startState.customPort)

viewModel.resetCustomPort()

val updatedState = awaitItem()
assertEquals(null, updatedState.customPort)
coVerify { mockSettingsRepository.setCustomShadowsocksObfuscationPort(Constraint.Any) }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package net.mullvad.mullvadvpn.viewmodel

import app.cash.turbine.test
import arrow.core.right
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.test.runTest
import net.mullvad.mullvadvpn.lib.common.test.TestCoroutineRule
import net.mullvad.mullvadvpn.lib.model.Constraint
import net.mullvad.mullvadvpn.lib.model.Port
import net.mullvad.mullvadvpn.lib.model.Settings
import net.mullvad.mullvadvpn.repository.SettingsRepository
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith

@ExtendWith(TestCoroutineRule::class)
class Udp2TcpSettingsViewModelTest {

private val mockSettingsRepository: SettingsRepository = mockk()

private val settingsFlow = MutableStateFlow<Settings?>(null)

private lateinit var viewModel: Udp2TcpSettingsViewModel

@BeforeEach
fun setUp() {
every { mockSettingsRepository.settingsUpdates } returns settingsFlow

viewModel = Udp2TcpSettingsViewModel(repository = mockSettingsRepository)
}

@Test
fun `uiState should reflect latest value from settings`() = runTest {
// Arrange
val mockSettings: Settings = mockk()
val port = Port(123)
every { mockSettings.obfuscationSettings.udp2tcp.port } returns Constraint.Only(port)

settingsFlow.update { mockSettings }

// Act, Assert
viewModel.uiState.test {
// Check result
val result = awaitItem().port
assertEquals(Constraint.Only(port), result)
}
}

@Test
fun `when onObfuscationPortSelected is called should call repository`() {
// Arrange
val port = Constraint.Only(Port(123))
coEvery { mockSettingsRepository.setCustomUdp2TcpObfuscationPort(port) } returns
Unit.right()

// Act
viewModel.onObfuscationPortSelected(port)

// Assert
coVerify { mockSettingsRepository.setCustomUdp2TcpObfuscationPort(port) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ class VpnSettingsViewModelTest {
runTest {
val customPort = Port(5001)
coEvery {
mockSettingsRepository.setCustomObfuscationPort(Constraint.Only(customPort))
mockSettingsRepository.setCustomUdp2TcpObfuscationPort(Constraint.Only(customPort))
} returns Unit.right()
viewModel.onObfuscationPortSelected(Constraint.Only(customPort))
coVerify(exactly = 1) {
mockSettingsRepository.setCustomObfuscationPort(Constraint.Only(customPort))
mockSettingsRepository.setCustomUdp2TcpObfuscationPort(Constraint.Only(customPort))
}
}

Expand Down Expand Up @@ -122,6 +122,8 @@ class VpnSettingsViewModelTest {
every { mockSettings.tunnelOptions } returns mockTunnelOptions
every { mockTunnelOptions.wireguard } returns mockWireguardTunnelOptions
every { mockSettings.relaySettings } returns mockk<RelaySettings>(relaxed = true)
every { mockSettings.relaySettings.relayConstraints.wireguardConstraints.port } returns
Constraint.Any

viewModel.uiState.test {
assertEquals(defaultResistantState, awaitItem().quantumResistant)
Expand All @@ -134,7 +136,7 @@ class VpnSettingsViewModelTest {
fun `when SettingsRepository emits Constraint Only then uiState should emit custom and selectedWireguardPort with port of Constraint`() =
runTest {
// Arrange
val expectedPort: Constraint<Port> = Constraint.Only(Port(99))
val expectedPort = Constraint.Only(Port(99))
val mockSettings: Settings = mockk(relaxed = true)
val mockRelaySettings: RelaySettings = mockk()
val mockRelayConstraints: RelayConstraints = mockk()
Expand All @@ -159,7 +161,7 @@ class VpnSettingsViewModelTest {
viewModel.uiState.test {
assertIs<Constraint.Any>(awaitItem().selectedWireguardPort)
mockSettingsUpdate.value = mockSettings
assertEquals(expectedPort, awaitItem().customWireguardPort)
assertEquals(expectedPort.value, awaitItem().customWireguardPort)
assertEquals(expectedPort, awaitItem().selectedWireguardPort)
}
}
Expand Down

0 comments on commit 15c889c

Please sign in to comment.