Skip to content

type tests.sentry.incidents.action_handlers.* #98112

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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.*",
Expand Down
2 changes: 1 addition & 1 deletion src/sentry/incidents/action_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
6 changes: 3 additions & 3 deletions tests/relay_integration/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
"""
Expand All @@ -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.
Expand Down
11 changes: 8 additions & 3 deletions tests/sentry/incidents/action_handlers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand All @@ -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)
8 changes: 2 additions & 6 deletions tests/sentry/incidents/action_handlers/test_discord.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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)}",
Expand All @@ -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()

Expand Down
31 changes: 20 additions & 11 deletions tests/sentry/incidents/action_handlers/test_email.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from functools import cached_property
from typing import Any
from unittest.mock import MagicMock, patch

import orjson
Expand Down Expand Up @@ -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,
Expand All @@ -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

Expand All @@ -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,
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions tests/sentry/incidents/action_handlers/test_msteams.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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,
)
Expand Down
4 changes: 2 additions & 2 deletions tests/sentry/incidents/action_handlers/test_opsgenie.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions tests/sentry/incidents/action_handlers/test_pagerduty.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 3 additions & 3 deletions tests/sentry/incidents/action_handlers/test_sentry_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Missing **kwargs in run_test Method

The run_test method in these test files is missing the **kwargs parameter required by its abstract base method. This signature mismatch could cause runtime errors if additional arguments, like chart_url, are passed.

Additional Locations (5)

Fix in Cursor Fix in Web

from sentry.rules.actions.notify_event_service import build_incident_attachment

responses.add(
Expand Down Expand Up @@ -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)
Expand Down
24 changes: 14 additions & 10 deletions tests/sentry/incidents/action_handlers/test_slack.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand All @@ -32,15 +33,15 @@
@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"},
) as self.mock_schedule:
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:
Expand Down Expand Up @@ -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():
Expand All @@ -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(
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
6 changes: 4 additions & 2 deletions tests/tools/mypy_helpers/test_sort_stronger_modules.py
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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]]
Expand Down
Loading