diff --git a/src/firebase_functions/options.py b/src/firebase_functions/options.py index 3d43273..7afd001 100644 --- a/src/firebase_functions/options.py +++ b/src/firebase_functions/options.py @@ -501,10 +501,16 @@ def _endpoint( assert kwargs["event_filters"] is not None assert kwargs["event_type"] is not None + event_filters_path_patterns = kwargs.get("event_filters_path_patterns") or None event_trigger = _manifest.EventTrigger( eventType=kwargs["event_type"], retry=self.retry if self.retry is not None else False, eventFilters=kwargs["event_filters"], + **( + {"eventFilterPathPatterns": event_filters_path_patterns} + if event_filters_path_patterns is not None + else {} + ), ) kwargs_merged = { @@ -905,7 +911,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. @@ -935,21 +941,11 @@ def _endpoint( event_filters: _typing.Any = { "bucket": bucket, } - event_trigger = _manifest.EventTrigger( - eventType=kwargs["event_type"], - retry=False, - eventFilters=event_filters, - ) - - kwargs_merged = { - **_dataclasses.asdict(super()._endpoint(**kwargs)), - "eventTrigger": event_trigger, - } - return _manifest.ManifestEndpoint(**_typing.cast(dict, kwargs_merged)) + return super()._endpoint(**kwargs, event_filters=event_filters) @_dataclasses.dataclass(frozen=True, kw_only=True) -class DatabaseOptions(RuntimeOptions): +class DatabaseOptions(EventHandlerOptions): """ Options specific to Realtime Database function types. Internal use only. @@ -988,19 +984,12 @@ def _endpoint( else: event_filters["instance"] = event_filter_instance - event_trigger = _manifest.EventTrigger( - eventType=kwargs["event_type"], - retry=False, - eventFilters=event_filters, - eventFilterPathPatterns=event_filters_path_patterns, + return super()._endpoint( + **kwargs, + event_filters=event_filters, + event_filters_path_patterns=event_filters_path_patterns, ) - kwargs_merged = { - **_dataclasses.asdict(super()._endpoint(**kwargs)), - "eventTrigger": event_trigger, - } - return _manifest.ManifestEndpoint(**_typing.cast(dict, kwargs_merged)) - @_dataclasses.dataclass(frozen=True, kw_only=True) class BlockingOptions(RuntimeOptions): @@ -1055,7 +1044,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. @@ -1095,19 +1084,12 @@ def _endpoint( event_filters_path_patterns["document"] = event_filter_document else: event_filters["document"] = event_filter_document - event_trigger = _manifest.EventTrigger( - eventType=kwargs["event_type"], - retry=False, - eventFilters=event_filters, - eventFilterPathPatterns=event_filters_path_patterns, + return super()._endpoint( + **kwargs, + event_filters=event_filters, + event_filters_path_patterns=event_filters_path_patterns, ) - kwargs_merged = { - **_dataclasses.asdict(super()._endpoint(**kwargs)), - "eventTrigger": event_trigger, - } - return _manifest.ManifestEndpoint(**_typing.cast(dict, kwargs_merged)) - @_dataclasses.dataclass(frozen=True, kw_only=True) class HttpsOptions(RuntimeOptions): 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