Skip to content

Commit

Permalink
Merge pull request #29 from icapps/feature/fix-refresh-loop
Browse files Browse the repository at this point in the history
Pass the retry count of the current request to the interceptor.
  • Loading branch information
fousa authored Mar 5, 2019
2 parents f5d4019 + f4f01eb commit e595108
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 11 deletions.
4 changes: 3 additions & 1 deletion Example/Tests/Mocks/MockedInterceptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import Cara

class MockedInterceptor: Interceptor {
var interceptHandle: ((_ error: ResponseError, _ retry: @escaping () -> Void) -> Bool)?
func intercept(_ error: ResponseError, data: Data?, retry: @escaping () -> Void) -> Bool {
var didReceiveRetryCount: UInt?
func intercept(_ error: ResponseError, data: Data?, retryCount: UInt, retry: @escaping () -> Void) -> Bool {
didReceiveRetryCount = retryCount
return interceptHandle?(error, retry) ?? false
}
}
19 changes: 13 additions & 6 deletions Example/Tests/Specs/Service/NetworkServiceSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class NetworkServiceSpec: QuickSpec {
self.stub(http(.get, uri: "https://relative.com/request"), delay: 0.1, http(200))
let request = URLRequest(url: URL(string: "https://relative.com/request")!)

service.execute(request, with: MockedSerializer(), retry: {}, completion: { _ in })
service.execute(request, with: MockedSerializer(), retryCount: 0, retry: {}, completion: { _ in })
expect(loggerOne.didTriggerStartRequest).toNot(beNil())
expect(loggerTwo.didTriggerStartRequest).toNot(beNil())
}
Expand All @@ -48,7 +48,7 @@ class NetworkServiceSpec: QuickSpec {
let request = URLRequest(url: URL(string: "https://relative.com/request")!)

waitUntil { done in
service.execute(request, with: MockedSerializer(), retry: {}, completion: { _ in
service.execute(request, with: MockedSerializer(), retryCount: 0, retry: {}, completion: { _ in
done()
})
}
Expand All @@ -70,7 +70,7 @@ class NetworkServiceSpec: QuickSpec {
service.interceptor = interceptor

waitUntil { done in
service.execute(one, with: MockedSerializer(), retry: {}, completion: { _ in
service.execute(one, with: MockedSerializer(), retryCount: 0, retry: {}, completion: { _ in
done()
})
}
Expand All @@ -88,7 +88,7 @@ class NetworkServiceSpec: QuickSpec {
service.interceptor = interceptor

waitUntil { done in
service.execute(one, with: MockedSerializer(), retry: {
service.execute(one, with: MockedSerializer(), retryCount: 0, retry: {
done()
}, completion: { _ in })
}
Expand All @@ -102,7 +102,10 @@ class NetworkServiceSpec: QuickSpec {

waitUntil { done in
DispatchQueue.main.async {
service.execute(request, with: MockedSerializer(), retry: {}, completion: { _ in
service.execute(request,
with: MockedSerializer(),
retryCount: 0,
retry: {}, completion: { _ in
expect(Thread.isMainThread) == true
done()
})
Expand All @@ -116,7 +119,11 @@ class NetworkServiceSpec: QuickSpec {

waitUntil { done in
DispatchQueue.global(qos: .utility).async {
service.execute(request, with: MockedSerializer(), retry: {}, completion: { _ in
service.execute(request,
with: MockedSerializer(),
retryCount: 0,
retry: {},
completion: { _ in
expect(Thread.isMainThread) == false
done()
})
Expand Down
29 changes: 29 additions & 0 deletions Example/Tests/Specs/Service/ServiceSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ class ServiceSpec: QuickSpec {
done()
}
}
expect(interceptor.didReceiveRetryCount) == 0
}

it("should retry a request with the new headers") {
Expand All @@ -126,6 +127,34 @@ class ServiceSpec: QuickSpec {
done()
}
}
expect(interceptor.didReceiveRetryCount) == 0
}

it("should retry a request with the new headers and have a retry count of one") {
self.stub(http(.get, uri: "https://relative.com/request"), http(401))
let request = MockedRequest(url: URL(string: "request"))

let interceptor = MockedInterceptor()
var count: Int = 0
interceptor.interceptHandle = { error, retry in
count += 1
configuration.headers = ["Some": "Header"]
if count > 1 {
// Make sure the second try also fails.
self.stub(http(.get, uri: "https://relative.com/request"), http(200))
}
DispatchQueue.global().asyncAfter(deadline: .now() + 0.1, execute: retry)
return true
}
service.interceptor = interceptor

waitUntil { done in
service.execute(request, with: MockedSerializer()) { _ in
expect(logger.didTriggerStartRequest?.allHTTPHeaderFields?["Some"]) == "Header"
done()
}
}
expect(interceptor.didReceiveRetryCount) == 1
}
}

Expand Down
3 changes: 2 additions & 1 deletion Sources/Configuration/Interceptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ public protocol Interceptor {
///
/// - parameter error: The error that triggers the interceptor.
/// - parameter data: The body's data object if available.
/// - parameter retryCount: The number of times the same request has been retried.
/// - parameter retry: The block you should trigger to retry the failed request.
///
/// - returns: Return if you want the response processing to be intercepted so that
/// the normal flow (with completion handler) is stopped.
func intercept(_ error: ResponseError, data: Data?, retry: @escaping () -> Void) -> Bool
func intercept(_ error: ResponseError, data: Data?, retryCount: UInt, retry: @escaping () -> Void) -> Bool
}
3 changes: 2 additions & 1 deletion Sources/Service/NetworkService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class NetworkService: NSObject {
@discardableResult
func execute<S: Serializer>(_ urlRequest: URLRequest,
with serializer: S,
retryCount: UInt,
retry: @escaping () -> Void,
completion: @escaping (_ response: S.Response) -> Void) -> URLSessionDataTask {
// Get the originating queue.
Expand All @@ -41,7 +42,7 @@ class NetworkService: NSObject {
if
let responseError = urlResponse?.responseError,
let interceptor = self?.interceptor,
interceptor.intercept(responseError, data: data, retry: retry) {
interceptor.intercept(responseError, data: data, retryCount: retryCount, retry: retry) {
return
}

Expand Down
12 changes: 10 additions & 2 deletions Sources/Service/Service.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,19 @@ open class Service {
public func execute<S: Serializer>(_ request: Request,
with serializer: S,
completion: @escaping (_ response: S.Response) -> Void) -> URLSessionDataTask? {
return execute(request, with: serializer, retryCount: 0, completion: completion)
}

/// This private function is used just to keep track of the retry count of the current request.
private func execute<S: Serializer>(_ request: Request,
with serializer: S,
retryCount: UInt,
completion: @escaping (_ response: S.Response) -> Void) -> URLSessionDataTask? {
do {
// Create the request.
let urlRequest = try request.makeURLRequest(with: configuration)
return networkService.execute(urlRequest, with: serializer, retry: { [weak self] in
self?.execute(request, with: serializer, completion: completion)
return networkService.execute(urlRequest, with: serializer, retryCount: retryCount, retry: { [weak self] in
self?.execute(request, with: serializer, retryCount: retryCount + 1, completion: completion)
}, completion: completion)
} catch {
let response = serializer.serialize(data: nil, error: error, response: nil)
Expand Down

0 comments on commit e595108

Please sign in to comment.