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
113
114
115
116
117
118
119
120
121
122
123
124
|
//
// PartnerAPIClient.swift
// MullvadVPNUITests
//
// Created by Niklas Berglund on 2024-04-19.
// Copyright © 2025 Mullvad VPN AB. All rights reserved.
//
import Foundation
import XCTest
class PartnerAPIClient {
let baseURL = URL(string: "https://partner.stagemole.eu/v1/")!
lazy var accessToken: String = {
guard let token = Bundle(for: BaseUITestCase.self).infoDictionary?["PartnerApiToken"] as? String else {
fatalError("Failed to retrieve partner API token from config")
}
return token
}()
/// Add time to an account
/// - Parameters:
/// - accountNumber: Account number
/// - days: Number of days to add. Needs to be between 1 and 31.
func addTime(accountNumber: String, days: Int) -> Date {
let jsonResponse = sendRequest(
method: "POST",
endpoint: "accounts/\(accountNumber)/extend",
jsonObject: ["days": "\(days)"]
)
guard let newExpiryString = jsonResponse["new_expiry"] as? String else {
XCTFail("Failed to read new account expiry from response")
return Date()
}
let dateFormatter = ISO8601DateFormatter()
guard let newExpiryDate = dateFormatter.date(from: newExpiryString) else {
XCTFail("Failed to create Date object from date string")
return Date()
}
return newExpiryDate
}
func createAccount() -> String {
let jsonResponse = sendRequest(method: "POST", endpoint: "accounts", jsonObject: nil)
guard let accountNumber = jsonResponse["id"] as? String else {
XCTFail("Failed to read created account number")
return String()
}
return accountNumber
}
func deleteAccount(accountNumber: String) {
_ = sendRequest(method: "DELETE", endpoint: "accounts/\(accountNumber)", jsonObject: nil)
}
private func sendRequest(method: String, endpoint: String, jsonObject: [String: Any]?) -> [String: Any] {
let url = baseURL.appendingPathComponent(endpoint)
var request = URLRequest(url: url)
request.httpMethod = method
request.setValue("Basic \(accessToken)", forHTTPHeaderField: "Authorization")
nonisolated(unsafe) var jsonResponse: [String: Any] = [:]
do {
if let jsonObject = jsonObject {
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try JSONSerialization.data(withJSONObject: jsonObject, options: [])
}
} catch {
XCTFail("Failed to serialize JSON object")
return [:]
}
let completionHandlerInvokedExpectation = XCTestExpectation(
description: "Completion handler for the request is invoked"
)
nonisolated(unsafe) var requestError: Error?
let task = URLSession.shared.dataTask(with: request) { data, response, error in
requestError = error
guard let data = data,
let response = response as? HTTPURLResponse,
error == nil
else {
XCTFail("Error: \(error?.localizedDescription ?? "Unknown error")")
completionHandlerInvokedExpectation.fulfill()
return
}
if 200...204 ~= response.statusCode {
print("Request successful")
do {
if data.isEmpty {
// Not all requests return JSON data
jsonResponse = [:]
} else {
jsonResponse = try JSONSerialization.jsonObject(with: data) as? [String: Any] ?? [:]
}
} catch {
XCTFail("Failed to deserialize JSON response")
}
} else {
XCTFail("Request failed with status code \(response.statusCode)")
}
completionHandlerInvokedExpectation.fulfill()
}
task.resume()
let waitResult = XCTWaiter().wait(for: [completionHandlerInvokedExpectation], timeout: 10)
XCTAssertEqual(waitResult, .completed, "Waiting for partner API request expectation completed")
XCTAssertNil(requestError)
return jsonResponse
}
}
|