test_minidump_full.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. from __future__ import absolute_import
  2. import pytest
  3. import zipfile
  4. from sentry.utils.compat.mock import patch
  5. from six import BytesIO
  6. from django.core.urlresolvers import reverse
  7. from django.core.files.uploadedfile import SimpleUploadedFile
  8. from sentry import eventstore
  9. from sentry.testutils import TransactionTestCase
  10. from sentry.models import EventAttachment
  11. from sentry.lang.native.utils import STORE_CRASH_REPORTS_ALL
  12. from tests.symbolicator import get_fixture_path, insta_snapshot_stacktrace_data
  13. class SymbolicatorMinidumpIntegrationTest(TransactionTestCase):
  14. # For these tests to run, write `symbolicator.enabled: true` into your
  15. # `~/.sentry/config.yml` and run `sentry devservices up`
  16. @pytest.fixture(autouse=True)
  17. def initialize(self, live_server):
  18. self.project.update_option("sentry:builtin_symbol_sources", [])
  19. new_prefix = live_server.url
  20. with patch("sentry.auth.system.is_internal_ip", return_value=True), self.options(
  21. {"system.url-prefix": new_prefix}
  22. ):
  23. # Run test case:
  24. yield
  25. def upload_symbols(self):
  26. url = reverse(
  27. "sentry-api-0-dsym-files",
  28. kwargs={
  29. "organization_slug": self.project.organization.slug,
  30. "project_slug": self.project.slug,
  31. },
  32. )
  33. self.login_as(user=self.user)
  34. out = BytesIO()
  35. f = zipfile.ZipFile(out, "w")
  36. f.write(get_fixture_path("windows.sym"), "crash.sym")
  37. f.close()
  38. response = self.client.post(
  39. url,
  40. {
  41. "file": SimpleUploadedFile(
  42. "symbols.zip", out.getvalue(), content_type="application/zip"
  43. )
  44. },
  45. format="multipart",
  46. )
  47. assert response.status_code == 201, response.content
  48. assert len(response.data) == 1
  49. def test_full_minidump(self):
  50. self.project.update_option("sentry:store_crash_reports", STORE_CRASH_REPORTS_ALL)
  51. self.upload_symbols()
  52. with self.feature("organizations:event-attachments"):
  53. attachment = BytesIO(b"Hello World!")
  54. attachment.name = "hello.txt"
  55. with open(get_fixture_path("windows.dmp"), "rb") as f:
  56. resp = self._postMinidumpWithHeader(
  57. f, {"sentry[logger]": "test-logger", "some_file": attachment}
  58. )
  59. assert resp.status_code == 200
  60. event_id = resp.content
  61. event = eventstore.get_event_by_id(self.project.id, event_id)
  62. insta_snapshot_stacktrace_data(self, event.data)
  63. assert event.data.get("logger") == "test-logger"
  64. # assert event.data.get("extra") == {"foo": "bar"}
  65. attachments = sorted(
  66. EventAttachment.objects.filter(event_id=event.event_id), key=lambda x: x.name
  67. )
  68. hello, minidump = attachments
  69. assert hello.name == "hello.txt"
  70. assert hello.file.type == "event.attachment"
  71. assert hello.file.checksum == "2ef7bde608ce5404e97d5f042f95f89f1c232871"
  72. assert minidump.name == "windows.dmp"
  73. assert minidump.file.type == "event.minidump"
  74. assert minidump.file.checksum == "74bb01c850e8d65d3ffbc5bad5cabc4668fce247"
  75. def test_full_minidump_json_extra(self):
  76. self.project.update_option("sentry:store_crash_reports", STORE_CRASH_REPORTS_ALL)
  77. self.upload_symbols()
  78. with self.feature("organizations:event-attachments"):
  79. with open(get_fixture_path("windows.dmp"), "rb") as f:
  80. resp = self._postMinidumpWithHeader(
  81. f, {"sentry": '{"logger":"test-logger"}', "foo": "bar"}
  82. )
  83. assert resp.status_code == 200
  84. event_id = resp.content
  85. event = eventstore.get_event_by_id(self.project.id, event_id)
  86. assert event.data.get("logger") == "test-logger"
  87. assert event.data.get("extra") == {"foo": "bar"}
  88. # Other assertions are performed by `test_full_minidump`
  89. def test_full_minidump_invalid_extra(self):
  90. self.project.update_option("sentry:store_crash_reports", STORE_CRASH_REPORTS_ALL)
  91. self.upload_symbols()
  92. with self.feature("organizations:event-attachments"):
  93. with open(get_fixture_path("windows.dmp"), "rb") as f:
  94. resp = self._postMinidumpWithHeader(
  95. f, {"sentry": "{{{{", "foo": "bar"} # invalid sentry JSON
  96. )
  97. assert resp.status_code == 200
  98. event_id = resp.content
  99. event = eventstore.get_event_by_id(self.project.id, event_id)
  100. assert not event.data.get("logger")
  101. assert event.data.get("extra") == {"foo": "bar"}
  102. # Other assertions are performed by `test_full_minidump`
  103. def test_raw_minidump(self):
  104. self.project.update_option("sentry:store_crash_reports", STORE_CRASH_REPORTS_ALL)
  105. self.upload_symbols()
  106. with self.feature("organizations:event-attachments"):
  107. with open(get_fixture_path("windows.dmp"), "rb") as f:
  108. # Send as raw request body instead of multipart/form-data
  109. resp = self._postMinidumpWithHeader(f, raw=True)
  110. assert resp.status_code == 200
  111. event_id = resp.content
  112. event = eventstore.get_event_by_id(self.project.id, event_id)
  113. insta_snapshot_stacktrace_data(self, event.data)
  114. def test_missing_dsym(self):
  115. with self.feature("organizations:event-attachments"):
  116. with open(get_fixture_path("windows.dmp"), "rb") as f:
  117. resp = self._postMinidumpWithHeader(f, {"sentry[logger]": "test-logger"})
  118. assert resp.status_code == 200
  119. event_id = resp.content
  120. event = eventstore.get_event_by_id(self.project.id, event_id)
  121. insta_snapshot_stacktrace_data(self, event.data)
  122. assert not EventAttachment.objects.filter(event_id=event.event_id)