Skip to content

Commit 6a05e3c

Browse files
authored
Merge pull request #41 from RxSwiftCommunity/customSessionDelegate
Allow to pass custom session delegate
2 parents 94c64a7 + e3a0ee3 commit 6a05e3c

11 files changed

+98
-37
lines changed

RxHttpClient.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
6E42A8C41DEA2EA8003687E3 /* (null) in Sources */ = {isa = PBXBuildFile; };
2222
6E4823B11DECAF1900F1A8DC /* (null) in Sources */ = {isa = PBXBuildFile; };
2323
6E4823B41DECBD1B00F1A8DC /* MimeType+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E4823B31DECBD1B00F1A8DC /* MimeType+Extensions.swift */; };
24+
6E5331E921FC6ABC000F2AA8 /* CustomSessionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E5331E821FC6ABC000F2AA8 /* CustomSessionDelegate.swift */; };
2425
6E556B591D57447A00E43388 /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6E556B581D57447A00E43388 /* RxSwift.framework */; };
2526
6E5B3CEE1D2D3C8400775D9F /* NSURLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E5B3CED1D2D3C8400775D9F /* NSURLTests.swift */; };
2627
6E5B3CF01D2D43C000775D9F /* MimeTypeConverterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E5B3CEF1D2D43C000775D9F /* MimeTypeConverterTests.swift */; };
@@ -63,6 +64,7 @@
6364
6E190F8C1DECC320002BA10F /* HttpRequestFileSystemCacheProviderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HttpRequestFileSystemCacheProviderTests.swift; sourceTree = "<group>"; };
6465
6E1C07C11D48FF92009513FD /* HttpClientType+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "HttpClientType+Extensions.swift"; sourceTree = "<group>"; };
6566
6E4823B31DECBD1B00F1A8DC /* MimeType+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MimeType+Extensions.swift"; sourceTree = "<group>"; };
67+
6E5331E821FC6ABC000F2AA8 /* CustomSessionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomSessionDelegate.swift; sourceTree = "<group>"; };
6668
6E556B581D57447A00E43388 /* RxSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxSwift.framework; path = Carthage/Build/iOS/RxSwift.framework; sourceTree = "<group>"; };
6769
6E5B3CE71D2D1F7400775D9F /* HttpClientBasicTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = HttpClientBasicTests.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
6870
6E5B3CEB1D2D32F900775D9F /* NSURLSessionTypeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = NSURLSessionTypeTests.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
@@ -182,6 +184,7 @@
182184
6E9AADF01E3CC47A00CCAB8F /* RequestPluginTests.swift */,
183185
6E9AADF71E3D017A00CCAB8F /* ActivityIndicatorPluginTests.swift */,
184186
6EFB9EC91D2A4E2600E30A5D /* Info.plist */,
187+
6E5331E821FC6ABC000F2AA8 /* CustomSessionDelegate.swift */,
185188
);
186189
path = RxHttpClientTests;
187190
sourceTree = "<group>";
@@ -353,6 +356,7 @@
353356
6E5B3CF01D2D43C000775D9F /* MimeTypeConverterTests.swift in Sources */,
354357
6E190F8E1DECC320002BA10F /* HttpRequestFileSystemCacheProviderTests.swift in Sources */,
355358
6E9AADF81E3D017A00CCAB8F /* ActivityIndicatorPluginTests.swift in Sources */,
359+
6E5331E921FC6ABC000F2AA8 /* CustomSessionDelegate.swift in Sources */,
356360
6EFB9EFE1D2A5C8E00E30A5D /* Fake.swift in Sources */,
357361
6ED185511DC7AE1C0071BD4D /* URLRequestTests.swift in Sources */,
358362
);

