test_organization_group_index.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. from datetime import datetime
  2. from unittest.mock import patch
  3. import pytz
  4. from django.utils import timezone
  5. from fixtures.page_objects.issue_list import IssueListPage
  6. from sentry.models import AssistantActivity, GroupInboxReason, GroupStatus
  7. from sentry.models.groupinbox import add_group_to_inbox
  8. from sentry.testutils import AcceptanceTestCase, SnubaTestCase
  9. from sentry.testutils.helpers.datetime import before_now, iso_format
  10. from sentry.testutils.silo import region_silo_test
  11. event_time = before_now(days=3).replace(tzinfo=pytz.utc)
  12. @region_silo_test
  13. class OrganizationGroupIndexTest(AcceptanceTestCase, SnubaTestCase):
  14. def setUp(self):
  15. super().setUp()
  16. self.user = self.create_user("foo@example.com")
  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.other_project = self.create_project(
  23. organization=self.org, teams=[self.team], name="Sumatra"
  24. )
  25. self.login_as(self.user)
  26. self.page = IssueListPage(self.browser, self.client)
  27. self.dismiss_assistant()
  28. def create_issues(self):
  29. self.event_a = self.store_event(
  30. data={
  31. "event_id": "a" * 32,
  32. "message": "oh no",
  33. "timestamp": iso_format(event_time),
  34. "fingerprint": ["group-1"],
  35. },
  36. project_id=self.project.id,
  37. )
  38. add_group_to_inbox(self.event_a.group, GroupInboxReason.NEW)
  39. self.event_b = self.store_event(
  40. data={
  41. "event_id": "b" * 32,
  42. "message": "oh snap",
  43. "timestamp": iso_format(event_time),
  44. "fingerprint": ["group-2"],
  45. },
  46. project_id=self.project.id,
  47. )
  48. add_group_to_inbox(self.event_b.group, GroupInboxReason.NEW)
  49. def test_with_onboarding(self):
  50. self.project.update(first_event=None)
  51. self.page.visit_issue_list(self.org.slug)
  52. self.browser.wait_until_test_id("awaiting-events")
  53. self.browser.snapshot("organization issues onboarding")
  54. def test_with_no_results(self):
  55. self.project.update(first_event=timezone.now())
  56. self.page.visit_issue_list(self.org.slug, query="?query=assigned%3Ame")
  57. self.browser.wait_until_test_id("empty-state")
  58. self.browser.snapshot("organization issues no results")
  59. @patch("django.utils.timezone.now")
  60. def test_with_results(self, mock_now):
  61. mock_now.return_value = datetime.utcnow().replace(tzinfo=pytz.utc)
  62. self.create_issues()
  63. self.page.visit_issue_list(self.org.slug)
  64. self.page.wait_for_stream()
  65. self.browser.snapshot("organization issues with issues")
  66. groups = self.browser.elements('[data-test-id="event-issue-header"]')
  67. assert len(groups) == 2
  68. assert "oh snap" in groups[0].text
  69. assert "oh no" in groups[1].text
  70. @patch("django.utils.timezone.now")
  71. def test_resolve_issues(self, mock_now):
  72. mock_now.return_value = datetime.utcnow().replace(tzinfo=pytz.utc)
  73. self.create_issues()
  74. self.page.visit_issue_list(self.org.slug)
  75. self.page.wait_for_stream()
  76. self.page.select_issue(1)
  77. self.page.select_issue(2)
  78. self.page.resolve_issues()
  79. self.page.wait_for_resolved_issue()
  80. resolved_groups = self.page.find_resolved_issues()
  81. assert len(resolved_groups) == 2
  82. @patch("django.utils.timezone.now")
  83. def test_resolve_issues_removal(self, mock_now):
  84. mock_now.return_value = datetime.utcnow().replace(tzinfo=pytz.utc)
  85. self.create_issues()
  86. # TODO(Kelly): update once issue-list-removal-action feature is stable
  87. with self.feature("organizations:issue-list-removal-action"):
  88. group1 = self.event_a.group
  89. self.page.visit_issue_list(self.org.slug)
  90. self.page.wait_for_stream()
  91. self.page.select_issue(1)
  92. self.page.resolve_issues_removal()
  93. group1.update(status=GroupStatus.RESOLVED, substatus=None)
  94. self.page.wait_for_issue_removal()
  95. groups = self.browser.elements('[data-test-id="event-issue-header"]')
  96. assert len(groups) == 1
  97. @patch("django.utils.timezone.now")
  98. def test_resolve_issues_multi_projects(self, mock_now):
  99. mock_now.return_value = datetime.utcnow().replace(tzinfo=pytz.utc)
  100. self.create_issues()
  101. with self.feature("organizations:global-views"):
  102. self.page.visit_issue_list(self.org.slug)
  103. self.page.wait_for_stream()
  104. self.page.select_issue(1)
  105. self.page.select_issue(2)
  106. self.page.resolve_issues()
  107. self.page.wait_for_resolved_issue()
  108. resolved_groups = self.page.find_resolved_issues()
  109. assert len(resolved_groups) == 2
  110. @patch("django.utils.timezone.now")
  111. def test_resolve_issues_removal_multi_projects(self, mock_now):
  112. mock_now.return_value = datetime.utcnow().replace(tzinfo=pytz.utc)
  113. self.create_issues()
  114. # TODO(Kelly): update once issue-list-removal-action feature is stable
  115. with self.feature(
  116. ["organizations:global-views", "organizations:issue-list-removal-action"]
  117. ):
  118. group1 = self.event_a.group
  119. self.page.visit_issue_list(self.org.slug)
  120. self.page.wait_for_stream()
  121. self.page.select_issue(1)
  122. self.page.resolve_issues_removal()
  123. group1.update(status=GroupStatus.RESOLVED, substatus=None)
  124. self.page.wait_for_issue_removal()
  125. groups = self.browser.elements('[data-test-id="event-issue-header"]')
  126. assert len(groups) == 1
  127. @patch("django.utils.timezone.now")
  128. def test_ignore_issues(self, mock_now):
  129. # TODO(Kelly): update once issue-list-removal-action feature is stable
  130. with self.feature("organizations:issue-list-removal-action"):
  131. mock_now.return_value = datetime.utcnow().replace(tzinfo=pytz.utc)
  132. self.create_issues()
  133. group1 = self.event_a.group
  134. self.page.visit_issue_list(self.org.slug)
  135. self.page.wait_for_stream()
  136. self.page.select_issue(1)
  137. self.page.ignore_issues()
  138. group1.update(status=GroupStatus.IGNORED, substatus=None)
  139. self.page.wait_for_issue_removal()
  140. groups = self.browser.elements('[data-test-id="event-issue-header"]')
  141. assert len(groups) == 1
  142. @patch("django.utils.timezone.now")
  143. def test_ignore_issues_multi_projects(self, mock_now):
  144. # TODO(Kelly): update once issue-list-removal-action feature is stable
  145. with self.feature("organizations:issue-list-removal-action"):
  146. mock_now.return_value = datetime.utcnow().replace(tzinfo=pytz.utc)
  147. self.create_issues()
  148. group1 = self.event_a.group
  149. with self.feature("organizations:global-views"):
  150. self.page.visit_issue_list(self.org.slug)
  151. self.page.wait_for_stream()
  152. self.page.select_issue(1)
  153. self.page.ignore_issues()
  154. group1.update(status=GroupStatus.IGNORED, substatus=None)
  155. self.page.wait_for_issue_removal()
  156. groups = self.browser.elements('[data-test-id="event-issue-header"]')
  157. assert len(groups) == 1
  158. @patch("django.utils.timezone.now")
  159. def test_delete_issues(self, mock_now):
  160. # TODO(Kelly): update once issue-list-removal-action feature is stable
  161. with self.feature("organizations:issue-list-removal-action"):
  162. mock_now.return_value = datetime.utcnow().replace(tzinfo=pytz.utc)
  163. self.create_issues()
  164. group1 = self.event_a.group
  165. self.page.visit_issue_list(self.org.slug)
  166. self.page.wait_for_stream()
  167. self.page.select_issue(1)
  168. self.page.delete_issues()
  169. group1.update(status=GroupStatus.PENDING_DELETION, substatus=None)
  170. self.page.wait_for_issue_removal()
  171. groups = self.browser.elements('[data-test-id="event-issue-header"]')
  172. assert len(groups) == 1
  173. @patch("django.utils.timezone.now")
  174. def test_delete_issues_multi_projects(self, mock_now):
  175. # TODO(Kelly): update once issue-list-removal-action feature is stable
  176. with self.feature("organizations:issue-list-removal-action"):
  177. mock_now.return_value = datetime.utcnow().replace(tzinfo=pytz.utc)
  178. self.create_issues()
  179. group1 = self.event_a.group
  180. with self.feature("organizations:global-views"):
  181. self.page.visit_issue_list(self.org.slug)
  182. self.page.wait_for_stream()
  183. self.page.select_issue(1)
  184. self.page.delete_issues()
  185. group1.update(status=GroupStatus.PENDING_DELETION, substatus=None)
  186. self.page.wait_for_issue_removal()
  187. groups = self.browser.elements('[data-test-id="event-issue-header"]')
  188. assert len(groups) == 1
  189. @patch("django.utils.timezone.now")
  190. def test_merge_issues(self, mock_now):
  191. # TODO(Kelly): update once issue-list-removal-action feature is stable
  192. with self.feature("organizations:issue-list-removal-action"):
  193. mock_now.return_value = datetime.utcnow().replace(tzinfo=pytz.utc)
  194. self.create_issues()
  195. group1 = self.event_a.group
  196. group2 = self.event_b.group
  197. self.page.visit_issue_list(self.org.slug)
  198. self.page.wait_for_stream()
  199. self.page.select_issue(1)
  200. self.page.select_issue(2)
  201. self.page.merge_issues()
  202. group1.update(status=GroupStatus.PENDING_MERGE, substatus=None)
  203. group2.update(status=GroupStatus.PENDING_MERGE, substatus=None)
  204. self.page.wait_for_issue_removal()
  205. groups = self.browser.elements('[data-test-id="event-issue-header"]')
  206. assert len(groups) == 1
  207. @patch("django.utils.timezone.now")
  208. def test_inbox_results(self, mock_now):
  209. mock_now.return_value = datetime.utcnow().replace(tzinfo=pytz.utc)
  210. self.create_issues()
  211. # Disable for_review_guide
  212. AssistantActivity.objects.create(user=self.user, guide_id=9, viewed_ts=timezone.now())
  213. self.page.visit_issue_list(
  214. self.org.slug,
  215. query="?query=is%3Aunresolved+is%3Afor_review+assigned_or_suggested%3A[me, none]",
  216. )
  217. self.page.wait_for_stream()
  218. self.browser.snapshot("organization issues inbox results")
  219. groups = self.browser.elements('[data-test-id="event-issue-header"]')
  220. assert len(groups) == 2
  221. self.page.select_issue(1)
  222. self.page.mark_reviewed_issues()
  223. self.page.visit_issue_list(
  224. self.org.slug,
  225. query="?query=is%3Aunresolved+is%3Afor_review+assigned_or_suggested%3A[me, none]",
  226. )
  227. self.page.wait_for_stream()
  228. groups = self.browser.elements('[data-test-id="event-issue-header"]')
  229. assert len(groups) == 1