Minor re-factoring for delegate and tests

This commit is contained in:
Mikhail Churbanov 2018-06-15 22:11:24 +03:00
parent 5a2160ef16
commit eb402cfb33
4 changed files with 63 additions and 119 deletions

View File

@ -6,7 +6,7 @@
// Copyright © 2018 CocoaPods. All rights reserved. // Copyright © 2018 CocoaPods. All rights reserved.
// //
import ProxyResolver @testable import ProxyResolver
typealias ProxyConfigDict = [CFString: AnyObject] typealias ProxyConfigDict = [CFString: AnyObject]
@ -27,12 +27,7 @@ class MockProxyConfigProvider: ProxyConfigProvider {
class MockProxyUrlFetcher: ProxyScriptFether { class MockProxyUrlFetcher: ProxyScriptFether {
func fetch(request: URLRequest, completion: @escaping (String?, Error?) -> Void) { func fetch(request: URLRequest, completion: @escaping (String?, Error?) -> Void) {
let contents = """ completion(TestConfigs.autoConfig.scriptContents, nil)
function FindProxyForURL(url, host) {
return "PROXY \(TestConfigs.autoConfig.host):\(TestConfigs.autoConfig.port)";
}
""".trimmingCharacters(in: .whitespacesAndNewlines)
completion(contents, nil)
} }
} }
@ -53,17 +48,15 @@ enum TestConfigs {
static let scriptUrl = "https://autoconf.server.com" static let scriptUrl = "https://autoconf.server.com"
static let scriptContents = """ static let scriptContents = """
function FindProxyForURL(url, host) { function FindProxyForURL(url, host) {
return "PROXY \(autoConfig.host):\(autoConfig.port)"; return "PROXY \(autoConfig.httpProxy.host):\(autoConfig.httpProxy.port)";
} }
""" """
static let host = "auto-http.proxy.com" static let httpProxy = Proxy(type: .http, host: "auto-http.proxy.com", port: 8000)
static let port = 8000 static let httpsProxy = Proxy(type: .https, host: "auto-https.proxy.com", port: 8001)
static let urlConfig = [ static let urlConfig = [
[kCFProxyTypeKey: kCFProxyTypeAutoConfigurationURL, [kCFProxyTypeKey: kCFProxyTypeAutoConfigurationURL,
kCFProxyAutoConfigurationURLKey: scriptUrl as AnyObject] kCFProxyAutoConfigurationURLKey: scriptUrl as AnyObject]
] ]
static let scriptConfig = [ static let scriptConfig = [
[kCFProxyTypeKey: kCFProxyTypeAutoConfigurationJavaScript, [kCFProxyTypeKey: kCFProxyTypeAutoConfigurationJavaScript,
kCFProxyAutoConfigurationJavaScriptKey: scriptContents as AnyObject] kCFProxyAutoConfigurationJavaScriptKey: scriptContents as AnyObject]
@ -71,37 +64,41 @@ enum TestConfigs {
} }
enum http { enum http {
static let host = "http.proxy.com" static let proxy = Proxy(type: .http, host: "http.proxy.com", port: 8080)
static let port = 8080
static let config = [ static let config = [
[kCFProxyTypeKey: kCFProxyTypeHTTP, [kCFProxyTypeKey: kCFProxyTypeHTTP,
kCFProxyHostNameKey: host as AnyObject, kCFProxyHostNameKey: proxy.host as AnyObject,
kCFProxyPortNumberKey: port as AnyObject] kCFProxyPortNumberKey: proxy.port as AnyObject]
] ]
} }
enum https { enum https {
static let host = "http.proxy.com" static let proxy = Proxy(type: .https, host: "https.proxy.com", port: 8081)
static let port = 8081
static let config = [ static let config = [
[kCFProxyTypeKey: kCFProxyTypeHTTPS, [kCFProxyTypeKey: kCFProxyTypeHTTPS,
kCFProxyHostNameKey: host as AnyObject, kCFProxyHostNameKey: proxy.host as AnyObject,
kCFProxyPortNumberKey: port as AnyObject] kCFProxyPortNumberKey: proxy.port as AnyObject]
] ]
} }
enum socks { enum socks {
static let host = "socks.proxy.com" static let proxy = Proxy(type: .socks, host: "socks", port: 8082)
static let port = 8082
static let config = [ static let config = [
[kCFProxyTypeKey: kCFProxyTypeSOCKS, [kCFProxyTypeKey: kCFProxyTypeSOCKS,
kCFProxyHostNameKey: host as AnyObject, kCFProxyHostNameKey: proxy.host as AnyObject,
kCFProxyPortNumberKey: port as AnyObject] kCFProxyPortNumberKey: proxy.port as AnyObject]
] ]
} }
// swiftlint:enable type_name // swiftlint:enable type_name
} }
extension ProxyResolutionResult {
func isSameSuccessfull(as other: ProxyResolutionResult) -> Bool {
switch (self, other) {
case (.direct, .direct): return true
case let (.proxy(lproxy), .proxy(rproxy)): return lproxy == rproxy
default: return false
}
}
}

View File

@ -14,31 +14,21 @@ class TestDelegate: ProxyResolverDelegate {
var didStopExpectation: XCTestExpectation? var didStopExpectation: XCTestExpectation?
var didResolveExpectation: XCTestExpectation? var didResolveExpectation: XCTestExpectation?
var resolveNext: ((Bool) -> Void)?
var resolveUrl: URL? var resolveUrl: URL?
var resolveResult: ProxyResolutionResult? var resolveResult: ProxyResolutionResult?
var stopUrl: URL? var resolveNextRoutine: ResolveNextRoutine?
var stopError: Error?
func proxyResolver(_ proxyResolver: ProxyResolver, didFinish url: URL, with error: Error?) { func proxyResolver(_ proxyResolver: ProxyResolver, didResolve result: ProxyResolutionResult, for url: URL,
stopUrl = url resolveNext: ResolveNextRoutine?) {
stopError = error
didStopExpectation?.fulfill()
}
func proxyResolver(_ proxyResolver: ProxyResolver, didResolve url: URL, with result: ProxyResolutionResult,
shouldResolveNext: @escaping (Bool) -> Void) {
resolveUrl = url resolveUrl = url
resolveResult = result resolveResult = result
resolveNext = shouldResolveNext resolveNextRoutine = resolveNext
didResolveExpectation?.fulfill() didResolveExpectation?.fulfill()
} }
func clearResults() { func clearResults() {
resolveUrl = nil resolveUrl = nil
resolveResult = nil resolveResult = nil
stopUrl = nil
stopError = nil
} }
} }
@ -89,9 +79,9 @@ class DelegateTests: XCTestCase {
default: default:
break break
} }
XCTAssertNotNil(testDelegate.resolveNext) XCTAssertNotNil(testDelegate.resolveNextRoutine)
testDelegate.resolveNext!(true) testDelegate.resolveNextRoutine!()
wait(for: [resolveExpectation], timeout: TestConfigs.timeout) wait(for: [resolveExpectation], timeout: TestConfigs.timeout)
XCTAssertNotNil(testDelegate.resolveUrl) XCTAssertNotNil(testDelegate.resolveUrl)
XCTAssert(testDelegate.resolveUrl! == TestConfigs.httpUrl) XCTAssert(testDelegate.resolveUrl! == TestConfigs.httpUrl)
@ -103,12 +93,6 @@ class DelegateTests: XCTestCase {
default: default:
break break
} }
testDelegate.resolveNext!(true)
wait(for: [stopExpectation], timeout: TestConfigs.timeout)
XCTAssertNotNil(testDelegate.stopUrl)
XCTAssert(testDelegate.stopUrl! == TestConfigs.httpUrl)
XCTAssertNil(testDelegate.stopError)
} }
} }

