diff --git a/pyfcm/baseapi.py b/pyfcm/baseapi.py index 8ece016..fab80de 100644 --- a/pyfcm/baseapi.py +++ b/pyfcm/baseapi.py @@ -8,7 +8,7 @@ import requests from requests.adapters import HTTPAdapter from urllib3 import Retry - +from os import path from google.oauth2 import service_account from google.oauth2.credentials import Credentials import google.auth.transport.requests @@ -177,6 +177,10 @@ def _initialize_credentials(self): Initialize credentials and FCM endpoint if not already initialized. """ if self.credentials is None: + if not path.isfile(self._service_account_file): + raise InvalidDataError(f"The service account file you passed does not exist at '{self._service_account_file}'. " + "Ensure it does not have any typos and exists." + ) self.credentials = service_account.Credentials.from_service_account_file( self._service_account_file, scopes=["https://www.googleapis.com/auth/firebase.messaging"], diff --git a/tests/test_fcm.py b/tests/test_fcm.py index 1c1284d..396ba52 100644 --- a/tests/test_fcm.py +++ b/tests/test_fcm.py @@ -8,6 +8,33 @@ def test_push_service_without_credentials(): except errors.AuthenticationError: pass +def test_push_service_with_incorrect_service_account_file(): + try: + fcm = FCMNotification(service_account_file='./foo.json', project_id=None, credentials=None) + fcm.notify() + assert False, "Should raise InvalidDataError without correct service account file path" + except errors.InvalidDataError: + pass + +def test_push_service_with_valid_service_account_file(mocker): + # When the service account file exists, credentials must be built via + # google.oauth2.service_account.Credentials.from_service_account_file. + # google.oauth2.credentials.Credentials does not provide that method. + mocker.patch("pyfcm.baseapi.path.isfile", return_value=True) + mock_from_file = mocker.patch( + "pyfcm.baseapi.service_account.Credentials.from_service_account_file", + return_value="dummy-credentials", + ) + + fcm = FCMNotification( + service_account_file="./service_account.json", + project_id="test", + credentials=None, + ) + fcm._initialize_credentials() + + mock_from_file.assert_called_once() + assert fcm.credentials == "dummy-credentials" def test_push_service_directly_passed_credentials(push_service): # We should infer the project ID/endpoint from credentials