DownloadTests.swift 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993
  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 { (resp) 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 { (resp) 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?.value(forHTTPHeaderField: "Authorization"), "123456")
  58. XCTAssertNotNil(request.response)
  59. }
  60. }
  61. // MARK: -
  62. class DownloadResponseTestCase: BaseTestCase {
  63. private var randomCachesFileURL: URL {
  64. return 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?>?
  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 testCancelledDownloadRequest() {
  97. // Given
  98. let fileURL = randomCachesFileURL
  99. let numberOfLines = 10
  100. let urlString = "https://httpbin.org/stream/\(numberOfLines)"
  101. let destination: DownloadRequest.Destination = { _, _ in (fileURL, []) }
  102. let expectation = self.expectation(description: "Cancelled download request should not download data to file")
  103. var response: DownloadResponse<URL?>?
  104. // When
  105. AF.download(urlString, to: destination)
  106. .response { resp in
  107. response = resp
  108. expectation.fulfill()
  109. }
  110. .cancel()
  111. waitForExpectations(timeout: timeout, handler: nil)
  112. // Then
  113. XCTAssertNil(response?.response)
  114. XCTAssertNil(response?.fileURL)
  115. XCTAssertNotNil(response?.error)
  116. }
  117. func testDownloadRequestWithProgress() {
  118. // Given
  119. let randomBytes = 1 * 1024 * 1024
  120. let urlString = "https://httpbin.org/bytes/\(randomBytes)"
  121. let expectation = self.expectation(description: "Bytes download progress should be reported: \(urlString)")
  122. var progressValues: [Double] = []
  123. var response: DownloadResponse<URL?>?
  124. // When
  125. AF.download(urlString)
  126. .downloadProgress { progress in
  127. progressValues.append(progress.fractionCompleted)
  128. }
  129. .response { resp in
  130. response = resp
  131. expectation.fulfill()
  132. }
  133. waitForExpectations(timeout: timeout, handler: nil)
  134. // Then
  135. XCTAssertNotNil(response?.request)
  136. XCTAssertNotNil(response?.response)
  137. XCTAssertNotNil(response?.fileURL)
  138. XCTAssertNil(response?.resumeData)
  139. XCTAssertNil(response?.error)
  140. var previousProgress: Double = progressValues.first ?? 0.0
  141. for progress in progressValues {
  142. XCTAssertGreaterThanOrEqual(progress, previousProgress)
  143. previousProgress = progress
  144. }
  145. if let lastProgressValue = progressValues.last {
  146. XCTAssertEqual(lastProgressValue, 1.0)
  147. } else {
  148. XCTFail("last item in progressValues should not be nil")
  149. }
  150. }
  151. func testDownloadRequestWithParameters() {
  152. // Given
  153. let fileURL = randomCachesFileURL
  154. let urlString = "https://httpbin.org/get"
  155. let parameters = ["foo": "bar"]
  156. let destination: DownloadRequest.Destination = { _, _ in (fileURL, []) }
  157. let expectation = self.expectation(description: "Download request should download data to file")
  158. var response: DownloadResponse<URL?>?
  159. // When
  160. AF.download(urlString, parameters: parameters, to: destination)
  161. .response { resp in
  162. response = resp
  163. expectation.fulfill()
  164. }
  165. waitForExpectations(timeout: timeout, handler: nil)
  166. // Then
  167. XCTAssertNotNil(response?.request)
  168. XCTAssertNotNil(response?.response)
  169. XCTAssertNotNil(response?.fileURL)
  170. XCTAssertNil(response?.resumeData)
  171. XCTAssertNil(response?.error)
  172. // TODO: Fails since the file is deleted by the time we get here?
  173. if
  174. let data = try? Data(contentsOf: fileURL),
  175. let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []),
  176. let json = jsonObject as? [String: Any],
  177. let args = json["args"] as? [String: String]
  178. {
  179. XCTAssertEqual(args["foo"], "bar")
  180. } else {
  181. XCTFail("args parameter in JSON should not be nil")
  182. }
  183. }
  184. func testDownloadRequestWithHeaders() {
  185. // Given
  186. let fileURL = randomCachesFileURL
  187. let urlString = "https://httpbin.org/get"
  188. let headers: HTTPHeaders = ["Authorization": "123456"]
  189. let destination: DownloadRequest.Destination = { _, _ in (fileURL, []) }
  190. let expectation = self.expectation(description: "Download request should download data to file: \(fileURL)")
  191. var response: DownloadResponse<URL?>?
  192. // When
  193. AF.download(urlString, headers: headers, to: destination)
  194. .response { resp in
  195. response = resp
  196. expectation.fulfill()
  197. }
  198. waitForExpectations(timeout: timeout, handler: nil)
  199. // Then
  200. XCTAssertNotNil(response?.request)
  201. XCTAssertNotNil(response?.response)
  202. XCTAssertNotNil(response?.fileURL)
  203. XCTAssertNil(response?.resumeData)
  204. XCTAssertNil(response?.error)
  205. if
  206. let data = try? Data(contentsOf: fileURL),
  207. let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []),
  208. let json = jsonObject as? [String: Any],
  209. let headers = json["headers"] as? [String: String]
  210. {
  211. XCTAssertEqual(headers["Authorization"], "123456")
  212. } else {
  213. XCTFail("headers parameter in JSON should not be nil")
  214. }
  215. }
  216. func testThatDownloadingFileAndMovingToDirectoryThatDoesNotExistThrowsError() {
  217. // Given
  218. let fileURL = testDirectoryURL.appendingPathComponent("some/random/folder/test_output.json")
  219. let expectation = self.expectation(description: "Download request should download data but fail to move file")
  220. var response: DownloadResponse<URL?>?
  221. // When
  222. AF.download("https://httpbin.org/get", to: { _, _ in (fileURL, [])})
  223. .response { resp in
  224. response = resp
  225. expectation.fulfill()
  226. }
  227. waitForExpectations(timeout: timeout, handler: nil)
  228. // Then
  229. XCTAssertNotNil(response?.request)
  230. XCTAssertNotNil(response?.response)
  231. XCTAssertNil(response?.fileURL)
  232. XCTAssertNil(response?.resumeData)
  233. XCTAssertNotNil(response?.error)
  234. if let error = response?.error as? CocoaError {
  235. XCTAssertEqual(error.code, .fileNoSuchFile)
  236. } else {
  237. XCTFail("error should not be nil")
  238. }
  239. }
  240. func testThatDownloadOptionsCanCreateIntermediateDirectoriesPriorToMovingFile() {
  241. // Given
  242. let fileURL = testDirectoryURL.appendingPathComponent("some/random/folder/test_output.json")
  243. let expectation = self.expectation(description: "Download request should download data to file: \(fileURL)")
  244. var response: DownloadResponse<URL?>?
  245. // When
  246. AF.download("https://httpbin.org/get", to: { _, _ in (fileURL, [.createIntermediateDirectories])})
  247. .response { resp in
  248. response = resp
  249. expectation.fulfill()
  250. }
  251. waitForExpectations(timeout: timeout, handler: nil)
  252. // Then
  253. XCTAssertNotNil(response?.request)
  254. XCTAssertNotNil(response?.response)
  255. XCTAssertNotNil(response?.fileURL)
  256. XCTAssertNil(response?.resumeData)
  257. XCTAssertNil(response?.error)
  258. }
  259. func testThatDownloadingFileAndMovingToDestinationThatIsOccupiedThrowsError() {
  260. do {
  261. // Given
  262. let directoryURL = testDirectoryURL.appendingPathComponent("some/random/folder")
  263. let directoryCreated = FileManager.createDirectory(at: directoryURL)
  264. let fileURL = directoryURL.appendingPathComponent("test_output.json")
  265. try "random_data".write(to: fileURL, atomically: true, encoding: .utf8)
  266. let expectation = self.expectation(description: "Download should complete but fail to move file")
  267. var response: DownloadResponse<URL?>?
  268. // When
  269. AF.download("https://httpbin.org/get", to: { _, _ in (fileURL, [])})
  270. .response { resp in
  271. response = resp
  272. expectation.fulfill()
  273. }
  274. waitForExpectations(timeout: timeout, handler: nil)
  275. // Then
  276. XCTAssertTrue(directoryCreated)
  277. XCTAssertNotNil(response?.request)
  278. XCTAssertNotNil(response?.response)
  279. XCTAssertNil(response?.fileURL)
  280. XCTAssertNil(response?.resumeData)
  281. XCTAssertNotNil(response?.error)
  282. if let error = response?.error as? CocoaError {
  283. XCTAssertEqual(error.code, .fileWriteFileExists)
  284. } else {
  285. XCTFail("error should not be nil")
  286. }
  287. } catch {
  288. XCTFail("Test encountered unexpected error: \(error)")
  289. }
  290. }
  291. func testThatDownloadOptionsCanRemovePreviousFilePriorToMovingFile() {
  292. // Given
  293. let directoryURL = testDirectoryURL.appendingPathComponent("some/random/folder")
  294. let directoryCreated = FileManager.createDirectory(at: directoryURL)
  295. let fileURL = directoryURL.appendingPathComponent("test_output.json")
  296. let expectation = self.expectation(description: "Download should complete and move file to URL: \(fileURL)")
  297. var response: DownloadResponse<URL?>?
  298. // When
  299. AF.download("https://httpbin.org/get", to: { _, _ in (fileURL, [.removePreviousFile, .createIntermediateDirectories])})
  300. .response { resp in
  301. response = resp
  302. expectation.fulfill()
  303. }
  304. waitForExpectations(timeout: timeout, handler: nil)
  305. // Then
  306. XCTAssertTrue(directoryCreated)
  307. XCTAssertNotNil(response?.request)
  308. XCTAssertNotNil(response?.response)
  309. XCTAssertNotNil(response?.fileURL)
  310. XCTAssertNil(response?.resumeData)
  311. XCTAssertNil(response?.error)
  312. }
  313. }
  314. final class DownloadRequestEventsTestCase: BaseTestCase {
  315. func testThatDownloadRequestTriggersAllAppropriateLifetimeEvents() {
  316. // Given
  317. let eventMonitor = ClosureEventMonitor()
  318. let session = Session(eventMonitors: [eventMonitor])
  319. let taskDidFinishCollecting = expectation(description: "taskDidFinishCollecting should fire")
  320. let didCreateInitialURLRequest = expectation(description: "didCreateInitialURLRequest should fire")
  321. let didCreateURLRequest = expectation(description: "didCreateURLRequest should fire")
  322. let didCreateTask = expectation(description: "didCreateTask should fire")
  323. let didGatherMetrics = expectation(description: "didGatherMetrics should fire")
  324. let didComplete = expectation(description: "didComplete should fire")
  325. let didWriteData = expectation(description: "didWriteData should fire")
  326. let didFinishDownloading = expectation(description: "didFinishDownloading should fire")
  327. let didFinishWithResult = expectation(description: "didFinishWithResult should fire")
  328. let didCreate = expectation(description: "didCreate should fire")
  329. let didFinish = expectation(description: "didFinish should fire")
  330. let didResume = expectation(description: "didResume should fire")
  331. let didResumeTask = expectation(description: "didResumeTask should fire")
  332. let didParseResponse = expectation(description: "didParseResponse should fire")
  333. let responseHandler = expectation(description: "responseHandler should fire")
  334. var wroteData = false
  335. eventMonitor.taskDidFinishCollectingMetrics = { (_, _, _) in taskDidFinishCollecting.fulfill() }
  336. eventMonitor.requestDidCreateInitialURLRequest = { (_, _) in didCreateInitialURLRequest.fulfill() }
  337. eventMonitor.requestDidCreateURLRequest = { (_, _) in didCreateURLRequest.fulfill() }
  338. eventMonitor.requestDidCreateTask = { (_, _) in didCreateTask.fulfill() }
  339. eventMonitor.requestDidGatherMetrics = { (_, _) in didGatherMetrics.fulfill() }
  340. eventMonitor.requestDidCompleteTaskWithError = { (_, _, _) in didComplete.fulfill() }
  341. eventMonitor.downloadTaskDidWriteData = { (_, _, _, _, _) in
  342. guard !wroteData else { return }
  343. wroteData = true
  344. didWriteData.fulfill()
  345. }
  346. eventMonitor.downloadTaskDidFinishDownloadingToURL = { (_, _, _) in didFinishDownloading.fulfill() }
  347. eventMonitor.requestDidFinishDownloadingUsingTaskWithResult = { (_, _, _) in didFinishWithResult.fulfill() }
  348. eventMonitor.requestDidCreateDestinationURL = { (_, _) in didCreate.fulfill() }
  349. eventMonitor.requestDidFinish = { (_) in didFinish.fulfill() }
  350. eventMonitor.requestDidResume = { (_) in didResume.fulfill() }
  351. eventMonitor.requestDidResumeTask = { (_, _) in didResumeTask.fulfill() }
  352. eventMonitor.requestDidParseDownloadResponse = { (_, _) in didParseResponse.fulfill() }
  353. // When
  354. let request = session.download(URLRequest.makeHTTPBinRequest()).response { response in
  355. responseHandler.fulfill()
  356. }
  357. waitForExpectations(timeout: timeout, handler: nil)
  358. // Then
  359. XCTAssertEqual(request.state, .finished)
  360. }
  361. func testThatCancelledDownloadRequestTriggersAllAppropriateLifetimeEvents() {
  362. // Given
  363. let eventMonitor = ClosureEventMonitor()
  364. let session = Session(startRequestsImmediately: false, eventMonitors: [eventMonitor])
  365. let taskDidFinishCollecting = expectation(description: "taskDidFinishCollecting should fire")
  366. let didCreateInitialURLRequest = expectation(description: "didCreateInitialURLRequest should fire")
  367. let didCreateURLRequest = expectation(description: "didCreateURLRequest should fire")
  368. let didCreateTask = expectation(description: "didCreateTask should fire")
  369. let didGatherMetrics = expectation(description: "didGatherMetrics should fire")
  370. let didComplete = expectation(description: "didComplete should fire")
  371. let didFinish = expectation(description: "didFinish should fire")
  372. let didResume = expectation(description: "didResume should fire")
  373. let didResumeTask = expectation(description: "didResumeTask should fire")
  374. let didParseResponse = expectation(description: "didParseResponse should fire")
  375. let didCancel = expectation(description: "didCancel should fire")
  376. let didCancelTask = expectation(description: "didCancelTask should fire")
  377. let responseHandler = expectation(description: "responseHandler should fire")
  378. eventMonitor.taskDidFinishCollectingMetrics = { (_, _, _) in taskDidFinishCollecting.fulfill() }
  379. eventMonitor.requestDidCreateInitialURLRequest = { (_, _) in didCreateInitialURLRequest.fulfill() }
  380. eventMonitor.requestDidCreateURLRequest = { (_, _) in didCreateURLRequest.fulfill() }
  381. eventMonitor.requestDidCreateTask = { (_, _) in didCreateTask.fulfill() }
  382. eventMonitor.requestDidGatherMetrics = { (_, _) in didGatherMetrics.fulfill() }
  383. eventMonitor.requestDidCompleteTaskWithError = { (_, _, _) in didComplete.fulfill() }
  384. eventMonitor.requestDidFinish = { (_) in didFinish.fulfill() }
  385. eventMonitor.requestDidResume = { (_) in didResume.fulfill() }
  386. eventMonitor.requestDidParseDownloadResponse = { (_, _) in didParseResponse.fulfill() }
  387. eventMonitor.requestDidCancel = { (_) in didCancel.fulfill() }
  388. eventMonitor.requestDidCancelTask = { (_, _) in didCancelTask.fulfill() }
  389. // When
  390. let request = session.download(URLRequest.makeHTTPBinRequest()).response { response in
  391. responseHandler.fulfill()
  392. }
  393. eventMonitor.requestDidResumeTask = { (_, _) in
  394. request.cancel()
  395. didResumeTask.fulfill()
  396. }
  397. request.resume()
  398. waitForExpectations(timeout: timeout, handler: nil)
  399. // Then
  400. XCTAssertEqual(request.state, .cancelled)
  401. }
  402. }
  403. // MARK: -
  404. final class DownloadResumeDataTestCase: BaseTestCase {
  405. let urlString = "https://upload.wikimedia.org/wikipedia/commons/6/69/NASA-HS201427a-HubbleUltraDeepField2014-20140603.jpg"
  406. func testThatCancelledDownloadRequestDoesNotProduceResumeData() {
  407. // Given
  408. let expectation = self.expectation(description: "Download should be cancelled")
  409. var cancelled = false
  410. var response: DownloadResponse<URL?>?
  411. // When
  412. let download = AF.download(urlString)
  413. download.downloadProgress { progress in
  414. guard !cancelled else { return }
  415. if progress.fractionCompleted > 0.1 {
  416. download.cancel()
  417. cancelled = true
  418. }
  419. }
  420. download.response { resp in
  421. response = resp
  422. expectation.fulfill()
  423. }
  424. waitForExpectations(timeout: timeout, handler: nil)
  425. // Then
  426. XCTAssertNotNil(response?.request)
  427. XCTAssertNotNil(response?.response)
  428. XCTAssertNil(response?.fileURL)
  429. XCTAssertNotNil(response?.error)
  430. XCTAssertNil(response?.resumeData)
  431. XCTAssertNil(download.resumeData)
  432. }
  433. func testThatCancelledDownloadResponseDataMatchesResumeData() {
  434. // Given
  435. let expectation = self.expectation(description: "Download should be cancelled")
  436. var cancelled = false
  437. var response: DownloadResponse<URL?>?
  438. // When
  439. let download = AF.download(urlString)
  440. download.downloadProgress { progress in
  441. guard !cancelled else { return }
  442. if progress.fractionCompleted > 0.1 {
  443. download.cancel(producingResumeData: true)
  444. cancelled = true
  445. }
  446. }
  447. download.response { resp in
  448. response = resp
  449. expectation.fulfill()
  450. }
  451. waitForExpectations(timeout: timeout, handler: nil)
  452. // Then
  453. XCTAssertNotNil(response?.request)
  454. XCTAssertNotNil(response?.response)
  455. XCTAssertNil(response?.fileURL)
  456. XCTAssertNotNil(response?.error)
  457. XCTAssertNotNil(response?.resumeData)
  458. XCTAssertNotNil(download.resumeData)
  459. XCTAssertEqual(response?.resumeData, download.resumeData)
  460. }
  461. func testThatCancelledDownloadResumeDataIsAvailableWithJSONResponseSerializer() {
  462. // Given
  463. let expectation = self.expectation(description: "Download should be cancelled")
  464. var cancelled = false
  465. var response: DownloadResponse<Any>?
  466. // When
  467. let download = AF.download(urlString)
  468. download.downloadProgress { progress in
  469. guard !cancelled else { return }
  470. if progress.fractionCompleted > 0.1 {
  471. download.cancel(producingResumeData: true)
  472. cancelled = true
  473. }
  474. }
  475. download.responseJSON { resp in
  476. response = resp
  477. expectation.fulfill()
  478. }
  479. waitForExpectations(timeout: timeout, handler: nil)
  480. // Then
  481. XCTAssertNotNil(response?.request)
  482. XCTAssertNotNil(response?.response)
  483. XCTAssertNil(response?.fileURL)
  484. XCTAssertEqual(response?.result.isFailure, true)
  485. XCTAssertNotNil(response?.result.error)
  486. XCTAssertNotNil(response?.resumeData)
  487. XCTAssertNotNil(download.resumeData)
  488. XCTAssertEqual(response?.resumeData, download.resumeData)
  489. }
  490. func testThatCancelledDownloadCanBeResumedWithResumeData() {
  491. // Given
  492. let expectation1 = self.expectation(description: "Download should be cancelled")
  493. var cancelled = false
  494. var response1: DownloadResponse<Data>?
  495. // When
  496. let download = AF.download(urlString)
  497. download.downloadProgress { progress in
  498. guard !cancelled else { return }
  499. if progress.fractionCompleted > 0.4 {
  500. download.cancel(producingResumeData: true)
  501. cancelled = true
  502. }
  503. }
  504. download.responseData { resp in
  505. response1 = resp
  506. expectation1.fulfill()
  507. }
  508. waitForExpectations(timeout: timeout, handler: nil)
  509. guard let resumeData = download.resumeData else {
  510. XCTFail("resumeData should not be nil")
  511. return
  512. }
  513. let expectation2 = self.expectation(description: "Download should complete")
  514. var progressValues: [Double] = []
  515. var response2: DownloadResponse<Data>?
  516. AF.download(resumingWith: resumeData)
  517. .downloadProgress { progress in
  518. progressValues.append(progress.fractionCompleted)
  519. }
  520. .responseData { resp in
  521. response2 = resp
  522. expectation2.fulfill()
  523. }
  524. waitForExpectations(timeout: timeout, handler: nil)
  525. // Then
  526. XCTAssertNotNil(response1?.request)
  527. XCTAssertNotNil(response1?.response)
  528. XCTAssertNil(response1?.fileURL)
  529. XCTAssertEqual(response1?.result.isFailure, true)
  530. XCTAssertNotNil(response1?.result.error)
  531. XCTAssertNotNil(response2?.response)
  532. XCTAssertNotNil(response2?.fileURL)
  533. XCTAssertEqual(response2?.result.isSuccess, true)
  534. XCTAssertNil(response2?.result.error)
  535. progressValues.forEach { XCTAssertGreaterThanOrEqual($0, 0.4) }
  536. }
  537. func testThatCancelledDownloadProducesMatchingResumeData() {
  538. // Given
  539. let expectation = self.expectation(description: "Download should be cancelled")
  540. var cancelled = false
  541. var receivedResumeData: Data?
  542. var response: DownloadResponse<URL?>?
  543. // When
  544. let download = AF.download(urlString)
  545. download.downloadProgress { progress in
  546. guard !cancelled else { return }
  547. if progress.fractionCompleted > 0.1 {
  548. download.cancel { receivedResumeData = $0 }
  549. cancelled = true
  550. }
  551. }
  552. download.response { resp in
  553. response = resp
  554. expectation.fulfill()
  555. }
  556. waitForExpectations(timeout: timeout, handler: nil)
  557. // Then
  558. XCTAssertNotNil(response?.request)
  559. XCTAssertNotNil(response?.response)
  560. XCTAssertNil(response?.fileURL)
  561. XCTAssertNotNil(response?.error)
  562. XCTAssertNotNil(response?.resumeData)
  563. XCTAssertNotNil(download.resumeData)
  564. XCTAssertEqual(response?.resumeData, download.resumeData)
  565. XCTAssertEqual(response?.resumeData, receivedResumeData)
  566. XCTAssertEqual(download.resumeData, receivedResumeData)
  567. }
  568. }
  569. // MARK: -
  570. class DownloadResponseMapTestCase: BaseTestCase {
  571. func testThatMapTransformsSuccessValue() {
  572. // Given
  573. let urlString = "https://httpbin.org/get"
  574. let expectation = self.expectation(description: "request should succeed")
  575. var response: DownloadResponse<String>?
  576. // When
  577. AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  578. response = resp.map { json in
  579. // json["args"]["foo"] is "bar": use this invariant to test the map function
  580. return ((json as? [String: Any])?["args"] as? [String: Any])?["foo"] as? String ?? "invalid"
  581. }
  582. expectation.fulfill()
  583. }
  584. waitForExpectations(timeout: timeout, handler: nil)
  585. // Then
  586. XCTAssertNotNil(response?.request)
  587. XCTAssertNotNil(response?.response)
  588. XCTAssertNotNil(response?.fileURL)
  589. XCTAssertNil(response?.resumeData)
  590. XCTAssertNil(response?.error)
  591. XCTAssertEqual(response?.result.value, "bar")
  592. XCTAssertNotNil(response?.metrics)
  593. }
  594. func testThatMapPreservesFailureError() {
  595. // Given
  596. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  597. let expectation = self.expectation(description: "request should fail with 404")
  598. var response: DownloadResponse<String>?
  599. // When
  600. AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  601. response = resp.map { _ in "ignored" }
  602. expectation.fulfill()
  603. }
  604. waitForExpectations(timeout: timeout, handler: nil)
  605. // Then
  606. XCTAssertNotNil(response?.request)
  607. XCTAssertNil(response?.response)
  608. XCTAssertNil(response?.fileURL)
  609. XCTAssertNil(response?.resumeData)
  610. XCTAssertNotNil(response?.error)
  611. XCTAssertEqual(response?.result.isFailure, true)
  612. XCTAssertNotNil(response?.metrics)
  613. }
  614. }
  615. // MARK: -
  616. class DownloadResponseFlatMapTestCase: BaseTestCase {
  617. func testThatFlatMapTransformsSuccessValue() {
  618. // Given
  619. let urlString = "https://httpbin.org/get"
  620. let expectation = self.expectation(description: "request should succeed")
  621. var response: DownloadResponse<String>?
  622. // When
  623. AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  624. response = resp.flatMap { json in
  625. // json["args"]["foo"] is "bar": use this invariant to test the map function
  626. return ((json as? [String: Any])?["args"] as? [String: Any])?["foo"] as? String ?? "invalid"
  627. }
  628. expectation.fulfill()
  629. }
  630. waitForExpectations(timeout: timeout, handler: nil)
  631. // Then
  632. XCTAssertNotNil(response?.request)
  633. XCTAssertNotNil(response?.response)
  634. XCTAssertNotNil(response?.fileURL)
  635. XCTAssertNil(response?.resumeData)
  636. XCTAssertNil(response?.error)
  637. XCTAssertEqual(response?.result.value, "bar")
  638. XCTAssertNotNil(response?.metrics)
  639. }
  640. func testThatFlatMapCatchesTransformationError() {
  641. // Given
  642. struct TransformError: Error {}
  643. let urlString = "https://httpbin.org/get"
  644. let expectation = self.expectation(description: "request should succeed")
  645. var response: DownloadResponse<String>?
  646. // When
  647. AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  648. response = resp.flatMap { json in
  649. throw TransformError()
  650. }
  651. expectation.fulfill()
  652. }
  653. waitForExpectations(timeout: timeout, handler: nil)
  654. // Then
  655. XCTAssertNotNil(response?.request)
  656. XCTAssertNotNil(response?.response)
  657. XCTAssertNotNil(response?.fileURL)
  658. XCTAssertNil(response?.resumeData)
  659. if let error = response?.result.error {
  660. XCTAssertTrue(error is TransformError)
  661. } else {
  662. XCTFail("flatMap should catch the transformation error")
  663. }
  664. XCTAssertNotNil(response?.metrics)
  665. }
  666. func testThatFlatMapPreservesFailureError() {
  667. // Given
  668. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  669. let expectation = self.expectation(description: "request should fail with 404")
  670. var response: DownloadResponse<String>?
  671. // When
  672. AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  673. response = resp.flatMap { _ in "ignored" }
  674. expectation.fulfill()
  675. }
  676. waitForExpectations(timeout: timeout, handler: nil)
  677. // Then
  678. XCTAssertNotNil(response?.request)
  679. XCTAssertNil(response?.response)
  680. XCTAssertNil(response?.fileURL)
  681. XCTAssertNil(response?.resumeData)
  682. XCTAssertNotNil(response?.error)
  683. XCTAssertEqual(response?.result.isFailure, true)
  684. XCTAssertNotNil(response?.metrics)
  685. }
  686. }
  687. class DownloadResponseMapErrorTestCase: BaseTestCase {
  688. func testThatMapErrorTransformsFailureValue() {
  689. // Given
  690. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  691. let expectation = self.expectation(description: "request should not succeed")
  692. var response: DownloadResponse<Any>?
  693. // When
  694. AF.download(urlString).responseJSON { resp in
  695. response = resp.mapError { error in
  696. return TestError.error(error: error)
  697. }
  698. expectation.fulfill()
  699. }
  700. waitForExpectations(timeout: timeout, handler: nil)
  701. // Then
  702. XCTAssertNotNil(response?.request)
  703. XCTAssertNil(response?.response)
  704. XCTAssertNil(response?.fileURL)
  705. XCTAssertNil(response?.resumeData)
  706. XCTAssertNotNil(response?.error)
  707. XCTAssertEqual(response?.result.isFailure, true)
  708. guard let error = response?.error as? TestError, case .error = error else { XCTFail(); return }
  709. XCTAssertNotNil(response?.metrics)
  710. }
  711. func testThatMapErrorPreservesSuccessValue() {
  712. // Given
  713. let urlString = "https://httpbin.org/get"
  714. let expectation = self.expectation(description: "request should succeed")
  715. var response: DownloadResponse<Data>?
  716. // When
  717. AF.download(urlString).responseData { resp in
  718. response = resp.mapError { TestError.error(error: $0) }
  719. expectation.fulfill()
  720. }
  721. waitForExpectations(timeout: timeout, handler: nil)
  722. // Then
  723. XCTAssertNotNil(response?.request)
  724. XCTAssertNotNil(response?.response)
  725. XCTAssertNotNil(response?.fileURL)
  726. XCTAssertNil(response?.resumeData)
  727. XCTAssertEqual(response?.result.isSuccess, true)
  728. XCTAssertNotNil(response?.metrics)
  729. }
  730. }
  731. // MARK: -
  732. class DownloadResponseFlatMapErrorTestCase: BaseTestCase {
  733. func testThatFlatMapErrorPreservesSuccessValue() {
  734. // Given
  735. let urlString = "https://httpbin.org/get"
  736. let expectation = self.expectation(description: "request should succeed")
  737. var response: DownloadResponse<Data>?
  738. // When
  739. AF.download(urlString).responseData { resp in
  740. response = resp.flatMapError { TestError.error(error: $0) }
  741. expectation.fulfill()
  742. }
  743. waitForExpectations(timeout: timeout, handler: nil)
  744. // Then
  745. XCTAssertNotNil(response?.request)
  746. XCTAssertNotNil(response?.response)
  747. XCTAssertNotNil(response?.fileURL)
  748. XCTAssertNil(response?.resumeData)
  749. XCTAssertNil(response?.error)
  750. XCTAssertEqual(response?.result.isSuccess, true)
  751. XCTAssertNotNil(response?.metrics)
  752. }
  753. func testThatFlatMapErrorCatchesTransformationError() {
  754. // Given
  755. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  756. let expectation = self.expectation(description: "request should fail")
  757. var response: DownloadResponse<Data>?
  758. // When
  759. AF.download(urlString).responseData { resp in
  760. response = resp.flatMapError { _ in try TransformationError.error.alwaysFails() }
  761. expectation.fulfill()
  762. }
  763. waitForExpectations(timeout: timeout, handler: nil)
  764. // Then
  765. XCTAssertNotNil(response?.request)
  766. XCTAssertNil(response?.response)
  767. XCTAssertNil(response?.fileURL)
  768. XCTAssertNil(response?.resumeData)
  769. XCTAssertNotNil(response?.error)
  770. XCTAssertEqual(response?.result.isFailure, true)
  771. if let error = response?.result.error {
  772. XCTAssertTrue(error is TransformationError)
  773. } else {
  774. XCTFail("flatMapError should catch the transformation error")
  775. }
  776. XCTAssertNotNil(response?.metrics)
  777. }
  778. func testThatFlatMapErrorTransformsError() {
  779. // Given
  780. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  781. let expectation = self.expectation(description: "request should fail")
  782. var response: DownloadResponse<Data>?
  783. // When
  784. AF.download(urlString).responseData { resp in
  785. response = resp.flatMapError { TestError.error(error: $0) }
  786. expectation.fulfill()
  787. }
  788. waitForExpectations(timeout: timeout, handler: nil)
  789. // Then
  790. XCTAssertNotNil(response?.request)
  791. XCTAssertNil(response?.response)
  792. XCTAssertNil(response?.fileURL)
  793. XCTAssertNil(response?.resumeData)
  794. XCTAssertNotNil(response?.error)
  795. XCTAssertEqual(response?.result.isFailure, true)
  796. guard let error = response?.error as? TestError, case .error = error else { XCTFail(); return }
  797. XCTAssertNotNil(response?.metrics)
  798. }
  799. }