-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathTransloaditKitTests.swift
More file actions
340 lines (261 loc) · 13.7 KB
/
TransloaditKitTests.swift
File metadata and controls
340 lines (261 loc) · 13.7 KB
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
import XCTest
import TransloaditKit // ⚠️ WARNING: We are not performing a testable import here. We want to test the real public API. By doing so, we'll know very quicklly if the public API is broken. Which is very important to prevent.
import AVFoundation
class TransloaditKitTests: XCTestCase {
public var transloadit: Transloadit!
let resizeStep = Step(name: "resize", robot: "/image/resize", options: ["width": 50,
"height": 75,
"resize_strategy": "fit",
"result": true])
var data: Data!
var fileDelegate: TransloadItMockDelegate!
override func setUp() {
super.setUp()
transloadit = makeClient()
do {
try transloadit.reset()
} catch {
// If there is no cache to delete, that's okay.
}
fileDelegate = TransloadItMockDelegate()
transloadit.fileDelegate = fileDelegate
data = Data("Hello".utf8)
}
override func tearDown() {
transloadit.fileDelegate = nil
}
fileprivate func makeClient() -> Transloadit {
let credentials = Transloadit.Credentials(key: "I am a key", secret: "I am a secret")
let configuration = URLSessionConfiguration.default
configuration.protocolClasses = [MockURLProtocol.self]
let session = URLSession.init(configuration: configuration)
return Transloadit(credentials: credentials, session: session)
}
// MARK: - File uploading
func testCreateAssembly_Without_Uploading() throws {
let serverAssembly = Fixtures.makeAssembly()
Network.prepareAssemblyResponse(assembly: serverAssembly)
let serverFinishedExpectation = expectation(description: "Waiting for createAssembly to be called")
transloadit.createAssembly(steps: [resizeStep]) { result in
switch result {
case .success:
serverFinishedExpectation.fulfill()
case .failure:
XCTFail("Creating an assembly should have succeeded")
}
}
waitForExpectations(timeout: 3.0, handler: nil)
}
func testCreatingAssembly_And_Uploading_Of_Files() throws {
let (files, serverAssembly) = try Network.prepareForUploadingFiles(data: data)
let numFiles = files.count
let finishedUploadExpectation = self.expectation(description: "Finished file upload")
finishedUploadExpectation.expectedFulfillmentCount = numFiles
let startedUploadsExpectation = self.expectation(description: "Started uploads")
startedUploadsExpectation.expectedFulfillmentCount = numFiles
fileDelegate.finishUploadExpectation = finishedUploadExpectation
fileDelegate.startUploadExpectation = startedUploadsExpectation
createAssembly(files, completed: { result in
switch result {
case .success(let receivedAssembly):
XCTAssertEqual(serverAssembly, receivedAssembly)
case .failure:
XCTFail("Expected call to succeed")
}
})
wait(for: [startedUploadsExpectation, finishedUploadExpectation], timeout: 3)
XCTAssertEqual(numFiles, fileDelegate.finishedUploads.count)
XCTAssertEqual(numFiles, fileDelegate.startedUploads.count)
}
func testConcurrentAssemblyCreation() throws {
let expect = expectation(description: "Wait for all assemblies to be created")
expect.expectedFulfillmentCount = 3
DispatchQueue.concurrentPerform(iterations: 3) { _ in
do {
let (files, serverAssembly) = try Network.prepareForUploadingFiles(data: data)
let numFiles = files.count
let _ = createAssembly(files) { _ in
expect.fulfill()
}
} catch {
XCTFail("Failed with error \(error)")
}
}
wait(for: [expect], timeout: 10)
try transloadit.reset()
}
func testCanReset() throws {
XCTAssertEqual(0, transloadit.remainingUploads)
// Preparation
let (files, _) = try Network.prepareForUploadingFiles(data: data)
// Start
createAssembly(files)
XCTAssertEqual(files.count, transloadit.remainingUploads)
try? transloadit.reset()
try? transloadit.reset()
XCTAssertEqual(0, transloadit.remainingUploads)
}
func testStatusFetching() throws {
let (_, serverAssembly) = try Network.prepareForUploadingFiles(data: data)
Network.prepareNetworkForStatusCheck(assemblyURL: serverAssembly.url, expectedStatus: .uploading)
let serverExpectation = self.expectation(description: "Expected server to respond with a success")
transloadit.fetchStatus(assemblyURL: serverAssembly.url, completion: { result in
switch result {
case .success:
serverExpectation.fulfill()
case .failure:
XCTFail("The status-check returned an error against expectations")
}
})
waitForExpectations(timeout: 3, handler: nil)
}
// MARK: - Restoring upload sessions
func testContinuingUploadsAfterStopping() throws {
// Stop uploads, resume them with the same client. Make sure uploads are finished.
let (files, _) = try Network.prepareForUploadingFiles(data: data)
Network.prepareForStatusResponse(data: data) // Because TUS will perform a status check after continuing.
let numFiles = files.count
let startedUploadsExpectation = self.expectation(description: "Started uploads")
startedUploadsExpectation.expectedFulfillmentCount = numFiles
let finishedUploadExpectation = self.expectation(description: "Finished file upload")
finishedUploadExpectation.expectedFulfillmentCount = numFiles
fileDelegate.startUploadExpectation = startedUploadsExpectation
var localAssembly: Assembly!
transloadit.createAssembly(steps: [resizeStep], andUpload: files, completion: { result in
switch result {
case .success(let assembly):
localAssembly = assembly
case .failure:
XCTFail("Expected assembly creation to succeed.")
}
})
wait(for: [startedUploadsExpectation], timeout: 3)
transloadit.stopRunningUploads()
// Restart uploads, continue where left off
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [self] in
fileDelegate.startUploadExpectation = nil
fileDelegate.finishUploadExpectation = finishedUploadExpectation
transloadit.start()
}
wait(for: [finishedUploadExpectation], timeout: 10)
XCTAssert(fileDelegate.finishedUploads.contains(localAssembly))
}
func testContinuingUploadsOnNewSession() throws {
// Stop uploads, resume them with a new client. Make sure uploads are finished.
let (files, _) = try Network.prepareForUploadingFiles(data: data)
Network.prepareForStatusResponse(data: data) // Because TUS will perform a status check after continuing.
let numFiles = files.count
let startedUploadsExpectation = self.expectation(description: "Started uploads")
startedUploadsExpectation.expectedFulfillmentCount = numFiles
fileDelegate.startUploadExpectation = startedUploadsExpectation
var localAssembly: Assembly!
transloadit.createAssembly(steps: [resizeStep], andUpload: files, completion: { result in
switch result {
case .success(let assembly):
localAssembly = assembly
case .failure:
XCTFail("Expected assembly creation to succeed.")
}
})
wait(for: [startedUploadsExpectation], timeout: 3)
transloadit.stopRunningUploads()
// Restart uploads from new client, continue where left off
let secondTransloadit = makeClient()
let secondFileDelegate = TransloadItMockDelegate()
secondTransloadit.fileDelegate = secondFileDelegate
secondFileDelegate.name = "SECOND"
let finishedUploadExpectation = self.expectation(description: "Finished file upload")
finishedUploadExpectation.expectedFulfillmentCount = numFiles
secondFileDelegate.finishUploadExpectation = finishedUploadExpectation
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
secondTransloadit.start()
}
wait(for: [finishedUploadExpectation], timeout: 5)
XCTAssert(secondFileDelegate.finishedUploads.contains(localAssembly))
}
// MARK: - Polling
func testPolling() throws {
try poll(statusToTestAgainst: .completed)
}
func testPollingStopsOnCancelState() throws {
// It's one thing if polling stops when status is completed. But it needs to stop polling on errors and canceled actions
try poll(statusToTestAgainst: .canceled)
}
func testPollingStopsOnAbortedState() throws {
// It's one thing if polling stops when status is completed. But it needs to stop polling on errors and canceled actions
try poll(statusToTestAgainst: .aborted)
}
func testTransloaditDoesntPollIfAssemblyFails() throws {
let (files, _) = try Network.prepareForUploadingFiles(data: data)
Network.prepareForFailingAssemblyResponse()
let serverFinishedExpectation = expectation(description: "Waiting for createAssembly to be called")
let poller = transloadit.createAssembly(steps: [resizeStep], andUpload: files, completion: { result in
switch result {
case .success:
XCTFail("Expected server to fail for this test")
case .failure:
serverFinishedExpectation.fulfill()
}
})
wait(for: [serverFinishedExpectation], timeout: 3)
// Now let's check polling
let pollerResponseThatShouldNotBeCalled = self.expectation(description: "Poller is called, but shouldn't have been called.")
pollerResponseThatShouldNotBeCalled.isInverted = true
poller.pollAssemblyStatus { result in
pollerResponseThatShouldNotBeCalled.fulfill()
}
let defaultPollingTime: Double = 3
waitForExpectations(timeout: defaultPollingTime + 1, handler: nil)
}
private func poll(statusToTestAgainst: AssemblyStatus.ProcessingStatus) throws {
let defaultPollingTime: Double = 3
let pollingExpectation = expectation(description: "Waiting for polling to be called twice")
pollingExpectation.expectedFulfillmentCount = 2 // The amount of calls required before a status check is finished (e.g. status is set to completed/canceled/aborted)
let pollingStatusCompleteExpectation = expectation(description: "Waiting for polling status to be complete")
let noMoreCallsExpectation = expectation(description: "This shouldn't be called")
noMoreCallsExpectation.isInverted = true
let (files, serverAssembly) = try Network.prepareForUploadingFiles(data: data)
Network.prepareNetworkForStatusCheck(assemblyURL: serverAssembly.url, expectedStatus: statusToTestAgainst)
var isStatusCanceled = false
createAssembly(files)
.pollAssemblyStatus { result in
pollingExpectation.fulfill()
switch result {
case .success(let status):
if status.processingStatus == statusToTestAgainst {
pollingStatusCompleteExpectation.fulfill()
// Now make sure that canceled isn't called any more
if isStatusCanceled {
noMoreCallsExpectation.fulfill()
}
isStatusCanceled = true
}
case .failure(let error):
XCTFail("Polling threw error \(error)")
}
}
wait(for: [pollingExpectation, pollingStatusCompleteExpectation], timeout: defaultPollingTime * 2 + 1)
// We wait to make sure polling doesnt keep calling
wait(for: [noMoreCallsExpectation], timeout: defaultPollingTime * 3)
}
func testPollingSameFilesMultipleTimesShouldNotBreak() throws {
// Here we are trying to break the thing.
try testPolling()
try testPolling()
}
// MARK: - Utils
@discardableResult
private func createAssembly(_ files: [URL]) -> TransloaditPoller {
return createAssembly(files, completed: { _ in })
}
@discardableResult
private func createAssembly(_ files: [URL], completed: @escaping (Result<Assembly, TransloaditError>) -> Void) -> TransloaditPoller {
let serverFinishedExpectation = expectation(description: "Waiting for createAssembly to be called")
let poller = transloadit.createAssembly(steps: [resizeStep], andUpload: files, completion: { result in
serverFinishedExpectation.fulfill()
completed(result)
})
wait(for: [serverFinishedExpectation], timeout: 3)
return poller
}
}