RxHttpClient/HttpClient.swift

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ public final class HttpClient {
66
internal let dataTaskScheduler = SerialDispatchQueueScheduler(qos: .utility, internalSerialQueueName: "com.RxHttpClient.HttpClient.DataTask")
77
/// Default concurrent scheduler for observing observable sequence created by loadStreamData method
88
internal let streamDataObservingScheduler = SerialDispatchQueueScheduler(qos: .utility, internalSerialQueueName: "com.RxHttpClient.HttpClient.Stream")
9-
internal let sessionObserver = NSURLSessionDataEventsObserver()
9+
internal let sessionObserver: NSURLSessionDataEventsObserverType
1010
internal let urlSession: URLSessionType
1111

1212
public let urlRequestCacheProvider: UrlRequestCacheProviderType?
@@ -18,10 +18,15 @@ public final class HttpClient {
1818
- parameter sessionConfiguration: NSURLSessionConfiguration that will be used to create NSURLSession
1919
(this session will be canceled while deiniting of HttpClient)
2020
- parameter urlRequestCacheProvider: Cache provider that will be used for caching requests
21+
- parameter requestPlugin: Plugin for HttpClient
22+
- parameter sessionDelegate: Delegate for UrlSession
2123
*/
2224
public init(sessionConfiguration: URLSessionConfiguration = URLSessionConfiguration.default,
2325
urlRequestCacheProvider: UrlRequestCacheProviderType? = nil,
24-
requestPlugin: RequestPluginType? = nil) {
26+
requestPlugin: RequestPluginType? = nil,
27+
sessionDelegate: NSURLSessionDataEventsObserverType = NSURLSessionDataEventsObserver()) {
28+
29+
self.sessionObserver = sessionDelegate
2530
urlSession = URLSession(configuration: sessionConfiguration,
2631
delegate: self.sessionObserver,
2732
delegateQueue: nil)
@@ -32,10 +37,12 @@ public final class HttpClient {
3237
/// Initializer for unit tests only
3338
internal init(session urlSession: URLSessionType,
3439
urlRequestCacheProvider: UrlRequestCacheProviderType? = nil,
35-
requestPlugin: RequestPluginType? = nil) {
40+
requestPlugin: RequestPluginType? = nil,
41+
sessionDelegate: NSURLSessionDataEventsObserverType = NSURLSessionDataEventsObserver()) {
3642
self.urlSession = urlSession
3743
self.urlRequestCacheProvider = urlRequestCacheProvider
3844
self.requestPlugin = requestPlugin
45+
self.sessionObserver = sessionDelegate
3946
}
4047

4148
deinit {

RxHttpClient/HttpExtensions.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import Foundation
22

3-
protocol URLSessionTaskType {
3+
public protocol URLSessionTaskType {
44
func isEqual(_ object: Any?) -> Bool
55
var state: URLSessionTask.State { get }
66
}
77
extension URLSessionTask : URLSessionTaskType { }
88

99
// URLSessionDataTaskType
10-
protocol URLSessionDataTaskType : URLSessionTaskType {
10+
public protocol URLSessionDataTaskType : URLSessionTaskType {
1111
func resume()
1212
func cancel()
1313
var originalRequest: URLRequest? { get }
@@ -16,13 +16,13 @@ extension URLSessionDataTask : URLSessionDataTaskType { }
1616

1717
// URLSessionType
1818
public typealias DataTaskResult = (Data?, URLResponse?, NSError?) -> Void
19-
protocol URLSessionType {
19+
public protocol URLSessionType {
2020
var configuration: URLSessionConfiguration { get }
2121
func finishTasksAndInvalidate()
2222
func dataTaskWithRequest(_ request: URLRequest) -> URLSessionDataTaskType
2323
}
2424
extension URLSession : URLSessionType {
25-
func dataTaskWithRequest(_ request: URLRequest) -> URLSessionDataTaskType {
25+
public func dataTaskWithRequest(_ request: URLRequest) -> URLSessionDataTaskType {
2626
return dataTask(with: request) as URLSessionDataTask
2727
}
2828
}
Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,45 @@
11
import Foundation
22
import RxSwift
33

4-
enum SessionDataEvents {
4+
public enum SessionDataEvents {
55
case didReceiveResponse(session: URLSessionType, dataTask: URLSessionDataTaskType, response: URLResponse,
66
completion: (URLSession.ResponseDisposition) -> Void)
77
case didReceiveData(session: URLSessionType, dataTask: URLSessionDataTaskType, data: Data)
88
case didCompleteWithError(session: URLSessionType, dataTask: URLSessionTaskType, error: Error?)
99
case didBecomeInvalidWithError(session: URLSessionType, error: Error?)
1010
}
1111

12-
protocol NSURLSessionDataEventsObserverType {
12+
public protocol NSURLSessionDataEventsObserverType: URLSessionDataDelegate {
1313
var sessionEvents: Observable<SessionDataEvents> { get }
1414
}
1515

16-
extension NSURLSessionDataEventsObserver : NSURLSessionDataEventsObserverType {
17-
var sessionEvents: Observable<SessionDataEvents> {
18-
return sessionEventsSubject
19-
}
16+
open class NSURLSessionDataEventsObserver: NSObject {
17+
public let sessionEventsSubject = PublishSubject<SessionDataEvents>()
2018
}
2119

22-
final class NSURLSessionDataEventsObserver : NSObject {
23-
internal let sessionEventsSubject = PublishSubject<SessionDataEvents>()
20+
extension NSURLSessionDataEventsObserver: NSURLSessionDataEventsObserverType {
21+
public var sessionEvents: Observable<SessionDataEvents> {
22+
return sessionEventsSubject
23+
}
2424
}
2525

26-
extension NSURLSessionDataEventsObserver : URLSessionDataDelegate {
27-
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse,
26+
extension NSURLSessionDataEventsObserver: URLSessionDataDelegate {
27+
open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse,
2828
completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
2929
sessionEventsSubject.onNext(.didReceiveResponse(session: session, dataTask: dataTask, response: response, completion: completionHandler))
3030
}
3131

32-
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
32+
open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
3333
sessionEventsSubject.onNext(.didReceiveData(session: session, dataTask: dataTask, data: data))
3434
}
3535
}
3636
extension NSURLSessionDataEventsObserver : URLSessionDelegate {
37-
func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) {
37+
open func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) {
3838
sessionEventsSubject.onNext(.didBecomeInvalidWithError(session: session, error: error))
3939
}
4040
}
4141
extension NSURLSessionDataEventsObserver : URLSessionTaskDelegate {
42-
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
42+
open func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
4343
sessionEventsSubject.onNext(.didCompleteWithError(session: session, dataTask: task, error: error))
4444
}
4545
}

RxHttpClientTests/ActivityIndicatorPluginTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ class ActivityIndicatorPluginTests: XCTestCase {
4040
let completion: (URLSession.ResponseDisposition) -> () = { _ in }
4141
DispatchQueue.global(qos: DispatchQoS.QoSClass.utility).async {
4242
switch task.originalRequest!.url!.absoluteString {
43-
case "https://test.com/post1": client.sessionObserver.sessionEventsSubject.onNext(.didReceiveResponse(session: session, dataTask: task, response: fakeResponse1, completion: completion))
44-
case "https://test.com/post2": client.sessionObserver.sessionEventsSubject.onNext(.didReceiveResponse(session: session, dataTask: task, response: fakeResponse2, completion: completion))
43+
case "https://test.com/post1": client.sessionDelegate.sessionEventsSubject.onNext(.didReceiveResponse(session: session, dataTask: task, response: fakeResponse1, completion: completion))
44+
case "https://test.com/post2": client.sessionDelegate.sessionEventsSubject.onNext(.didReceiveResponse(session: session, dataTask: task, response: fakeResponse2, completion: completion))
4545
default: break
4646
}
4747
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//
2+
// CustomSessionDelegate.swift
3+
// RxHttpClientTests
4+
//
5+
// Created by Anton Efimenko on 26/01/2019.
6+
// Copyright © 2019 RxSwiftCommunity. All rights reserved.
7+
//
8+
9+
import XCTest
10+
import RxHttpClient
11+
import RxSwift
12+
import OHHTTPStubs
13+
14+
class AlwaysFail: NSURLSessionDataEventsObserver {
15+
override func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
16+
// response with static statusCode
17+
let response = HTTPURLResponse(url: response.url!, statusCode: 500, httpVersion: nil, headerFields: nil)!
18+
sessionEventsSubject.onNext(.didReceiveResponse(session: session, dataTask: dataTask, response: response, completion: completionHandler))
19+
}
20+
}
21+
22+
class CustomSessionDelegate: XCTestCase {
23+
func testOwerrideResponse() {
24+
let sendData = "testData".data(using: String.Encoding.utf8)!
25+
let _ = stub(condition: { $0.url?.absoluteString == "https://test.com/json" && $0.httpMethod == HttpMethod.get.rawValue }) { _ in
26+
return OHHTTPStubsResponse(data: sendData, statusCode: 200, headers: nil)
27+
}
28+
29+
let client = HttpClient(sessionConfiguration: .default, sessionDelegate: AlwaysFail())
30+
let url = URL(baseUrl: "https://test.com/json", parameters: nil)!
31+
let bag = DisposeBag()
32+
33+
let expectation = self.expectation(description: "Should return error")
34+
35+
client.requestData(url: url).subscribe(onNext: { _ in XCTFail("Should not emit data") }, onError: { result in
36+
guard case let HttpClientError.invalidResponse(response, data) = result else { return }
37+
XCTAssertEqual(response.statusCode, 500, "Check correct status code")
38+
XCTAssertEqual(true, data == sendData, "Check received data is still correct")
39+
expectation.fulfill()
40+
}).disposed(by: bag)
41+
42+
waitForExpectations(timeout: 1, handler: nil)
43+
}
44+
}

RxHttpClientTests/Fake.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@ import Foundation
22
@testable import RxHttpClient
33
import RxSwift
44

5+
extension HttpClient {
6+
var sessionDelegate: NSURLSessionDataEventsObserver {
7+
return self.sessionObserver as! NSURLSessionDataEventsObserver
8+
}
9+
}
10+
511
class FakeDataTask : NSObject, URLSessionDataTaskType {
612
var originalRequest: URLRequest?
713
var isCancelled = false

RxHttpClientTests/HttpClientBasicTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ class HttpClientBasicTests: XCTestCase {
272272
let client = HttpClient(session: session)
273273

274274
session.task = FakeDataTask(resumeClosure: { _ in
275-
client.sessionObserver.sessionEventsSubject.onNext(.didBecomeInvalidWithError(session: session, error: NSError(domain: "Test", code: 123, userInfo: nil)))
275+
client.sessionDelegate.sessionEventsSubject.onNext(.didBecomeInvalidWithError(session: session, error: NSError(domain: "Test", code: 123, userInfo: nil)))
276276
})
277277

278278
let url = URL(baseUrl: "https://test.com/json", parameters: nil)!

RxHttpClientTests/HttpClientSendTests.swift

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,14 @@ class HttpClientSendTests: XCTestCase {
3434
task.originalRequest!.allHTTPHeaderFields?["Header1"] == "HeaderVal1",
3535
task.originalRequest!.httpBody?.elementsEqual(sendData) ?? false else {
3636

37-
client.sessionObserver.sessionEventsSubject.onNext(.didCompleteWithError(session: session,
37+
client.sessionDelegate.sessionEventsSubject.onNext(.didCompleteWithError(session: session,
3838
dataTask: task,
3939
error: NSError(domain: "HttpRequestTests", code: 1, userInfo: nil)))
4040

4141
return
4242
}
4343

44-
client.sessionObserver.sessionEventsSubject.onNext(.didCompleteWithError(session: session,
44+
client.sessionDelegate.sessionEventsSubject.onNext(.didCompleteWithError(session: session,
4545
dataTask: task,
4646
error: nil))
4747
}
@@ -72,14 +72,14 @@ class HttpClientSendTests: XCTestCase {
7272
task.originalRequest!.allHTTPHeaderFields?["Header1"] == "HeaderVal1",
7373
task.originalRequest!.httpBody?.elementsEqual(sendJsonData) ?? false else {
7474

75-
client.sessionObserver.sessionEventsSubject.onNext(.didCompleteWithError(session: session,
75+
client.sessionDelegate.sessionEventsSubject.onNext(.didCompleteWithError(session: session,
7676
dataTask: task,
7777
error: NSError(domain: "HttpRequestTests", code: 1, userInfo: nil)))
7878

7979
return
8080
}
8181

82-
client.sessionObserver.sessionEventsSubject.onNext(.didCompleteWithError(session: session,
82+
client.sessionDelegate.sessionEventsSubject.onNext(.didCompleteWithError(session: session,
8383
dataTask: task,
8484
error: nil))
8585
}
@@ -109,20 +109,20 @@ class HttpClientSendTests: XCTestCase {
109109
task.originalRequest!.httpMethod == HttpMethod.patch.rawValue,
110110
task.originalRequest!.allHTTPHeaderFields?["Header1"] == "HeaderVal1",
111111
task.originalRequest!.httpBody?.elementsEqual(sendJsonData) ?? false else {
112-
client.sessionObserver.sessionEventsSubject.onNext(.didCompleteWithError(session: session,
112+
client.sessionDelegate.sessionEventsSubject.onNext(.didCompleteWithError(session: session,
113113
dataTask: task,
114114
error: NSError(domain: "HttpRequestTests", code: 1, userInfo: nil)))
115115

116116
return
117117
}
118118

119-
client.sessionObserver.sessionEventsSubject.onNext(
119+
client.sessionDelegate.sessionEventsSubject.onNext(
120120
SessionDataEvents.didReceiveResponse(session: session,
121121
dataTask: task,
122122
response: URLResponse(url: task.originalRequest!.url!, mimeType: "Application/json", expectedContentLength: 26, textEncodingName: nil),
123123
completion: { _ in }))
124-
client.sessionObserver.sessionEventsSubject.onNext(.didReceiveData(session: session, dataTask: task, data: sendJsonData))
125-
client.sessionObserver.sessionEventsSubject.onNext(.didCompleteWithError(session: session,
124+
client.sessionDelegate.sessionEventsSubject.onNext(.didReceiveData(session: session, dataTask: task, data: sendJsonData))
125+
client.sessionDelegate.sessionEventsSubject.onNext(.didCompleteWithError(session: session,
126126
dataTask: task,
127127
error: nil))
128128
}
@@ -152,14 +152,14 @@ class HttpClientSendTests: XCTestCase {
152152
task.originalRequest!.httpMethod == HttpMethod.patch.rawValue,
153153
task.originalRequest!.allHTTPHeaderFields?["Header1"] == "HeaderVal1",
154154
task.originalRequest!.httpBody?.elementsEqual(sendJsonData) ?? false else {
155-
client.sessionObserver.sessionEventsSubject.onNext(.didCompleteWithError(session: session,
155+
client.sessionDelegate.sessionEventsSubject.onNext(.didCompleteWithError(session: session,
156156
dataTask: task,
157157
error: NSError(domain: "HttpRequestTests", code: 1, userInfo: nil)))
158158

159159
return
160160
}
161161

162-
client.sessionObserver.sessionEventsSubject.onNext(.didCompleteWithError(session: session,
162+
client.sessionDelegate.sessionEventsSubject.onNext(.didCompleteWithError(session: session,
163163
dataTask: task,
164164
error: nil))
165165
}

RxHttpClientTests/MemoryCacheProviderTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class MemoryCacheProviderTests: XCTestCase {
3838
DispatchQueue.global(qos: DispatchQoS.QoSClass.utility).async { [unowned self] in
3939
for event in fakeUrlEvents {
4040
// send events to session observer (simulates NSURLSession behavior)
41-
self.httpClient.sessionObserver.sessionEventsSubject.onNext(event)
41+
self.httpClient.sessionDelegate.sessionEventsSubject.onNext(event)
4242
// simulate delay
4343
Thread.sleep(forTimeInterval: 0.005)
4444
}

0 commit comments

Comments
 (0)