diff --git a/SignalServiceKit/src/Network/WebSockets/HTTP+OWS.swift b/SignalServiceKit/src/Network/WebSockets/HTTP+OWS.swift index a925b88e18..6e5eb0d6ca 100644 --- a/SignalServiceKit/src/Network/WebSockets/HTTP+OWS.swift +++ b/SignalServiceKit/src/Network/WebSockets/HTTP+OWS.swift @@ -58,8 +58,6 @@ public enum OWSHTTPError: Error, IsRetryableProvider { case invalidRequest(requestUrl: URL) // Request failed without a response from the service. case networkFailure(requestUrl: URL) - // Request failed without a response from the service. - case other(requestUrl: URL) // Request failed with a response from the service. case serviceResponse(serviceResponse: HTTPErrorServiceResponse) @@ -110,11 +108,20 @@ public enum OWSHTTPError: Error, IsRetryableProvider { if isNetworkConnectivityError { return true } - // TODO: We might eventually special-case 413 Rate Limited errors. - let responseStatus = self.responseStatusCode - // TODO: What about 5xx? - if responseStatus >= 400, responseStatus <= 499 { + switch self { + case .invalidAppState, .invalidRequest: return false + case .networkFailure: + return true + case .serviceResponse: + // TODO: We might eventually special-case 413 Rate Limited errors. + let responseStatus = self.responseStatusCode + // TODO: What about 5xx? + if responseStatus >= 400, responseStatus <= 499 { + return false + } else { + return true + } } return true } @@ -132,8 +139,6 @@ extension OWSHTTPError: HTTPError { return requestUrl case .networkFailure(let requestUrl): return requestUrl - case .other(let requestUrl): - return requestUrl case .serviceResponse(let serviceResponse): return serviceResponse.requestUrl } @@ -142,7 +147,7 @@ extension OWSHTTPError: HTTPError { // NOTE: This function should only be called from NetworkManager.swiftHTTPStatusCodeForError. public var responseStatusCode: Int { switch self { - case .invalidAppState, .invalidRequest, .networkFailure, .other: + case .invalidAppState, .invalidRequest, .networkFailure: return 0 case .serviceResponse(let serviceResponse): return Int(serviceResponse.responseStatus) @@ -151,7 +156,7 @@ extension OWSHTTPError: HTTPError { public var responseHeaders: OWSHttpHeaders? { switch self { - case .invalidAppState, .invalidRequest, .networkFailure, .other: + case .invalidAppState, .invalidRequest, .networkFailure: return nil case .serviceResponse(let serviceResponse): return serviceResponse.responseHeaders @@ -160,7 +165,7 @@ extension OWSHTTPError: HTTPError { public var responseError: Error? { switch self { - case .invalidAppState, .invalidRequest, .networkFailure, .other: + case .invalidAppState, .invalidRequest, .networkFailure: return nil case .serviceResponse(let serviceResponse): return serviceResponse.responseError @@ -169,7 +174,7 @@ extension OWSHTTPError: HTTPError { public var responseBodyData: Data? { switch self { - case .invalidAppState, .invalidRequest, .networkFailure, .other: + case .invalidAppState, .invalidRequest, .networkFailure: return nil case .serviceResponse(let serviceResponse): return serviceResponse.responseData @@ -183,7 +188,7 @@ extension OWSHTTPError: HTTPError { } switch self { - case .invalidAppState, .invalidRequest, .networkFailure, .other: + case .invalidAppState, .invalidRequest, .networkFailure: return nil case .serviceResponse(let serviceResponse): return serviceResponse.customRetryAfterDate @@ -192,7 +197,7 @@ extension OWSHTTPError: HTTPError { public var customLocalizedDescription: String? { switch self { - case .invalidAppState, .invalidRequest, .networkFailure, .other: + case .invalidAppState, .invalidRequest, .networkFailure: return nil case .serviceResponse(let serviceResponse): return serviceResponse.customLocalizedDescription @@ -201,7 +206,7 @@ extension OWSHTTPError: HTTPError { public var customLocalizedRecoverySuggestion: String? { switch self { - case .invalidAppState, .invalidRequest, .networkFailure, .other: + case .invalidAppState, .invalidRequest, .networkFailure: return nil case .serviceResponse(let serviceResponse): return serviceResponse.customLocalizedRecoverySuggestion @@ -217,8 +222,6 @@ extension OWSHTTPError: HTTPError { return false case .networkFailure: return true - case .other: - return false case .serviceResponse: if 0 == self.responseStatusCode { // statusCode should now be nil, not zero, in this diff --git a/SignalServiceKit/src/Network/WebSockets/OWSWebSocket.swift b/SignalServiceKit/src/Network/WebSockets/OWSWebSocket.swift index 56b93783d9..efa2bbd145 100644 --- a/SignalServiceKit/src/Network/WebSockets/OWSWebSocket.swift +++ b/SignalServiceKit/src/Network/WebSockets/OWSWebSocket.swift @@ -17,7 +17,7 @@ extension OWSWebSocket { guard let requestUrl = request.url else { owsFail("Missing requestUrl.") } - let error = OWSHTTPError.other(requestUrl: requestUrl) + let error = OWSHTTPError.invalidAppState(requestUrl: requestUrl) let failure = OWSHTTPErrorWrapper(error: error) failureParam(failure) } @@ -261,18 +261,6 @@ public class SocketMessageInfo: NSObject { // didFail(status: 0, headers: OWSHttpHeaders(), error: error, bodyData: nil) } - @objc - public func didFailForOtherReasons() { - let error = OWSHTTPError.other(requestUrl: requestUrl) - // TODO: Set retry. - didFail(error: error) - // TODO: copy. - // let errorMessage = NSLocalizedString("ERROR_DESCRIPTION_REQUEST_FAILED", - // comment: "Error indicating that a socket request failed.") - // let error = OWSErrorWithCodeDescription(.messageRequestFailed, errorMessage) - // didFail(status: 0, headers: OWSHttpHeaders(), error: error, bodyData: nil) - } - @objc public func didFailDueToNetwork() { let error = OWSHTTPError.networkFailure(requestUrl: requestUrl) diff --git a/SignalServiceKit/tests/Util/OWSErrorTest.swift b/SignalServiceKit/tests/Util/OWSErrorTest.swift index 6a674640a8..d97714a154 100644 --- a/SignalServiceKit/tests/Util/OWSErrorTest.swift +++ b/SignalServiceKit/tests/Util/OWSErrorTest.swift @@ -18,306 +18,38 @@ class OWSErrorTest: SSKBaseTestSwift { let errorGeneric = OWSGenericError("Yipes!") let error1 = OWSHTTPError.invalidRequest(requestUrl: URL(string: "https://google.com/")!) let error2 = OWSHTTPError.networkFailure(requestUrl: URL(string: "https://google.com/")!) + let error3 = OWSUnretryableError() + let error4 = OWSRetryableError() XCTAssertFalse(errorFooBar.hasIsRetryable) XCTAssertTrue(errorFooBar.isRetryable) XCTAssertFalse(errorFooBar.shouldBeIgnoredForGroups) - XCTAssertFalse(errorFooBar.isFatal) - XCTAssertEqual(errorFooBar.localizedDescription, NSError.localizedDescriptionDefault) - XCTAssertNotNil(errorFooBar.localizedRecoverySuggestion) + XCTAssertFalse(errorFooBar.isFatalError) XCTAssertTrue(errorGeneric.hasIsRetryable) XCTAssertFalse(errorGeneric.isRetryable) XCTAssertFalse(errorGeneric.shouldBeIgnoredForGroups) - XCTAssertFalse(errorGeneric.isFatal) - XCTAssertEqual(errorGeneric.localizedDescription, NSError.localizedDescriptionDefault) - XCTAssertNotNil(errorGeneric.localizedRecoverySuggestion) - XCTAssertEqual(errorGeneric.nsDomain, "SignalCoreKit.OWSGenericError") + XCTAssertFalse(errorGeneric.isFatalError) XCTAssertTrue(error1.hasIsRetryable) XCTAssertFalse(error1.isRetryable) XCTAssertFalse(error1.shouldBeIgnoredForGroups) - XCTAssertFalse(error1.isFatal) - XCTAssertEqual(error1.localizedDescription, NSError.localizedDescriptionDefault) - XCTAssertNotNil(error1.localizedRecoverySuggestion) - XCTAssertEqual(error1.nsDomain, "SignalServiceKit." + OWSHTTPError.errorDomain) + XCTAssertFalse(error1.isFatalError) XCTAssertTrue(error2.hasIsRetryable) XCTAssertTrue(error2.isRetryable) XCTAssertFalse(error2.shouldBeIgnoredForGroups) - XCTAssertFalse(error2.isFatal) - XCTAssertEqual(error2.localizedDescription, NSError.localizedDescriptionDefault) - // XCTAssertNotNil(error2.localizedDescription) - XCTAssertNotNil(error2.localizedRecoverySuggestion) - XCTAssertEqual(error1.nsDomain, "SignalServiceKit." + OWSHTTPError.errorDomain) - } + XCTAssertFalse(error2.isFatalError) - func testAssociatedStrings() { - enum FooError: Error { - case bar - } - var key: UInt8 = 0 - let value1: String = "a" - let value2: String = "b" - let value3: String = "c" - - let error0 = FooError.bar - XCTAssertNil((error0 as NSError).ows_getAssociatedString(&key)) - - (error0 as NSError).ows_setAssociatedString(&key, value: value1) - XCTAssertNil((error0 as NSError).ows_getAssociatedString(&key)) - - let error1: Error = error0 - XCTAssertNil((error0 as NSError).ows_getAssociatedString(&key)) - XCTAssertNil((error1 as NSError).ows_getAssociatedString(&key)) - - (error1 as NSError).ows_setAssociatedString(&key, value: value1) - XCTAssertNil((error0 as NSError).ows_getAssociatedString(&key)) - XCTAssertEqual((error1 as NSError).ows_getAssociatedString(&key), value1) - let error2: NSError = error1 as NSError - XCTAssertNil((error0 as NSError).ows_getAssociatedString(&key)) - XCTAssertEqual((error1 as NSError).ows_getAssociatedString(&key), value1) - XCTAssertEqual(error2.ows_getAssociatedString(&key), value1) - - error2.ows_setAssociatedString(&key, value: value2) - XCTAssertNil((error0 as NSError).ows_getAssociatedString(&key)) - XCTAssertEqual((error1 as NSError).ows_getAssociatedString(&key), value2) - XCTAssertEqual(error2.ows_getAssociatedString(&key), value2) - let error3: Error = error2 as Error - XCTAssertNil((error0 as NSError).ows_getAssociatedString(&key)) - XCTAssertEqual((error1 as NSError).ows_getAssociatedString(&key), value2) - XCTAssertEqual(error2.ows_getAssociatedString(&key), value2) - XCTAssertEqual((error3 as NSError).ows_getAssociatedString(&key), value2) - let error4: NSError = error3 as NSError - let error5: Error = error4 as Error - XCTAssertNil((error0 as NSError).ows_getAssociatedString(&key)) - XCTAssertEqual((error1 as NSError).ows_getAssociatedString(&key), value2) - XCTAssertEqual(error2.ows_getAssociatedString(&key), value2) - XCTAssertEqual((error3 as NSError).ows_getAssociatedString(&key), value2) - XCTAssertEqual(error4.ows_getAssociatedString(&key), value2) - XCTAssertEqual((error5 as NSError).ows_getAssociatedString(&key), value2) - - (error5 as NSError).ows_setAssociatedString(&key, value: value3) - XCTAssertNil((error0 as NSError).ows_getAssociatedString(&key)) - XCTAssertEqual((error1 as NSError).ows_getAssociatedString(&key), value3) - XCTAssertEqual(error2.ows_getAssociatedString(&key), value3) - XCTAssertEqual((error3 as NSError).ows_getAssociatedString(&key), value3) - XCTAssertEqual(error4.ows_getAssociatedString(&key), value3) - XCTAssertEqual((error5 as NSError).ows_getAssociatedString(&key), value3) - } - - func testAssociatedNSNumber() { - enum FooError: Error { - case bar - } - var key: UInt8 = 0 - let value1: NSNumber = NSNumber(value: true) - let value2: NSNumber = NSNumber(value: false) - let value3: NSNumber = NSNumber(value: UInt64(3)) - - let error0 = FooError.bar - XCTAssertNil((error0 as NSError).ows_getAssociatedNSNumber(&key)) - - (error0 as NSError).ows_setAssociatedNSNumber(&key, value: value1) - XCTAssertNil((error0 as NSError).ows_getAssociatedNSNumber(&key)) - - let error1: Error = error0 - XCTAssertNil((error0 as NSError).ows_getAssociatedNSNumber(&key)) - XCTAssertNil((error1 as NSError).ows_getAssociatedNSNumber(&key)) - - (error1 as NSError).ows_setAssociatedNSNumber(&key, value: value1) - XCTAssertNil((error0 as NSError).ows_getAssociatedNSNumber(&key)) - XCTAssertEqual((error1 as NSError).ows_getAssociatedNSNumber(&key), value1) - let error2: NSError = error1 as NSError - XCTAssertNil((error0 as NSError).ows_getAssociatedNSNumber(&key)) - XCTAssertEqual((error1 as NSError).ows_getAssociatedNSNumber(&key), value1) - XCTAssertEqual(error2.ows_getAssociatedNSNumber(&key), value1) - - error2.ows_setAssociatedNSNumber(&key, value: value2) - XCTAssertNil((error0 as NSError).ows_getAssociatedNSNumber(&key)) - XCTAssertEqual((error1 as NSError).ows_getAssociatedNSNumber(&key), value2) - XCTAssertEqual(error2.ows_getAssociatedNSNumber(&key), value2) - let error3: Error = error2 as Error - XCTAssertNil((error0 as NSError).ows_getAssociatedNSNumber(&key)) - XCTAssertEqual((error1 as NSError).ows_getAssociatedNSNumber(&key), value2) - XCTAssertEqual(error2.ows_getAssociatedNSNumber(&key), value2) - XCTAssertEqual((error3 as NSError).ows_getAssociatedNSNumber(&key), value2) - let error4: NSError = error3 as NSError - let error5: Error = error4 as Error - XCTAssertNil((error0 as NSError).ows_getAssociatedNSNumber(&key)) - XCTAssertEqual((error1 as NSError).ows_getAssociatedNSNumber(&key), value2) - XCTAssertEqual(error2.ows_getAssociatedNSNumber(&key), value2) - XCTAssertEqual((error3 as NSError).ows_getAssociatedNSNumber(&key), value2) - XCTAssertEqual(error4.ows_getAssociatedNSNumber(&key), value2) - XCTAssertEqual((error5 as NSError).ows_getAssociatedNSNumber(&key), value2) - - (error5 as NSError).ows_setAssociatedNSNumber(&key, value: value3) - XCTAssertNil((error0 as NSError).ows_getAssociatedNSNumber(&key)) - XCTAssertEqual((error1 as NSError).ows_getAssociatedNSNumber(&key), value3) - XCTAssertEqual(error2.ows_getAssociatedNSNumber(&key), value3) - XCTAssertEqual((error3 as NSError).ows_getAssociatedNSNumber(&key), value3) - XCTAssertEqual(error4.ows_getAssociatedNSNumber(&key), value3) - XCTAssertEqual((error5 as NSError).ows_getAssociatedNSNumber(&key), value3) - - // error.obj - // - // fileprivate func ows_getAssociatedNSNumber(_ key: UnsafeRawPointer) -> NSNumber? { - // ows_getAssociatedObject(key) - // } - // - // fileprivate func ows_getAssociatedObject(_ key: UnsafeRawPointer) -> T? { - // if let rawValue = objc_getAssociatedObject(self, key) { - // if let value = rawValue as? T { - // return value - // } else { - // owsFailDebug("Invalid value: \(type(of: rawValue))") - // } - // } - // return nil - // } - // - // fileprivate func ows_setAssociatedObject(_ key: UnsafeRawPointer, - // _ value: Any?, - // _ policy: objc_AssociationPolicy = .OBJC_ASSOCIATION_COPY) { - // objc_setAssociatedObjec - // - // if let rawValue = objc_getAssociatedObject(self, &kErrorKey_IsRetryable) { - } - - func testIsRetryable() { - enum FooError: Error { - case bar - } - - let error1: Error = FooError.bar - - XCTAssertFalse(error1.hasIsRetryable) - XCTAssertTrue(error1.isRetryable) - - let error2: Error = error1.with(isRetryable: false) - - Logger.verbose("---- error1: \(error1)") - Logger.verbose("---- error1: \((error1 as NSError).userInfo)") - Logger.verbose("---- error2: \(error2)") - Logger.verbose("---- error2: \((error2 as NSError).userInfo)") - Logger.flush() - - XCTAssertFalse(error1.hasIsRetryable) - XCTAssertTrue(error1.isRetryable) - XCTAssertTrue(error2.hasIsRetryable) - XCTAssertFalse(error2.isRetryable) - - let error3 = error2.with(isRetryable: true) - - XCTAssertFalse(error1.hasIsRetryable) - XCTAssertTrue(error1.isRetryable) - XCTAssertTrue(error2.hasIsRetryable) - XCTAssertFalse(error2.isRetryable) XCTAssertTrue(error3.hasIsRetryable) - XCTAssertTrue(error3.isRetryable) + XCTAssertFalse(error3.isRetryable) + XCTAssertFalse(error3.shouldBeIgnoredForGroups) + XCTAssertFalse(error3.isFatalError) - XCTAssertFalse((error1 as NSError) === (error1 as NSError)) - XCTAssertTrue((error2 as NSError) === (error2 as NSError)) - XCTAssertTrue((error3 as NSError) === (error3 as NSError)) - XCTAssertFalse((error1 as NSError) === (error2 as NSError)) - XCTAssertFalse((error1 as NSError) === (error3 as NSError)) - XCTAssertFalse((error2 as NSError) === (error3 as NSError)) - XCTAssertNotEqual((error2 as NSError).debugPointerName, (error1 as NSError).debugPointerName) - XCTAssertEqual((error2 as NSError).debugPointerName, (error3 as NSError).debugPointerName) - - // XCTAssertTrue(errorGeneric.hasIsRetryable) - // XCTAssertFalse(errorGeneric.isRetryable) - // XCTAssertFalse(errorGeneric.shouldBeIgnoredForGroups) - // XCTAssertFalse(errorGeneric.isFatal) - // XCTAssertEqual(errorGeneric.localizedDescription, NSError.localizedDescriptionDefault) - // XCTAssertNotNil(errorGeneric.localizedRecoverySuggestion) - // XCTAssertEqual(errorGeneric.nsDomain, "SignalCoreKit.OWSGenericError") - // - // XCTAssertTrue(error1.hasIsRetryable) - // XCTAssertFalse(error1.isRetryable) - // XCTAssertFalse(error1.shouldBeIgnoredForGroups) - // XCTAssertFalse(error1.isFatal) - // XCTAssertEqual(error1.localizedDescription, NSError.localizedDescriptionDefault) - // XCTAssertNotNil(error1.localizedRecoverySuggestion) - // XCTAssertEqual(error1.nsDomain, "SignalServiceKit." + OWSHTTPError.errorDomain) - // - // XCTAssertTrue(error2.hasIsRetryable) - // XCTAssertTrue(error2.isRetryable) - // XCTAssertFalse(error2.shouldBeIgnoredForGroups) - // XCTAssertFalse(error2.isFatal) - // XCTAssertEqual(error2.localizedDescription, NSError.localizedDescriptionDefault) - // XCTAssertNotNil(error2.localizedRecoverySuggestion) - // XCTAssertEqual(error1.nsDomain, "SignalServiceKit." + OWSHTTPError.errorDomain) - - let error1a = error1.with(isRetryable: true) - - // public var hasIsRetryable: Bool { (self as NSError).hasIsRetryableImpl } - // - // public var isRetryable: Bool { (self as NSError).isRetryableImpl } - // public func with(isRetryable: Bool) -> Error { - // let error = self as NSError - // error.isRetryableImpl = isRetryable - // return error - // } - // - // public var shouldBeIgnoredForGroups: Bool { (self as NSError).shouldBeIgnoredForGroupsImpl } - // public func with(shouldBeIgnoredForGroups: Bool) -> Error { - // let error = self as NSError - // error.shouldBeIgnoredForGroupsImpl = shouldBeIgnoredForGroups - // return error - // } - // - // public var isFatal: Bool { (self as NSError).isFatalImpl } - // public func with(isFatal: Bool) -> Error { - // let error = self as NSError - // error.isFatalImpl = isFatal - // return error - // } - // - // // TODO: - // // public var localizedDescription: String { (self as NSError).localizedDescriptionImpl } - // public func with(localizedDescription: String) -> Error { - // let error = self as NSError - // error.localizedDescriptionImpl = localizedDescription - // return error - // } - // - // // TODO: - // public var localizedRecoverySuggestion: String { (self as NSError).localizedRecoverySuggestionImpl } - // public func with(localizedRecoverySuggestion: String) -> Error { - // let error = self as NSError - // error.localizedRecoverySuggestionImpl = localizedRecoverySuggestion - // return error - // } - // - // public var nsDomain: String { (self as NSError).domain } - // public var nsCode: Int { (self as NSError).code } - // - // // /// NSError bridging: the domain of the error. - // // /// :nodoc: - // // public static var errorDomain: String { - // // return "GRDB.DatabaseError" - // // } - // // - // // /// NSError bridging: the error code within the given domain. - // // /// :nodoc: - // // public var errorCode: Int { - // // return Int(extendedResultCode.rawValue) - // // } - // - // /// NSError bridging: the user-info dictionary. - // /// :nodoc: - // public var errorUserInfo: [String: Any] { - // var result = [String: Any]() - // // TODO: - // // if let responseError = self.responseError { - // // result[NSUnderlyingErrorKey] = responseError - // // } - // result[NSLocalizedDescriptionKey] = (self as NSError).localizedDescriptionImpl - // result[NSLocalizedRecoverySuggestionErrorKey] = (self as NSError).localizedRecoverySuggestionImpl - // return result - // } - // } + XCTAssertTrue(error4.hasIsRetryable) + XCTAssertTrue(error4.isRetryable) + XCTAssertFalse(error4.shouldBeIgnoredForGroups) + XCTAssertFalse(error4.isFatalError) } }