test_payload_full.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. import zipfile
  2. from io import BytesIO
  3. from unittest.mock import patch
  4. import pytest
  5. from django.core.files.uploadedfile import SimpleUploadedFile
  6. from django.urls import reverse
  7. from sentry import eventstore
  8. from sentry.models import File, ProjectDebugFile
  9. from sentry.testutils import RelayStoreHelper, TransactionTestCase
  10. from sentry.testutils.factories import get_fixture_path
  11. from sentry.testutils.helpers.datetime import before_now, iso_format
  12. from tests.symbolicator import insta_snapshot_native_stacktrace_data, redact_location
  13. # IMPORTANT:
  14. #
  15. # This test suite requires Symbolicator in order to run correctly.
  16. # Set `symbolicator.enabled: true` in your `~/.sentry/config.yml` and run `sentry devservices up`
  17. #
  18. # If you are using a local instance of Symbolicator, you need to
  19. # either change `system.url-prefix` option override inside `initialize` fixture to `system.internal-url-prefix`,
  20. # or add `127.0.0.1 host.docker.internal` entry to your `/etc/hosts`
  21. REAL_RESOLVING_EVENT_DATA = {
  22. "platform": "cocoa",
  23. "debug_meta": {
  24. "images": [
  25. {
  26. "type": "apple",
  27. "arch": "x86_64",
  28. "uuid": "502fc0a5-1ec1-3e47-9998-684fa139dca7",
  29. "image_vmaddr": "0x0000000100000000",
  30. "image_size": 4096,
  31. "image_addr": "0x0000000100000000",
  32. "name": "Foo.app/Contents/Foo",
  33. }
  34. ],
  35. "sdk_info": {
  36. "dsym_type": "macho",
  37. "sdk_name": "macOS",
  38. "version_major": 10,
  39. "version_minor": 12,
  40. "version_patchlevel": 4,
  41. },
  42. },
  43. "exception": {
  44. "values": [
  45. {
  46. "stacktrace": {
  47. "frames": [
  48. {"platform": "foobar", "function": "hi"},
  49. {"function": "unknown", "instruction_addr": "0x0000000100000fa0"},
  50. ]
  51. },
  52. "type": "Fail",
  53. "value": "fail",
  54. }
  55. ]
  56. },
  57. "timestamp": iso_format(before_now(seconds=1)),
  58. }
  59. class SymbolicatorResolvingIntegrationTest(RelayStoreHelper, TransactionTestCase):
  60. @pytest.fixture(autouse=True)
  61. def initialize(self, live_server):
  62. self.project.update_option("sentry:builtin_symbol_sources", [])
  63. with patch("sentry.auth.system.is_internal_ip", return_value=True), self.options(
  64. {"system.url-prefix": live_server.url}
  65. ):
  66. # Run test case
  67. yield
  68. def get_event(self, event_id):
  69. return eventstore.get_event_by_id(self.project.id, event_id)
  70. def test_real_resolving(self):
  71. url = reverse(
  72. "sentry-api-0-dsym-files",
  73. kwargs={
  74. "organization_slug": self.project.organization.slug,
  75. "project_slug": self.project.slug,
  76. },
  77. )
  78. self.login_as(user=self.user)
  79. out = BytesIO()
  80. f = zipfile.ZipFile(out, "w")
  81. f.write(get_fixture_path("native", "hello.dsym"), "dSYM/hello")
  82. f.close()
  83. response = self.client.post(
  84. url,
  85. {
  86. "file": SimpleUploadedFile(
  87. "symbols.zip", out.getvalue(), content_type="application/zip"
  88. )
  89. },
  90. format="multipart",
  91. )
  92. assert response.status_code == 201, response.content
  93. assert len(response.data) == 1
  94. event = self.post_and_retrieve_event(REAL_RESOLVING_EVENT_DATA)
  95. assert event.data["culprit"] == "main"
  96. candidates = event.data["debug_meta"]["images"][0]["candidates"]
  97. redact_location(candidates)
  98. event.data["debug_meta"]["images"][0]["candidates"] = candidates
  99. insta_snapshot_native_stacktrace_data(self, event.data)
  100. def test_debug_id_resolving(self):
  101. file = File.objects.create(
  102. name="crash.pdb", type="default", headers={"Content-Type": "text/x-breakpad"}
  103. )
  104. path = get_fixture_path("native", "windows.sym")
  105. with open(path, "rb") as f:
  106. file.putfile(f)
  107. ProjectDebugFile.objects.create(
  108. file=file,
  109. object_name="crash.pdb",
  110. cpu_name="x86",
  111. project_id=self.project.id,
  112. debug_id="3249d99d-0c40-4931-8610-f4e4fb0b6936-1",
  113. code_id="5AB380779000",
  114. )
  115. self.login_as(user=self.user)
  116. event_data = {
  117. "contexts": {
  118. "device": {"arch": "x86"},
  119. "os": {"build": "", "name": "Windows", "type": "os", "version": "10.0.14393"},
  120. },
  121. "debug_meta": {
  122. "images": [
  123. {
  124. "id": "3249d99d-0c40-4931-8610-f4e4fb0b6936-1",
  125. "image_addr": "0x2a0000",
  126. "image_size": 36864,
  127. "name": "C:\\projects\\breakpad-tools\\windows\\Release\\crash.exe",
  128. "type": "symbolic",
  129. }
  130. ]
  131. },
  132. "exception": {
  133. "stacktrace": {
  134. "frames": [
  135. {
  136. "function": "<unknown>",
  137. "instruction_addr": "0x2a2a3d",
  138. "package": "C:\\projects\\breakpad-tools\\windows\\Release\\crash.exe",
  139. }
  140. ]
  141. },
  142. "thread_id": 1636,
  143. "type": "EXCEPTION_ACCESS_VIOLATION_WRITE",
  144. "value": "Fatal Error: EXCEPTION_ACCESS_VIOLATION_WRITE",
  145. },
  146. "platform": "native",
  147. "timestamp": iso_format(before_now(seconds=1)),
  148. }
  149. event = self.post_and_retrieve_event(event_data)
  150. assert event.data["culprit"] == "main"
  151. candidates = event.data["debug_meta"]["images"][0]["candidates"]
  152. redact_location(candidates)
  153. event.data["debug_meta"]["images"][0]["candidates"] = candidates
  154. insta_snapshot_native_stacktrace_data(self, event.data)
  155. def test_missing_dsym(self):
  156. self.login_as(user=self.user)
  157. event = self.post_and_retrieve_event(REAL_RESOLVING_EVENT_DATA)
  158. assert event.data["culprit"] == "unknown"
  159. insta_snapshot_native_stacktrace_data(self, event.data)
  160. def test_missing_debug_images(self):
  161. self.login_as(user=self.user)
  162. payload = dict(project=self.project.id, **REAL_RESOLVING_EVENT_DATA)
  163. del payload["debug_meta"]
  164. event = self.post_and_retrieve_event(payload)
  165. assert event.data["culprit"] == "unknown"
  166. insta_snapshot_native_stacktrace_data(self, event.data)
  167. def test_resolving_with_candidates_sentry_source(self):
  168. # Checks the candidates with a sentry source URI for location
  169. file = File.objects.create(
  170. name="crash.pdb", type="default", headers={"Content-Type": "text/x-breakpad"}
  171. )
  172. path = get_fixture_path("native", "windows.sym")
  173. with open(path, "rb") as f:
  174. file.putfile(f)
  175. ProjectDebugFile.objects.create(
  176. file=file,
  177. object_name="crash.pdb",
  178. cpu_name="x86",
  179. project_id=self.project.id,
  180. debug_id="3249d99d-0c40-4931-8610-f4e4fb0b6936-1",
  181. code_id="5AB380779000",
  182. )
  183. self.login_as(user=self.user)
  184. event_data = {
  185. "contexts": {
  186. "device": {"arch": "x86"},
  187. },
  188. "debug_meta": {
  189. "images": [
  190. {
  191. "id": "3249d99d-0c40-4931-8610-f4e4fb0b6936-1",
  192. "image_addr": "0x2a0000",
  193. "image_size": 36864,
  194. "name": "C:\\projects\\breakpad-tools\\windows\\Release\\crash.exe",
  195. "type": "symbolic",
  196. }
  197. ]
  198. },
  199. "exception": {
  200. "stacktrace": {
  201. "frames": [
  202. {
  203. "instruction_addr": "0x2a2a3d",
  204. }
  205. ]
  206. },
  207. "type": "EXCEPTION_ACCESS_VIOLATION_WRITE",
  208. "value": "Fatal Error: EXCEPTION_ACCESS_VIOLATION_WRITE",
  209. },
  210. "platform": "native",
  211. "timestamp": iso_format(before_now(seconds=1)),
  212. }
  213. event = self.post_and_retrieve_event(event_data)
  214. assert event.data["culprit"] == "main"
  215. candidates = event.data["debug_meta"]["images"][0]["candidates"]
  216. redact_location(candidates)
  217. self.insta_snapshot(candidates)