Skip to content

Commit bfdee7b

Browse files
authored
fix(aci milestone 3): check for resolution condition in metric detector validator (#102922)
Verify on the backend that metric detectors have a resolution condition.
1 parent 424693e commit bfdee7b

File tree

4 files changed

+75
-7
lines changed

4 files changed

+75
-7
lines changed

src/sentry/incidents/metric_issue_detector.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,13 @@ def schedule_update_project_config(detector: Detector) -> None:
8282

8383
class MetricIssueComparisonConditionValidator(BaseDataConditionValidator):
8484
supported_conditions = frozenset(
85-
(Condition.GREATER, Condition.LESS, Condition.ANOMALY_DETECTION)
85+
(
86+
Condition.GREATER,
87+
Condition.LESS,
88+
Condition.GREATER_OR_EQUAL,
89+
Condition.LESS_OR_EQUAL,
90+
Condition.ANOMALY_DETECTION,
91+
)
8692
)
8793
supported_condition_results = frozenset(
8894
(DetectorPriorityLevel.HIGH, DetectorPriorityLevel.MEDIUM, DetectorPriorityLevel.OK)
@@ -132,6 +138,12 @@ def validate_conditions(self, value):
132138
MetricIssueComparisonConditionValidator(data=value, many=True).is_valid(
133139
raise_exception=True
134140
)
141+
if not any(
142+
condition["condition_result"] == DetectorPriorityLevel.OK for condition in value
143+
) and not any(condition["type"] == Condition.ANOMALY_DETECTION for condition in value):
144+
raise serializers.ValidationError(
145+
"Resolution condition required for metric issue detector."
146+
)
135147
return value
136148

137149

@@ -146,7 +158,7 @@ def validate(self, attrs):
146158

147159
if "condition_group" in attrs:
148160
conditions = attrs.get("condition_group", {}).get("conditions")
149-
if len(conditions) > 2:
161+
if len(conditions) > 3:
150162
raise serializers.ValidationError("Too many conditions")
151163

152164
return attrs

tests/sentry/incidents/endpoints/validators/test_validators.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,12 @@ def setUp(self) -> None:
161161
"conditionResult": DetectorPriorityLevel.HIGH,
162162
"conditionGroupId": self.data_condition_group.id,
163163
},
164+
{
165+
"type": Condition.LESS_OR_EQUAL,
166+
"comparison": 100,
167+
"conditionResult": DetectorPriorityLevel.OK,
168+
"conditionGroupId": self.data_condition_group.id,
169+
},
164170
],
165171
},
166172
"config": {
@@ -244,7 +250,7 @@ def test_create_with_valid_data(
244250

245251
# Verify conditions in DB
246252
conditions = list(DataCondition.objects.filter(condition_group=condition_group))
247-
assert len(conditions) == 1
253+
assert len(conditions) == 2
248254
condition = conditions[0]
249255
assert condition.type == Condition.GREATER
250256
assert condition.comparison == 100
@@ -399,6 +405,31 @@ def test_invalid_detector_type(self) -> None:
399405
)
400406
]
401407

408+
def test_no_resolution_condition(self) -> None:
409+
data = {
410+
**self.valid_data,
411+
"conditionGroup": {
412+
"id": self.data_condition_group.id,
413+
"organizationId": self.organization.id,
414+
"logicType": self.data_condition_group.logic_type,
415+
"conditions": [
416+
{
417+
"type": Condition.GREATER,
418+
"comparison": 100,
419+
"conditionResult": DetectorPriorityLevel.HIGH,
420+
"conditionGroupId": self.data_condition_group.id,
421+
},
422+
],
423+
},
424+
}
425+
validator = MetricIssueDetectorValidator(data=data, context=self.context)
426+
assert not validator.is_valid()
427+
assert validator.errors.get("conditionGroup", {}).get("conditions") == [
428+
ErrorDetail(
429+
string="Resolution condition required for metric issue detector.", code="invalid"
430+
)
431+
]
432+
402433
def test_too_many_conditions(self) -> None:
403434
data = {
404435
**self.valid_data,
@@ -425,6 +456,12 @@ def test_too_many_conditions(self) -> None:
425456
"conditionResult": DetectorPriorityLevel.HIGH,
426457
"conditionGroupId": self.data_condition_group.id,
427458
},
459+
{
460+
"type": Condition.LESS_OR_EQUAL,
461+
"comparison": 100,
462+
"conditionResult": DetectorPriorityLevel.OK,
463+
"conditionGroupId": self.data_condition_group.id,
464+
},
428465
],
429466
},
430467
}

tests/sentry/workflow_engine/endpoints/test_organization_detector_details.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ def setUp(self) -> None:
7979
comparison=50,
8080
condition_result=DetectorPriorityLevel.LOW,
8181
)
82+
self.resolve_condition = self.create_data_condition(
83+
condition_group=self.data_condition_group,
84+
type=Condition.GREATER_OR_EQUAL,
85+
comparison=50,
86+
condition_result=DetectorPriorityLevel.OK,
87+
)
8288
self.detector = self.create_detector(
8389
project_id=self.project.id,
8490
name="Test Detector",
@@ -180,6 +186,13 @@ def setUp(self) -> None:
180186
"conditionResult": DetectorPriorityLevel.HIGH,
181187
"conditionGroupId": self.condition.condition_group.id,
182188
},
189+
{
190+
"id": self.resolve_condition.id,
191+
"comparison": 100,
192+
"type": Condition.LESS_OR_EQUAL,
193+
"conditionResult": DetectorPriorityLevel.OK,
194+
"conditionGroupId": self.condition.condition_group.id,
195+
},
183196
],
184197
},
185198
"config": self.detector.config,
@@ -223,7 +236,7 @@ def test_update(self, mock_schedule_update_project_config: mock.MagicMock) -> No
223236
self.assert_condition_group_updated(condition_group)
224237

225238
conditions = list(DataCondition.objects.filter(condition_group=condition_group))
226-
assert len(conditions) == 1
239+
assert len(conditions) == 2
227240
condition = conditions[0]
228241
self.assert_data_condition_updated(condition)
229242

@@ -276,7 +289,7 @@ def test_update_add_data_condition(self) -> None:
276289
condition_group = detector.workflow_condition_group
277290
assert condition_group
278291
conditions = list(DataCondition.objects.filter(condition_group=condition_group))
279-
assert len(conditions) == 2
292+
assert len(conditions) == 3
280293

281294
def test_update_bad_schema(self) -> None:
282295
"""

tests/sentry/workflow_engine/endpoints/test_organization_detector_index.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -727,7 +727,13 @@ def setUp(self) -> None:
727727
"comparison": 100,
728728
"conditionResult": DetectorPriorityLevel.HIGH,
729729
"conditionGroupId": self.data_condition_group.id,
730-
}
730+
},
731+
{
732+
"type": Condition.LESS_OR_EQUAL,
733+
"comparison": 100,
734+
"conditionResult": DetectorPriorityLevel.OK,
735+
"conditionGroupId": self.data_condition_group.id,
736+
},
731737
],
732738
},
733739
"config": {
@@ -868,7 +874,7 @@ def test_valid_creation(
868874
assert condition_group.organization_id == self.organization.id
869875

870876
conditions = list(DataCondition.objects.filter(condition_group=condition_group))
871-
assert len(conditions) == 1
877+
assert len(conditions) == 2
872878
condition = conditions[0]
873879
assert condition.type == Condition.GREATER
874880
assert condition.comparison == 100

0 commit comments

Comments
 (0)