-
Notifications
You must be signed in to change notification settings - Fork 372
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'unit-tests-for-starttunneloperation-ios-480'
- Loading branch information
Showing
6 changed files
with
264 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// | ||
// MockTunnel.swift | ||
// MullvadVPNTests | ||
// | ||
// Created by Andrew Bulhak on 2024-02-05. | ||
// Copyright © 2024 Mullvad VPN AB. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
import NetworkExtension | ||
|
||
class MockTunnel: TunnelProtocol { | ||
typealias TunnelManagerProtocol = SimulatorTunnelProviderManager | ||
|
||
var status: NEVPNStatus | ||
|
||
var isOnDemandEnabled: Bool | ||
|
||
var startDate: Date? | ||
|
||
required init(tunnelProvider: TunnelManagerProtocol) { | ||
status = .disconnected | ||
isOnDemandEnabled = false | ||
startDate = nil | ||
} | ||
|
||
// Observers are currently unimplemented | ||
func addObserver(_ observer: TunnelStatusObserver) {} | ||
|
||
func removeObserver(_ observer: TunnelStatusObserver) {} | ||
|
||
func addBlockObserver( | ||
queue: DispatchQueue?, | ||
handler: @escaping (any TunnelProtocol, NEVPNStatus) -> Void | ||
) -> TunnelStatusBlockObserver { | ||
fatalError("MockTunnel.addBlockObserver Not implemented") | ||
} | ||
|
||
func logFormat() -> String { | ||
"" | ||
} | ||
|
||
func saveToPreferences(_ completion: @escaping (Error?) -> Void) { | ||
completion(nil) | ||
} | ||
|
||
func removeFromPreferences(completion: @escaping (Error?) -> Void) { | ||
completion(nil) | ||
} | ||
|
||
func setConfiguration(_ configuration: TunnelConfiguration) {} | ||
|
||
func start(options: [String: NSObject]?) throws { | ||
startDate = Date() | ||
} | ||
|
||
func stop() {} | ||
|
||
func sendProviderMessage(_ messageData: Data, responseHandler: ((Data?) -> Void)?) throws {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
// | ||
// MockTunnelInteractor.swift | ||
// MullvadVPNTests | ||
// | ||
// Created by Andrew Bulhak on 2024-02-02. | ||
// Copyright © 2024 Mullvad VPN AB. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
import MullvadSettings | ||
import PacketTunnelCore | ||
|
||
// this is still very minimal, and will be fleshed out as needed. | ||
class MockTunnelInteractor: TunnelInteractor { | ||
var isConfigurationLoaded: Bool | ||
|
||
var settings: MullvadSettings.LatestTunnelSettings | ||
|
||
var deviceState: MullvadSettings.DeviceState | ||
|
||
var onUpdateTunnelStatus: ((TunnelStatus) -> Void)? | ||
|
||
var tunnel: (any TunnelProtocol)? | ||
|
||
init( | ||
isConfigurationLoaded: Bool, | ||
settings: MullvadSettings.LatestTunnelSettings, | ||
deviceState: MullvadSettings.DeviceState, | ||
onUpdateTunnelStatus: ((TunnelStatus) -> Void)? = nil | ||
) { | ||
self.isConfigurationLoaded = isConfigurationLoaded | ||
self.settings = settings | ||
self.deviceState = deviceState | ||
self.onUpdateTunnelStatus = onUpdateTunnelStatus | ||
self.tunnel = nil | ||
self.tunnelStatus = TunnelStatus() | ||
} | ||
|
||
func getPersistentTunnels() -> [any TunnelProtocol] { | ||
return [] | ||
} | ||
|
||
func createNewTunnel() -> any TunnelProtocol { | ||
return MockTunnel(tunnelProvider: SimulatorTunnelProviderManager()) | ||
} | ||
|
||
func setTunnel(_ tunnel: (any TunnelProtocol)?, shouldRefreshTunnelState: Bool) { | ||
self.tunnel = tunnel | ||
} | ||
|
||
var tunnelStatus: TunnelStatus | ||
|
||
func updateTunnelStatus(_ block: (inout TunnelStatus) -> Void) -> TunnelStatus { | ||
var tunnelStatus = self.tunnelStatus | ||
block(&tunnelStatus) | ||
onUpdateTunnelStatus?(tunnelStatus) | ||
return tunnelStatus | ||
} | ||
|
||
func setConfigurationLoaded() {} | ||
|
||
func setSettings(_ settings: MullvadSettings.LatestTunnelSettings, persist: Bool) {} | ||
|
||
func setDeviceState(_ deviceState: MullvadSettings.DeviceState, persist: Bool) {} | ||
|
||
func removeLastUsedAccount() {} | ||
|
||
func handleRestError(_ error: Error) {} | ||
|
||
func startTunnel() {} | ||
|
||
func prepareForVPNConfigurationDeletion() {} | ||
|
||
struct NotImplementedError: Error {} | ||
|
||
func selectRelay() throws -> PacketTunnelCore.SelectedRelay { | ||
throw NotImplementedError() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
// | ||
// StartTunnelOperationTests.swift | ||
// MullvadVPNTests | ||
// | ||
// Created by Andrew Bulhak on 2024-02-02. | ||
// Copyright © 2024 Mullvad VPN AB. All rights reserved. | ||
// | ||
|
||
import MullvadSettings | ||
import Network | ||
import Operations | ||
import WireGuardKitTypes | ||
import XCTest | ||
|
||
class StartTunnelOperationTests: XCTestCase { | ||
// MARK: utility code for setting up tests | ||
|
||
let testQueue = DispatchQueue(label: "StartTunnelOperationTests.testQueue") | ||
let operationQueue = AsyncOperationQueue() | ||
|
||
let loggedInDeviceState = DeviceState.loggedIn( | ||
StoredAccountData( | ||
identifier: "", | ||
number: "", | ||
expiry: .distantFuture | ||
), | ||
StoredDeviceData( | ||
creationDate: Date(), | ||
identifier: "", | ||
name: "", | ||
hijackDNS: false, | ||
ipv4Address: IPAddressRange(from: "127.0.0.1/32")!, | ||
ipv6Address: IPAddressRange(from: "::ff/64")!, | ||
wgKeyData: StoredWgKeyData(creationDate: Date(), privateKey: PrivateKey()) | ||
) | ||
) | ||
|
||
func makeInteractor(deviceState: DeviceState, tunnelState: TunnelState? = nil) -> MockTunnelInteractor { | ||
let interactor = MockTunnelInteractor( | ||
isConfigurationLoaded: true, | ||
settings: LatestTunnelSettings(), | ||
deviceState: deviceState | ||
) | ||
if let tunnelState { | ||
interactor.tunnelStatus = TunnelStatus(state: tunnelState) | ||
} | ||
return interactor | ||
} | ||
|
||
// MARK: the tests | ||
|
||
func testFailsIfNotLoggedIn() throws { | ||
let expectation = expectation(description: "Start tunnel operation failed") | ||
let operation = StartTunnelOperation( | ||
dispatchQueue: testQueue, | ||
interactor: makeInteractor(deviceState: .loggedOut) | ||
) { result in | ||
guard case .failure = result else { | ||
XCTFail("Operation returned \(result), not failure") | ||
return | ||
} | ||
expectation.fulfill() | ||
} | ||
|
||
operationQueue.addOperation(operation) | ||
wait(for: [expectation], timeout: 1.0) | ||
} | ||
|
||
func testSetsReconnectIfDisconnecting() { | ||
let interactor = makeInteractor(deviceState: loggedInDeviceState, tunnelState: .disconnecting(.nothing)) | ||
var tunnelStatus = TunnelStatus() | ||
interactor.onUpdateTunnelStatus = { status in tunnelStatus = status } | ||
let expectation = expectation(description: "Tunnel status set to reconnect") | ||
|
||
let operation = StartTunnelOperation( | ||
dispatchQueue: testQueue, | ||
interactor: interactor | ||
) { result in | ||
XCTAssertEqual(tunnelStatus.state, .disconnecting(.reconnect)) | ||
expectation.fulfill() | ||
} | ||
operationQueue.addOperation(operation) | ||
wait(for: [expectation], timeout: 1.0) | ||
} | ||
|
||
func testStartsTunnelIfDisconnected() { | ||
let interactor = makeInteractor(deviceState: loggedInDeviceState, tunnelState: .disconnected) | ||
let expectation = expectation(description: "Make tunnel provider and start tunnel") | ||
let operation = StartTunnelOperation( | ||
dispatchQueue: testQueue, | ||
interactor: interactor | ||
) { result in | ||
XCTAssertNotNil(interactor.tunnel) | ||
XCTAssertNotNil(interactor.tunnel?.startDate) | ||
expectation.fulfill() | ||
} | ||
operationQueue.addOperation(operation) | ||
wait(for: [expectation], timeout: 1.0) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters