Skip to content

Adding a few overlooked error types #319

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

Merged
merged 2 commits into from
Aug 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions firebase_admin/_auth_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,15 @@ def __init__(self, message, cause, http_response):
exceptions.AlreadyExistsError.__init__(self, message, cause, http_response)


class EmailAlreadyExistsError(exceptions.AlreadyExistsError):
"""The user with the provided email already exists."""

default_message = 'The user with the provided email already exists'

def __init__(self, message, cause, http_response):
exceptions.AlreadyExistsError.__init__(self, message, cause, http_response)


class InvalidDynamicLinkDomainError(exceptions.InvalidArgumentError):
"""Dynamic link domain in ActionCodeSettings is not authorized."""

Expand All @@ -220,6 +229,15 @@ def __init__(self, message, cause=None, http_response=None):
exceptions.InvalidArgumentError.__init__(self, message, cause, http_response)


class PhoneNumberAlreadyExistsError(exceptions.AlreadyExistsError):
"""The user with the provided phone number already exists."""

default_message = 'The user with the provided phone number already exists'

def __init__(self, message, cause, http_response):
exceptions.AlreadyExistsError.__init__(self, message, cause, http_response)


class UnexpectedResponseError(exceptions.UnknownError):
"""Backend service responded with an unexpected or malformed response."""

Expand All @@ -237,9 +255,11 @@ def __init__(self, message, cause=None, http_response=None):


_CODE_TO_EXC_TYPE = {
'DUPLICATE_EMAIL': EmailAlreadyExistsError,
'DUPLICATE_LOCAL_ID': UidAlreadyExistsError,
'INVALID_DYNAMIC_LINK_DOMAIN': InvalidDynamicLinkDomainError,
'INVALID_ID_TOKEN': InvalidIdTokenError,
'PHONE_NUMBER_EXISTS': PhoneNumberAlreadyExistsError,
'USER_NOT_FOUND': UserNotFoundError,
}

Expand Down
4 changes: 4 additions & 0 deletions firebase_admin/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
'ActionCodeSettings',
'CertificateFetchError',
'DELETE_ATTRIBUTE',
'EmailAlreadyExistsError',
'ErrorInfo',
'ExpiredIdTokenError',
'ExpiredSessionCookieError',
Expand All @@ -46,6 +47,7 @@
'InvalidIdTokenError',
'InvalidSessionCookieError',
'ListUsersPage',
'PhoneNumberAlreadyExistsError',
'RevokedIdTokenError',
'RevokedSessionCookieError',
'TokenSignError',
Expand Down Expand Up @@ -81,6 +83,7 @@
ActionCodeSettings = _user_mgt.ActionCodeSettings
CertificateFetchError = _token_gen.CertificateFetchError
DELETE_ATTRIBUTE = _user_mgt.DELETE_ATTRIBUTE
EmailAlreadyExistsError = _auth_utils.EmailAlreadyExistsError
ErrorInfo = _user_import.ErrorInfo
ExpiredIdTokenError = _token_gen.ExpiredIdTokenError
ExpiredSessionCookieError = _token_gen.ExpiredSessionCookieError
Expand All @@ -90,6 +93,7 @@
InvalidIdTokenError = _auth_utils.InvalidIdTokenError
InvalidSessionCookieError = _token_gen.InvalidSessionCookieError
ListUsersPage = _user_mgt.ListUsersPage
PhoneNumberAlreadyExistsError = _auth_utils.PhoneNumberAlreadyExistsError
RevokedIdTokenError = _token_gen.RevokedIdTokenError
RevokedSessionCookieError = _token_gen.RevokedSessionCookieError
TokenSignError = _token_gen.TokenSignError
Expand Down
13 changes: 12 additions & 1 deletion firebase_admin/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,18 @@


class FirebaseError(Exception):
"""Base class for all errors raised by the Admin SDK."""
"""Base class for all errors raised by the Admin SDK.

Args:
code: A string error code that represents the type of the exception. Possible error
codes are defined in https://cloud.google.com/apis/design/errors#handling_errors.
message: A human-readable error message string.
cause: The exception that caused this error (optional).
http_response: If this error was caused by an HTTP error response, this property is
set to the ``requests.Response`` object that represents the HTTP response (optional).
See https://2.python-requests.org/en/master/api/#requests.Response for details of
this object.
"""

def __init__(self, code, message, cause=None, http_response=None):
Exception.__init__(self, message)
Expand Down
18 changes: 13 additions & 5 deletions tests/test_user_mgt.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,12 @@ def test_get_user_by_phone_http_error(self, user_mgt_app):

class TestCreateUser(object):

already_exists_errors = {
'DUPLICATE_EMAIL': auth.EmailAlreadyExistsError,
'DUPLICATE_LOCAL_ID': auth.UidAlreadyExistsError,
'PHONE_NUMBER_EXISTS': auth.PhoneNumberAlreadyExistsError,
}

@pytest.mark.parametrize('arg', INVALID_STRINGS[1:] + ['a'*129])
def test_invalid_uid(self, user_mgt_app, arg):
with pytest.raises(ValueError):
Expand Down Expand Up @@ -358,13 +364,15 @@ def test_create_user_error(self, user_mgt_app):
assert excinfo.value.http_response is not None
assert excinfo.value.cause is not None

def test_uid_already_exists(self, user_mgt_app):
_instrument_user_manager(user_mgt_app, 500, '{"error": {"message": "DUPLICATE_LOCAL_ID"}}')
with pytest.raises(auth.UidAlreadyExistsError) as excinfo:
@pytest.mark.parametrize('error_code', already_exists_errors.keys())
def test_user_already_exists(self, user_mgt_app, error_code):
resp = {'error': {'message': error_code}}
_instrument_user_manager(user_mgt_app, 500, json.dumps(resp))
exc_type = self.already_exists_errors[error_code]
with pytest.raises(exc_type) as excinfo:
auth.create_user(app=user_mgt_app)
assert isinstance(excinfo.value, exceptions.AlreadyExistsError)
assert str(excinfo.value) == ('The user with the provided uid already exists '
'(DUPLICATE_LOCAL_ID).')
assert str(excinfo.value) == '{0} ({1}).'.format(exc_type.default_message, error_code)
assert excinfo.value.http_response is not None
assert excinfo.value.cause is not None

Expand Down