test_group.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. import uuid
  2. from unittest.mock import patch
  3. from sentry.issues.grouptype import PerformanceNPlusOneGroupType, ProfileFileIOGroupType
  4. from sentry.issues.occurrence_consumer import process_event_and_issue_occurrence
  5. from sentry.models.group import Group
  6. from sentry.testutils.cases import PerformanceIssueTestCase, SnubaTestCase, TestCase
  7. from sentry.testutils.helpers.datetime import before_now, iso_format
  8. from sentry.testutils.silo import region_silo_test
  9. from sentry.utils.samples import load_data
  10. from tests.sentry.issues.test_utils import OccurrenceTestMixin
  11. @region_silo_test
  12. class GroupTestSnuba(TestCase, SnubaTestCase, PerformanceIssueTestCase, OccurrenceTestMixin):
  13. def test_get_oldest_latest_for_environments(self):
  14. project = self.create_project()
  15. min_ago = iso_format(before_now(minutes=1))
  16. self.store_event(
  17. data={
  18. "event_id": "a" * 32,
  19. "environment": "production",
  20. "timestamp": min_ago,
  21. "fingerprint": ["group-1"],
  22. },
  23. project_id=project.id,
  24. )
  25. self.store_event(
  26. data={
  27. "event_id": "b" * 32,
  28. "environment": "production",
  29. "timestamp": min_ago,
  30. "fingerprint": ["group-1"],
  31. },
  32. project_id=project.id,
  33. )
  34. self.store_event(
  35. data={"event_id": "c" * 32, "timestamp": min_ago, "fingerprint": ["group-1"]},
  36. project_id=project.id,
  37. )
  38. group = Group.objects.first()
  39. assert group.get_latest_event_for_environments().event_id == "c" * 32
  40. assert group.get_latest_event_for_environments(["staging"]) is None
  41. assert group.get_latest_event_for_environments(["production"]).event_id == "b" * 32
  42. assert group.get_oldest_event_for_environments().event_id == "a" * 32
  43. assert (
  44. group.get_oldest_event_for_environments(["staging", "production"]).event_id == "a" * 32
  45. )
  46. assert group.get_oldest_event_for_environments(["staging"]) is None
  47. def test_perf_issue(self):
  48. group_fingerprint = f"{PerformanceNPlusOneGroupType.type_id}-group1"
  49. event_data_1 = load_data("transaction-n-plus-one", fingerprint=[group_fingerprint])
  50. event_data_1["timestamp"] = iso_format(before_now(seconds=10))
  51. event_data_1["start_timestamp"] = iso_format(before_now(seconds=11))
  52. event_data_1["event_id"] = "d" * 32
  53. event_data_2 = load_data("transaction-n-plus-one", fingerprint=[group_fingerprint])
  54. event_data_2["timestamp"] = iso_format(before_now(seconds=20))
  55. event_data_2["start_timestamp"] = iso_format(before_now(seconds=21))
  56. event_data_2["event_id"] = "f" * 32
  57. event_data_3 = load_data("transaction-n-plus-one", fingerprint=[group_fingerprint])
  58. event_data_3["timestamp"] = iso_format(before_now(seconds=30))
  59. event_data_3["start_timestamp"] = iso_format(before_now(seconds=31))
  60. event_data_3["event_id"] = "f" * 32
  61. transaction_event_1 = self.create_performance_issue(
  62. event_data=event_data_1, fingerprint=group_fingerprint
  63. )
  64. self.create_performance_issue(event_data=event_data_2, fingerprint=group_fingerprint)
  65. self.create_performance_issue(event_data=event_data_3, fingerprint=group_fingerprint)
  66. perf_group = transaction_event_1.group
  67. assert perf_group.get_latest_event_for_environments().event_id == "d" * 32
  68. assert perf_group.get_oldest_event_for_environments().event_id == "f" * 32
  69. def test_error_issue_get_helpful_for_environments(self):
  70. project = self.create_project()
  71. min_ago = iso_format(before_now(minutes=1))
  72. replay_id = uuid.uuid4().hex
  73. event_all_helpful_params = self.store_event(
  74. data={
  75. "event_id": "a" * 32,
  76. "timestamp": min_ago,
  77. "fingerprint": ["group-1"],
  78. "contexts": {
  79. "replay": {"replay_id": replay_id},
  80. "trace": {
  81. "sampled": True,
  82. "span_id": "babaae0d4b7512d9",
  83. "trace_id": "a7d67cf796774551a95be6543cacd459",
  84. },
  85. },
  86. "errors": [],
  87. },
  88. project_id=project.id,
  89. assert_no_errors=False,
  90. )
  91. self.store_event(
  92. data={
  93. "event_id": "b" * 32,
  94. "timestamp": min_ago,
  95. "fingerprint": ["group-1"],
  96. "contexts": {
  97. "replay": {"replay_id": replay_id},
  98. },
  99. "errors": [{"type": "one"}, {"type": "two"}],
  100. },
  101. project_id=project.id,
  102. assert_no_errors=False,
  103. )
  104. event_none_helpful_params = self.store_event(
  105. data={"event_id": "c" * 32, "timestamp": min_ago, "fingerprint": ["group-1"]},
  106. project_id=project.id,
  107. )
  108. group = Group.objects.first()
  109. assert (
  110. group.get_recommended_event_for_environments().event_id
  111. == event_all_helpful_params.event_id
  112. )
  113. assert (
  114. group.get_latest_event_for_environments().event_id == event_none_helpful_params.event_id
  115. )
  116. assert (
  117. group.get_oldest_event_for_environments().event_id == event_all_helpful_params.event_id
  118. )
  119. def test_perf_issue_helpful(self):
  120. group_fingerprint = f"{PerformanceNPlusOneGroupType.type_id}-group1"
  121. transaction_event_data_with_all_helpful = load_data(
  122. "transaction-n-plus-one", fingerprint=[group_fingerprint]
  123. )
  124. transaction_event_data_with_all_helpful["timestamp"] = iso_format(before_now(seconds=10))
  125. transaction_event_data_with_all_helpful["start_timestamp"] = iso_format(
  126. before_now(seconds=11)
  127. )
  128. transaction_event_data_with_all_helpful["event_id"] = "d" * 32
  129. transaction_event_data_with_all_helpful["contexts"].update(
  130. {"profile": {"profile_id": uuid.uuid4().hex}}
  131. )
  132. transaction_event_data_with_all_helpful["contexts"].update(
  133. {"replay": {"replay_id": uuid.uuid4().hex}}
  134. )
  135. transaction_event_data_with_all_helpful["contexts"]["trace"]["sampled"] = True
  136. transaction_event_data_with_all_helpful["errors"] = []
  137. transaction_event_data_with_none_helpful = load_data(
  138. "transaction-n-plus-one", fingerprint=[group_fingerprint]
  139. )
  140. transaction_event_data_with_none_helpful["timestamp"] = iso_format(before_now(seconds=20))
  141. transaction_event_data_with_none_helpful["start_timestamp"] = iso_format(
  142. before_now(seconds=21)
  143. )
  144. transaction_event_data_with_none_helpful["event_id"] = "f" * 32
  145. transaction_event_1 = self.create_performance_issue(
  146. event_data=transaction_event_data_with_all_helpful, fingerprint=group_fingerprint
  147. )
  148. transaction_event_2 = self.create_performance_issue(
  149. event_data=transaction_event_data_with_none_helpful, fingerprint=group_fingerprint
  150. )
  151. perf_group = transaction_event_1.group
  152. assert (
  153. perf_group.get_recommended_event_for_environments().event_id
  154. == transaction_event_1.event_id
  155. )
  156. assert (
  157. perf_group.get_latest_event_for_environments().event_id == transaction_event_1.event_id
  158. )
  159. assert (
  160. perf_group.get_oldest_event_for_environments().event_id == transaction_event_2.event_id
  161. )
  162. def test_profile_issue_helpful(self):
  163. event_id_1 = uuid.uuid4().hex
  164. occurrence = process_event_and_issue_occurrence(
  165. self.build_occurrence_data(event_id=event_id_1, project_id=self.project.id),
  166. {
  167. "event_id": event_id_1,
  168. "fingerprint": ["group-1"],
  169. "project_id": self.project.id,
  170. "timestamp": before_now(minutes=2).isoformat(),
  171. "contexts": {
  172. "profile": {"profile_id": uuid.uuid4().hex},
  173. "replay": {"replay_id": uuid.uuid4().hex},
  174. "trace": {
  175. "sampled": True,
  176. "span_id": "babaae0d4b7512d9",
  177. "trace_id": "a7d67cf796774551a95be6543cacd459",
  178. },
  179. },
  180. "errors": [],
  181. },
  182. )[0]
  183. event_id_2 = uuid.uuid4().hex
  184. occurrence_2 = process_event_and_issue_occurrence(
  185. self.build_occurrence_data(event_id=event_id_2, project_id=self.project.id),
  186. {
  187. "event_id": event_id_2,
  188. "fingerprint": ["group-1"],
  189. "project_id": self.project.id,
  190. "timestamp": before_now(minutes=1).isoformat(),
  191. },
  192. )[0]
  193. group = Group.objects.first()
  194. group.update(type=ProfileFileIOGroupType.type_id)
  195. group_event = group.get_recommended_event_for_environments()
  196. assert group_event.event_id == occurrence.event_id
  197. self.assert_occurrences_identical(group_event.occurrence, occurrence)
  198. assert group.get_latest_event_for_environments().event_id == occurrence_2.event_id
  199. assert group.get_oldest_event_for_environments().event_id == occurrence.event_id
  200. @patch("sentry.quotas.backend.get_event_retention")
  201. def test_get_recommended_event_for_environments_retention_limit(self, mock_get_event_retention):
  202. """
  203. If last_seen is outside of the retention limit, falls back to the latest event behavior.
  204. """
  205. mock_get_event_retention.return_value = 90
  206. project = self.create_project()
  207. outside_retention_date = before_now(days=91)
  208. event = self.store_event(
  209. data={
  210. "event_id": "a" * 32,
  211. "timestamp": iso_format(outside_retention_date),
  212. "fingerprint": ["group-1"],
  213. "contexts": {},
  214. "errors": [],
  215. },
  216. project_id=project.id,
  217. assert_no_errors=False,
  218. )
  219. group = Group.objects.first()
  220. group.last_seen = before_now(days=91)
  221. assert group.get_recommended_event_for_environments().event_id == event.event_id