From f945aa8e6bab7ba92b49a94b1a35e0bde5c98d62 Mon Sep 17 00:00:00 2001 From: Valery Brobbey Date: Fri, 24 Oct 2025 11:03:52 -0700 Subject: [PATCH] feat(billing): add transaction retention to config as span --- src/sentry/quotas/base.py | 6 ++++- .../endpoints/test_relay_projectconfigs.py | 25 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/sentry/quotas/base.py b/src/sentry/quotas/base.py index 452e0862b7c17c..bf1fe9578c06f8 100644 --- a/src/sentry/quotas/base.py +++ b/src/sentry/quotas/base.py @@ -71,7 +71,11 @@ def to_object(self) -> Mapping[str, Any]: # This mirrors the Retentions struct in relay # https://github.com/getsentry/relay/blob/641e7f20cd/relay-dynamic-config/src/project.rs#L34-L45 -RETENTIONS_CONFIG_MAPPING = {DataCategory.SPAN: "span", DataCategory.LOG_BYTE: "log"} +RETENTIONS_CONFIG_MAPPING = { + DataCategory.LOG_BYTE: "log", + DataCategory.TRANSACTION: "span", + DataCategory.SPAN: "span", +} def build_metric_abuse_quotas() -> list[AbuseQuota]: diff --git a/tests/sentry/api/endpoints/test_relay_projectconfigs.py b/tests/sentry/api/endpoints/test_relay_projectconfigs.py index 29c3eee4b723ad..fe93053b358d6c 100644 --- a/tests/sentry/api/endpoints/test_relay_projectconfigs.py +++ b/tests/sentry/api/endpoints/test_relay_projectconfigs.py @@ -192,6 +192,31 @@ def test_parse_retentions(call_endpoint, default_project): } +@django_db_all +def test_parse_retentions_with_transactions(call_endpoint, default_project): + with patch("sentry.quotas.backend") as quotas_mock: + quotas_mock.get_retentions = lambda x: { + DataCategory.ERROR: RetentionSettings(standard=10, downsampled=20), + DataCategory.REPLAY: RetentionSettings(standard=11, downsampled=21), + DataCategory.TRANSACTION: RetentionSettings(standard=12, downsampled=22), + DataCategory.LOG_BYTE: RetentionSettings(standard=13, downsampled=23), + } + quotas_mock.get_event_retention = lambda x: 45 + quotas_mock.get_downsampled_event_retention = lambda x: 90 + + result, status_code = call_endpoint() + assert status_code < 400 + assert_no_snakecase_key(result) + cfg = safe.get_path(result, "configs", str(default_project.id)) + + assert safe.get_path(cfg, "config", "eventRetention") == 45 + assert safe.get_path(cfg, "config", "downsampledEventRetention") == 90 + assert safe.get_path(cfg, "config", "retentions") == { + "span": {"standard": 12, "downsampled": 22}, + "log": {"standard": 13, "downsampled": 23}, + } + + @django_db_all def test_relays_dyamic_sampling(call_endpoint, default_project) -> None: """