|
27 | 27 | from sentry.testutils.cases import BaseMetricsLayerTestCase, SnubaTestCase, TestCase |
28 | 28 | from sentry.testutils.helpers.datetime import freeze_time |
29 | 29 | from sentry.testutils.helpers.features import with_feature |
| 30 | +from sentry.testutils.helpers.options import override_options |
30 | 31 |
|
31 | 32 | MOCK_DATETIME = (timezone.now() - timedelta(days=1)).replace( |
32 | 33 | hour=0, minute=0, second=0, microsecond=0 |
@@ -167,6 +168,43 @@ def test_simple_one_org_one_project_task_target_sample_rate(self) -> None: |
167 | 168 | ) |
168 | 169 | assert (sample_rate, got_value) == (0.5, True) |
169 | 170 |
|
| 171 | + @with_feature(["organizations:dynamic-sampling", "organizations:dynamic-sampling-custom"]) |
| 172 | + def test_per_project_sample_rate_override(self) -> None: |
| 173 | + # A per-project override configured via options hard-replaces the rate the |
| 174 | + # custom dynamic sampling path would otherwise resolve for that project -- |
| 175 | + # winning even over the recently-added 100% boost -- and leaves other projects |
| 176 | + # untouched. |
| 177 | + org1 = self.create_organization("am3-override-org") |
| 178 | + org1.update_option("sentry:sampling_mode", DynamicSamplingMode.ORGANIZATION) |
| 179 | + org1.update_option("sentry:target_sample_rate", 0.5) |
| 180 | + overridden = self.create_project(organization=org1) |
| 181 | + normal = self.create_project(organization=org1) |
| 182 | + |
| 183 | + # Baseline: freshly-created projects are boosted to 1.0 by the recently-added |
| 184 | + # rule, so neither resolves to the org target yet. |
| 185 | + assert get_guarded_project_sample_rate(org1, overridden) == 1.0 |
| 186 | + |
| 187 | + with override_options( |
| 188 | + {"dynamic-sampling.sample-rate-override-per-project": {str(overridden.id): 0.9}} |
| 189 | + ): |
| 190 | + assert get_guarded_project_sample_rate(org1, overridden) == 0.9 |
| 191 | + # Not in the override map -> unaffected by the override. |
| 192 | + assert get_guarded_project_sample_rate(org1, normal) == 1.0 |
| 193 | + |
| 194 | + @with_feature(["organizations:dynamic-sampling", "organizations:dynamic-sampling-custom"]) |
| 195 | + def test_per_project_sample_rate_override_ignores_out_of_range(self) -> None: |
| 196 | + org1 = self.create_organization("am3-override-org-bad") |
| 197 | + org1.update_option("sentry:sampling_mode", DynamicSamplingMode.ORGANIZATION) |
| 198 | + org1.update_option("sentry:target_sample_rate", 0.5) |
| 199 | + project = self.create_project(organization=org1) |
| 200 | + |
| 201 | + baseline = get_guarded_project_sample_rate(org1, project) |
| 202 | + with override_options( |
| 203 | + {"dynamic-sampling.sample-rate-override-per-project": {str(project.id): 2.0}} |
| 204 | + ): |
| 205 | + # Out-of-range override is ignored; the resolved rate is unchanged. |
| 206 | + assert get_guarded_project_sample_rate(org1, project) == baseline |
| 207 | + |
170 | 208 | @with_feature(["organizations:dynamic-sampling", "organizations:dynamic-sampling-custom"]) |
171 | 209 | def test_project_mode_sampling_with_query(self) -> None: |
172 | 210 | org1 = self.create_organization("test-org") |
|
0 commit comments