Files
2024-02-15 17:01:50 +00:00

315 lines
13 KiB
Python

import uuid
from datetime import timedelta
import pytest
from django.utils import timezone
from sentry.incidents.logic import CRITICAL_TRIGGER_LABEL
from sentry.incidents.models import IncidentStatus, IncidentTrigger
from sentry.integrations.metric_alerts import incident_attachment_info
from sentry.snuba.dataset import Dataset
from sentry.testutils.cases import BaseIncidentsTest, BaseMetricsTestCase, SnubaTestCase, TestCase
from sentry.testutils.helpers.datetime import freeze_time
from sentry.utils.dates import to_timestamp
pytestmark = pytest.mark.sentry_metrics
class IncidentAttachmentInfoTest(TestCase, BaseIncidentsTest):
def test_returns_correct_info(self):
alert_rule = self.create_alert_rule()
date_started = self.now
incident = self.create_incident(
self.organization,
title="Incident #1",
projects=[self.project],
alert_rule=alert_rule,
status=IncidentStatus.CLOSED.value,
date_started=date_started,
)
trigger = self.create_alert_rule_trigger(alert_rule, CRITICAL_TRIGGER_LABEL, 100)
self.create_alert_rule_trigger_action(
alert_rule_trigger=trigger, triggered_for_incident=incident
)
metric_value = 123
referrer = "metric_alert_custom"
notification_uuid = str(uuid.uuid4())
data = incident_attachment_info(
incident,
IncidentStatus.CLOSED,
metric_value,
notification_uuid=notification_uuid,
referrer=referrer,
)
assert data["title"] == f"Resolved: {alert_rule.name}"
assert data["status"] == "Resolved"
assert data["text"] == "123 events in the last 10 minutes"
assert data["ts"] == date_started
assert (
data["title_link"]
== f"http://testserver/organizations/baz/alerts/rules/details/{alert_rule.id}/?alert={incident.identifier}&referrer={referrer}&notification_uuid={notification_uuid}"
)
assert (
data["logo_url"]
== "http://testserver/_static/{version}/sentry/images/sentry-email-avatar.png"
)
def test_with_incident_trigger(self):
alert_rule = self.create_alert_rule()
now = self.now
date_started = now - timedelta(minutes=5)
event_date = now - timedelta(minutes=5)
self.create_event(event_date)
self.create_event(event_date)
self.create_event(event_date)
self.create_event(event_date)
incident = self.create_incident(
self.organization,
title="Incident #2",
projects=[self.project],
alert_rule=alert_rule,
status=IncidentStatus.CLOSED.value,
date_started=date_started,
query="",
)
trigger = self.create_alert_rule_trigger(alert_rule, CRITICAL_TRIGGER_LABEL, 100)
self.create_alert_rule_trigger_action(
alert_rule_trigger=trigger, triggered_for_incident=incident
)
incident_trigger = (
IncidentTrigger.objects.filter(incident=incident).order_by("-date_modified").first()
)
incident_trigger.update(date_modified=now)
# Test the trigger "firing"
data = incident_attachment_info(incident, IncidentStatus.CRITICAL)
assert data["title"] == "Critical: {}".format(
alert_rule.name
) # Pulls from trigger, not incident
assert data["status"] == "Critical" # Should pull from the action/trigger.
assert data["text"] == "4 events in the last 10 minutes"
assert data["ts"] == date_started
assert (
data["title_link"]
== f"http://testserver/organizations/baz/alerts/rules/details/{alert_rule.id}/?alert={incident.identifier}&referrer=metric_alert"
)
assert (
data["logo_url"]
== "http://testserver/_static/{version}/sentry/images/sentry-email-avatar.png"
)
# Test the trigger "resolving"
data = incident_attachment_info(incident, IncidentStatus.CLOSED)
assert data["title"] == f"Resolved: {alert_rule.name}"
assert data["status"] == "Resolved"
assert data["text"] == "4 events in the last 10 minutes"
assert data["ts"] == date_started
assert (
data["title_link"]
== f"http://testserver/organizations/baz/alerts/rules/details/{alert_rule.id}/?alert={incident.identifier}&referrer=metric_alert"
)
assert (
data["logo_url"]
== "http://testserver/_static/{version}/sentry/images/sentry-email-avatar.png"
)
# No trigger passed, uses incident as fallback
data = incident_attachment_info(incident, IncidentStatus.CLOSED)
assert data["title"] == f"Resolved: {alert_rule.name}"
assert data["status"] == "Resolved"
assert data["text"] == "4 events in the last 10 minutes"
assert data["ts"] == date_started
assert (
data["title_link"]
== f"http://testserver/organizations/baz/alerts/rules/details/{alert_rule.id}/?alert={incident.identifier}&referrer=metric_alert"
)
assert (
data["logo_url"]
== "http://testserver/_static/{version}/sentry/images/sentry-email-avatar.png"
)
def test_percent_change_alert(self):
# 1 hour comparison_delta
alert_rule = self.create_alert_rule(comparison_delta=60)
date_started = self.now
incident = self.create_incident(
self.organization,
title="Incident #1",
projects=[self.project],
alert_rule=alert_rule,
status=IncidentStatus.CLOSED.value,
date_started=date_started,
)
trigger = self.create_alert_rule_trigger(alert_rule, CRITICAL_TRIGGER_LABEL, 100)
self.create_alert_rule_trigger_action(
alert_rule_trigger=trigger, triggered_for_incident=incident
)
metric_value = 123.12
data = incident_attachment_info(incident, IncidentStatus.CRITICAL, metric_value)
assert (
data["text"]
== "Events 123% higher in the last 10 minutes compared to the same time one hour ago"
)
def test_percent_change_alert_custom_comparison_delta(self):
# 12 hour comparison_delta
alert_rule = self.create_alert_rule(comparison_delta=60 * 12)
date_started = self.now
incident = self.create_incident(
self.organization,
title="Incident #1",
projects=[self.project],
alert_rule=alert_rule,
status=IncidentStatus.CLOSED.value,
date_started=date_started,
)
trigger = self.create_alert_rule_trigger(alert_rule, CRITICAL_TRIGGER_LABEL, 100)
self.create_alert_rule_trigger_action(
alert_rule_trigger=trigger, triggered_for_incident=incident
)
metric_value = 123.12
data = incident_attachment_info(incident, IncidentStatus.CRITICAL, metric_value)
assert (
data["text"]
== "Events 123% higher in the last 10 minutes compared to the same time 720 minutes ago"
)
MOCK_NOW = timezone.now().replace(hour=13, minute=0, second=0, microsecond=0)
@freeze_time(MOCK_NOW)
class IncidentAttachmentInfoTestForCrashRateAlerts(TestCase, SnubaTestCase):
def setUp(self):
super().setUp()
self.now = timezone.now().replace(minute=0, second=0, microsecond=0)
self._5_min_ago = to_timestamp(self.now - timedelta(minutes=5))
self.date_started = self.now - timedelta(minutes=120)
def create_incident_and_related_objects(self, field="sessions"):
self.alert_rule = self.create_alert_rule(
query="",
aggregate=f"percentage({field}_crashed, {field}) AS _crash_rate_alert_aggregate",
dataset=Dataset.Sessions,
time_window=60,
)
self.incident = self.create_incident(
self.organization,
title="Incident #1",
projects=[self.project],
alert_rule=self.alert_rule,
status=IncidentStatus.CLOSED.value,
date_started=self.now - timedelta(minutes=120),
)
trigger = self.create_alert_rule_trigger(self.alert_rule, CRITICAL_TRIGGER_LABEL, 95)
self.action = self.create_alert_rule_trigger_action(
alert_rule_trigger=trigger, triggered_for_incident=self.incident
)
for _ in range(2):
self.store_session(self.build_session(status="exited", started=self._5_min_ago))
def test_with_incident_trigger_sessions(self):
self.create_incident_and_related_objects()
data = incident_attachment_info(self.incident, IncidentStatus.CRITICAL, 92)
assert data["title"] == f"Critical: {self.alert_rule.name}"
assert data["status"] == "Critical"
assert data["text"] == "92% sessions crash free rate in the last 60 minutes"
assert data["ts"] == self.date_started
assert (
data["logo_url"]
== "http://testserver/_static/{version}/sentry/images/sentry-email-avatar.png"
)
def test_with_incident_trigger_sessions_resolve(self):
self.create_incident_and_related_objects()
data = incident_attachment_info(self.incident, IncidentStatus.CLOSED)
assert data["title"] == f"Resolved: {self.alert_rule.name}"
assert data["status"] == "Resolved"
assert data["text"] == "100.0% sessions crash free rate in the last 60 minutes"
assert data["ts"] == self.date_started
assert (
data["logo_url"]
== "http://testserver/_static/{version}/sentry/images/sentry-email-avatar.png"
)
def test_with_incident_trigger_users(self):
self.create_incident_and_related_objects(field="users")
data = incident_attachment_info(self.incident, IncidentStatus.CRITICAL, 92)
assert data["title"] == f"Critical: {self.alert_rule.name}"
assert data["status"] == "Critical"
assert data["text"] == "92% users crash free rate in the last 60 minutes"
assert data["ts"] == self.date_started
assert (
data["logo_url"]
== "http://testserver/_static/{version}/sentry/images/sentry-email-avatar.png"
)
def test_with_incident_trigger_users_resolve(self):
self.create_incident_and_related_objects(field="users")
data = incident_attachment_info(self.incident, IncidentStatus.CLOSED)
assert data["title"] == f"Resolved: {self.alert_rule.name}"
assert data["status"] == "Resolved"
assert data["text"] == "100.0% users crash free rate in the last 60 minutes"
assert data["ts"] == self.date_started
assert (
data["logo_url"]
== "http://testserver/_static/{version}/sentry/images/sentry-email-avatar.png"
)
def test_with_incident_where_no_sessions_exist(self):
alert_rule = self.create_alert_rule(
query="",
aggregate="percentage(sessions_crashed, sessions) AS _crash_rate_alert_aggregate",
dataset=Dataset.Sessions,
time_window=60,
)
trigger = self.create_alert_rule_trigger(alert_rule, CRITICAL_TRIGGER_LABEL, 95)
incident = self.create_incident(
self.organization,
title="Incident #2",
projects=[self.project],
alert_rule=alert_rule,
status=IncidentStatus.CLOSED.value,
date_started=self.now,
)
self.create_alert_rule_trigger_action(
alert_rule_trigger=trigger, triggered_for_incident=incident
)
data = incident_attachment_info(incident, IncidentStatus.CRITICAL)
assert data["title"] == f"Critical: {alert_rule.name}"
assert data["status"] == "Critical"
assert data["text"] == "No sessions crash free rate in the last 60 minutes"
@freeze_time(MOCK_NOW)
class IncidentAttachmentInfoTestForMetricsCrashRateAlerts(
IncidentAttachmentInfoTestForCrashRateAlerts, BaseMetricsTestCase
):
def create_incident_and_related_objects(self, field="sessions"):
self.alert_rule = self.create_alert_rule(
query="",
aggregate=f"percentage({field}_crashed, {field}) AS _crash_rate_alert_aggregate",
dataset=Dataset.Metrics,
time_window=60,
)
self.incident = self.create_incident(
self.organization,
title="Incident #1",
projects=[self.project],
alert_rule=self.alert_rule,
status=IncidentStatus.CLOSED.value,
date_started=self.now - timedelta(minutes=120),
)
trigger = self.create_alert_rule_trigger(self.alert_rule, CRITICAL_TRIGGER_LABEL, 95)
self.action = self.create_alert_rule_trigger_action(
alert_rule_trigger=trigger, triggered_for_incident=self.incident
)
for _ in range(2):
self.store_session(self.build_session(status="exited", started=self._5_min_ago))