DownloadTests.swift 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007
  1. //
  2. // DownloadTests.swift
  3. //
  4. // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/)
  5. //
  6. // Permission is hereby granted, free of charge, to any person obtaining a copy
  7. // of this software and associated documentation files (the "Software"), to deal
  8. // in the Software without restriction, including without limitation the rights
  9. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. // copies of the Software, and to permit persons to whom the Software is
  11. // furnished to do so, subject to the following conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be included in
  14. // all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. // THE SOFTWARE.
  23. //
  24. import Alamofire
  25. import Foundation
  26. import XCTest
  27. class DownloadInitializationTestCase: BaseTestCase {
  28. func testDownloadClassMethodWithMethodURLAndDestination() {
  29. // Given
  30. let urlString = "https://httpbin.org/get"
  31. let expectation = self.expectation(description: "download should complete")
  32. // When
  33. let request = AF.download(urlString).response { _ in
  34. expectation.fulfill()
  35. }
  36. waitForExpectations(timeout: timeout, handler: nil)
  37. // Then
  38. XCTAssertNotNil(request.request)
  39. XCTAssertEqual(request.request?.httpMethod, "GET")
  40. XCTAssertEqual(request.request?.url?.absoluteString, urlString)
  41. XCTAssertNotNil(request.response)
  42. }
  43. func testDownloadClassMethodWithMethodURLHeadersAndDestination() {
  44. // Given
  45. let urlString = "https://httpbin.org/get"
  46. let headers: HTTPHeaders = ["Authorization": "123456"]
  47. let expectation = self.expectation(description: "download should complete")
  48. // When
  49. let request = AF.download(urlString, headers: headers).response { _ in
  50. expectation.fulfill()
  51. }
  52. waitForExpectations(timeout: timeout, handler: nil)
  53. // Then
  54. XCTAssertNotNil(request.request)
  55. XCTAssertEqual(request.request?.httpMethod, "GET")
  56. XCTAssertEqual(request.request?.url?.absoluteString, urlString)
  57. XCTAssertEqual(request.request?.headers["Authorization"], "123456")
  58. XCTAssertNotNil(request.response)
  59. }
  60. }
  61. // MARK: -
  62. class DownloadResponseTestCase: BaseTestCase {
  63. private var randomCachesFileURL: URL {
  64. testDirectoryURL.appendingPathComponent("\(UUID().uuidString).json")
  65. }
  66. func testDownloadRequest() {
  67. // Given
  68. let fileURL = randomCachesFileURL
  69. let numberOfLines = 10
  70. let urlString = "https://httpbin.org/stream/\(numberOfLines)"
  71. let destination: DownloadRequest.Destination = { _, _ in (fileURL, []) }
  72. let expectation = self.expectation(description: "Download request should download data to file: \(urlString)")
  73. var response: DownloadResponse<URL?, AFError>?
  74. // When
  75. AF.download(urlString, to: destination)
  76. .response { resp in
  77. response = resp
  78. expectation.fulfill()
  79. }
  80. waitForExpectations(timeout: timeout, handler: nil)
  81. // Then
  82. XCTAssertNotNil(response?.request)
  83. XCTAssertNotNil(response?.response)
  84. XCTAssertNotNil(response?.fileURL)
  85. XCTAssertNil(response?.resumeData)
  86. XCTAssertNil(response?.error)
  87. if let destinationURL = response?.fileURL {
  88. XCTAssertTrue(FileManager.default.fileExists(atPath: destinationURL.path))
  89. if let data = try? Data(contentsOf: destinationURL) {
  90. XCTAssertGreaterThan(data.count, 0)
  91. } else {
  92. XCTFail("data should exist for contents of destinationURL")
  93. }
  94. }
  95. }
  96. func testDownloadRequestResponseURLProducesURL() throws {
  97. // Given
  98. let request = URLRequest.makeHTTPBinRequest()
  99. let expectation = self.expectation(description: "Download request should download data")
  100. var response: DownloadResponse<URL, AFError>?
  101. // When
  102. AF.download(request)
  103. .responseURL { resp in
  104. response = resp
  105. expectation.fulfill()
  106. }
  107. waitForExpectations(timeout: timeout, handler: nil)
  108. // Then
  109. XCTAssertNotNil(response?.request)
  110. XCTAssertNotNil(response?.response)
  111. XCTAssertNotNil(response?.fileURL)
  112. XCTAssertNil(response?.resumeData)
  113. XCTAssertNil(response?.error)
  114. let url = try XCTUnwrap(response?.value)
  115. XCTAssertTrue(FileManager.default.fileExists(atPath: url.path))
  116. }
  117. func testCancelledDownloadRequest() {
  118. // Given
  119. let fileURL = randomCachesFileURL
  120. let numberOfLines = 10
  121. let urlString = "https://httpbin.org/stream/\(numberOfLines)"
  122. let destination: DownloadRequest.Destination = { _, _ in (fileURL, []) }
  123. let expectation = self.expectation(description: "Cancelled download request should not download data to file")
  124. var response: DownloadResponse<URL?, AFError>?
  125. // When
  126. AF.download(urlString, to: destination)
  127. .response { resp in
  128. response = resp
  129. expectation.fulfill()
  130. }
  131. .cancel()
  132. waitForExpectations(timeout: timeout, handler: nil)
  133. // Then
  134. XCTAssertNil(response?.response)
  135. XCTAssertNil(response?.fileURL)
  136. XCTAssertNotNil(response?.error)
  137. XCTAssertEqual(response?.error?.isExplicitlyCancelledError, true)
  138. }
  139. func testDownloadRequestWithProgress() {
  140. // Given
  141. let randomBytes = 1 * 25 * 1024
  142. let urlString = "https://httpbin.org/bytes/\(randomBytes)"
  143. let expectation = self.expectation(description: "Bytes download progress should be reported: \(urlString)")
  144. var progressValues: [Double] = []
  145. var response: DownloadResponse<URL?, AFError>?
  146. // When
  147. AF.download(urlString)
  148. .downloadProgress { progress in
  149. progressValues.append(progress.fractionCompleted)
  150. }
  151. .response { resp in
  152. response = resp
  153. expectation.fulfill()
  154. }
  155. waitForExpectations(timeout: timeout, handler: nil)
  156. // Then
  157. XCTAssertNotNil(response?.request)
  158. XCTAssertNotNil(response?.response)
  159. XCTAssertNotNil(response?.fileURL)
  160. XCTAssertNil(response?.resumeData)
  161. XCTAssertNil(response?.error)
  162. var previousProgress: Double = progressValues.first ?? 0.0
  163. for progress in progressValues {
  164. XCTAssertGreaterThanOrEqual(progress, previousProgress)
  165. previousProgress = progress
  166. }
  167. if let lastProgressValue = progressValues.last {
  168. XCTAssertEqual(lastProgressValue, 1.0)
  169. } else {
  170. XCTFail("last item in progressValues should not be nil")
  171. }
  172. }
  173. func testDownloadRequestWithParameters() {
  174. // Given
  175. let fileURL = randomCachesFileURL
  176. let urlString = "https://httpbin.org/get"
  177. let parameters = ["foo": "bar"]
  178. let destination: DownloadRequest.Destination = { _, _ in (fileURL, []) }
  179. let expectation = self.expectation(description: "Download request should download data to file")
  180. var response: DownloadResponse<URL?, AFError>?
  181. // When
  182. AF.download(urlString, parameters: parameters, to: destination)
  183. .response { resp in
  184. response = resp
  185. expectation.fulfill()
  186. }
  187. waitForExpectations(timeout: timeout, handler: nil)
  188. // Then
  189. XCTAssertNotNil(response?.request)
  190. XCTAssertNotNil(response?.response)
  191. XCTAssertNotNil(response?.fileURL)
  192. XCTAssertNil(response?.resumeData)
  193. XCTAssertNil(response?.error)
  194. if
  195. let data = try? Data(contentsOf: fileURL),
  196. let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []),
  197. let json = jsonObject as? [String: Any],
  198. let args = json["args"] as? [String: String] {
  199. XCTAssertEqual(args["foo"], "bar")
  200. } else {
  201. XCTFail("args parameter in JSON should not be nil")
  202. }
  203. }
  204. func testDownloadRequestWithHeaders() {
  205. // Given
  206. let fileURL = randomCachesFileURL
  207. let urlString = "https://httpbin.org/get"
  208. let headers: HTTPHeaders = ["Authorization": "123456"]
  209. let destination: DownloadRequest.Destination = { _, _ in (fileURL, []) }
  210. let expectation = self.expectation(description: "Download request should download data to file: \(fileURL)")
  211. var response: DownloadResponse<URL?, AFError>?
  212. // When
  213. AF.download(urlString, headers: headers, to: destination)
  214. .response { resp in
  215. response = resp
  216. expectation.fulfill()
  217. }
  218. waitForExpectations(timeout: timeout, handler: nil)
  219. // Then
  220. XCTAssertNotNil(response?.request)
  221. XCTAssertNotNil(response?.response)
  222. XCTAssertNotNil(response?.fileURL)
  223. XCTAssertNil(response?.resumeData)
  224. XCTAssertNil(response?.error)
  225. if
  226. let data = try? Data(contentsOf: fileURL),
  227. let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []),
  228. let json = jsonObject as? [String: Any],
  229. let headers = json["headers"] as? [String: String] {
  230. XCTAssertEqual(headers["Authorization"], "123456")
  231. } else {
  232. XCTFail("headers parameter in JSON should not be nil")
  233. }
  234. }
  235. func testThatDownloadingFileAndMovingToDirectoryThatDoesNotExistThrowsError() {
  236. // Given
  237. let fileURL = testDirectoryURL.appendingPathComponent("some/random/folder/test_output.json")
  238. let expectation = self.expectation(description: "Download request should download data but fail to move file")
  239. var response: DownloadResponse<URL?, AFError>?
  240. // When
  241. AF.download("https://httpbin.org/get", to: { _, _ in (fileURL, []) })
  242. .response { resp in
  243. response = resp
  244. expectation.fulfill()
  245. }
  246. waitForExpectations(timeout: timeout, handler: nil)
  247. // Then
  248. XCTAssertNotNil(response?.request)
  249. XCTAssertNotNil(response?.response)
  250. XCTAssertNil(response?.fileURL)
  251. XCTAssertNil(response?.resumeData)
  252. XCTAssertNotNil(response?.error)
  253. XCTAssertEqual((response?.error?.underlyingError as? CocoaError)?.code, .fileNoSuchFile)
  254. }
  255. func testThatDownloadOptionsCanCreateIntermediateDirectoriesPriorToMovingFile() {
  256. // Given
  257. let fileURL = testDirectoryURL.appendingPathComponent("some/random/folder/test_output.json")
  258. let expectation = self.expectation(description: "Download request should download data to file: \(fileURL)")
  259. var response: DownloadResponse<URL?, AFError>?
  260. // When
  261. AF.download("https://httpbin.org/get", to: { _, _ in (fileURL, [.createIntermediateDirectories]) })
  262. .response { resp in
  263. response = resp
  264. expectation.fulfill()
  265. }
  266. waitForExpectations(timeout: timeout, handler: nil)
  267. // Then
  268. XCTAssertNotNil(response?.request)
  269. XCTAssertNotNil(response?.response)
  270. XCTAssertNotNil(response?.fileURL)
  271. XCTAssertNil(response?.resumeData)
  272. XCTAssertNil(response?.error)
  273. }
  274. func testThatDownloadingFileAndMovingToDestinationThatIsOccupiedThrowsError() throws {
  275. // Given
  276. let directoryURL = testDirectoryURL.appendingPathComponent("some/random/folder")
  277. let directoryCreated = FileManager.createDirectory(at: directoryURL)
  278. let fileURL = directoryURL.appendingPathComponent("test_output.json")
  279. try "random_data".write(to: fileURL, atomically: true, encoding: .utf8)
  280. let expectation = self.expectation(description: "Download should complete but fail to move file")
  281. var response: DownloadResponse<URL?, AFError>?
  282. // When
  283. AF.download("https://httpbin.org/get", to: { _, _ in (fileURL, []) })
  284. .response { resp in
  285. response = resp
  286. expectation.fulfill()
  287. }
  288. waitForExpectations(timeout: timeout, handler: nil)
  289. // Then
  290. XCTAssertTrue(directoryCreated)
  291. XCTAssertNotNil(response?.request)
  292. XCTAssertNotNil(response?.response)
  293. XCTAssertNil(response?.fileURL)
  294. XCTAssertNil(response?.resumeData)
  295. XCTAssertNotNil(response?.error)
  296. XCTAssertEqual((response?.error?.underlyingError as? CocoaError)?.code, .fileWriteFileExists)
  297. }
  298. func testThatDownloadOptionsCanRemovePreviousFilePriorToMovingFile() {
  299. // Given
  300. let directoryURL = testDirectoryURL.appendingPathComponent("some/random/folder")
  301. let directoryCreated = FileManager.createDirectory(at: directoryURL)
  302. let fileURL = directoryURL.appendingPathComponent("test_output.json")
  303. let expectation = self.expectation(description: "Download should complete and move file to URL: \(fileURL)")
  304. var response: DownloadResponse<URL?, AFError>?
  305. // When
  306. AF.download("https://httpbin.org/get", to: { _, _ in (fileURL, [.removePreviousFile, .createIntermediateDirectories]) })
  307. .response { resp in
  308. response = resp
  309. expectation.fulfill()
  310. }
  311. waitForExpectations(timeout: timeout, handler: nil)
  312. // Then
  313. XCTAssertTrue(directoryCreated)
  314. XCTAssertNotNil(response?.request)
  315. XCTAssertNotNil(response?.response)
  316. XCTAssertNotNil(response?.fileURL)
  317. XCTAssertNil(response?.resumeData)
  318. XCTAssertNil(response?.error)
  319. }
  320. }
  321. // MARK: -
  322. final class DownloadRequestEventsTestCase: BaseTestCase {
  323. func testThatDownloadRequestTriggersAllAppropriateLifetimeEvents() {
  324. // Given
  325. let eventMonitor = ClosureEventMonitor()
  326. let session = Session(eventMonitors: [eventMonitor])
  327. let taskDidFinishCollecting = expectation(description: "taskDidFinishCollecting should fire")
  328. let didCreateInitialURLRequest = expectation(description: "didCreateInitialURLRequest should fire")
  329. let didCreateURLRequest = expectation(description: "didCreateURLRequest should fire")
  330. let didCreateTask = expectation(description: "didCreateTask should fire")
  331. let didGatherMetrics = expectation(description: "didGatherMetrics should fire")
  332. let didComplete = expectation(description: "didComplete should fire")
  333. let didWriteData = expectation(description: "didWriteData should fire")
  334. let didFinishDownloading = expectation(description: "didFinishDownloading should fire")
  335. let didFinishWithResult = expectation(description: "didFinishWithResult should fire")
  336. let didCreate = expectation(description: "didCreate should fire")
  337. let didFinish = expectation(description: "didFinish should fire")
  338. let didResume = expectation(description: "didResume should fire")
  339. let didResumeTask = expectation(description: "didResumeTask should fire")
  340. let didParseResponse = expectation(description: "didParseResponse should fire")
  341. let responseHandler = expectation(description: "responseHandler should fire")
  342. var wroteData = false
  343. eventMonitor.taskDidFinishCollectingMetrics = { _, _, _ in taskDidFinishCollecting.fulfill() }
  344. eventMonitor.requestDidCreateInitialURLRequest = { _, _ in didCreateInitialURLRequest.fulfill() }
  345. eventMonitor.requestDidCreateURLRequest = { _, _ in didCreateURLRequest.fulfill() }
  346. eventMonitor.requestDidCreateTask = { _, _ in didCreateTask.fulfill() }
  347. eventMonitor.requestDidGatherMetrics = { _, _ in didGatherMetrics.fulfill() }
  348. eventMonitor.requestDidCompleteTaskWithError = { _, _, _ in didComplete.fulfill() }
  349. eventMonitor.downloadTaskDidWriteData = { _, _, _, _, _ in
  350. guard !wroteData else { return }
  351. wroteData = true
  352. didWriteData.fulfill()
  353. }
  354. eventMonitor.downloadTaskDidFinishDownloadingToURL = { _, _, _ in didFinishDownloading.fulfill() }
  355. eventMonitor.requestDidFinishDownloadingUsingTaskWithResult = { _, _, _ in didFinishWithResult.fulfill() }
  356. eventMonitor.requestDidCreateDestinationURL = { _, _ in didCreate.fulfill() }
  357. eventMonitor.requestDidFinish = { _ in didFinish.fulfill() }
  358. eventMonitor.requestDidResume = { _ in didResume.fulfill() }
  359. eventMonitor.requestDidResumeTask = { _, _ in didResumeTask.fulfill() }
  360. eventMonitor.requestDidParseDownloadResponse = { _, _ in didParseResponse.fulfill() }
  361. // When
  362. let request = session.download(URLRequest.makeHTTPBinRequest()).response { _ in
  363. responseHandler.fulfill()
  364. }
  365. waitForExpectations(timeout: timeout, handler: nil)
  366. // Then
  367. XCTAssertEqual(request.state, .finished)
  368. }
  369. func testThatCancelledDownloadRequestTriggersAllAppropriateLifetimeEvents() {
  370. // Given
  371. let eventMonitor = ClosureEventMonitor()
  372. let session = Session(startRequestsImmediately: false, eventMonitors: [eventMonitor])
  373. let taskDidFinishCollecting = expectation(description: "taskDidFinishCollecting should fire")
  374. let didCreateInitialURLRequest = expectation(description: "didCreateInitialURLRequest should fire")
  375. let didCreateURLRequest = expectation(description: "didCreateURLRequest should fire")
  376. let didCreateTask = expectation(description: "didCreateTask should fire")
  377. let didGatherMetrics = expectation(description: "didGatherMetrics should fire")
  378. let didComplete = expectation(description: "didComplete should fire")
  379. let didFinish = expectation(description: "didFinish should fire")
  380. let didResume = expectation(description: "didResume should fire")
  381. let didResumeTask = expectation(description: "didResumeTask should fire")
  382. let didParseResponse = expectation(description: "didParseResponse should fire")
  383. let didCancel = expectation(description: "didCancel should fire")
  384. let didCancelTask = expectation(description: "didCancelTask should fire")
  385. let responseHandler = expectation(description: "responseHandler should fire")
  386. eventMonitor.taskDidFinishCollectingMetrics = { _, _, _ in taskDidFinishCollecting.fulfill() }
  387. eventMonitor.requestDidCreateInitialURLRequest = { _, _ in didCreateInitialURLRequest.fulfill() }
  388. eventMonitor.requestDidCreateURLRequest = { _, _ in didCreateURLRequest.fulfill() }
  389. eventMonitor.requestDidCreateTask = { _, _ in didCreateTask.fulfill() }
  390. eventMonitor.requestDidGatherMetrics = { _, _ in didGatherMetrics.fulfill() }
  391. eventMonitor.requestDidCompleteTaskWithError = { _, _, _ in didComplete.fulfill() }
  392. eventMonitor.requestDidFinish = { _ in didFinish.fulfill() }
  393. eventMonitor.requestDidResume = { _ in didResume.fulfill() }
  394. eventMonitor.requestDidParseDownloadResponse = { _, _ in didParseResponse.fulfill() }
  395. eventMonitor.requestDidCancel = { _ in didCancel.fulfill() }
  396. eventMonitor.requestDidCancelTask = { _, _ in didCancelTask.fulfill() }
  397. // When
  398. let request = session.download(URLRequest.makeHTTPBinRequest(path: "delay/5")).response { _ in
  399. responseHandler.fulfill()
  400. }
  401. eventMonitor.requestDidResumeTask = { [unowned request] _, _ in
  402. request.cancel()
  403. didResumeTask.fulfill()
  404. }
  405. request.resume()
  406. waitForExpectations(timeout: timeout, handler: nil)
  407. // Then
  408. XCTAssertEqual(request.state, .cancelled)
  409. }
  410. }
  411. // MARK: -
  412. final class DownloadResumeDataTestCase: BaseTestCase {
  413. let urlString = "https://upload.wikimedia.org/wikipedia/commons/thumb/5/5f/HubbleDeepField.800px.jpg/2048px-HubbleDeepField.800px.jpg"
  414. func testThatCancelledDownloadRequestDoesNotProduceResumeData() {
  415. // Given
  416. let expectation = self.expectation(description: "Download should be cancelled")
  417. var cancelled = false
  418. var response: DownloadResponse<URL?, AFError>?
  419. // When
  420. let download = AF.download(urlString)
  421. download.downloadProgress { [unowned download] progress in
  422. guard !cancelled else { return }
  423. if progress.fractionCompleted > 0.1 {
  424. download.cancel()
  425. cancelled = true
  426. }
  427. }
  428. download.response { resp in
  429. response = resp
  430. expectation.fulfill()
  431. }
  432. waitForExpectations(timeout: timeout, handler: nil)
  433. // Then
  434. XCTAssertNotNil(response?.request)
  435. XCTAssertNotNil(response?.response)
  436. XCTAssertNil(response?.fileURL)
  437. XCTAssertNotNil(response?.error)
  438. XCTAssertNil(response?.resumeData)
  439. XCTAssertNil(download.resumeData)
  440. }
  441. func testThatCancelledDownloadResponseDataMatchesResumeData() {
  442. // Given
  443. let expectation = self.expectation(description: "Download should be cancelled")
  444. var cancelled = false
  445. var response: DownloadResponse<URL?, AFError>?
  446. // When
  447. let download = AF.download(urlString)
  448. download.downloadProgress { [unowned download] progress in
  449. guard !cancelled else { return }
  450. if progress.fractionCompleted > 0.1 {
  451. download.cancel(producingResumeData: true)
  452. cancelled = true
  453. }
  454. }
  455. download.response { resp in
  456. response = resp
  457. expectation.fulfill()
  458. }
  459. waitForExpectations(timeout: timeout, handler: nil)
  460. // Then
  461. XCTAssertNotNil(response?.request)
  462. XCTAssertNotNil(response?.response)
  463. XCTAssertNil(response?.fileURL)
  464. XCTAssertNotNil(response?.error)
  465. XCTAssertNotNil(response?.resumeData)
  466. XCTAssertNotNil(download.resumeData)
  467. XCTAssertEqual(response?.resumeData, download.resumeData)
  468. }
  469. func testThatCancelledDownloadResumeDataIsAvailableWithJSONResponseSerializer() {
  470. // Given
  471. let expectation = self.expectation(description: "Download should be cancelled")
  472. var cancelled = false
  473. var response: DownloadResponse<Any, AFError>?
  474. // When
  475. let download = AF.download(urlString)
  476. download.downloadProgress { [unowned download] progress in
  477. guard !cancelled else { return }
  478. if progress.fractionCompleted > 0.1 {
  479. download.cancel(producingResumeData: true)
  480. cancelled = true
  481. }
  482. }
  483. download.responseJSON { resp in
  484. response = resp
  485. expectation.fulfill()
  486. }
  487. waitForExpectations(timeout: timeout, handler: nil)
  488. // Then
  489. XCTAssertNotNil(response?.request)
  490. XCTAssertNotNil(response?.response)
  491. XCTAssertNil(response?.fileURL)
  492. XCTAssertEqual(response?.result.isFailure, true)
  493. XCTAssertNotNil(response?.result.failure)
  494. XCTAssertNotNil(response?.resumeData)
  495. XCTAssertNotNil(download.resumeData)
  496. XCTAssertEqual(response?.resumeData, download.resumeData)
  497. }
  498. // Disabled until we can find another source which supports resume ranges.
  499. func _testThatCancelledDownloadCanBeResumedWithResumeData() {
  500. // Given
  501. let expectation1 = expectation(description: "Download should be cancelled")
  502. var cancelled = false
  503. var response1: DownloadResponse<Data, AFError>?
  504. // When
  505. let download = AF.download(urlString)
  506. download.downloadProgress { [unowned download] progress in
  507. guard !cancelled else { return }
  508. if progress.fractionCompleted > 0.1 {
  509. download.cancel(producingResumeData: true)
  510. cancelled = true
  511. }
  512. }
  513. download.responseData { resp in
  514. response1 = resp
  515. expectation1.fulfill()
  516. }
  517. waitForExpectations(timeout: timeout, handler: nil)
  518. guard let resumeData = download.resumeData else {
  519. XCTFail("resumeData should not be nil")
  520. return
  521. }
  522. let expectation2 = expectation(description: "Download should complete")
  523. var progressValues: [Double] = []
  524. var response2: DownloadResponse<Data, AFError>?
  525. AF.download(resumingWith: resumeData)
  526. .downloadProgress { progress in
  527. progressValues.append(progress.fractionCompleted)
  528. }
  529. .responseData { resp in
  530. response2 = resp
  531. expectation2.fulfill()
  532. }
  533. waitForExpectations(timeout: timeout, handler: nil)
  534. // Then
  535. XCTAssertNotNil(response1?.request)
  536. XCTAssertNotNil(response1?.response)
  537. XCTAssertNil(response1?.fileURL)
  538. XCTAssertEqual(response1?.result.isFailure, true)
  539. XCTAssertNotNil(response1?.result.failure)
  540. XCTAssertNotNil(response2?.response)
  541. XCTAssertNotNil(response2?.fileURL)
  542. XCTAssertEqual(response2?.result.isSuccess, true)
  543. XCTAssertNil(response2?.result.failure)
  544. progressValues.forEach { XCTAssertGreaterThanOrEqual($0, 0.1) }
  545. }
  546. func testThatCancelledDownloadProducesMatchingResumeData() {
  547. // Given
  548. let expectation = self.expectation(description: "Download should be cancelled")
  549. var cancelled = false
  550. var receivedResumeData: Data?
  551. var response: DownloadResponse<URL?, AFError>?
  552. // When
  553. let download = AF.download(urlString)
  554. download.downloadProgress { [unowned download] progress in
  555. guard !cancelled else { return }
  556. if progress.fractionCompleted > 0.1 {
  557. download.cancel { receivedResumeData = $0 }
  558. cancelled = true
  559. }
  560. }
  561. download.response { resp in
  562. response = resp
  563. expectation.fulfill()
  564. }
  565. waitForExpectations(timeout: timeout, handler: nil)
  566. // Then
  567. XCTAssertNotNil(response?.request)
  568. XCTAssertNotNil(response?.response)
  569. XCTAssertNil(response?.fileURL)
  570. XCTAssertNotNil(response?.error)
  571. XCTAssertNotNil(response?.resumeData)
  572. XCTAssertNotNil(download.resumeData)
  573. XCTAssertEqual(response?.resumeData, download.resumeData)
  574. XCTAssertEqual(response?.resumeData, receivedResumeData)
  575. XCTAssertEqual(download.resumeData, receivedResumeData)
  576. }
  577. }
  578. // MARK: -
  579. final class DownloadResponseMapTestCase: BaseTestCase {
  580. func testThatMapTransformsSuccessValue() {
  581. // Given
  582. let urlString = "https://httpbin.org/get"
  583. let expectation = self.expectation(description: "request should succeed")
  584. var response: DownloadResponse<String, AFError>?
  585. // When
  586. AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  587. response = resp.map { json in
  588. // json["args"]["foo"] is "bar": use this invariant to test the map function
  589. ((json as? [String: Any])?["args"] as? [String: Any])?["foo"] as? String ?? "invalid"
  590. }
  591. expectation.fulfill()
  592. }
  593. waitForExpectations(timeout: timeout, handler: nil)
  594. // Then
  595. XCTAssertNotNil(response?.request)
  596. XCTAssertNotNil(response?.response)
  597. XCTAssertNotNil(response?.fileURL)
  598. XCTAssertNil(response?.resumeData)
  599. XCTAssertNil(response?.error)
  600. XCTAssertEqual(response?.result.success, "bar")
  601. XCTAssertNotNil(response?.metrics)
  602. }
  603. func testThatMapPreservesFailureError() {
  604. // Given
  605. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  606. let expectation = self.expectation(description: "request should fail with 404")
  607. var response: DownloadResponse<String, AFError>?
  608. // When
  609. AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  610. response = resp.map { _ in "ignored" }
  611. expectation.fulfill()
  612. }
  613. waitForExpectations(timeout: timeout, handler: nil)
  614. // Then
  615. XCTAssertNotNil(response?.request)
  616. XCTAssertNil(response?.response)
  617. XCTAssertNil(response?.fileURL)
  618. XCTAssertNil(response?.resumeData)
  619. XCTAssertNotNil(response?.error)
  620. XCTAssertEqual(response?.result.isFailure, true)
  621. XCTAssertNotNil(response?.metrics)
  622. }
  623. }
  624. // MARK: -
  625. final class DownloadResponseTryMapTestCase: BaseTestCase {
  626. func testThatTryMapTransformsSuccessValue() {
  627. // Given
  628. let urlString = "https://httpbin.org/get"
  629. let expectation = self.expectation(description: "request should succeed")
  630. var response: DownloadResponse<String, Error>?
  631. // When
  632. AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  633. response = resp.tryMap { json in
  634. // json["args"]["foo"] is "bar": use this invariant to test the map function
  635. ((json as? [String: Any])?["args"] as? [String: Any])?["foo"] as? String ?? "invalid"
  636. }
  637. expectation.fulfill()
  638. }
  639. waitForExpectations(timeout: timeout, handler: nil)
  640. // Then
  641. XCTAssertNotNil(response?.request)
  642. XCTAssertNotNil(response?.response)
  643. XCTAssertNotNil(response?.fileURL)
  644. XCTAssertNil(response?.resumeData)
  645. XCTAssertNil(response?.error)
  646. XCTAssertEqual(response?.result.success, "bar")
  647. XCTAssertNotNil(response?.metrics)
  648. }
  649. func testThatTryMapCatchesTransformationError() {
  650. // Given
  651. struct TransformError: Error {}
  652. let urlString = "https://httpbin.org/get"
  653. let expectation = self.expectation(description: "request should succeed")
  654. var response: DownloadResponse<String, Error>?
  655. // When
  656. AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  657. response = resp.tryMap { _ in
  658. throw TransformError()
  659. }
  660. expectation.fulfill()
  661. }
  662. waitForExpectations(timeout: timeout, handler: nil)
  663. // Then
  664. XCTAssertNotNil(response?.request)
  665. XCTAssertNotNil(response?.response)
  666. XCTAssertNotNil(response?.fileURL)
  667. XCTAssertNil(response?.resumeData)
  668. if let error = response?.result.failure {
  669. XCTAssertTrue(error is TransformError)
  670. } else {
  671. XCTFail("flatMap should catch the transformation error")
  672. }
  673. XCTAssertNotNil(response?.metrics)
  674. }
  675. func testThatTryMapPreservesFailureError() {
  676. // Given
  677. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  678. let expectation = self.expectation(description: "request should fail with 404")
  679. var response: DownloadResponse<String, Error>?
  680. // When
  681. AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  682. response = resp.tryMap { _ in "ignored" }
  683. expectation.fulfill()
  684. }
  685. waitForExpectations(timeout: timeout, handler: nil)
  686. // Then
  687. XCTAssertNotNil(response?.request)
  688. XCTAssertNil(response?.response)
  689. XCTAssertNil(response?.fileURL)
  690. XCTAssertNil(response?.resumeData)
  691. XCTAssertNotNil(response?.error)
  692. XCTAssertEqual(response?.result.isFailure, true)
  693. XCTAssertNotNil(response?.metrics)
  694. }
  695. }
  696. final class DownloadResponseMapErrorTestCase: BaseTestCase {
  697. func testThatMapErrorTransformsFailureValue() {
  698. // Given
  699. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  700. let expectation = self.expectation(description: "request should not succeed")
  701. var response: DownloadResponse<Any, TestError>?
  702. // When
  703. AF.download(urlString).responseJSON { resp in
  704. response = resp.mapError { error in
  705. TestError.error(error: error)
  706. }
  707. expectation.fulfill()
  708. }
  709. waitForExpectations(timeout: timeout, handler: nil)
  710. // Then
  711. XCTAssertNotNil(response?.request)
  712. XCTAssertNil(response?.response)
  713. XCTAssertNil(response?.fileURL)
  714. XCTAssertNil(response?.resumeData)
  715. XCTAssertNotNil(response?.error)
  716. XCTAssertEqual(response?.result.isFailure, true)
  717. guard let error = response?.error, case .error = error else { XCTFail(); return }
  718. XCTAssertNotNil(response?.metrics)
  719. }
  720. func testThatMapErrorPreservesSuccessValue() {
  721. // Given
  722. let urlString = "https://httpbin.org/get"
  723. let expectation = self.expectation(description: "request should succeed")
  724. var response: DownloadResponse<Data, TestError>?
  725. // When
  726. AF.download(urlString).responseData { resp in
  727. response = resp.mapError { TestError.error(error: $0) }
  728. expectation.fulfill()
  729. }
  730. waitForExpectations(timeout: timeout, handler: nil)
  731. // Then
  732. XCTAssertNotNil(response?.request)
  733. XCTAssertNotNil(response?.response)
  734. XCTAssertNotNil(response?.fileURL)
  735. XCTAssertNil(response?.resumeData)
  736. XCTAssertEqual(response?.result.isSuccess, true)
  737. XCTAssertNotNil(response?.metrics)
  738. }
  739. }
  740. // MARK: -
  741. final class DownloadResponseTryMapErrorTestCase: BaseTestCase {
  742. func testThatTryMapErrorPreservesSuccessValue() {
  743. // Given
  744. let urlString = "https://httpbin.org/get"
  745. let expectation = self.expectation(description: "request should succeed")
  746. var response: DownloadResponse<Data, Error>?
  747. // When
  748. AF.download(urlString).responseData { resp in
  749. response = resp.tryMapError { TestError.error(error: $0) }
  750. expectation.fulfill()
  751. }
  752. waitForExpectations(timeout: timeout, handler: nil)
  753. // Then
  754. XCTAssertNotNil(response?.request)
  755. XCTAssertNotNil(response?.response)
  756. XCTAssertNotNil(response?.fileURL)
  757. XCTAssertNil(response?.resumeData)
  758. XCTAssertNil(response?.error)
  759. XCTAssertEqual(response?.result.isSuccess, true)
  760. XCTAssertNotNil(response?.metrics)
  761. }
  762. func testThatTryMapErrorCatchesTransformationError() {
  763. // Given
  764. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  765. let expectation = self.expectation(description: "request should fail")
  766. var response: DownloadResponse<Data, Error>?
  767. // When
  768. AF.download(urlString).responseData { resp in
  769. response = resp.tryMapError { _ in try TransformationError.error.alwaysFails() }
  770. expectation.fulfill()
  771. }
  772. waitForExpectations(timeout: timeout, handler: nil)
  773. // Then
  774. XCTAssertNotNil(response?.request)
  775. XCTAssertNil(response?.response)
  776. XCTAssertNil(response?.fileURL)
  777. XCTAssertNil(response?.resumeData)
  778. XCTAssertNotNil(response?.error)
  779. XCTAssertEqual(response?.result.isFailure, true)
  780. if let error = response?.result.failure {
  781. XCTAssertTrue(error is TransformationError)
  782. } else {
  783. XCTFail("flatMapError should catch the transformation error")
  784. }
  785. XCTAssertNotNil(response?.metrics)
  786. }
  787. func testThatTryMapErrorTransformsError() {
  788. // Given
  789. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  790. let expectation = self.expectation(description: "request should fail")
  791. var response: DownloadResponse<Data, Error>?
  792. // When
  793. AF.download(urlString).responseData { resp in
  794. response = resp.tryMapError { TestError.error(error: $0) }
  795. expectation.fulfill()
  796. }
  797. waitForExpectations(timeout: timeout, handler: nil)
  798. // Then
  799. XCTAssertNotNil(response?.request)
  800. XCTAssertNil(response?.response)
  801. XCTAssertNil(response?.fileURL)
  802. XCTAssertNil(response?.resumeData)
  803. XCTAssertNotNil(response?.error)
  804. XCTAssertEqual(response?.result.isFailure, true)
  805. guard let error = response?.error, case TestError.error = error else { XCTFail(); return }
  806. XCTAssertNotNil(response?.metrics)
  807. }
  808. }