diff --git a/src/firebase_functions/options.py b/src/firebase_functions/options.py index 3d43273..21a932a 100644 --- a/src/firebase_functions/options.py +++ b/src/firebase_functions/options.py @@ -905,7 +905,7 @@ def _required_apis(self) -> list[_manifest.ManifestRequiredApi]: @_dataclasses.dataclass(frozen=True, kw_only=True) -class StorageOptions(RuntimeOptions): +class StorageOptions(EventHandlerOptions): """ Options specific to Cloud Storage function types. Internal use only. @@ -937,19 +937,19 @@ def _endpoint( } event_trigger = _manifest.EventTrigger( eventType=kwargs["event_type"], - retry=False, + retry=self.retry if self.retry is not None else False, eventFilters=event_filters, ) kwargs_merged = { - **_dataclasses.asdict(super()._endpoint(**kwargs)), + **_dataclasses.asdict(RuntimeOptions._endpoint(self, **kwargs)), "eventTrigger": event_trigger, } return _manifest.ManifestEndpoint(**_typing.cast(dict, kwargs_merged)) @_dataclasses.dataclass(frozen=True, kw_only=True) -class DatabaseOptions(RuntimeOptions): +class DatabaseOptions(EventHandlerOptions): """ Options specific to Realtime Database function types. Internal use only. @@ -990,13 +990,13 @@ def _endpoint( event_trigger = _manifest.EventTrigger( eventType=kwargs["event_type"], - retry=False, + retry=self.retry if self.retry is not None else False, eventFilters=event_filters, eventFilterPathPatterns=event_filters_path_patterns, ) kwargs_merged = { - **_dataclasses.asdict(super()._endpoint(**kwargs)), + **_dataclasses.asdict(RuntimeOptions._endpoint(self, **kwargs)), "eventTrigger": event_trigger, } return _manifest.ManifestEndpoint(**_typing.cast(dict, kwargs_merged)) @@ -1055,7 +1055,7 @@ def _required_apis(self) -> list[_manifest.ManifestRequiredApi]: @_dataclasses.dataclass(frozen=True, kw_only=True) -class FirestoreOptions(RuntimeOptions): +class FirestoreOptions(EventHandlerOptions): """ Options specific to Firestore function types. Internal use only. @@ -1097,13 +1097,13 @@ def _endpoint( event_filters["document"] = event_filter_document event_trigger = _manifest.EventTrigger( eventType=kwargs["event_type"], - retry=False, + retry=self.retry if self.retry is not None else False, eventFilters=event_filters, eventFilterPathPatterns=event_filters_path_patterns, ) kwargs_merged = { - **_dataclasses.asdict(super()._endpoint(**kwargs)), + **_dataclasses.asdict(RuntimeOptions._endpoint(self, **kwargs)), "eventTrigger": event_trigger, } return _manifest.ManifestEndpoint(**_typing.cast(dict, kwargs_merged)) diff --git a/tests/test_db.py b/tests/test_db.py index 94afad5..b31add6 100644 --- a/tests/test_db.py +++ b/tests/test_db.py @@ -16,6 +16,24 @@ class TestDb(unittest.TestCase): Tests for the db module. """ + def test_database_decorator_retry_option(self): + func = mock.Mock(__name__="example_func") + decorated_func = db_fn.on_value_written(reference="/items/{itemId}", retry=True)(func) + + endpoint = decorated_func.__firebase_endpoint__ + + self.assertIsNotNone(endpoint.eventTrigger) + self.assertTrue(endpoint.eventTrigger["retry"]) + + def test_database_decorator_retry_defaults_false(self): + func = mock.Mock(__name__="example_func") + decorated_func = db_fn.on_value_written(reference="/items/{itemId}")(func) + + endpoint = decorated_func.__firebase_endpoint__ + + self.assertIsNotNone(endpoint.eventTrigger) + self.assertFalse(endpoint.eventTrigger["retry"]) + def test_calls_init_function(self): hello = None diff --git a/tests/test_firestore_fn.py b/tests/test_firestore_fn.py index 0e07b10..d75f610 100644 --- a/tests/test_firestore_fn.py +++ b/tests/test_firestore_fn.py @@ -18,6 +18,33 @@ class TestFirestore(TestCase): firestore_fn tests. """ + def test_firestore_decorator_retry_option(self): + with patch.dict("sys.modules", mocked_modules): + from firebase_functions import firestore_fn + + func = Mock(__name__="example_func") + decorated_func = firestore_fn.on_document_created( + document="/foo/{bar}", + retry=True, + )(func) + + endpoint = decorated_func.__firebase_endpoint__ + + self.assertIsNotNone(endpoint.eventTrigger) + self.assertTrue(endpoint.eventTrigger["retry"]) + + def test_firestore_decorator_retry_defaults_false(self): + with patch.dict("sys.modules", mocked_modules): + from firebase_functions import firestore_fn + + func = Mock(__name__="example_func") + decorated_func = firestore_fn.on_document_created(document="/foo/{bar}")(func) + + endpoint = decorated_func.__firebase_endpoint__ + + self.assertIsNotNone(endpoint.eventTrigger) + self.assertFalse(endpoint.eventTrigger["retry"]) + def test_firestore_endpoint_handler_calls_function_with_correct_args(self): with patch.dict("sys.modules", mocked_modules): from cloudevents.http import CloudEvent diff --git a/tests/test_storage_fn.py b/tests/test_storage_fn.py index 299c9e4..a859db0 100644 --- a/tests/test_storage_fn.py +++ b/tests/test_storage_fn.py @@ -15,6 +15,24 @@ class TestStorage(unittest.TestCase): Storage function tests. """ + def test_storage_decorator_retry_option(self): + func = Mock(__name__="example_func") + decorated_func = storage_fn.on_object_finalized(bucket="bucket", retry=True)(func) + + endpoint = decorated_func.__firebase_endpoint__ + + self.assertIsNotNone(endpoint.eventTrigger) + self.assertTrue(endpoint.eventTrigger["retry"]) + + def test_storage_decorator_retry_defaults_false(self): + func = Mock(__name__="example_func") + decorated_func = storage_fn.on_object_finalized(bucket="bucket")(func) + + endpoint = decorated_func.__firebase_endpoint__ + + self.assertIsNotNone(endpoint.eventTrigger) + self.assertFalse(endpoint.eventTrigger["retry"]) + def test_calls_init(self): hello = None