diff --git a/pyproject.toml b/pyproject.toml index c09cca3074d7e1..a28905670a2613 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -680,6 +680,7 @@ module = [ "tests.sentry.flags.providers.*", "tests.sentry.grouping.*", "tests.sentry.hybridcloud.*", + "tests.sentry.incidents.action_handlers.*", "tests.sentry.incidents.handlers.*", "tests.sentry.incidents.serializers.*", "tests.sentry.insights.*", diff --git a/src/sentry/incidents/action_handlers.py b/src/sentry/incidents/action_handlers.py index 136e1fd5fedc9e..dbb57d4f4f93bb 100644 --- a/src/sentry/incidents/action_handlers.py +++ b/src/sentry/incidents/action_handlers.py @@ -509,7 +509,7 @@ def generate_incident_trigger_email_context( trigger_threshold: float, user: User | RpcUser | None = None, notification_uuid: str | None = None, -): +) -> dict[str, Any]: from sentry.notifications.notification_action.utils import should_fire_workflow_actions from sentry.seer.anomaly_detection.types import AnomalyDetectionThresholdType diff --git a/tests/relay_integration/test_integration.py b/tests/relay_integration/test_integration.py index 1922ec5b33fd6c..2c2da78827eced 100644 --- a/tests/relay_integration/test_integration.py +++ b/tests/relay_integration/test_integration.py @@ -4,7 +4,7 @@ import pytest import requests -from sentry_relay.auth import generate_key_pair +from sentry_relay.auth import SecretKey, generate_key_pair from sentry.models.eventattachment import EventAttachment from sentry.tasks.relay import invalidate_project_config @@ -17,7 +17,7 @@ pytestmark = [requires_kafka] -def create_trusted_relay_signature(secret_key): +def create_trusted_relay_signature(secret_key: SecretKey) -> str | bytes: """ Mimics how the trusted relay signature is built so we can test communication. """ @@ -33,7 +33,7 @@ def create_trusted_relay_signature(secret_key): class SentryRemoteTest(RelayStoreHelper, TransactionTestCase): - def setup_for_trusted_relay_signature(self): + def setup_for_trusted_relay_signature(self) -> tuple[str, SecretKey]: """ sets up project config settings and returns the relay_id and the secret key which can be used to create the signature if required. diff --git a/tests/sentry/incidents/action_handlers/__init__.py b/tests/sentry/incidents/action_handlers/__init__.py index 186c87d37e1996..efba9d4bd15f38 100644 --- a/tests/sentry/incidents/action_handlers/__init__.py +++ b/tests/sentry/incidents/action_handlers/__init__.py @@ -10,10 +10,15 @@ class FireTest(TestCase, abc.ABC): __test__ = Abstract(__module__, __qualname__) @abc.abstractmethod - def run_test(self, incident: Incident, method: str, **kwargs): + def run_test(self, incident: Incident, method: str, **kwargs: object) -> None: pass - def run_fire_test(self, method="fire", chart_url=None, status=IncidentStatus.CLOSED): + def run_fire_test( + self, + method: str = "fire", + chart_url: str | None = None, + status: IncidentStatus = IncidentStatus.CLOSED, + ) -> None: kwargs = {} if chart_url: kwargs = {"chart_url": chart_url} @@ -24,4 +29,4 @@ def run_fire_test(self, method="fire", chart_url=None, status=IncidentStatus.CLO update_incident_status( incident, IncidentStatus.CLOSED, status_method=IncidentStatusMethod.MANUAL ) - return self.run_test(incident, method, **kwargs) + self.run_test(incident, method, **kwargs) diff --git a/tests/sentry/incidents/action_handlers/test_discord.py b/tests/sentry/incidents/action_handlers/test_discord.py index e5592fa804f041..d6f16b87f757f1 100644 --- a/tests/sentry/incidents/action_handlers/test_discord.py +++ b/tests/sentry/incidents/action_handlers/test_discord.py @@ -1,10 +1,9 @@ from unittest.mock import MagicMock, patch -import orjson import responses from sentry.incidents.models.alert_rule import AlertRuleTriggerAction -from sentry.incidents.models.incident import IncidentStatus +from sentry.incidents.models.incident import Incident, IncidentStatus from sentry.integrations.discord.client import CHANNEL_URL, DISCORD_BASE_URL, MESSAGE_URL from sentry.integrations.discord.spec import DiscordMessagingSpec from sentry.integrations.messaging.spec import MessagingActionHandler @@ -51,7 +50,7 @@ def setUp(self) -> None: ) @responses.activate - def run_test(self, incident, method): + def run_test(self, incident: Incident, method: str) -> None: responses.add( method=responses.POST, url=f"{DISCORD_BASE_URL}{MESSAGE_URL.format(channel_id=self.channel_id)}", @@ -69,9 +68,6 @@ def run_test(self, incident, method): metric_value=metric_value, ) - data = orjson.loads(responses.calls[0].request.body) - return data - def test_fire_metric_alert(self) -> None: self.run_fire_test() diff --git a/tests/sentry/incidents/action_handlers/test_email.py b/tests/sentry/incidents/action_handlers/test_email.py index 590f417db7e797..bd2e811e8c5d70 100644 --- a/tests/sentry/incidents/action_handlers/test_email.py +++ b/tests/sentry/incidents/action_handlers/test_email.py @@ -1,4 +1,5 @@ from functools import cached_property +from typing import Any from unittest.mock import MagicMock, patch import orjson @@ -27,13 +28,19 @@ ) from sentry.incidents.logic import CRITICAL_TRIGGER_LABEL, WARNING_TRIGGER_LABEL from sentry.incidents.models.alert_rule import ( + AlertRule, AlertRuleDetectionType, AlertRuleSeasonality, AlertRuleSensitivity, AlertRuleThresholdType, AlertRuleTriggerAction, ) -from sentry.incidents.models.incident import INCIDENT_STATUS, IncidentStatus, TriggerStatus +from sentry.incidents.models.incident import ( + INCIDENT_STATUS, + Incident, + IncidentStatus, + TriggerStatus, +) from sentry.incidents.typings.metric_detector import ( AlertContext, MetricIssueContext, @@ -51,8 +58,10 @@ from sentry.testutils.helpers.datetime import freeze_time from sentry.testutils.helpers.features import with_feature from sentry.testutils.silo import assume_test_silo_mode_of +from sentry.users.models.user import User from sentry.users.models.user_option import UserOption from sentry.users.models.useremail import UserEmail +from sentry.users.services.user import RpcUser from . import FireTest @@ -62,7 +71,7 @@ @freeze_time() class EmailActionHandlerTest(FireTest): @responses.activate - def run_test(self, incident, method): + def run_test(self, incident: Incident, method: str) -> None: action = self.create_alert_rule_trigger_action( target_identifier=str(self.user.id), triggered_for_incident=incident, @@ -111,7 +120,7 @@ def setUp(self) -> None: self.handler = EmailActionHandler() @cached_property - def incident(self): + def incident(self) -> Incident: return self.create_incident() def test_user(self) -> None: @@ -268,20 +277,20 @@ def test_team_email_routing(self) -> None: @freeze_time() class EmailActionHandlerGenerateEmailContextTest(TestCase): - def serialize_incident(self, incident) -> DetailedIncidentSerializerResponse: + def serialize_incident(self, incident: Incident) -> DetailedIncidentSerializerResponse: return serialize(incident, None, DetailedIncidentSerializer()) - def serialize_alert_rule(self, alert_rule) -> AlertRuleSerializerResponse: + def serialize_alert_rule(self, alert_rule: AlertRule) -> AlertRuleSerializerResponse: return serialize(alert_rule, None, AlertRuleSerializer()) def _generate_email_context( self, - incident, - trigger_status, - trigger_threshold, - user=None, - notification_uuid=None, - ): + incident: Incident, + trigger_status: TriggerStatus, + trigger_threshold: float, + user: User | RpcUser | None = None, + notification_uuid: str | None = None, + ) -> dict[str, Any]: """ Helper method to generate email context from an incident and trigger status. Encapsulates the common pattern of creating contexts and serializing models. diff --git a/tests/sentry/incidents/action_handlers/test_msteams.py b/tests/sentry/incidents/action_handlers/test_msteams.py index 7fbcb936119fbd..5e295772ede293 100644 --- a/tests/sentry/incidents/action_handlers/test_msteams.py +++ b/tests/sentry/incidents/action_handlers/test_msteams.py @@ -14,7 +14,7 @@ AlertRuleSensitivity, AlertRuleTriggerAction, ) -from sentry.incidents.models.incident import IncidentStatus, IncidentStatusMethod +from sentry.incidents.models.incident import Incident, IncidentStatus, IncidentStatusMethod from sentry.incidents.typings.metric_detector import AlertContext, MetricIssueContext from sentry.integrations.messaging.spec import MessagingActionHandler from sentry.integrations.msteams.card_builder.block import ( @@ -77,7 +77,7 @@ def setUp(self) -> None: @responses.activate @patch("sentry.integrations.utils.metrics.EventLifecycle.record_event") - def run_test(self, incident, method, mock_record): + def run_test(self, incident: Incident, method: str, mock_record: MagicMock) -> None: from sentry.integrations.msteams.card_builder.incident_attachment import ( build_incident_attachment, ) diff --git a/tests/sentry/incidents/action_handlers/test_opsgenie.py b/tests/sentry/incidents/action_handlers/test_opsgenie.py index 65af37e244eb1c..ceb5f9533741f5 100644 --- a/tests/sentry/incidents/action_handlers/test_opsgenie.py +++ b/tests/sentry/incidents/action_handlers/test_opsgenie.py @@ -13,7 +13,7 @@ AlertRuleSensitivity, AlertRuleTriggerAction, ) -from sentry.incidents.models.incident import IncidentStatus, IncidentStatusMethod +from sentry.incidents.models.incident import Incident, IncidentStatus, IncidentStatusMethod from sentry.incidents.typings.metric_detector import AlertContext, MetricIssueContext from sentry.integrations.models.integration import Integration from sentry.integrations.models.organization_integration import OrganizationIntegration @@ -174,7 +174,7 @@ def test_build_incident_attachment_dynamic_alert(self, mock_seer_request: MagicM ) @responses.activate - def run_test(self, incident, method): + def run_test(self, incident: Incident, method: str) -> None: from sentry.integrations.opsgenie.utils import ( attach_custom_priority, build_incident_attachment, diff --git a/tests/sentry/incidents/action_handlers/test_pagerduty.py b/tests/sentry/incidents/action_handlers/test_pagerduty.py index a87810356a56c9..0bcc522f7711ed 100644 --- a/tests/sentry/incidents/action_handlers/test_pagerduty.py +++ b/tests/sentry/incidents/action_handlers/test_pagerduty.py @@ -14,7 +14,7 @@ AlertRuleSensitivity, AlertRuleTriggerAction, ) -from sentry.incidents.models.incident import IncidentStatus, IncidentStatusMethod +from sentry.incidents.models.incident import Incident, IncidentStatus, IncidentStatusMethod from sentry.incidents.typings.metric_detector import AlertContext, MetricIssueContext from sentry.integrations.pagerduty.utils import add_service from sentry.seer.anomaly_detection.types import StoreDataResponse @@ -161,7 +161,7 @@ def test_build_incident_attachment_dynamic_alert(self, mock_seer_request: MagicM ) @responses.activate - def run_test(self, incident, method): + def run_test(self, incident: Incident, method: str) -> None: from sentry.integrations.pagerduty.utils import ( attach_custom_severity, build_incident_attachment, diff --git a/tests/sentry/incidents/action_handlers/test_sentry_app.py b/tests/sentry/incidents/action_handlers/test_sentry_app.py index ce359074bc47dd..4c3a7363774225 100644 --- a/tests/sentry/incidents/action_handlers/test_sentry_app.py +++ b/tests/sentry/incidents/action_handlers/test_sentry_app.py @@ -7,7 +7,7 @@ from sentry.incidents.action_handlers import SentryAppActionHandler from sentry.incidents.endpoints.serializers.incident import IncidentSerializer from sentry.incidents.models.alert_rule import AlertRuleTriggerAction -from sentry.incidents.models.incident import IncidentStatus +from sentry.incidents.models.incident import Incident, IncidentStatus from sentry.incidents.typings.metric_detector import AlertContext, MetricIssueContext from sentry.integrations.types import EventLifecycleOutcome from sentry.sentry_apps.metrics import SentryAppWebhookHaltReason @@ -46,7 +46,7 @@ def setUp(self) -> None: self.handler = SentryAppActionHandler() @responses.activate - def run_test(self, incident, method): + def run_test(self, incident: Incident, method: str) -> None: from sentry.rules.actions.notify_event_service import build_incident_attachment responses.add( @@ -210,7 +210,7 @@ def setUp(self) -> None: self.handler = SentryAppActionHandler() @responses.activate - def run_test(self, incident, method): + def run_test(self, incident: Incident, method: str) -> None: from sentry.rules.actions.notify_event_service import build_incident_attachment trigger = self.create_alert_rule_trigger(self.alert_rule, "hi", 1000) diff --git a/tests/sentry/incidents/action_handlers/test_slack.py b/tests/sentry/incidents/action_handlers/test_slack.py index b692ef47f64379..cd205bd9151c1f 100644 --- a/tests/sentry/incidents/action_handlers/test_slack.py +++ b/tests/sentry/incidents/action_handlers/test_slack.py @@ -1,4 +1,5 @@ -from unittest.mock import MagicMock, patch +from collections.abc import Generator +from unittest.mock import MagicMock, Mock, patch import orjson import pytest @@ -10,7 +11,7 @@ from sentry.constants import ObjectStatus from sentry.incidents.logic import update_incident_status from sentry.incidents.models.alert_rule import AlertRuleTriggerAction -from sentry.incidents.models.incident import IncidentStatus, IncidentStatusMethod +from sentry.incidents.models.incident import Incident, IncidentStatus, IncidentStatusMethod from sentry.incidents.typings.metric_detector import AlertContext, MetricIssueContext from sentry.integrations.messaging.spec import MessagingActionHandler from sentry.integrations.slack.message_builder.incidents import SlackIncidentsMessageBuilder @@ -32,7 +33,7 @@ @with_feature("organizations:metric-alert-thread-flag") class SlackActionHandlerTest(FireTest): @pytest.fixture(autouse=True) - def mock_chat_postEphemeral(self): + def mock_chat_postEphemeral(self) -> Generator[None]: with mock_slack_response( "chat_scheduleMessage", body={"ok": True, "channel": "chan-id", "scheduled_message_id": "Q1298393284"}, @@ -40,7 +41,7 @@ def mock_chat_postEphemeral(self): yield @pytest.fixture(autouse=True) - def mock_chat_unfurl(self): + def mock_chat_unfurl(self) -> Generator[None]: with mock_slack_response( "chat_deleteScheduledMessage", body={"ok": True} ) as self.mock_delete: @@ -84,8 +85,7 @@ def setUp(self) -> None: ) self.alert_rule = self.create_alert_rule() - def run_test(self, incident, method, **kwargs): - chart_url = kwargs.get("chart_url") + def run_test(self, incident: Incident, method: str, **kwargs: object) -> None: metric_value = 1000 status = IncidentStatus(incident.status) with self.tasks(): @@ -97,9 +97,9 @@ def run_test(self, incident, method, **kwargs): metric_value=metric_value, ) - return incident, chart_url - - def _assert_blocks(self, mock_post, incident, metric_value, chart_url): + def _assert_blocks( + self, mock_post: Mock, incident: Incident, metric_value: float | None, chart_url: str | None + ) -> None: slack_body = SlackIncidentsMessageBuilder( alert_context=AlertContext.from_alert_rule_incident(incident.alert_rule), metric_issue_context=MetricIssueContext.from_legacy_models( @@ -129,7 +129,11 @@ def test_fire_metric_alert_sdk( "status": 200, } - incident, chart_url = self.run_fire_test() + incident = self.create_incident( + alert_rule=self.alert_rule, status=IncidentStatus.CLOSED.value + ) + self.run_test(incident, "fire") + chart_url = None self._assert_blocks(mock_post, incident, 1000, chart_url) assert NotificationMessage.objects.all().count() == 1 diff --git a/tests/sentry/integrations/slack/utils/test_mock_slack_response.py b/tests/sentry/integrations/slack/utils/test_mock_slack_response.py index a57c54ee15218b..10aa1ea4d13c9b 100644 --- a/tests/sentry/integrations/slack/utils/test_mock_slack_response.py +++ b/tests/sentry/integrations/slack/utils/test_mock_slack_response.py @@ -4,7 +4,13 @@ def mock_slack_response( - method_name, body, status_code=200, http_verb="POST", api_url=None, req_args=None, headers=None + method_name: str, + body: dict[str, object] | bytes, + status_code: int = 200, + http_verb: str = "POST", + api_url: str | None = None, + req_args: dict[str, object] | None = None, + headers: dict[str, object] | None = None, ): if api_url is None: api_url = f"https://slack.com/api/{method_name}" diff --git a/tests/sentry/workflow_engine/handlers/condition/test_latest_adopted_release_handler.py b/tests/sentry/workflow_engine/handlers/condition/test_latest_adopted_release_handler.py index 290b727caee9ea..5c3a42480aed17 100644 --- a/tests/sentry/workflow_engine/handlers/condition/test_latest_adopted_release_handler.py +++ b/tests/sentry/workflow_engine/handlers/condition/test_latest_adopted_release_handler.py @@ -272,8 +272,8 @@ def test_latest_release_for_env_does_not_exist( return_value=None, ) def test_first_last_release_for_event_does_not_exist( - self, mock_get_first_last_release_for_event - ): + self, mock_get_first_last_release_for_event: MagicMock + ) -> None: self.assert_does_not_pass(self.dc, self.event_data) @patch( diff --git a/tests/tools/mypy_helpers/test_sort_stronger_modules.py b/tests/tools/mypy_helpers/test_sort_stronger_modules.py index 80c589ada3adc0..f93d7344a836c7 100644 --- a/tests/tools/mypy_helpers/test_sort_stronger_modules.py +++ b/tests/tools/mypy_helpers/test_sort_stronger_modules.py @@ -1,7 +1,9 @@ +from pathlib import Path + from tools.mypy_helpers.sort_stronger_modules import main -def test_sort_stronger_modules(tmp_path) -> None: +def test_sort_stronger_modules(tmp_path: Path) -> None: src = """\ # before @@ -43,7 +45,7 @@ def test_sort_stronger_modules(tmp_path) -> None: assert main((str(f),)) == 0 -def test_removes_duplicates(tmp_path) -> None: +def test_removes_duplicates(tmp_path: Path) -> None: src = """\ # begin: stronger typing [[tool.mypy.overrides]]