Skip to content

Commit 4be8990

Browse files
committed
Fix network errors treated as “Internal error”
This patch fixes a bug that would cause all network related errors (such as when the user is offline) as opaque `OhMyAuthError.internalError`, which prevents the appropriate error handling to be done in clients. The problem was that the logic dealing with responses was first checking if a valid `HTTPURLResponse` was received before checking the error. This patch simply flips the order of those two operations. Tests have also been implemented for `NetworkRequestable`.
1 parent dc34e41 commit 4be8990

File tree

4 files changed

+75
-8
lines changed

4 files changed

+75
-8
lines changed

OhMyAuth.xcodeproj/project.pbxproj

+6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
5255FEBC1FB457FA004D012B /* NetworkRequestableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5255FEBB1FB457FA004D012B /* NetworkRequestableTests.swift */; };
11+
5255FEBD1FB457FA004D012B /* NetworkRequestableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5255FEBB1FB457FA004D012B /* NetworkRequestableTests.swift */; };
1012
922A1E591DC28A680088A7E7 /* Networking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 922A1E581DC28A680088A7E7 /* Networking.swift */; };
1113
922A1E5A1DC28A680088A7E7 /* Networking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 922A1E581DC28A680088A7E7 /* Networking.swift */; };
1214
923CA22C1DC144290016B791 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 923CA22B1DC144290016B791 /* Utils.swift */; };
@@ -76,6 +78,7 @@
7678
/* End PBXContainerItemProxy section */
7779

7880
/* Begin PBXFileReference section */
81+
5255FEBB1FB457FA004D012B /* NetworkRequestableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkRequestableTests.swift; sourceTree = "<group>"; };
7982
922A1E581DC28A680088A7E7 /* Networking.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Networking.swift; sourceTree = "<group>"; };
8083
923CA22B1DC144290016B791 /* Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = "<group>"; };
8184
D20836161EF7D0A8004ED8E0 /* Keychains.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Keychains.framework; path = Carthage/Build/iOS/Keychains.framework; sourceTree = "<group>"; };
@@ -308,6 +311,7 @@
308311
D5ED737D1C64B1E4003772EF /* Info-Mac.plist */,
309312
D2DD2AB31DEEFF2900AFF5BA /* LockerTests.swift */,
310313
D20A12A41E769648000DB14C /* ServiceTests.swift */,
314+
5255FEBB1FB457FA004D012B /* NetworkRequestableTests.swift */,
311315
);
312316
path = OhMyAuthTests;
313317
sourceTree = "<group>";
@@ -553,6 +557,7 @@
553557
files = (
554558
D2DD2AB41DEEFF2900AFF5BA /* LockerTests.swift in Sources */,
555559
D20A12A51E769648000DB14C /* ServiceTests.swift in Sources */,
560+
5255FEBC1FB457FA004D012B /* NetworkRequestableTests.swift in Sources */,
556561
);
557562
runOnlyForDeploymentPostprocessing = 0;
558563
};
@@ -588,6 +593,7 @@
588593
files = (
589594
D2DD2AB51DEEFF2900AFF5BA /* LockerTests.swift in Sources */,
590595
D20A12A61E769648000DB14C /* ServiceTests.swift in Sources */,
596+
5255FEBD1FB457FA004D012B /* NetworkRequestableTests.swift in Sources */,
591597
);
592598
runOnlyForDeploymentPostprocessing = 0;
593599
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import Foundation
2+
import XCTest
3+
@testable import OhMyAuth
4+
5+
final class NetworkRequestableTests: XCTestCase {
6+
func testSuccessfulResult() throws {
7+
let networking = NetworkingMock(configuration: .default)
8+
networking.data = try JSONSerialization.data(withJSONObject: [:], options: [])
9+
networking.response = HTTPURLResponse()
10+
11+
var result: Result<Any>?
12+
let request = RequestMock()
13+
request.start(using: networking) { result = $0 }
14+
15+
switch result {
16+
case .some(.success(let object)):
17+
// Since we get an untyped object from the API, we need to use reflection for verification
18+
XCTAssertEqual(String(reflecting: object), String(reflecting: [:]))
19+
default:
20+
XCTFail("Unexpected result: \(String(describing: result))")
21+
}
22+
}
23+
24+
func testOfflineErrorReturnedAsResult() {
25+
let networking = NetworkingMock(configuration: .default)
26+
networking.error = NSError(
27+
domain: NSURLErrorDomain,
28+
code: URLError.notConnectedToInternet.rawValue,
29+
userInfo: nil
30+
)
31+
32+
var result: Result<Any>?
33+
let request = RequestMock()
34+
request.start(using: networking) { result = $0 }
35+
36+
switch result {
37+
case .some(.failure(let error as NSError)):
38+
XCTAssertEqual(error.code, URLError.notConnectedToInternet.rawValue)
39+
default:
40+
XCTFail("Unexpected result: \(String(describing: result))")
41+
}
42+
}
43+
}
44+
45+
private extension NetworkRequestableTests {
46+
struct RequestMock: NetworkRequestable {
47+
let url = URL(string: "https://www.hyper.no")!
48+
let parameters = [String: Any]()
49+
let headers = [String: String]()
50+
}
51+
52+
class NetworkingMock: Networking {
53+
var data: Data?
54+
var response: URLResponse?
55+
var error: Error?
56+
57+
override func post(url: URL, parameters: [String : Any], headers: [String : String], completion: @escaping ((Data?, URLResponse?, Error?) -> Void)) {
58+
completion(data, response, error)
59+
}
60+
}
61+
}

Sources/Shared/Networking/Networking.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ open class Networking {
77
session = URLSession(configuration: configuration, delegate: nil, delegateQueue: OperationQueue.main)
88
}
99

10-
public func post(url: URL, parameters: [String: Any], headers: [String: String], completion: @escaping ((Data?, URLResponse?, Error?) -> Void)) {
10+
open func post(url: URL, parameters: [String: Any], headers: [String: String], completion: @escaping ((Data?, URLResponse?, Error?) -> Void)) {
1111
var request = URLRequest(url: url)
1212

1313
headers.forEach { (key, value) in

Sources/Shared/Protocols/NetworkRequestable.swift

+7-7
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,8 @@ protocol NetworkRequestable {
88

99
extension NetworkRequestable {
1010

11-
func start(_ completion: @escaping (_ result: Result<Any>) -> Void) {
12-
AuthConfig.networking.post(url: url, parameters: parameters, headers: headers) { (data, response, error) in
13-
guard let response = response as? HTTPURLResponse else {
14-
completion(Result.failure(OhMyAuthError.internalError.toNSError()))
15-
return
16-
}
17-
11+
func start(using networking: Networking = AuthConfig.networking, completion: @escaping (_ result: Result<Any>) -> Void) {
12+
networking.post(url: url, parameters: parameters, headers: headers) { (data, response, error) in
1813
guard error == nil
1914
else {
2015
if let error = error {
@@ -25,6 +20,11 @@ extension NetworkRequestable {
2520

2621
return
2722
}
23+
24+
guard let response = response as? HTTPURLResponse else {
25+
completion(Result.failure(OhMyAuthError.internalError.toNSError()))
26+
return
27+
}
2828

2929
guard let data = data,
3030
let jsonObject = try? JSONSerialization.jsonObject(with: data, options: .allowFragments),

0 commit comments

Comments
 (0)