test_sentry_api_compat.py 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. import json
  2. from typing import List, Dict
  3. from django.urls import reverse
  4. from rest_framework.test import APITestCase
  5. from model_bakery import baker
  6. from event_store.test_data.django_error_factory import template_error, message
  7. from event_store.test_data.js_error_factory import throw_error
  8. from event_store.test_data.csp import mdn_sample_csp
  9. from organizations_ext.models import OrganizationUserRole
  10. from issues.models import Event
  11. class SentryAPICompatTestCase(APITestCase):
  12. def setUp(self):
  13. self.user = baker.make("users.user")
  14. self.organization = baker.make("organizations_ext.Organization")
  15. self.organization.add_user(self.user, OrganizationUserRole.ADMIN)
  16. self.team = baker.make("teams.Team", organization=self.organization)
  17. self.team.members.add(self.user)
  18. self.project = baker.make("projects.Project", organization=self.organization)
  19. self.project.team_set.add(self.team)
  20. self.client.force_login(self.user)
  21. key = self.project.projectkey_set.first().public_key
  22. self.event_store_url = (
  23. reverse("event_store", args=[self.project.id]) + "?sentry_key=" + key.hex
  24. )
  25. self.csp_store_url = (
  26. reverse("csp_store", args=[self.project.id]) + "?sentry_key=" + key.hex
  27. )
  28. def assertCompareData(self, data1: Dict, data2: Dict, fields: List[str]):
  29. """ Compare data of two dict objects. Compare only provided fields list """
  30. for field in fields:
  31. self.assertEqual(
  32. data1.get(field), data2.get(field), f"Failed for field '{field}'",
  33. )
  34. def get_json_data(self, path: str):
  35. with open(path) as json_file:
  36. return json.load(json_file)
  37. def get_project_events_detail(self, event_id):
  38. return reverse(
  39. "project-events-detail",
  40. kwargs={
  41. "project_pk": f"{self.project.organization.slug}/{self.project.slug}",
  42. "pk": event_id,
  43. },
  44. )
  45. def test_template_error(self):
  46. res = self.client.post(self.event_store_url, template_error, format="json")
  47. self.assertEqual(res.status_code, 200)
  48. event_id = res.data["id"]
  49. url = self.get_project_events_detail(event_id)
  50. res = self.client.get(url)
  51. self.assertEqual(res.status_code, 200)
  52. issue = Event.objects.get(event_id=event_id).issue
  53. data = self.get_json_data(
  54. "event_store/test_data/django_template_error_event.json"
  55. )
  56. self.assertCompareData(res.data, data, ["culprit", "title", "metadata"])
  57. res_frames = res.data["entries"][0]["data"]["values"][0]["stacktrace"]["frames"]
  58. frames = data["entries"][0]["data"]["values"][0]["stacktrace"]["frames"]
  59. for i in range(9):
  60. # absPath don't always match - needs fixed
  61. self.assertCompareData(res_frames[i], frames[i], ["absPath"])
  62. for res_frame, frame in zip(res_frames, frames):
  63. self.assertCompareData(
  64. res_frame,
  65. frame,
  66. ["lineNo", "function", "filename", "module", "context"],
  67. )
  68. if frame.get("vars"):
  69. self.assertCompareData(
  70. res_frame["vars"], frame["vars"], ["exc", "request"]
  71. )
  72. if frame["vars"].get("get_response"):
  73. # Memory address is different, truncate it
  74. self.assertEqual(
  75. res_frame["vars"]["get_response"][:-16],
  76. frame["vars"]["get_response"][:-16],
  77. )
  78. self.assertCompareData(
  79. res.data["entries"][1]["data"],
  80. data["entries"][1]["data"],
  81. ["env", "headers", "url", "method", "inferredContentType"],
  82. )
  83. url = reverse("issue-detail", kwargs={"pk": issue.pk})
  84. res = self.client.get(url)
  85. self.assertEqual(res.status_code, 200)
  86. data = self.get_json_data(
  87. "event_store/test_data/django_template_error_issue.json"
  88. )
  89. self.assertCompareData(res.data, data, ["title", "metadata"])
  90. def test_throw_error(self):
  91. res = self.client.post(self.event_store_url, throw_error, format="json")
  92. self.assertEqual(res.status_code, 200)
  93. event_id = res.data["id"]
  94. url = self.get_project_events_detail(event_id)
  95. res = self.client.get(url)
  96. self.assertEqual(res.status_code, 200)
  97. issue = Event.objects.get(event_id=event_id).issue
  98. data = self.get_json_data("event_store/test_data/js_throw_error_event.json")
  99. self.assertCompareData(res.data, data, ["title"])
  100. self.assertEqual(
  101. res.data["culprit"],
  102. "viewWrappedDebugError(http://localhost:4200/vendor.js)",
  103. "Not perfect match, should really be viewWrappedDebugError(vendor)",
  104. )
  105. self.assertEqual(res.data["metadata"]["function"], data["metadata"]["function"])
  106. url = reverse("issue-detail", kwargs={"pk": issue.pk})
  107. res = self.client.get(url)
  108. self.assertEqual(res.status_code, 200)
  109. data = self.get_json_data("event_store/test_data/js_throw_error_issue.json")
  110. self.assertCompareData(res.data, data, ["title"])
  111. self.assertEqual(res.data["metadata"]["function"], data["metadata"]["function"])
  112. def test_dotnet_error(self):
  113. sdk_error = self.get_json_data(
  114. "event_store/test_data/incoming_events/dotnet_error.json"
  115. )
  116. res = self.client.post(self.event_store_url, sdk_error, format="json")
  117. self.assertEqual(res.status_code, 200)
  118. self.assertEqual(Event.objects.count(), 1)
  119. event_id = res.data["id"]
  120. sentry_data = self.get_json_data(
  121. "event_store/test_data/oss_sentry_events/dotnet_error.json"
  122. )
  123. url = self.get_project_events_detail(event_id)
  124. res = self.client.get(url)
  125. self.assertEqual(res.status_code, 200)
  126. self.assertCompareData(
  127. res.data,
  128. sentry_data,
  129. ["eventID", "title", "culprit", "platform", "type", "metadata"],
  130. )
  131. def test_csp_event(self):
  132. data = mdn_sample_csp
  133. res = self.client.post(self.csp_store_url, data, format="json")
  134. self.assertEqual(res.status_code, 200)
  135. event_id = res.data["id"]
  136. url = self.get_project_events_detail(event_id)
  137. res = self.client.get(url)
  138. self.assertEqual(res.status_code, 200)
  139. data = self.get_json_data("event_store/test_data/csp_event.json")
  140. self.assertCompareData(res.data, data, ["title", "culprit", "type", "metadata"])
  141. self.assertEqual(res.data["entries"][0], data["entries"][0])
  142. self.assertEqual(res.data["entries"][1], data["entries"][1])
  143. def test_message_event(self):
  144. """ A generic message made with the Sentry SDK. Generally has less data than exceptions. """
  145. res = self.client.post(self.event_store_url, message, format="json")
  146. self.assertEqual(res.status_code, 200)
  147. event_id = res.data["id"]
  148. url = self.get_project_events_detail(event_id)
  149. res = self.client.get(url)
  150. self.assertEqual(res.status_code, 200)
  151. data = self.get_json_data("event_store/test_data/django_message_event.json")
  152. self.assertCompareData(
  153. res.data,
  154. data,
  155. ["title", "culprit", "type", "metadata", "platform", "packages"],
  156. )
  157. def test_python_logging(self):
  158. """ Test Sentry SDK logging integration based event """
  159. sdk_error = self.get_json_data(
  160. "event_store/test_data/incoming_events/python_logging.json"
  161. )
  162. res = self.client.post(self.event_store_url, sdk_error, format="json")
  163. self.assertEqual(res.status_code, 200)
  164. self.assertEqual(Event.objects.count(), 1)
  165. event_id = res.data["id"]
  166. sentry_data = self.get_json_data(
  167. "event_store/test_data/oss_sentry_events/python_logging.json"
  168. )
  169. url = self.get_project_events_detail(event_id)
  170. res = self.client.get(url)
  171. self.assertEqual(res.status_code, 200)
  172. self.assertCompareData(
  173. res.data,
  174. sentry_data,
  175. ["title", "culprit", "type", "metadata", "platform", "packages"],
  176. )