mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-09-29 22:34:33 +00:00
171 lines
6.5 KiB
Python
171 lines
6.5 KiB
Python
from __future__ import annotations
|
|
|
|
from time import time
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
from sentry.event_manager import EventManager
|
|
from sentry.grouping.ingest import (
|
|
_calculate_background_grouping,
|
|
_calculate_event_grouping,
|
|
_calculate_secondary_hash,
|
|
)
|
|
from sentry.models.group import Group
|
|
from sentry.testutils.cases import TestCase
|
|
from sentry.testutils.silo import region_silo_test
|
|
from sentry.testutils.skips import requires_snuba
|
|
|
|
pytestmark = [requires_snuba]
|
|
|
|
|
|
@region_silo_test
|
|
class BackgroundGroupingTest(TestCase):
|
|
@patch(
|
|
"sentry.grouping.ingest._calculate_background_grouping",
|
|
wraps=_calculate_background_grouping,
|
|
)
|
|
def test_applies_background_grouping(self, mock_calc_background_grouping: MagicMock) -> None:
|
|
manager = EventManager({"message": "foo 123"})
|
|
manager.normalize()
|
|
manager.save(self.project.id)
|
|
|
|
assert mock_calc_background_grouping.call_count == 0
|
|
|
|
with self.options(
|
|
{
|
|
"store.background-grouping-config-id": "mobile:2021-02-12",
|
|
"store.background-grouping-sample-rate": 1.0,
|
|
}
|
|
):
|
|
manager.save(self.project.id)
|
|
|
|
assert mock_calc_background_grouping.call_count == 1
|
|
|
|
@patch("sentry_sdk.capture_exception")
|
|
def test_handles_errors_with_background_grouping(
|
|
self, mock_capture_exception: MagicMock
|
|
) -> None:
|
|
background_grouping_error = Exception("nope")
|
|
|
|
with patch(
|
|
"sentry.grouping.ingest._calculate_background_grouping",
|
|
side_effect=background_grouping_error,
|
|
):
|
|
manager = EventManager({"message": "foo 123"})
|
|
manager.normalize()
|
|
event = manager.save(self.project.id)
|
|
|
|
with self.options(
|
|
{
|
|
"store.background-grouping-config-id": "mobile:2021-02-12",
|
|
"store.background-grouping-sample-rate": 1.0,
|
|
}
|
|
):
|
|
manager.save(self.project.id)
|
|
|
|
mock_capture_exception.assert_called_with(background_grouping_error)
|
|
# This proves the background grouping crash didn't crash the overall grouping process
|
|
assert event.group
|
|
|
|
@patch("sentry.grouping.ingest._calculate_background_grouping")
|
|
def test_background_grouping_can_be_disabled_via_sample_rate(
|
|
self, mock_calc_background_grouping: MagicMock
|
|
) -> None:
|
|
manager = EventManager({"message": "foo 123"})
|
|
manager.normalize()
|
|
manager.save(self.project.id)
|
|
|
|
assert mock_calc_background_grouping.call_count == 0
|
|
|
|
with self.options(
|
|
{
|
|
"store.background-grouping-config-id": "mobile:2021-02-12",
|
|
"store.background-grouping-sample-rate": 0.0,
|
|
}
|
|
):
|
|
manager.save(self.project.id)
|
|
|
|
manager.save(self.project.id)
|
|
|
|
assert mock_calc_background_grouping.call_count == 0
|
|
|
|
|
|
@region_silo_test
|
|
class SecondaryGroupingTest(TestCase):
|
|
def test_applies_secondary_grouping(self):
|
|
project = self.project
|
|
project.update_option("sentry:grouping_config", "legacy:2019-03-12")
|
|
|
|
timestamp = time()
|
|
manager = EventManager({"message": "foo 123", "timestamp": timestamp})
|
|
manager.normalize()
|
|
event = manager.save(project.id)
|
|
|
|
project.update_option("sentry:grouping_config", "newstyle:2023-01-11")
|
|
project.update_option("sentry:secondary_grouping_config", "legacy:2019-03-12")
|
|
project.update_option("sentry:secondary_grouping_expiry", timestamp + 3600)
|
|
|
|
# Switching to newstyle grouping changes the hash because now '123' will be parametrized
|
|
manager = EventManager({"message": "foo 123", "timestamp": timestamp + 2.0})
|
|
manager.normalize()
|
|
# We need `self.tasks` here because updating group metadata normally happens async
|
|
with self.tasks():
|
|
event2 = manager.save(project.id)
|
|
|
|
# Make sure that events did get into same group because of fallback grouping, not because of
|
|
# hashes which come from primary grouping only
|
|
assert not set(event.get_hashes().hashes) & set(event2.get_hashes().hashes)
|
|
assert event.group_id == event2.group_id
|
|
|
|
group = Group.objects.get(id=event.group_id)
|
|
|
|
assert group.times_seen == 2
|
|
assert group.last_seen == event2.datetime
|
|
assert group.message == event2.message
|
|
assert group.data.get("type") == "default"
|
|
assert group.data.get("metadata").get("title") == "foo 123"
|
|
|
|
# After expiry, new events are still assigned to the same group
|
|
project.update_option("sentry:secondary_grouping_expiry", 0)
|
|
manager = EventManager({"message": "foo 123"})
|
|
manager.normalize()
|
|
|
|
with self.tasks():
|
|
event3 = manager.save(project.id)
|
|
assert event3.group_id == event2.group_id
|
|
|
|
@patch("sentry_sdk.capture_exception")
|
|
@patch("sentry.grouping.ingest._calculate_secondary_hash", wraps=_calculate_secondary_hash)
|
|
def test_handles_errors_with_secondary_grouping(
|
|
self,
|
|
mock_calculate_secondary_hash: MagicMock,
|
|
mock_capture_exception: MagicMock,
|
|
) -> None:
|
|
secondary_grouping_error = Exception("nope")
|
|
secondary_grouping_config = "legacy:2019-03-12"
|
|
|
|
def mock_calculate_event_grouping(project, event, grouping_config):
|
|
# We only want `_calculate_event_grouping` to error inside of `_calculate_secondary_hash`,
|
|
# not anywhere else it's called
|
|
if grouping_config["id"] == secondary_grouping_config:
|
|
raise secondary_grouping_error
|
|
else:
|
|
return _calculate_event_grouping(project, event, grouping_config)
|
|
|
|
project = self.project
|
|
project.update_option("sentry:grouping_config", "newstyle:2023-01-11")
|
|
project.update_option("sentry:secondary_grouping_config", secondary_grouping_config)
|
|
project.update_option("sentry:secondary_grouping_expiry", time() + 3600)
|
|
|
|
with patch(
|
|
"sentry.grouping.ingest._calculate_event_grouping",
|
|
wraps=mock_calculate_event_grouping,
|
|
):
|
|
manager = EventManager({"message": "foo 123"})
|
|
manager.normalize()
|
|
event = manager.save(self.project.id)
|
|
|
|
assert mock_calculate_secondary_hash.call_count == 1
|
|
mock_capture_exception.assert_called_with(secondary_grouping_error)
|
|
# This proves the secondary grouping crash didn't crash the overall grouping process
|
|
assert event.group
|