test_performance_issues.py 3.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. import random
  2. import string
  3. from unittest.mock import patch
  4. import pytz
  5. from fixtures.page_objects.issue_details import IssueDetailsPage
  6. from sentry import options
  7. from sentry.models import Group
  8. from sentry.testutils import AcceptanceTestCase, SnubaTestCase
  9. from sentry.testutils.helpers.datetime import before_now
  10. from sentry.utils import json
  11. FEATURES = {
  12. "projects:performance-suspect-spans-ingestion": True,
  13. }
  14. class PerformanceIssuesTest(AcceptanceTestCase, SnubaTestCase):
  15. def setUp(self):
  16. super().setUp()
  17. self.org = self.create_organization(owner=self.user, name="Rowdy Tiger")
  18. self.team = self.create_team(
  19. organization=self.org, name="Mariachi Band", members=[self.user]
  20. )
  21. self.project = self.create_project(organization=self.org, teams=[self.team], name="Bengal")
  22. self.login_as(self.user)
  23. options.set("performance.issues.n_plus_one_db.problem-creation", 1.0)
  24. self.page = IssueDetailsPage(self.browser, self.client)
  25. self.dismiss_assistant()
  26. def create_sample_event(self, start_timestamp):
  27. event = json.loads(
  28. self.load_fixture("events/performance_problems/n-plus-one-in-django-new-view.json")
  29. )
  30. for key in ["datetime", "location", "title"]:
  31. del event[key]
  32. event["contexts"] = {
  33. "trace": {"trace_id": "530c14e044aa464db6ddb43660e6474f", "span_id": "139fcdb7c5534eb4"}
  34. }
  35. ms_delta = start_timestamp - event["start_timestamp"]
  36. for item in [event, *event["spans"]]:
  37. item["start_timestamp"] += ms_delta
  38. item["timestamp"] += ms_delta
  39. return event
  40. def randomize_span_description(self, span):
  41. return {
  42. **span,
  43. "description": "".join(random.choice(string.ascii_lowercase) for _ in range(10)),
  44. }
  45. @patch("django.utils.timezone.now")
  46. def test_with_one_performance_issue(self, mock_now):
  47. mock_now.return_value = before_now(minutes=5).replace(tzinfo=pytz.utc)
  48. event_data = self.create_sample_event(mock_now.return_value.timestamp())
  49. with self.feature(FEATURES):
  50. event = self.store_event(data=event_data, project_id=self.project.id)
  51. self.page.visit_issue(self.org.slug, event.groups[0].id)
  52. self.browser.click('[aria-label="Show Details"]')
  53. self.browser.snapshot("performance issue details", desktop_only=True)
  54. @patch("django.utils.timezone.now")
  55. def test_multiple_events_with_one_cause_are_grouped(self, mock_now):
  56. mock_now.return_value = before_now(minutes=5).replace(tzinfo=pytz.utc)
  57. event_data = self.create_sample_event(mock_now.return_value.timestamp())
  58. with self.feature(FEATURES):
  59. [self.store_event(data=event_data, project_id=self.project.id) for _ in range(3)]
  60. assert Group.objects.count() == 1
  61. @patch("django.utils.timezone.now")
  62. def test_multiple_events_with_multiple_causes_are_not_grouped(self, mock_now):
  63. mock_now.return_value = before_now(minutes=5).replace(tzinfo=pytz.utc)
  64. # Create identical events with different parent spans
  65. for _ in range(3):
  66. event_data = self.create_sample_event(mock_now.return_value.timestamp())
  67. event_data["spans"] = [
  68. self.randomize_span_description(span) if span["op"] == "django.view" else span
  69. for span in event_data["spans"]
  70. ]
  71. with self.feature(FEATURES):
  72. self.store_event(data=event_data, project_id=self.project.id)
  73. assert Group.objects.count() == 3