diff options
| author | Niklas Berglund <niklas.berglund@gmail.com> | 2024-11-20 16:31:37 +0100 |
|---|---|---|
| committer | Niklas Berglund <niklas.berglund@gmail.com> | 2024-12-03 15:15:37 +0100 |
| commit | a83948cbb4be5c02c90ebddf8068a06e0e892fb8 (patch) | |
| tree | a5ade65e3c9e2999dd3e9bfc04deda07e65ab8ff /android | |
| parent | 7b0f970d286089d6d00ede630e275624a8b84022 (diff) | |
| download | mullvadvpn-a83948cbb4be5c02c90ebddf8068a06e0e892fb8.tar.xz mullvadvpn-a83948cbb4be5c02c90ebddf8068a06e0e892fb8.zip | |
Implement UDP-over-TCP e2e test and firewall API client
Diffstat (limited to 'android')
26 files changed, 352 insertions, 48 deletions
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 45edfcd204..19802571f6 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 @@ -16,7 +16,7 @@ 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.test.LAZY_LIST_VPN_SETTINGS_TEST_TAG import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_WIREGUARD_CUSTOM_PORT_NUMBER_TEST_TAG import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_WIREGUARD_CUSTOM_PORT_TEXT_TEST_TAG import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_WIREGUARD_OBFUSCATION_TITLE_TEST_TAG @@ -47,7 +47,7 @@ class VpnSettingsScreenTest { // Arrange setContentWithTheme { VpnSettingsScreen(state = VpnSettingsUiState.createDefault()) } - onNodeWithTag(LAZY_LIST_TEST_TAG) + onNodeWithTag(LAZY_LIST_VPN_SETTINGS_TEST_TAG) .performScrollToNode(hasTestTag(LAZY_LIST_LAST_ITEM_TEST_TAG)) // Assert @@ -70,7 +70,7 @@ class VpnSettingsScreenTest { ) } - onNodeWithTag(LAZY_LIST_TEST_TAG) + onNodeWithTag(LAZY_LIST_VPN_SETTINGS_TEST_TAG) .performScrollToNode(hasTestTag(LAZY_LIST_LAST_ITEM_TEST_TAG)) // Assert @@ -117,7 +117,7 @@ class VpnSettingsScreenTest { ) ) } - onNodeWithTag(LAZY_LIST_TEST_TAG) + onNodeWithTag(LAZY_LIST_VPN_SETTINGS_TEST_TAG) .performScrollToNode(hasTestTag(LAZY_LIST_LAST_ITEM_TEST_TAG)) // Assert onNodeWithText(DUMMY_DNS_ADDRESS).assertDoesNotExist() @@ -213,7 +213,7 @@ class VpnSettingsScreenTest { ) ) } - onNodeWithTag(LAZY_LIST_TEST_TAG) + onNodeWithTag(LAZY_LIST_VPN_SETTINGS_TEST_TAG) .performScrollToNode(hasTestTag(LAZY_LIST_QUANTUM_ITEM_OFF_TEST_TAG)) // Assert @@ -236,7 +236,7 @@ class VpnSettingsScreenTest { onSelectQuantumResistanceSetting = mockSelectQuantumResistantSettingListener, ) } - onNodeWithTag(LAZY_LIST_TEST_TAG) + onNodeWithTag(LAZY_LIST_VPN_SETTINGS_TEST_TAG) .performScrollToNode(hasTestTag(LAZY_LIST_QUANTUM_ITEM_OFF_TEST_TAG)) // Assert @@ -261,7 +261,7 @@ class VpnSettingsScreenTest { } // Act - onNodeWithTag(LAZY_LIST_TEST_TAG) + onNodeWithTag(LAZY_LIST_VPN_SETTINGS_TEST_TAG) .performScrollToNode( hasTestTag(String.format(LAZY_LIST_WIREGUARD_PORT_ITEM_X_TEST_TAG, 53)) ) @@ -291,7 +291,7 @@ class VpnSettingsScreenTest { } // Act - onNodeWithTag(LAZY_LIST_TEST_TAG) + onNodeWithTag(LAZY_LIST_VPN_SETTINGS_TEST_TAG) .performScrollToNode( hasTestTag(String.format(LAZY_LIST_WIREGUARD_PORT_ITEM_X_TEST_TAG, 53)) ) @@ -318,7 +318,7 @@ class VpnSettingsScreenTest { } // Act - onNodeWithTag(LAZY_LIST_TEST_TAG) + onNodeWithTag(LAZY_LIST_VPN_SETTINGS_TEST_TAG) .performScrollToNode(hasTestTag(LAZY_LIST_WIREGUARD_CUSTOM_PORT_TEXT_TEST_TAG)) // Assert @@ -342,7 +342,7 @@ class VpnSettingsScreenTest { } // Act - onNodeWithTag(LAZY_LIST_TEST_TAG) + onNodeWithTag(LAZY_LIST_VPN_SETTINGS_TEST_TAG) .performScrollToNode(hasTestTag(LAZY_LIST_WIREGUARD_CUSTOM_PORT_TEXT_TEST_TAG)) onNodeWithTag(testTag = LAZY_LIST_WIREGUARD_CUSTOM_PORT_TEXT_TEST_TAG).performClick() @@ -364,7 +364,7 @@ class VpnSettingsScreenTest { ) } - onNodeWithTag(LAZY_LIST_TEST_TAG) + onNodeWithTag(LAZY_LIST_VPN_SETTINGS_TEST_TAG) .performScrollToNode(hasTestTag(LAZY_LIST_LAST_ITEM_TEST_TAG)) // Act @@ -407,7 +407,7 @@ class VpnSettingsScreenTest { } // Act - onNodeWithTag(LAZY_LIST_TEST_TAG) + onNodeWithTag(LAZY_LIST_VPN_SETTINGS_TEST_TAG) .performScrollToNode(hasTestTag(LAZY_LIST_WIREGUARD_OBFUSCATION_TITLE_TEST_TAG)) onNodeWithText("WireGuard obfuscation").performClick() @@ -430,7 +430,7 @@ class VpnSettingsScreenTest { // Act - onNodeWithTag(LAZY_LIST_TEST_TAG) + onNodeWithTag(LAZY_LIST_VPN_SETTINGS_TEST_TAG) .performScrollToNode(hasTestTag(LAZY_LIST_QUANTUM_ITEM_ON_TEST_TAG)) onNodeWithText("Quantum-resistant tunnel").performClick() @@ -469,7 +469,7 @@ class VpnSettingsScreenTest { ) } - onNodeWithTag(LAZY_LIST_TEST_TAG) + onNodeWithTag(LAZY_LIST_VPN_SETTINGS_TEST_TAG) .performScrollToNode(hasTestTag(LAZY_LIST_WIREGUARD_CUSTOM_PORT_NUMBER_TEST_TAG)) onNodeWithText("Custom").performClick() @@ -490,7 +490,7 @@ class VpnSettingsScreenTest { } // Act - onNodeWithTag(LAZY_LIST_TEST_TAG) + onNodeWithTag(LAZY_LIST_VPN_SETTINGS_TEST_TAG) .performScrollToNode(hasTestTag(LAZY_LIST_WIREGUARD_CUSTOM_PORT_TEXT_TEST_TAG)) onNodeWithTag(LAZY_LIST_WIREGUARD_CUSTOM_PORT_TEXT_TEST_TAG).performClick() @@ -514,7 +514,7 @@ class VpnSettingsScreenTest { } // Act - onNodeWithTag(LAZY_LIST_TEST_TAG) + onNodeWithTag(LAZY_LIST_VPN_SETTINGS_TEST_TAG) .performScrollToNode(hasTestTag(LAZY_LIST_WIREGUARD_CUSTOM_PORT_TEXT_TEST_TAG)) onNodeWithTag(testTag = LAZY_LIST_WIREGUARD_CUSTOM_PORT_NUMBER_TEST_TAG).performClick() diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ObfuscationModeCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ObfuscationModeCell.kt index 6688f5d0ab..5191eba331 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ObfuscationModeCell.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ObfuscationModeCell.kt @@ -19,6 +19,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.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter @@ -57,12 +58,14 @@ fun ObfuscationModeCell( isSelected: Boolean, onSelected: (ObfuscationMode) -> Unit, onNavigate: () -> Unit = {}, + testTag: String? = null, ) { Row( modifier = Modifier.height(IntrinsicSize.Min) .fillMaxWidth() .background(MaterialTheme.colorScheme.surfaceContainerLow) + .let { if (testTag != null) it.testTag(testTag) else it } ) { TwoRowCell( modifier = Modifier.weight(1f), diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/connectioninfo/ConnectionDetailPanel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/connectioninfo/ConnectionDetailPanel.kt index 3ec353bc96..7d4e2a5838 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/connectioninfo/ConnectionDetailPanel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/connectioninfo/ConnectionDetailPanel.kt @@ -16,6 +16,7 @@ import androidx.constraintlayout.compose.ConstraintLayout import androidx.constraintlayout.compose.Dimension import net.mullvad.mullvadvpn.R import net.mullvad.mullvadvpn.compose.screen.ConnectionDetails +import net.mullvad.mullvadvpn.compose.test.LOCATION_INFO_CONNECTION_IN_TEST_TAG import net.mullvad.mullvadvpn.compose.test.LOCATION_INFO_CONNECTION_OUT_TEST_TAG import net.mullvad.mullvadvpn.constant.SPACE_CHAR import net.mullvad.mullvadvpn.lib.model.TransportProtocol @@ -88,7 +89,7 @@ fun ConnectionDetails( maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = - Modifier.constrainAs(inAddr) { + Modifier.testTag(LOCATION_INFO_CONNECTION_IN_TEST_TAG).constrainAs(inAddr) { start.linkTo(headerBarrier) end.linkTo(parent.end) top.linkTo(parent.top) 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 f763272438..6489b53e79 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 @@ -82,11 +82,13 @@ 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.test.LAZY_LIST_VPN_SETTINGS_TEST_TAG import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_WIREGUARD_CUSTOM_PORT_NUMBER_TEST_TAG import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_WIREGUARD_CUSTOM_PORT_TEXT_TEST_TAG import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_WIREGUARD_OBFUSCATION_TITLE_TEST_TAG import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_WIREGUARD_PORT_ITEM_X_TEST_TAG +import net.mullvad.mullvadvpn.compose.test.WIREGUARD_OBFUSCATION_OFF_CELL +import net.mullvad.mullvadvpn.compose.test.WIREGUARD_OBFUSCATION_UDP_OVER_TCP_CELL import net.mullvad.mullvadvpn.compose.transitions.SlideInFromRightTransition import net.mullvad.mullvadvpn.compose.util.CollectSideEffectWithLifecycle import net.mullvad.mullvadvpn.compose.util.OnNavResultValue @@ -297,7 +299,7 @@ fun VpnSettingsScreen( snackbarHostState = snackbarHostState, ) { modifier, lazyListState -> LazyColumn( - modifier = modifier.testTag(LAZY_LIST_TEST_TAG).animateContentSize(), + modifier = modifier.testTag(LAZY_LIST_VPN_SETTINGS_TEST_TAG).animateContentSize(), state = lazyListState, ) { if (state.systemVpnSettingsAvailable) { @@ -568,6 +570,7 @@ fun VpnSettingsScreen( port = state.selectedUdp2TcpObfuscationPort, onSelected = onSelectObfuscationMode, onNavigate = navigateToUdp2TcpSettings, + testTag = WIREGUARD_OBFUSCATION_UDP_OVER_TCP_CELL, ) } itemWithDivider { @@ -575,6 +578,7 @@ fun VpnSettingsScreen( title = stringResource(id = R.string.off), isSelected = state.obfuscationMode == ObfuscationMode.Off, onCellClicked = { onSelectObfuscationMode(ObfuscationMode.Off) }, + testTag = WIREGUARD_OBFUSCATION_OFF_CELL, ) } 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 d90f14a763..b124ffcc61 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 @@ -5,6 +5,7 @@ const val TOP_BAR_ACCOUNT_BUTTON = "top_bar_account_button" const val TOP_BAR_SETTINGS_BUTTON = "top_bar_settings_button" // VpnSettingsScreen +const val LAZY_LIST_VPN_SETTINGS_TEST_TAG = "lazy_list_vpn_settings_test_tag" 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" @@ -18,6 +19,9 @@ const val CUSTOM_PORT_DIALOG_INPUT_TEST_TAG = "custom_port_dialog_input_test_tag const val LAZY_LIST_WIREGUARD_OBFUSCATION_TITLE_TEST_TAG = "lazy_list_wireguard_obfuscation_title_test_tag" const val SWITCH_TEST_TAG = "switch_test_tag" +const val WIREGUARD_OBFUSCATION_OFF_CELL = "wireguard_obfuscation_off_cell_test_tag" +const val WIREGUARD_OBFUSCATION_UDP_OVER_TCP_CELL = + "wireguard_obfuscation_udp_over_tcp_cell_test_tag" // SelectLocationScreen, ConnectScreen, CustomListLocationsScreen const val CIRCULAR_PROGRESS_INDICATOR = "circular_progress_indicator" diff --git a/android/gradle.properties b/android/gradle.properties index 74c277e3a1..b8a39d5d02 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -3,3 +3,4 @@ android.nonTransitiveRClass=false android.useAndroidX=true kotlin.code.style=official org.gradle.jvmargs=-Xmx8192M -Dkotlin.daemon.jvm.options\="-Xmx8192M" +test.e2e.enableAccessToLocalApiTests=false diff --git a/android/scripts/run-instrumented-tests.sh b/android/scripts/run-instrumented-tests.sh index 055112fb43..8d835ddb5a 100755 --- a/android/scripts/run-instrumented-tests.sh +++ b/android/scripts/run-instrumented-tests.sh @@ -150,6 +150,8 @@ if [[ -z $REPORT_DIR || ! -d $REPORT_DIR ]]; then exit 1 fi +GRADLE_ENVIRONMENT_VARIABLES="TEST_E2E_ENABLEACCESSTOLOCALAPITESTS=$ENABLE_ACCESS_TO_LOCAL_API_TESTS" + INSTRUMENTATION_LOG_FILE_PATH="$REPORT_DIR/instrumentation-log.txt" LOGCAT_FILE_PATH="$REPORT_DIR/logcat.txt" LOCAL_SCREENSHOT_PATH="$REPORT_DIR/screenshots" @@ -222,7 +224,7 @@ else -e runnerBuilder de.mannodermaus.junit5.AndroidJUnit5Builder \ $TEST_PACKAGE_NAME/androidx.test.runner.AndroidJUnitRunner" fi -adb shell "$INSTRUMENTATION_COMMAND" | tee "$INSTRUMENTATION_LOG_FILE_PATH" +adb shell "$GRADLE_ENVIRONMENT_VARIABLES $INSTRUMENTATION_COMMAND" | tee "$INSTRUMENTATION_LOG_FILE_PATH" echo "" echo "### Ensure that packages are uninstalled ###" diff --git a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/interactor/AppInteractor.kt b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/interactor/AppInteractor.kt index 34690022c9..ea9b761ea1 100644 --- a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/interactor/AppInteractor.kt +++ b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/interactor/AppInteractor.kt @@ -96,7 +96,7 @@ class AppInteractor( } fun extractInIpv4Address(): String { - device.findObjectWithTimeout(By.res("location_info_test_tag")).click() + device.findObjectWithTimeout(By.res("connect_card_header_test_tag")).click() val inString = device .findObjectWithTimeout( @@ -105,7 +105,7 @@ class AppInteractor( ) .text - val extractedIpAddress = inString.split(" ")[1].split(":")[0] + val extractedIpAddress = inString.split(" ")[0].split(":")[0] return extractedIpAddress } diff --git a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/rule/ForgetAllVpnAppsInSettingsTestRule.kt b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/rule/ForgetAllVpnAppsInSettingsTestRule.kt index c96718da61..2a4a4dfeb1 100644 --- a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/rule/ForgetAllVpnAppsInSettingsTestRule.kt +++ b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/rule/ForgetAllVpnAppsInSettingsTestRule.kt @@ -45,6 +45,8 @@ class ForgetAllVpnAppsInSettingsTestRule : BeforeTestExecutionCallback { device .findObjectWithTimeout(By.text(DELETE_VPN_CONFIRM_BUTTON_TEXT_REGEXP)) .click() + } else if (device.hasObjectWithTimeout(By.text(FORGET_VPN_BUTTON_TEXT))) { + device.findObjectWithTimeout(By.text(FORGET_VPN_BUTTON_TEXT)).click() } else { fail("Unable to find forget or delete button") } @@ -60,6 +62,7 @@ class ForgetAllVpnAppsInSettingsTestRule : BeforeTestExecutionCallback { private val HARDCODED_VPN_PROFILE_NAMES = listOf("VPN by Google") private const val FORGET_VPN_VPN_BUTTON_TEXT = "Forget VPN" + private const val FORGET_VPN_BUTTON_TEXT = "Forget" // Legacy VPN private const val DELETE_VPN_PROFILE_TEXT = "Delete VPN profile" private const val FORGET_VPN_VPN_CONFIRM_BUTTON_TEXT = "Forget" // Samsung S22 shows "Delete" diff --git a/android/test/e2e/build.gradle.kts b/android/test/e2e/build.gradle.kts index 4b1b2b9d60..500a1e27cd 100644 --- a/android/test/e2e/build.gradle.kts +++ b/android/test/e2e/build.gradle.kts @@ -36,7 +36,7 @@ android { load(project.file("e2e.properties").inputStream()) addRequiredPropertyAsBuildConfigField("API_VERSION") addRequiredPropertyAsBuildConfigField("TRAFFIC_GENERATION_IP_ADDRESS") - addRequiredPropertyAsBuildConfigField("PACKET_CAPTURE_API_HOST") + addRequiredPropertyAsBuildConfigField("TEST_ROUTER_API_HOST") } fun MutableMap<String, String>.addOptionalPropertyAsArgument(name: String) { @@ -52,10 +52,12 @@ android { testInstrumentationRunnerArguments += mutableMapOf<String, String>().apply { put("clearPackageData", "true") - addOptionalPropertyAsArgument("enable_access_to_local_api_tests") addOptionalPropertyAsArgument("enable_highly_rate_limited_tests") addOptionalPropertyAsArgument("valid_test_account_number") addOptionalPropertyAsArgument("invalid_test_account_number") + project.findProperty("test.e2e.enableAccessToLocalApiTests")?.let { + put("enable_access_to_local_api_tests", it.toString()) + } } } diff --git a/android/test/e2e/e2e.properties b/android/test/e2e/e2e.properties index db9bdd29a5..1cfa0f6bd1 100644 --- a/android/test/e2e/e2e.properties +++ b/android/test/e2e/e2e.properties @@ -1,3 +1,3 @@ API_VERSION=v1 TRAFFIC_GENERATION_IP_ADDRESS=45.83.223.209 -PACKET_CAPTURE_API_HOST=192.168.105.1 +TEST_ROUTER_API_HOST=192.168.105.1 diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/ConnectionTest.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/ConnectionTest.kt index 7b98c2f8f3..81a9eabfe6 100644 --- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/ConnectionTest.kt +++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/ConnectionTest.kt @@ -1,13 +1,27 @@ package net.mullvad.mullvadvpn.test.e2e import androidx.test.uiautomator.By +import androidx.test.uiautomator.Direction +import androidx.test.uiautomator.Until +import kotlin.time.Duration.Companion.milliseconds +import kotlinx.coroutines.delay +import kotlinx.coroutines.runBlocking import net.mullvad.mullvadvpn.BuildConfig +import net.mullvad.mullvadvpn.compose.test.EXPAND_BUTTON_TEST_TAG +import net.mullvad.mullvadvpn.compose.test.SELECT_LOCATION_BUTTON_TEST_TAG +import net.mullvad.mullvadvpn.compose.test.SWITCH_TEST_TAG +import net.mullvad.mullvadvpn.compose.test.TOP_BAR_SETTINGS_BUTTON +import net.mullvad.mullvadvpn.test.common.constant.EXTREMELY_LONG_TIMEOUT import net.mullvad.mullvadvpn.test.common.constant.VERY_LONG_TIMEOUT import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout import net.mullvad.mullvadvpn.test.common.rule.ForgetAllVpnAppsInSettingsTestRule +import net.mullvad.mullvadvpn.test.e2e.annotations.HasDependencyOnLocalAPI import net.mullvad.mullvadvpn.test.e2e.misc.AccountTestRule +import net.mullvad.mullvadvpn.test.e2e.misc.ClearFirewallRules import net.mullvad.mullvadvpn.test.e2e.misc.ConnCheckState import net.mullvad.mullvadvpn.test.e2e.misc.SimpleMullvadHttpClient +import net.mullvad.mullvadvpn.test.e2e.router.firewall.DropRule +import net.mullvad.mullvadvpn.test.e2e.router.firewall.FirewallClient import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.RegisterExtension @@ -20,6 +34,8 @@ class ConnectionTest : EndToEndTest(BuildConfig.FLAVOR_infrastructure) { @JvmField val forgetAllVpnAppsInSettingsTestRule = ForgetAllVpnAppsInSettingsTestRule() + val firewallClient = FirewallClient() + @Test fun testConnect() { // Given @@ -48,4 +64,117 @@ class ConnectionTest : EndToEndTest(BuildConfig.FLAVOR_infrastructure) { val result = SimpleMullvadHttpClient(targetContext).runConnectionCheck() assertEquals(expected, result) } + + @Test + @HasDependencyOnLocalAPI + @ClearFirewallRules + fun testWireGuardObfuscationOff() = runBlocking { + app.launchAndEnsureLoggedIn(accountTestRule.validAccountNumber) + + enableLocalNetworkSharing() + + device.findObjectWithTimeout(By.res(SELECT_LOCATION_BUTTON_TEST_TAG)).click() + clickLocationExpandButton(DEFAULT_COUNTRY) + clickLocationExpandButton(DEFAULT_CITY) + device.findObjectWithTimeout(By.text(DEFAULT_RELAY)).click() + device.findObjectWithTimeout(By.text("OK")).click() + device.findObjectWithTimeout(By.text("CONNECTED"), VERY_LONG_TIMEOUT) + val relayIpAddress = app.extractInIpv4Address() + device.findObjectWithTimeout(By.text("Disconnect")).click() + + // Disable obfuscation + device.findObjectWithTimeout(By.res(TOP_BAR_SETTINGS_BUTTON)).click() + device.findObjectWithTimeout(By.text("VPN settings")).click() + val scrollView = device.findObjectWithTimeout(By.res(SETTINGS_SCROLL_VIEW_TEST_TAG)) + scrollView.scrollUntil( + Direction.DOWN, + Until.hasObject(By.res(WIREGUARD_OBFUSCATION_OFF_CELL_TEST_TAG)), + ) + device.findObjectWithTimeout(By.res(WIREGUARD_OBFUSCATION_OFF_CELL_TEST_TAG)).click() + device.pressBack() + device.pressBack() + + // Block UDP traffic to the relay + val firewallRule = DropRule.blockUDPTrafficRule(relayIpAddress) + firewallClient.createRule(firewallRule) + + // Ensure it is not possible to connect to relay + device.findObjectWithTimeout(By.text("Connect")).click() + // Give it some time and then verify still unable to connect. This duration must be long + // enough to ensure all retry attempts have been made. + delay(UNSUCCESSFUL_CONNECTION_TIMEOUT.milliseconds) + device.findObjectWithTimeout(By.text(("CONNECTING..."))) + device.findObjectWithTimeout(By.text("Cancel")).click() + } + + @Test + @HasDependencyOnLocalAPI + @ClearFirewallRules + fun testUDPOverTCP() = + runBlocking<Unit> { + app.launchAndEnsureLoggedIn(accountTestRule.validAccountNumber) + + enableLocalNetworkSharing() + + device.findObjectWithTimeout(By.res(SELECT_LOCATION_BUTTON_TEST_TAG)).click() + clickLocationExpandButton(DEFAULT_COUNTRY) + clickLocationExpandButton(DEFAULT_CITY) + device.findObjectWithTimeout(By.text(DEFAULT_RELAY)).click() + device.findObjectWithTimeout(By.text("OK")).click() + device.findObjectWithTimeout(By.text("CONNECTED"), VERY_LONG_TIMEOUT) + val relayIpAddress = app.extractInIpv4Address() + device.findObjectWithTimeout(By.text("Disconnect")).click() + + // Block UDP traffic to the relay + val firewallRule = DropRule.blockUDPTrafficRule(relayIpAddress) + firewallClient.createRule(firewallRule) + + // Enable UDP-over-TCP + device.findObjectWithTimeout(By.res(TOP_BAR_SETTINGS_BUTTON)).click() + device.findObjectWithTimeout(By.text("VPN settings")).click() + val scrollView2 = device.findObjectWithTimeout(By.res(SETTINGS_SCROLL_VIEW_TEST_TAG)) + scrollView2.scrollUntil( + Direction.DOWN, + Until.hasObject(By.res(WIREGUARD_OBFUSCATION_UDP_OVER_TCP_CELL_TEST_TAG)), + ) + device + .findObjectWithTimeout(By.res(WIREGUARD_OBFUSCATION_UDP_OVER_TCP_CELL_TEST_TAG)) + .click() + device.pressBack() + device.pressBack() + + // Ensure it is possible to connect by using UDP-over-TCP + device.findObjectWithTimeout(By.text("Connect")).click() + device.findObjectWithTimeout(By.text("CONNECTED"), EXTREMELY_LONG_TIMEOUT) + device.findObjectWithTimeout(By.text("Disconnect")).click() + } + + private fun enableLocalNetworkSharing() { + device.findObjectWithTimeout(By.res(TOP_BAR_SETTINGS_BUTTON)).click() + device.findObjectWithTimeout(By.text("VPN settings")).click() + + val localNetworkSharingCell = + device.findObjectWithTimeout(By.text("Local network sharing")).parent + val localNetworkSharingSwitch = + localNetworkSharingCell.findObjectWithTimeout(By.res(SWITCH_TEST_TAG)) + + localNetworkSharingSwitch.click() + device.pressBack() + device.pressBack() + } + + private fun clickLocationExpandButton(locationName: String) { + val locationCell = device.findObjectWithTimeout(By.text(locationName)).parent.parent + val expandButton = locationCell.findObjectWithTimeout(By.res(EXPAND_BUTTON_TEST_TAG)) + expandButton.click() + } + + companion object { + const val SETTINGS_SCROLL_VIEW_TEST_TAG = "lazy_list_vpn_settings_test_tag" + const val WIREGUARD_OBFUSCATION_OFF_CELL_TEST_TAG = + "wireguard_obfuscation_off_cell_test_tag" + const val WIREGUARD_OBFUSCATION_UDP_OVER_TCP_CELL_TEST_TAG = + "wireguard_obfuscation_udp_over_tcp_cell_test_tag" + const val UNSUCCESSFUL_CONNECTION_TIMEOUT = 60000L + } } diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LeakTest.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LeakTest.kt index 406671d346..47f2c72068 100644 --- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LeakTest.kt +++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LeakTest.kt @@ -16,9 +16,9 @@ import net.mullvad.mullvadvpn.test.e2e.annotations.HasDependencyOnLocalAPI import net.mullvad.mullvadvpn.test.e2e.misc.AccountTestRule import net.mullvad.mullvadvpn.test.e2e.misc.LeakCheck import net.mullvad.mullvadvpn.test.e2e.misc.NoTrafficToHostRule -import net.mullvad.mullvadvpn.test.e2e.misc.PacketCapture -import net.mullvad.mullvadvpn.test.e2e.misc.PacketCaptureResult import net.mullvad.mullvadvpn.test.e2e.misc.TrafficGenerator +import net.mullvad.mullvadvpn.test.e2e.router.packetCapture.PacketCapture +import net.mullvad.mullvadvpn.test.e2e.router.packetCapture.PacketCaptureResult import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.RegisterExtension diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/annotations/HasDependencyOnLocalAPI.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/annotations/HasDependencyOnLocalAPI.kt index c6c9a70ee9..12987df9e0 100644 --- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/annotations/HasDependencyOnLocalAPI.kt +++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/annotations/HasDependencyOnLocalAPI.kt @@ -1,7 +1,6 @@ package net.mullvad.mullvadvpn.test.e2e.annotations import androidx.test.platform.app.InstrumentationRegistry -import net.mullvad.mullvadvpn.test.e2e.constant.ENABLE_ACCESS_TO_LOCAL_API_TESTS import net.mullvad.mullvadvpn.test.e2e.extension.getRequiredArgument import org.junit.jupiter.api.extension.ConditionEvaluationResult import org.junit.jupiter.api.extension.ExecutionCondition @@ -22,7 +21,7 @@ annotation class HasDependencyOnLocalAPI { val enable = InstrumentationRegistry.getArguments() - .getRequiredArgument(ENABLE_ACCESS_TO_LOCAL_API_TESTS) + .getRequiredArgument("enable_access_to_local_api_tests") .toBoolean() return if (enable) { diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/misc/ClearFirewallRules.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/misc/ClearFirewallRules.kt new file mode 100644 index 0000000000..5fe73e04c7 --- /dev/null +++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/misc/ClearFirewallRules.kt @@ -0,0 +1,24 @@ +package net.mullvad.mullvadvpn.test.e2e.misc + +import kotlinx.coroutines.runBlocking +import net.mullvad.mullvadvpn.test.e2e.router.firewall.FirewallClient +import org.junit.jupiter.api.extension.AfterTestExecutionCallback +import org.junit.jupiter.api.extension.BeforeTestExecutionCallback +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.api.extension.ExtensionContext + +@Retention(AnnotationRetention.RUNTIME) +@ExtendWith(ClearFirewallRules.ClearFirewallRulesAfterTest::class) +annotation class ClearFirewallRules { + class ClearFirewallRulesAfterTest : BeforeTestExecutionCallback, AfterTestExecutionCallback { + val firewallClient = FirewallClient() + + override fun beforeTestExecution(context: ExtensionContext?) { + runBlocking { firewallClient.removeAllRules() } + } + + override fun afterTestExecution(context: ExtensionContext?) { + runBlocking { firewallClient.removeAllRules() } + } + } +} diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/misc/LeakCheck.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/misc/LeakCheck.kt index cab83f243c..6770551f65 100644 --- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/misc/LeakCheck.kt +++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/misc/LeakCheck.kt @@ -1,6 +1,6 @@ package net.mullvad.mullvadvpn.test.e2e.misc -import net.mullvad.mullvadvpn.test.e2e.model.Stream +import net.mullvad.mullvadvpn.test.e2e.router.packetCapture.Stream import org.junit.jupiter.api.Assertions.assertFalse import org.junit.jupiter.api.Assertions.assertTrue diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/NetworkingProtocol.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/NetworkingProtocol.kt new file mode 100644 index 0000000000..7cc12a9250 --- /dev/null +++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/NetworkingProtocol.kt @@ -0,0 +1,11 @@ +package net.mullvad.mullvadvpn.test.e2e.router + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +enum class NetworkingProtocol { + @SerialName("tcp") TCP, + @SerialName("udp") UDP, + @SerialName("icmp") ICMP, +} diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/firewall/DropRule.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/firewall/DropRule.kt new file mode 100644 index 0000000000..627ecdc0fe --- /dev/null +++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/firewall/DropRule.kt @@ -0,0 +1,26 @@ +package net.mullvad.mullvadvpn.test.e2e.router.firewall + +import android.annotation.SuppressLint +import kotlinx.serialization.EncodeDefault +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import net.mullvad.mullvadvpn.test.e2e.misc.Networking +import net.mullvad.mullvadvpn.test.e2e.router.NetworkingProtocol + +@SuppressLint("HardwareIds") +@OptIn(ExperimentalSerializationApi::class) +@Serializable +data class DropRule( + @SerialName("src") val source: String, + @SerialName("dst") val destination: String, + val protocols: List<NetworkingProtocol>, + @EncodeDefault val label: String = "urn:uuid:${SessionIdentifier.fromDeviceIdentifier()}", +) { + companion object { + fun blockUDPTrafficRule(to: String): DropRule { + val testDeviceIpAddress = Networking.getDeviceIpv4Address() + return DropRule(testDeviceIpAddress, to, listOf(NetworkingProtocol.UDP)) + } + } +} diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/firewall/FirewallClient.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/firewall/FirewallClient.kt new file mode 100644 index 0000000000..fabfee0132 --- /dev/null +++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/firewall/FirewallClient.kt @@ -0,0 +1,73 @@ +package net.mullvad.mullvadvpn.test.e2e.router.firewall + +import co.touchlab.kermit.Logger +import io.ktor.client.HttpClient +import io.ktor.client.call.body +import io.ktor.client.engine.cio.CIO +import io.ktor.client.plugins.HttpResponseValidator +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.client.plugins.defaultRequest +import io.ktor.client.request.delete +import io.ktor.client.request.post +import io.ktor.client.request.setBody +import io.ktor.http.ContentType +import io.ktor.http.contentType +import io.ktor.serialization.kotlinx.json.json +import kotlinx.serialization.json.Json +import kotlinx.serialization.modules.SerializersModule +import kotlinx.serialization.modules.contextual +import net.mullvad.mullvadvpn.test.e2e.BuildConfig +import net.mullvad.mullvadvpn.test.e2e.serializer.NanoSecondsTimestampSerializer +import org.junit.jupiter.api.fail + +class FirewallClient(private val httpClient: HttpClient = defaultHttpClient()) { + suspend fun createRule(rule: DropRule) { + Logger.v( + "Sending create rule request with body: ${Json.encodeToString(DropRule.serializer(), rule)}" + ) + Logger.v( + "Requesting firewall API to block ${rule.protocols} traffic from ${rule.source} to ${rule.destination}" + ) + httpClient.post("rule") { + contentType(ContentType.Application.Json) + setBody(Json.encodeToString(DropRule.serializer(), rule)) + } + } + + suspend fun removeAllRules() { + Logger.v("Sending remove all rules request") + httpClient.delete("remove-rules/${SessionIdentifier.fromDeviceIdentifier()}") + } +} + +private fun defaultHttpClient(): HttpClient = + HttpClient(CIO) { + defaultRequest { url("http://${BuildConfig.TEST_ROUTER_API_HOST}") } + + install(ContentNegotiation) { + json( + Json { + isLenient = true + prettyPrint = true + + serializersModule = SerializersModule { + contextual(NanoSecondsTimestampSerializer) + } + } + ) + } + + HttpResponseValidator { + validateResponse { response -> + val statusCode = response.status.value + if (statusCode >= 400) { + fail( + "Request failed with response status code $statusCode: ${response.body<String>()}" + ) + } + } + handleResponseExceptionWithRequest { exception, _ -> + fail("Request failed to be sent with exception: ${exception.message}") + } + } + } diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/firewall/SessionIdentifier.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/firewall/SessionIdentifier.kt new file mode 100644 index 0000000000..4838c36486 --- /dev/null +++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/firewall/SessionIdentifier.kt @@ -0,0 +1,28 @@ +package net.mullvad.mullvadvpn.test.e2e.router.firewall + +import android.annotation.SuppressLint +import android.provider.Settings +import androidx.test.platform.app.InstrumentationRegistry +import java.util.UUID +import kotlinx.serialization.Serializable + +@JvmInline +@Serializable +value class SessionIdentifier(val value: String) { + override fun toString(): String = value + + companion object { + @SuppressLint("HardwareIds") + fun fromDeviceIdentifier(): SessionIdentifier { + val deviceIdentifier = + Settings.Secure.getString( + InstrumentationRegistry.getInstrumentation().targetContext.contentResolver, + Settings.Secure.ANDROID_ID, + ) + + return SessionIdentifier( + UUID.nameUUIDFromBytes(deviceIdentifier.toByteArray()).toString() + ) + } + } +} diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/model/Host.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/packetCapture/Host.kt index d59e15d017..0a7a2a5605 100644 --- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/model/Host.kt +++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/packetCapture/Host.kt @@ -1,4 +1,4 @@ -package net.mullvad.mullvadvpn.test.e2e.model +package net.mullvad.mullvadvpn.test.e2e.router.packetCapture data class Host(val ipAddress: String, val port: Int) { companion object { diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/model/Packet.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/packetCapture/Packet.kt index df5c5a57b9..5c788e5710 100644 --- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/model/Packet.kt +++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/packetCapture/Packet.kt @@ -1,4 +1,4 @@ -package net.mullvad.mullvadvpn.test.e2e.model +package net.mullvad.mullvadvpn.test.e2e.router.packetCapture import kotlinx.serialization.Contextual import kotlinx.serialization.SerialName diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/misc/PacketCapture.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/packetCapture/PacketCapture.kt index aa167c55b4..7854170114 100644 --- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/misc/PacketCapture.kt +++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/packetCapture/PacketCapture.kt @@ -1,4 +1,4 @@ -package net.mullvad.mullvadvpn.test.e2e.misc +package net.mullvad.mullvadvpn.test.e2e.router.packetCapture import co.touchlab.kermit.Logger import io.ktor.client.HttpClient @@ -23,7 +23,7 @@ import kotlinx.serialization.json.Json import kotlinx.serialization.modules.SerializersModule import kotlinx.serialization.modules.contextual import net.mullvad.mullvadvpn.test.e2e.BuildConfig -import net.mullvad.mullvadvpn.test.e2e.model.Stream +import net.mullvad.mullvadvpn.test.e2e.misc.Networking import net.mullvad.mullvadvpn.test.e2e.serializer.NanoSecondsTimestampSerializer import net.mullvad.mullvadvpn.test.e2e.serializer.PacketCaptureSessionSerializer import org.junit.jupiter.api.fail @@ -63,7 +63,7 @@ class PacketCapture { private fun defaultHttpClient(): HttpClient = HttpClient(CIO) { - defaultRequest { url("http://${BuildConfig.PACKET_CAPTURE_API_HOST}") } + defaultRequest { url("http://${BuildConfig.TEST_ROUTER_API_HOST}") } install(ContentNegotiation) { json( diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/model/Stream.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/packetCapture/Stream.kt index 38feff34d6..564d0e25cb 100644 --- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/model/Stream.kt +++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/packetCapture/Stream.kt @@ -1,8 +1,9 @@ -package net.mullvad.mullvadvpn.test.e2e.model +package net.mullvad.mullvadvpn.test.e2e.router.packetCapture import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.Transient +import net.mullvad.mullvadvpn.test.e2e.router.NetworkingProtocol import org.joda.time.DateTime import org.joda.time.Interval @@ -11,7 +12,7 @@ data class Stream( @SerialName("peer_addr") private val sourceAddressAndPort: String, @SerialName("other_addr") private val destinationAddressAndPort: String, @SerialName("flow_id") val flowId: String?, - @SerialName("transport_protocol") val transportProtocol: NetworkTransportProtocol, + @SerialName("transport_protocol") val transportProtocol: NetworkingProtocol, val packets: List<Packet>, ) { @Transient val sourceHost = Host.fromString(sourceAddressAndPort) @@ -40,10 +41,3 @@ data class Stream( require(packets.isNotEmpty()) { "Stream must contain at least one packet" } } } - -@Serializable -enum class NetworkTransportProtocol { - @SerialName("tcp") TCP, - @SerialName("udp") UDP, - @SerialName("icmp") ICMP, -} diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/serializer/PacketCaptureSessionSerializer.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/serializer/PacketCaptureSessionSerializer.kt index 8ec1a8bed9..16824af178 100644 --- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/serializer/PacketCaptureSessionSerializer.kt +++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/serializer/PacketCaptureSessionSerializer.kt @@ -6,7 +6,7 @@ import kotlinx.serialization.builtins.serializer import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder -import net.mullvad.mullvadvpn.test.e2e.misc.PacketCaptureSession +import net.mullvad.mullvadvpn.test.e2e.router.packetCapture.PacketCaptureSession object PacketCaptureSessionSerializer : KSerializer<PacketCaptureSession> { override val descriptor: SerialDescriptor = String.serializer().descriptor diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/serializer/PacketSerializer.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/serializer/PacketSerializer.kt index 60391218b4..b3617a6b65 100644 --- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/serializer/PacketSerializer.kt +++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/serializer/PacketSerializer.kt @@ -6,9 +6,9 @@ import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.booleanOrNull import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonPrimitive -import net.mullvad.mullvadvpn.test.e2e.model.Packet -import net.mullvad.mullvadvpn.test.e2e.model.RxPacket -import net.mullvad.mullvadvpn.test.e2e.model.TxPacket +import net.mullvad.mullvadvpn.test.e2e.router.packetCapture.Packet +import net.mullvad.mullvadvpn.test.e2e.router.packetCapture.RxPacket +import net.mullvad.mullvadvpn.test.e2e.router.packetCapture.TxPacket object PacketSerializer : JsonContentPolymorphicSerializer<Packet>(Packet::class) { override fun selectDeserializer(element: JsonElement): KSerializer<out Packet> { |
