UploadTests.swift 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  1. //
  2. // UploadTests.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 UploadFileInitializationTestCase: BaseTestCase {
  28. func testUploadClassMethodWithMethodURLAndFile() {
  29. // Given
  30. let urlString = "https://httpbin.org/"
  31. let imageURL = url(forResource: "rainbow", withExtension: "jpg")
  32. // When
  33. let request = Alamofire.upload(imageURL, to: urlString)
  34. // Then
  35. XCTAssertNotNil(request.request, "request should not be nil")
  36. XCTAssertEqual(request.request?.httpMethod ?? "", "POST", "request HTTP method should be POST")
  37. XCTAssertEqual(request.request?.url?.absoluteString, urlString, "request URL string should be equal")
  38. XCTAssertNil(request.response, "response should be nil")
  39. }
  40. func testUploadClassMethodWithMethodURLHeadersAndFile() {
  41. // Given
  42. let urlString = "https://httpbin.org/"
  43. let headers = ["Authorization": "123456"]
  44. let imageURL = url(forResource: "rainbow", withExtension: "jpg")
  45. // When
  46. let request = Alamofire.upload(imageURL, to: urlString, method: .post, headers: headers)
  47. // Then
  48. XCTAssertNotNil(request.request, "request should not be nil")
  49. XCTAssertEqual(request.request?.httpMethod ?? "", "POST", "request HTTP method should be POST")
  50. XCTAssertEqual(request.request?.url?.absoluteString, urlString, "request URL string should be equal")
  51. let authorizationHeader = request.request?.value(forHTTPHeaderField: "Authorization") ?? ""
  52. XCTAssertEqual(authorizationHeader, "123456", "Authorization header is incorrect")
  53. XCTAssertNil(request.response, "response should be nil")
  54. }
  55. }
  56. // MARK: -
  57. class UploadDataInitializationTestCase: BaseTestCase {
  58. func testUploadClassMethodWithMethodURLAndData() {
  59. // Given
  60. let urlString = "https://httpbin.org/"
  61. // When
  62. let request = Alamofire.upload(Data(), to: urlString)
  63. // Then
  64. XCTAssertNotNil(request.request, "request should not be nil")
  65. XCTAssertEqual(request.request?.httpMethod ?? "", "POST", "request HTTP method should be POST")
  66. XCTAssertEqual(request.request?.url?.absoluteString, urlString, "request URL string should be equal")
  67. XCTAssertNil(request.response, "response should be nil")
  68. }
  69. func testUploadClassMethodWithMethodURLHeadersAndData() {
  70. // Given
  71. let urlString = "https://httpbin.org/"
  72. let headers = ["Authorization": "123456"]
  73. // When
  74. let request = Alamofire.upload(Data(), to: urlString, headers: headers)
  75. // Then
  76. XCTAssertNotNil(request.request, "request should not be nil")
  77. XCTAssertEqual(request.request?.httpMethod ?? "", "POST", "request HTTP method should be POST")
  78. XCTAssertEqual(request.request?.url?.absoluteString, urlString, "request URL string should be equal")
  79. let authorizationHeader = request.request?.value(forHTTPHeaderField: "Authorization") ?? ""
  80. XCTAssertEqual(authorizationHeader, "123456", "Authorization header is incorrect")
  81. XCTAssertNil(request.response, "response should be nil")
  82. }
  83. }
  84. // MARK: -
  85. class UploadStreamInitializationTestCase: BaseTestCase {
  86. func testUploadClassMethodWithMethodURLAndStream() {
  87. // Given
  88. let urlString = "https://httpbin.org/"
  89. let imageURL = url(forResource: "rainbow", withExtension: "jpg")
  90. let imageStream = InputStream(url: imageURL)!
  91. // When
  92. let request = Alamofire.upload(imageStream, to: urlString)
  93. // Then
  94. XCTAssertNotNil(request.request, "request should not be nil")
  95. XCTAssertEqual(request.request?.httpMethod ?? "", "POST", "request HTTP method should be POST")
  96. XCTAssertEqual(request.request?.url?.absoluteString, urlString, "request URL string should be equal")
  97. XCTAssertNil(request.response, "response should be nil")
  98. }
  99. func testUploadClassMethodWithMethodURLHeadersAndStream() {
  100. // Given
  101. let urlString = "https://httpbin.org/"
  102. let imageURL = url(forResource: "rainbow", withExtension: "jpg")
  103. let headers = ["Authorization": "123456"]
  104. let imageStream = InputStream(url: imageURL)!
  105. // When
  106. let request = Alamofire.upload(imageStream, to: urlString, headers: headers)
  107. // Then
  108. XCTAssertNotNil(request.request, "request should not be nil")
  109. XCTAssertEqual(request.request?.httpMethod ?? "", "POST", "request HTTP method should be POST")
  110. XCTAssertEqual(request.request?.url?.absoluteString, urlString, "request URL string should be equal")
  111. let authorizationHeader = request.request?.value(forHTTPHeaderField: "Authorization") ?? ""
  112. XCTAssertEqual(authorizationHeader, "123456", "Authorization header is incorrect")
  113. XCTAssertNil(request.response, "response should be nil")
  114. }
  115. }
  116. // MARK: -
  117. class UploadDataTestCase: BaseTestCase {
  118. func testUploadDataRequest() {
  119. // Given
  120. let urlString = "https://httpbin.org/post"
  121. let data = "Lorem ipsum dolor sit amet".data(using: String.Encoding.utf8, allowLossyConversion: false)!
  122. let expectation = self.expectation(description: "Upload request should succeed: \(urlString)")
  123. var response: DefaultDataResponse?
  124. // When
  125. Alamofire.upload(data, to: urlString)
  126. .response { resp in
  127. response = resp
  128. expectation.fulfill()
  129. }
  130. waitForExpectations(timeout: timeout, handler: nil)
  131. // Then
  132. XCTAssertNotNil(response?.request)
  133. XCTAssertNotNil(response?.response)
  134. XCTAssertNil(response?.error)
  135. }
  136. func testUploadDataRequestWithProgress() {
  137. // Given
  138. let urlString = "https://httpbin.org/post"
  139. let data: Data = {
  140. var text = ""
  141. for _ in 1...3_000 {
  142. text += "Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
  143. }
  144. return text.data(using: String.Encoding.utf8, allowLossyConversion: false)!
  145. }()
  146. let expectation = self.expectation(description: "Bytes upload progress should be reported: \(urlString)")
  147. var uploadProgressValues: [Double] = []
  148. var downloadProgressValues: [Double] = []
  149. var response: DefaultDataResponse?
  150. // When
  151. Alamofire.upload(data, to: urlString)
  152. .uploadProgress { progress in
  153. uploadProgressValues.append(progress.fractionCompleted)
  154. }
  155. .downloadProgress { progress in
  156. downloadProgressValues.append(progress.fractionCompleted)
  157. }
  158. .response { resp in
  159. response = resp
  160. expectation.fulfill()
  161. }
  162. waitForExpectations(timeout: timeout, handler: nil)
  163. // Then
  164. XCTAssertNotNil(response?.request)
  165. XCTAssertNotNil(response?.response)
  166. XCTAssertNotNil(response?.data)
  167. XCTAssertNil(response?.error)
  168. var previousUploadProgress: Double = uploadProgressValues.first ?? 0.0
  169. for progress in uploadProgressValues {
  170. XCTAssertGreaterThanOrEqual(progress, previousUploadProgress)
  171. previousUploadProgress = progress
  172. }
  173. if let lastProgressValue = uploadProgressValues.last {
  174. XCTAssertEqual(lastProgressValue, 1.0)
  175. } else {
  176. XCTFail("last item in uploadProgressValues should not be nil")
  177. }
  178. var previousDownloadProgress: Double = downloadProgressValues.first ?? 0.0
  179. for progress in downloadProgressValues {
  180. XCTAssertGreaterThanOrEqual(progress, previousDownloadProgress)
  181. previousDownloadProgress = progress
  182. }
  183. if let lastProgressValue = downloadProgressValues.last {
  184. XCTAssertEqual(lastProgressValue, 1.0)
  185. } else {
  186. XCTFail("last item in downloadProgressValues should not be nil")
  187. }
  188. }
  189. }
  190. // MARK: -
  191. class UploadMultipartFormDataTestCase: BaseTestCase {
  192. // MARK: Tests
  193. func testThatUploadingMultipartFormDataSetsContentTypeHeader() {
  194. // Given
  195. let urlString = "https://httpbin.org/post"
  196. let uploadData = "upload_data".data(using: String.Encoding.utf8, allowLossyConversion: false)!
  197. let expectation = self.expectation(description: "multipart form data upload should succeed")
  198. var formData: MultipartFormData?
  199. var response: DefaultDataResponse?
  200. // When
  201. Alamofire.upload(
  202. multipartFormData: { multipartFormData in
  203. multipartFormData.append(uploadData, withName: "upload_data")
  204. formData = multipartFormData
  205. },
  206. to: urlString,
  207. encodingCompletion: { result in
  208. switch result {
  209. case .success(let upload, _, _):
  210. upload.response { resp in
  211. response = resp
  212. expectation.fulfill()
  213. }
  214. case .failure:
  215. expectation.fulfill()
  216. }
  217. }
  218. )
  219. waitForExpectations(timeout: timeout, handler: nil)
  220. // Then
  221. XCTAssertNotNil(response?.request)
  222. XCTAssertNotNil(response?.response)
  223. XCTAssertNotNil(response?.data)
  224. XCTAssertNil(response?.error)
  225. if
  226. let request = response?.request,
  227. let multipartFormData = formData,
  228. let contentType = request.value(forHTTPHeaderField: "Content-Type")
  229. {
  230. XCTAssertEqual(contentType, multipartFormData.contentType)
  231. } else {
  232. XCTFail("Content-Type header value should not be nil")
  233. }
  234. }
  235. func testThatUploadingMultipartFormDataSucceedsWithDefaultParameters() {
  236. // Given
  237. let urlString = "https://httpbin.org/post"
  238. let frenchData = "français".data(using: String.Encoding.utf8, allowLossyConversion: false)!
  239. let japaneseData = "日本語".data(using: String.Encoding.utf8, allowLossyConversion: false)!
  240. let expectation = self.expectation(description: "multipart form data upload should succeed")
  241. var response: DefaultDataResponse?
  242. // When
  243. Alamofire.upload(
  244. multipartFormData: { multipartFormData in
  245. multipartFormData.append(frenchData, withName: "french")
  246. multipartFormData.append(japaneseData, withName: "japanese")
  247. },
  248. to: urlString,
  249. encodingCompletion: { result in
  250. switch result {
  251. case .success(let upload, _, _):
  252. upload.response { resp in
  253. response = resp
  254. expectation.fulfill()
  255. }
  256. case .failure:
  257. expectation.fulfill()
  258. }
  259. }
  260. )
  261. waitForExpectations(timeout: timeout, handler: nil)
  262. // Then
  263. XCTAssertNotNil(response?.request)
  264. XCTAssertNotNil(response?.response)
  265. XCTAssertNotNil(response?.data)
  266. XCTAssertNil(response?.error)
  267. }
  268. func testThatUploadingMultipartFormDataWhileStreamingFromMemoryMonitorsProgress() {
  269. executeMultipartFormDataUploadRequestWithProgress(streamFromDisk: false)
  270. }
  271. func testThatUploadingMultipartFormDataWhileStreamingFromDiskMonitorsProgress() {
  272. executeMultipartFormDataUploadRequestWithProgress(streamFromDisk: true)
  273. }
  274. func testThatUploadingMultipartFormDataBelowMemoryThresholdStreamsFromMemory() {
  275. // Given
  276. let urlString = "https://httpbin.org/post"
  277. let frenchData = "français".data(using: String.Encoding.utf8, allowLossyConversion: false)!
  278. let japaneseData = "日本語".data(using: String.Encoding.utf8, allowLossyConversion: false)!
  279. let expectation = self.expectation(description: "multipart form data upload should succeed")
  280. var streamingFromDisk: Bool?
  281. var streamFileURL: URL?
  282. // When
  283. Alamofire.upload(
  284. multipartFormData: { multipartFormData in
  285. multipartFormData.append(frenchData, withName: "french")
  286. multipartFormData.append(japaneseData, withName: "japanese")
  287. },
  288. to: urlString,
  289. encodingCompletion: { result in
  290. switch result {
  291. case let .success(upload, uploadStreamingFromDisk, uploadStreamFileURL):
  292. streamingFromDisk = uploadStreamingFromDisk
  293. streamFileURL = uploadStreamFileURL
  294. upload.response { _ in
  295. expectation.fulfill()
  296. }
  297. case .failure:
  298. expectation.fulfill()
  299. }
  300. }
  301. )
  302. waitForExpectations(timeout: timeout, handler: nil)
  303. // Then
  304. XCTAssertNotNil(streamingFromDisk, "streaming from disk should not be nil")
  305. XCTAssertNil(streamFileURL, "stream file URL should be nil")
  306. if let streamingFromDisk = streamingFromDisk {
  307. XCTAssertFalse(streamingFromDisk, "streaming from disk should be false")
  308. }
  309. }
  310. func testThatUploadingMultipartFormDataBelowMemoryThresholdSetsContentTypeHeader() {
  311. // Given
  312. let urlString = "https://httpbin.org/post"
  313. let uploadData = "upload data".data(using: String.Encoding.utf8, allowLossyConversion: false)!
  314. let expectation = self.expectation(description: "multipart form data upload should succeed")
  315. var formData: MultipartFormData?
  316. var request: URLRequest?
  317. var streamingFromDisk: Bool?
  318. // When
  319. Alamofire.upload(
  320. multipartFormData: { multipartFormData in
  321. multipartFormData.append(uploadData, withName: "upload_data")
  322. formData = multipartFormData
  323. },
  324. to: urlString,
  325. encodingCompletion: { result in
  326. switch result {
  327. case let .success(upload, uploadStreamingFromDisk, _):
  328. streamingFromDisk = uploadStreamingFromDisk
  329. upload.response { resp in
  330. request = resp.request
  331. expectation.fulfill()
  332. }
  333. case .failure:
  334. expectation.fulfill()
  335. }
  336. }
  337. )
  338. waitForExpectations(timeout: timeout, handler: nil)
  339. // Then
  340. XCTAssertNotNil(streamingFromDisk, "streaming from disk should not be nil")
  341. if let streamingFromDisk = streamingFromDisk {
  342. XCTAssertFalse(streamingFromDisk, "streaming from disk should be false")
  343. }
  344. if
  345. let request = request,
  346. let multipartFormData = formData,
  347. let contentType = request.value(forHTTPHeaderField: "Content-Type")
  348. {
  349. XCTAssertEqual(contentType, multipartFormData.contentType, "Content-Type header value should match")
  350. } else {
  351. XCTFail("Content-Type header value should not be nil")
  352. }
  353. }
  354. func testThatUploadingMultipartFormDataAboveMemoryThresholdStreamsFromDisk() {
  355. // Given
  356. let urlString = "https://httpbin.org/post"
  357. let frenchData = "français".data(using: String.Encoding.utf8, allowLossyConversion: false)!
  358. let japaneseData = "日本語".data(using: String.Encoding.utf8, allowLossyConversion: false)!
  359. let expectation = self.expectation(description: "multipart form data upload should succeed")
  360. var streamingFromDisk: Bool?
  361. var streamFileURL: URL?
  362. // When
  363. Alamofire.upload(
  364. multipartFormData: { multipartFormData in
  365. multipartFormData.append(frenchData, withName: "french")
  366. multipartFormData.append(japaneseData, withName: "japanese")
  367. },
  368. usingThreshold: 0,
  369. to: urlString,
  370. encodingCompletion: { result in
  371. switch result {
  372. case let .success(upload, uploadStreamingFromDisk, uploadStreamFileURL):
  373. streamingFromDisk = uploadStreamingFromDisk
  374. streamFileURL = uploadStreamFileURL
  375. upload.response { _ in
  376. expectation.fulfill()
  377. }
  378. case .failure:
  379. expectation.fulfill()
  380. }
  381. }
  382. )
  383. waitForExpectations(timeout: timeout, handler: nil)
  384. // Then
  385. XCTAssertNotNil(streamingFromDisk, "streaming from disk should not be nil")
  386. XCTAssertNotNil(streamFileURL, "stream file URL should not be nil")
  387. if let streamingFromDisk = streamingFromDisk, let streamFilePath = streamFileURL?.path {
  388. XCTAssertTrue(streamingFromDisk, "streaming from disk should be true")
  389. XCTAssertTrue(
  390. FileManager.default.fileExists(atPath: streamFilePath),
  391. "stream file path should exist"
  392. )
  393. }
  394. }
  395. func testThatUploadingMultipartFormDataAboveMemoryThresholdSetsContentTypeHeader() {
  396. // Given
  397. let urlString = "https://httpbin.org/post"
  398. let uploadData = "upload data".data(using: String.Encoding.utf8, allowLossyConversion: false)!
  399. let expectation = self.expectation(description: "multipart form data upload should succeed")
  400. var formData: MultipartFormData?
  401. var request: URLRequest?
  402. var streamingFromDisk: Bool?
  403. // When
  404. Alamofire.upload(
  405. multipartFormData: { multipartFormData in
  406. multipartFormData.append(uploadData, withName: "upload_data")
  407. formData = multipartFormData
  408. },
  409. usingThreshold: 0,
  410. to: urlString,
  411. encodingCompletion: { result in
  412. switch result {
  413. case let .success(upload, uploadStreamingFromDisk, _):
  414. streamingFromDisk = uploadStreamingFromDisk
  415. upload.response { resp in
  416. request = resp.request
  417. expectation.fulfill()
  418. }
  419. case .failure:
  420. expectation.fulfill()
  421. }
  422. }
  423. )
  424. waitForExpectations(timeout: timeout, handler: nil)
  425. // Then
  426. XCTAssertNotNil(streamingFromDisk, "streaming from disk should not be nil")
  427. if let streamingFromDisk = streamingFromDisk {
  428. XCTAssertTrue(streamingFromDisk, "streaming from disk should be true")
  429. }
  430. if
  431. let request = request,
  432. let multipartFormData = formData,
  433. let contentType = request.value(forHTTPHeaderField: "Content-Type")
  434. {
  435. XCTAssertEqual(contentType, multipartFormData.contentType, "Content-Type header value should match")
  436. } else {
  437. XCTFail("Content-Type header value should not be nil")
  438. }
  439. }
  440. // ⚠️ This test has been removed as a result of rdar://26870455 in Xcode 8 Seed 1
  441. // func testThatUploadingMultipartFormDataOnBackgroundSessionWritesDataToFileToAvoidCrash() {
  442. // // Given
  443. // let manager: SessionManager = {
  444. // let identifier = "org.alamofire.uploadtests.\(UUID().uuidString)"
  445. // let configuration = URLSessionConfiguration.background(withIdentifier: identifier)
  446. //
  447. // return SessionManager(configuration: configuration, serverTrustPolicyManager: nil)
  448. // }()
  449. //
  450. // let urlString = "https://httpbin.org/post"
  451. // let french = "français".data(using: String.Encoding.utf8, allowLossyConversion: false)!
  452. // let japanese = "日本語".data(using: String.Encoding.utf8, allowLossyConversion: false)!
  453. //
  454. // let expectation = self.expectation(description: "multipart form data upload should succeed")
  455. //
  456. // var request: URLRequest?
  457. // var response: HTTPURLResponse?
  458. // var data: Data?
  459. // var error: Error?
  460. // var streamingFromDisk: Bool?
  461. //
  462. // // When
  463. // manager.upload(
  464. // multipartFormData: { multipartFormData in
  465. // multipartFormData.append(french, withName: "french")
  466. // multipartFormData.append(japanese, withName: "japanese")
  467. // },
  468. // to: urlString,
  469. // withMethod: .post,
  470. // encodingCompletion: { result in
  471. // switch result {
  472. // case let .success(upload, uploadStreamingFromDisk, _):
  473. // streamingFromDisk = uploadStreamingFromDisk
  474. //
  475. // upload.response { responseRequest, responseResponse, responseData, responseError in
  476. // request = responseRequest
  477. // response = responseResponse
  478. // data = responseData
  479. // error = responseError
  480. //
  481. // expectation.fulfill()
  482. // }
  483. // case .failure:
  484. // expectation.fulfill()
  485. // }
  486. // }
  487. // )
  488. //
  489. // waitForExpectations(timeout: timeout, handler: nil)
  490. //
  491. // // Then
  492. // XCTAssertNotNil(request, "request should not be nil")
  493. // XCTAssertNotNil(response, "response should not be nil")
  494. // XCTAssertNotNil(data, "data should not be nil")
  495. // XCTAssertNil(error, "error should be nil")
  496. //
  497. // if let streamingFromDisk = streamingFromDisk {
  498. // XCTAssertTrue(streamingFromDisk, "streaming from disk should be true")
  499. // } else {
  500. // XCTFail("streaming from disk should not be nil")
  501. // }
  502. // }
  503. // MARK: Combined Test Execution
  504. private func executeMultipartFormDataUploadRequestWithProgress(streamFromDisk: Bool) {
  505. // Given
  506. let urlString = "https://httpbin.org/post"
  507. let loremData1: Data = {
  508. var loremValues: [String] = []
  509. for _ in 1...1_500 {
  510. loremValues.append("Lorem ipsum dolor sit amet, consectetur adipiscing elit.")
  511. }
  512. return loremValues.joined(separator: " ").data(using: String.Encoding.utf8, allowLossyConversion: false)!
  513. }()
  514. let loremData2: Data = {
  515. var loremValues: [String] = []
  516. for _ in 1...1_500 {
  517. loremValues.append("Lorem ipsum dolor sit amet, nam no graeco recusabo appellantur.")
  518. }
  519. return loremValues.joined(separator: " ").data(using: String.Encoding.utf8, allowLossyConversion: false)!
  520. }()
  521. let expectation = self.expectation(description: "multipart form data upload should succeed")
  522. var uploadProgressValues: [Double] = []
  523. var downloadProgressValues: [Double] = []
  524. var response: DefaultDataResponse?
  525. // When
  526. Alamofire.upload(
  527. multipartFormData: { multipartFormData in
  528. multipartFormData.append(loremData1, withName: "lorem1")
  529. multipartFormData.append(loremData2, withName: "lorem2")
  530. },
  531. usingThreshold: streamFromDisk ? 0 : 100_000_000,
  532. to: urlString,
  533. encodingCompletion: { result in
  534. switch result {
  535. case .success(let upload, _, _):
  536. upload
  537. .uploadProgress { progress in
  538. uploadProgressValues.append(progress.fractionCompleted)
  539. }
  540. .downloadProgress { progress in
  541. downloadProgressValues.append(progress.fractionCompleted)
  542. }
  543. .response { resp in
  544. response = resp
  545. expectation.fulfill()
  546. }
  547. case .failure:
  548. expectation.fulfill()
  549. }
  550. }
  551. )
  552. waitForExpectations(timeout: timeout, handler: nil)
  553. // Then
  554. XCTAssertNotNil(response?.request)
  555. XCTAssertNotNil(response?.response)
  556. XCTAssertNotNil(response?.data)
  557. XCTAssertNil(response?.error)
  558. var previousUploadProgress: Double = uploadProgressValues.first ?? 0.0
  559. for progress in uploadProgressValues {
  560. XCTAssertGreaterThanOrEqual(progress, previousUploadProgress)
  561. previousUploadProgress = progress
  562. }
  563. if let lastProgressValue = uploadProgressValues.last {
  564. XCTAssertEqual(lastProgressValue, 1.0)
  565. } else {
  566. XCTFail("last item in uploadProgressValues should not be nil")
  567. }
  568. var previousDownloadProgress: Double = downloadProgressValues.first ?? 0.0
  569. for progress in downloadProgressValues {
  570. XCTAssertGreaterThanOrEqual(progress, previousDownloadProgress)
  571. previousDownloadProgress = progress
  572. }
  573. if let lastProgressValue = downloadProgressValues.last {
  574. XCTAssertEqual(lastProgressValue, 1.0)
  575. } else {
  576. XCTFail("last item in downloadProgressValues should not be nil")
  577. }
  578. }
  579. }