DownloadTests.swift 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846
  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 = ["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. XCTAssertNotNil(response?.request)
  114. XCTAssertNil(response?.response)
  115. XCTAssertNil(response?.fileURL)
  116. XCTAssertNil(response?.resumeData)
  117. XCTAssertNotNil(response?.error)
  118. }
  119. func testDownloadRequestWithProgress() {
  120. // Given
  121. let randomBytes = 1 * 1024 * 1024
  122. let urlString = "https://httpbin.org/bytes/\(randomBytes)"
  123. let expectation = self.expectation(description: "Bytes download progress should be reported: \(urlString)")
  124. var progressValues: [Double] = []
  125. var response: DownloadResponse<URL?>?
  126. // When
  127. AF.download(urlString)
  128. .downloadProgress { progress in
  129. progressValues.append(progress.fractionCompleted)
  130. }
  131. .response { resp in
  132. response = resp
  133. expectation.fulfill()
  134. }
  135. waitForExpectations(timeout: timeout, handler: nil)
  136. // Then
  137. XCTAssertNotNil(response?.request)
  138. XCTAssertNotNil(response?.response)
  139. XCTAssertNotNil(response?.fileURL)
  140. XCTAssertNil(response?.resumeData)
  141. XCTAssertNil(response?.error)
  142. var previousProgress: Double = progressValues.first ?? 0.0
  143. for progress in progressValues {
  144. XCTAssertGreaterThanOrEqual(progress, previousProgress)
  145. previousProgress = progress
  146. }
  147. if let lastProgressValue = progressValues.last {
  148. XCTAssertEqual(lastProgressValue, 1.0)
  149. } else {
  150. XCTFail("last item in progressValues should not be nil")
  151. }
  152. }
  153. func testDownloadRequestWithParameters() {
  154. // Given
  155. let fileURL = randomCachesFileURL
  156. let urlString = "https://httpbin.org/get"
  157. let parameters = ["foo": "bar"]
  158. let destination: DownloadRequest.Destination = { _, _ in (fileURL, []) }
  159. let expectation = self.expectation(description: "Download request should download data to file")
  160. var response: DownloadResponse<URL?>?
  161. // When
  162. AF.download(urlString, parameters: parameters, to: destination)
  163. .response { resp in
  164. response = resp
  165. expectation.fulfill()
  166. }
  167. waitForExpectations(timeout: timeout, handler: nil)
  168. // Then
  169. XCTAssertNotNil(response?.request)
  170. XCTAssertNotNil(response?.response)
  171. XCTAssertNotNil(response?.fileURL)
  172. XCTAssertNil(response?.resumeData)
  173. XCTAssertNil(response?.error)
  174. // TODO: Fails since the file is deleted by the time we get here?
  175. if
  176. let data = try? Data(contentsOf: fileURL),
  177. let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []),
  178. let json = jsonObject as? [String: Any],
  179. let args = json["args"] as? [String: String]
  180. {
  181. XCTAssertEqual(args["foo"], "bar")
  182. } else {
  183. XCTFail("args parameter in JSON should not be nil")
  184. }
  185. }
  186. func testDownloadRequestWithHeaders() {
  187. // Given
  188. let fileURL = randomCachesFileURL
  189. let urlString = "https://httpbin.org/get"
  190. let headers = ["Authorization": "123456"]
  191. let destination: DownloadRequest.Destination = { _, _ in (fileURL, []) }
  192. let expectation = self.expectation(description: "Download request should download data to file: \(fileURL)")
  193. var response: DownloadResponse<URL?>?
  194. // When
  195. AF.download(urlString, headers: headers, to: destination)
  196. .response { resp in
  197. response = resp
  198. expectation.fulfill()
  199. }
  200. waitForExpectations(timeout: timeout, handler: nil)
  201. // Then
  202. XCTAssertNotNil(response?.request)
  203. XCTAssertNotNil(response?.response)
  204. XCTAssertNotNil(response?.fileURL)
  205. XCTAssertNil(response?.resumeData)
  206. XCTAssertNil(response?.error)
  207. if
  208. let data = try? Data(contentsOf: fileURL),
  209. let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []),
  210. let json = jsonObject as? [String: Any],
  211. let headers = json["headers"] as? [String: String]
  212. {
  213. XCTAssertEqual(headers["Authorization"], "123456")
  214. } else {
  215. XCTFail("headers parameter in JSON should not be nil")
  216. }
  217. }
  218. func testThatDownloadingFileAndMovingToDirectoryThatDoesNotExistThrowsError() {
  219. // Given
  220. let fileURL = testDirectoryURL.appendingPathComponent("some/random/folder/test_output.json")
  221. let expectation = self.expectation(description: "Download request should download data but fail to move file")
  222. var response: DownloadResponse<URL?>?
  223. // When
  224. AF.download("https://httpbin.org/get", to: { _, _ in (fileURL, [])})
  225. .response { resp in
  226. response = resp
  227. expectation.fulfill()
  228. }
  229. waitForExpectations(timeout: timeout, handler: nil)
  230. // Then
  231. XCTAssertNotNil(response?.request)
  232. XCTAssertNotNil(response?.response)
  233. XCTAssertNil(response?.fileURL)
  234. XCTAssertNil(response?.resumeData)
  235. XCTAssertNotNil(response?.error)
  236. if let error = response?.error as? CocoaError {
  237. XCTAssertEqual(error.code, .fileNoSuchFile)
  238. } else {
  239. XCTFail("error should not be nil")
  240. }
  241. }
  242. func testThatDownloadOptionsCanCreateIntermediateDirectoriesPriorToMovingFile() {
  243. // Given
  244. let fileURL = testDirectoryURL.appendingPathComponent("some/random/folder/test_output.json")
  245. let expectation = self.expectation(description: "Download request should download data to file: \(fileURL)")
  246. var response: DownloadResponse<URL?>?
  247. // When
  248. AF.download("https://httpbin.org/get", to: { _, _ in (fileURL, [.createIntermediateDirectories])})
  249. .response { resp in
  250. response = resp
  251. expectation.fulfill()
  252. }
  253. waitForExpectations(timeout: timeout, handler: nil)
  254. // Then
  255. XCTAssertNotNil(response?.request)
  256. XCTAssertNotNil(response?.response)
  257. XCTAssertNotNil(response?.fileURL)
  258. XCTAssertNil(response?.resumeData)
  259. XCTAssertNil(response?.error)
  260. }
  261. func testThatDownloadingFileAndMovingToDestinationThatIsOccupiedThrowsError() {
  262. do {
  263. // Given
  264. let directoryURL = testDirectoryURL.appendingPathComponent("some/random/folder")
  265. let directoryCreated = FileManager.createDirectory(at: directoryURL)
  266. let fileURL = directoryURL.appendingPathComponent("test_output.json")
  267. try "random_data".write(to: fileURL, atomically: true, encoding: .utf8)
  268. let expectation = self.expectation(description: "Download should complete but fail to move file")
  269. var response: DownloadResponse<URL?>?
  270. // When
  271. AF.download("https://httpbin.org/get", to: { _, _ in (fileURL, [])})
  272. .response { resp in
  273. response = resp
  274. expectation.fulfill()
  275. }
  276. waitForExpectations(timeout: timeout, handler: nil)
  277. // Then
  278. XCTAssertTrue(directoryCreated)
  279. XCTAssertNotNil(response?.request)
  280. XCTAssertNotNil(response?.response)
  281. XCTAssertNil(response?.fileURL)
  282. XCTAssertNil(response?.resumeData)
  283. XCTAssertNotNil(response?.error)
  284. if let error = response?.error as? CocoaError {
  285. XCTAssertEqual(error.code, .fileWriteFileExists)
  286. } else {
  287. XCTFail("error should not be nil")
  288. }
  289. } catch {
  290. XCTFail("Test encountered unexpected error: \(error)")
  291. }
  292. }
  293. func testThatDownloadOptionsCanRemovePreviousFilePriorToMovingFile() {
  294. // Given
  295. let directoryURL = testDirectoryURL.appendingPathComponent("some/random/folder")
  296. let directoryCreated = FileManager.createDirectory(at: directoryURL)
  297. let fileURL = directoryURL.appendingPathComponent("test_output.json")
  298. let expectation = self.expectation(description: "Download should complete and move file to URL: \(fileURL)")
  299. var response: DownloadResponse<URL?>?
  300. // When
  301. AF.download("https://httpbin.org/get", to: { _, _ in (fileURL, [.removePreviousFile, .createIntermediateDirectories])})
  302. .response { resp in
  303. response = resp
  304. expectation.fulfill()
  305. }
  306. waitForExpectations(timeout: timeout, handler: nil)
  307. // Then
  308. XCTAssertTrue(directoryCreated)
  309. XCTAssertNotNil(response?.request)
  310. XCTAssertNotNil(response?.response)
  311. XCTAssertNotNil(response?.fileURL)
  312. XCTAssertNil(response?.resumeData)
  313. XCTAssertNil(response?.error)
  314. }
  315. }
  316. // MARK: -
  317. class DownloadResumeDataTestCase: BaseTestCase {
  318. let urlString = "https://upload.wikimedia.org/wikipedia/commons/6/69/NASA-HS201427a-HubbleUltraDeepField2014-20140603.jpg"
  319. func testThatImmediatelyCancelledDownloadDoesNotHaveResumeDataAvailable() {
  320. // Given
  321. let expectation = self.expectation(description: "Download should be cancelled")
  322. var response: DownloadResponse<URL?>?
  323. // When
  324. let download = AF.download(urlString)
  325. .response { resp in
  326. response = resp
  327. expectation.fulfill()
  328. }
  329. download.cancel()
  330. waitForExpectations(timeout: timeout, handler: nil)
  331. // Then
  332. XCTAssertNotNil(response?.request)
  333. XCTAssertNil(response?.response)
  334. XCTAssertNil(response?.fileURL)
  335. XCTAssertNil(response?.resumeData)
  336. XCTAssertNotNil(response?.error)
  337. XCTAssertNil(download.resumeData)
  338. }
  339. func testThatCancelledDownloadResponseDataMatchesResumeData() {
  340. // Given
  341. let expectation = self.expectation(description: "Download should be cancelled")
  342. var cancelled = false
  343. var response: DownloadResponse<URL?>?
  344. // When
  345. let download = AF.download(urlString)
  346. download.downloadProgress { progress in
  347. guard !cancelled else { return }
  348. if progress.fractionCompleted > 0.1 {
  349. download.cancel()
  350. cancelled = true
  351. }
  352. }
  353. download.response { resp in
  354. response = resp
  355. expectation.fulfill()
  356. }
  357. waitForExpectations(timeout: timeout, handler: nil)
  358. // Then
  359. XCTAssertNotNil(response?.request)
  360. XCTAssertNotNil(response?.response)
  361. XCTAssertNil(response?.fileURL)
  362. XCTAssertNotNil(response?.error)
  363. XCTAssertNotNil(response?.resumeData)
  364. XCTAssertNotNil(download.resumeData)
  365. XCTAssertEqual(response?.resumeData, download.resumeData)
  366. }
  367. func testThatCancelledDownloadResumeDataIsAvailableWithJSONResponseSerializer() {
  368. // Given
  369. let expectation = self.expectation(description: "Download should be cancelled")
  370. var cancelled = false
  371. var response: DownloadResponse<Any>?
  372. // When
  373. let download = AF.download(urlString)
  374. download.downloadProgress { progress in
  375. guard !cancelled else { return }
  376. if progress.fractionCompleted > 0.1 {
  377. download.cancel()
  378. cancelled = true
  379. }
  380. }
  381. download.responseJSON { resp in
  382. response = resp
  383. expectation.fulfill()
  384. }
  385. waitForExpectations(timeout: timeout, handler: nil)
  386. // Then
  387. XCTAssertNotNil(response?.request)
  388. XCTAssertNotNil(response?.response)
  389. XCTAssertNil(response?.fileURL)
  390. XCTAssertEqual(response?.result.isFailure, true)
  391. XCTAssertNotNil(response?.result.error)
  392. XCTAssertNotNil(response?.resumeData)
  393. XCTAssertNotNil(download.resumeData)
  394. XCTAssertEqual(response?.resumeData, download.resumeData)
  395. }
  396. func testThatCancelledDownloadCanBeResumedWithResumeData() {
  397. // Given
  398. let expectation1 = self.expectation(description: "Download should be cancelled")
  399. var cancelled = false
  400. var response1: DownloadResponse<Data>?
  401. // When
  402. let download = AF.download(urlString)
  403. download.downloadProgress { progress in
  404. guard !cancelled else { return }
  405. if progress.fractionCompleted > 0.4 {
  406. download.cancel()
  407. cancelled = true
  408. }
  409. }
  410. download.responseData { resp in
  411. response1 = resp
  412. expectation1.fulfill()
  413. }
  414. waitForExpectations(timeout: timeout, handler: nil)
  415. guard let resumeData = download.resumeData else {
  416. XCTFail("resumeData should not be nil")
  417. return
  418. }
  419. let expectation2 = self.expectation(description: "Download should complete")
  420. var progressValues: [Double] = []
  421. var response2: DownloadResponse<Data>?
  422. let destination = DownloadRequest.suggestedDownloadDestination(options: [.removePreviousFile, .createIntermediateDirectories])
  423. // TODO: Added destination because temp file was being deleted very quickly.
  424. AF.download(resumingWith: resumeData,
  425. to: destination)
  426. .downloadProgress { progress in
  427. progressValues.append(progress.fractionCompleted)
  428. }
  429. .responseData { resp in
  430. response2 = resp
  431. expectation2.fulfill()
  432. }
  433. waitForExpectations(timeout: timeout, handler: nil)
  434. // Then
  435. XCTAssertNotNil(response1?.request)
  436. XCTAssertNotNil(response1?.response)
  437. XCTAssertNil(response1?.fileURL)
  438. XCTAssertEqual(response1?.result.isFailure, true)
  439. XCTAssertNotNil(response1?.result.error)
  440. XCTAssertNotNil(response2?.response)
  441. XCTAssertNotNil(response2?.fileURL)
  442. XCTAssertEqual(response2?.result.isSuccess, true)
  443. XCTAssertNil(response2?.result.error)
  444. progressValues.forEach { XCTAssertGreaterThanOrEqual($0, 0.4) }
  445. }
  446. }
  447. // MARK: -
  448. class DownloadResponseMapTestCase: BaseTestCase {
  449. func testThatMapTransformsSuccessValue() {
  450. // Given
  451. let urlString = "https://httpbin.org/get"
  452. let expectation = self.expectation(description: "request should succeed")
  453. var response: DownloadResponse<String>?
  454. // When
  455. AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  456. response = resp.map { json in
  457. // json["args"]["foo"] is "bar": use this invariant to test the map function
  458. return ((json as? [String: Any])?["args"] as? [String: Any])?["foo"] as? String ?? "invalid"
  459. }
  460. expectation.fulfill()
  461. }
  462. waitForExpectations(timeout: timeout, handler: nil)
  463. // Then
  464. XCTAssertNotNil(response?.request)
  465. XCTAssertNotNil(response?.response)
  466. XCTAssertNotNil(response?.fileURL)
  467. XCTAssertNil(response?.resumeData)
  468. XCTAssertNil(response?.error)
  469. XCTAssertEqual(response?.result.value, "bar")
  470. XCTAssertNotNil(response?.metrics)
  471. }
  472. func testThatMapPreservesFailureError() {
  473. // Given
  474. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  475. let expectation = self.expectation(description: "request should fail with 404")
  476. var response: DownloadResponse<String>?
  477. // When
  478. AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  479. response = resp.map { _ in "ignored" }
  480. expectation.fulfill()
  481. }
  482. waitForExpectations(timeout: timeout, handler: nil)
  483. // Then
  484. XCTAssertNotNil(response?.request)
  485. XCTAssertNil(response?.response)
  486. XCTAssertNil(response?.fileURL)
  487. XCTAssertNil(response?.resumeData)
  488. XCTAssertNotNil(response?.error)
  489. XCTAssertEqual(response?.result.isFailure, true)
  490. XCTAssertNotNil(response?.metrics)
  491. }
  492. }
  493. // MARK: -
  494. class DownloadResponseFlatMapTestCase: BaseTestCase {
  495. func testThatFlatMapTransformsSuccessValue() {
  496. // Given
  497. let urlString = "https://httpbin.org/get"
  498. let expectation = self.expectation(description: "request should succeed")
  499. var response: DownloadResponse<String>?
  500. // When
  501. AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  502. response = resp.flatMap { json in
  503. // json["args"]["foo"] is "bar": use this invariant to test the map function
  504. return ((json as? [String: Any])?["args"] as? [String: Any])?["foo"] as? String ?? "invalid"
  505. }
  506. expectation.fulfill()
  507. }
  508. waitForExpectations(timeout: timeout, handler: nil)
  509. // Then
  510. XCTAssertNotNil(response?.request)
  511. XCTAssertNotNil(response?.response)
  512. XCTAssertNotNil(response?.fileURL)
  513. XCTAssertNil(response?.resumeData)
  514. XCTAssertNil(response?.error)
  515. XCTAssertEqual(response?.result.value, "bar")
  516. XCTAssertNotNil(response?.metrics)
  517. }
  518. func testThatFlatMapCatchesTransformationError() {
  519. // Given
  520. struct TransformError: Error {}
  521. let urlString = "https://httpbin.org/get"
  522. let expectation = self.expectation(description: "request should succeed")
  523. var response: DownloadResponse<String>?
  524. // When
  525. AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  526. response = resp.flatMap { json in
  527. throw TransformError()
  528. }
  529. expectation.fulfill()
  530. }
  531. waitForExpectations(timeout: timeout, handler: nil)
  532. // Then
  533. XCTAssertNotNil(response?.request)
  534. XCTAssertNotNil(response?.response)
  535. XCTAssertNotNil(response?.fileURL)
  536. XCTAssertNil(response?.resumeData)
  537. if let error = response?.result.error {
  538. XCTAssertTrue(error is TransformError)
  539. } else {
  540. XCTFail("flatMap should catch the transformation error")
  541. }
  542. XCTAssertNotNil(response?.metrics)
  543. }
  544. func testThatFlatMapPreservesFailureError() {
  545. // Given
  546. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  547. let expectation = self.expectation(description: "request should fail with 404")
  548. var response: DownloadResponse<String>?
  549. // When
  550. AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  551. response = resp.flatMap { _ in "ignored" }
  552. expectation.fulfill()
  553. }
  554. waitForExpectations(timeout: timeout, handler: nil)
  555. // Then
  556. XCTAssertNotNil(response?.request)
  557. XCTAssertNil(response?.response)
  558. XCTAssertNil(response?.fileURL)
  559. XCTAssertNil(response?.resumeData)
  560. XCTAssertNotNil(response?.error)
  561. XCTAssertEqual(response?.result.isFailure, true)
  562. XCTAssertNotNil(response?.metrics)
  563. }
  564. }
  565. class DownloadResponseMapErrorTestCase: BaseTestCase {
  566. func testThatMapErrorTransformsFailureValue() {
  567. // Given
  568. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  569. let expectation = self.expectation(description: "request should not succeed")
  570. var response: DownloadResponse<Any>?
  571. // When
  572. AF.download(urlString).responseJSON { resp in
  573. response = resp.mapError { error in
  574. return TestError.error(error: error)
  575. }
  576. expectation.fulfill()
  577. }
  578. waitForExpectations(timeout: timeout, handler: nil)
  579. // Then
  580. XCTAssertNotNil(response?.request)
  581. XCTAssertNil(response?.response)
  582. XCTAssertNil(response?.fileURL)
  583. XCTAssertNil(response?.resumeData)
  584. XCTAssertNotNil(response?.error)
  585. XCTAssertEqual(response?.result.isFailure, true)
  586. guard let error = response?.error as? TestError, case .error = error else { XCTFail(); return }
  587. XCTAssertNotNil(response?.metrics)
  588. }
  589. func testThatMapErrorPreservesSuccessValue() {
  590. // Given
  591. let urlString = "https://httpbin.org/get"
  592. let expectation = self.expectation(description: "request should succeed")
  593. var response: DownloadResponse<Data>?
  594. // When
  595. AF.download(urlString).responseData { resp in
  596. response = resp.mapError { TestError.error(error: $0) }
  597. expectation.fulfill()
  598. }
  599. waitForExpectations(timeout: timeout, handler: nil)
  600. // Then
  601. XCTAssertNotNil(response?.request)
  602. XCTAssertNotNil(response?.response)
  603. XCTAssertNotNil(response?.fileURL)
  604. XCTAssertNil(response?.resumeData)
  605. XCTAssertEqual(response?.result.isSuccess, true)
  606. XCTAssertNotNil(response?.metrics)
  607. }
  608. }
  609. // MARK: -
  610. class DownloadResponseFlatMapErrorTestCase: BaseTestCase {
  611. func testThatFlatMapErrorPreservesSuccessValue() {
  612. // Given
  613. let urlString = "https://httpbin.org/get"
  614. let expectation = self.expectation(description: "request should succeed")
  615. var response: DownloadResponse<Data>?
  616. // When
  617. AF.download(urlString).responseData { resp in
  618. response = resp.flatMapError { TestError.error(error: $0) }
  619. expectation.fulfill()
  620. }
  621. waitForExpectations(timeout: timeout, handler: nil)
  622. // Then
  623. XCTAssertNotNil(response?.request)
  624. XCTAssertNotNil(response?.response)
  625. XCTAssertNotNil(response?.fileURL)
  626. XCTAssertNil(response?.resumeData)
  627. XCTAssertNil(response?.error)
  628. XCTAssertEqual(response?.result.isSuccess, true)
  629. XCTAssertNotNil(response?.metrics)
  630. }
  631. func testThatFlatMapErrorCatchesTransformationError() {
  632. // Given
  633. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  634. let expectation = self.expectation(description: "request should fail")
  635. var response: DownloadResponse<Data>?
  636. // When
  637. AF.download(urlString).responseData { resp in
  638. response = resp.flatMapError { _ in try TransformationError.error.alwaysFails() }
  639. expectation.fulfill()
  640. }
  641. waitForExpectations(timeout: timeout, handler: nil)
  642. // Then
  643. XCTAssertNotNil(response?.request)
  644. XCTAssertNil(response?.response)
  645. XCTAssertNil(response?.fileURL)
  646. XCTAssertNil(response?.resumeData)
  647. XCTAssertNotNil(response?.error)
  648. XCTAssertEqual(response?.result.isFailure, true)
  649. if let error = response?.result.error {
  650. XCTAssertTrue(error is TransformationError)
  651. } else {
  652. XCTFail("flatMapError should catch the transformation error")
  653. }
  654. XCTAssertNotNil(response?.metrics)
  655. }
  656. func testThatFlatMapErrorTransformsError() {
  657. // Given
  658. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  659. let expectation = self.expectation(description: "request should fail")
  660. var response: DownloadResponse<Data>?
  661. // When
  662. AF.download(urlString).responseData { resp in
  663. response = resp.flatMapError { TestError.error(error: $0) }
  664. expectation.fulfill()
  665. }
  666. waitForExpectations(timeout: timeout, handler: nil)
  667. // Then
  668. XCTAssertNotNil(response?.request)
  669. XCTAssertNil(response?.response)
  670. XCTAssertNil(response?.fileURL)
  671. XCTAssertNil(response?.resumeData)
  672. XCTAssertNotNil(response?.error)
  673. XCTAssertEqual(response?.result.isFailure, true)
  674. guard let error = response?.error as? TestError, case .error = error else { XCTFail(); return }
  675. XCTAssertNotNil(response?.metrics)
  676. }
  677. }