| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895 |
- //
- // UploadTests.swift
- //
- // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/)
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- //
- import Alamofire
- import Foundation
- import XCTest
- final class UploadFileInitializationTestCase: BaseTestCase {
- @MainActor
- func testUploadClassMethodWithMethodURLAndFile() {
- // Given
- let requestURL = Endpoint.method(.post).url
- let imageURL = url(forResource: "rainbow", withExtension: "jpg")
- let expectation = expectation(description: "upload should complete")
- // When
- let request = AF.upload(imageURL, to: requestURL).response { _ in
- expectation.fulfill()
- }
- waitForExpectations(timeout: timeout)
- // Then
- XCTAssertNotNil(request.request, "request should not be nil")
- XCTAssertEqual(request.request?.httpMethod, "POST", "request HTTP method should be POST")
- XCTAssertEqual(request.request?.url, requestURL, "request URL should be equal")
- XCTAssertNotNil(request.response, "response should not be nil")
- }
- @MainActor
- func testUploadClassMethodWithMethodURLHeadersAndFile() {
- // Given
- let requestURL = Endpoint.method(.post).url
- let headers: HTTPHeaders = ["Authorization": "123456"]
- let imageURL = url(forResource: "rainbow", withExtension: "jpg")
- let expectation = expectation(description: "upload should complete")
- // When
- let request = AF.upload(imageURL, to: requestURL, method: .post, headers: headers).response { _ in
- expectation.fulfill()
- }
- waitForExpectations(timeout: timeout)
- // Then
- XCTAssertNotNil(request.request, "request should not be nil")
- XCTAssertEqual(request.request?.httpMethod, "POST", "request HTTP method should be POST")
- XCTAssertEqual(request.request?.url, requestURL, "request URL should be equal")
- let authorizationHeader = request.request?.value(forHTTPHeaderField: "Authorization") ?? ""
- XCTAssertEqual(authorizationHeader, "123456", "Authorization header is incorrect")
- XCTAssertNotNil(request.response, "response should not be nil")
- }
- }
- // MARK: -
- final class UploadDataInitializationTestCase: BaseTestCase {
- @MainActor
- func testUploadClassMethodWithMethodURLAndData() {
- // Given
- let url = Endpoint.method(.post).url
- let expectation = expectation(description: "upload should complete")
- // When
- let request = AF.upload(Data(), to: url).response { _ in
- expectation.fulfill()
- }
- waitForExpectations(timeout: timeout)
- // Then
- XCTAssertNotNil(request.request, "request should not be nil")
- XCTAssertEqual(request.request?.httpMethod ?? "", "POST", "request HTTP method should be POST")
- XCTAssertEqual(request.request?.url, url, "request URL should be equal")
- XCTAssertNotNil(request.response, "response should not be nil")
- }
- @MainActor
- func testUploadClassMethodWithMethodURLHeadersAndData() {
- // Given
- let url = Endpoint.method(.post).url
- let headers: HTTPHeaders = ["Authorization": "123456"]
- let expectation = expectation(description: "upload should complete")
- // When
- let request = AF.upload(Data(), to: url, headers: headers).response { _ in
- expectation.fulfill()
- }
- waitForExpectations(timeout: timeout)
- // Then
- XCTAssertNotNil(request.request, "request should not be nil")
- XCTAssertEqual(request.request?.httpMethod, "POST", "request HTTP method should be POST")
- XCTAssertEqual(request.request?.url, url, "request URL should be equal")
- let authorizationHeader = request.request?.value(forHTTPHeaderField: "Authorization") ?? ""
- XCTAssertEqual(authorizationHeader, "123456", "Authorization header is incorrect")
- XCTAssertNotNil(request.response, "response should not be nil")
- }
- }
- // MARK: -
- final class UploadStreamInitializationTestCase: BaseTestCase {
- @MainActor
- func testUploadClassMethodWithMethodURLAndStream() {
- // Given
- let requestURL = Endpoint.method(.post).url
- let imageURL = url(forResource: "rainbow", withExtension: "jpg")
- let imageStream = InputStream(url: imageURL)!
- let expectation = expectation(description: "upload should complete")
- // When
- let request = AF.upload(imageStream, to: requestURL).response { _ in
- expectation.fulfill()
- }
- waitForExpectations(timeout: timeout)
- // Then
- XCTAssertNotNil(request.request, "request should not be nil")
- XCTAssertEqual(request.request?.httpMethod, "POST", "request HTTP method should be POST")
- XCTAssertEqual(request.request?.url, requestURL, "request URL should be equal")
- XCTAssertNotNil(request.response, "response should not be nil")
- }
- @MainActor
- func testUploadClassMethodWithMethodURLHeadersAndStream() {
- // Given
- let requestURL = Endpoint.method(.post).url
- let imageURL = url(forResource: "rainbow", withExtension: "jpg")
- let headers: HTTPHeaders = ["Authorization": "123456"]
- let imageStream = InputStream(url: imageURL)!
- let expectation = expectation(description: "upload should complete")
- // When
- let request = AF.upload(imageStream, to: requestURL, headers: headers).response { _ in
- expectation.fulfill()
- }
- waitForExpectations(timeout: timeout)
- // Then
- XCTAssertNotNil(request.request, "request should not be nil")
- XCTAssertEqual(request.request?.httpMethod, "POST", "request HTTP method should be POST")
- XCTAssertEqual(request.request?.url, requestURL, "request URL should be equal")
- let authorizationHeader = request.request?.value(forHTTPHeaderField: "Authorization") ?? ""
- XCTAssertEqual(authorizationHeader, "123456", "Authorization header is incorrect")
- XCTAssertNotNil(request.response, "response should not be nil, tasks: \(request.tasks)")
- }
- }
- // MARK: -
- final class UploadDataTestCase: BaseTestCase {
- @MainActor
- func testUploadDataRequest() {
- // Given
- let url = Endpoint.method(.post).url
- let data = Data("Lorem ipsum dolor sit amet".utf8)
- let expectation = expectation(description: "Upload request should succeed: \(url)")
- var response: DataResponse<Data?, AFError>?
- // When
- AF.upload(data, to: url)
- .response { resp in
- response = resp
- expectation.fulfill()
- }
- waitForExpectations(timeout: timeout)
- // Then
- XCTAssertNotNil(response?.request)
- XCTAssertNotNil(response?.response)
- XCTAssertNil(response?.error)
- }
- @MainActor
- func testUploadDataRequestWithProgress() {
- // Given
- let url = Endpoint.method(.post).url
- let string = String(repeating: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. ", count: 1000)
- let data = Data(string.utf8)
- let expectation = expectation(description: "Bytes upload progress should be reported: \(url)")
- var uploadProgressValues: [Double] = []
- var downloadProgressValues: [Double] = []
- var response: DataResponse<Data?, AFError>?
- // When
- AF.upload(data, to: url)
- .uploadProgress { progress in
- uploadProgressValues.append(progress.fractionCompleted)
- }
- .downloadProgress { progress in
- downloadProgressValues.append(progress.fractionCompleted)
- }
- .response { resp in
- response = resp
- expectation.fulfill()
- }
- waitForExpectations(timeout: timeout)
- // Then
- XCTAssertNotNil(response?.request)
- XCTAssertNotNil(response?.response)
- XCTAssertNotNil(response?.data)
- XCTAssertNil(response?.error)
- var previousUploadProgress: Double = uploadProgressValues.first ?? 0.0
- for progress in uploadProgressValues {
- XCTAssertGreaterThanOrEqual(progress, previousUploadProgress)
- previousUploadProgress = progress
- }
- if let lastProgressValue = uploadProgressValues.last {
- XCTAssertEqual(lastProgressValue, 1.0)
- } else {
- XCTFail("last item in uploadProgressValues should not be nil")
- }
- var previousDownloadProgress: Double = downloadProgressValues.first ?? 0.0
- for progress in downloadProgressValues {
- XCTAssertGreaterThanOrEqual(progress, previousDownloadProgress)
- previousDownloadProgress = progress
- }
- if let lastProgressValue = downloadProgressValues.last {
- XCTAssertEqual(lastProgressValue, 1.0)
- } else {
- XCTFail("last item in downloadProgressValues should not be nil")
- }
- }
- }
- // MARK: -
- final class UploadMultipartFormDataTestCase: BaseTestCase {
- @MainActor
- func testThatUploadingMultipartFormDataSetsContentTypeHeader() {
- // Given
- let url = Endpoint.method(.post).url
- let uploadData = Data("upload_data".utf8)
- let expectation = expectation(description: "multipart form data upload should succeed")
- var formData: MultipartFormData?
- var response: DataResponse<Data?, AFError>?
- // When
- AF.upload(multipartFormData: { multipartFormData in
- multipartFormData.append(uploadData, withName: "upload_data")
- formData = multipartFormData
- },
- to: url)
- .response { resp in
- response = resp
- expectation.fulfill()
- }
- waitForExpectations(timeout: timeout)
- // Then
- XCTAssertNotNil(response?.request)
- XCTAssertNotNil(response?.response)
- XCTAssertNotNil(response?.data)
- XCTAssertNil(response?.error)
- if
- let request = response?.request,
- let multipartFormData = formData,
- let contentType = request.value(forHTTPHeaderField: "Content-Type") {
- XCTAssertEqual(contentType, multipartFormData.contentType)
- } else {
- XCTFail("Content-Type header value should not be nil")
- }
- }
- @MainActor
- func testThatAccessingMultipartFormDataURLIsThreadSafe() {
- // Given
- let url = Endpoint.method(.post).url
- let uploadData = Data("upload_data".utf8)
- let expectation = expectation(description: "multipart form data upload should succeed")
- var formData: MultipartFormData?
- var generatedURL: URL?
- var response: DataResponse<Data?, AFError>?
- // When
- let upload = AF.upload(multipartFormData: { multipartFormData in
- multipartFormData.append(uploadData, withName: "upload_data")
- formData = multipartFormData
- },
- to: url)
- // Access will produce a thread-sanitizer issue if it isn't safe.
- generatedURL = upload.convertible.urlRequest?.url
- upload.response { resp in
- response = resp
- expectation.fulfill()
- }
- waitForExpectations(timeout: timeout)
- // Then
- XCTAssertNotNil(response?.request)
- XCTAssertNotNil(response?.response)
- XCTAssertNotNil(response?.data)
- XCTAssertNil(response?.error)
- if
- let request = response?.request,
- let multipartFormData = formData,
- let contentType = request.value(forHTTPHeaderField: "Content-Type") {
- XCTAssertEqual(contentType, multipartFormData.contentType)
- XCTAssertEqual(url, generatedURL)
- } else {
- XCTFail("Content-Type header value should not be nil")
- }
- }
- @MainActor
- func testThatCustomBoundaryCanBeSetWhenUploadingMultipartFormData() throws {
- // Given
- let uploadData = Data("upload_data".utf8)
- let formData = MultipartFormData(fileManager: .default, boundary: "custom-test-boundary")
- formData.append(uploadData, withName: "upload_data")
- let expectation = expectation(description: "multipart form data upload should succeed")
- var response: DataResponse<Data?, AFError>?
- // When
- AF.upload(multipartFormData: formData, with: Endpoint.method(.post)).response { resp in
- response = resp
- expectation.fulfill()
- }
- waitForExpectations(timeout: timeout)
- // Then
- XCTAssertNotNil(response?.request)
- XCTAssertNotNil(response?.response)
- XCTAssertNotNil(response?.data)
- XCTAssertNil(response?.error)
- if let request = response?.request, let contentType = request.value(forHTTPHeaderField: "Content-Type") {
- XCTAssertEqual(contentType, formData.contentType)
- XCTAssertTrue(contentType.contains("boundary=custom-test-boundary"))
- } else {
- XCTFail("Content-Type header value should not be nil")
- }
- }
- @MainActor
- func testThatUploadingMultipartFormDataSucceedsWithDefaultParameters() {
- // Given
- let frenchData = Data("français".utf8)
- let japaneseData = Data("日本語".utf8)
- let expectation = expectation(description: "multipart form data upload should succeed")
- var response: DataResponse<Data?, AFError>?
- // When
- AF.upload(multipartFormData: { multipartFormData in
- multipartFormData.append(frenchData, withName: "french")
- multipartFormData.append(japaneseData, withName: "japanese")
- },
- to: Endpoint.method(.post))
- .response { resp in
- response = resp
- expectation.fulfill()
- }
- waitForExpectations(timeout: timeout)
- // Then
- XCTAssertNotNil(response?.request)
- XCTAssertNotNil(response?.response)
- XCTAssertNotNil(response?.data)
- XCTAssertNil(response?.error)
- }
- // func testThatUploadingMultipartFormDataWhileStreamingFromMemoryMonitorsProgress() {
- // executeMultipartFormDataUploadRequestWithProgress(streamFromDisk: false)
- // }
- //
- // func testThatUploadingMultipartFormDataWhileStreamingFromDiskMonitorsProgress() {
- // executeMultipartFormDataUploadRequestWithProgress(streamFromDisk: true)
- // }
- @MainActor
- func testThatUploadingMultipartFormDataBelowMemoryThresholdStreamsFromMemory() {
- // Given
- let frenchData = Data("français".utf8)
- let japaneseData = Data("日本語".utf8)
- let expectation = expectation(description: "multipart form data upload should succeed")
- var response: DataResponse<Data?, AFError>?
- // When
- let request = AF.upload(multipartFormData: { multipartFormData in
- multipartFormData.append(frenchData, withName: "french")
- multipartFormData.append(japaneseData, withName: "japanese")
- },
- to: Endpoint.method(.post))
- .response { resp in
- response = resp
- expectation.fulfill()
- }
- waitForExpectations(timeout: timeout)
- // Then
- guard let uploadable = request.uploadable, case .data = uploadable else {
- XCTFail("Uploadable is not .data")
- return
- }
- XCTAssertTrue(response?.result.isSuccess == true)
- }
- @MainActor
- func testThatUploadingMultipartFormDataBelowMemoryThresholdSetsContentTypeHeader() {
- // Given
- let uploadData = Data("upload_data".utf8)
- let expectation = expectation(description: "multipart form data upload should succeed")
- var formData: MultipartFormData?
- var response: DataResponse<Data?, AFError>?
- // When
- let request = AF.upload(multipartFormData: { multipartFormData in
- multipartFormData.append(uploadData, withName: "upload_data")
- formData = multipartFormData
- },
- to: Endpoint.method(.post))
- .response { resp in
- response = resp
- expectation.fulfill()
- }
- waitForExpectations(timeout: timeout)
- // Then
- guard let uploadable = request.uploadable, case .data = uploadable else {
- XCTFail("Uploadable is not .data")
- return
- }
- if
- let request = response?.request,
- let multipartFormData = formData,
- let contentType = request.value(forHTTPHeaderField: "Content-Type") {
- XCTAssertEqual(contentType, multipartFormData.contentType, "Content-Type header value should match")
- } else {
- XCTFail("Content-Type header value should not be nil")
- }
- }
- @MainActor
- func testThatUploadingMultipartFormDataAboveMemoryThresholdStreamsFromDisk() {
- // Given
- let frenchData = Data("français".utf8)
- let japaneseData = Data("日本語".utf8)
- let expectation = expectation(description: "multipart form data upload should succeed")
- var response: DataResponse<Data?, AFError>?
- // When
- let request = AF.upload(multipartFormData: { multipartFormData in
- multipartFormData.append(frenchData, withName: "french")
- multipartFormData.append(japaneseData, withName: "japanese")
- },
- to: Endpoint.method(.post),
- usingThreshold: 0).response { resp in
- response = resp
- expectation.fulfill()
- }
- waitForExpectations(timeout: timeout)
- // Then
- guard let uploadable = request.uploadable, case let .file(url, _) = uploadable else {
- XCTFail("Uploadable is not .file")
- return
- }
- XCTAssertTrue(response?.result.isSuccess == true)
- XCTAssertFalse(FileManager.default.fileExists(atPath: url.path))
- }
- @MainActor
- func testThatUploadingMultipartFormDataAboveMemoryThresholdSetsContentTypeHeader() {
- // Given
- let uploadData = Data("upload_data".utf8)
- let expectation = expectation(description: "multipart form data upload should succeed")
- var response: DataResponse<Data?, AFError>?
- var formData: MultipartFormData?
- // When
- let request = AF.upload(multipartFormData: { multipartFormData in
- multipartFormData.append(uploadData, withName: "upload_data")
- formData = multipartFormData
- },
- to: Endpoint.method(.post),
- usingThreshold: 0).response { resp in
- response = resp
- expectation.fulfill()
- }
- waitForExpectations(timeout: timeout)
- // Then
- guard let uploadable = request.uploadable, case .file = uploadable else {
- XCTFail("Uploadable is not .file")
- return
- }
- XCTAssertTrue(response?.result.isSuccess == true)
- if
- let request = response?.request,
- let multipartFormData = formData,
- let contentType = request.value(forHTTPHeaderField: "Content-Type") {
- XCTAssertEqual(contentType, multipartFormData.contentType, "Content-Type header value should match")
- } else {
- XCTFail("Content-Type header value should not be nil")
- }
- }
- @MainActor
- func testThatUploadingMultipartFormDataWithNonexistentFileThrowsAnError() {
- // Given
- let imageURL = URL(fileURLWithPath: "does_not_exist.jpg")
- let expectation = expectation(description: "multipart form data upload from nonexistent file should fail")
- var response: DataResponse<Data?, AFError>?
- // When
- let request = AF.upload(multipartFormData: { multipartFormData in
- multipartFormData.append(imageURL, withName: "upload_file")
- },
- to: Endpoint.method(.post),
- usingThreshold: 0).response { resp in
- response = resp
- expectation.fulfill()
- }
- waitForExpectations(timeout: timeout)
- // Then
- XCTAssertNil(request.uploadable)
- XCTAssertTrue(response?.result.isSuccess == false)
- }
- @MainActor
- func testThatUploadingMultipartFormDataWorksWhenAppendingBodyPartsInURLRequestConvertible() {
- // Given
- struct MultipartFormDataRequest: URLRequestConvertible {
- let multipartFormData = MultipartFormData()
- func asURLRequest() throws -> URLRequest {
- appendBodyParts()
- return try Endpoint.method(.post).asURLRequest()
- }
- func appendBodyParts() {
- let frenchData = Data("français".utf8)
- multipartFormData.append(frenchData, withName: "french")
- let japaneseData = Data("日本語".utf8)
- multipartFormData.append(japaneseData, withName: "japanese")
- }
- }
- let request = MultipartFormDataRequest()
- let expectation = expectation(description: "multipart form data upload should succeed")
- var response: DataResponse<Data?, AFError>?
- // When
- let uploadRequest = AF.upload(multipartFormData: request.multipartFormData, with: request)
- .response { resp in
- response = resp
- expectation.fulfill()
- }
- waitForExpectations(timeout: timeout)
- // Then
- XCTAssertNotNil(response?.request)
- XCTAssertNotNil(response?.response)
- XCTAssertNotNil(response?.data)
- XCTAssertNil(response?.error)
- switch uploadRequest.uploadable {
- case let .data(data):
- XCTAssertEqual(data.count, 241)
- default:
- XCTFail("Uploadable should be of type data and not be empty")
- }
- }
- #if os(macOS)
- @MainActor
- func disabled_testThatUploadingMultipartFormDataOnBackgroundSessionWritesDataToFileToAvoidCrash() {
- // Given
- let manager: Session = {
- let identifier = "org.alamofire.uploadtests.\(UUID().uuidString)"
- let configuration = URLSessionConfiguration.background(withIdentifier: identifier)
- return Session(configuration: configuration)
- }()
- let french = Data("français".utf8)
- let japanese = Data("日本語".utf8)
- let expectation = expectation(description: "multipart form data upload should succeed")
- var request: URLRequest?
- var response: HTTPURLResponse?
- var data: Data?
- var error: AFError?
- // When
- let upload = manager.upload(multipartFormData: { multipartFormData in
- multipartFormData.append(french, withName: "french")
- multipartFormData.append(japanese, withName: "japanese")
- },
- to: Endpoint.method(.post))
- .response { defaultResponse in
- request = defaultResponse.request
- response = defaultResponse.response
- data = defaultResponse.data
- error = defaultResponse.error
- expectation.fulfill()
- }
- waitForExpectations(timeout: timeout)
- // Then
- XCTAssertNotNil(request, "request should not be nil")
- XCTAssertNotNil(response, "response should not be nil")
- XCTAssertNotNil(data, "data should not be nil")
- XCTAssertNil(error, "error should be nil")
- guard let uploadable = upload.uploadable, case .file = uploadable else {
- XCTFail("Uploadable is not .file")
- return
- }
- }
- #endif
- // MARK: Combined Test Execution
- @MainActor
- private func executeMultipartFormDataUploadRequestWithProgress(streamFromDisk: Bool) {
- // Given
- let loremData1 = Data(String(repeating: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
- count: 4).utf8)
- let loremData2 = Data(String(repeating: "Lorem ipsum dolor sit amet, nam no graeco recusabo appellantur.",
- count: 4).utf8)
- let expectation = expectation(description: "multipart form data upload should succeed")
- var uploadProgressValues: [Double] = []
- var downloadProgressValues: [Double] = []
- var response: DataResponse<Data?, AFError>?
- // When
- AF.upload(multipartFormData: { multipartFormData in
- multipartFormData.append(loremData1, withName: "lorem1")
- multipartFormData.append(loremData2, withName: "lorem2")
- },
- to: Endpoint.method(.post),
- usingThreshold: streamFromDisk ? 0 : 100_000_000)
- .uploadProgress { progress in
- uploadProgressValues.append(progress.fractionCompleted)
- }
- .downloadProgress { progress in
- downloadProgressValues.append(progress.fractionCompleted)
- }
- .response { resp in
- response = resp
- expectation.fulfill()
- }
- waitForExpectations(timeout: timeout)
- // Then
- XCTAssertNotNil(response?.request)
- XCTAssertNotNil(response?.response)
- XCTAssertNotNil(response?.data)
- XCTAssertNil(response?.error)
- var previousUploadProgress: Double = uploadProgressValues.first ?? 0.0
- for progress in uploadProgressValues {
- XCTAssertGreaterThanOrEqual(progress, previousUploadProgress)
- previousUploadProgress = progress
- }
- if let lastProgressValue = uploadProgressValues.last {
- XCTAssertEqual(lastProgressValue, 1.0)
- } else {
- XCTFail("last item in uploadProgressValues should not be nil")
- }
- var previousDownloadProgress: Double = downloadProgressValues.first ?? 0.0
- for progress in downloadProgressValues {
- XCTAssertGreaterThanOrEqual(progress, previousDownloadProgress)
- previousDownloadProgress = progress
- }
- if let lastProgressValue = downloadProgressValues.last {
- XCTAssertEqual(lastProgressValue, 1.0)
- } else {
- XCTFail("last item in downloadProgressValues should not be nil")
- }
- }
- }
- final class UploadRetryTests: BaseTestCase {
- @MainActor
- func testThatDataUploadRetriesCorrectly() {
- // Given
- let endpoint = Endpoint(path: .delay(interval: 1),
- method: .post,
- headers: [.contentType("text/plain")],
- timeout: 0.1)
- let retrier = InspectorInterceptor(SingleRetrier())
- let didRetry = expectation(description: "request did retry")
- retrier.onRetry = { _ in didRetry.fulfill() }
- let session = Session(interceptor: retrier)
- let body = "body"
- let data = Data(body.utf8)
- var response: AFDataResponse<TestResponse>?
- let completion = expectation(description: "upload should complete")
- // When
- session.upload(data, with: endpoint).responseDecodable(of: TestResponse.self) {
- response = $0
- completion.fulfill()
- }
- waitForExpectations(timeout: timeout)
- // Then
- XCTAssertEqual(retrier.retryCalledCount, 1)
- XCTAssertTrue(response?.result.isSuccess == true)
- XCTAssertEqual(response?.value?.data, body)
- }
- }
- final class UploadRequestEventsTestCase: BaseTestCase {
- @MainActor
- func testThatUploadRequestTriggersAllAppropriateLifetimeEvents() {
- // Given
- let eventMonitor = ClosureEventMonitor()
- let session = Session(eventMonitors: [eventMonitor])
- let taskDidFinishCollecting = expectation(description: "taskDidFinishCollecting should fire")
- let didCreateInitialURLRequest = expectation(description: "didCreateInitialURLRequest should fire")
- let didCreateURLRequest = expectation(description: "didCreateURLRequest should fire")
- let didCreateTask = expectation(description: "didCreateTask should fire")
- let didGatherMetrics = expectation(description: "didGatherMetrics should fire")
- let didComplete = expectation(description: "didComplete should fire")
- let didFinish = expectation(description: "didFinish should fire")
- let didResume = expectation(description: "didResume should fire")
- let didResumeTask = expectation(description: "didResumeTask should fire")
- let didCreateUploadable = expectation(description: "didCreateUploadable should fire")
- let didParseResponse = expectation(description: "didParseResponse should fire")
- let responseHandler = expectation(description: "responseHandler should fire")
- eventMonitor.taskDidFinishCollectingMetrics = { _, _, _ in taskDidFinishCollecting.fulfill() }
- eventMonitor.requestDidCreateInitialURLRequest = { _, _ in didCreateInitialURLRequest.fulfill() }
- eventMonitor.requestDidCreateURLRequest = { _, _ in didCreateURLRequest.fulfill() }
- eventMonitor.requestDidCreateTask = { _, _ in didCreateTask.fulfill() }
- eventMonitor.requestDidGatherMetrics = { _, _ in didGatherMetrics.fulfill() }
- eventMonitor.requestDidCompleteTaskWithError = { _, _, _ in didComplete.fulfill() }
- eventMonitor.requestDidFinish = { _ in didFinish.fulfill() }
- eventMonitor.requestDidResume = { _ in didResume.fulfill() }
- eventMonitor.requestDidResumeTask = { _, _ in didResumeTask.fulfill() }
- eventMonitor.requestDidCreateUploadable = { _, _ in didCreateUploadable.fulfill() }
- eventMonitor.requestDidParseResponse = { _, _ in didParseResponse.fulfill() }
- // When
- let request = session.upload(Data("PAYLOAD".utf8),
- with: Endpoint.method(.post)).response { _ in
- responseHandler.fulfill()
- }
- waitForExpectations(timeout: timeout)
- // Then
- XCTAssertEqual(request.state, .finished)
- }
- @MainActor
- func testThatCancelledUploadRequestTriggersAllAppropriateLifetimeEvents() {
- // Given
- let eventMonitor = ClosureEventMonitor()
- let session = Session(startRequestsImmediately: false, eventMonitors: [eventMonitor])
- let taskDidFinishCollecting = expectation(description: "taskDidFinishCollecting should fire")
- let didCreateInitialURLRequest = expectation(description: "didCreateInitialURLRequest should fire")
- let didCreateURLRequest = expectation(description: "didCreateURLRequest should fire")
- let didCreateTask = expectation(description: "didCreateTask should fire")
- let didGatherMetrics = expectation(description: "didGatherMetrics should fire")
- let didComplete = expectation(description: "didComplete should fire")
- let didFinish = expectation(description: "didFinish should fire")
- let didResume = expectation(description: "didResume should fire")
- let didResumeTask = expectation(description: "didResumeTask should fire")
- let didCreateUploadable = expectation(description: "didCreateUploadable should fire")
- let didParseResponse = expectation(description: "didParseResponse should fire")
- let didCancel = expectation(description: "didCancel should fire")
- let didCancelTask = expectation(description: "didCancelTask should fire")
- let responseHandler = expectation(description: "responseHandler should fire")
- eventMonitor.taskDidFinishCollectingMetrics = { _, _, _ in taskDidFinishCollecting.fulfill() }
- eventMonitor.requestDidCreateInitialURLRequest = { _, _ in didCreateInitialURLRequest.fulfill() }
- eventMonitor.requestDidCreateURLRequest = { _, _ in didCreateURLRequest.fulfill() }
- eventMonitor.requestDidCreateTask = { _, _ in didCreateTask.fulfill() }
- eventMonitor.requestDidGatherMetrics = { _, _ in didGatherMetrics.fulfill() }
- eventMonitor.requestDidCompleteTaskWithError = { _, _, _ in didComplete.fulfill() }
- eventMonitor.requestDidFinish = { _ in didFinish.fulfill() }
- eventMonitor.requestDidResume = { _ in didResume.fulfill() }
- eventMonitor.requestDidCreateUploadable = { _, _ in didCreateUploadable.fulfill() }
- eventMonitor.requestDidParseResponse = { _, _ in didParseResponse.fulfill() }
- eventMonitor.requestDidCancel = { _ in didCancel.fulfill() }
- eventMonitor.requestDidCancelTask = { _, _ in didCancelTask.fulfill() }
- // When
- let request = session.upload(Data("PAYLOAD".utf8),
- with: Endpoint.delay(5).modifying(\.method, to: .post)).response { _ in
- responseHandler.fulfill()
- }
- eventMonitor.requestDidResumeTask = { [unowned request] _, _ in
- request.cancel()
- didResumeTask.fulfill()
- }
- request.resume()
- waitForExpectations(timeout: timeout)
- // Then
- XCTAssertEqual(request.state, .cancelled)
- }
- }
|