DownloadTests.swift 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897
  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 expect = expectation(description: "request should receive appropriate lifetime events")
  320. expect.expectedFulfillmentCount = 14
  321. var wroteData = false
  322. eventMonitor.taskDidFinishCollectingMetrics = { (_, _, _) in expect.fulfill() }
  323. eventMonitor.requestDidCreateURLRequest = { (_, _) in expect.fulfill() }
  324. eventMonitor.requestDidCreateTask = { (_, _) in expect.fulfill() }
  325. eventMonitor.requestDidGatherMetrics = { (_, _) in expect.fulfill() }
  326. eventMonitor.requestDidCompleteTaskWithError = { (_, _, _) in expect.fulfill() }
  327. eventMonitor.downloadTaskDidWriteData = { (_, _, _, _, _) in
  328. guard !wroteData else { return }
  329. wroteData = true
  330. expect.fulfill()
  331. }
  332. eventMonitor.downloadTaskDidFinishDownloadingToURL = { (_, _, _) in expect.fulfill() }
  333. eventMonitor.requestDidFinishDownloadingUsingTaskWithResult = { (_, _, _) in expect.fulfill() }
  334. eventMonitor.requestDidCreateDestinationURL = { (_, _) in expect.fulfill() }
  335. eventMonitor.requestDidFinish = { (_) in expect.fulfill() }
  336. eventMonitor.requestDidResume = { (_) in expect.fulfill() }
  337. eventMonitor.requestDidResumeTask = { (_, _) in expect.fulfill() }
  338. eventMonitor.requestDidParseDownloadResponse = { (_, _) in expect.fulfill() }
  339. // When
  340. let request = session.download(URLRequest.makeHTTPBinRequest()).response { response in
  341. expect.fulfill()
  342. }
  343. waitForExpectations(timeout: timeout, handler: nil)
  344. // Then
  345. XCTAssertEqual(request.state, .resumed)
  346. }
  347. func testThatCancelledDownloadRequestTriggersAllAppropriateLifetimeEvents() {
  348. // Given
  349. let eventMonitor = ClosureEventMonitor()
  350. let session = Session(startRequestsImmediately: false, eventMonitors: [eventMonitor])
  351. let expect = expectation(description: "request should receive appropriate lifetime events")
  352. expect.expectedFulfillmentCount = 12
  353. eventMonitor.taskDidFinishCollectingMetrics = { (_, _, _) in expect.fulfill() }
  354. eventMonitor.requestDidCreateURLRequest = { (_, _) in expect.fulfill() }
  355. eventMonitor.requestDidCreateTask = { (_, _) in expect.fulfill() }
  356. eventMonitor.requestDidGatherMetrics = { (_, _) in expect.fulfill() }
  357. eventMonitor.requestDidCompleteTaskWithError = { (_, _, _) in expect.fulfill() }
  358. eventMonitor.requestDidFinish = { (_) in expect.fulfill() }
  359. eventMonitor.requestDidResume = { (_) in expect.fulfill() }
  360. eventMonitor.requestDidCancel = { _ in expect.fulfill() }
  361. eventMonitor.requestDidCancelTask = { _, _ in expect.fulfill() }
  362. eventMonitor.requestDidParseDownloadResponse = { (_, _) in expect.fulfill() }
  363. // When
  364. let request = session.download(URLRequest.makeHTTPBinRequest()).response { response in
  365. expect.fulfill()
  366. }
  367. eventMonitor.requestDidResumeTask = { (_, _) in
  368. request.cancel()
  369. expect.fulfill()
  370. }
  371. request.resume()
  372. waitForExpectations(timeout: timeout, handler: nil)
  373. // Then
  374. XCTAssertEqual(request.state, .cancelled)
  375. }
  376. }
  377. // MARK: -
  378. class DownloadResumeDataTestCase: BaseTestCase {
  379. let urlString = "https://upload.wikimedia.org/wikipedia/commons/6/69/NASA-HS201427a-HubbleUltraDeepField2014-20140603.jpg"
  380. func testThatCancelledDownloadResponseDataMatchesResumeData() {
  381. // Given
  382. let expectation = self.expectation(description: "Download should be cancelled")
  383. var cancelled = false
  384. var response: DownloadResponse<URL?>?
  385. // When
  386. let download = AF.download(urlString)
  387. download.downloadProgress { progress in
  388. guard !cancelled else { return }
  389. if progress.fractionCompleted > 0.1 {
  390. download.cancel()
  391. cancelled = true
  392. }
  393. }
  394. download.response { resp in
  395. response = resp
  396. expectation.fulfill()
  397. }
  398. waitForExpectations(timeout: timeout, handler: nil)
  399. // Then
  400. XCTAssertNotNil(response?.request)
  401. XCTAssertNotNil(response?.response)
  402. XCTAssertNil(response?.fileURL)
  403. XCTAssertNotNil(response?.error)
  404. XCTAssertNotNil(response?.resumeData)
  405. XCTAssertNotNil(download.resumeData)
  406. XCTAssertEqual(response?.resumeData, download.resumeData)
  407. }
  408. func testThatCancelledDownloadResumeDataIsAvailableWithJSONResponseSerializer() {
  409. // Given
  410. let expectation = self.expectation(description: "Download should be cancelled")
  411. var cancelled = false
  412. var response: DownloadResponse<Any>?
  413. // When
  414. let download = AF.download(urlString)
  415. download.downloadProgress { progress in
  416. guard !cancelled else { return }
  417. if progress.fractionCompleted > 0.1 {
  418. download.cancel()
  419. cancelled = true
  420. }
  421. }
  422. download.responseJSON { resp in
  423. response = resp
  424. expectation.fulfill()
  425. }
  426. waitForExpectations(timeout: timeout, handler: nil)
  427. // Then
  428. XCTAssertNotNil(response?.request)
  429. XCTAssertNotNil(response?.response)
  430. XCTAssertNil(response?.fileURL)
  431. XCTAssertEqual(response?.result.isFailure, true)
  432. XCTAssertNotNil(response?.result.error)
  433. XCTAssertNotNil(response?.resumeData)
  434. XCTAssertNotNil(download.resumeData)
  435. XCTAssertEqual(response?.resumeData, download.resumeData)
  436. }
  437. func testThatCancelledDownloadCanBeResumedWithResumeData() {
  438. // Given
  439. let expectation1 = self.expectation(description: "Download should be cancelled")
  440. var cancelled = false
  441. var response1: DownloadResponse<Data>?
  442. // When
  443. let download = AF.download(urlString)
  444. download.downloadProgress { progress in
  445. guard !cancelled else { return }
  446. if progress.fractionCompleted > 0.4 {
  447. download.cancel()
  448. cancelled = true
  449. }
  450. }
  451. download.responseData { resp in
  452. response1 = resp
  453. expectation1.fulfill()
  454. }
  455. waitForExpectations(timeout: timeout, handler: nil)
  456. guard let resumeData = download.resumeData else {
  457. XCTFail("resumeData should not be nil")
  458. return
  459. }
  460. let expectation2 = self.expectation(description: "Download should complete")
  461. var progressValues: [Double] = []
  462. var response2: DownloadResponse<Data>?
  463. let destination = DownloadRequest.suggestedDownloadDestination(options: [.removePreviousFile, .createIntermediateDirectories])
  464. // TODO: Added destination because temp file was being deleted very quickly.
  465. AF.download(resumingWith: resumeData,
  466. to: destination)
  467. .downloadProgress { progress in
  468. progressValues.append(progress.fractionCompleted)
  469. }
  470. .responseData { resp in
  471. response2 = resp
  472. expectation2.fulfill()
  473. }
  474. waitForExpectations(timeout: timeout, handler: nil)
  475. // Then
  476. XCTAssertNotNil(response1?.request)
  477. XCTAssertNotNil(response1?.response)
  478. XCTAssertNil(response1?.fileURL)
  479. XCTAssertEqual(response1?.result.isFailure, true)
  480. XCTAssertNotNil(response1?.result.error)
  481. XCTAssertNotNil(response2?.response)
  482. XCTAssertNotNil(response2?.fileURL)
  483. XCTAssertEqual(response2?.result.isSuccess, true)
  484. XCTAssertNil(response2?.result.error)
  485. progressValues.forEach { XCTAssertGreaterThanOrEqual($0, 0.4) }
  486. }
  487. }
  488. // MARK: -
  489. class DownloadResponseMapTestCase: BaseTestCase {
  490. func testThatMapTransformsSuccessValue() {
  491. // Given
  492. let urlString = "https://httpbin.org/get"
  493. let expectation = self.expectation(description: "request should succeed")
  494. var response: DownloadResponse<String>?
  495. // When
  496. AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  497. response = resp.map { json in
  498. // json["args"]["foo"] is "bar": use this invariant to test the map function
  499. return ((json as? [String: Any])?["args"] as? [String: Any])?["foo"] as? String ?? "invalid"
  500. }
  501. expectation.fulfill()
  502. }
  503. waitForExpectations(timeout: timeout, handler: nil)
  504. // Then
  505. XCTAssertNotNil(response?.request)
  506. XCTAssertNotNil(response?.response)
  507. XCTAssertNotNil(response?.fileURL)
  508. XCTAssertNil(response?.resumeData)
  509. XCTAssertNil(response?.error)
  510. XCTAssertEqual(response?.result.value, "bar")
  511. XCTAssertNotNil(response?.metrics)
  512. }
  513. func testThatMapPreservesFailureError() {
  514. // Given
  515. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  516. let expectation = self.expectation(description: "request should fail with 404")
  517. var response: DownloadResponse<String>?
  518. // When
  519. AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  520. response = resp.map { _ in "ignored" }
  521. expectation.fulfill()
  522. }
  523. waitForExpectations(timeout: timeout, handler: nil)
  524. // Then
  525. XCTAssertNotNil(response?.request)
  526. XCTAssertNil(response?.response)
  527. XCTAssertNil(response?.fileURL)
  528. XCTAssertNil(response?.resumeData)
  529. XCTAssertNotNil(response?.error)
  530. XCTAssertEqual(response?.result.isFailure, true)
  531. XCTAssertNotNil(response?.metrics)
  532. }
  533. }
  534. // MARK: -
  535. class DownloadResponseFlatMapTestCase: BaseTestCase {
  536. func testThatFlatMapTransformsSuccessValue() {
  537. // Given
  538. let urlString = "https://httpbin.org/get"
  539. let expectation = self.expectation(description: "request should succeed")
  540. var response: DownloadResponse<String>?
  541. // When
  542. AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  543. response = resp.flatMap { json in
  544. // json["args"]["foo"] is "bar": use this invariant to test the map function
  545. return ((json as? [String: Any])?["args"] as? [String: Any])?["foo"] as? String ?? "invalid"
  546. }
  547. expectation.fulfill()
  548. }
  549. waitForExpectations(timeout: timeout, handler: nil)
  550. // Then
  551. XCTAssertNotNil(response?.request)
  552. XCTAssertNotNil(response?.response)
  553. XCTAssertNotNil(response?.fileURL)
  554. XCTAssertNil(response?.resumeData)
  555. XCTAssertNil(response?.error)
  556. XCTAssertEqual(response?.result.value, "bar")
  557. XCTAssertNotNil(response?.metrics)
  558. }
  559. func testThatFlatMapCatchesTransformationError() {
  560. // Given
  561. struct TransformError: Error {}
  562. let urlString = "https://httpbin.org/get"
  563. let expectation = self.expectation(description: "request should succeed")
  564. var response: DownloadResponse<String>?
  565. // When
  566. AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  567. response = resp.flatMap { json in
  568. throw TransformError()
  569. }
  570. expectation.fulfill()
  571. }
  572. waitForExpectations(timeout: timeout, handler: nil)
  573. // Then
  574. XCTAssertNotNil(response?.request)
  575. XCTAssertNotNil(response?.response)
  576. XCTAssertNotNil(response?.fileURL)
  577. XCTAssertNil(response?.resumeData)
  578. if let error = response?.result.error {
  579. XCTAssertTrue(error is TransformError)
  580. } else {
  581. XCTFail("flatMap should catch the transformation error")
  582. }
  583. XCTAssertNotNil(response?.metrics)
  584. }
  585. func testThatFlatMapPreservesFailureError() {
  586. // Given
  587. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  588. let expectation = self.expectation(description: "request should fail with 404")
  589. var response: DownloadResponse<String>?
  590. // When
  591. AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  592. response = resp.flatMap { _ in "ignored" }
  593. expectation.fulfill()
  594. }
  595. waitForExpectations(timeout: timeout, handler: nil)
  596. // Then
  597. XCTAssertNotNil(response?.request)
  598. XCTAssertNil(response?.response)
  599. XCTAssertNil(response?.fileURL)
  600. XCTAssertNil(response?.resumeData)
  601. XCTAssertNotNil(response?.error)
  602. XCTAssertEqual(response?.result.isFailure, true)
  603. XCTAssertNotNil(response?.metrics)
  604. }
  605. }
  606. class DownloadResponseMapErrorTestCase: BaseTestCase {
  607. func testThatMapErrorTransformsFailureValue() {
  608. // Given
  609. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  610. let expectation = self.expectation(description: "request should not succeed")
  611. var response: DownloadResponse<Any>?
  612. // When
  613. AF.download(urlString).responseJSON { resp in
  614. response = resp.mapError { error in
  615. return TestError.error(error: error)
  616. }
  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. guard let error = response?.error as? TestError, case .error = error else { XCTFail(); return }
  628. XCTAssertNotNil(response?.metrics)
  629. }
  630. func testThatMapErrorPreservesSuccessValue() {
  631. // Given
  632. let urlString = "https://httpbin.org/get"
  633. let expectation = self.expectation(description: "request should succeed")
  634. var response: DownloadResponse<Data>?
  635. // When
  636. AF.download(urlString).responseData { resp in
  637. response = resp.mapError { TestError.error(error: $0) }
  638. expectation.fulfill()
  639. }
  640. waitForExpectations(timeout: timeout, handler: nil)
  641. // Then
  642. XCTAssertNotNil(response?.request)
  643. XCTAssertNotNil(response?.response)
  644. XCTAssertNotNil(response?.fileURL)
  645. XCTAssertNil(response?.resumeData)
  646. XCTAssertEqual(response?.result.isSuccess, true)
  647. XCTAssertNotNil(response?.metrics)
  648. }
  649. }
  650. // MARK: -
  651. class DownloadResponseFlatMapErrorTestCase: BaseTestCase {
  652. func testThatFlatMapErrorPreservesSuccessValue() {
  653. // Given
  654. let urlString = "https://httpbin.org/get"
  655. let expectation = self.expectation(description: "request should succeed")
  656. var response: DownloadResponse<Data>?
  657. // When
  658. AF.download(urlString).responseData { resp in
  659. response = resp.flatMapError { TestError.error(error: $0) }
  660. expectation.fulfill()
  661. }
  662. waitForExpectations(timeout: timeout, handler: nil)
  663. // Then
  664. XCTAssertNotNil(response?.request)
  665. XCTAssertNotNil(response?.response)
  666. XCTAssertNotNil(response?.fileURL)
  667. XCTAssertNil(response?.resumeData)
  668. XCTAssertNil(response?.error)
  669. XCTAssertEqual(response?.result.isSuccess, true)
  670. XCTAssertNotNil(response?.metrics)
  671. }
  672. func testThatFlatMapErrorCatchesTransformationError() {
  673. // Given
  674. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  675. let expectation = self.expectation(description: "request should fail")
  676. var response: DownloadResponse<Data>?
  677. // When
  678. AF.download(urlString).responseData { resp in
  679. response = resp.flatMapError { _ in try TransformationError.error.alwaysFails() }
  680. expectation.fulfill()
  681. }
  682. waitForExpectations(timeout: timeout, handler: nil)
  683. // Then
  684. XCTAssertNotNil(response?.request)
  685. XCTAssertNil(response?.response)
  686. XCTAssertNil(response?.fileURL)
  687. XCTAssertNil(response?.resumeData)
  688. XCTAssertNotNil(response?.error)
  689. XCTAssertEqual(response?.result.isFailure, true)
  690. if let error = response?.result.error {
  691. XCTAssertTrue(error is TransformationError)
  692. } else {
  693. XCTFail("flatMapError should catch the transformation error")
  694. }
  695. XCTAssertNotNil(response?.metrics)
  696. }
  697. func testThatFlatMapErrorTransformsError() {
  698. // Given
  699. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  700. let expectation = self.expectation(description: "request should fail")
  701. var response: DownloadResponse<Data>?
  702. // When
  703. AF.download(urlString).responseData { resp in
  704. response = resp.flatMapError { TestError.error(error: $0) }
  705. expectation.fulfill()
  706. }
  707. waitForExpectations(timeout: timeout, handler: nil)
  708. // Then
  709. XCTAssertNotNil(response?.request)
  710. XCTAssertNil(response?.response)
  711. XCTAssertNil(response?.fileURL)
  712. XCTAssertNil(response?.resumeData)
  713. XCTAssertNotNil(response?.error)
  714. XCTAssertEqual(response?.result.isFailure, true)
  715. guard let error = response?.error as? TestError, case .error = error else { XCTFail(); return }
  716. XCTAssertNotNil(response?.metrics)
  717. }
  718. }