test_organization_group_index_stats.py 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. import uuid
  2. from sentry.issues.grouptype import ProfileFileIOGroupType
  3. from sentry.testutils.cases import APITestCase, SnubaTestCase
  4. from sentry.testutils.helpers import parse_link_header, with_feature
  5. from sentry.testutils.helpers.datetime import before_now, iso_format
  6. from sentry.testutils.silo import region_silo_test
  7. from tests.sentry.issues.test_utils import OccurrenceTestMixin
  8. @region_silo_test
  9. class GroupListTest(APITestCase, SnubaTestCase, OccurrenceTestMixin):
  10. endpoint = "sentry-api-0-organization-group-index-stats"
  11. def setUp(self):
  12. super().setUp()
  13. self.min_ago = before_now(minutes=1)
  14. def _parse_links(self, header):
  15. # links come in {url: {...attrs}}, but we need {rel: {...attrs}}
  16. links = {}
  17. for url, attrs in parse_link_header(header).items():
  18. links[attrs["rel"]] = attrs
  19. attrs["href"] = url
  20. return links
  21. def get_response(self, *args, **kwargs):
  22. if not args:
  23. org = self.project.organization.slug
  24. else:
  25. org = args[0]
  26. return super().get_response(org, **kwargs)
  27. def test_simple(self):
  28. self.store_event(
  29. data={"timestamp": iso_format(before_now(seconds=500)), "fingerprint": ["group-1"]},
  30. project_id=self.project.id,
  31. )
  32. group_a = self.store_event(
  33. data={"timestamp": iso_format(before_now(seconds=1)), "fingerprint": ["group-a"]},
  34. project_id=self.project.id,
  35. ).group
  36. self.store_event(
  37. data={"timestamp": iso_format(before_now(seconds=2)), "fingerprint": ["group-b"]},
  38. project_id=self.project.id,
  39. )
  40. group_c = self.store_event(
  41. data={"timestamp": iso_format(before_now(seconds=3)), "fingerprint": ["group-c"]},
  42. project_id=self.project.id,
  43. ).group
  44. self.login_as(user=self.user)
  45. response = self.get_response(query="is:unresolved", groups=[group_a.id, group_c.id])
  46. response_data = sorted(response.data, key=lambda x: x["firstSeen"], reverse=True)
  47. assert response.status_code == 200
  48. assert len(response_data) == 2
  49. assert int(response_data[0]["id"]) == group_a.id
  50. assert int(response_data[1]["id"]) == group_c.id
  51. assert "title" not in response_data[0]
  52. assert "hasSeen" not in response_data[0]
  53. assert "stats" in response_data[0]
  54. assert "firstSeen" in response_data[0]
  55. assert "lastSeen" in response_data[0]
  56. assert "count" in response_data[0]
  57. assert "userCount" in response_data[0]
  58. assert "lifetime" in response_data[0]
  59. assert "filtered" in response_data[0]
  60. assert "isUnhandled" not in response_data[0]
  61. @with_feature("organizations:issue-stream-performance")
  62. def test_unhandled(self):
  63. self.store_event(
  64. data={"timestamp": iso_format(before_now(seconds=500)), "fingerprint": ["group-1"]},
  65. project_id=self.project.id,
  66. )
  67. group_a = self.store_event(
  68. data={"timestamp": iso_format(before_now(seconds=1)), "fingerprint": ["group-a"]},
  69. project_id=self.project.id,
  70. ).group
  71. self.login_as(user=self.user)
  72. response = self.get_response(query="is:unresolved", groups=[group_a.id])
  73. response_data = sorted(response.data, key=lambda x: x["firstSeen"], reverse=True)
  74. assert response.status_code == 200
  75. assert len(response_data) == 1
  76. assert "title" not in response_data[0]
  77. assert "hasSeen" not in response_data[0]
  78. assert "stats" in response_data[0]
  79. assert "firstSeen" in response_data[0]
  80. assert "lastSeen" in response_data[0]
  81. assert "count" in response_data[0]
  82. assert "userCount" in response_data[0]
  83. assert "lifetime" in response_data[0]
  84. assert "filtered" in response_data[0]
  85. assert "isUnhandled" in response_data[0]
  86. def test_issue_platform_issue(self):
  87. event_id = uuid.uuid4().hex
  88. _, group_info = self.process_occurrence(
  89. event_id=event_id,
  90. project_id=self.project.id,
  91. type=ProfileFileIOGroupType.type_id,
  92. event_data={
  93. "fingerprint": ["group-1"],
  94. "timestamp": before_now(minutes=1).isoformat(),
  95. },
  96. )
  97. assert group_info is not None
  98. profile_group = group_info.group
  99. self.login_as(user=self.user)
  100. response = self.get_response(
  101. query=f"issue:{profile_group.qualified_short_id}", groups=[profile_group.id]
  102. )
  103. response_data = sorted(response.data, key=lambda x: x["firstSeen"], reverse=True)
  104. assert response.status_code == 200
  105. assert len(response_data) == 1
  106. assert int(response_data[0]["id"]) == profile_group.id
  107. assert "title" not in response_data[0]
  108. assert "hasSeen" not in response_data[0]
  109. assert "stats" in response_data[0]
  110. assert "firstSeen" in response_data[0]
  111. assert "lastSeen" in response_data[0]
  112. assert "count" in response_data[0]
  113. assert "userCount" in response_data[0]
  114. assert "lifetime" in response_data[0]
  115. assert "filtered" in response_data[0]
  116. def test_issue_platform_mixed_issue_not_title(self):
  117. event_id = uuid.uuid4().hex
  118. _, group_info = self.process_occurrence(
  119. event_id=event_id,
  120. project_id=self.project.id,
  121. type=ProfileFileIOGroupType.type_id,
  122. event_data={
  123. "fingerprint": ["group-a"],
  124. "timestamp": before_now(minutes=1).isoformat(),
  125. },
  126. )
  127. assert group_info is not None
  128. profile_group = group_info.group
  129. error_event = self.store_event(
  130. data={"timestamp": iso_format(before_now(seconds=500)), "fingerprint": ["group-1"]},
  131. project_id=self.project.id,
  132. )
  133. error_group = error_event.group
  134. self.login_as(user=self.user)
  135. response = self.get_response(
  136. query=f"!title:{profile_group.title}", groups=[profile_group.id, error_group.id]
  137. )
  138. response_data = sorted(response.data, key=lambda x: x["firstSeen"], reverse=True)
  139. assert response.status_code == 200
  140. assert [int(grp["id"]) for grp in response_data] == [profile_group.id, error_group.id]
  141. for data in response_data:
  142. assert "title" not in data
  143. assert "hasSeen" not in data
  144. assert "stats" in data
  145. assert "firstSeen" in data
  146. assert "lastSeen" in data
  147. assert "count" in data
  148. assert "userCount" in data
  149. assert "lifetime" in data
  150. assert "filtered" in data
  151. def test_no_matching_groups(self):
  152. self.login_as(user=self.user)
  153. response = self.get_response(sort_by="date", limit=10, query="is:unresolved", groups=[1337])
  154. assert response.status_code == 400
  155. def test_simple_with_project(self):
  156. self.store_event(
  157. data={"timestamp": iso_format(before_now(seconds=500)), "fingerprint": ["group-1"]},
  158. project_id=self.project.id,
  159. )
  160. group_a = self.store_event(
  161. data={"timestamp": iso_format(before_now(seconds=1)), "fingerprint": ["group-a"]},
  162. project_id=self.project.id,
  163. ).group
  164. self.store_event(
  165. data={"timestamp": iso_format(before_now(seconds=2)), "fingerprint": ["group-b"]},
  166. project_id=self.project.id,
  167. )
  168. group_c = self.store_event(
  169. data={"timestamp": iso_format(before_now(seconds=3)), "fingerprint": ["group-c"]},
  170. project_id=self.project.id,
  171. ).group
  172. self.login_as(user=self.user)
  173. response = self.get_response(
  174. query=f"project:{self.project.slug}", groups=[group_a.id, group_c.id]
  175. )
  176. assert response.status_code == 200
  177. assert len(response.data) == 2
  178. def test_query_timestamp(self):
  179. self.store_event(
  180. data={"timestamp": iso_format(before_now(seconds=500)), "fingerprint": ["group-1"]},
  181. project_id=self.project.id,
  182. )
  183. event2 = self.store_event(
  184. data={"timestamp": iso_format(before_now(seconds=1)), "fingerprint": ["group-a"]},
  185. project_id=self.project.id,
  186. )
  187. self.store_event(
  188. data={"timestamp": iso_format(before_now(seconds=2)), "fingerprint": ["group-b"]},
  189. project_id=self.project.id,
  190. )
  191. event4 = self.store_event(
  192. data={"timestamp": iso_format(before_now(seconds=3)), "fingerprint": ["group-c"]},
  193. project_id=self.project.id,
  194. )
  195. group_a = event2.group
  196. group_c = event4.group
  197. self.login_as(user=self.user)
  198. response = self.get_response(
  199. query=f"timestamp:>{iso_format(before_now(seconds=3))} timestamp:<{iso_format(before_now(seconds=1))}",
  200. groups=[group_a.id, group_c.id],
  201. )
  202. assert response.status_code == 200
  203. assert len(response.data) == 2