|
12 | 12 | from urllib3.response import HTTPResponse |
13 | 13 |
|
14 | 14 | from sentry.constants import ObjectStatus |
15 | | -from sentry.incidents.subscription_processor import SubscriptionProcessor, has_downgraded |
| 15 | +from sentry.incidents.subscription_processor import SubscriptionProcessor |
| 16 | +from sentry.incidents.utils.subscription_limits import is_metric_subscription_allowed |
16 | 17 | from sentry.incidents.utils.types import QuerySubscriptionUpdate |
17 | 18 | from sentry.models.organization import Organization |
18 | 19 | from sentry.seer.anomaly_detection.types import ( |
@@ -65,17 +66,18 @@ def test_missing_project(self, mock_metrics: MagicMock) -> None: |
65 | 66 | self.sub.project.delete() |
66 | 67 | assert self.send_update(self.critical_threshold + 1) is False |
67 | 68 |
|
68 | | - @patch("sentry.incidents.subscription_processor.has_downgraded", return_value=True) |
69 | | - def test_process_update_returns_false_when_downgraded( |
70 | | - self, mock_has_downgraded: MagicMock |
71 | | - ) -> None: |
| 69 | + @patch( |
| 70 | + "sentry.incidents.subscription_processor.is_metric_subscription_allowed", |
| 71 | + return_value=False, |
| 72 | + ) |
| 73 | + def test_process_update_returns_false_when_downgraded(self, mock_is_enabled: MagicMock) -> None: |
72 | 74 | message = self.build_subscription_update( |
73 | 75 | self.sub, value=self.critical_threshold + 1, time_delta=timedelta() |
74 | 76 | ) |
75 | 77 |
|
76 | 78 | with self.capture_on_commit_callbacks(execute=True): |
77 | 79 | assert SubscriptionProcessor.process(self.sub, message) is False |
78 | | - mock_has_downgraded.assert_called_once() |
| 80 | + mock_is_enabled.assert_called_once() |
79 | 81 |
|
80 | 82 | @patch("sentry.incidents.subscription_processor.metrics") |
81 | 83 | def test_invalid_aggregation_value(self, mock_metrics: MagicMock) -> None: |
@@ -1014,90 +1016,94 @@ def test_ensure_case_when_no_metrics_index_not_found_is_handled_gracefully( |
1014 | 1016 | ) |
1015 | 1017 |
|
1016 | 1018 |
|
1017 | | -@patch("sentry.incidents.subscription_processor.metrics") |
1018 | | -class TestHasDowngraded: |
| 1019 | +class TestIsMetricSubscriptionAllowed: |
1019 | 1020 | org = MagicMock(spec=Organization) |
1020 | 1021 |
|
1021 | 1022 | @contextmanager |
1022 | 1023 | def fake_features(self, enabled: set[str]): |
1023 | | - with patch("sentry.incidents.subscription_processor.features") as mock_features: |
| 1024 | + with patch("sentry.incidents.utils.subscription_limits.features") as mock_features: |
1024 | 1025 | mock_features.has.side_effect = lambda name, *a, **kw: name in enabled |
1025 | 1026 | yield |
1026 | 1027 |
|
1027 | | - def test_events_without_incidents_feature(self, mock_metrics: MagicMock) -> None: |
| 1028 | + # -- :incidents is the universal gate -- |
| 1029 | + |
| 1030 | + def test_no_incidents_disables_events(self) -> None: |
1028 | 1031 | with self.fake_features(set()): |
1029 | | - assert has_downgraded(Dataset.Events.value, self.org) is True |
1030 | | - mock_metrics.incr.assert_called_with( |
1031 | | - "incidents.alert_rules.ignore_update_missing_incidents" |
1032 | | - ) |
| 1032 | + assert is_metric_subscription_allowed(Dataset.Events.value, self.org) is False |
1033 | 1033 |
|
1034 | | - def test_events_with_incidents_feature(self, mock_metrics: MagicMock) -> None: |
1035 | | - with self.fake_features({"organizations:incidents"}): |
1036 | | - assert has_downgraded(Dataset.Events.value, self.org) is False |
| 1034 | + def test_no_incidents_disables_transactions(self) -> None: |
| 1035 | + with self.fake_features({"organizations:performance-view"}): |
| 1036 | + assert is_metric_subscription_allowed(Dataset.Transactions.value, self.org) is False |
1037 | 1037 |
|
1038 | | - def test_transactions_without_any_features(self, mock_metrics: MagicMock) -> None: |
| 1038 | + def test_no_incidents_disables_eap(self) -> None: |
| 1039 | + with self.fake_features({"organizations:visibility-explore-view"}): |
| 1040 | + assert ( |
| 1041 | + is_metric_subscription_allowed(Dataset.EventsAnalyticsPlatform.value, self.org) |
| 1042 | + is False |
| 1043 | + ) |
| 1044 | + |
| 1045 | + def test_no_incidents_disables_performance_metrics(self) -> None: |
| 1046 | + with self.fake_features({"organizations:on-demand-metrics-extraction"}): |
| 1047 | + assert ( |
| 1048 | + is_metric_subscription_allowed(Dataset.PerformanceMetrics.value, self.org) is False |
| 1049 | + ) |
| 1050 | + |
| 1051 | + def test_no_incidents_disables_unknown_dataset(self) -> None: |
1039 | 1052 | with self.fake_features(set()): |
1040 | | - assert has_downgraded(Dataset.Transactions.value, self.org) is True |
1041 | | - mock_metrics.incr.assert_called_with( |
1042 | | - "incidents.alert_rules.ignore_update_missing_incidents_performance" |
1043 | | - ) |
| 1053 | + assert is_metric_subscription_allowed("unknown_dataset", self.org) is False |
1044 | 1054 |
|
1045 | | - def test_transactions_with_only_performance_view(self, mock_metrics: MagicMock) -> None: |
1046 | | - with self.fake_features({"organizations:performance-view"}): |
1047 | | - assert has_downgraded(Dataset.Transactions.value, self.org) is True |
1048 | | - mock_metrics.incr.assert_called_with( |
1049 | | - "incidents.alert_rules.ignore_update_missing_incidents_performance" |
1050 | | - ) |
| 1055 | + # -- Events -- |
| 1056 | + |
| 1057 | + def test_events_enabled(self) -> None: |
| 1058 | + with self.fake_features({"organizations:incidents"}): |
| 1059 | + assert is_metric_subscription_allowed(Dataset.Events.value, self.org) is True |
| 1060 | + |
| 1061 | + # -- Transactions -- |
| 1062 | + |
| 1063 | + def test_transactions_without_performance_view(self) -> None: |
| 1064 | + with self.fake_features({"organizations:incidents"}): |
| 1065 | + assert is_metric_subscription_allowed(Dataset.Transactions.value, self.org) is False |
1051 | 1066 |
|
1052 | | - def test_transactions_with_both_features(self, mock_metrics: MagicMock) -> None: |
| 1067 | + def test_transactions_with_both_features(self) -> None: |
1053 | 1068 | with self.fake_features({"organizations:incidents", "organizations:performance-view"}): |
1054 | | - assert has_downgraded(Dataset.Transactions.value, self.org) is False |
| 1069 | + assert is_metric_subscription_allowed(Dataset.Transactions.value, self.org) is True |
1055 | 1070 |
|
1056 | | - def test_eap_without_features(self, mock_metrics: MagicMock) -> None: |
1057 | | - with self.fake_features(set()): |
1058 | | - assert has_downgraded(Dataset.EventsAnalyticsPlatform.value, self.org) is True |
1059 | | - mock_metrics.incr.assert_called_with( |
1060 | | - "incidents.alert_rules.ignore_update_missing_incidents_eap" |
1061 | | - ) |
| 1071 | + # -- EAP -- |
1062 | 1072 |
|
1063 | | - def test_eap_with_only_explore_view(self, mock_metrics: MagicMock) -> None: |
1064 | | - with self.fake_features({"organizations:visibility-explore-view"}): |
1065 | | - assert has_downgraded(Dataset.EventsAnalyticsPlatform.value, self.org) is True |
1066 | | - mock_metrics.incr.assert_called_with( |
1067 | | - "incidents.alert_rules.ignore_update_missing_incidents_eap" |
1068 | | - ) |
| 1073 | + def test_eap_without_explore_view(self) -> None: |
| 1074 | + with self.fake_features({"organizations:incidents"}): |
| 1075 | + assert ( |
| 1076 | + is_metric_subscription_allowed(Dataset.EventsAnalyticsPlatform.value, self.org) |
| 1077 | + is False |
| 1078 | + ) |
1069 | 1079 |
|
1070 | | - def test_eap_with_both_features(self, mock_metrics: MagicMock) -> None: |
| 1080 | + def test_eap_with_both_features(self) -> None: |
1071 | 1081 | with self.fake_features( |
1072 | 1082 | {"organizations:incidents", "organizations:visibility-explore-view"} |
1073 | 1083 | ): |
1074 | | - assert has_downgraded(Dataset.EventsAnalyticsPlatform.value, self.org) is False |
| 1084 | + assert ( |
| 1085 | + is_metric_subscription_allowed(Dataset.EventsAnalyticsPlatform.value, self.org) |
| 1086 | + is True |
| 1087 | + ) |
1075 | 1088 |
|
1076 | | - def test_performance_metrics_without_on_demand_feature(self, mock_metrics: MagicMock) -> None: |
1077 | | - with self.fake_features(set()): |
1078 | | - assert has_downgraded(Dataset.PerformanceMetrics.value, self.org) is True |
1079 | | - mock_metrics.incr.assert_called_with( |
1080 | | - "incidents.alert_rules.ignore_update_missing_on_demand" |
1081 | | - ) |
| 1089 | + # -- PerformanceMetrics -- |
1082 | 1090 |
|
1083 | | - def test_performance_metrics_with_on_demand_feature(self, mock_metrics: MagicMock) -> None: |
1084 | | - with self.fake_features({"organizations:on-demand-metrics-extraction"}): |
1085 | | - assert has_downgraded(Dataset.PerformanceMetrics.value, self.org) is False |
| 1091 | + def test_performance_metrics_without_on_demand(self) -> None: |
| 1092 | + with self.fake_features({"organizations:incidents"}): |
| 1093 | + assert ( |
| 1094 | + is_metric_subscription_allowed(Dataset.PerformanceMetrics.value, self.org) is False |
| 1095 | + ) |
1086 | 1096 |
|
1087 | | - def test_unknown_dataset_not_downgraded(self, mock_metrics: MagicMock) -> None: |
1088 | | - with self.fake_features(set()): |
1089 | | - assert has_downgraded("unknown_dataset", self.org) is False |
1090 | | - mock_metrics.incr.assert_called_with( |
1091 | | - "incidents.alert_rules.no_incidents_not_downgraded", |
1092 | | - sample_rate=1.0, |
1093 | | - tags={"dataset": "unknown_dataset"}, |
1094 | | - ) |
| 1097 | + def test_performance_metrics_with_both_features(self) -> None: |
| 1098 | + with self.fake_features( |
| 1099 | + {"organizations:incidents", "organizations:on-demand-metrics-extraction"} |
| 1100 | + ): |
| 1101 | + assert ( |
| 1102 | + is_metric_subscription_allowed(Dataset.PerformanceMetrics.value, self.org) is True |
| 1103 | + ) |
1095 | 1104 |
|
1096 | | - def test_no_incidents_not_downgraded_emits_metric(self, mock_metrics: MagicMock) -> None: |
1097 | | - with self.fake_features({"organizations:on-demand-metrics-extraction"}): |
1098 | | - assert has_downgraded(Dataset.PerformanceMetrics.value, self.org) is False |
1099 | | - mock_metrics.incr.assert_called_with( |
1100 | | - "incidents.alert_rules.no_incidents_not_downgraded", |
1101 | | - sample_rate=1.0, |
1102 | | - tags={"dataset": Dataset.PerformanceMetrics.value}, |
1103 | | - ) |
| 1105 | + # -- Unknown / other datasets -- |
| 1106 | + |
| 1107 | + def test_unknown_dataset_with_incidents(self) -> None: |
| 1108 | + with self.fake_features({"organizations:incidents"}): |
| 1109 | + assert is_metric_subscription_allowed("unknown_dataset", self.org) is True |
0 commit comments