Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Critical error handling and presentation #367

Merged
merged 3 commits into from
Jan 12, 2017
Merged

Conversation

cocojoe
Copy link
Member

@cocojoe cocojoe commented Jan 10, 2017

Added Error support to CDNLoader callback
Added ConnectionError Presenter/View
Added Option to disable full screen critical errors
Added ConnectionError Route
Updated CDNLoader callback tests
Added Tests for new Presenter/View

Added ConnectionError Presenter/View
Added Option to disable full screen critical errors
Added ConnectionError Route
Updated CDNLoader callback tests
Added Tests for new Presenter/View
@cocojoe cocojoe requested a review from hzalaz January 10, 2017 17:12
func load(_ callback: @escaping (Connections?) -> ()) {
func load(_ callback: @escaping (Connections?, RemoteConnectionLoaderError?) -> ()) {
let sessionConfiguration = URLSessionConfiguration.default
sessionConfiguration.timeoutIntervalForRequest = 30 // Default 60
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why the change?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh yeah should have mentioned, I added it for testing but 60 is a LONG time and we did mention timeout tweaking. Happy to remove if you feel it is too short?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use the default, probably we can inject the session to the interactor in some way

guard error == nil else {
self.logger.error("Failed to load with error \(error!)")
callback(nil)
if let error = error, error._code == NSURLErrorTimedOut {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might rewrite this whole error handling like

guard error?._code != NSURLErrorTimedOut else { return callback(.connectionTimeout) }
guard error == nil else { return callback(.requestIssue) }

@@ -54,12 +62,15 @@ struct CDNLoaderInteractor: RemoteConnectionLoader, Loggable {
}
guard 200...299 ~= response.statusCode else {
self.logger.error("HTTP response was not successful. HTTP \(response.statusCode) <\(payload ?? "No Body")>")
return callback(nil)
if response.statusCode == 403 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not have a guard before this one? (or an if) like

guard response.statusCode != 403 else { return callback(nil, RemoteConnectionLoaderError.invalidClient) }

}

guard var jsonp = payload else {
self.logger.error("HTTP response had no jsonp \(payload ?? "No Body")")
return callback(nil)
return callback(nil, RemoteConnectionLoaderError.invalidClientInfo)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can omit the class name here

@@ -93,10 +104,14 @@ struct CDNLoaderInteractor: RemoteConnectionLoader, Loggable {
info.oauth2.forEach { strategy in
strategy.connections.forEach { connections.social(name: $0.name, style: AuthStyle.style(forStrategy: strategy.name, connectionName: $0.name)) }
}
callback(connections)
if connections.isEmpty {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use guard?


import Foundation

enum RemoteConnectionLoaderError: Error, LocalizableError {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a unrecoverable error enum with some of this errors already

case invalidClient
case invalidClientInfo
case noConnections
case requestIssue
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see this one and the next have no message so why have a different case?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to distinguish the error from the ones we care about, from the users perspective they will show connectionTimeout message. However, they are not technically the same thing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what I mean we can merge them and said just request failed since at this point we discarded network or client issues so it only is that the server is unavailable


enum RemoteConnectionLoaderError: Error, LocalizableError {
case connectionTimeout
case invalidClient
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one and the next are exactly the same thing from user perspective

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It depends on the circumstance, invalidClientInfo could be a temp issue as your credentials are valid but for whatever reason the response isn't right.
invalidClient is more a developer one really, saying you're credentials are invalid based upon the 403. Although again technically could be a temp server issue.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But for the developer is the same thing (check your clientid and try again) and the end user is even simpler. If we need more debug info or fine grained errors for it the developer can use the log or even debug it


import Foundation

class ConnectionErrorPresenter: Presentable, Loggable {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make this presenter (and views) generic like UnrecoverableErrorPresenter or similar so we can reuse

var localizableMessage: String {
switch self {
case .invalidClient:
return "No client information found, please check your Auth0 client credentials.".i18n(key: "com.auth0.lock.critical.credentials", comment: "Invalid client credentials")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use the prefix com.auth0.lock.error and maybe unrecoverable too

@cocojoe
Copy link
Member Author

cocojoe commented Jan 11, 2017

I've unified the errors into UnrecoverableError. However there is an annoying issue due to equitability. We have

Route: Equatable

https://github.com/auth0/Lock.iOS-OSX/blob/feature_critical_errors/Lock/Routes.swift#L74

This is a requirement due to one line of code in Lock:

https://github.com/auth0/Lock.iOS-OSX/blob/feature_critical_errors/Lock/Router.swift#L170

Now because UniversalError will now contain an enum case with a value.

case invalidOptions(cause: String)

It will also need to be made equatable to satisfy as the errors are of type UniversalError

case (.connectionError(let lhsError), .connectionError(let rhsError)):
        return lhsError == rhsError

Rather than having having two custom equatable enums and two equatable unit tests (both need to be maintained for any additions). Could we remove all of this and simply satisfy the original requirement in enum Route?

var isRoot: Bool {
    switch self {
    case .root:
        return true
    default:
        return false
    }
}

UPDATE: Actually there are a few genuine requirements in LockTests for Route Equatable. I've made UniversalError: Equatable for now.

Soft errors now default, option removed.
Added more tests, updated existing tests
General code style improvements
@cocojoe cocojoe force-pushed the feature_critical_errors branch from 952c1b0 to 5b9fefe Compare January 11, 2017 14:48
@cocojoe
Copy link
Member Author

cocojoe commented Jan 11, 2017

simulator screen shot 11 jan 2017 11 24 48
simulator screen shot 11 jan 2017 11 25 14
simulator screen shot 11 jan 2017 11 25 54

var localizableMessage: String {
switch self {
case .invalidClientOrDomain:
return "No client information found, please check your Auth0 client credentials.".i18n(key: "com.auth0.lock.error.invalidclient", comment: "Invalid client")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add to the prefix com.auth0.lock.error an extra part like unrecoverable for all keys of unrecoverable error

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also move this error to the requestIssue case

case .invalidClientOrDomain:
return "No client information found, please check your Auth0 client credentials.".i18n(key: "com.auth0.lock.error.invalidclient", comment: "Invalid client")
case .clientWithNoConnections:
return "No connections available for this client, please check your Auth0 client setup.".i18n(key: "com.auth0.lock.error.noconnections", comment: "No client connections")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No authentication methods found for this client. Please check your client setup.

case .clientWithNoConnections:
return "No connections available for this client, please check your Auth0 client setup.".i18n(key: "com.auth0.lock.error.noconnections", comment: "No client connections")
case .connectionTimeout, .requestIssue:
return "There was a problem with your request, please try again later.".i18n(key: "com.auth0.lock.error.requestfailed", comment: "Generic request failure")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


var userVisible: Bool {
switch self {
case .missingDatabaseConnection, .invalidOptions:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also invalidClientOrDomain

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make all visible, those who were previously non visible we should show the message https://github.com/auth0/lock/blob/master/src/i18n/en.js#L97

return "No connections available for this client, please check your Auth0 client setup.".i18n(key: "com.auth0.lock.error.noconnections", comment: "No client connections")
case .connectionTimeout, .requestIssue:
return "There was a problem with your request, please try again later.".i18n(key: "com.auth0.lock.error.requestfailed", comment: "Generic request failure")
case .missingDatabaseConnection:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this error to the requestIssue case

Update UnrecoverableError Tests
@cocojoe cocojoe force-pushed the feature_critical_errors branch from d7bbb07 to 1792803 Compare January 12, 2017 09:52
@hzalaz hzalaz merged commit b86c88e into v2 Jan 12, 2017
@hzalaz hzalaz deleted the feature_critical_errors branch January 12, 2017 14:59
@hzalaz hzalaz added this to the v2-Next milestone Jan 12, 2017
@hzalaz hzalaz modified the milestones: v2-Next, 2.0.0 Feb 16, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants