diff options
| author | Bug Magnet <marco.nikic@mullvad.net> | 2024-02-14 11:30:41 +0100 |
|---|---|---|
| committer | Bug Magnet <marco.nikic@mullvad.net> | 2024-02-14 11:30:41 +0100 |
| commit | 5c29187dbc4104d2f81f5c8e2cd53299a78c53fe (patch) | |
| tree | c0157efc23ee39ee0ed0384c90ed14802a1e4137 | |
| parent | 3a7fdd497202182f28c7eba45fbb9c563f444f6c (diff) | |
| parent | bf96edc4621f21e4c4f0da2127e234c2932a996a (diff) | |
| download | mullvadvpn-5c29187dbc4104d2f81f5c8e2cd53299a78c53fe.tar.xz mullvadvpn-5c29187dbc4104d2f81f5c8e2cd53299a78c53fe.zip | |
Merge branch 'test-api-connection-via-alternative-means-ios-438'
19 files changed, 584 insertions, 98 deletions
diff --git a/ios/Configurations/UITests.xcconfig.template b/ios/Configurations/UITests.xcconfig.template index 2ed40f1624..0584179b3d 100644 --- a/ios/Configurations/UITests.xcconfig.template +++ b/ios/Configurations/UITests.xcconfig.template @@ -1,19 +1,18 @@ -// -// MullvadVPNUITests.xcconfig -// MullvadVPN -// -// Created by Niklas Berglund on 2024-01-10. -// Copyright © 2024 Mullvad VPN AB. All rights reserved. -// +#include "Base.xcconfig" // Pin code of the iOS device under test -MULLVAD_IOS_DEVICE_PIN_CODE = +IOS_DEVICE_PIN_CODE = -// Ad serving domain used when testing ad blocking. Not that we are assuming there's an HTTP server running on the host. -MULLVAD_AD_SERVING_DOMAIN = +// UUID to identify test runs. Should be unique per test device. Generate with for example uuidgen on macOS. +TEST_DEVICE_IDENTIFIER_UUID = // Mullvad accounts used by UI tests -MULLVAD_NO_TIME_ACCOUNT_NUMBER = -MULLVAD_HAS_TIME_ACCOUNT_NUMBER = -MULLVAD_FIVE_WIREGUARD_KEYS_ACCOUNT_NUMBER = +NO_TIME_ACCOUNT_NUMBER = +HAS_TIME_ACCOUNT_NUMBER = +FIVE_WIREGUARD_KEYS_ACCOUNT_NUMBER = + +// Ad serving domain used when testing ad blocking. Note that we are assuming there's an HTTP server running on the host. +AD_SERVING_DOMAIN = vpnlist.to +// Base URL for the firewall API, Note that // will be treated as a comment, therefor you need to insert a ${} between the slashes for example http:/${}/8.8.8.8 +FIREWALL_API_BASE_URL = http:/${}/8.8.8.8 diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index e2ad8ebbcc..b7685c0ad8 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -38,10 +38,10 @@ 06799AFC28F98EE300ACD94E /* AddressCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06AC114128F8413A0037AF9A /* AddressCache.swift */; }; 0697D6E728F01513007A9E99 /* TransportMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0697D6E628F01513007A9E99 /* TransportMonitor.swift */; }; 06AC116228F94C450037AF9A /* ApplicationConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58BFA5CB22A7CE1F00A6173D /* ApplicationConfiguration.swift */; }; - 44DD7D2D2B74E44A0005F67F /* QuantumResistanceSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44DD7D2C2B74E44A0005F67F /* QuantumResistanceSettings.swift */; }; 44DD7D242B6CFFD70005F67F /* StartTunnelOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44DD7D232B6CFFD70005F67F /* StartTunnelOperationTests.swift */; }; 44DD7D272B6D18FB0005F67F /* MockTunnelInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44DD7D262B6D18FB0005F67F /* MockTunnelInteractor.swift */; }; 44DD7D292B7113CA0005F67F /* MockTunnel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44DD7D282B7113CA0005F67F /* MockTunnel.swift */; }; + 44DD7D2D2B74E44A0005F67F /* QuantumResistanceSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44DD7D2C2B74E44A0005F67F /* QuantumResistanceSettings.swift */; }; 5803B4B02940A47300C23744 /* TunnelConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5803B4AF2940A47300C23744 /* TunnelConfiguration.swift */; }; 5803B4B22940A48700C23744 /* TunnelStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5803B4B12940A48700C23744 /* TunnelStore.swift */; }; 5807E2C02432038B00F5FF30 /* String+Split.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5807E2BF2432038B00F5FF30 /* String+Split.swift */; }; @@ -590,13 +590,18 @@ 852969362B4E9724007EAD4C /* AccessbilityIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A0B311D2B303A0D004B12E0 /* AccessbilityIdentifier.swift */; }; 8529693A2B4F0238007EAD4C /* TermsOfServicePage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 852969392B4F0238007EAD4C /* TermsOfServicePage.swift */; }; 8529693C2B4F0257007EAD4C /* Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8529693B2B4F0257007EAD4C /* Alert.swift */; }; + 85557B0E2B591B2600795FE1 /* FirewallAPIClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85557B0D2B591B2600795FE1 /* FirewallAPIClient.swift */; }; + 85557B102B59215F00795FE1 /* FirewallRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85557B0F2B59215F00795FE1 /* FirewallRule.swift */; }; + 85557B122B594FC900795FE1 /* ConnectivityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85557B112B594FC900795FE1 /* ConnectivityTests.swift */; }; + 85557B142B5983CF00795FE1 /* MullvadAPIWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85557B132B5983CF00795FE1 /* MullvadAPIWrapper.swift */; }; 85557B162B5ABBBE00795FE1 /* XCUIElementQuery+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85557B152B5ABBBE00795FE1 /* XCUIElementQuery+Extensions.swift */; }; 85557B1E2B5FB8C700795FE1 /* HeaderBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85557B1D2B5FB8C700795FE1 /* HeaderBar.swift */; }; 85557B202B5FBBD700795FE1 /* AccountPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85557B1F2B5FBBD700795FE1 /* AccountPage.swift */; }; + 855D9F5B2B63E56B00D7C64D /* ProblemReportPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 855D9F5A2B63E56B00D7C64D /* ProblemReportPage.swift */; }; 8590896C2B61763B003AF5F5 /* LoggedInWithoutTimeUITestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 859089682B61763B003AF5F5 /* LoggedInWithoutTimeUITestCase.swift */; }; - 8590896D2B61763B003AF5F5 /* LoggedInWithTimeUITestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 859089692B61763B003AF5F5 /* LoggedInWithTimeUITestCase.swift */; }; - 8590896E2B61763B003AF5F5 /* BaseUITestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8590896A2B61763B003AF5F5 /* BaseUITestCase.swift */; }; 8590896F2B61763B003AF5F5 /* LoggedOutUITestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8590896B2B61763B003AF5F5 /* LoggedOutUITestCase.swift */; }; + 85D2B0B12B6BD32400DF9DA7 /* BaseUITestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8590896A2B61763B003AF5F5 /* BaseUITestCase.swift */; }; + 85E3BDE52B70E18C00FA71FD /* Networking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85E3BDE42B70E18C00FA71FD /* Networking.swift */; }; A900E9B82ACC5C2B00C95F67 /* AccountsProxy+Stubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = A900E9B72ACC5C2B00C95F67 /* AccountsProxy+Stubs.swift */; }; A900E9BA2ACC5D0600C95F67 /* RESTRequestExecutor+Stubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = A900E9B92ACC5D0600C95F67 /* RESTRequestExecutor+Stubs.swift */; }; A900E9BC2ACC609200C95F67 /* DevicesProxy+Stubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = A900E9BB2ACC609200C95F67 /* DevicesProxy+Stubs.swift */; }; @@ -1245,10 +1250,10 @@ 06FAE67A28F83CA50033DD93 /* RESTDevicesProxy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RESTDevicesProxy.swift; sourceTree = "<group>"; }; 06FAE67B28F83CA50033DD93 /* REST.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = REST.swift; sourceTree = "<group>"; }; 06FAE67D28F83CA50033DD93 /* RESTTransport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RESTTransport.swift; sourceTree = "<group>"; }; - 44DD7D2C2B74E44A0005F67F /* QuantumResistanceSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuantumResistanceSettings.swift; sourceTree = "<group>"; }; 44DD7D232B6CFFD70005F67F /* StartTunnelOperationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartTunnelOperationTests.swift; sourceTree = "<group>"; }; 44DD7D262B6D18FB0005F67F /* MockTunnelInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockTunnelInteractor.swift; sourceTree = "<group>"; }; 44DD7D282B7113CA0005F67F /* MockTunnel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockTunnel.swift; sourceTree = "<group>"; }; + 44DD7D2C2B74E44A0005F67F /* QuantumResistanceSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuantumResistanceSettings.swift; sourceTree = "<group>"; }; 5802EBC42A8E44AC00E5CE4C /* AppRoutes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRoutes.swift; sourceTree = "<group>"; }; 5802EBC62A8E457A00E5CE4C /* AppRouteProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRouteProtocol.swift; sourceTree = "<group>"; }; 5802EBC82A8E45BA00E5CE4C /* ApplicationRouterDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationRouterDelegate.swift; sourceTree = "<group>"; }; @@ -1774,13 +1779,19 @@ 852969382B4ED818007EAD4C /* UITests.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = UITests.xcconfig; sourceTree = "<group>"; }; 852969392B4F0238007EAD4C /* TermsOfServicePage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TermsOfServicePage.swift; sourceTree = "<group>"; }; 8529693B2B4F0257007EAD4C /* Alert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Alert.swift; sourceTree = "<group>"; }; + 85557B0D2B591B2600795FE1 /* FirewallAPIClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirewallAPIClient.swift; sourceTree = "<group>"; }; + 85557B0F2B59215F00795FE1 /* FirewallRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirewallRule.swift; sourceTree = "<group>"; }; + 85557B112B594FC900795FE1 /* ConnectivityTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectivityTests.swift; sourceTree = "<group>"; }; + 85557B132B5983CF00795FE1 /* MullvadAPIWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MullvadAPIWrapper.swift; sourceTree = "<group>"; }; 85557B152B5ABBBE00795FE1 /* XCUIElementQuery+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "XCUIElementQuery+Extensions.swift"; sourceTree = "<group>"; }; 85557B1D2B5FB8C700795FE1 /* HeaderBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderBar.swift; sourceTree = "<group>"; }; 85557B1F2B5FBBD700795FE1 /* AccountPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountPage.swift; sourceTree = "<group>"; }; + 855D9F5A2B63E56B00D7C64D /* ProblemReportPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProblemReportPage.swift; sourceTree = "<group>"; }; 859089682B61763B003AF5F5 /* LoggedInWithoutTimeUITestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoggedInWithoutTimeUITestCase.swift; sourceTree = "<group>"; }; 859089692B61763B003AF5F5 /* LoggedInWithTimeUITestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoggedInWithTimeUITestCase.swift; sourceTree = "<group>"; }; 8590896A2B61763B003AF5F5 /* BaseUITestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseUITestCase.swift; sourceTree = "<group>"; }; 8590896B2B61763B003AF5F5 /* LoggedOutUITestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoggedOutUITestCase.swift; sourceTree = "<group>"; }; + 85E3BDE42B70E18C00FA71FD /* Networking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Networking.swift; sourceTree = "<group>"; }; A900E9B72ACC5C2B00C95F67 /* AccountsProxy+Stubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AccountsProxy+Stubs.swift"; sourceTree = "<group>"; }; A900E9B92ACC5D0600C95F67 /* RESTRequestExecutor+Stubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RESTRequestExecutor+Stubs.swift"; sourceTree = "<group>"; }; A900E9BB2ACC609200C95F67 /* DevicesProxy+Stubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DevicesProxy+Stubs.swift"; sourceTree = "<group>"; }; @@ -3390,12 +3401,14 @@ 852969262B4D9C1F007EAD4C /* MullvadVPNUITests */ = { isa = PBXGroup; children = ( - 8518F6392B601910009EB113 /* Test base classes */, - 852969312B4E9220007EAD4C /* Pages */, 852969272B4D9C1F007EAD4C /* AccountTests.swift */, + 85557B112B594FC900795FE1 /* ConnectivityTests.swift */, + 852969372B4ED20E007EAD4C /* Info.plist */, + 85557B0C2B591B0F00795FE1 /* Networking */, + 852969312B4E9220007EAD4C /* Pages */, 850201DA2B503D7700EF8C96 /* RelayTests.swift */, + 8518F6392B601910009EB113 /* Test base classes */, 85557B152B5ABBBE00795FE1 /* XCUIElementQuery+Extensions.swift */, - 852969372B4ED20E007EAD4C /* Info.plist */, ); path = MullvadVPNUITests; sourceTree = "<group>"; @@ -3403,19 +3416,31 @@ 852969312B4E9220007EAD4C /* Pages */ = { isa = PBXGroup; children = ( + 85557B1F2B5FBBD700795FE1 /* AccountPage.swift */, 8529693B2B4F0257007EAD4C /* Alert.swift */, + 85557B1D2B5FB8C700795FE1 /* HeaderBar.swift */, 852969342B4E9270007EAD4C /* LoginPage.swift */, 852969322B4E9232007EAD4C /* Page.swift */, + 855D9F5A2B63E56B00D7C64D /* ProblemReportPage.swift */, 850201DC2B503D8C00EF8C96 /* SelectLocationPage.swift */, 850201E22B51A93C00EF8C96 /* SettingsPage.swift */, - 850201DE2B5040A500EF8C96 /* TunnelControlPage.swift */, - 85557B1D2B5FB8C700795FE1 /* HeaderBar.swift */, 852969392B4F0238007EAD4C /* TermsOfServicePage.swift */, - 85557B1F2B5FBBD700795FE1 /* AccountPage.swift */, + 850201DE2B5040A500EF8C96 /* TunnelControlPage.swift */, ); path = Pages; sourceTree = "<group>"; }; + 85557B0C2B591B0F00795FE1 /* Networking */ = { + isa = PBXGroup; + children = ( + 85557B0D2B591B2600795FE1 /* FirewallAPIClient.swift */, + 85557B0F2B59215F00795FE1 /* FirewallRule.swift */, + 85557B132B5983CF00795FE1 /* MullvadAPIWrapper.swift */, + 85E3BDE42B70E18C00FA71FD /* Networking.swift */, + ); + path = Networking; + sourceTree = "<group>"; + }; A907639F2B2857D50045ADF0 /* Socks5 */ = { isa = PBXGroup; children = ( @@ -5291,23 +5316,29 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8590896D2B61763B003AF5F5 /* LoggedInWithTimeUITestCase.swift in Sources */, + 85D2B0B12B6BD32400DF9DA7 /* BaseUITestCase.swift in Sources */, 8529693C2B4F0257007EAD4C /* Alert.swift in Sources */, 850201DD2B503D8C00EF8C96 /* SelectLocationPage.swift in Sources */, 850201DB2B503D7700EF8C96 /* RelayTests.swift in Sources */, + 85557B142B5983CF00795FE1 /* MullvadAPIWrapper.swift in Sources */, 852969362B4E9724007EAD4C /* AccessbilityIdentifier.swift in Sources */, + 85E3BDE52B70E18C00FA71FD /* Networking.swift in Sources */, 8590896C2B61763B003AF5F5 /* LoggedInWithoutTimeUITestCase.swift in Sources */, 8590896F2B61763B003AF5F5 /* LoggedOutUITestCase.swift in Sources */, 85557B202B5FBBD700795FE1 /* AccountPage.swift in Sources */, 852969352B4E9270007EAD4C /* LoginPage.swift in Sources */, - 8590896E2B61763B003AF5F5 /* BaseUITestCase.swift in Sources */, 850201E32B51A93C00EF8C96 /* SettingsPage.swift in Sources */, 8518F6382B60157E009EB113 /* LoggedInWithoutTimeUITestCase.swift in Sources */, + 85557B102B59215F00795FE1 /* FirewallRule.swift in Sources */, + 850201E32B51A93C00EF8C96 /* SettingsPage.swift in Sources */, + 85557B0E2B591B2600795FE1 /* FirewallAPIClient.swift in Sources */, 852969282B4D9C1F007EAD4C /* AccountTests.swift in Sources */, 85557B162B5ABBBE00795FE1 /* XCUIElementQuery+Extensions.swift in Sources */, + 855D9F5B2B63E56B00D7C64D /* ProblemReportPage.swift in Sources */, 8529693A2B4F0238007EAD4C /* TermsOfServicePage.swift in Sources */, 850201DF2B5040A500EF8C96 /* TunnelControlPage.swift in Sources */, 85557B1E2B5FB8C700795FE1 /* HeaderBar.swift in Sources */, + 85557B122B594FC900795FE1 /* ConnectivityTests.swift in Sources */, 852969332B4E9232007EAD4C /* Page.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/MullvadVPNUITests.xcscheme b/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/MullvadVPNUITests.xcscheme index 45ec07ec85..7c65faea3b 100644 --- a/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/MullvadVPNUITests.xcscheme +++ b/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/MullvadVPNUITests.xcscheme @@ -40,7 +40,8 @@ debugDocumentVersioning = "YES" debugServiceExtension = "internal" allowLocationSimulation = "YES"> - <MacroExpansion> + <BuildableProductRunnable + runnableDebuggingMode = "0"> <BuildableReference BuildableIdentifier = "primary" BlueprintIdentifier = "58CE5E5F224146200008646E" @@ -48,7 +49,7 @@ BlueprintName = "MullvadVPN" ReferencedContainer = "container:MullvadVPN.xcodeproj"> </BuildableReference> - </MacroExpansion> + </BuildableProductRunnable> </LaunchAction> <ProfileAction buildConfiguration = "Release" @@ -56,6 +57,15 @@ savedToolIdentifier = "" useCustomWorkingDirectory = "NO" debugDocumentVersioning = "YES"> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "58CE5E5F224146200008646E" + BuildableName = "MullvadVPN.app" + BlueprintName = "MullvadVPN" + ReferencedContainer = "container:MullvadVPN.xcodeproj"> + </BuildableReference> + </MacroExpansion> </ProfileAction> <AnalyzeAction buildConfiguration = "Debug"> diff --git a/ios/MullvadVPN/Classes/AccessbilityIdentifier.swift b/ios/MullvadVPN/Classes/AccessbilityIdentifier.swift index 24a87ed14f..855ea3c748 100644 --- a/ios/MullvadVPN/Classes/AccessbilityIdentifier.swift +++ b/ios/MullvadVPN/Classes/AccessbilityIdentifier.swift @@ -27,9 +27,12 @@ public enum AccessibilityIdentifier: String { case purchaseButton case redeemVoucherButton case restorePurchasesButton + case secureConnectionButton case selectLocationButton case settingsButton case startUsingTheAppButton + case problemReportAppLogsButton + case problemReportSendButton // Cells case preferencesCell @@ -43,6 +46,7 @@ public enum AccessibilityIdentifier: String { // Labels case headerDeviceNameLabel + case connectionStatusLabel // Views case accountView @@ -55,6 +59,7 @@ public enum AccessibilityIdentifier: String { case selectLocationTableView case settingsTableView case tunnelControlView + case problemReportView // Other UI elements case connectionPanelInAddressRow @@ -63,6 +68,8 @@ public enum AccessibilityIdentifier: String { case dnsContentBlockersHeaderView case loginTextField case selectLocationSearchTextField + case problemReportEmailTextField + case problemReportMessageTextView // DNS settings case dnsSettings diff --git a/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportViewController.swift b/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportViewController.swift index 45292672d3..f255b43b51 100644 --- a/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportViewController.swift +++ b/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportViewController.swift @@ -75,6 +75,7 @@ final class ProblemReportViewController: UIViewController, UITextFieldDelegate { super.viewDidLoad() view.backgroundColor = .secondaryColor + view.accessibilityIdentifier = .problemReportView navigationItem.title = Self.persistentViewModel.navigationTitle @@ -90,6 +91,9 @@ final class ProblemReportViewController: UIViewController, UITextFieldDelegate { messageTextView.setContentHuggingPriority(.defaultLow, for: .vertical) messageTextView.setContentCompressionResistancePriority(.defaultLow, for: .vertical) + emailTextField.accessibilityIdentifier = .problemReportEmailTextField + messageTextView.accessibilityIdentifier = .problemReportMessageTextView + addConstraints() registerForNotifications() loadPersistentViewModel() diff --git a/ios/MullvadVPN/View controllers/Tunnel/TunnelControlView.swift b/ios/MullvadVPN/View controllers/Tunnel/TunnelControlView.swift index e1f393b1b7..bd991142e6 100644 --- a/ios/MullvadVPN/View controllers/Tunnel/TunnelControlView.swift +++ b/ios/MullvadVPN/View controllers/Tunnel/TunnelControlView.swift @@ -64,6 +64,7 @@ final class TunnelControlView: UIView { private let connectButton: AppButton = { let button = AppButton(style: .success) + button.accessibilityIdentifier = .secureConnectionButton button.translatesAutoresizingMaskIntoConstraints = false return button }() @@ -120,6 +121,8 @@ final class TunnelControlView: UIView { accessibilityContainerType = .semanticGroup accessibilityIdentifier = .tunnelControlView + secureLabel.accessibilityIdentifier = .connectionStatusLabel + addSubviews() addButtonHandlers() } diff --git a/ios/MullvadVPNUITests/ConnectivityTests.swift b/ios/MullvadVPNUITests/ConnectivityTests.swift new file mode 100644 index 0000000000..1c4e46ac14 --- /dev/null +++ b/ios/MullvadVPNUITests/ConnectivityTests.swift @@ -0,0 +1,52 @@ +// +// ConnectivityTests.swift +// MullvadVPNUITests +// +// Created by Niklas Berglund on 2024-01-18. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import Network +import XCTest + +class ConnectivityTests: LoggedOutUITestCase { + let firewallAPIClient = FirewallAPIClient() + + override func setUpWithError() throws { + super.setUp() + } + + override func tearDownWithError() throws { + super.tearDown() + firewallAPIClient.removeRules() + } + + /// Verifies that the app still functions when API has been blocked + func testAPIConnectionViaBridges() throws { + let app = XCUIApplication() + app.launch() + + try Networking.verifyCanAccessAPI() // Just to make sure there's no old firewall rule still active + firewallAPIClient.createRule(try FirewallRule.makeBlockAPIAccessFirewallRule()) + try Networking.verifyCannotAccessAPI() + + LoginPage(app) + .tapAccountNumberTextField() + .enterText(self.hasTimeAccountNumber) + .tapAccountNumberSubmitButton() + + // After creating firewall rule first login attempt might fail. One more attempt is allowed since the app is cycling between two methods. + if isLoggedIn() { + LoginPage(app) + .verifySuccessIconShown() + .verifyDeviceLabelShown() + } else { + LoginPage(app) + .verifyFailIconShown() + .tapAccountNumberSubmitButton() + .verifySuccessIconShown() + .verifyDeviceLabelShown() + } + } +} diff --git a/ios/MullvadVPNUITests/Info.plist b/ios/MullvadVPNUITests/Info.plist index 85eb161b49..dd7e65bae2 100644 --- a/ios/MullvadVPNUITests/Info.plist +++ b/ios/MullvadVPNUITests/Info.plist @@ -2,17 +2,25 @@ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> - <key>MullvadAdServingDomain</key> - <string>$(MULLVAD_AD_SERVING_DOMAIN)</string> - <key>MullvadDisplayName</key> + <key>AdServingDomain</key> + <string>$(AD_SERVING_DOMAIN)</string> + <key>ApiEndpoint</key> + <string>$(API_ENDPOINT)</string> + <key>ApiHostName</key> + <string>$(API_HOST_NAME)</string> + <key>DisplayName</key> <string>$(DISPLAY_NAME)</string> - <key>MullvadFiveWireGuardKeysAccountNumber</key> - <string>$(MULLVAD_FIVE_WIREGUARD_KEYS_ACCOUNT_NUMBER)</string> - <key>MullvadHasTimeAccountNumber</key> - <string>$(MULLVAD_HAS_TIME_ACCOUNT_NUMBER)</string> - <key>MullvadIOSDevicePinCode</key> - <string>$(MULLVAD_IOS_DEVICE_PIN_CODE)</string> - <key>MullvadNoTimeAccountNumber</key> - <string>$(MULLVAD_NO_TIME_ACCOUNT_NUMBER)</string> + <key>FirewallApiBaseURL</key> + <string>$(FIREWALL_API_BASE_URL)</string> + <key>FiveWireGuardKeysAccountNumber</key> + <string>$(FIVE_WIREGUARD_KEYS_ACCOUNT_NUMBER)</string> + <key>HasTimeAccountNumber</key> + <string>$(HAS_TIME_ACCOUNT_NUMBER)</string> + <key>IOSDevicePinCode</key> + <string>$(IOS_DEVICE_PIN_CODE)</string> + <key>NoTimeAccountNumber</key> + <string>$(NO_TIME_ACCOUNT_NUMBER)</string> + <key>TestDeviceIdentifier</key> + <string>$(TEST_DEVICE_IDENTIFIER_UUID</string> </dict> </plist> diff --git a/ios/MullvadVPNUITests/Networking/FirewallAPIClient.swift b/ios/MullvadVPNUITests/Networking/FirewallAPIClient.swift new file mode 100644 index 0000000000..49496f3d2e --- /dev/null +++ b/ios/MullvadVPNUITests/Networking/FirewallAPIClient.swift @@ -0,0 +1,113 @@ +// +// FirewallClient.swift +// MullvadVPNUITests +// +// Created by Niklas Berglund on 2024-01-18. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import SystemConfiguration +import UIKit +import XCTest + +class FirewallAPIClient { + // swiftlint:disable force_cast + let baseURL = URL( + string: + Bundle(for: FirewallAPIClient.self).infoDictionary?["FirewallApiBaseURL"] as! String + )! + let testDeviceIdentifier = Bundle(for: FirewallAPIClient.self).infoDictionary?["TestDeviceIdentifier"] as! String + // swiftlint:enable force_cast + + lazy var sessionIdentifier = "urn:uuid:" + testDeviceIdentifier + + /// Create a new rule associated to the device under test + public func createRule(_ firewallRule: FirewallRule) { + let createRuleURL = baseURL.appendingPathComponent("rule") + + var request = URLRequest(url: createRuleURL) + request.httpMethod = "POST" + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + + let dataDictionary: [String: Any] = [ + "label": sessionIdentifier, + "from": firewallRule.fromIPAddress, + "to": firewallRule.toIPAddress, + ] + + var requestError: Error? + var requestResponse: URLResponse? + let completionHandlerInvokedExpectation = XCTestExpectation( + description: "Completion handler for the request is invoked" + ) + + do { + let jsonData = try JSONSerialization.data(withJSONObject: dataDictionary) + request.httpBody = jsonData + + let dataTask = URLSession.shared.dataTask(with: request) { _, response, error in + requestError = error + requestResponse = response + completionHandlerInvokedExpectation.fulfill() + } + + dataTask.resume() + + let waitResult = XCTWaiter.wait(for: [completionHandlerInvokedExpectation], timeout: 30) + + if waitResult != .completed { + XCTFail("Failed to create firewall rule - timeout") + } else { + if let response = requestResponse as? HTTPURLResponse { + if response.statusCode != 201 { + XCTFail("Failed to create firewall rule - unexpected server response") + } + } + + if let error = requestError { + XCTFail("Failed to create firewall rule - encountered error \(error.localizedDescription)") + } + } + } catch { + XCTFail("Failed to create firewall rule - couldn't serialize JSON") + } + } + + /// Remove all firewall rules associated to this device under test + public func removeRules() { + let removeRulesURL = baseURL.appendingPathComponent("remove-rules/\(sessionIdentifier)") + + var request = URLRequest(url: removeRulesURL) + request.httpMethod = "DELETE" + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + + var requestResponse: URLResponse? + var requestError: Error? + let completionHandlerInvokedExpectation = XCTestExpectation( + description: "Completion handler for the request is invoked" + ) + + let dataTask = URLSession.shared.dataTask(with: request) { _, response, error in + requestResponse = response + requestError = error + completionHandlerInvokedExpectation.fulfill() + } + + dataTask.resume() + + let waitResult = XCTWaiter.wait(for: [completionHandlerInvokedExpectation], timeout: 30) + + if waitResult != .completed { + XCTFail("Failed to remove firewall rules - timeout") + } else { + if let response = requestResponse as? HTTPURLResponse, response.statusCode != 200 { + XCTFail("Failed to remove firewall rules - unexpected server response") + } + + if let error = requestError { + XCTFail("Failed to remove firewall rules - encountered error \(error.localizedDescription)") + } + } + } +} diff --git a/ios/MullvadVPNUITests/Networking/FirewallRule.swift b/ios/MullvadVPNUITests/Networking/FirewallRule.swift new file mode 100644 index 0000000000..d89dbc6853 --- /dev/null +++ b/ios/MullvadVPNUITests/Networking/FirewallRule.swift @@ -0,0 +1,43 @@ +// +// FirewallRule.swift +// MullvadVPNUITests +// +// Created by Niklas Berglund on 2024-01-18. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import XCTest + +enum NetworkingProtocol: String { + case TCP = "tcp" + case UDP = "udp" + case ICMP = "icmp" +} + +struct FirewallRule { + let fromIPAddress: String + let toIPAddress: String + let protocols: [NetworkingProtocol] + + /// - Parameters: + /// - fromIPAddress: Block traffic originating from this source IP address. + /// - toIPAddress: Block traffic to this destination IP address. + /// - protocols: Protocols which should be blocked. If none is specified all will be blocked. + private init(fromIPAddress: String, toIPAddress: String, protocols: [NetworkingProtocol]) { + self.fromIPAddress = fromIPAddress + self.toIPAddress = toIPAddress + self.protocols = protocols + } + + /// Make a firewall rule blocking API access for the current device under test + public static func makeBlockAPIAccessFirewallRule() throws -> FirewallRule { + let deviceIPAddress = try Networking.getIPAddress() + let apiIPAddress = try MullvadAPIWrapper.getAPIIPAddress() + return FirewallRule( + fromIPAddress: deviceIPAddress, + toIPAddress: apiIPAddress, + protocols: [NetworkingProtocol.TCP] + ) + } +} diff --git a/ios/MullvadVPNUITests/Networking/MullvadAPIWrapper.swift b/ios/MullvadVPNUITests/Networking/MullvadAPIWrapper.swift new file mode 100644 index 0000000000..71343dd4f3 --- /dev/null +++ b/ios/MullvadVPNUITests/Networking/MullvadAPIWrapper.swift @@ -0,0 +1,45 @@ +// +// AppAPI.swift +// MullvadVPNUITests +// +// Created by Niklas Berglund on 2024-01-18. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import XCTest + +enum MullvadAPIError: Error { + case incorrectConfigurationFormat +} + +class MullvadAPIWrapper { + // swiftlint:disable force_cast + static let hostName = Bundle(for: MullvadAPIWrapper.self) + .infoDictionary?["ApiHostName"] as! String + + /// API endpoint configuration value in the format <IP-address>:<port> + static let endpoint = Bundle(for: MullvadAPIWrapper.self) + .infoDictionary?["ApiEndpoint"] as! String + // swiftlint:enable force_cast + + public static func getAPIHostname() -> String { + return hostName + } + + public static func getAPIIPAddress() throws -> String { + guard let ipAddress = endpoint.components(separatedBy: ":").first else { + throw MullvadAPIError.incorrectConfigurationFormat + } + + return ipAddress + } + + public static func getAPIPort() throws -> String { + guard let port = endpoint.components(separatedBy: ":").last else { + throw MullvadAPIError.incorrectConfigurationFormat + } + + return port + } +} diff --git a/ios/MullvadVPNUITests/Networking/Networking.swift b/ios/MullvadVPNUITests/Networking/Networking.swift new file mode 100644 index 0000000000..e8a038b4a2 --- /dev/null +++ b/ios/MullvadVPNUITests/Networking/Networking.swift @@ -0,0 +1,146 @@ +// +// Networking.swift +// MullvadVPNUITests +// +// Created by Niklas Berglund on 2024-02-05. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import Network +import XCTest + +enum NetworkingError: Error { + case notConfiguredError + case internalError(reason: String) +} + +/// Class with methods for verifying network connectivity +class Networking { + /// Get IP address of the iOS device under test + static func getIPAddress() throws -> String { + var ipAddress: String + // Get list of all interfaces on the local machine: + var interfaceList: UnsafeMutablePointer<ifaddrs>? + guard getifaddrs(&interfaceList) == 0, let firstInterfaceAddress = interfaceList else { + throw NetworkingError.internalError(reason: "Failed to locate local networking interface") + } + + // For each interface + for interfacePointer in sequence(first: firstInterfaceAddress, next: { $0.pointee.ifa_next }) { + let flags = Int32(interfacePointer.pointee.ifa_flags) + let interfaceAddress = interfacePointer.pointee.ifa_addr.pointee + + // Check for running IPv4 interfaces. Skip the loopback interface. + if ( + flags & + (IFF_UP | IFF_RUNNING | IFF_LOOPBACK) + ) == (IFF_UP | IFF_RUNNING), + interfaceAddress.sa_family == UInt8(AF_INET) { + // Check if interface is en0 which is the WiFi connection on the iPhone + let name = String(cString: interfacePointer.pointee.ifa_name) + if name == "en0" { + // Convert interface address to a human readable string: + var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST)) + if getnameinfo( + interfacePointer.pointee.ifa_addr, + socklen_t(interfaceAddress.sa_len), + &hostname, + socklen_t(hostname.count), + nil, + socklen_t(0), + NI_NUMERICHOST + ) == 0 { + ipAddress = String(cString: hostname) + return ipAddress + } + } + } + } + + freeifaddrs(interfaceList) + + throw NetworkingError.internalError(reason: "Failed to determine device's IP address") + } + + private static func getAdServingDomainURL() -> URL? { + guard let adServingDomain = Bundle(for: BaseUITestCase.self) + .infoDictionary?["AdServingDomain"] as? String, + let adServingDomainURL = URL(string: adServingDomain) else { + XCTFail("Ad serving domain not configured") + return nil + } + + return adServingDomainURL + } + + private static func getAdServingDomain() throws -> String { + guard let adServingDomain = Bundle(for: BaseUITestCase.self) + .infoDictionary?["AdServingDomain"] as? String else { + throw NetworkingError.notConfiguredError + } + + return adServingDomain + } + + /// Check whether host and port is reachable by attempting to connect a socket + private static func canConnectSocket(host: String, port: String) throws -> Bool { + let socketHost = NWEndpoint.Host(host) + let socketPort = try XCTUnwrap(NWEndpoint.Port(port)) + let connection = NWConnection(host: socketHost, port: socketPort, using: .tcp) + var connectionError: Error? + + let connectionStateDeterminedExpectation = XCTestExpectation( + description: "Completion handler for the reach ad serving domain request is invoked" + ) + + connection.stateUpdateHandler = { state in + print("State: \(state)") + + switch state { + case let .failed(error): + connection.cancel() + connectionError = error + connectionStateDeterminedExpectation.fulfill() + case .ready: + connection.cancel() + connectionStateDeterminedExpectation.fulfill() + default: + break + } + } + + connection.start(queue: .global()) + let waitResult = XCTWaiter.wait(for: [connectionStateDeterminedExpectation], timeout: 15) + + if waitResult != .completed || connectionError != nil { + return false + } + + return true + } + + /// Verify API can be accessed by attempting to connect a socket to the configured API host and port + public static func verifyCanAccessAPI() throws { + let apiIPAddress = try MullvadAPIWrapper.getAPIIPAddress() + let apiPort = try MullvadAPIWrapper.getAPIPort() + XCTAssertTrue(try canConnectSocket(host: apiIPAddress, port: apiPort)) + } + + /// Verify API cannot be accessed by attempting to connect a socket to the configured API host and port + public static func verifyCannotAccessAPI() throws { + let apiIPAddress = try MullvadAPIWrapper.getAPIIPAddress() + let apiPort = try MullvadAPIWrapper.getAPIPort() + XCTAssertFalse(try canConnectSocket(host: apiIPAddress, port: apiPort)) + } + + /// Verify that an ad serving domain is reachable by making sure a connection can be established on port 80 + public static func verifyCanReachAdServingDomain() throws { + XCTAssertTrue(try Self.canConnectSocket(host: try Self.getAdServingDomain(), port: "80")) + } + + /// Verify that an ad serving domain is NOT reachable by making sure a connection can not be established on port 80 + public static func verifyCannotReachAdServingDomain() throws { + XCTAssertFalse(try Self.canConnectSocket(host: try Self.getAdServingDomain(), port: "80")) + } +} diff --git a/ios/MullvadVPNUITests/Pages/LoginPage.swift b/ios/MullvadVPNUITests/Pages/LoginPage.swift index 18a44b5e74..399943fe52 100644 --- a/ios/MullvadVPNUITests/Pages/LoginPage.swift +++ b/ios/MullvadVPNUITests/Pages/LoginPage.swift @@ -37,12 +37,12 @@ class LoginPage: Page { } @discardableResult public func verifySuccessIconShown() -> Self { - app.images.element(matching: .image, identifier: "IconSuccess") + _ = app.images.element(matching: .image, identifier: "IconSuccess") return self } @discardableResult public func verifyFailIconShown() -> Self { - app.images.element(matching: .image, identifier: "IconFail") + _ = app.images.element(matching: .image, identifier: "IconFail").waitForExistence(timeout: 15) return self } } diff --git a/ios/MullvadVPNUITests/Pages/Page.swift b/ios/MullvadVPNUITests/Pages/Page.swift index 5a11e586e5..453bd57375 100644 --- a/ios/MullvadVPNUITests/Pages/Page.swift +++ b/ios/MullvadVPNUITests/Pages/Page.swift @@ -17,7 +17,7 @@ class Page { self.app = app } - public func waitForPageToBeShown() { + func waitForPageToBeShown() { if let pageAccessibilityIdentifier = self.pageAccessibilityIdentifier { XCTAssert( self.app.otherElements[pageAccessibilityIdentifier] @@ -26,7 +26,7 @@ class Page { } } - @discardableResult public func enterText(_ text: String) -> Self { + @discardableResult func enterText(_ text: String) -> Self { app.typeText(text) return self } @@ -36,4 +36,9 @@ class Page { app.swipeDown(velocity: .fast) return self } + + @discardableResult func tapKeyboardDoneButton() -> Self { + app.toolbars.buttons["Done"].tap() + return self + } } diff --git a/ios/MullvadVPNUITests/Pages/ProblemReportPage.swift b/ios/MullvadVPNUITests/Pages/ProblemReportPage.swift new file mode 100644 index 0000000000..4bb2407cec --- /dev/null +++ b/ios/MullvadVPNUITests/Pages/ProblemReportPage.swift @@ -0,0 +1,48 @@ +// +// ProblemReportPage.swift +// MullvadVPNUITests +// +// Created by Niklas Berglund on 2024-01-26. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import XCTest + +class ProblemReportPage: Page { + @discardableResult override init(_ app: XCUIApplication) { + super.init(app) + + pageAccessibilityIdentifier = .problemReportView + + waitForPageToBeShown() + } + + @discardableResult func tapEmailTextField() -> Self { + app.textFields[AccessibilityIdentifier.problemReportEmailTextField] + .tap() + + return self + } + + @discardableResult func tapMessageTextView() -> Self { + app.textViews[AccessibilityIdentifier.problemReportMessageTextView] + .tap() + + return self + } + + @discardableResult func tapViewAppLogsButton() -> Self { + app.otherElements[AccessibilityIdentifier.problemReportAppLogsButton] + .tap() + + return self + } + + @discardableResult func tapSendButton() -> Self { + app.otherElements[AccessibilityIdentifier.problemReportSendButton] + .tap() + + return self + } +} diff --git a/ios/MullvadVPNUITests/Pages/SettingsPage.swift b/ios/MullvadVPNUITests/Pages/SettingsPage.swift index c57fd3ff04..72acac4019 100644 --- a/ios/MullvadVPNUITests/Pages/SettingsPage.swift +++ b/ios/MullvadVPNUITests/Pages/SettingsPage.swift @@ -24,6 +24,14 @@ class SettingsPage: Page { return self } + @discardableResult func tapReportAProblemCell() -> Self { + app.tables[AccessibilityIdentifier.settingsTableView] + .cells[AccessibilityIdentifier.problemReportCell] + .tap() + + return self + } + @discardableResult func tapDNSSettingsCell() -> Self { app.tables .cells[AccessibilityIdentifier.dnsSettings] diff --git a/ios/MullvadVPNUITests/Pages/TunnelControlPage.swift b/ios/MullvadVPNUITests/Pages/TunnelControlPage.swift index 6469ed2232..860b928024 100644 --- a/ios/MullvadVPNUITests/Pages/TunnelControlPage.swift +++ b/ios/MullvadVPNUITests/Pages/TunnelControlPage.swift @@ -20,4 +20,15 @@ class TunnelControlPage: Page { app.buttons[AccessibilityIdentifier.selectLocationButton].tap() return self } + + @discardableResult func tapSecureConnectionButton() -> Self { + app.buttons[AccessibilityIdentifier.secureConnectionButton].tap() + return self + } + + @discardableResult func waitForSecureConnectionLabel() -> Self { + _ = app.staticTexts[AccessibilityIdentifier.connectionStatusLabel] + .waitForExistence(timeout: BaseUITestCase.defaultTimeout) + return self + } } diff --git a/ios/MullvadVPNUITests/RelayTests.swift b/ios/MullvadVPNUITests/RelayTests.swift index cb1454c801..a186bd7548 100644 --- a/ios/MullvadVPNUITests/RelayTests.swift +++ b/ios/MullvadVPNUITests/RelayTests.swift @@ -22,58 +22,13 @@ class RelayTests: LoggedInWithTimeUITestCase { .swipeDownToDismissModal() TunnelControlPage(app) - .tapSelectLocationButton() - - SelectLocationPage(app) - .tapLocationCellExpandButton(withName: "Sweden") - .tapLocationCellExpandButton(withName: "Gothenburg") - .tapLocationCell(withName: "se-got-wg-001") + .tapSecureConnectionButton() allowAddVPNConfigurations() // Allow adding VPN configurations iOS permission - TunnelControlPage(app) // Make sure we're taken back to tunnel control page again - - verifyCannotReachAdServingDomain() - } - - /// Verify that an ad serving domain is reachable by making sure the host can be found when sending HTTP request to it - func verifyCanReachAdServingDomain() { - XCTAssertTrue(canReachAdServingDomain()) - } - - /// Verify that an ad serving domain is NOT reachable by making sure the host cannot be found when sending HTTP request to it - func verifyCannotReachAdServingDomain() { - XCTAssertFalse(canReachAdServingDomain()) - } - - /// Attempt to reach HTTP server on an ad serving domain - /// - Returns: `true` if host can be resolved, otherwise `false` - private func canReachAdServingDomain() -> Bool { - guard let url = URL(string: "http://\(adServingDomain)") else { return false } - - var requestError: Error? - var requestResponse: URLResponse? - - let completionHandlerInvokedExpectation = expectation( - description: "Completion handler for the request is invoked" - ) - - let task = URLSession.shared.dataTask(with: url) { _, response, error in - requestError = error - requestResponse = response - completionHandlerInvokedExpectation.fulfill() - } - - task.resume() - - wait(for: [completionHandlerInvokedExpectation], timeout: 30) - - if let urlError = requestError as? URLError { - if urlError.code == .cannotFindHost && requestResponse == nil { - return false - } - } + TunnelControlPage(app) + .waitForSecureConnectionLabel() - return true + try Networking.verifyCannotReachAdServingDomain() } } diff --git a/ios/MullvadVPNUITests/Test base classes/BaseUITestCase.swift b/ios/MullvadVPNUITests/Test base classes/BaseUITestCase.swift index cedba952dc..eae33b0805 100644 --- a/ios/MullvadVPNUITests/Test base classes/BaseUITestCase.swift +++ b/ios/MullvadVPNUITests/Test base classes/BaseUITestCase.swift @@ -15,17 +15,15 @@ class BaseUITestCase: XCTestCase { // swiftlint:disable force_cast let displayName = Bundle(for: BaseUITestCase.self) - .infoDictionary?["MullvadDisplayName"] as! String + .infoDictionary?["DisplayName"] as! String let noTimeAccountNumber = Bundle(for: BaseUITestCase.self) - .infoDictionary?["MullvadNoTimeAccountNumber"] as! String + .infoDictionary?["NoTimeAccountNumber"] as! String let hasTimeAccountNumber = Bundle(for: BaseUITestCase.self) - .infoDictionary?["MullvadHasTimeAccountNumber"] as! String + .infoDictionary?["HasTimeAccountNumber"] as! String let fiveWireGuardKeysAccountNumber = Bundle(for: BaseUITestCase.self) - .infoDictionary?["MullvadFiveWireGuardKeysAccountNumber"] as! String + .infoDictionary?["FiveWireGuardKeysAccountNumber"] as! String let iOSDevicePinCode = Bundle(for: BaseUITestCase.self) - .infoDictionary?["MullvadIOSDevicePinCode"] as! String - let adServingDomain = Bundle(for: BaseUITestCase.self) - .infoDictionary?["MullvadAdServingDomain"] as! String + .infoDictionary?["IOSDevicePinCode"] as! String // swiftlint:enable force_cast /// Handle iOS add VPN configuration permission alert - allow and enter device PIN code |
