test_integration.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. from io import BytesIO
  2. from unittest import mock
  3. from uuid import uuid4
  4. import pytest
  5. from sentry.models.eventattachment import EventAttachment
  6. from sentry.spans.grouping.utils import hash_values
  7. from sentry.tasks.relay import invalidate_project_config
  8. from sentry.testutils import RelayStoreHelper, TransactionTestCase
  9. from sentry.testutils.helpers import Feature
  10. from sentry.testutils.helpers.datetime import before_now, iso_format, timestamp_format
  11. class SentryRemoteTest(RelayStoreHelper, TransactionTestCase):
  12. # used to be test_ungzipped_data
  13. def test_simple_data(self):
  14. event_data = {"message": "hello", "timestamp": iso_format(before_now(seconds=1))}
  15. event = self.post_and_retrieve_event(event_data)
  16. assert event.message == "hello"
  17. def test_csp(self):
  18. event_data = {
  19. "csp-report": {
  20. "document-uri": "https://example.com/foo/bar",
  21. "referrer": "https://www.google.com/",
  22. "violated-directive": "default-src self",
  23. "original-policy": "default-src self; report-uri /csp-hotline.php",
  24. "blocked-uri": "http://evilhackerscripts.com",
  25. }
  26. }
  27. event = self.post_and_retrieve_security_report(event_data)
  28. assert event.message == "Blocked 'default-src' from 'evilhackerscripts.com'"
  29. def test_hpkp(self):
  30. event_data = {
  31. "date-time": "2014-04-06T13:00:50Z",
  32. "hostname": "www.example.com",
  33. "port": 443,
  34. "effective-expiration-date": "2014-05-01T12:40:50Z",
  35. "include-subdomains": False,
  36. "served-certificate-chain": [
  37. "-----BEGIN CERTIFICATE-----\n MIIEBDCCAuygBQUAMEIxCzAJBgNVBAYTAlVT\n -----END CERTIFICATE-----"
  38. ],
  39. "validated-certificate-chain": [
  40. "-----BEGIN CERTIFICATE-----\n MIIEBDCCAuygAwIBAgIDCzAJBgNVBAYTAlVT\n -----END CERTIFICATE-----"
  41. ],
  42. "known-pins": [
  43. 'pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="',
  44. 'pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g="',
  45. ],
  46. }
  47. event = self.post_and_retrieve_security_report(event_data)
  48. assert event.message == "Public key pinning validation failed for 'www.example.com'"
  49. assert event.group.title == "Public key pinning validation failed for 'www.example.com'"
  50. def test_expect_ct(self):
  51. event_data = {
  52. "expect-ct-report": {
  53. "date-time": "2014-04-06T13:00:50Z",
  54. "hostname": "www.example.com",
  55. "port": 443,
  56. "effective-expiration-date": "2014-05-01T12:40:50Z",
  57. "served-certificate-chain": [
  58. "-----BEGIN CERTIFICATE-----\nABC\n-----END CERTIFICATE-----"
  59. ],
  60. "validated-certificate-chain": [
  61. "-----BEGIN CERTIFICATE-----\nCDE\n-----END CERTIFICATE-----"
  62. ],
  63. "scts": [
  64. {
  65. "version": 1,
  66. "status": "invalid",
  67. "source": "embedded",
  68. "serialized_sct": "ABCD==",
  69. }
  70. ],
  71. }
  72. }
  73. event = self.post_and_retrieve_security_report(event_data)
  74. assert event.message == "Expect-CT failed for 'www.example.com'"
  75. assert event.group.title == "Expect-CT failed for 'www.example.com'"
  76. def test_expect_staple(self):
  77. event_data = {
  78. "expect-staple-report": {
  79. "date-time": "2014-04-06T13:00:50Z",
  80. "hostname": "www.example.com",
  81. "port": 443,
  82. "response-status": "ERROR_RESPONSE",
  83. "cert-status": "REVOKED",
  84. "effective-expiration-date": "2014-05-01T12:40:50Z",
  85. "served-certificate-chain": [
  86. "-----BEGIN CERTIFICATE-----\nABC\n-----END CERTIFICATE-----"
  87. ],
  88. "validated-certificate-chain": [
  89. "-----BEGIN CERTIFICATE-----\nCDE\n-----END CERTIFICATE-----"
  90. ],
  91. }
  92. }
  93. event = self.post_and_retrieve_security_report(event_data)
  94. assert event.message == "Expect-Staple failed for 'www.example.com'"
  95. assert event.group.title == "Expect-Staple failed for 'www.example.com'"
  96. def test_standalone_attachment(self):
  97. event_id = uuid4().hex
  98. # First, ingest the attachment and ensure it is saved
  99. files = {"some_file": ("hello.txt", BytesIO(b"Hello World!"))}
  100. self.post_and_retrieve_attachment(event_id, files)
  101. # Next, ingest an error event
  102. event = self.post_and_retrieve_event({"event_id": event_id, "message": "my error"})
  103. assert event.event_id == event_id
  104. assert event.group_id
  105. # Finally, fetch the updated attachment and compare the group id
  106. attachment = EventAttachment.objects.get(project_id=self.project.id, event_id=event_id)
  107. assert attachment.group_id == event.group_id
  108. def test_transaction(self):
  109. event_data = {
  110. "event_id": "d2132d31b39445f1938d7e21b6bf0ec4",
  111. "type": "transaction",
  112. "transaction": "/organizations/:orgId/performance/:eventSlug/",
  113. "start_timestamp": iso_format(before_now(minutes=1, milliseconds=500)),
  114. "timestamp": iso_format(before_now(minutes=1)),
  115. "contexts": {
  116. "trace": {
  117. "trace_id": "ff62a8b040f340bda5d830223def1d81",
  118. "span_id": "8f5a2b8768cafb4e",
  119. "type": "trace",
  120. }
  121. },
  122. "spans": [
  123. {
  124. "description": "<OrganizationContext>",
  125. "op": "react.mount",
  126. "parent_span_id": "8f5a2b8768cafb4e",
  127. "span_id": "bd429c44b67a3eb4",
  128. "start_timestamp": timestamp_format(before_now(minutes=1, milliseconds=250)),
  129. "timestamp": timestamp_format(before_now(minutes=1)),
  130. "trace_id": "ff62a8b040f340bda5d830223def1d81",
  131. },
  132. {
  133. "description": "browser span",
  134. "op": "browser",
  135. "parent_span_id": "bd429c44b67a3eb4",
  136. "span_id": "a99fd04e79e17631",
  137. "start_timestamp": timestamp_format(before_now(minutes=1, milliseconds=200)),
  138. "timestamp": timestamp_format(before_now(minutes=1)),
  139. "trace_id": "ff62a8b040f340bda5d830223def1d81",
  140. },
  141. {
  142. "description": "resource span",
  143. "op": "resource",
  144. "parent_span_id": "bd429c44b67a3eb4",
  145. "span_id": "a71a5e67db5ce938",
  146. "start_timestamp": timestamp_format(before_now(minutes=1, milliseconds=200)),
  147. "timestamp": timestamp_format(before_now(minutes=1)),
  148. "trace_id": "ff62a8b040f340bda5d830223def1d81",
  149. },
  150. {
  151. "description": "http span",
  152. "op": "http",
  153. "parent_span_id": "a99fd04e79e17631",
  154. "span_id": "abe79ad9292b90a9",
  155. "start_timestamp": timestamp_format(before_now(minutes=1, milliseconds=200)),
  156. "timestamp": timestamp_format(before_now(minutes=1)),
  157. "trace_id": "ff62a8b040f340bda5d830223def1d81",
  158. },
  159. {
  160. "description": "db span",
  161. "op": "db",
  162. "parent_span_id": "abe79ad9292b90a9",
  163. "span_id": "9c045ea336297177",
  164. "start_timestamp": timestamp_format(before_now(minutes=1, milliseconds=200)),
  165. "timestamp": timestamp_format(before_now(minutes=1)),
  166. "trace_id": "ff62a8b040f340bda5d830223def1d81",
  167. },
  168. ],
  169. }
  170. with Feature(
  171. {
  172. "organizations:performance-ops-breakdown": True,
  173. "projects:performance-suspect-spans-ingestion": True,
  174. }
  175. ):
  176. event = self.post_and_retrieve_event(event_data)
  177. raw_event = event.get_raw_data()
  178. exclusive_times = [
  179. pytest.approx(50, abs=2),
  180. pytest.approx(0, abs=2),
  181. pytest.approx(200, abs=2),
  182. pytest.approx(0, abs=2),
  183. pytest.approx(200, abs=2),
  184. ]
  185. for actual, expected, exclusive_time in zip(
  186. raw_event["spans"], event_data["spans"], exclusive_times
  187. ):
  188. assert actual == dict(
  189. expected,
  190. exclusive_time=exclusive_time,
  191. hash=hash_values([expected["description"]]),
  192. )
  193. assert raw_event["breakdowns"] == {
  194. "span_ops": {
  195. "ops.browser": {"unit": "millisecond", "value": pytest.approx(200, abs=2)},
  196. "ops.resource": {"unit": "millisecond", "value": pytest.approx(200, abs=2)},
  197. "ops.http": {"unit": "millisecond", "value": pytest.approx(200, abs=2)},
  198. "ops.db": {"unit": "millisecond", "value": pytest.approx(200, abs=2)},
  199. "total.time": {"unit": "millisecond", "value": pytest.approx(1050, abs=2)},
  200. }
  201. }
  202. def test_project_config_compression(self):
  203. # Populate redis cache with compressed config:
  204. invalidate_project_config(public_key=self.projectkey, trigger="test")
  205. # Disable project config endpoint, to make sure Relay gets its data
  206. # from redis:
  207. with mock.patch(
  208. "sentry.api.endpoints.relay.project_configs.RelayProjectConfigsEndpoint.post"
  209. ):
  210. event_data = {"message": "hello", "timestamp": iso_format(before_now(seconds=1))}
  211. event = self.post_and_retrieve_event(event_data)
  212. assert event.message == "hello"