From a386b7da702c9dc15583033406457575a07d913c Mon Sep 17 00:00:00 2001 From: "Armen Zambrano G." <44410+armenzg@users.noreply.github.com> Date: Fri, 17 Oct 2025 10:48:57 -0400 Subject: [PATCH] tests: Remove setUp function When debugging tests, it becomes harder to do when there are events and groups that have nothing to do with the tests you're working on. This refactor moves the majority of the logic from the setUp function to the first test. --- tests/sentry/deletions/test_group.py | 156 +++++++++++++++------------ 1 file changed, 86 insertions(+), 70 deletions(-) diff --git a/tests/sentry/deletions/test_group.py b/tests/sentry/deletions/test_group.py index de230707d9474a..69c317765955b2 100644 --- a/tests/sentry/deletions/test_group.py +++ b/tests/sentry/deletions/test_group.py @@ -2,13 +2,13 @@ import random from datetime import datetime, timedelta from time import time +from typing import Any from unittest import mock from uuid import uuid4 from snuba_sdk import Column, Condition, Entity, Function, Op, Query, Request from sentry import deletions, nodestore -from sentry.deletions.defaults.group import ErrorEventsDeletionTask from sentry.deletions.tasks.groups import delete_groups_for_project from sentry.issues.grouptype import FeedbackGroup, GroupCategory from sentry.issues.issue_occurrence import IssueOccurrence @@ -31,93 +31,102 @@ class DeleteGroupTest(TestCase, SnubaTestCase): - def setUp(self) -> None: - super().setUp() - one_minute = before_now(minutes=1).isoformat() - group1_data = {"timestamp": one_minute, "fingerprint": ["group1"]} - group2_data = {"timestamp": one_minute, "fingerprint": ["group2"]} - - # Group 1 events - self.event = self.store_event( - data=group1_data | {"tags": {"foo": "bar"}}, project_id=self.project.id - ) - self.event_id = self.event.event_id - self.node_id = Event.generate_node_id(self.project.id, self.event_id) - group = self.event.group - self.event2 = self.store_event(data=group1_data, project_id=self.project.id) - self.node_id2 = Event.generate_node_id(self.project.id, self.event2.event_id) - # Group 2 event - self.keep_event = self.store_event(data=group2_data, project_id=self.project.id) - self.keep_node_id = Event.generate_node_id(self.project.id, self.keep_event.event_id) + def _generate_data(self, fingerprint: str | None = None) -> dict[str, Any]: + return { + "fingerprint": [fingerprint or uuid4().hex], + "timestamp": before_now(minutes=1).isoformat(), + } + + def _get_node_id(self, event: Event) -> str: + return Event.generate_node_id(event.project_id, event.event_id) + def _create_event_with_many_group_children(self) -> Event: + event = self.store_event( + data=self._generate_data(fingerprint="group1"), + project_id=self.project.id, + ) UserReport.objects.create( - group_id=group.id, project_id=self.event.project_id, name="With group id" + group_id=event.group.id, project_id=event.project_id, name="With group id" ) UserReport.objects.create( - event_id=self.event.event_id, project_id=self.event.project_id, name="With event id" + event_id=event.event_id, project_id=event.project_id, name="With event id" ) EventAttachment.objects.create( - event_id=self.event.event_id, - project_id=self.event.project_id, + event_id=event.event_id, + project_id=event.project_id, name="hello.png", content_type="image/png", ) - GroupAssignee.objects.create(group=group, project=self.project, user_id=self.user.id) - GroupHash.objects.create(project=self.project, group=group, hash=uuid4().hex) - GroupMeta.objects.create(group=group, key="foo", value="bar") - GroupRedirect.objects.create(group_id=group.id, previous_group_id=1) + GroupAssignee.objects.create(group=event.group, project=self.project, user_id=self.user.id) + GroupHash.objects.create(project=self.project, group=event.group, hash=uuid4().hex) + GroupMeta.objects.create(group=event.group, key="foo", value="bar") + GroupRedirect.objects.create(group_id=event.group.id, previous_group_id=1) - def test_simple(self) -> None: - ErrorEventsDeletionTask.DEFAULT_CHUNK_SIZE = 1 # test chunking logic - group = self.event.group - assert nodestore.backend.get(self.node_id) - assert nodestore.backend.get(self.node_id2) - assert nodestore.backend.get(self.keep_node_id) + return event + + def test_delete_group_with_many_related_children(self) -> None: + event = self._create_event_with_many_group_children() + assert event.group is not None + + event2 = self.store_event( + data=self._generate_data(fingerprint="group1"), project_id=self.project.id + ) + assert event2.group is not None + + assert nodestore.backend.get(self._get_node_id(event)) + assert nodestore.backend.get(self._get_node_id(event2)) with self.tasks(): delete_groups_for_project( - object_ids=[group.id], transaction_id=uuid4().hex, project_id=self.project.id + object_ids=[event.group.id], transaction_id=uuid4().hex, project_id=self.project.id ) - assert not UserReport.objects.filter(group_id=group.id).exists() - assert not UserReport.objects.filter(event_id=self.event.event_id).exists() - assert not EventAttachment.objects.filter(event_id=self.event.event_id).exists() + assert not UserReport.objects.filter(group_id=event.group.id).exists() + assert not UserReport.objects.filter(event_id=event.event_id).exists() + assert not EventAttachment.objects.filter(event_id=event.event_id).exists() - assert not GroupRedirect.objects.filter(group_id=group.id).exists() - assert not GroupHash.objects.filter(group_id=group.id).exists() - assert not Group.objects.filter(id=group.id).exists() - assert not nodestore.backend.get(self.node_id) - assert not nodestore.backend.get(self.node_id2) - assert nodestore.backend.get(self.keep_node_id), "Does not remove from second group" - assert Group.objects.filter(id=self.keep_event.group_id).exists() + assert not GroupRedirect.objects.filter(group_id=event.group.id).exists() + assert not GroupHash.objects.filter(group_id=event.group.id).exists() + assert not Group.objects.filter(id=event.group.id).exists() + assert not nodestore.backend.get(self._get_node_id(event)) + assert not nodestore.backend.get(self._get_node_id(event2)) - def test_simple_multiple_groups(self) -> None: + def test_multiple_groups(self) -> None: + event = self.store_event( + data=self._generate_data(fingerprint="group1"), + project_id=self.project.id, + ) + assert event.group is not None + keep_event = self.store_event( + data=self._generate_data(fingerprint="group2"), + project_id=self.project.id, + ) + assert keep_event.group is not None other_event = self.store_event( - data={"timestamp": before_now(minutes=1).isoformat(), "fingerprint": ["group3"]}, + data=self._generate_data(fingerprint="group3"), project_id=self.project.id, ) - other_node_id = Event.generate_node_id(self.project.id, other_event.event_id) + assert other_event.group is not None - group = self.event.group with self.tasks(): delete_groups_for_project( - object_ids=[group.id, other_event.group_id], + object_ids=[event.group.id, other_event.group.id], transaction_id=uuid4().hex, project_id=self.project.id, ) - assert not Group.objects.filter(id=group.id).exists() + assert not Group.objects.filter(id=event.group.id).exists() assert not Group.objects.filter(id=other_event.group_id).exists() - assert not nodestore.backend.get(self.node_id) - assert not nodestore.backend.get(other_node_id) + assert not nodestore.backend.get(self._get_node_id(event)) + assert not nodestore.backend.get(self._get_node_id(other_event)) - assert Group.objects.filter(id=self.keep_event.group_id).exists() - assert nodestore.backend.get(self.keep_node_id) + assert Group.objects.filter(id=keep_event.group.id).exists() + assert nodestore.backend.get(self._get_node_id(keep_event)) def test_grouphistory_relation(self) -> None: other_event = self.store_event( - data={"timestamp": before_now(minutes=1).isoformat(), "fingerprint": ["group3"]}, + data=self._generate_data(fingerprint="other_group"), project_id=self.project.id, ) other_group = other_event.group @@ -172,39 +181,45 @@ def test_delete_groups_delete_grouping_records_by_hash( self, mock_delete_seer_grouping_records_by_hash_apply_async: mock.Mock ) -> None: self.project.update_option("sentry:similarity_backfill_completed", int(time())) + event = self.store_event( + data=self._generate_data(fingerprint="group1"), + project_id=self.project.id, + ) + assert event.group + keep_event = self.store_event( + data=self._generate_data(fingerprint="group2"), + project_id=self.project.id, + ) + assert keep_event.group other_event = self.store_event( - data={ - "timestamp": before_now(minutes=1).isoformat(), - "fingerprint": ["group3"], - }, + data=self._generate_data(fingerprint="group3"), project_id=self.project.id, ) - other_node_id = Event.generate_node_id(self.project.id, other_event.event_id) hashes = [ grouphash.hash for grouphash in GroupHash.objects.filter( - project_id=self.project.id, group_id__in=[self.event.group.id, other_event.group_id] + project_id=self.project.id, group_id__in=[event.group.id, other_event.group_id] ) ] - group = self.event.group + with self.tasks(): delete_groups_for_project( - object_ids=[group.id, other_event.group_id], + object_ids=[event.group.id, other_event.group_id], transaction_id=uuid4().hex, project_id=self.project.id, ) - assert not Group.objects.filter(id=group.id).exists() + assert not Group.objects.filter(id=event.group.id).exists() assert not Group.objects.filter(id=other_event.group_id).exists() - assert not nodestore.backend.get(self.node_id) - assert not nodestore.backend.get(other_node_id) + assert not nodestore.backend.get(self._get_node_id(event)) + assert not nodestore.backend.get(self._get_node_id(other_event)) - assert Group.objects.filter(id=self.keep_event.group_id).exists() - assert nodestore.backend.get(self.keep_node_id) + assert Group.objects.filter(id=keep_event.group_id).exists() + assert nodestore.backend.get(self._get_node_id(keep_event)) assert mock_delete_seer_grouping_records_by_hash_apply_async.call_args[1] == { - "args": [group.project.id, hashes, 0] + "args": [event.project.id, hashes, 0] } @mock.patch( @@ -291,13 +306,14 @@ def test_delete_grouphashes_and_metadata(self) -> None: project_id=self.project.id, ) grouphash_b = GroupHash.objects.get(hash=event_b.get_primary_hash()) - # assert grouphash_b.metadata is not None assert grouphash_b.metadata is not None metadata_b_id = grouphash_b.metadata.id # Verify that seer matched event_b to event_a's hash assert event_a.group_id == event_b.group_id + # Make sure it has not changed + grouphash_a.refresh_from_db() assert grouphash_a.metadata is not None assert grouphash_a.metadata.seer_matched_grouphash is None assert grouphash_b.metadata is not None