From 1713fd4ccc7be614401ffdbb853ae11326ff7d6f Mon Sep 17 00:00:00 2001 From: Graeme Arthur Date: Thu, 28 Sep 2023 19:16:28 +0100 Subject: [PATCH] Connection interruption simulation option (#1686) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task/Issue URL: https://app.asana.com/0/0/1205601804599806/f BSK PR: https://github.com/duckduckgo/BrowserServicesKit/pull/516 **Description**: This PR adds a `Connection Interruption` failure simulation option and updates BSK to bring in the changes made to allow this. I also added some changes to the PacketTunnelProvider in order to test connection interruptions for the iOS NetP Notifications project. I found that simply setting reasserting to true causes the ConnectionnTester to trigger an interruption, then setting it to false recovers it. This has the benefit of testing the result of the real callback, not needing to mess with any of the connection tester’s callback handling, not needing to add any new state and also mimicking an actual interruption (as the VPN connection status also changes). **Steps to test this PR**: 1. Build this branch through Xcode 2. Start Network Protection 3. If this is the first time launching, agree to any notifications prompt. 4. Go to the Debug menu and simulate a connection interruption (Debug -> Network Protection -> Simulate Failure -> Connection Interruption) 5. **Observe the interruption notification** 6. Go back to Network Protection Status View 7. **Observe the status is reconnecting** 8. Wait for the reconnected notification. — ###### Internal references: [Pull Request Review Checklist](https://app.asana.com/0/1202500774821704/1203764234894239/f) [Software Engineering Expectations](https://app.asana.com/0/59792373528535/199064865822552) [Technical Design Template](https://app.asana.com/0/59792373528535/184709971311943) [Pull Request Documentation](https://app.asana.com/0/1202500774821704/1204012835277482/f) --------- Co-authored-by: Diego Rey Mendez --- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 6 +++--- DuckDuckGo/Menus/MainMenu.storyboard | 11 +++++++++-- .../NetworkProtectionSimulateFailureMenu.swift | 7 +++++++ .../NetworkProtectionTunnelController.swift | 10 ++++++++++ LocalPackages/DataBrokerProtection/Package.swift | 2 +- LocalPackages/NetworkProtectionUI/Package.swift | 2 +- 7 files changed, 32 insertions(+), 8 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 949f7ef19c..16fb57ef40 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -12295,7 +12295,7 @@ repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 80.2.1; + version = 80.3.0; }; }; AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 010d7ca7da..434ac22609 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -14,8 +14,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { - "revision" : "e955f958201a91ef353c55236361e095357e9505", - "version" : "80.2.1" + "revision" : "2bed3ed259ca7bde33f3d41424345acfeff8031d", + "version" : "80.3.0" } }, { @@ -129,7 +129,7 @@ { "identity" : "trackerradarkit", "kind" : "remoteSourceControl", - "location" : "https://github.com/duckduckgo/TrackerRadarKit.git", + "location" : "https://github.com/duckduckgo/TrackerRadarKit", "state" : { "revision" : "4684440d03304e7638a2c8086895367e90987463", "version" : "1.2.1" diff --git a/DuckDuckGo/Menus/MainMenu.storyboard b/DuckDuckGo/Menus/MainMenu.storyboard index 552341ee91..abb5ebf502 100644 --- a/DuckDuckGo/Menus/MainMenu.storyboard +++ b/DuckDuckGo/Menus/MainMenu.storyboard @@ -1,7 +1,7 @@ - + - + @@ -1033,8 +1033,15 @@ CQ + + + + + + + diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionSimulateFailureMenu.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionSimulateFailureMenu.swift index f2f8887d23..e770d08855 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionSimulateFailureMenu.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionSimulateFailureMenu.swift @@ -37,6 +37,7 @@ final class NetworkProtectionSimulateFailureMenu: NSMenu { @IBOutlet weak var simulateControllerFailureMenuItem: NSMenuItem! @IBOutlet weak var simulateTunnelFailureMenuItem: NSMenuItem! @IBOutlet weak var simulateTunnelCrashMenuItem: NSMenuItem! + @IBOutlet weak var simulateConnectionInterruptionMenuItem: NSMenuItem! private var simulationOptions: NetworkProtectionSimulationOptions { NetworkProtectionTunnelController.simulationOptions @@ -63,6 +64,11 @@ final class NetworkProtectionSimulateFailureMenu: NSMenu { simulateFailure(NetworkProtectionTunnelController().toggleShouldSimulateTunnelFatalError) } + @IBAction + func simulateConnectionInterruption(_ menuItem: NSMenuItem) { + simulateFailure(NetworkProtectionTunnelController().toggleShouldSimulateConnectionInterruption) + } + private func simulateFailure(_ simulationFunction: @escaping () async throws -> Void) { Task { do { @@ -77,6 +83,7 @@ final class NetworkProtectionSimulateFailureMenu: NSMenu { simulateControllerFailureMenuItem.state = simulationOptions.isEnabled(.controllerFailure) ? .on : .off simulateTunnelFailureMenuItem.state = simulationOptions.isEnabled(.tunnelFailure) ? .on : .off simulateTunnelCrashMenuItem.state = simulationOptions.isEnabled(.crashFatalError) ? .on : .off + simulateConnectionInterruptionMenuItem.state = simulationOptions.isEnabled(.connectionInterruption) ? .on : .off } } diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift index 6652453353..e72c64a25f 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift @@ -572,6 +572,16 @@ final class NetworkProtectionTunnelController: NetworkProtection.TunnelControlle } } + @MainActor + func toggleShouldSimulateConnectionInterruption() async throws { + if Self.simulationOptions.isEnabled(.connectionInterruption) { + Self.simulationOptions.setEnabled(false, option: .connectionInterruption) + } else { + Self.simulationOptions.setEnabled(true, option: .connectionInterruption) + try await sendProviderMessageToActiveSession(.simulateConnectionInterruption) + } + } + @MainActor private func sendProviderMessageToActiveSession(_ message: ExtensionMessage) async throws { guard await isConnected, diff --git a/LocalPackages/DataBrokerProtection/Package.swift b/LocalPackages/DataBrokerProtection/Package.swift index ef88212406..0eb21eddf9 100644 --- a/LocalPackages/DataBrokerProtection/Package.swift +++ b/LocalPackages/DataBrokerProtection/Package.swift @@ -29,7 +29,7 @@ let package = Package( targets: ["DataBrokerProtection"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "80.2.1"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "80.3.0"), .package(path: "../SwiftUIExtensions") ], targets: [ diff --git a/LocalPackages/NetworkProtectionUI/Package.swift b/LocalPackages/NetworkProtectionUI/Package.swift index bba964fbc4..36595f3eca 100644 --- a/LocalPackages/NetworkProtectionUI/Package.swift +++ b/LocalPackages/NetworkProtectionUI/Package.swift @@ -15,7 +15,7 @@ let package = Package( targets: ["NetworkProtectionUI"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "80.2.1"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "80.3.0"), .package(path: "../SwiftUIExtensions") ], targets: [