From 0481753fba623234d9d07c4f3f54abd48fab308e Mon Sep 17 00:00:00 2001 From: Mathieu Velten Date: Fri, 17 May 2024 09:57:00 +0200 Subject: [PATCH] Add tests --- sygnal/gcmpushkin.py | 19 ++++++++------- tests/test_gcm.py | 57 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 56 insertions(+), 20 deletions(-) diff --git a/sygnal/gcmpushkin.py b/sygnal/gcmpushkin.py index f25d96b9..1bd06bc0 100644 --- a/sygnal/gcmpushkin.py +++ b/sygnal/gcmpushkin.py @@ -159,15 +159,6 @@ def __init__(self, name: str, sygnal: "Sygnal", config: Dict[str, Any]) -> None: proxy_url_str=proxy_url, ) - # Use the fcm_options config dictionary as a foundation for the body; - # this lets the Sygnal admin choose custom FCM options - # (e.g. content_available). - self.base_request_body = self.get_config("fcm_options", dict, {}) - if not isinstance(self.base_request_body, dict): - raise PushkinSetupException( - "Config field fcm_options, if set, must be a dictionary of options" - ) - self.api_version = APIVersion.Legacy version_str = self.get_config("api_version", str) if not version_str: @@ -224,6 +215,15 @@ def __init__(self, name: str, sygnal: "Sygnal", config: Dict[str, Any]) -> None: session=session ) + # Use the fcm_options config dictionary as a foundation for the body; + # this lets the Sygnal admin choose custom FCM options + # (e.g. content_available). + self.base_request_body = self.get_config("fcm_options", dict, {}) + if not isinstance(self.base_request_body, dict): + raise PushkinSetupException( + "Config field fcm_options, if set, must be a dictionary of options" + ) + @classmethod async def create( cls, name: str, sygnal: "Sygnal", config: Dict[str, Any] @@ -498,6 +498,7 @@ async def _get_auth_header(self) -> str: :return: Needed content of the `Authorization` header """ + print("_get_auth_header") if self.api_version is APIVersion.Legacy: return "key=%s" % (self.api_key,) else: diff --git a/tests/test_gcm.py b/tests/test_gcm.py index 7add90ae..b5204753 100644 --- a/tests/test_gcm.py +++ b/tests/test_gcm.py @@ -13,10 +13,11 @@ # See the License for the specific language governing permissions and # limitations under the License. import json +import tempfile from typing import TYPE_CHECKING, Any, AnyStr, Dict, List, Tuple from unittest.mock import MagicMock -from sygnal.gcmpushkin import GcmPushkin, PushkinSetupException +from sygnal.gcmpushkin import APIVersion, GcmPushkin from tests import testutils from tests.testutils import DummyResponse @@ -79,6 +80,21 @@ } +class TestCredentials: + def __init__(self) -> None: + self.valid = False + + @property + def token(self) -> str: + if self.valid: + return "myaccesstoken" + else: + raise Exception() + + async def refresh(self, request: Any) -> None: + self.valid = True + + class TestGcmPushkin(GcmPushkin): """ A GCM pushkin with the ability to make HTTP requests removed and instead @@ -86,18 +102,14 @@ class TestGcmPushkin(GcmPushkin): """ def __init__(self, name: str, sygnal: "Sygnal", config: Dict[str, Any]): + super().__init__(name, sygnal, config) self.preloaded_response = DummyResponse(0) self.preloaded_response_payload: Dict[str, Any] = {} self.last_request_body: Dict[str, Any] = {} self.last_request_headers: Dict[AnyStr, List[AnyStr]] = {} # type: ignore[valid-type] self.num_requests = 0 - try: - super().__init__(name, sygnal, config) - except PushkinSetupException as e: - # for FCM v1 API we get an exception because the service account file - # does not exist, let's ignore it and move forward - if "service_account_file" not in str(e): - raise e + if self.api_version is APIVersion.V1: + self.credentials = TestCredentials() # type: ignore[assignment] def preload_with_response( self, code: int, response_payload: Dict[str, Any] @@ -116,8 +128,22 @@ async def _perform_http_request( # type: ignore[override] self.num_requests += 1 return self.preloaded_response, json.dumps(self.preloaded_response_payload) - async def _get_auth_header(self) -> str: - return "token" + +FAKE_SERVICE_ACCOUNT_FILE = b""" +{ + "type": "service_account", + "project_id": "project_id", + "private_key_id": "private_key_id", + "private_key": "-----BEGIN PRIVATE KEY-----\\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC0PwE6TeTHjD5R\\nY2nOw1rsTgQZ38LCR2CLtx36n+LUkgej/9b+fwC88oKIqJKjUwn43JEOhf4rbA/a\\nqo4jVoLgv754G5+7Glfarr3/rqg+AVT75x6J5DRvhIYpDXwMIUqLAAbfk3TTFNJn\\n2ctrkBF2ZP9p3mzZ3NRjU63Wbf3LBpRqs8jdFEQu8JAecG8VKV1mboJIXG3hwqFN\\nJmcpC/+sWaxB5iMgSqy0w/rGFs6ZbZF6D10XYvf40lEEk9jQIovT+QD4+6GTlroT\\nbOk8uIwxFQcwMFpXj4MktqVNSNyiuuttptIvBWcMWHlaabXrR89vqUFe1g1Jx4GL\\nCF89RrcLAgMBAAECggEAPUYZ3b8zId78JGDeTEq+8wwGeuFFbRQkrvpeN5/41Xib\\nHlZPuQ5lqtXqKBjeWKVXA4G/0icc45gFv7kxPrQfI9YrItuJLmrjKNU0g+HVEdcU\\nE9pa2Fd6t9peXUBXRixfEee9bm3LTiKK8IDqlTNRrGTjKxNQ/7MBhI6izv1vRH/x\\n8i0o1xxNdqstHZ9wBFKYO9w8UQjtfzckkBNDLkaJ/WN0BoRubmUiV1+KwAyyBr6O\\nRnnZ9Tvy8VraSNSdJhX36ai36y18/sT6PWOp99zHYuDyz89KIz1la/fT9eSoR0Jy\\nYePmTEi+9pWhvtpAkqJkRxe5IDz71JVsQ07KoVfzaQKBgQDzKKUd/0ujhv/B9MQf\\nHcwSeWu/XnQ4hlcwz8dTWQjBV8gv9l4yBj9Pra62rg/tQ7b5XKMt6lv/tWs1IpdA\\neMsySY4972VPrmggKXgCnyKckDUYydNtHAIj9buo6AV8rONaneYnGv5wpSsf3q2c\\nOZrkamRgbBkI+B2mZ2obH1oVlQKBgQC9w9HkrDMvZ5L/ilZmpsvoHNFlQwmDgNlN\\n0ej5QGID5rljRM3CcLNHdyQiKqvLA9MCpPEXb2vVJPdmquD12A7a9s0OwxB/dtOD\\nykofcTY0ZHEM1HEyYJGmdK4FvZuNU4o2/D268dePjtj1Xw3c5fs0bcDiGQMtjWlz\\n5hjBzMsyHwKBgGjrIsPcwlBfEcAo0u7yNnnKNnmuUcuJ+9kt7j3Cbwqty80WKvK+\\ny1agBIECfhDMZQkXtbk8JFIjf4y/zi+db1/VaTDEORy2jmtCOWw4KgEQIDj/7OBp\\nc2r8vupUovl2x+rzsrkw5pTIT+FCffqoyHLCjWkle2/pTzHb8Waekoo5AoGAbELk\\nYy5uwTO45Hr60fOEzzZpq/iz28dNshz4agL2KD2gNGcTcEO1tCbfgXKQsfDLmG2b\\ncgBKJ77AOl1wnDEYQIme8TYOGnojL8Pfx9Jh10AaUvR8Y/49+hYFFhdXQCiR6M69\\nNQM2NJuNYWdKVGUMjJu0+AjHDFzp9YonQ6Ffp4cCgYEAmVALALCjU9GjJymgJ0lx\\nD9LccVHMwf9NmR/sMg0XNePRbCEcMDHKdtVJ1zPGS5txuxY3sRb/tDpv7TfuitrU\\nAw0/2ooMzunaoF/HXo+C/+t+pfuqPqLK4sCCyezUlMfCcaPdwXN2FmbgsaFHfe7I\\n7sGEnS/d8wEgydMiptJEf9s=\\n-----END PRIVATE KEY-----\\n", + "client_email": "firebase-adminsdk@project_id.iam.gserviceaccount.com", + "client_id": "client_id", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-04u89%40tchap-beta.iam.gserviceaccount.com", + "universe_domain": "googleapis.com" +} +""" class GcmTestCase(testutils.TestCase): @@ -134,11 +160,14 @@ def config_setup(self, config: Dict[str, Any]) -> None: "api_key": "kii", "fcm_options": {"content_available": True, "mutable_content": True}, } + self.service_account_file = tempfile.NamedTemporaryFile() + self.service_account_file.write(FAKE_SERVICE_ACCOUNT_FILE) + self.service_account_file.flush() config["apps"]["com.example.gcm.apiv1"] = { "type": "tests.test_gcm.TestGcmPushkin", "api_version": "v1", "project_id": "example_project", - "service_account_file": "/path/to/file.json", + "service_account_file": self.service_account_file.name, "fcm_options": { "apns": { "payload": { @@ -152,6 +181,9 @@ def config_setup(self, config: Dict[str, Any]) -> None: }, } + def tearDown(self) -> None: + self.service_account_file.close() + def get_test_pushkin(self, name: str) -> TestGcmPushkin: pushkin = self.sygnal.pushkins[name] assert isinstance(pushkin, TestGcmPushkin) @@ -266,6 +298,9 @@ def test_expected_api_v1(self) -> None: ) self.assertEqual(resp, {"rejected": []}) + self.assertEqual( + gcm.last_request_headers.get("Authorization"), ["Bearer myaccesstoken"] + ) def test_expected_with_default_payload(self) -> None: """