test_image_block_builder.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. import uuid
  2. from datetime import timedelta
  3. from unittest.mock import patch
  4. import pytest
  5. from django.core.cache import cache
  6. from sentry.integrations.slack.message_builder.image_block_builder import ImageBlockBuilder
  7. from sentry.issues.grouptype import (
  8. PerformanceHTTPOverheadGroupType,
  9. PerformanceP95EndpointRegressionGroupType,
  10. ProfileFunctionRegressionType,
  11. )
  12. from sentry.models.group import Group
  13. from sentry.testutils.cases import (
  14. AcceptanceTestCase,
  15. MetricsEnhancedPerformanceTestCase,
  16. ProfilesSnubaTestCase,
  17. )
  18. from sentry.testutils.helpers.datetime import before_now
  19. from sentry.testutils.helpers.features import with_feature
  20. from tests.sentry.issues.test_utils import OccurrenceTestMixin
  21. pytestmark = pytest.mark.sentry_metrics
  22. class TestSlackImageBlockBuilder(
  23. AcceptanceTestCase,
  24. MetricsEnhancedPerformanceTestCase,
  25. ProfilesSnubaTestCase,
  26. OccurrenceTestMixin,
  27. ):
  28. def setUp(self):
  29. super().setUp()
  30. self.features = {
  31. "organizations:performance-use-metrics": True,
  32. "organizations:slack-endpoint-regression-image": True,
  33. "organizations:slack-function-regression-image": True,
  34. }
  35. cache.clear()
  36. def _create_endpoint_regression_issue(self):
  37. for i in range(10):
  38. event_id = uuid.uuid4().hex
  39. _ = self.process_occurrence(
  40. project_id=self.project.id,
  41. event_id=event_id,
  42. type=PerformanceP95EndpointRegressionGroupType.type_id,
  43. event_data={
  44. "fingerprint": ["group-1"],
  45. "timestamp": before_now(minutes=i + 10).isoformat(),
  46. "transaction": "/books/",
  47. },
  48. evidence_data={
  49. "breakpoint": before_now(minutes=i + 10).timestamp(),
  50. },
  51. )
  52. self.store_transaction_metric(
  53. metric="transaction.duration",
  54. tags={"transaction": "/books/"},
  55. value=1,
  56. timestamp=before_now(minutes=i + 10),
  57. project=self.project.id,
  58. )
  59. group = Group.objects.get()
  60. group.update(type=PerformanceP95EndpointRegressionGroupType.type_id)
  61. return group
  62. @with_feature("organizations:slack-endpoint-regression-image")
  63. def test_image_block_for_endpoint_regression(self):
  64. group = self._create_endpoint_regression_issue()
  65. with self.feature(self.features):
  66. image_block = ImageBlockBuilder(group=group).build_image_block()
  67. assert image_block and "type" in image_block and image_block["type"] == "image"
  68. assert "_media/" in image_block["image_url"]
  69. @patch("sentry.utils.performance_issues.detectors.utils.escape_transaction")
  70. @with_feature("organizations:slack-endpoint-regression-image")
  71. def test_caching(self, mock_escape_transaction):
  72. mock_escape_transaction.return_value = "Test Transaction"
  73. group = self._create_endpoint_regression_issue()
  74. image_blocks = []
  75. for _ in range(5):
  76. with self.feature(self.features):
  77. image_blocks.append(ImageBlockBuilder(group=group).build_image_block())
  78. assert mock_escape_transaction.call_count == 1
  79. assert len(image_blocks) == 5
  80. assert image_blocks[0]
  81. image_url = image_blocks[0]["image_url"]
  82. for image_block in image_blocks:
  83. assert image_block is not None
  84. assert image_block["image_url"] == image_url
  85. @with_feature("organizations:slack-function-regression-image")
  86. def test_image_block_for_function_regression(self):
  87. hour_ago = (before_now(minutes=10) - timedelta(hours=1)).replace(
  88. minute=0, second=0, microsecond=0
  89. )
  90. for i in range(10):
  91. event_id = uuid.uuid4().hex
  92. _ = self.process_occurrence(
  93. project_id=self.project.id,
  94. event_id=event_id,
  95. type=ProfileFunctionRegressionType.type_id,
  96. event_data={
  97. "fingerprint": ["group-1"],
  98. "timestamp": before_now(minutes=i + 10).isoformat(),
  99. "function": "foo",
  100. },
  101. evidence_data={
  102. "breakpoint": before_now(minutes=i + 10).timestamp(),
  103. "fingerprint": self.function_fingerprint({"package": "foo", "function": "foo"}),
  104. "aggregate_range_1": 51588984.199999996,
  105. "aggregate_range_2": 839118611.8535699,
  106. },
  107. )
  108. self.store_functions(
  109. [
  110. {
  111. "self_times_ns": [100 for _ in range(100)],
  112. "package": "foo",
  113. "function": "foo",
  114. # only in app functions should
  115. # appear in the results
  116. "in_app": True,
  117. },
  118. ],
  119. project=self.project,
  120. timestamp=hour_ago,
  121. )
  122. group = Group.objects.get()
  123. with self.feature(self.features):
  124. image_block = ImageBlockBuilder(group=group).build_image_block()
  125. assert image_block and "type" in image_block and image_block["type"] == "image"
  126. assert "_media/" in image_block["image_url"]
  127. @patch("sentry_sdk.capture_exception")
  128. @with_feature("organizations:slack-function-regression-image")
  129. def test_image_not_generated_for_unsupported_issues(self, mock_capture_exception):
  130. group = self.create_group()
  131. group.update(type=PerformanceHTTPOverheadGroupType.type_id)
  132. image_block = ImageBlockBuilder(group=group).build_image_block()
  133. assert image_block is None
  134. assert mock_capture_exception.call_count == 0