test_project_event_details.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  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_RENDER_BLOCKING_ASSET_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_RENDER_BLOCKING_ASSET_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_RENDER_BLOCKING_ASSET_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. response = self.client.get(url, format="json", data={"group_id": self.group.id})
  178. assert response.status_code == 200, response.content
  179. assert response.data["id"] == str(self.cur_transaction_event.event_id)
  180. assert response.data["nextEventID"] == str(self.next_transaction_event.event_id)
  181. assert response.data["previousEventID"] == str(self.prev_transaction_event.event_id)
  182. assert response.data["groupID"] == str(self.cur_transaction_event.groups[0].id)
  183. def test_no_previous_event(self):
  184. """Test the case in which there is no previous event"""
  185. url = reverse(
  186. "sentry-api-0-project-event-details",
  187. kwargs={
  188. "event_id": self.prev_transaction_event.event_id,
  189. "project_slug": self.prev_transaction_event.project.slug,
  190. "organization_slug": self.prev_transaction_event.project.organization.slug,
  191. },
  192. )
  193. response = self.client.get(url, format="json", data={"group_id": self.group.id})
  194. assert response.status_code == 200, response.content
  195. assert response.data["id"] == str(self.prev_transaction_event.event_id)
  196. assert response.data["previousEventID"] is None
  197. assert response.data["nextEventID"] == self.cur_transaction_event.event_id
  198. assert response.data["groupID"] == str(self.prev_transaction_event.groups[0].id)
  199. def test_ignores_different_group(self):
  200. """Test that a different group's events aren't attributed to the one that was passed"""
  201. url = reverse(
  202. "sentry-api-0-project-event-details",
  203. kwargs={
  204. "event_id": self.next_transaction_event.event_id,
  205. "project_slug": self.next_transaction_event.project.slug,
  206. "organization_slug": self.next_transaction_event.project.organization.slug,
  207. },
  208. )
  209. response = self.client.get(url, format="json", data={"group_id": self.group.id})
  210. assert response.status_code == 200, response.content
  211. assert response.data["id"] == str(self.next_transaction_event.event_id)
  212. assert response.data["nextEventID"] is None
  213. def test_no_group_id(self):
  214. """Test the case where a group_id was not passed"""
  215. url = reverse(
  216. "sentry-api-0-project-event-details",
  217. kwargs={
  218. "event_id": self.cur_transaction_event.event_id,
  219. "project_slug": self.cur_transaction_event.project.slug,
  220. "organization_slug": self.cur_transaction_event.project.organization.slug,
  221. },
  222. )
  223. response = self.client.get(url, format="json")
  224. assert response.status_code == 200, response.content
  225. assert response.data["id"] == str(self.cur_transaction_event.event_id)
  226. assert response.data["previousEventID"] is None
  227. assert response.data["nextEventID"] is None
  228. assert response.data["groupID"] is None
  229. @region_silo_test
  230. class ProjectEventJsonEndpointTest(APITestCase, SnubaTestCase):
  231. def setUp(self):
  232. super().setUp()
  233. self.login_as(user=self.user)
  234. self.event_id = "c" * 32
  235. self.fingerprint = ["group_2"]
  236. self.min_ago = iso_format(before_now(minutes=1))
  237. self.event = self.store_event(
  238. data={
  239. "event_id": self.event_id,
  240. "timestamp": self.min_ago,
  241. "fingerprint": self.fingerprint,
  242. "user": {"email": self.user.email},
  243. },
  244. project_id=self.project.id,
  245. )
  246. self.url = reverse(
  247. "sentry-api-0-event-json",
  248. kwargs={
  249. "organization_slug": self.organization.slug,
  250. "project_slug": self.project.slug,
  251. "event_id": self.event_id,
  252. },
  253. )
  254. def assert_event(self, data):
  255. assert data["event_id"] == self.event_id
  256. assert data["user"]["email"] == self.user.email
  257. assert data["datetime"][:19] == self.min_ago
  258. assert data["fingerprint"] == self.fingerprint
  259. def test_simple(self):
  260. response = self.client.get(self.url, format="json")
  261. assert response.status_code == 200, response.content
  262. self.assert_event(response.data)
  263. def test_event_does_not_exist(self):
  264. self.url = reverse(
  265. "sentry-api-0-event-json",
  266. kwargs={
  267. "organization_slug": self.organization.slug,
  268. "project_slug": self.project.slug,
  269. "event_id": "no" * 16,
  270. },
  271. )
  272. response = self.client.get(self.url, format="json")
  273. assert response.status_code == 404, response.content
  274. assert response.data == {"detail": "Event not found"}
  275. def test_user_unauthorized(self):
  276. user = self.create_user()
  277. self.login_as(user)
  278. response = self.client.get(self.url, format="json")
  279. assert response.status_code == 403, response.content
  280. assert response.data == {"detail": "You do not have permission to perform this action."}
  281. def test_project_not_associated_with_event(self):
  282. project2 = self.create_project(organization=self.organization)
  283. url = reverse(
  284. "sentry-api-0-event-json",
  285. kwargs={
  286. "organization_slug": self.organization.slug,
  287. "project_slug": project2.slug,
  288. "event_id": self.event_id,
  289. },
  290. )
  291. response = self.client.get(url, format="json")
  292. assert response.status_code == 404, response.content
  293. assert response.data == {"detail": "Event not found"}