test_envelope_api.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. import json
  2. import uuid
  3. from unittest import mock
  4. from urllib.parse import urlparse
  5. from django.core.cache import cache
  6. from django.test.client import FakePayload
  7. from django.urls import reverse
  8. from apps.issue_events.models import IssueEvent
  9. from apps.performance.models import TransactionEvent
  10. from .utils import EventIngestTestCase
  11. class EnvelopeAPITestCase(EventIngestTestCase):
  12. """
  13. These test specifically test the envelope API and act more of integration test
  14. Use test_process_issue_events.py for testing Event Ingest more specifically
  15. """
  16. def setUp(self):
  17. super().setUp()
  18. cache.clear()
  19. self.url = reverse("api:event_envelope", args=[self.project.id]) + self.params
  20. self.django_event = self.get_json_data(
  21. "apps/event_ingest/tests/test_data/envelopes/django_message.json"
  22. )
  23. self.js_event = self.get_json_data(
  24. "apps/event_ingest/tests/test_data/envelopes/js_angular_message.json"
  25. )
  26. def get_payload(self, path, replace_id=False, set_release=None):
  27. """Convert JSON file into envelope format string"""
  28. with open(path) as json_file:
  29. json_data = json.load(json_file)
  30. if replace_id:
  31. new_id = uuid.uuid4().hex
  32. json_data[0]["event_id"] = new_id
  33. json_data[2]["event_id"] = new_id
  34. if set_release:
  35. json_data[0]["trace"]["release"] = set_release
  36. json_data[2]["release"] = set_release
  37. data = "\n".join([json.dumps(line) for line in json_data])
  38. return data
  39. def get_string_payload(self, json_data):
  40. """Convert JSON data into envelope format string"""
  41. return "\n".join([json.dumps(line) for line in json_data])
  42. def test_envelope_api(self):
  43. with self.assertNumQueries(16):
  44. res = self.client.post(
  45. self.url, self.django_event, content_type="application/json"
  46. )
  47. self.assertContains(res, self.django_event[0]["event_id"])
  48. self.assertEqual(self.project.issues.count(), 1)
  49. self.assertEqual(IssueEvent.objects.count(), 1)
  50. def test_envelope_api_content_type(self):
  51. js_payload = self.get_string_payload(self.js_event)
  52. res = self.client.post(
  53. self.url, js_payload, content_type="text/plain;charset=UTF-8"
  54. )
  55. self.assertEqual(res.status_code, 200)
  56. self.assertContains(res, self.js_event[0]["event_id"])
  57. self.assertEqual(self.project.issues.count(), 1)
  58. self.assertEqual(IssueEvent.objects.count(), 1)
  59. def test_accept_transaction(self):
  60. data = self.get_payload("events/test_data/transactions/django_simple.json")
  61. res = self.client.post(
  62. self.url, data, content_type="application/x-sentry-envelope"
  63. )
  64. print(res.json())
  65. self.assertEqual(res.status_code, 200)
  66. self.assertTrue(TransactionEvent.objects.exists())
  67. def test_malformed_sdk_packages(self):
  68. event = self.django_event
  69. event[2]["sdk"]["packages"] = {
  70. "name": "cocoapods",
  71. "version": "just_aint_right",
  72. }
  73. res = self.client.post(self.url, event, content_type="application/json")
  74. self.assertEqual(res.status_code, 200)
  75. self.assertEqual(IssueEvent.objects.count(), 1)
  76. def test_nothing_event(self):
  77. res = self.client.post(
  78. self.url,
  79. '{}\n{"lol": "haha"}',
  80. content_type="application/x-sentry-envelope",
  81. )
  82. self.assertEqual(res.status_code, 200)
  83. @mock.patch("glitchtip.api.api.logger.warning")
  84. def test_invalid_event_warning(self, mock_log):
  85. res = self.client.post(
  86. self.url,
  87. '{"event_id": "A"}\n{"type": "nothing"}',
  88. content_type="application/x-sentry-envelope",
  89. )
  90. self.assertEqual(res.status_code, 422)
  91. mock_log.assert_called_once()
  92. @mock.patch("glitchtip.api.api.logger.warning")
  93. def test_invalid_issue_event_warning(self, mock_log):
  94. res = self.client.post(
  95. self.url,
  96. '{}\n{"type": "event"}\n{"timestamp": false}',
  97. content_type="application/x-sentry-envelope",
  98. )
  99. self.assertEqual(res.status_code, 422)
  100. mock_log.assert_called_once()
  101. @mock.patch("glitchtip.api.parsers.logger.warning")
  102. def test_invalid_content_type(self, mock_log):
  103. res = self.client.post(
  104. self.url,
  105. '{}\n{"type": "event"}\n{"timestamp": false}',
  106. content_type="application/wut",
  107. )
  108. self.assertEqual(res.status_code, 400)
  109. mock_log.assert_called_once()
  110. def test_no_content_type(self):
  111. data = (
  112. b'{"event_id": "5a337086bc1545448e29ed938729cba3"}\n{"type": "event"}\n{}'
  113. )
  114. parsed = urlparse(self.url) # path can be lazy
  115. r = {
  116. "PATH_INFO": self.client._get_path(parsed),
  117. "REQUEST_METHOD": "POST",
  118. "SERVER_PORT": "80",
  119. "wsgi.url_scheme": "http",
  120. "CONTENT_LENGTH": str(len(data)),
  121. "HTTP_X_SENTRY_AUTH": f"x=x sentry_key={self.projectkey.public_key.hex}",
  122. "wsgi.input": FakePayload(data),
  123. }
  124. res = self.client.request(**r)
  125. self.assertEqual(res.status_code, 200)
  126. self.assertEqual(self.project.issues.count(), 1)
  127. def test_discarded_exception(self):
  128. event = self.django_event
  129. event[2]["exception"] = {
  130. "values": [
  131. {"type": "fun", "value": "this is a fun error"},
  132. {"module": "", "thread_id": 1, "stacktrace": {}},
  133. ]
  134. }
  135. res = self.client.post(self.url, event, content_type="application/json")
  136. self.assertEqual(res.status_code, 200)
  137. self.assertTrue(
  138. IssueEvent.objects.filter(
  139. data__exception=[{"type": "fun", "value": "this is a fun error"}]
  140. ).exists()
  141. )
  142. def test_coerce_message_params(self):
  143. event = self.django_event
  144. # The ["b"] param is wrong, it should get coerced to a str
  145. event[2]["logentry"] = {"params": ["a", ["b"]], "message": "%s %s"}
  146. res = self.client.post(self.url, event, content_type="application/json")
  147. self.assertEqual(res.status_code, 200)
  148. def test_weird_debug_meta(self):
  149. event = self.django_event
  150. # The ["b"] param is wrong, it should get coerced to a str
  151. event[2]["debug_meta"] = {"images": [{"type": "silly"}]}
  152. res = self.client.post(self.url, event, content_type="application/json")
  153. self.assertEqual(res.status_code, 200)
  154. def test_invalid_mechanism(self):
  155. """
  156. The mechanism should not be an empty object, but the go sdk sends this
  157. https://github.com/getsentry/sentry-go/issues/896
  158. """
  159. event = self.django_event
  160. event[2]["exception"] = {
  161. "values": [{"type": "Error", "value": "The error", "mechanism": {}}]
  162. }
  163. res = self.client.post(self.url, event, content_type="application/json")
  164. self.assertEqual(res.status_code, 200)