DownloadTests.swift 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818
  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. // MARK: -
  315. class DownloadResumeDataTestCase: BaseTestCase {
  316. let urlString = "https://upload.wikimedia.org/wikipedia/commons/6/69/NASA-HS201427a-HubbleUltraDeepField2014-20140603.jpg"
  317. func testThatCancelledDownloadResponseDataMatchesResumeData() {
  318. // Given
  319. let expectation = self.expectation(description: "Download should be cancelled")
  320. var cancelled = false
  321. var response: DownloadResponse<URL?>?
  322. // When
  323. let download = AF.download(urlString)
  324. download.downloadProgress { progress in
  325. guard !cancelled else { return }
  326. if progress.fractionCompleted > 0.1 {
  327. download.cancel()
  328. cancelled = true
  329. }
  330. }
  331. download.response { resp in
  332. response = resp
  333. expectation.fulfill()
  334. }
  335. waitForExpectations(timeout: timeout, handler: nil)
  336. // Then
  337. XCTAssertNotNil(response?.request)
  338. XCTAssertNotNil(response?.response)
  339. XCTAssertNil(response?.fileURL)
  340. XCTAssertNotNil(response?.error)
  341. XCTAssertNotNil(response?.resumeData)
  342. XCTAssertNotNil(download.resumeData)
  343. XCTAssertEqual(response?.resumeData, download.resumeData)
  344. }
  345. func testThatCancelledDownloadResumeDataIsAvailableWithJSONResponseSerializer() {
  346. // Given
  347. let expectation = self.expectation(description: "Download should be cancelled")
  348. var cancelled = false
  349. var response: DownloadResponse<Any>?
  350. // When
  351. let download = AF.download(urlString)
  352. download.downloadProgress { progress in
  353. guard !cancelled else { return }
  354. if progress.fractionCompleted > 0.1 {
  355. download.cancel()
  356. cancelled = true
  357. }
  358. }
  359. download.responseJSON { resp in
  360. response = resp
  361. expectation.fulfill()
  362. }
  363. waitForExpectations(timeout: timeout, handler: nil)
  364. // Then
  365. XCTAssertNotNil(response?.request)
  366. XCTAssertNotNil(response?.response)
  367. XCTAssertNil(response?.fileURL)
  368. XCTAssertEqual(response?.result.isFailure, true)
  369. XCTAssertNotNil(response?.result.error)
  370. XCTAssertNotNil(response?.resumeData)
  371. XCTAssertNotNil(download.resumeData)
  372. XCTAssertEqual(response?.resumeData, download.resumeData)
  373. }
  374. func testThatCancelledDownloadCanBeResumedWithResumeData() {
  375. // Given
  376. let expectation1 = self.expectation(description: "Download should be cancelled")
  377. var cancelled = false
  378. var response1: DownloadResponse<Data>?
  379. // When
  380. let download = AF.download(urlString)
  381. download.downloadProgress { progress in
  382. guard !cancelled else { return }
  383. if progress.fractionCompleted > 0.4 {
  384. download.cancel()
  385. cancelled = true
  386. }
  387. }
  388. download.responseData { resp in
  389. response1 = resp
  390. expectation1.fulfill()
  391. }
  392. waitForExpectations(timeout: timeout, handler: nil)
  393. guard let resumeData = download.resumeData else {
  394. XCTFail("resumeData should not be nil")
  395. return
  396. }
  397. let expectation2 = self.expectation(description: "Download should complete")
  398. var progressValues: [Double] = []
  399. var response2: DownloadResponse<Data>?
  400. let destination = DownloadRequest.suggestedDownloadDestination(options: [.removePreviousFile, .createIntermediateDirectories])
  401. // TODO: Added destination because temp file was being deleted very quickly.
  402. AF.download(resumingWith: resumeData,
  403. to: destination)
  404. .downloadProgress { progress in
  405. progressValues.append(progress.fractionCompleted)
  406. }
  407. .responseData { resp in
  408. response2 = resp
  409. expectation2.fulfill()
  410. }
  411. waitForExpectations(timeout: timeout, handler: nil)
  412. // Then
  413. XCTAssertNotNil(response1?.request)
  414. XCTAssertNotNil(response1?.response)
  415. XCTAssertNil(response1?.fileURL)
  416. XCTAssertEqual(response1?.result.isFailure, true)
  417. XCTAssertNotNil(response1?.result.error)
  418. XCTAssertNotNil(response2?.response)
  419. XCTAssertNotNil(response2?.fileURL)
  420. XCTAssertEqual(response2?.result.isSuccess, true)
  421. XCTAssertNil(response2?.result.error)
  422. progressValues.forEach { XCTAssertGreaterThanOrEqual($0, 0.4) }
  423. }
  424. }
  425. // MARK: -
  426. class DownloadResponseMapTestCase: BaseTestCase {
  427. func testThatMapTransformsSuccessValue() {
  428. // Given
  429. let urlString = "https://httpbin.org/get"
  430. let expectation = self.expectation(description: "request should succeed")
  431. var response: DownloadResponse<String>?
  432. // When
  433. AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  434. response = resp.map { json in
  435. // json["args"]["foo"] is "bar": use this invariant to test the map function
  436. return ((json as? [String: Any])?["args"] as? [String: Any])?["foo"] as? String ?? "invalid"
  437. }
  438. expectation.fulfill()
  439. }
  440. waitForExpectations(timeout: timeout, handler: nil)
  441. // Then
  442. XCTAssertNotNil(response?.request)
  443. XCTAssertNotNil(response?.response)
  444. XCTAssertNotNil(response?.fileURL)
  445. XCTAssertNil(response?.resumeData)
  446. XCTAssertNil(response?.error)
  447. XCTAssertEqual(response?.result.value, "bar")
  448. XCTAssertNotNil(response?.metrics)
  449. }
  450. func testThatMapPreservesFailureError() {
  451. // Given
  452. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  453. let expectation = self.expectation(description: "request should fail with 404")
  454. var response: DownloadResponse<String>?
  455. // When
  456. AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  457. response = resp.map { _ in "ignored" }
  458. expectation.fulfill()
  459. }
  460. waitForExpectations(timeout: timeout, handler: nil)
  461. // Then
  462. XCTAssertNotNil(response?.request)
  463. XCTAssertNil(response?.response)
  464. XCTAssertNil(response?.fileURL)
  465. XCTAssertNil(response?.resumeData)
  466. XCTAssertNotNil(response?.error)
  467. XCTAssertEqual(response?.result.isFailure, true)
  468. XCTAssertNotNil(response?.metrics)
  469. }
  470. }
  471. // MARK: -
  472. class DownloadResponseFlatMapTestCase: BaseTestCase {
  473. func testThatFlatMapTransformsSuccessValue() {
  474. // Given
  475. let urlString = "https://httpbin.org/get"
  476. let expectation = self.expectation(description: "request should succeed")
  477. var response: DownloadResponse<String>?
  478. // When
  479. AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  480. response = resp.flatMap { json in
  481. // json["args"]["foo"] is "bar": use this invariant to test the map function
  482. return ((json as? [String: Any])?["args"] as? [String: Any])?["foo"] as? String ?? "invalid"
  483. }
  484. expectation.fulfill()
  485. }
  486. waitForExpectations(timeout: timeout, handler: nil)
  487. // Then
  488. XCTAssertNotNil(response?.request)
  489. XCTAssertNotNil(response?.response)
  490. XCTAssertNotNil(response?.fileURL)
  491. XCTAssertNil(response?.resumeData)
  492. XCTAssertNil(response?.error)
  493. XCTAssertEqual(response?.result.value, "bar")
  494. XCTAssertNotNil(response?.metrics)
  495. }
  496. func testThatFlatMapCatchesTransformationError() {
  497. // Given
  498. struct TransformError: Error {}
  499. let urlString = "https://httpbin.org/get"
  500. let expectation = self.expectation(description: "request should succeed")
  501. var response: DownloadResponse<String>?
  502. // When
  503. AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  504. response = resp.flatMap { json in
  505. throw TransformError()
  506. }
  507. expectation.fulfill()
  508. }
  509. waitForExpectations(timeout: timeout, handler: nil)
  510. // Then
  511. XCTAssertNotNil(response?.request)
  512. XCTAssertNotNil(response?.response)
  513. XCTAssertNotNil(response?.fileURL)
  514. XCTAssertNil(response?.resumeData)
  515. if let error = response?.result.error {
  516. XCTAssertTrue(error is TransformError)
  517. } else {
  518. XCTFail("flatMap should catch the transformation error")
  519. }
  520. XCTAssertNotNil(response?.metrics)
  521. }
  522. func testThatFlatMapPreservesFailureError() {
  523. // Given
  524. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  525. let expectation = self.expectation(description: "request should fail with 404")
  526. var response: DownloadResponse<String>?
  527. // When
  528. AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  529. response = resp.flatMap { _ in "ignored" }
  530. expectation.fulfill()
  531. }
  532. waitForExpectations(timeout: timeout, handler: nil)
  533. // Then
  534. XCTAssertNotNil(response?.request)
  535. XCTAssertNil(response?.response)
  536. XCTAssertNil(response?.fileURL)
  537. XCTAssertNil(response?.resumeData)
  538. XCTAssertNotNil(response?.error)
  539. XCTAssertEqual(response?.result.isFailure, true)
  540. XCTAssertNotNil(response?.metrics)
  541. }
  542. }
  543. class DownloadResponseMapErrorTestCase: BaseTestCase {
  544. func testThatMapErrorTransformsFailureValue() {
  545. // Given
  546. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  547. let expectation = self.expectation(description: "request should not succeed")
  548. var response: DownloadResponse<Any>?
  549. // When
  550. AF.download(urlString).responseJSON { resp in
  551. response = resp.mapError { error in
  552. return TestError.error(error: error)
  553. }
  554. expectation.fulfill()
  555. }
  556. waitForExpectations(timeout: timeout, handler: nil)
  557. // Then
  558. XCTAssertNotNil(response?.request)
  559. XCTAssertNil(response?.response)
  560. XCTAssertNil(response?.fileURL)
  561. XCTAssertNil(response?.resumeData)
  562. XCTAssertNotNil(response?.error)
  563. XCTAssertEqual(response?.result.isFailure, true)
  564. guard let error = response?.error as? TestError, case .error = error else { XCTFail(); return }
  565. XCTAssertNotNil(response?.metrics)
  566. }
  567. func testThatMapErrorPreservesSuccessValue() {
  568. // Given
  569. let urlString = "https://httpbin.org/get"
  570. let expectation = self.expectation(description: "request should succeed")
  571. var response: DownloadResponse<Data>?
  572. // When
  573. AF.download(urlString).responseData { resp in
  574. response = resp.mapError { TestError.error(error: $0) }
  575. expectation.fulfill()
  576. }
  577. waitForExpectations(timeout: timeout, handler: nil)
  578. // Then
  579. XCTAssertNotNil(response?.request)
  580. XCTAssertNotNil(response?.response)
  581. XCTAssertNotNil(response?.fileURL)
  582. XCTAssertNil(response?.resumeData)
  583. XCTAssertEqual(response?.result.isSuccess, true)
  584. XCTAssertNotNil(response?.metrics)
  585. }
  586. }
  587. // MARK: -
  588. class DownloadResponseFlatMapErrorTestCase: BaseTestCase {
  589. func testThatFlatMapErrorPreservesSuccessValue() {
  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.flatMapError { 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. XCTAssertNil(response?.error)
  606. XCTAssertEqual(response?.result.isSuccess, true)
  607. XCTAssertNotNil(response?.metrics)
  608. }
  609. func testThatFlatMapErrorCatchesTransformationError() {
  610. // Given
  611. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  612. let expectation = self.expectation(description: "request should fail")
  613. var response: DownloadResponse<Data>?
  614. // When
  615. AF.download(urlString).responseData { resp in
  616. response = resp.flatMapError { _ in try TransformationError.error.alwaysFails() }
  617. expectation.fulfill()
  618. }
  619. waitForExpectations(timeout: timeout, handler: nil)
  620. // Then
  621. XCTAssertNotNil(response?.request)
  622. XCTAssertNil(response?.response)
  623. XCTAssertNil(response?.fileURL)
  624. XCTAssertNil(response?.resumeData)
  625. XCTAssertNotNil(response?.error)
  626. XCTAssertEqual(response?.result.isFailure, true)
  627. if let error = response?.result.error {
  628. XCTAssertTrue(error is TransformationError)
  629. } else {
  630. XCTFail("flatMapError should catch the transformation error")
  631. }
  632. XCTAssertNotNil(response?.metrics)
  633. }
  634. func testThatFlatMapErrorTransformsError() {
  635. // Given
  636. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  637. let expectation = self.expectation(description: "request should fail")
  638. var response: DownloadResponse<Data>?
  639. // When
  640. AF.download(urlString).responseData { resp in
  641. response = resp.flatMapError { TestError.error(error: $0) }
  642. expectation.fulfill()
  643. }
  644. waitForExpectations(timeout: timeout, handler: nil)
  645. // Then
  646. XCTAssertNotNil(response?.request)
  647. XCTAssertNil(response?.response)
  648. XCTAssertNil(response?.fileURL)
  649. XCTAssertNil(response?.resumeData)
  650. XCTAssertNotNil(response?.error)
  651. XCTAssertEqual(response?.result.isFailure, true)
  652. guard let error = response?.error as? TestError, case .error = error else { XCTFail(); return }
  653. XCTAssertNotNil(response?.metrics)
  654. }
  655. }