View File

@ -23,17 +23,11 @@ class Tests: XCTestCase {
func testNoProxyResolve() { func testNoProxyResolve() {
let expectation = XCTestExpectation(description: "Completion called") let expectation = XCTestExpectation(description: "Completion called")
let expectedResult = ProxyResolutionResult.direct
testConfigProvider.setTestConfig(TestConfigs.noProxy.config) testConfigProvider.setTestConfig(TestConfigs.noProxy.config)
proxy.resolve(for: TestConfigs.httpUrl) { result in proxy.resolve(for: TestConfigs.httpUrl) { result in
switch result { XCTAssert(result.isSameSuccessfull(as: expectedResult))
case .direct:
XCTAssert(true)
case .proxy(let proxy):
XCTAssert(false, "Incorrect proxy connection resolved: \(proxy)")
case .error(let error):
XCTFail(error.localizedDescription)
}
expectation.fulfill() expectation.fulfill()
} }
wait(for: [expectation], timeout: TestConfigs.timeout) wait(for: [expectation], timeout: TestConfigs.timeout)
@ -41,19 +35,11 @@ class Tests: XCTestCase {
func testAutoConfigurationUrlResolve() { func testAutoConfigurationUrlResolve() {
let expectation = XCTestExpectation(description: "Completion called") let expectation = XCTestExpectation(description: "Completion called")
let expectedResult = ProxyResolutionResult.proxy(TestConfigs.autoConfig.httpProxy)
testConfigProvider.setTestConfig(TestConfigs.autoConfig.urlConfig) testConfigProvider.setTestConfig(TestConfigs.autoConfig.urlConfig)
proxy.resolve(for: TestConfigs.httpUrl) { result in proxy.resolve(for: TestConfigs.httpUrl) { result in
switch result { XCTAssert(result.isSameSuccessfull(as: expectedResult))
case .direct:
XCTAssert(false, "Incorrect direct connection resolved")
case .proxy(let proxy):
XCTAssert(proxy.type == .http)
XCTAssert(proxy.host == TestConfigs.autoConfig.host)
XCTAssert(proxy.port == TestConfigs.autoConfig.port)
case .error(let error):
XCTFail(error.localizedDescription)
}
expectation.fulfill() expectation.fulfill()
} }
wait(for: [expectation], timeout: TestConfigs.timeout) wait(for: [expectation], timeout: TestConfigs.timeout)
@ -61,19 +47,11 @@ class Tests: XCTestCase {
func testAutoConfigurationScriptResolve() { func testAutoConfigurationScriptResolve() {
let expectation = XCTestExpectation(description: "Completion called") let expectation = XCTestExpectation(description: "Completion called")
let expectedResult = ProxyResolutionResult.proxy(TestConfigs.autoConfig.httpProxy)
testConfigProvider.setTestConfig(TestConfigs.autoConfig.scriptConfig) testConfigProvider.setTestConfig(TestConfigs.autoConfig.scriptConfig)
proxy.resolve(for: TestConfigs.httpUrl) { result in proxy.resolve(for: TestConfigs.httpUrl) { result in
switch result { XCTAssert(result.isSameSuccessfull(as: expectedResult))
case .direct:
XCTAssert(false, "Incorrect direct connection resolved")
case .proxy(let proxy):
XCTAssert(proxy.type == .http)
XCTAssert(proxy.host == TestConfigs.autoConfig.host)
XCTAssert(proxy.port == TestConfigs.autoConfig.port)
case .error(let error):
XCTFail(error.localizedDescription)
}
expectation.fulfill() expectation.fulfill()
} }
wait(for: [expectation], timeout: TestConfigs.timeout) wait(for: [expectation], timeout: TestConfigs.timeout)
@ -81,19 +59,11 @@ class Tests: XCTestCase {
func testHttpResolve() { func testHttpResolve() {
let expectation = XCTestExpectation(description: "Completion called") let expectation = XCTestExpectation(description: "Completion called")
let expectedResult = ProxyResolutionResult.proxy(TestConfigs.http.proxy)
testConfigProvider.setTestConfig(TestConfigs.http.config) testConfigProvider.setTestConfig(TestConfigs.http.config)
proxy.resolve(for: TestConfigs.httpUrl) { result in proxy.resolve(for: TestConfigs.httpUrl) { result in
switch result { XCTAssert(result.isSameSuccessfull(as: expectedResult))
case .direct:
XCTAssert(false, "Incorrect direct connection resolved")
case .proxy(let proxy):
XCTAssert(proxy.type == .http)
XCTAssert(proxy.host == TestConfigs.http.host)
XCTAssert(proxy.port == TestConfigs.http.port)
case .error(let error):
XCTFail(error.localizedDescription)
}
expectation.fulfill() expectation.fulfill()
} }
wait(for: [expectation], timeout: TestConfigs.timeout) wait(for: [expectation], timeout: TestConfigs.timeout)
@ -101,19 +71,11 @@ class Tests: XCTestCase {
func testHttpsResolve() { func testHttpsResolve() {
let expectation = XCTestExpectation(description: "Completion called") let expectation = XCTestExpectation(description: "Completion called")
let expectedResult = ProxyResolutionResult.proxy(TestConfigs.https.proxy)
testConfigProvider.setTestConfig(TestConfigs.https.config) testConfigProvider.setTestConfig(TestConfigs.https.config)
proxy.resolve(for: TestConfigs.httpUrl) { result in proxy.resolve(for: TestConfigs.httpUrl) { result in
switch result { XCTAssert(result.isSameSuccessfull(as: expectedResult))
case .direct:
XCTAssert(false, "Incorrect direct connection resolved")
case .proxy(let proxy):
XCTAssert(proxy.type == .https)
XCTAssert(proxy.host == TestConfigs.https.host)
XCTAssert(proxy.port == TestConfigs.https.port)
case .error(let error):
XCTFail(error.localizedDescription)
}
expectation.fulfill() expectation.fulfill()
} }
wait(for: [expectation], timeout: TestConfigs.timeout) wait(for: [expectation], timeout: TestConfigs.timeout)
@ -121,19 +83,11 @@ class Tests: XCTestCase {
func testSocksResolve() { func testSocksResolve() {
let expectation = XCTestExpectation(description: "Completion called") let expectation = XCTestExpectation(description: "Completion called")
let expectedResult = ProxyResolutionResult.proxy(TestConfigs.socks.proxy)
testConfigProvider.setTestConfig(TestConfigs.socks.config) testConfigProvider.setTestConfig(TestConfigs.socks.config)
proxy.resolve(for: TestConfigs.httpUrl) { result in proxy.resolve(for: TestConfigs.httpUrl) { result in
switch result { XCTAssert(result.isSameSuccessfull(as: expectedResult))
case .direct:
XCTAssert(false, "Incorrect direct connection resolved")
case .proxy(let proxy):
XCTAssert(proxy.type == .socks)
XCTAssert(proxy.host == TestConfigs.socks.host)
XCTAssert(proxy.port == TestConfigs.socks.port)
case .error(let error):
XCTFail(error.localizedDescription)
}
expectation.fulfill() expectation.fulfill()
} }
wait(for: [expectation], timeout: TestConfigs.timeout) wait(for: [expectation], timeout: TestConfigs.timeout)

View File

@ -31,6 +31,13 @@ public struct Proxy {
} }
} }
// TODO: Swift 4.2 should have it auto-generated
extension Proxy: Equatable {
public static func == (lhs: Proxy, rhs: Proxy) -> Bool {
return lhs.type == rhs.type && lhs.host == rhs.host && lhs.port == rhs.port
}
}
public enum ProxyResolutionResult { public enum ProxyResolutionResult {
case direct case direct
case proxy(Proxy) case proxy(Proxy)
@ -74,10 +81,11 @@ public final class ProxyResolverConfig {
// MARK: - ProxyResolverDelegate protocol // MARK: - ProxyResolverDelegate protocol
public typealias ResolveNextRoutine = () -> Void
public protocol ProxyResolverDelegate: class { public protocol ProxyResolverDelegate: class {
func proxyResolver(_ proxyResolver: ProxyResolver, didFinish url: URL, with error: Error?) func proxyResolver(_ proxyResolver: ProxyResolver, didResolve result: ProxyResolutionResult, for url: URL,
func proxyResolver(_ proxyResolver: ProxyResolver, didResolve url: URL, with result: ProxyResolutionResult, resolveNext: ResolveNextRoutine?)
shouldResolveNext: @escaping (Bool) -> Void)
} }
// MARK: - ProxyResolver class // MARK: - ProxyResolver class
@ -129,23 +137,24 @@ public final class ProxyResolver {
!proxiesConfig.isEmpty !proxiesConfig.isEmpty
else { else {
let error = ProxyResolutionError.unexpectedError(nil) let error = ProxyResolutionError.unexpectedError(nil)
self.delegate?.proxyResolver(self, didFinish: url, with: error) let result = ProxyResolutionResult.error(error)
self.delegate?.proxyResolver(self,
didResolve: result,
for: url,
resolveNext: nil)
return return
} }
var resolveCompletion: ((ProxyResolutionResult) -> Void)! var resolveCompletion: ((ProxyResolutionResult) -> Void)!
let shouldResolveNextCallback: (Bool) -> Void = { shouldResolve in let resolveNextRoutine: ResolveNextRoutine = {
guard shouldResolve, !proxiesConfig.isEmpty else { guard !proxiesConfig.isEmpty else { return }
self.delegate?.proxyResolver(self, didFinish: url, with: nil)
return
}
self.resolveProxy(from: proxiesConfig.removeFirst(), for: normalizedUrl, completion: resolveCompletion) self.resolveProxy(from: proxiesConfig.removeFirst(), for: normalizedUrl, completion: resolveCompletion)
} }
resolveCompletion = { result in resolveCompletion = { result in
self.delegate?.proxyResolver(self, self.delegate?.proxyResolver(self,
didResolve: url, didResolve: result,
with: result, for: url,
shouldResolveNext: shouldResolveNextCallback) resolveNext: resolveNextRoutine)
} }
resolveProxy(from: proxiesConfig.removeFirst(), for: normalizedUrl, completion: resolveCompletion) resolveProxy(from: proxiesConfig.removeFirst(), for: normalizedUrl, completion: resolveCompletion)
} }