|
@@ -4,7 +4,7 @@ from datetime import UTC, datetime, timedelta
|
|
|
from random import choice
|
|
|
from string import ascii_uppercase
|
|
|
from typing import Any
|
|
|
-from unittest.mock import call, patch
|
|
|
+from unittest.mock import ANY, call, patch
|
|
|
|
|
|
import pytest
|
|
|
from django.conf import settings
|
|
@@ -177,10 +177,16 @@ class TestBackfillSeerGroupingRecords(SnubaTestCase, TestCase):
|
|
|
assert group_data == expected_group_data
|
|
|
assert stacktrace_string == EXCEPTION_STACKTRACE_STRING
|
|
|
|
|
|
- @patch("sentry.tasks.backfill_seer_grouping_records.lookup_event")
|
|
|
+ @patch("time.sleep", return_value=None)
|
|
|
@patch("sentry.tasks.backfill_seer_grouping_records.logger")
|
|
|
- def test_lookup_group_data_stacktrace_single_exceptions(self, mock_logger, mock_lookup_event):
|
|
|
- """Test cases where ServiceUnavailable and DeadlineExceeded exceptions occur"""
|
|
|
+ @patch("sentry.tasks.backfill_seer_grouping_records.lookup_event")
|
|
|
+ def test_lookup_group_data_stacktrace_single_exceptions(
|
|
|
+ self, mock_lookup_event, mock_logger, mock_sleep
|
|
|
+ ):
|
|
|
+ """
|
|
|
+ Test when ServiceUnavailable and DeadlineExceeded exceptions occur, that we stop the
|
|
|
+ backfill
|
|
|
+ """
|
|
|
exceptions = [
|
|
|
ServiceUnavailable(message="Service Unavailable"),
|
|
|
DeadlineExceeded(message="Deadline Exceeded"),
|
|
@@ -189,24 +195,24 @@ class TestBackfillSeerGroupingRecords(SnubaTestCase, TestCase):
|
|
|
|
|
|
for exception in exceptions:
|
|
|
mock_lookup_event.side_effect = exception
|
|
|
- group_data, stacktrace_string = lookup_group_data_stacktrace_single(
|
|
|
- self.project,
|
|
|
- event.event_id,
|
|
|
- event.group_id,
|
|
|
- event.group.message,
|
|
|
- self.group_hashes[event.group.id],
|
|
|
- )
|
|
|
- assert (group_data, stacktrace_string) == (None, "")
|
|
|
- mock_logger.exception.assert_called_with(
|
|
|
- "tasks.backfill_seer_grouping_records.event_lookup_exception",
|
|
|
- extra={
|
|
|
- "organization_id": self.project.organization.id,
|
|
|
- "project_id": self.project.id,
|
|
|
- "group_id": event.group.id,
|
|
|
- "event_id": event.event_id,
|
|
|
- "error": exception.message,
|
|
|
- },
|
|
|
- )
|
|
|
+ with pytest.raises(Exception):
|
|
|
+ lookup_group_data_stacktrace_single(
|
|
|
+ self.project,
|
|
|
+ event.event_id,
|
|
|
+ event.group_id,
|
|
|
+ event.group.message,
|
|
|
+ self.group_hashes[event.group.id],
|
|
|
+ )
|
|
|
+ mock_logger.exception.assert_called_with(
|
|
|
+ "tasks.backfill_seer_grouping_records.event_lookup_exception",
|
|
|
+ extra={
|
|
|
+ "organization_id": self.project.organization.id,
|
|
|
+ "project_id": self.project.id,
|
|
|
+ "group_id": event.group.id,
|
|
|
+ "event_id": event.event_id,
|
|
|
+ "error": exception.message,
|
|
|
+ },
|
|
|
+ )
|
|
|
|
|
|
def test_lookup_group_data_stacktrace_single_not_stacktrace_grouping(self):
|
|
|
"""Test that no data is returned if the group did not use the stacktrace to determine grouping"""
|
|
@@ -264,14 +270,14 @@ class TestBackfillSeerGroupingRecords(SnubaTestCase, TestCase):
|
|
|
)
|
|
|
|
|
|
@patch("time.sleep", return_value=None)
|
|
|
- @patch("sentry.nodestore.backend.get_multi")
|
|
|
@patch("sentry.tasks.backfill_seer_grouping_records.logger")
|
|
|
+ @patch("sentry.nodestore.backend.get_multi")
|
|
|
def test_lookup_group_data_stacktrace_bulk_exceptions(
|
|
|
- self, mock_logger, mock_get_multi, mock_sleep
|
|
|
+ self, mock_get_multi, mock_logger, mock_sleep
|
|
|
):
|
|
|
"""
|
|
|
Test cases where ServiceUnavailable or DeadlineExceeded exceptions occur in bulk data
|
|
|
- lookup
|
|
|
+ lookup, that the backfill stops
|
|
|
"""
|
|
|
exceptions = [
|
|
|
ServiceUnavailable(message="Service Unavailable"),
|
|
@@ -281,24 +287,17 @@ class TestBackfillSeerGroupingRecords(SnubaTestCase, TestCase):
|
|
|
|
|
|
for exception in exceptions:
|
|
|
mock_get_multi.side_effect = exception
|
|
|
- (
|
|
|
- bulk_event_ids,
|
|
|
- invalid_event_ids,
|
|
|
- bulk_group_data_stacktraces,
|
|
|
- ) = lookup_group_data_stacktrace_bulk(self.project, rows, messages, self.group_hashes)
|
|
|
- assert bulk_event_ids == set()
|
|
|
- assert invalid_event_ids == set()
|
|
|
- assert bulk_group_data_stacktraces["data"] == []
|
|
|
- assert bulk_group_data_stacktraces["stacktrace_list"] == []
|
|
|
- mock_logger.exception.assert_called_with(
|
|
|
- "tasks.backfill_seer_grouping_records.bulk_event_lookup_exception",
|
|
|
- extra={
|
|
|
- "organization_id": self.project.organization.id,
|
|
|
- "project_id": self.project.id,
|
|
|
- "group_data": json.dumps(rows),
|
|
|
- "error": exception.message,
|
|
|
- },
|
|
|
- )
|
|
|
+ with pytest.raises(Exception):
|
|
|
+ lookup_group_data_stacktrace_bulk(self.project, rows, messages, self.group_hashes)
|
|
|
+ mock_logger.exception.assert_called_with(
|
|
|
+ "tasks.backfill_seer_grouping_records.bulk_event_lookup_exception",
|
|
|
+ extra={
|
|
|
+ "organization_id": self.project.organization.id,
|
|
|
+ "project_id": self.project.id,
|
|
|
+ "group_data": json.dumps(rows),
|
|
|
+ "error": exception.message,
|
|
|
+ },
|
|
|
+ )
|
|
|
|
|
|
def test_lookup_group_data_stacktrace_bulk_not_stacktrace_grouping(self):
|
|
|
"""
|
|
@@ -697,7 +696,7 @@ class TestBackfillSeerGroupingRecords(SnubaTestCase, TestCase):
|
|
|
self, mock_post_bulk_grouping_records
|
|
|
):
|
|
|
"""
|
|
|
- Test that different metadata is set for groups where times_seen > 1 and times_seen == 1.
|
|
|
+ Test that groups where times_seen == 1 are not included.
|
|
|
"""
|
|
|
mock_post_bulk_grouping_records.return_value = {"success": True, "groups_with_neighbor": {}}
|
|
|
|
|
@@ -725,7 +724,7 @@ class TestBackfillSeerGroupingRecords(SnubaTestCase, TestCase):
|
|
|
"request_hash": self.group_hashes[group.id],
|
|
|
}
|
|
|
else:
|
|
|
- assert group.data["metadata"].get("seer_similarity") == {"times_seen_once": True}
|
|
|
+ assert group.data["metadata"].get("seer_similarity") is None
|
|
|
|
|
|
redis_client = redis.redis_clusters.get(settings.SENTRY_MONITORS_REDIS_CLUSTER)
|
|
|
last_processed_index = int(redis_client.get(make_backfill_redis_key(self.project.id)) or 0)
|
|
@@ -1100,3 +1099,35 @@ class TestBackfillSeerGroupingRecords(SnubaTestCase, TestCase):
|
|
|
# Assert metadata was not set for groups that is 90 days old
|
|
|
old_group = Group.objects.filter(project_id=self.project.id, id=old_group_id).first()
|
|
|
assert old_group.data["metadata"].get("seer_similarity") is None
|
|
|
+
|
|
|
+ @with_feature("projects:similarity-embeddings-backfill")
|
|
|
+ @patch("sentry.tasks.backfill_seer_grouping_records.logger")
|
|
|
+ @patch(
|
|
|
+ "sentry.tasks.backfill_seer_grouping_records.lookup_group_data_stacktrace_bulk_with_fallback"
|
|
|
+ )
|
|
|
+ @patch("sentry.tasks.backfill_seer_grouping_records.call_next_backfill")
|
|
|
+ def test_backfill_seer_grouping_records_empty_nodestore(
|
|
|
+ self,
|
|
|
+ mock_call_next_backfill,
|
|
|
+ mock_lookup_group_data_stacktrace_bulk_with_fallback,
|
|
|
+ mock_logger,
|
|
|
+ ):
|
|
|
+ mock_lookup_group_data_stacktrace_bulk_with_fallback.return_value = GroupStacktraceData(
|
|
|
+ data=[], stacktrace_list=[]
|
|
|
+ )
|
|
|
+
|
|
|
+ with TaskRunner():
|
|
|
+ backfill_seer_grouping_records(self.project.id, None)
|
|
|
+
|
|
|
+ groups = Group.objects.all()
|
|
|
+ groups_len = len(groups)
|
|
|
+ mock_logger.info.assert_called_with(
|
|
|
+ "tasks.backfill_seer_grouping_records.no_data",
|
|
|
+ extra={
|
|
|
+ "project_id": self.project.id,
|
|
|
+ "group_id_batch": json.dumps([group.id for group in groups]),
|
|
|
+ },
|
|
|
+ )
|
|
|
+ mock_call_next_backfill.assert_called_with(
|
|
|
+ groups_len, self.project.id, ANY, groups_len, groups[groups_len - 1].id, False
|
|
|
+ )
|