DownloadTests.swift 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  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. let searchPathDirectory: FileManager.SearchPathDirectory = .cachesDirectory
  29. let searchPathDomain: FileManager.SearchPathDomainMask = .userDomainMask
  30. func testDownloadClassMethodWithMethodURLAndDestination() {
  31. // Given
  32. let urlString = "https://httpbin.org/"
  33. let destination = DownloadRequest.suggestedDownloadDestination(for: searchPathDirectory, in: searchPathDomain)
  34. // When
  35. let request = Alamofire.download(urlString, to: destination, withMethod: .get)
  36. // Then
  37. XCTAssertNotNil(request.request)
  38. XCTAssertEqual(request.request?.httpMethod, "GET")
  39. XCTAssertEqual(request.request?.urlString, urlString)
  40. XCTAssertNil(request.response)
  41. }
  42. func testDownloadClassMethodWithMethodURLHeadersAndDestination() {
  43. // Given
  44. let urlString = "https://httpbin.org/"
  45. let headers = ["Authorization": "123456"]
  46. let destination = DownloadRequest.suggestedDownloadDestination(for: searchPathDirectory, in: searchPathDomain)
  47. // When
  48. let request = Alamofire.download(urlString, to: destination, withMethod: .get, headers: headers)
  49. // Then
  50. XCTAssertNotNil(request.request)
  51. XCTAssertEqual(request.request?.httpMethod, "GET")
  52. XCTAssertEqual(request.request?.urlString, urlString)
  53. XCTAssertEqual(request.request?.value(forHTTPHeaderField: "Authorization"), "123456")
  54. XCTAssertNil(request.response)
  55. }
  56. }
  57. // MARK: -
  58. class DownloadResponseTestCase: BaseTestCase {
  59. let searchPathDirectory: FileManager.SearchPathDirectory = .cachesDirectory
  60. let searchPathDomain: FileManager.SearchPathDomainMask = .userDomainMask
  61. let cachesURL: URL = {
  62. let cachesDirectory = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first!
  63. let cachesURL = URL(fileURLWithPath: cachesDirectory, isDirectory: true)
  64. return cachesURL
  65. }()
  66. var randomCachesFileURL: URL {
  67. return cachesURL.appendingPathComponent("\(UUID().uuidString).json")
  68. }
  69. func testDownloadRequest() {
  70. // Given
  71. let numberOfLines = 100
  72. let urlString = "https://httpbin.org/stream/\(numberOfLines)"
  73. let destination = DownloadRequest.suggestedDownloadDestination(for: searchPathDirectory, in: searchPathDomain)
  74. let expectation = self.expectation(description: "Download request should download data to file: \(urlString)")
  75. var response: DefaultDownloadResponse?
  76. // When
  77. Alamofire.download(urlString, to: destination, withMethod: .get)
  78. .response { resp in
  79. response = resp
  80. expectation.fulfill()
  81. }
  82. waitForExpectations(timeout: timeout, handler: nil)
  83. // Then
  84. XCTAssertNotNil(response?.request)
  85. XCTAssertNotNil(response?.response)
  86. XCTAssertNotNil(response?.destinationURL)
  87. XCTAssertNil(response?.resumeData)
  88. XCTAssertNil(response?.error)
  89. if let destinationURL = response?.destinationURL {
  90. XCTAssertTrue(FileManager.default.fileExists(atPath: destinationURL.path))
  91. if let data = try? Data(contentsOf: destinationURL) {
  92. XCTAssertGreaterThan(data.count, 0)
  93. } else {
  94. XCTFail("data should exist for contents of destinationURL")
  95. }
  96. }
  97. }
  98. func testDownloadRequestWithProgress() {
  99. // Given
  100. let randomBytes = 4 * 1024 * 1024
  101. let urlString = "https://httpbin.org/bytes/\(randomBytes)"
  102. let fileManager = FileManager.default
  103. let directory = fileManager.urls(for: searchPathDirectory, in: self.searchPathDomain)[0]
  104. let filename = "test_download_data"
  105. let fileURL = directory.appendingPathComponent(filename)
  106. let expectation = self.expectation(description: "Bytes download progress should be reported: \(urlString)")
  107. var byteValues: [(bytes: Int64, totalBytes: Int64, totalBytesExpected: Int64)] = []
  108. var progressValues: [(completedUnitCount: Int64, totalUnitCount: Int64)] = []
  109. var response: DefaultDownloadResponse?
  110. // When
  111. Alamofire.download(urlString, to: { _, _ in fileURL }, withMethod: .get)
  112. .downloadProgress { progress in
  113. progressValues.append((progress.completedUnitCount, progress.totalUnitCount))
  114. }
  115. .downloadProgress { bytesRead, totalBytesRead, totalBytesExpectedToRead in
  116. let bytes = (bytes: bytesRead, totalBytes: totalBytesRead, totalBytesExpected: totalBytesExpectedToRead)
  117. byteValues.append(bytes)
  118. }
  119. .response { resp in
  120. response = resp
  121. expectation.fulfill()
  122. }
  123. waitForExpectations(timeout: timeout, handler: nil)
  124. // Then
  125. XCTAssertNotNil(response?.request)
  126. XCTAssertNotNil(response?.response)
  127. XCTAssertNotNil(response?.destinationURL)
  128. XCTAssertNil(response?.resumeData)
  129. XCTAssertNil(response?.error)
  130. XCTAssertEqual(byteValues.count, progressValues.count)
  131. if byteValues.count == progressValues.count {
  132. for (byteValue, progressValue) in zip(byteValues, progressValues) {
  133. XCTAssertGreaterThan(byteValue.bytes, 0)
  134. print("\(byteValue.totalBytes) - \(progressValue.completedUnitCount)")
  135. XCTAssertEqual(byteValue.totalBytes, progressValue.completedUnitCount)
  136. XCTAssertEqual(byteValue.totalBytesExpected, progressValue.totalUnitCount)
  137. }
  138. }
  139. if let lastByteValue = byteValues.last, let lastProgressValue = progressValues.last {
  140. let byteValueFractionalCompletion = Double(lastByteValue.totalBytes) / Double(lastByteValue.totalBytesExpected)
  141. let progressValueFractionalCompletion = Double(lastProgressValue.0) / Double(lastProgressValue.1)
  142. XCTAssertEqual(byteValueFractionalCompletion, 1.0)
  143. XCTAssertEqual(progressValueFractionalCompletion, 1.0)
  144. } else {
  145. XCTFail("last item in bytesValues and progressValues should not be nil")
  146. }
  147. do {
  148. try fileManager.removeItem(at: fileURL)
  149. } catch {
  150. XCTFail("file manager should remove item at URL: \(fileURL)")
  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.DownloadFileDestination = { _, _ in fileURL }
  159. let expectation = self.expectation(description: "Download request should download data to file: \(fileURL)")
  160. var response: DefaultDownloadResponse?
  161. // When
  162. Alamofire.download(urlString, to: destination, withMethod: .get, parameters: parameters)
  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?.destinationURL)
  172. XCTAssertNil(response?.resumeData)
  173. XCTAssertNil(response?.error)
  174. if
  175. let data = try? Data(contentsOf: fileURL),
  176. let jsonObject = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions(rawValue: 0)),
  177. let json = jsonObject as? [String: Any],
  178. let args = json["args"] as? [String: String]
  179. {
  180. XCTAssertEqual(args["foo"], "bar")
  181. } else {
  182. XCTFail("args parameter in JSON should not be nil")
  183. }
  184. }
  185. func testDownloadRequestWithHeaders() {
  186. // Given
  187. let fileURL = randomCachesFileURL
  188. let urlString = "https://httpbin.org/get"
  189. let headers = ["Authorization": "123456"]
  190. let destination: DownloadRequest.DownloadFileDestination = { _, _ in fileURL }
  191. let expectation = self.expectation(description: "Download request should download data to file: \(fileURL)")
  192. var response: DefaultDownloadResponse?
  193. // When
  194. Alamofire.download(urlString, to: destination, withMethod: .get, headers: headers)
  195. .response { resp in
  196. response = resp
  197. expectation.fulfill()
  198. }
  199. waitForExpectations(timeout: timeout, handler: nil)
  200. // Then
  201. XCTAssertNotNil(response?.request)
  202. XCTAssertNotNil(response?.response)
  203. XCTAssertNotNil(response?.destinationURL)
  204. XCTAssertNil(response?.resumeData)
  205. XCTAssertNil(response?.error)
  206. if
  207. let data = try? Data(contentsOf: fileURL),
  208. let jsonObject = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions(rawValue: 0)),
  209. let json = jsonObject as? [String: Any],
  210. let headers = json["headers"] as? [String: String]
  211. {
  212. XCTAssertEqual(headers["Authorization"], "123456")
  213. } else {
  214. XCTFail("headers parameter in JSON should not be nil")
  215. }
  216. }
  217. }
  218. // MARK: -
  219. class DownloadResumeDataTestCase: BaseTestCase {
  220. let urlString = "https://upload.wikimedia.org/wikipedia/commons/6/69/NASA-HS201427a-HubbleUltraDeepField2014-20140603.jpg"
  221. let destination: DownloadRequest.DownloadFileDestination = {
  222. let searchPathDirectory: FileManager.SearchPathDirectory = .cachesDirectory
  223. let searchPathDomain: FileManager.SearchPathDomainMask = .userDomainMask
  224. return DownloadRequest.suggestedDownloadDestination(for: searchPathDirectory, in: searchPathDomain)
  225. }()
  226. func testThatImmediatelyCancelledDownloadDoesNotHaveResumeDataAvailable() {
  227. // Given
  228. let expectation = self.expectation(description: "Download should be cancelled")
  229. var response: DefaultDownloadResponse?
  230. // When
  231. let download = Alamofire.download(urlString, to: destination, withMethod: .get)
  232. .response { resp in
  233. response = resp
  234. expectation.fulfill()
  235. }
  236. download.cancel()
  237. waitForExpectations(timeout: timeout, handler: nil)
  238. // Then
  239. XCTAssertNotNil(response?.request)
  240. XCTAssertNil(response?.response)
  241. XCTAssertNil(response?.destinationURL)
  242. XCTAssertNil(response?.resumeData)
  243. XCTAssertNotNil(response?.error)
  244. XCTAssertNil(download.resumeData)
  245. }
  246. func testThatCancelledDownloadResponseDataMatchesResumeData() {
  247. // Given
  248. let expectation = self.expectation(description: "Download should be cancelled")
  249. var response: DefaultDownloadResponse?
  250. // When
  251. let download = Alamofire.download(urlString, to: destination, withMethod: .get)
  252. download.downloadProgress { _, _, _ in
  253. download.cancel()
  254. }
  255. download.response { resp in
  256. response = resp
  257. expectation.fulfill()
  258. }
  259. waitForExpectations(timeout: timeout, handler: nil)
  260. // Then
  261. XCTAssertNotNil(response?.request)
  262. XCTAssertNotNil(response?.response)
  263. XCTAssertNil(response?.destinationURL)
  264. XCTAssertNotNil(response?.resumeData)
  265. XCTAssertNotNil(response?.error)
  266. XCTAssertNotNil(download.resumeData, "resume data should not be nil")
  267. if let responseResumeData = response?.resumeData, let resumeData = download.resumeData {
  268. XCTAssertEqual(responseResumeData, resumeData)
  269. } else {
  270. XCTFail("response resume data or resume data was unexpectedly nil")
  271. }
  272. }
  273. func testThatCancelledDownloadResumeDataIsAvailableWithJSONResponseSerializer() {
  274. // Given
  275. let expectation = self.expectation(description: "Download should be cancelled")
  276. var response: DownloadResponse<Any>?
  277. // When
  278. let download = Alamofire.download(urlString, to: destination, withMethod: .get)
  279. download.downloadProgress { _, _, _ in
  280. download.cancel()
  281. }
  282. download.responseJSON { resp in
  283. response = resp
  284. expectation.fulfill()
  285. }
  286. waitForExpectations(timeout: timeout, handler: nil)
  287. // Then
  288. XCTAssertNotNil(response?.request)
  289. XCTAssertNotNil(response?.response)
  290. XCTAssertNil(response?.destinationURL)
  291. XCTAssertNotNil(response?.resumeData)
  292. XCTAssertEqual(response?.result.isFailure, true)
  293. XCTAssertNotNil(response?.result.error)
  294. XCTAssertNotNil(download.resumeData)
  295. }
  296. }