test_organization_group_index_stats.py 9.3 KB

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