Explorar o código

Appending response serializer now resumes request if finished to handle races (#2862)

Christian Noon %!s(int64=6) %!d(string=hai) anos
pai
achega
0bab25fab5
Modificáronse 4 ficheiros con 39 adicións e 18 borrados
  1. 0 4
      Source/AFError.swift
  2. 1 1
      Source/Request.swift
  3. 0 10
      Tests/AFError+AlamofireTests.swift
  4. 38 3
      Tests/RequestTests.swift

+ 0 - 4
Source/AFError.swift

@@ -111,8 +111,6 @@ public enum AFError: Error {
         case decodingFailed(error: Error)
         /// Generic serialization failed for an empty response that wasn't type `Empty` but instead the associated type.
         case invalidEmptyResponse(type: String)
-        /// A response serializer was added to the request after the request was already finished.
-        case responseSerializerAddedAfterRequestFinished
     }
 
     /// Underlying reason a server trust evaluation error occurred.
@@ -541,8 +539,6 @@ extension AFError.ResponseSerializationFailureReason {
             return "Empty response could not be serialized to type: \(type). Use Empty as the expected type for such responses."
         case .decodingFailed(let error):
             return "Response could not be decoded because of error:\n\(error.localizedDescription)"
-        case .responseSerializerAddedAfterRequestFinished:
-            return "Response serializer was added to the request after it had already finished."
         }
     }
 }

+ 1 - 1
Source/Request.swift

@@ -442,7 +442,7 @@ public class Request {
             mutableState.responseSerializers.append(closure)
 
             if mutableState.state == .finished {
-                mutableState.error = AFError.responseSerializationFailed(reason: .responseSerializerAddedAfterRequestFinished)
+                mutableState.state = .resumed
             }
 
             if mutableState.responseSerializerProcessingFinished {

+ 0 - 10
Tests/AFError+AlamofireTests.swift

@@ -142,11 +142,6 @@ extension AFError {
         return false
     }
 
-    var isResponseSerializerAddedAfterRequestFinished: Bool {
-        if case let .responseSerializationFailed(reason) = self, reason.isResponseSerializerAddedAfterRequestFinished { return true }
-        return false
-    }
-
     // ResponseValidationFailureReason
 
     var isDataFileNil: Bool {
@@ -295,11 +290,6 @@ extension AFError.ResponseSerializationFailureReason {
         if case .invalidEmptyResponse = self { return true }
         return false
     }
-
-    var isResponseSerializerAddedAfterRequestFinished: Bool {
-        if case .responseSerializerAddedAfterRequestFinished = self { return true }
-        return false
-    }
 }
 
 // MARK: -

+ 38 - 3
Tests/RequestTests.swift

@@ -652,15 +652,16 @@ class RequestResponseTestCase: BaseTestCase {
         XCTAssertEqual(response2?.error?.asAFError?.isExplicitlyCancelledError, true)
     }
 
-    func testThatAppendingResponseSerializerToCompletedRequestCallsCompletion() {
+    func testThatAppendingResponseSerializerToCompletedRequestInsideCompletionResumesRequest() {
         // Given
         let session = Session()
 
         var response1: DataResponse<Any>?
         var response2: DataResponse<Any>?
+        var response3: DataResponse<Any>?
 
         let expect = expectation(description: "both response serializer completions should be called")
-        expect.expectedFulfillmentCount = 2
+        expect.expectedFulfillmentCount = 3
 
         // When
         let request = session.request(URLRequest.makeHTTPBinRequest())
@@ -672,6 +673,11 @@ class RequestResponseTestCase: BaseTestCase {
             request.responseJSON { resp in
                 response2 = resp
                 expect.fulfill()
+
+                request.responseJSON { resp in
+                    response3 = resp
+                    expect.fulfill()
+                }
             }
         }
 
@@ -679,7 +685,36 @@ class RequestResponseTestCase: BaseTestCase {
 
         // Then
         XCTAssertNotNil(response1?.value)
-        XCTAssertEqual(response2?.error?.asAFError?.isResponseSerializerAddedAfterRequestFinished, true)
+        XCTAssertNotNil(response2?.value)
+        XCTAssertNotNil(response3?.value)
+    }
+
+    func testThatAppendingResponseSerializerToCompletedRequestOutsideCompletionResumesRequest() {
+        // Given
+        let session = Session()
+        let request = session.request(URLRequest.makeHTTPBinRequest())
+
+        var response1: DataResponse<Any>?
+        var response2: DataResponse<Any>?
+        var response3: DataResponse<Any>?
+
+        // When
+        let expect1 = expectation(description: "response serializer 1 completion should be called")
+        request.responseJSON { response1 = $0; expect1.fulfill() }
+        waitForExpectations(timeout: timeout, handler: nil)
+
+        let expect2 = expectation(description: "response serializer 2 completion should be called")
+        request.responseJSON { response2 = $0; expect2.fulfill() }
+        waitForExpectations(timeout: timeout, handler: nil)
+
+        let expect3 = expectation(description: "response serializer 3 completion should be called")
+        request.responseJSON { response3 = $0; expect3.fulfill() }
+        waitForExpectations(timeout: timeout, handler: nil)
+
+        // Then
+        XCTAssertNotNil(response1?.value)
+        XCTAssertNotNil(response2?.value)
+        XCTAssertNotNil(response3?.value)
     }
 }