|
1 |
| -from datetime import UTC, datetime, timedelta |
2 |
| - |
3 | 1 | from sentry.incidents.grouptype import MetricIssueDetectorHandler
|
4 |
| -from sentry.incidents.utils.constants import INCIDENTS_SNUBA_SUBSCRIPTION_TYPE |
5 |
| -from sentry.incidents.utils.types import QuerySubscriptionUpdate |
6 | 2 | from sentry.issues.issue_occurrence import IssueOccurrence
|
7 |
| -from sentry.snuba.dataset import Dataset |
8 |
| -from sentry.snuba.models import SnubaQuery, SnubaQueryEventType |
9 |
| -from sentry.snuba.subscriptions import create_snuba_query, create_snuba_subscription |
10 | 3 | from sentry.testutils.helpers.datetime import freeze_time
|
11 |
| -from sentry.workflow_engine.models import DataCondition, DataPacket |
| 4 | +from sentry.workflow_engine.models import DataCondition |
12 | 5 | from sentry.workflow_engine.models.data_condition import Condition
|
13 |
| -from sentry.workflow_engine.types import ( |
14 |
| - DetectorEvaluationResult, |
15 |
| - DetectorGroupKey, |
16 |
| - DetectorPriorityLevel, |
17 |
| -) |
18 |
| -from tests.sentry.workflow_engine.handlers.detector.test_base import BaseDetectorHandlerTest |
| 6 | +from tests.sentry.incidents.utils.test_metric_issue_base import BaseMetricIssueTest |
19 | 7 |
|
20 | 8 |
|
21 | 9 | @freeze_time()
|
22 |
| -class TestEvaluateMetricDetector(BaseDetectorHandlerTest): |
| 10 | +class TestEvaluateMetricDetector(BaseMetricIssueTest): |
23 | 11 | def setUp(self):
|
24 | 12 | super().setUp()
|
25 |
| - self.detector_group_key = None |
26 |
| - self.detector = self.create_detector( |
27 |
| - project=self.project, |
28 |
| - workflow_condition_group=self.create_data_condition_group(), |
29 |
| - type="handler_with_state", |
30 |
| - created_by_id=self.user.id, |
31 |
| - ) |
32 |
| - self.critical_detector_trigger = self.create_data_condition( |
33 |
| - type=Condition.GREATER, |
34 |
| - comparison=5, |
35 |
| - condition_result=DetectorPriorityLevel.HIGH, |
36 |
| - condition_group=self.detector.workflow_condition_group, |
37 |
| - ) |
38 |
| - self.warning_detector_trigger = self.create_data_condition( |
39 |
| - comparison=3, |
40 |
| - type=Condition.GREATER, |
41 |
| - condition_result=DetectorPriorityLevel.MEDIUM, |
42 |
| - condition_group=self.detector.workflow_condition_group, |
43 |
| - ) |
44 |
| - with self.tasks(): |
45 |
| - self.snuba_query = create_snuba_query( |
46 |
| - query_type=SnubaQuery.Type.ERROR, |
47 |
| - dataset=Dataset.Events, |
48 |
| - query="hello", |
49 |
| - aggregate="count()", |
50 |
| - time_window=timedelta(minutes=1), |
51 |
| - resolution=timedelta(minutes=1), |
52 |
| - environment=self.environment, |
53 |
| - event_types=[SnubaQueryEventType.EventType.ERROR], |
54 |
| - ) |
55 |
| - self.query_subscription = create_snuba_subscription( |
56 |
| - project=self.detector.project, |
57 |
| - subscription_type=INCIDENTS_SNUBA_SUBSCRIPTION_TYPE, |
58 |
| - snuba_query=self.snuba_query, |
59 |
| - ) |
60 |
| - self.alert_rule = self.create_alert_rule() |
61 |
| - self.create_alert_rule_detector(alert_rule_id=self.alert_rule.id, detector=self.detector) |
62 |
| - |
63 | 13 | self.handler = MetricIssueDetectorHandler(self.detector)
|
64 | 14 |
|
65 | 15 | def generate_evidence_data(
|
@@ -93,100 +43,68 @@ def generate_evidence_data(
|
93 | 43 | )
|
94 | 44 | return evidence_data
|
95 | 45 |
|
96 |
| - def test_metric_issue_occurrence(self): |
97 |
| - value = self.critical_detector_trigger.comparison + 1 |
98 |
| - packet = QuerySubscriptionUpdate( |
99 |
| - entity="entity", |
100 |
| - subscription_id=str(self.query_subscription.id), |
101 |
| - values={"value": value}, |
102 |
| - timestamp=datetime.now(UTC), |
103 |
| - ) |
104 |
| - data_packet = DataPacket[QuerySubscriptionUpdate]( |
105 |
| - source_id=str(self.query_subscription.id), packet=packet |
106 |
| - ) |
107 |
| - evidence_data = self.generate_evidence_data( |
108 |
| - value, self.critical_detector_trigger, self.warning_detector_trigger |
109 |
| - ) |
110 |
| - |
111 |
| - result: dict[DetectorGroupKey, DetectorEvaluationResult] = self.handler.evaluate( |
112 |
| - data_packet |
113 |
| - ) |
114 |
| - evaluation_result: DetectorEvaluationResult = result[self.detector_group_key] |
115 |
| - assert isinstance(evaluation_result.result, IssueOccurrence) |
116 |
| - occurrence: IssueOccurrence = evaluation_result.result |
117 |
| - |
| 46 | + def verify_issue_occurrence( |
| 47 | + self, occurrence: IssueOccurrence, evidence_data: dict, detector_trigger: DataCondition |
| 48 | + ) -> None: |
118 | 49 | assert occurrence is not None
|
119 | 50 | assert occurrence.issue_title == self.detector.name
|
120 | 51 | assert occurrence.subtitle == self.handler.construct_title(
|
121 | 52 | snuba_query=self.snuba_query,
|
122 |
| - detector_trigger=self.critical_detector_trigger, |
123 |
| - priority=self.critical_detector_trigger.condition_result, |
| 53 | + detector_trigger=detector_trigger, |
| 54 | + priority=detector_trigger.condition_result, |
124 | 55 | )
|
125 | 56 | assert occurrence.evidence_data == evidence_data
|
126 | 57 | assert occurrence.level == "error"
|
127 |
| - assert occurrence.priority == self.critical_detector_trigger.condition_result |
| 58 | + assert occurrence.priority == detector_trigger.condition_result |
128 | 59 | assert occurrence.assignee
|
129 | 60 | assert occurrence.assignee.id == self.detector.created_by_id
|
130 | 61 |
|
| 62 | + def test_metric_issue_occurrence(self): |
| 63 | + value = self.critical_detector_trigger.comparison + 1 |
| 64 | + data_packet = self.create_subscription_packet(value) |
| 65 | + evidence_data = self.generate_evidence_data( |
| 66 | + value, self.critical_detector_trigger, self.warning_detector_trigger |
| 67 | + ) |
| 68 | + |
| 69 | + occurrence = self.process_packet_and_return_result(data_packet) |
| 70 | + assert isinstance(occurrence, IssueOccurrence) |
| 71 | + |
| 72 | + self.verify_issue_occurrence(occurrence, evidence_data, self.critical_detector_trigger) |
| 73 | + |
131 | 74 | def test_warning_level(self):
|
132 | 75 | value = self.warning_detector_trigger.comparison + 1
|
133 |
| - packet = QuerySubscriptionUpdate( |
134 |
| - entity="entity", |
135 |
| - subscription_id=str(self.query_subscription.id), |
136 |
| - values={"value": value}, |
137 |
| - timestamp=datetime.now(UTC), |
138 |
| - ) |
139 |
| - data_packet = DataPacket[QuerySubscriptionUpdate]( |
140 |
| - source_id=str(self.query_subscription.id), packet=packet |
141 |
| - ) |
| 76 | + data_packet = self.create_subscription_packet(value) |
142 | 77 | evidence_data = self.generate_evidence_data(value, self.warning_detector_trigger)
|
143 | 78 |
|
144 |
| - result: dict[DetectorGroupKey, DetectorEvaluationResult] = self.handler.evaluate( |
145 |
| - data_packet |
146 |
| - ) |
147 |
| - evaluation_result: DetectorEvaluationResult = result[self.detector_group_key] |
148 |
| - assert isinstance(evaluation_result.result, IssueOccurrence) |
149 |
| - occurrence: IssueOccurrence = evaluation_result.result |
| 79 | + occurrence = self.process_packet_and_return_result(data_packet) |
| 80 | + assert isinstance(occurrence, IssueOccurrence) |
150 | 81 |
|
151 |
| - assert occurrence is not None |
152 |
| - assert occurrence.issue_title == self.detector.name |
153 |
| - assert occurrence.subtitle == self.handler.construct_title( |
154 |
| - snuba_query=self.snuba_query, |
155 |
| - detector_trigger=self.warning_detector_trigger, |
156 |
| - priority=self.warning_detector_trigger.condition_result, |
157 |
| - ) |
158 |
| - assert occurrence.evidence_data == evidence_data |
159 |
| - assert occurrence.level == "error" |
160 |
| - assert occurrence.priority == self.warning_detector_trigger.condition_result |
| 82 | + self.verify_issue_occurrence(occurrence, evidence_data, self.warning_detector_trigger) |
161 | 83 |
|
162 | 84 | def test_does_not_trigger(self):
|
163 | 85 | value = self.warning_detector_trigger.comparison - 1
|
164 |
| - packet = QuerySubscriptionUpdate( |
165 |
| - entity="entity", |
166 |
| - subscription_id=str(self.query_subscription.id), |
167 |
| - values={"value": value}, |
168 |
| - timestamp=datetime.now(UTC), |
169 |
| - ) |
170 |
| - data_packet = DataPacket[QuerySubscriptionUpdate]( |
171 |
| - source_id=str(self.query_subscription.id), packet=packet |
172 |
| - ) |
173 |
| - result = self.handler.evaluate(data_packet) |
174 |
| - assert result == {} |
| 86 | + data_packet = self.create_subscription_packet(value) |
| 87 | + result = self.process_packet_and_return_result(data_packet) |
| 88 | + assert result is None |
175 | 89 |
|
176 | 90 | def test_missing_detector_trigger(self):
|
177 | 91 | value = self.critical_detector_trigger.comparison + 1
|
178 |
| - packet = QuerySubscriptionUpdate( |
179 |
| - entity="entity", |
180 |
| - subscription_id=str(self.query_subscription.id), |
181 |
| - values={"value": value}, |
182 |
| - timestamp=datetime.now(UTC), |
183 |
| - ) |
184 |
| - data_packet = DataPacket[QuerySubscriptionUpdate]( |
185 |
| - source_id=str(self.query_subscription.id), packet=packet |
186 |
| - ) |
| 92 | + data_packet = self.create_subscription_packet(value) |
187 | 93 | DataCondition.objects.all().delete()
|
188 |
| - result = self.handler.evaluate(data_packet) |
189 |
| - assert result == {} |
| 94 | + result = self.process_packet_and_return_result(data_packet) |
| 95 | + assert result is None |
| 96 | + |
| 97 | + def test_flipped_detector_trigger(self): |
| 98 | + self.warning_detector_trigger.delete() |
| 99 | + self.critical_detector_trigger.update(type=Condition.LESS) |
| 100 | + value = self.critical_detector_trigger.comparison - 1 |
| 101 | + data_packet = self.create_subscription_packet(value) |
| 102 | + evidence_data = self.generate_evidence_data(value, self.critical_detector_trigger) |
| 103 | + |
| 104 | + occurrence = self.process_packet_and_return_result(data_packet) |
| 105 | + assert isinstance(occurrence, IssueOccurrence) |
| 106 | + |
| 107 | + self.verify_issue_occurrence(occurrence, evidence_data, self.critical_detector_trigger) |
190 | 108 |
|
191 | 109 |
|
192 | 110 | class TestConstructTitle(TestEvaluateMetricDetector):
|
|
0 commit comments