1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
//
// FirewallClient.swift
// MullvadVPNUITests
//
// Created by Niklas Berglund on 2024-01-18.
// Copyright © 2025 Mullvad VPN AB. All rights reserved.
//
import Foundation
import SystemConfiguration
import UIKit
import XCTest
class FirewallClient: TestRouterAPIClient {
let testDeviceIdentifier = Bundle(for: FirewallClient.self).infoDictionary?["TestDeviceIdentifier"] as! String
lazy var sessionIdentifier = "urn:uuid:" + testDeviceIdentifier
/// Create a new rule associated to the device under test
public func createRule(_ firewallRule: FirewallRule) {
let createRuleURL = TestRouterAPIClient.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, // Deprecated, replaced by "src"
"to": firewallRule.toIPAddress, // Deprectated, replaced by "dst"
"src": firewallRule.fromIPAddress,
"dst": firewallRule.toIPAddress,
"block_all_except_dst": firewallRule.inverted,
"protocols": firewallRule.protocolsAsStringArray(),
]
nonisolated(unsafe) var requestError: Error?
nonisolated(unsafe) 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 response status code \(response.statusCode)"
)
}
}
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 = TestRouterAPIClient.baseURL.appendingPathComponent("remove-rules/\(sessionIdentifier)")
var request = URLRequest(url: removeRulesURL)
request.httpMethod = "DELETE"
nonisolated(unsafe) var requestResponse: URLResponse?
nonisolated(unsafe) 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)")
}
}
}
}
|