test_project_event_details.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. from django.urls import reverse
  2. from sentry.testutils import APITestCase, SnubaTestCase
  3. from sentry.testutils.helpers.datetime import before_now, iso_format
  4. from sentry.testutils.silo import region_silo_test
  5. from sentry.types.issues import GroupType
  6. @region_silo_test
  7. class ProjectEventDetailsTest(APITestCase, SnubaTestCase):
  8. def setUp(self):
  9. super().setUp()
  10. self.login_as(user=self.user)
  11. project = self.create_project()
  12. one_min_ago = iso_format(before_now(minutes=1))
  13. two_min_ago = iso_format(before_now(minutes=2))
  14. three_min_ago = iso_format(before_now(minutes=3))
  15. four_min_ago = iso_format(before_now(minutes=4))
  16. self.prev_event = self.store_event(
  17. data={"event_id": "a" * 32, "timestamp": four_min_ago, "fingerprint": ["group-1"]},
  18. project_id=project.id,
  19. )
  20. self.cur_event = self.store_event(
  21. data={"event_id": "b" * 32, "timestamp": three_min_ago, "fingerprint": ["group-1"]},
  22. project_id=project.id,
  23. )
  24. self.next_event = self.store_event(
  25. data={
  26. "event_id": "c" * 32,
  27. "timestamp": two_min_ago,
  28. "fingerprint": ["group-1"],
  29. "environment": "production",
  30. "tags": {"environment": "production"},
  31. },
  32. project_id=project.id,
  33. )
  34. # Event in different group
  35. self.store_event(
  36. data={
  37. "event_id": "d" * 32,
  38. "timestamp": one_min_ago,
  39. "fingerprint": ["group-2"],
  40. "environment": "production",
  41. "tags": {"environment": "production"},
  42. },
  43. project_id=project.id,
  44. )
  45. def test_simple(self):
  46. url = reverse(
  47. "sentry-api-0-project-event-details",
  48. kwargs={
  49. "event_id": self.cur_event.event_id,
  50. "project_slug": self.cur_event.project.slug,
  51. "organization_slug": self.cur_event.project.organization.slug,
  52. },
  53. )
  54. response = self.client.get(url, format="json")
  55. assert response.status_code == 200, response.content
  56. assert response.data["id"] == str(self.cur_event.event_id)
  57. assert response.data["nextEventID"] == str(self.next_event.event_id)
  58. assert response.data["previousEventID"] == str(self.prev_event.event_id)
  59. assert response.data["groupID"] == str(self.cur_event.group.id)
  60. def test_snuba_no_prev(self):
  61. url = reverse(
  62. "sentry-api-0-project-event-details",
  63. kwargs={
  64. "event_id": self.prev_event.event_id,
  65. "project_slug": self.prev_event.project.slug,
  66. "organization_slug": self.prev_event.project.organization.slug,
  67. },
  68. )
  69. response = self.client.get(url, format="json")
  70. assert response.status_code == 200, response.content
  71. assert response.data["id"] == str(self.prev_event.event_id)
  72. assert response.data["previousEventID"] is None
  73. assert response.data["nextEventID"] == self.cur_event.event_id
  74. assert response.data["groupID"] == str(self.prev_event.group.id)
  75. def test_snuba_with_environment(self):
  76. url = reverse(
  77. "sentry-api-0-project-event-details",
  78. kwargs={
  79. "event_id": self.cur_event.event_id,
  80. "project_slug": self.cur_event.project.slug,
  81. "organization_slug": self.cur_event.project.organization.slug,
  82. },
  83. )
  84. response = self.client.get(
  85. url, format="json", data={"environment": ["production", "staging"]}
  86. )
  87. assert response.status_code == 200, response.content
  88. assert response.data["id"] == str(self.cur_event.event_id)
  89. assert response.data["previousEventID"] is None
  90. assert response.data["nextEventID"] == self.next_event.event_id
  91. assert response.data["groupID"] == str(self.prev_event.group.id)
  92. def test_ignores_different_group(self):
  93. url = reverse(
  94. "sentry-api-0-project-event-details",
  95. kwargs={
  96. "event_id": self.next_event.event_id,
  97. "project_slug": self.next_event.project.slug,
  98. "organization_slug": self.next_event.project.organization.slug,
  99. },
  100. )
  101. response = self.client.get(url, format="json")
  102. assert response.status_code == 200, response.content
  103. assert response.data["id"] == str(self.next_event.event_id)
  104. assert response.data["nextEventID"] is None
  105. @region_silo_test
  106. class ProjectEventDetailsTransactionTest(APITestCase, SnubaTestCase):
  107. def setUp(self):
  108. super().setUp()
  109. self.login_as(user=self.user)
  110. project = self.create_project()
  111. one_min_ago = iso_format(before_now(minutes=1))
  112. two_min_ago = iso_format(before_now(minutes=2))
  113. three_min_ago = iso_format(before_now(minutes=3))
  114. four_min_ago = iso_format(before_now(minutes=4))
  115. transaction_event_data = {
  116. "level": "info",
  117. "message": "ayoo",
  118. "type": "transaction",
  119. "culprit": "app/components/events/eventEntries in map",
  120. "contexts": {"trace": {"trace_id": "b" * 32, "span_id": "c" * 16, "op": ""}},
  121. }
  122. self.prev_transaction_event = self.store_event(
  123. data={
  124. **transaction_event_data,
  125. "event_id": "a" * 32,
  126. "timestamp": four_min_ago,
  127. "start_timestamp": four_min_ago,
  128. "fingerprint": [f"{GroupType.PERFORMANCE_SLOW_SPAN.value}-group1"],
  129. },
  130. project_id=project.id,
  131. )
  132. self.cur_transaction_event = self.store_event(
  133. data={
  134. **transaction_event_data,
  135. "event_id": "b" * 32,
  136. "timestamp": three_min_ago,
  137. "start_timestamp": three_min_ago,
  138. "fingerprint": [f"{GroupType.PERFORMANCE_SLOW_SPAN.value}-group1"],
  139. },
  140. project_id=project.id,
  141. )
  142. self.next_transaction_event = self.store_event(
  143. data={
  144. **transaction_event_data,
  145. "event_id": "c" * 32,
  146. "timestamp": two_min_ago,
  147. "start_timestamp": two_min_ago,
  148. "environment": "production",
  149. "tags": {"environment": "production"},
  150. "fingerprint": [f"{GroupType.PERFORMANCE_SLOW_SPAN.value}-group1"],
  151. },
  152. project_id=project.id,
  153. )
  154. self.group = self.prev_transaction_event.groups[0]
  155. # Event in different group
  156. self.store_event(
  157. data={
  158. **transaction_event_data,
  159. "event_id": "d" * 32,
  160. "timestamp": one_min_ago,
  161. "start_timestamp": one_min_ago,
  162. "environment": "production",
  163. "tags": {"environment": "production"},
  164. },
  165. project_id=project.id,
  166. )
  167. def test_transaction_event(self):
  168. """Test that you can look up a transaction event w/ a prev and next event"""
  169. url = reverse(
  170. "sentry-api-0-project-event-details",
  171. kwargs={
  172. "event_id": self.cur_transaction_event.event_id,
  173. "project_slug": self.cur_transaction_event.project.slug,
  174. "organization_slug": self.cur_transaction_event.project.organization.slug,
  175. },
  176. )
  177. with self.feature("organizations:performance-issues"):
  178. response = self.client.get(url, format="json", data={"group_id": self.group.id})
  179. assert response.status_code == 200, response.content
  180. assert response.data["id"] == str(self.cur_transaction_event.event_id)
  181. assert response.data["nextEventID"] == str(self.next_transaction_event.event_id)
  182. assert response.data["previousEventID"] == str(self.prev_transaction_event.event_id)
  183. assert response.data["groupID"] == str(self.cur_transaction_event.groups[0].id)
  184. def test_no_previous_event(self):
  185. """Test the case in which there is no previous event"""
  186. url = reverse(
  187. "sentry-api-0-project-event-details",
  188. kwargs={
  189. "event_id": self.prev_transaction_event.event_id,
  190. "project_slug": self.prev_transaction_event.project.slug,
  191. "organization_slug": self.prev_transaction_event.project.organization.slug,
  192. },
  193. )
  194. with self.feature("organizations:performance-issues"):
  195. response = self.client.get(url, format="json", data={"group_id": self.group.id})
  196. assert response.status_code == 200, response.content
  197. assert response.data["id"] == str(self.prev_transaction_event.event_id)
  198. assert response.data["previousEventID"] is None
  199. assert response.data["nextEventID"] == self.cur_transaction_event.event_id
  200. assert response.data["groupID"] == str(self.prev_transaction_event.groups[0].id)
  201. def test_ignores_different_group(self):
  202. """Test that a different group's events aren't attributed to the one that was passed"""
  203. url = reverse(
  204. "sentry-api-0-project-event-details",
  205. kwargs={
  206. "event_id": self.next_transaction_event.event_id,
  207. "project_slug": self.next_transaction_event.project.slug,
  208. "organization_slug": self.next_transaction_event.project.organization.slug,
  209. },
  210. )
  211. with self.feature("organizations:performance-issues"):
  212. response = self.client.get(url, format="json", data={"group_id": self.group.id})
  213. assert response.status_code == 200, response.content
  214. assert response.data["id"] == str(self.next_transaction_event.event_id)
  215. assert response.data["nextEventID"] is None
  216. def test_no_group_id(self):
  217. """Test the case where a group_id was not passed"""
  218. url = reverse(
  219. "sentry-api-0-project-event-details",
  220. kwargs={
  221. "event_id": self.cur_transaction_event.event_id,
  222. "project_slug": self.cur_transaction_event.project.slug,
  223. "organization_slug": self.cur_transaction_event.project.organization.slug,
  224. },
  225. )
  226. with self.feature("organizations:performance-issues"):
  227. response = self.client.get(url, format="json")
  228. assert response.status_code == 200, response.content
  229. assert response.data["id"] == str(self.cur_transaction_event.event_id)
  230. assert response.data["previousEventID"] is None
  231. assert response.data["nextEventID"] is None
  232. assert response.data["groupID"] is None
  233. @region_silo_test
  234. class ProjectEventJsonEndpointTest(APITestCase, SnubaTestCase):
  235. def setUp(self):
  236. super().setUp()
  237. self.login_as(user=self.user)
  238. self.event_id = "c" * 32
  239. self.fingerprint = ["group_2"]
  240. self.min_ago = iso_format(before_now(minutes=1))
  241. self.event = self.store_event(
  242. data={
  243. "event_id": self.event_id,
  244. "timestamp": self.min_ago,
  245. "fingerprint": self.fingerprint,
  246. "user": {"email": self.user.email},
  247. },
  248. project_id=self.project.id,
  249. )
  250. self.url = reverse(
  251. "sentry-api-0-event-json",
  252. kwargs={
  253. "organization_slug": self.organization.slug,
  254. "project_slug": self.project.slug,
  255. "event_id": self.event_id,
  256. },
  257. )
  258. def assert_event(self, data):
  259. assert data["event_id"] == self.event_id
  260. assert data["user"]["email"] == self.user.email
  261. assert data["datetime"][:19] == self.min_ago
  262. assert data["fingerprint"] == self.fingerprint
  263. def test_simple(self):
  264. response = self.client.get(self.url, format="json")
  265. assert response.status_code == 200, response.content
  266. self.assert_event(response.data)
  267. def test_event_does_not_exist(self):
  268. self.url = reverse(
  269. "sentry-api-0-event-json",
  270. kwargs={
  271. "organization_slug": self.organization.slug,
  272. "project_slug": self.project.slug,
  273. "event_id": "no" * 16,
  274. },
  275. )
  276. response = self.client.get(self.url, format="json")
  277. assert response.status_code == 404, response.content
  278. assert response.data == {"detail": "Event not found"}
  279. def test_user_unauthorized(self):
  280. user = self.create_user()
  281. self.login_as(user)
  282. response = self.client.get(self.url, format="json")
  283. assert response.status_code == 403, response.content
  284. assert response.data == {"detail": "You do not have permission to perform this action."}
  285. def test_project_not_associated_with_event(self):
  286. project2 = self.create_project(organization=self.organization)
  287. url = reverse(
  288. "sentry-api-0-event-json",
  289. kwargs={
  290. "organization_slug": self.organization.slug,
  291. "project_slug": project2.slug,
  292. "event_id": self.event_id,
  293. },
  294. )
  295. response = self.client.get(url, format="json")
  296. assert response.status_code == 404, response.content
  297. assert response.data == {"detail": "Event not found"}