DownloadTests.swift 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. //
  2. // DownloadTests.swift
  3. //
  4. // Copyright (c) 2014-2016 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/"
  31. // When
  32. let request = Alamofire.download(urlString)
  33. // Then
  34. XCTAssertNotNil(request.request)
  35. XCTAssertEqual(request.request?.httpMethod, "GET")
  36. XCTAssertEqual(request.request?.url?.absoluteString, urlString)
  37. XCTAssertNil(request.response)
  38. }
  39. func testDownloadClassMethodWithMethodURLHeadersAndDestination() {
  40. // Given
  41. let urlString = "https://httpbin.org/"
  42. let headers = ["Authorization": "123456"]
  43. // When
  44. let request = Alamofire.download(urlString, headers: headers)
  45. // Then
  46. XCTAssertNotNil(request.request)
  47. XCTAssertEqual(request.request?.httpMethod, "GET")
  48. XCTAssertEqual(request.request?.url?.absoluteString, urlString)
  49. XCTAssertEqual(request.request?.value(forHTTPHeaderField: "Authorization"), "123456")
  50. XCTAssertNil(request.response)
  51. }
  52. }
  53. // MARK: -
  54. class DownloadResponseTestCase: BaseTestCase {
  55. private var randomCachesFileURL: URL {
  56. return testDirectoryURL.appendingPathComponent("\(UUID().uuidString).json")
  57. }
  58. func testDownloadRequest() {
  59. // Given
  60. let fileURL = randomCachesFileURL
  61. let numberOfLines = 100
  62. let urlString = "https://httpbin.org/stream/\(numberOfLines)"
  63. let destination: DownloadRequest.DownloadFileDestination = { _, _ in (fileURL, []) }
  64. let expectation = self.expectation(description: "Download request should download data to file: \(urlString)")
  65. var response: DefaultDownloadResponse?
  66. // When
  67. Alamofire.download(urlString, to: destination)
  68. .response { resp in
  69. response = resp
  70. expectation.fulfill()
  71. }
  72. waitForExpectations(timeout: timeout, handler: nil)
  73. // Then
  74. XCTAssertNotNil(response?.request)
  75. XCTAssertNotNil(response?.response)
  76. XCTAssertNotNil(response?.destinationURL)
  77. XCTAssertNil(response?.resumeData)
  78. XCTAssertNil(response?.error)
  79. if let destinationURL = response?.destinationURL {
  80. XCTAssertTrue(FileManager.default.fileExists(atPath: destinationURL.path))
  81. if let data = try? Data(contentsOf: destinationURL) {
  82. XCTAssertGreaterThan(data.count, 0)
  83. } else {
  84. XCTFail("data should exist for contents of destinationURL")
  85. }
  86. }
  87. }
  88. func testDownloadRequestWithProgress() {
  89. // Given
  90. let randomBytes = 4 * 1024 * 1024
  91. let urlString = "https://httpbin.org/bytes/\(randomBytes)"
  92. let expectation = self.expectation(description: "Bytes download progress should be reported: \(urlString)")
  93. var progressValues: [Double] = []
  94. var response: DefaultDownloadResponse?
  95. // When
  96. Alamofire.download(urlString)
  97. .downloadProgress { progress in
  98. progressValues.append(progress.fractionCompleted)
  99. }
  100. .response { resp in
  101. response = resp
  102. expectation.fulfill()
  103. }
  104. waitForExpectations(timeout: timeout, handler: nil)
  105. // Then
  106. XCTAssertNotNil(response?.request)
  107. XCTAssertNotNil(response?.response)
  108. XCTAssertNotNil(response?.temporaryURL)
  109. XCTAssertNil(response?.destinationURL)
  110. XCTAssertNil(response?.resumeData)
  111. XCTAssertNil(response?.error)
  112. var previousProgress: Double = progressValues.first ?? 0.0
  113. for progress in progressValues {
  114. XCTAssertGreaterThanOrEqual(progress, previousProgress)
  115. previousProgress = progress
  116. }
  117. if let lastProgressValue = progressValues.last {
  118. XCTAssertEqual(lastProgressValue, 1.0)
  119. } else {
  120. XCTFail("last item in progressValues should not be nil")
  121. }
  122. }
  123. func testDownloadRequestWithParameters() {
  124. // Given
  125. let urlString = "https://httpbin.org/get"
  126. let parameters = ["foo": "bar"]
  127. let expectation = self.expectation(description: "Download request should download data to file")
  128. var response: DefaultDownloadResponse?
  129. // When
  130. Alamofire.download(urlString, parameters: parameters)
  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?.temporaryURL)
  140. XCTAssertNil(response?.destinationURL)
  141. XCTAssertNil(response?.resumeData)
  142. XCTAssertNil(response?.error)
  143. if
  144. let temporaryURL = response?.temporaryURL,
  145. let data = try? Data(contentsOf: temporaryURL),
  146. let jsonObject = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions(rawValue: 0)),
  147. let json = jsonObject as? [String: Any],
  148. let args = json["args"] as? [String: String]
  149. {
  150. XCTAssertEqual(args["foo"], "bar")
  151. } else {
  152. XCTFail("args parameter in JSON should not be nil")
  153. }
  154. }
  155. func testDownloadRequestWithHeaders() {
  156. // Given
  157. let fileURL = randomCachesFileURL
  158. let urlString = "https://httpbin.org/get"
  159. let headers = ["Authorization": "123456"]
  160. let destination: DownloadRequest.DownloadFileDestination = { _, _ in (fileURL, []) }
  161. let expectation = self.expectation(description: "Download request should download data to file: \(fileURL)")
  162. var response: DefaultDownloadResponse?
  163. // When
  164. Alamofire.download(urlString, headers: headers, to: destination)
  165. .response { resp in
  166. response = resp
  167. expectation.fulfill()
  168. }
  169. waitForExpectations(timeout: timeout, handler: nil)
  170. // Then
  171. XCTAssertNotNil(response?.request)
  172. XCTAssertNotNil(response?.response)
  173. XCTAssertNotNil(response?.destinationURL)
  174. XCTAssertNil(response?.resumeData)
  175. XCTAssertNil(response?.error)
  176. if
  177. let data = try? Data(contentsOf: fileURL),
  178. let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []),
  179. let json = jsonObject as? [String: Any],
  180. let headers = json["headers"] as? [String: String]
  181. {
  182. XCTAssertEqual(headers["Authorization"], "123456")
  183. } else {
  184. XCTFail("headers parameter in JSON should not be nil")
  185. }
  186. }
  187. func testThatDownloadingFileAndMovingToDirectoryThatDoesNotExistThrowsError() {
  188. // Given
  189. let fileURL = testDirectoryURL.appendingPathComponent("some/random/folder/test_output.json")
  190. let expectation = self.expectation(description: "Download request should download data but fail to move file")
  191. var response: DefaultDownloadResponse?
  192. // When
  193. Alamofire.download("https://httpbin.org/get", to: { _, _ in (fileURL, [])})
  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?.temporaryURL)
  203. XCTAssertNotNil(response?.destinationURL)
  204. XCTAssertNil(response?.resumeData)
  205. XCTAssertNotNil(response?.error)
  206. if let error = response?.error as? CocoaError {
  207. XCTAssertEqual(error.code, .fileNoSuchFile)
  208. } else {
  209. XCTFail("error should not be nil")
  210. }
  211. }
  212. func testThatDownloadOptionsCanCreateIntermediateDirectoriesPriorToMovingFile() {
  213. // Given
  214. let fileURL = testDirectoryURL.appendingPathComponent("some/random/folder/test_output.json")
  215. let expectation = self.expectation(description: "Download request should download data to file: \(fileURL)")
  216. var response: DefaultDownloadResponse?
  217. // When
  218. Alamofire.download("https://httpbin.org/get", to: { _, _ in (fileURL, [.createIntermediateDirectories])})
  219. .response { resp in
  220. response = resp
  221. expectation.fulfill()
  222. }
  223. waitForExpectations(timeout: timeout, handler: nil)
  224. // Then
  225. XCTAssertNotNil(response?.request)
  226. XCTAssertNotNil(response?.response)
  227. XCTAssertNotNil(response?.temporaryURL)
  228. XCTAssertNotNil(response?.destinationURL)
  229. XCTAssertNil(response?.resumeData)
  230. XCTAssertNil(response?.error)
  231. }
  232. func testThatDownloadingFileAndMovingToDestinationThatIsOccupiedThrowsError() {
  233. do {
  234. // Given
  235. let directoryURL = testDirectoryURL.appendingPathComponent("some/random/folder")
  236. let directoryCreated = FileManager.createDirectory(at: directoryURL)
  237. let fileURL = directoryURL.appendingPathComponent("test_output.json")
  238. try "random_data".write(to: fileURL, atomically: true, encoding: .utf8)
  239. let expectation = self.expectation(description: "Download should complete but fail to move file")
  240. var response: DefaultDownloadResponse?
  241. // When
  242. Alamofire.download("https://httpbin.org/get", to: { _, _ in (fileURL, [])})
  243. .response { resp in
  244. response = resp
  245. expectation.fulfill()
  246. }
  247. waitForExpectations(timeout: timeout, handler: nil)
  248. // Then
  249. XCTAssertTrue(directoryCreated)
  250. XCTAssertNotNil(response?.request)
  251. XCTAssertNotNil(response?.response)
  252. XCTAssertNotNil(response?.temporaryURL)
  253. XCTAssertNotNil(response?.destinationURL)
  254. XCTAssertNil(response?.resumeData)
  255. XCTAssertNotNil(response?.error)
  256. if let error = response?.error as? CocoaError {
  257. XCTAssertEqual(error.code, .fileWriteFileExists)
  258. } else {
  259. XCTFail("error should not be nil")
  260. }
  261. } catch {
  262. XCTFail("Test encountered unexpected error: \(error)")
  263. }
  264. }
  265. func testThatDownloadOptionsCanRemovePreviousFilePriorToMovingFile() {
  266. // Given
  267. let directoryURL = testDirectoryURL.appendingPathComponent("some/random/folder")
  268. let directoryCreated = FileManager.createDirectory(at: directoryURL)
  269. let fileURL = directoryURL.appendingPathComponent("test_output.json")
  270. let expectation = self.expectation(description: "Download should complete and move file to URL: \(fileURL)")
  271. var response: DefaultDownloadResponse?
  272. // When
  273. Alamofire.download("https://httpbin.org/get", to: { _, _ in (fileURL, [.removePreviousFile])})
  274. .response { resp in
  275. response = resp
  276. expectation.fulfill()
  277. }
  278. waitForExpectations(timeout: timeout, handler: nil)
  279. // Then
  280. XCTAssertTrue(directoryCreated)
  281. XCTAssertNotNil(response?.request)
  282. XCTAssertNotNil(response?.response)
  283. XCTAssertNotNil(response?.temporaryURL)
  284. XCTAssertNotNil(response?.destinationURL)
  285. XCTAssertNil(response?.resumeData)
  286. XCTAssertNil(response?.error)
  287. }
  288. }
  289. // MARK: -
  290. class DownloadResumeDataTestCase: BaseTestCase {
  291. let urlString = "https://upload.wikimedia.org/wikipedia/commons/6/69/NASA-HS201427a-HubbleUltraDeepField2014-20140603.jpg"
  292. func testThatImmediatelyCancelledDownloadDoesNotHaveResumeDataAvailable() {
  293. // Given
  294. let expectation = self.expectation(description: "Download should be cancelled")
  295. var response: DefaultDownloadResponse?
  296. // When
  297. let download = Alamofire.download(urlString)
  298. .response { resp in
  299. response = resp
  300. expectation.fulfill()
  301. }
  302. download.cancel()
  303. waitForExpectations(timeout: timeout, handler: nil)
  304. // Then
  305. XCTAssertNotNil(response?.request)
  306. XCTAssertNil(response?.response)
  307. XCTAssertNil(response?.destinationURL)
  308. XCTAssertNil(response?.resumeData)
  309. XCTAssertNotNil(response?.error)
  310. XCTAssertNil(download.resumeData)
  311. }
  312. func testThatCancelledDownloadResponseDataMatchesResumeData() {
  313. // Given
  314. let expectation = self.expectation(description: "Download should be cancelled")
  315. var cancelled = false
  316. var response: DefaultDownloadResponse?
  317. // When
  318. let download = Alamofire.download(urlString)
  319. download.downloadProgress { progress in
  320. guard !cancelled else { return }
  321. if progress.fractionCompleted > 0.1 {
  322. download.cancel()
  323. cancelled = true
  324. }
  325. }
  326. download.response { resp in
  327. response = resp
  328. expectation.fulfill()
  329. }
  330. waitForExpectations(timeout: timeout, handler: nil)
  331. // Then
  332. XCTAssertNotNil(response?.request)
  333. XCTAssertNotNil(response?.response)
  334. XCTAssertNil(response?.destinationURL)
  335. XCTAssertNotNil(response?.error)
  336. XCTAssertNotNil(response?.resumeData)
  337. XCTAssertNotNil(download.resumeData)
  338. XCTAssertEqual(response?.resumeData, download.resumeData)
  339. }
  340. func testThatCancelledDownloadResumeDataIsAvailableWithJSONResponseSerializer() {
  341. // Given
  342. let expectation = self.expectation(description: "Download should be cancelled")
  343. var cancelled = false
  344. var response: DownloadResponse<Any>?
  345. // When
  346. let download = Alamofire.download(urlString)
  347. download.downloadProgress { progress in
  348. guard !cancelled else { return }
  349. if progress.fractionCompleted > 0.1 {
  350. download.cancel()
  351. cancelled = true
  352. }
  353. }
  354. download.responseJSON { resp in
  355. response = resp
  356. expectation.fulfill()
  357. }
  358. waitForExpectations(timeout: timeout, handler: nil)
  359. // Then
  360. XCTAssertNotNil(response?.request)
  361. XCTAssertNotNil(response?.response)
  362. XCTAssertNil(response?.destinationURL)
  363. XCTAssertEqual(response?.result.isFailure, true)
  364. XCTAssertNotNil(response?.result.error)
  365. XCTAssertNotNil(response?.resumeData)
  366. XCTAssertNotNil(download.resumeData)
  367. XCTAssertEqual(response?.resumeData, download.resumeData)
  368. }
  369. }