Browse Source

feat(issue-alerts): preview for tagged event filter (#41182)

Adds support for event tag filter for previews.
Andrew Xue 2 years ago
parent
commit
cbe17c5685

+ 21 - 5
src/sentry/rules/conditions/tagged_event.py

@@ -1,6 +1,6 @@
 from __future__ import annotations
 
-from typing import Any
+from typing import Any, Dict, Sequence, Tuple
 
 from django import forms
 
@@ -8,6 +8,7 @@ from sentry import tagstore
 from sentry.eventstore.models import GroupEvent
 from sentry.rules import MATCH_CHOICES, EventState, MatchType
 from sentry.rules.conditions.base import EventCondition
+from sentry.types.condition_activity import ConditionActivity
 
 
 class TaggedEventForm(forms.Form):  # type: ignore
@@ -38,7 +39,7 @@ class TaggedEventCondition(EventCondition):
         "value": {"type": "string", "placeholder": "value"},
     }
 
-    def passes(self, event: GroupEvent, state: EventState, **kwargs: Any) -> bool:
+    def _passes(self, raw_tags: Sequence[Tuple[str, Any]]) -> bool:
         key = self.get_option("key")
         match = self.get_option("match")
         value = self.get_option("value")
@@ -51,8 +52,8 @@ class TaggedEventCondition(EventCondition):
         tags = (
             k
             for gen in (
-                (k.lower() for k, v in event.tags),
-                (tagstore.get_standardized_key(k) for k, v in event.tags),
+                (k.lower() for k, v in raw_tags),
+                (tagstore.get_standardized_key(k) for k, v in raw_tags),
             )
             for k in gen
         )
@@ -70,7 +71,7 @@ class TaggedEventCondition(EventCondition):
 
         values = (
             v.lower()
-            for k, v in event.tags
+            for k, v in raw_tags
             if k.lower() == key or tagstore.get_standardized_key(k) == key
         )
 
@@ -124,6 +125,18 @@ class TaggedEventCondition(EventCondition):
 
         raise RuntimeError("Invalid Match")
 
+    def passes(self, event: GroupEvent, state: EventState, **kwargs: Any) -> bool:
+        return self._passes(event.tags)
+
+    def passes_activity(
+        self, condition_activity: ConditionActivity, event_map: Dict[str, Any]
+    ) -> bool:
+        try:
+            tags = event_map[condition_activity.data["event_id"]]["tags"]
+            return self._passes(tags.items())
+        except (TypeError, KeyError):
+            return False
+
     def render_label(self) -> str:
         data = {
             "key": self.data["key"],
@@ -131,3 +144,6 @@ class TaggedEventCondition(EventCondition):
             "match": MATCH_CHOICES[self.data["match"]],
         }
         return self.label.format(**data)
+
+    def get_event_columns(self) -> Sequence[str]:
+        return ["tags.key", "tags.value"]

+ 32 - 15
tests/sentry/rules/history/test_preview.py

@@ -40,6 +40,17 @@ class ProjectRulePreviewTest(TestCase):
             )
         return hours
 
+    def _set_up_event(self, data):
+        event = self.store_event(
+            project_id=self.project.id,
+            data={
+                "timestamp": iso_format(timezone.now() - timedelta(hours=1)),
+                **data,
+            },
+        )
+        event.group.update(first_seen=timezone.now() - timedelta(hours=1))
+        return event
+
     def _test_preview(self, condition, expected):
         conditions = [{"id": condition}]
         result = preview(self.project, conditions, [], "all", "all", 60)
@@ -166,22 +177,9 @@ class ProjectRulePreviewTest(TestCase):
         assert all(group not in result for group in n_plus_one)
 
     def test_level(self):
-        event = self.store_event(
-            project_id=self.project.id,
-            data={
-                "timestamp": iso_format(timezone.now() - timedelta(hours=1)),
-                "tags": {"level": "error"},
-            },
-        )
-        Activity.objects.create(
-            project=self.project,
-            group=event.group,
-            type=ActivityType.SET_REGRESSION.value,
-            datetime=timezone.now() - timedelta(hours=1),
-            data={"event_id": event.event_id},
-        )
+        event = self._set_up_event({"tags": {"level": "error"}})
 
-        conditions = [{"id": "sentry.rules.conditions.regression_event.RegressionEventCondition"}]
+        conditions = [{"id": "sentry.rules.conditions.first_seen_event.FirstSeenEventCondition"}]
         filters = [{"id": "sentry.rules.filters.level.LevelFilter", "level": "40", "match": "eq"}]
         results = preview(self.project, conditions, filters, "all", "all", 0)
         assert event.group in results
@@ -195,6 +193,25 @@ class ProjectRulePreviewTest(TestCase):
         results = preview(self.project, conditions, filters, "all", "all", 0)
         assert event.group in results
 
+    def test_tagged(self):
+        event = self._set_up_event({"tags": {"foo": "bar"}})
+        conditions = [{"id": "sentry.rules.conditions.first_seen_event.FirstSeenEventCondition"}]
+        filters = [
+            {
+                "id": "sentry.rules.filters.tagged_event.TaggedEventFilter",
+                "key": "foo",
+                "match": "eq",
+                "value": "bar",
+            }
+        ]
+
+        results = preview(self.project, conditions, filters, "all", "all", 0)
+        assert event.group in results
+
+        filters[0]["value"] = "baz"
+        results = preview(self.project, conditions, filters, "all", "all", 0)
+        assert event.group not in results
+
     def test_unsupported_conditions(self):
         self._set_up_first_seen()
         # conditions with no immediate plan to support