test_organization_group_index_stats.py 8.9 KB

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