From 208206689637c8c49ee20be9abb05578e8915444 Mon Sep 17 00:00:00 2001 From: hiranya911 Date: Fri, 19 Jul 2019 15:04:22 -0700 Subject: [PATCH 1/3] New error handling support in create/update/delete user APIs --- firebase_admin/_auth_utils.py | 10 +++++ firebase_admin/_user_mgt.py | 38 +++++++++--------- firebase_admin/auth.py | 35 +++++++---------- integration/test_auth.py | 12 ++---- tests/test_user_mgt.py | 73 +++++++++++++++++++++++++++-------- 5 files changed, 103 insertions(+), 65 deletions(-) diff --git a/firebase_admin/_auth_utils.py b/firebase_admin/_auth_utils.py index 7e992db06..2dfa23e08 100644 --- a/firebase_admin/_auth_utils.py +++ b/firebase_admin/_auth_utils.py @@ -193,6 +193,15 @@ def validate_action_type(action_type): return action_type +class UidAlreadyExistsError(exceptions.AlreadyExistsError): + """The user with the provided uid already exists.""" + + default_message = 'The user with the provided uid already exists' + + def __init__(self, message, cause, http_response=None): + exceptions.AlreadyExistsError.__init__(self, message, cause, http_response) + + class InvalidIdTokenError(exceptions.InvalidArgumentError): """The provided ID token is not a valid Firebase ID token.""" @@ -219,6 +228,7 @@ def __init__(self, message, cause=None, http_response=None): _CODE_TO_EXC_TYPE = { + 'DUPLICATE_LOCAL_ID': UidAlreadyExistsError, 'INVALID_ID_TOKEN': InvalidIdTokenError, 'USER_NOT_FOUND': UserNotFoundError, } diff --git a/firebase_admin/_user_mgt.py b/firebase_admin/_user_mgt.py index a217d108c..61090da9b 100644 --- a/firebase_admin/_user_mgt.py +++ b/firebase_admin/_user_mgt.py @@ -24,9 +24,6 @@ from firebase_admin import _user_import -USER_CREATE_ERROR = 'USER_CREATE_ERROR' -USER_UPDATE_ERROR = 'USER_UPDATE_ERROR' -USER_DELETE_ERROR = 'USER_DELETE_ERROR' USER_IMPORT_ERROR = 'USER_IMPORT_ERROR' USER_DOWNLOAD_ERROR = 'LIST_USERS_ERROR' GENERATE_EMAIL_ACTION_LINK_ERROR = 'GENERATE_EMAIL_ACTION_LINK_ERROR' @@ -531,13 +528,14 @@ def create_user(self, uid=None, display_name=None, email=None, phone_number=None } payload = {k: v for k, v in payload.items() if v is not None} try: - response = self._client.body('post', '/accounts', json=payload) + body, http_resp = self._client.body_and_response('post', '/accounts', json=payload) except requests.exceptions.RequestException as error: - self._handle_http_error(USER_CREATE_ERROR, 'Failed to create new user.', error) + raise _auth_utils.handle_auth_backend_error(error) else: - if not response or not response.get('localId'): - raise ApiCallError(USER_CREATE_ERROR, 'Failed to create new user.') - return response.get('localId') + if not body or not body.get('localId'): + raise _auth_utils.UnexpectedResponseError( + 'Failed to create new user.', http_response=http_resp) + return body.get('localId') def update_user(self, uid, display_name=_UNSPECIFIED, email=None, phone_number=_UNSPECIFIED, photo_url=_UNSPECIFIED, password=None, disabled=None, email_verified=None, @@ -581,26 +579,28 @@ def update_user(self, uid, display_name=_UNSPECIFIED, email=None, phone_number=_ payload = {k: v for k, v in payload.items() if v is not None} try: - response = self._client.body('post', '/accounts:update', json=payload) + body, http_resp = self._client.body_and_response( + 'post', '/accounts:update', json=payload) except requests.exceptions.RequestException as error: - self._handle_http_error( - USER_UPDATE_ERROR, 'Failed to update user: {0}.'.format(uid), error) + raise _auth_utils.handle_auth_backend_error(error) else: - if not response or not response.get('localId'): - raise ApiCallError(USER_UPDATE_ERROR, 'Failed to update user: {0}.'.format(uid)) - return response.get('localId') + if not body or not body.get('localId'): + raise _auth_utils.UnexpectedResponseError( + 'Failed to update user: {0}.'.format(uid), http_response=http_resp) + return body.get('localId') def delete_user(self, uid): """Deletes the user identified by the specified user ID.""" _auth_utils.validate_uid(uid, required=True) try: - response = self._client.body('post', '/accounts:delete', json={'localId' : uid}) + body, http_resp = self._client.body_and_response( + 'post', '/accounts:delete', json={'localId' : uid}) except requests.exceptions.RequestException as error: - self._handle_http_error( - USER_DELETE_ERROR, 'Failed to delete user: {0}.'.format(uid), error) + raise _auth_utils.handle_auth_backend_error(error) else: - if not response or not response.get('kind'): - raise ApiCallError(USER_DELETE_ERROR, 'Failed to delete user: {0}.'.format(uid)) + if not body or not body.get('kind'): + raise _auth_utils.UnexpectedResponseError( + 'Failed to delete user: {0}.'.format(uid), http_response=http_resp) def import_users(self, users, hash_alg=None): """Imports the given list of users to Firebase Auth.""" diff --git a/firebase_admin/auth.py b/firebase_admin/auth.py index f654eae42..19eaa54f5 100644 --- a/firebase_admin/auth.py +++ b/firebase_admin/auth.py @@ -44,6 +44,8 @@ 'ImportUserRecord', 'ListUsersPage', 'TokenSignError', + 'UidAlreadyExistsError', + 'UnexpectedResponseError', 'UserImportHash', 'UserImportResult', 'UserInfo', @@ -80,6 +82,7 @@ ImportUserRecord = _user_import.ImportUserRecord InvalidIdTokenError = _auth_utils.InvalidIdTokenError TokenSignError = _token_gen.TokenSignError +UidAlreadyExistsError = _auth_utils.UidAlreadyExistsError UnexpectedResponseError = _auth_utils.UnexpectedResponseError UserImportResult = _user_import.UserImportResult UserInfo = _user_mgt.UserInfo @@ -333,15 +336,12 @@ def create_user(**kwargs): Raises: ValueError: If the specified user properties are invalid. - AuthError: If an error occurs while creating the user account. + FirebaseError: If an error occurs while creating the user account. """ app = kwargs.pop('app', None) user_manager = _get_auth_service(app).user_manager - try: - uid = user_manager.create_user(**kwargs) - return UserRecord(user_manager.get_user(uid=uid)) - except _user_mgt.ApiCallError as error: - raise AuthError(error.code, str(error), error.detail) + uid = user_manager.create_user(**kwargs) + return UserRecord(user_manager.get_user(uid=uid)) def update_user(uid, **kwargs): @@ -373,15 +373,12 @@ def update_user(uid, **kwargs): Raises: ValueError: If the specified user ID or properties are invalid. - AuthError: If an error occurs while updating the user account. + FirebaseError: If an error occurs while updating the user account. """ app = kwargs.pop('app', None) user_manager = _get_auth_service(app).user_manager - try: - user_manager.update_user(uid, **kwargs) - return UserRecord(user_manager.get_user(uid=uid)) - except _user_mgt.ApiCallError as error: - raise AuthError(error.code, str(error), error.detail) + user_manager.update_user(uid, **kwargs) + return UserRecord(user_manager.get_user(uid=uid)) def set_custom_user_claims(uid, custom_claims, app=None): @@ -402,13 +399,10 @@ def set_custom_user_claims(uid, custom_claims, app=None): Raises: ValueError: If the specified user ID or the custom claims are invalid. - AuthError: If an error occurs while updating the user account. + FirebaseError: If an error occurs while updating the user account. """ user_manager = _get_auth_service(app).user_manager - try: - user_manager.update_user(uid, custom_claims=custom_claims) - except _user_mgt.ApiCallError as error: - raise AuthError(error.code, str(error), error.detail) + user_manager.update_user(uid, custom_claims=custom_claims) def delete_user(uid, app=None): @@ -420,13 +414,10 @@ def delete_user(uid, app=None): Raises: ValueError: If the user ID is None, empty or malformed. - AuthError: If an error occurs while deleting the user account. + FirebaseError: If an error occurs while deleting the user account. """ user_manager = _get_auth_service(app).user_manager - try: - user_manager.delete_user(uid) - except _user_mgt.ApiCallError as error: - raise AuthError(error.code, str(error), error.detail) + user_manager.delete_user(uid) def import_users(users, hash_alg=None, app=None): diff --git a/integration/test_auth.py b/integration/test_auth.py index 3af7be288..d92021b1d 100644 --- a/integration/test_auth.py +++ b/integration/test_auth.py @@ -148,14 +148,12 @@ def test_get_non_existing_user_by_email(): assert str(excinfo.value) == error_msg def test_update_non_existing_user(): - with pytest.raises(auth.AuthError) as excinfo: + with pytest.raises(auth.UserNotFoundError) as excinfo: auth.update_user('non.existing') - assert 'USER_UPDATE_ERROR' in str(excinfo.value.code) def test_delete_non_existing_user(): - with pytest.raises(auth.AuthError) as excinfo: + with pytest.raises(auth.UserNotFoundError) as excinfo: auth.delete_user('non.existing') - assert 'USER_DELETE_ERROR' in str(excinfo.value.code) @pytest.fixture def new_user(): @@ -258,9 +256,8 @@ def test_create_user(new_user): assert user.user_metadata.creation_timestamp > 0 assert user.user_metadata.last_sign_in_timestamp is None assert len(user.provider_data) is 0 - with pytest.raises(auth.AuthError) as excinfo: + with pytest.raises(auth.UidAlreadyExistsError) as excinfo: auth.create_user(uid=new_user.uid) - assert excinfo.value.code == 'USER_CREATE_ERROR' def test_update_user(new_user): _, email = _random_id() @@ -329,9 +326,8 @@ def test_disable_user(new_user_with_params): def test_delete_user(): user = auth.create_user() auth.delete_user(user.uid) - with pytest.raises(auth.AuthError) as excinfo: + with pytest.raises(auth.UserNotFoundError) as excinfo: auth.get_user(user.uid) - assert excinfo.value.code == 'USER_NOT_FOUND_ERROR' def test_revoke_refresh_tokens(new_user): user = auth.get_user(new_user.uid) diff --git a/tests/test_user_mgt.py b/tests/test_user_mgt.py index 951205621..f2ee4b58c 100644 --- a/tests/test_user_mgt.py +++ b/tests/test_user_mgt.py @@ -351,11 +351,31 @@ def test_create_user_with_id(self, user_mgt_app): assert request == {'localId' : 'testuser'} def test_create_user_error(self, user_mgt_app): - _instrument_user_manager(user_mgt_app, 500, '{"error":"test"}') - with pytest.raises(auth.AuthError) as excinfo: + _instrument_user_manager(user_mgt_app, 500, '{"error": {"message": "UNEXPECTED_CODE"}}') + with pytest.raises(exceptions.InternalError) as excinfo: auth.create_user(app=user_mgt_app) - assert excinfo.value.code == _user_mgt.USER_CREATE_ERROR - assert '{"error":"test"}' in str(excinfo.value) + assert str(excinfo.value) == 'Error while calling Auth service (UNEXPECTED_CODE).' + 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: + 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 excinfo.value.http_response is not None + assert excinfo.value.cause is not None + + def test_create_user_unexpected_response(self, user_mgt_app): + _instrument_user_manager(user_mgt_app, 200, '{"error": "test"}') + with pytest.raises(auth.UnexpectedResponseError) as excinfo: + auth.create_user(app=user_mgt_app) + assert str(excinfo.value) == 'Failed to create new user.' + assert excinfo.value.http_response is not None + assert excinfo.value.cause is None + assert isinstance(excinfo.value, exceptions.UnknownError) class TestUpdateUser(object): @@ -462,11 +482,21 @@ def test_update_user_delete_fields(self, user_mgt_app): } def test_update_user_error(self, user_mgt_app): - _instrument_user_manager(user_mgt_app, 500, '{"error":"test"}') - with pytest.raises(auth.AuthError) as excinfo: + _instrument_user_manager(user_mgt_app, 500, '{"error": {"message": "UNEXPECTED_CODE"}}') + with pytest.raises(exceptions.InternalError) as excinfo: auth.update_user('user', app=user_mgt_app) - assert excinfo.value.code == _user_mgt.USER_UPDATE_ERROR - assert '{"error":"test"}' in str(excinfo.value) + assert str(excinfo.value) == 'Error while calling Auth service (UNEXPECTED_CODE).' + assert excinfo.value.http_response is not None + assert excinfo.value.cause is not None + + def test_update_user_unexpected_response(self, user_mgt_app): + _instrument_user_manager(user_mgt_app, 200, '{"error": "test"}') + with pytest.raises(auth.UnexpectedResponseError) as excinfo: + auth.update_user('user', app=user_mgt_app) + assert str(excinfo.value) == 'Failed to update user: user.' + assert excinfo.value.http_response is not None + assert excinfo.value.cause is None + assert isinstance(excinfo.value, exceptions.UnknownError) @pytest.mark.parametrize('arg', [1, 1.0]) def test_update_user_valid_since(self, user_mgt_app, arg): @@ -530,11 +560,12 @@ def test_set_custom_user_claims_none(self, user_mgt_app): assert request == {'localId' : 'testuser', 'customAttributes' : json.dumps({})} def test_set_custom_user_claims_error(self, user_mgt_app): - _instrument_user_manager(user_mgt_app, 500, '{"error":"test"}') - with pytest.raises(auth.AuthError) as excinfo: + _instrument_user_manager(user_mgt_app, 500, '{"error": {"message": "UNEXPECTED_CODE"}}') + with pytest.raises(exceptions.InternalError) as excinfo: auth.set_custom_user_claims('user', {}, app=user_mgt_app) - assert excinfo.value.code == _user_mgt.USER_UPDATE_ERROR - assert '{"error":"test"}' in str(excinfo.value) + assert str(excinfo.value) == 'Error while calling Auth service (UNEXPECTED_CODE).' + assert excinfo.value.http_response is not None + assert excinfo.value.cause is not None class TestDeleteUser(object): @@ -550,11 +581,21 @@ def test_delete_user(self, user_mgt_app): auth.delete_user('testuser', user_mgt_app) def test_delete_user_error(self, user_mgt_app): - _instrument_user_manager(user_mgt_app, 500, '{"error":"test"}') - with pytest.raises(auth.AuthError) as excinfo: + _instrument_user_manager(user_mgt_app, 500, '{"error": {"message": "UNEXPECTED_CODE"}}') + with pytest.raises(exceptions.InternalError) as excinfo: auth.delete_user('user', app=user_mgt_app) - assert excinfo.value.code == _user_mgt.USER_DELETE_ERROR - assert '{"error":"test"}' in str(excinfo.value) + assert str(excinfo.value) == 'Error while calling Auth service (UNEXPECTED_CODE).' + assert excinfo.value.http_response is not None + assert excinfo.value.cause is not None + + def test_delete_user_unexpected_response(self, user_mgt_app): + _instrument_user_manager(user_mgt_app, 200, '{"error": "test"}') + with pytest.raises(auth.UnexpectedResponseError) as excinfo: + auth.delete_user('user', app=user_mgt_app) + assert str(excinfo.value) == 'Failed to delete user: user.' + assert excinfo.value.http_response is not None + assert excinfo.value.cause is None + assert isinstance(excinfo.value, exceptions.UnknownError) class TestListUsers(object): From 875a5b7fefe3ba47ee6cff354f6c2a232da1c29c Mon Sep 17 00:00:00 2001 From: hiranya911 Date: Fri, 19 Jul 2019 15:26:04 -0700 Subject: [PATCH 2/3] Fixing some lint errors --- integration/test_auth.py | 8 ++++---- lint.sh | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/integration/test_auth.py b/integration/test_auth.py index d92021b1d..c0149fd69 100644 --- a/integration/test_auth.py +++ b/integration/test_auth.py @@ -148,11 +148,11 @@ def test_get_non_existing_user_by_email(): assert str(excinfo.value) == error_msg def test_update_non_existing_user(): - with pytest.raises(auth.UserNotFoundError) as excinfo: + with pytest.raises(auth.UserNotFoundError): auth.update_user('non.existing') def test_delete_non_existing_user(): - with pytest.raises(auth.UserNotFoundError) as excinfo: + with pytest.raises(auth.UserNotFoundError): auth.delete_user('non.existing') @pytest.fixture @@ -256,7 +256,7 @@ def test_create_user(new_user): assert user.user_metadata.creation_timestamp > 0 assert user.user_metadata.last_sign_in_timestamp is None assert len(user.provider_data) is 0 - with pytest.raises(auth.UidAlreadyExistsError) as excinfo: + with pytest.raises(auth.UidAlreadyExistsError): auth.create_user(uid=new_user.uid) def test_update_user(new_user): @@ -326,7 +326,7 @@ def test_disable_user(new_user_with_params): def test_delete_user(): user = auth.create_user() auth.delete_user(user.uid) - with pytest.raises(auth.UserNotFoundError) as excinfo: + with pytest.raises(auth.UserNotFoundError): auth.get_user(user.uid) def test_revoke_refresh_tokens(new_user): diff --git a/lint.sh b/lint.sh index 603b78f92..aeb37f741 100755 --- a/lint.sh +++ b/lint.sh @@ -20,7 +20,7 @@ function lintAllFiles () { } function lintChangedFiles () { - files=`git status -s $1 | grep -v "^D" | awk '{print $NF}' | grep .py$` + files=`git status -s $1 | (grep -v "^D") | awk '{print $NF}' | (grep .py$ || true)` for f in $files do echo "Running linter on $f" From 98501e52b11a7112ec0f126ad3339e3c38bf243a Mon Sep 17 00:00:00 2001 From: hiranya911 Date: Sat, 20 Jul 2019 13:54:53 -0700 Subject: [PATCH 3/3] Error handling update in email action link APIs --- firebase_admin/_auth_utils.py | 12 +++++++++++- firebase_admin/_user_mgt.py | 14 +++++++------- firebase_admin/auth.py | 30 ++++++++++++------------------ tests/test_user_mgt.py | 30 +++++++++++++++++++++++++++--- 4 files changed, 57 insertions(+), 29 deletions(-) diff --git a/firebase_admin/_auth_utils.py b/firebase_admin/_auth_utils.py index 2dfa23e08..08b930ae6 100644 --- a/firebase_admin/_auth_utils.py +++ b/firebase_admin/_auth_utils.py @@ -198,10 +198,19 @@ class UidAlreadyExistsError(exceptions.AlreadyExistsError): default_message = 'The user with the provided uid already exists' - def __init__(self, message, cause, http_response=None): + 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.""" + + default_message = 'Dynamic link domain specified in ActionCodeSettings is not authorized' + + def __init__(self, message, cause, http_response): + exceptions.InvalidArgumentError.__init__(self, message, cause, http_response) + + class InvalidIdTokenError(exceptions.InvalidArgumentError): """The provided ID token is not a valid Firebase ID token.""" @@ -229,6 +238,7 @@ def __init__(self, message, cause=None, http_response=None): _CODE_TO_EXC_TYPE = { 'DUPLICATE_LOCAL_ID': UidAlreadyExistsError, + 'INVALID_DYNAMIC_LINK_DOMAIN': InvalidDynamicLinkDomainError, 'INVALID_ID_TOKEN': InvalidIdTokenError, 'USER_NOT_FOUND': UserNotFoundError, } diff --git a/firebase_admin/_user_mgt.py b/firebase_admin/_user_mgt.py index 61090da9b..3910f9690 100644 --- a/firebase_admin/_user_mgt.py +++ b/firebase_admin/_user_mgt.py @@ -26,7 +26,6 @@ USER_IMPORT_ERROR = 'USER_IMPORT_ERROR' USER_DOWNLOAD_ERROR = 'LIST_USERS_ERROR' -GENERATE_EMAIL_ACTION_LINK_ERROR = 'GENERATE_EMAIL_ACTION_LINK_ERROR' MAX_LIST_USERS_RESULTS = 1000 MAX_IMPORT_USERS_SIZE = 1000 @@ -654,14 +653,15 @@ def generate_email_action_link(self, action_type, email, action_code_settings=No payload.update(encode_action_code_settings(action_code_settings)) try: - response = self._client.body('post', '/accounts:sendOobCode', json=payload) + body, http_resp = self._client.body_and_response( + 'post', '/accounts:sendOobCode', json=payload) except requests.exceptions.RequestException as error: - self._handle_http_error(GENERATE_EMAIL_ACTION_LINK_ERROR, 'Failed to generate link.', - error) + raise _auth_utils.handle_auth_backend_error(error) else: - if not response or not response.get('oobLink'): - raise ApiCallError(GENERATE_EMAIL_ACTION_LINK_ERROR, 'Failed to generate link.') - return response.get('oobLink') + if not body or not body.get('oobLink'): + raise _auth_utils.UnexpectedResponseError( + 'Failed to generate email action link.', http_response=http_resp) + return body.get('oobLink') def _handle_http_error(self, code, msg, error): if error.response is not None: diff --git a/firebase_admin/auth.py b/firebase_admin/auth.py index 19eaa54f5..61d71ad9f 100644 --- a/firebase_admin/auth.py +++ b/firebase_admin/auth.py @@ -42,6 +42,8 @@ 'ErrorInfo', 'ExportedUserRecord', 'ImportUserRecord', + 'InvalidDynamicLinkDomainError', + 'InvalidIdTokenError', 'ListUsersPage', 'TokenSignError', 'UidAlreadyExistsError', @@ -80,6 +82,7 @@ ListUsersPage = _user_mgt.ListUsersPage UserImportHash = _user_import.UserImportHash ImportUserRecord = _user_import.ImportUserRecord +InvalidDynamicLinkDomainError = _auth_utils.InvalidDynamicLinkDomainError InvalidIdTokenError = _auth_utils.InvalidIdTokenError TokenSignError = _token_gen.TokenSignError UidAlreadyExistsError = _auth_utils.UidAlreadyExistsError @@ -465,14 +468,11 @@ def generate_password_reset_link(email, action_code_settings=None, app=None): Raises: ValueError: If the provided arguments are invalid - AuthError: If an error occurs while generating the link + FirebaseError: If an error occurs while generating the link """ user_manager = _get_auth_service(app).user_manager - try: - return user_manager.generate_email_action_link('PASSWORD_RESET', email, - action_code_settings=action_code_settings) - except _user_mgt.ApiCallError as error: - raise AuthError(error.code, str(error), error.detail) + return user_manager.generate_email_action_link( + 'PASSWORD_RESET', email, action_code_settings=action_code_settings) def generate_email_verification_link(email, action_code_settings=None, app=None): @@ -490,14 +490,11 @@ def generate_email_verification_link(email, action_code_settings=None, app=None) Raises: ValueError: If the provided arguments are invalid - AuthError: If an error occurs while generating the link + FirebaseError: If an error occurs while generating the link """ user_manager = _get_auth_service(app).user_manager - try: - return user_manager.generate_email_action_link('VERIFY_EMAIL', email, - action_code_settings=action_code_settings) - except _user_mgt.ApiCallError as error: - raise AuthError(error.code, str(error), error.detail) + return user_manager.generate_email_action_link( + 'VERIFY_EMAIL', email, action_code_settings=action_code_settings) def generate_sign_in_with_email_link(email, action_code_settings, app=None): @@ -515,14 +512,11 @@ def generate_sign_in_with_email_link(email, action_code_settings, app=None): Raises: ValueError: If the provided arguments are invalid - AuthError: If an error occurs while generating the link + FirebaseError: If an error occurs while generating the link """ user_manager = _get_auth_service(app).user_manager - try: - return user_manager.generate_email_action_link('EMAIL_SIGNIN', email, - action_code_settings=action_code_settings) - except _user_mgt.ApiCallError as error: - raise AuthError(error.code, str(error), error.detail) + return user_manager.generate_email_action_link( + 'EMAIL_SIGNIN', email, action_code_settings=action_code_settings) def _check_jwt_revoked(verified_claims, error_code, label, app): diff --git a/tests/test_user_mgt.py b/tests/test_user_mgt.py index f2ee4b58c..594de2d4c 100644 --- a/tests/test_user_mgt.py +++ b/tests/test_user_mgt.py @@ -1200,9 +1200,29 @@ def test_password_reset_with_settings(self, user_mgt_app): auth.generate_password_reset_link, ]) def test_api_call_failure(self, user_mgt_app, func): - _instrument_user_manager(user_mgt_app, 500, '{"error":"dummy error"}') - with pytest.raises(auth.AuthError): + _instrument_user_manager(user_mgt_app, 500, '{"error":{"message": "UNEXPECTED_CODE"}}') + with pytest.raises(exceptions.InternalError) as excinfo: + func('test@test.com', MOCK_ACTION_CODE_SETTINGS, app=user_mgt_app) + assert str(excinfo.value) == 'Error while calling Auth service (UNEXPECTED_CODE).' + assert excinfo.value.http_response is not None + assert excinfo.value.cause is not None + + @pytest.mark.parametrize('func', [ + auth.generate_sign_in_with_email_link, + auth.generate_email_verification_link, + auth.generate_password_reset_link, + ]) + def test_invalid_dynamic_link(self, user_mgt_app, func): + resp = '{"error":{"message": "INVALID_DYNAMIC_LINK_DOMAIN: Because of this reason."}}' + _instrument_user_manager(user_mgt_app, 500, resp) + with pytest.raises(auth.InvalidDynamicLinkDomainError) as excinfo: func('test@test.com', MOCK_ACTION_CODE_SETTINGS, app=user_mgt_app) + assert isinstance(excinfo.value, exceptions.InvalidArgumentError) + assert str(excinfo.value) == ('Dynamic link domain specified in ActionCodeSettings is ' + 'not authorized (INVALID_DYNAMIC_LINK_DOMAIN). Because ' + 'of this reason.') + assert excinfo.value.http_response is not None + assert excinfo.value.cause is not None @pytest.mark.parametrize('func', [ auth.generate_sign_in_with_email_link, @@ -1211,8 +1231,12 @@ def test_api_call_failure(self, user_mgt_app, func): ]) def test_api_call_no_link(self, user_mgt_app, func): _instrument_user_manager(user_mgt_app, 200, '{}') - with pytest.raises(auth.AuthError): + with pytest.raises(auth.UnexpectedResponseError) as excinfo: func('test@test.com', MOCK_ACTION_CODE_SETTINGS, app=user_mgt_app) + assert str(excinfo.value) == 'Failed to generate email action link.' + assert excinfo.value.http_response is not None + assert excinfo.value.cause is None + assert isinstance(excinfo.value, exceptions.UnknownError) @pytest.mark.parametrize('func', [ auth.generate_sign_in_with_email_link,