|
4 | 4 | import pytest
|
5 | 5 | import responses
|
6 | 6 | from django.urls import reverse
|
7 |
| -from requests.exceptions import ChunkedEncodingError |
| 7 | +from requests import HTTPError |
| 8 | +from requests.exceptions import ChunkedEncodingError, ConnectionError, Timeout |
8 | 9 |
|
9 | 10 | from sentry.api.serializers import serialize
|
10 | 11 | from sentry.api.serializers.rest_framework import convert_dict_key_case, snake_to_camel_case
|
@@ -71,6 +72,10 @@ def raiseException():
|
71 | 72 | raise Exception
|
72 | 73 |
|
73 | 74 |
|
| 75 | +def raiseHTTPError(): |
| 76 | + raise HTTPError() |
| 77 | + |
| 78 | + |
74 | 79 | class RequestMock:
|
75 | 80 | def __init__(self):
|
76 | 81 | self.body = "blah blah"
|
@@ -99,6 +104,9 @@ def __init__(self):
|
99 | 104 | )
|
100 | 105 | MockResponseInstance = MockResponse({}, b"{}", "", True, 200, raiseStatusFalse, None)
|
101 | 106 | MockResponse404 = MockResponse({}, b'{"bruh": "bruhhhhhhh"}', "", False, 404, raiseException, None)
|
| 107 | +MockResponse504 = MockResponse(headers, json_content, "", False, 504, raiseStatusFalse, None) |
| 108 | +MockResponse503 = MockResponse(headers, json_content, "", False, 503, raiseStatusFalse, None) |
| 109 | +MockResponse502 = MockResponse(headers, json_content, "", False, 502, raiseHTTPError, None) |
102 | 110 |
|
103 | 111 |
|
104 | 112 | class TestSendAlertEvent(TestCase, OccurrenceTestMixin):
|
@@ -594,6 +602,126 @@ def test_ignores_restricted_ip_error(self, capture_exception, safe_urlopen):
|
594 | 602 | assert len(capture_exception.mock_calls) == 0
|
595 | 603 | assert safe_urlopen.called
|
596 | 604 |
|
| 605 | + @patch("sentry_sdk.capture_exception") |
| 606 | + def test_ignores_timeout_error(self, capture_exception, safe_urlopen): |
| 607 | + safe_urlopen.side_effect = Timeout() |
| 608 | + |
| 609 | + event = self.store_event(data={}, project_id=self.project.id) |
| 610 | + assert event.group is not None |
| 611 | + |
| 612 | + # The task should complete without reporting to sentry when Timeout is raised |
| 613 | + # because it's in the on_silent list of the retry decorator |
| 614 | + with self.tasks(): |
| 615 | + post_process_group( |
| 616 | + is_new=True, |
| 617 | + is_regression=False, |
| 618 | + is_new_group_environment=False, |
| 619 | + cache_key=write_event_to_cache(event), |
| 620 | + group_id=event.group_id, |
| 621 | + project_id=self.project.id, |
| 622 | + eventstream_type=EventStreamEventType.Error.value, |
| 623 | + ) |
| 624 | + |
| 625 | + # Verify that the exception was not captured by Sentry since it's on_silent |
| 626 | + assert len(capture_exception.mock_calls) == 0 |
| 627 | + assert safe_urlopen.called |
| 628 | + |
| 629 | + @patch("sentry_sdk.capture_exception") |
| 630 | + def test_ignores_api_host_error(self, capture_exception, safe_urlopen): |
| 631 | + safe_urlopen.return_value = MockResponse503 |
| 632 | + |
| 633 | + event = self.store_event(data={}, project_id=self.project.id) |
| 634 | + assert event.group is not None |
| 635 | + |
| 636 | + # The task should complete without reporting to sentry when ApiHostError is raised |
| 637 | + # because it's in the on_silent list of the retry decorator |
| 638 | + with self.tasks(): |
| 639 | + post_process_group( |
| 640 | + is_new=True, |
| 641 | + is_regression=False, |
| 642 | + is_new_group_environment=False, |
| 643 | + cache_key=write_event_to_cache(event), |
| 644 | + group_id=event.group_id, |
| 645 | + project_id=self.project.id, |
| 646 | + eventstream_type=EventStreamEventType.Error.value, |
| 647 | + ) |
| 648 | + |
| 649 | + # Verify that the exception was not captured by Sentry since it's on_silent |
| 650 | + assert len(capture_exception.mock_calls) == 0 |
| 651 | + assert safe_urlopen.called |
| 652 | + |
| 653 | + @patch("sentry_sdk.capture_exception") |
| 654 | + def test_ignores_api_timeout_error(self, capture_exception, safe_urlopen): |
| 655 | + safe_urlopen.return_value = MockResponse504 |
| 656 | + |
| 657 | + event = self.store_event(data={}, project_id=self.project.id) |
| 658 | + assert event.group is not None |
| 659 | + |
| 660 | + # The task should complete without reporting to sentry when ApiTimeoutError is raised |
| 661 | + # because it's in the on_silent list of the retry decorator |
| 662 | + with self.tasks(): |
| 663 | + post_process_group( |
| 664 | + is_new=True, |
| 665 | + is_regression=False, |
| 666 | + is_new_group_environment=False, |
| 667 | + cache_key=write_event_to_cache(event), |
| 668 | + group_id=event.group_id, |
| 669 | + project_id=self.project.id, |
| 670 | + eventstream_type=EventStreamEventType.Error.value, |
| 671 | + ) |
| 672 | + |
| 673 | + # Verify that the exception was not captured by Sentry since it's on_silent |
| 674 | + assert len(capture_exception.mock_calls) == 0 |
| 675 | + assert safe_urlopen.called |
| 676 | + |
| 677 | + @patch("sentry_sdk.capture_exception") |
| 678 | + def test_ignores_connection_error(self, capture_exception, safe_urlopen): |
| 679 | + safe_urlopen.side_effect = ConnectionError() |
| 680 | + |
| 681 | + event = self.store_event(data={}, project_id=self.project.id) |
| 682 | + assert event.group is not None |
| 683 | + |
| 684 | + # The task should complete without reporting to sentry when ConnectionError is raised |
| 685 | + # because it's in the on_silent list of the retry decorator |
| 686 | + with self.tasks(): |
| 687 | + post_process_group( |
| 688 | + is_new=True, |
| 689 | + is_regression=False, |
| 690 | + is_new_group_environment=False, |
| 691 | + cache_key=write_event_to_cache(event), |
| 692 | + group_id=event.group_id, |
| 693 | + project_id=self.project.id, |
| 694 | + eventstream_type=EventStreamEventType.Error.value, |
| 695 | + ) |
| 696 | + |
| 697 | + # Verify that the exception was not captured by Sentry since it's on_silent |
| 698 | + assert len(capture_exception.mock_calls) == 0 |
| 699 | + assert safe_urlopen.called |
| 700 | + |
| 701 | + @patch("sentry_sdk.capture_exception") |
| 702 | + def test_ignores_http_error(self, capture_exception, safe_urlopen): |
| 703 | + safe_urlopen.return_value = MockResponse502 |
| 704 | + |
| 705 | + event = self.store_event(data={}, project_id=self.project.id) |
| 706 | + assert event.group is not None |
| 707 | + |
| 708 | + # The task should complete without reporting to sentry when HTTPError is raised |
| 709 | + # because it's in the on_silent list of the retry decorator |
| 710 | + with self.tasks(): |
| 711 | + post_process_group( |
| 712 | + is_new=True, |
| 713 | + is_regression=False, |
| 714 | + is_new_group_environment=False, |
| 715 | + cache_key=write_event_to_cache(event), |
| 716 | + group_id=event.group_id, |
| 717 | + project_id=self.project.id, |
| 718 | + eventstream_type=EventStreamEventType.Error.value, |
| 719 | + ) |
| 720 | + |
| 721 | + # Verify that the exception was not captured by Sentry since it's on_silent |
| 722 | + assert len(capture_exception.mock_calls) == 0 |
| 723 | + assert safe_urlopen.called |
| 724 | + |
597 | 725 | @patch("sentry_sdk.capture_exception")
|
598 | 726 | def test_silently_retries_chunked_encoding_error_unpublished(
|
599 | 727 | self, capture_exception, safe_urlopen
|
|
0 commit comments