From aa068fe9d585621323ce7258cba6f6722ee19291 Mon Sep 17 00:00:00 2001 From: Grant Patterson Date: Thu, 17 Sep 2026 16:14:56 -0700 Subject: [PATCH] ref(np): Dispatch provider renderers through a registry Replaces the per-provider `get_renderer` overrides with a `NotificationRendererRegistry` keyed by provider and notification source. Renderers register themselves where they are defined, and `NotificationProvider.get_renderer` resolves the renderer from the notification's source, falling back to the provider's default renderer. Keying on source rather than category lets the Seer renderers be registered directly, replacing the nested source check the Slack provider needed to separate `SeerAgentWriteApprovalSlackRenderer` from `SeerSlackRenderer`. Also drops the unused `provider_key` attribute from the `NotificationRenderer` protocol. Co-authored-by: Cursor --- src/sentry/notifications/apps.py | 6 +++ .../internal_registered_templates.py | 2 +- .../platform/discord/provider.py | 18 ------- .../platform/discord/renderers/issue.py | 5 +- .../discord/renderers/metric_alert.py | 5 +- .../notifications/platform/email/provider.py | 2 - .../platform/msteams/provider.py | 2 - src/sentry/notifications/platform/provider.py | 11 ++-- src/sentry/notifications/platform/registry.py | 54 ++++++++++++++++++- src/sentry/notifications/platform/renderer.py | 3 -- src/sentry/notifications/platform/service.py | 2 +- .../notifications/platform/slack/provider.py | 29 ---------- .../platform/slack/renderers/issue.py | 5 +- .../platform/slack/renderers/metric_alert.py | 5 +- .../platform/slack/renderers/seer.py | 12 +++++ .../renderers/seer_agent_write_approval.py | 7 ++- .../integrations/slack/test_integration.py | 5 +- .../platform/discord/renderers/test_issue.py | 22 ++------ .../discord/renderers/test_metric_alert.py | 16 ++---- .../platform/discord/test_provider.py | 21 ++------ .../platform/msteams/test_provider.py | 21 ++------ .../platform/slack/renderers/test_issue.py | 21 ++------ .../slack/renderers/test_metric_alert.py | 16 ++---- .../platform/slack/renderers/test_seer.py | 6 +-- .../platform/slack/test_provider.py | 5 +- .../notifications/platform/test_provider.py | 5 +- 26 files changed, 130 insertions(+), 176 deletions(-) diff --git a/src/sentry/notifications/apps.py b/src/sentry/notifications/apps.py index 731ba25d3a3e..b96c5a01f5be 100644 --- a/src/sentry/notifications/apps.py +++ b/src/sentry/notifications/apps.py @@ -7,7 +7,13 @@ class Config(AppConfig): def ready(self) -> None: # Imports to populate registries import sentry.notifications.platform.discord.provider # noqa: F401 + import sentry.notifications.platform.discord.renderers.issue # noqa: F401 + import sentry.notifications.platform.discord.renderers.metric_alert # noqa: F401 import sentry.notifications.platform.email.provider # noqa: F401 import sentry.notifications.platform.msteams.provider # noqa: F401 import sentry.notifications.platform.slack.provider # noqa: F401 + import sentry.notifications.platform.slack.renderers.issue # noqa: F401 + import sentry.notifications.platform.slack.renderers.metric_alert # noqa: F401 + import sentry.notifications.platform.slack.renderers.seer # noqa: F401 + import sentry.notifications.platform.slack.renderers.seer_agent_write_approval # noqa: F401 import sentry.notifications.platform.templates # noqa: F401 diff --git a/src/sentry/notifications/platform/api/endpoints/internal_registered_templates.py b/src/sentry/notifications/platform/api/endpoints/internal_registered_templates.py index 98a1428a8943..9171b4f0c9cf 100644 --- a/src/sentry/notifications/platform/api/endpoints/internal_registered_templates.py +++ b/src/sentry/notifications/platform/api/endpoints/internal_registered_templates.py @@ -104,7 +104,7 @@ def serialize_slack_preview[T: NotificationData]( ) -> dict[str, Any]: data = template.example_data rendered_template = template.render_example() - renderer = SlackNotificationProvider.get_renderer(data=data, category=template.category) + renderer = SlackNotificationProvider.get_renderer(data=data) message = renderer.render(data=data, rendered_template=rendered_template) serialized_blocks = [] diff --git a/src/sentry/notifications/platform/discord/provider.py b/src/sentry/notifications/platform/discord/provider.py index a9e29683ef3b..b92e23fa7a56 100644 --- a/src/sentry/notifications/platform/discord/provider.py +++ b/src/sentry/notifications/platform/discord/provider.py @@ -18,7 +18,6 @@ from sentry.notifications.platform.threading import ThreadContext from sentry.notifications.platform.types import ( LinkTextBlock, - NotificationCategory, NotificationData, NotificationProviderKey, NotificationRenderedTemplate, @@ -40,8 +39,6 @@ class DiscordRenderer(NotificationRenderer[DiscordRenderable]): - provider_key = NotificationProviderKey.DISCORD - @classmethod def render[DataT: NotificationData]( cls, *, data: DataT, rendered_template: NotificationRenderedTemplate @@ -152,21 +149,6 @@ def is_available(cls, *, organization: RpcOrganizationSummary | None = None) -> # TODO(ecosystem): Check for the integration, maybe a feature as well return False - @classmethod - def get_renderer( - cls, *, data: NotificationData, category: NotificationCategory - ) -> type[NotificationRenderer[DiscordRenderable]]: - from sentry.notifications.platform.discord.renderers.issue import IssueDiscordRenderer - from sentry.notifications.platform.discord.renderers.metric_alert import ( - DiscordMetricAlertRenderer, - ) - - if category == NotificationCategory.ISSUE: - return IssueDiscordRenderer - if category == NotificationCategory.METRIC_ALERT: - return DiscordMetricAlertRenderer - return cls.default_renderer - @classmethod def send( cls, diff --git a/src/sentry/notifications/platform/discord/renderers/issue.py b/src/sentry/notifications/platform/discord/renderers/issue.py index 855f2a163cec..47037f32f5cf 100644 --- a/src/sentry/notifications/platform/discord/renderers/issue.py +++ b/src/sentry/notifications/platform/discord/renderers/issue.py @@ -4,6 +4,7 @@ from sentry.integrations.discord.message_builder.issues import DiscordIssuesMessageBuilder from sentry.models.group import Group from sentry.notifications.platform.discord.provider import DiscordRenderable +from sentry.notifications.platform.registry import renderer_registry from sentry.notifications.platform.renderer import NotificationRenderer from sentry.notifications.platform.service import NotificationRenderError from sentry.notifications.platform.templates.issue import IssueNotificationData @@ -11,13 +12,13 @@ NotificationData, NotificationProviderKey, NotificationRenderedTemplate, + NotificationSource, ) from sentry.services.eventstore.models import Event +@renderer_registry.register(NotificationProviderKey.DISCORD, NotificationSource.ISSUE) class IssueDiscordRenderer(NotificationRenderer[DiscordRenderable]): - provider_key = NotificationProviderKey.DISCORD - @classmethod def render[DataT: NotificationData]( cls, *, data: DataT, rendered_template: NotificationRenderedTemplate diff --git a/src/sentry/notifications/platform/discord/renderers/metric_alert.py b/src/sentry/notifications/platform/discord/renderers/metric_alert.py index 4b6ab9127693..9454da057806 100644 --- a/src/sentry/notifications/platform/discord/renderers/metric_alert.py +++ b/src/sentry/notifications/platform/discord/renderers/metric_alert.py @@ -8,18 +8,19 @@ from sentry.integrations.discord.message_builder.metric_alerts import get_started_at from sentry.integrations.metric_alerts import get_status_text from sentry.notifications.platform.discord.provider import DiscordRenderable +from sentry.notifications.platform.registry import renderer_registry from sentry.notifications.platform.renderer import NotificationRenderer from sentry.notifications.platform.templates.metric_alert import MetricAlertNotificationData from sentry.notifications.platform.types import ( NotificationData, NotificationProviderKey, NotificationRenderedTemplate, + NotificationSource, ) +@renderer_registry.register(NotificationProviderKey.DISCORD, NotificationSource.METRIC_ALERT) class DiscordMetricAlertRenderer(NotificationRenderer[DiscordRenderable]): - provider_key = NotificationProviderKey.DISCORD - @classmethod def render[DataT: NotificationData]( cls, *, data: DataT, rendered_template: NotificationRenderedTemplate diff --git a/src/sentry/notifications/platform/email/provider.py b/src/sentry/notifications/platform/email/provider.py index 14db78280d64..0e108f7e9e1a 100644 --- a/src/sentry/notifications/platform/email/provider.py +++ b/src/sentry/notifications/platform/email/provider.py @@ -38,8 +38,6 @@ class EmailRenderer(NotificationRenderer[EmailRenderable]): - provider_key = NotificationProviderKey.EMAIL - @classmethod def render[DataT: NotificationData]( cls, *, data: DataT, rendered_template: NotificationRenderedTemplate diff --git a/src/sentry/notifications/platform/msteams/provider.py b/src/sentry/notifications/platform/msteams/provider.py index e4949ec20b8b..6325e6716d4e 100644 --- a/src/sentry/notifications/platform/msteams/provider.py +++ b/src/sentry/notifications/platform/msteams/provider.py @@ -38,8 +38,6 @@ class MSTeamsRenderer(NotificationRenderer[MSTeamsRenderable]): - provider_key = NotificationProviderKey.MSTEAMS - @classmethod def render[DataT: NotificationData]( cls, *, data: DataT, rendered_template: NotificationRenderedTemplate diff --git a/src/sentry/notifications/platform/provider.py b/src/sentry/notifications/platform/provider.py index 6a1b15adb451..3210be58aa24 100644 --- a/src/sentry/notifications/platform/provider.py +++ b/src/sentry/notifications/platform/provider.py @@ -8,7 +8,6 @@ from sentry.notifications.platform.target import IntegrationNotificationTarget from sentry.notifications.platform.threading import ThreadContext from sentry.notifications.platform.types import ( - NotificationCategory, NotificationData, NotificationProviderKey, NotificationTarget, @@ -133,15 +132,17 @@ def validate_target(cls, *, target: NotificationTarget) -> None: return @classmethod - def get_renderer( - cls, *, data: NotificationData, category: NotificationCategory - ) -> type[NotificationRenderer[RenderableT]]: + def get_renderer(cls, *, data: NotificationData) -> type[NotificationRenderer[RenderableT]]: """ Returns an instance of a renderer for a given notification, falling back to the default renderer. Override this to method to permit different renderers for the provider, though keep in mind that this may produce inconsistencies between notifications. """ - return cls.default_renderer + # Imported here since the registry imports this module to type its registrations. + from sentry.notifications.platform.registry import renderer_registry + + renderer = renderer_registry.get(provider_key=cls.key, source=data.source) + return renderer or cls.default_renderer @classmethod def is_available(cls, *, organization: RpcOrganizationSummary | None = None) -> bool: diff --git a/src/sentry/notifications/platform/registry.py b/src/sentry/notifications/platform/registry.py index 84d313d4293f..86edf134b05f 100644 --- a/src/sentry/notifications/platform/registry.py +++ b/src/sentry/notifications/platform/registry.py @@ -1,11 +1,17 @@ from __future__ import annotations +from collections.abc import Callable from typing import Any from sentry.notifications.platform.provider import NotificationProvider -from sentry.notifications.platform.types import NotificationTemplate +from sentry.notifications.platform.renderer import NotificationRenderer +from sentry.notifications.platform.types import ( + NotificationProviderKey, + NotificationSource, + NotificationTemplate, +) from sentry.organizations.services.organization.model import RpcOrganizationSummary -from sentry.utils.registry import Registry +from sentry.utils.registry import AlreadyRegisteredError, Registry class NotificationProviderRegistry(Registry[type[NotificationProvider[Any]]]): @@ -33,5 +39,49 @@ def get_available( ] +class NotificationRendererRegistry: + """ + A registry for renderers which override a provider's default renderer. Renderers are keyed by + the provider they produce output for, and the notification sources they render. + """ + + def __init__(self) -> None: + self.registrations: dict[ + tuple[NotificationProviderKey, NotificationSource], type[NotificationRenderer[Any]] + ] = {} + + def register[RenderableT]( + self, provider_key: NotificationProviderKey, *sources: NotificationSource + ) -> Callable[ + [type[NotificationRenderer[RenderableT]]], type[NotificationRenderer[RenderableT]] + ]: + if not sources: + raise ValueError("At least one notification source is required to register a renderer") + + def inner( + renderer: type[NotificationRenderer[RenderableT]], + ) -> type[NotificationRenderer[RenderableT]]: + for source in sources: + key = (provider_key, source) + if key in self.registrations: + raise AlreadyRegisteredError( + f"A registration already exists for {key}: {self.registrations[key]}" + ) + self.registrations[key] = renderer + return renderer + + return inner + + def get( + self, *, provider_key: NotificationProviderKey, source: NotificationSource + ) -> type[NotificationRenderer[Any]] | None: + """ + Returns the registered renderer for the provider/source pair, or `None` if the provider has + no override and should fall back to its default renderer. + """ + return self.registrations.get((provider_key, source)) + + provider_registry = NotificationProviderRegistry() template_registry = Registry[type[NotificationTemplate[Any]]]() +renderer_registry = NotificationRendererRegistry() diff --git a/src/sentry/notifications/platform/renderer.py b/src/sentry/notifications/platform/renderer.py index 9cbea90090bd..b84a890420ea 100644 --- a/src/sentry/notifications/platform/renderer.py +++ b/src/sentry/notifications/platform/renderer.py @@ -2,7 +2,6 @@ from sentry.notifications.platform.types import ( NotificationData, - NotificationProviderKey, NotificationRenderedTemplate, ) @@ -17,8 +16,6 @@ class NotificationRenderer[RenderableT](Protocol): RenderableT is a type that matches the connected provider. """ - provider_key: NotificationProviderKey - @classmethod def render[DataT: NotificationData]( cls, *, data: DataT, rendered_template: NotificationRenderedTemplate diff --git a/src/sentry/notifications/platform/service.py b/src/sentry/notifications/platform/service.py index bbe95c0931b1..72aa5d0715a4 100644 --- a/src/sentry/notifications/platform/service.py +++ b/src/sentry/notifications/platform/service.py @@ -171,7 +171,7 @@ def render_template[RenderableT]( provider: type[NotificationProvider[RenderableT]], ) -> RenderableT: rendered_template = template.render(data=data) - renderer = provider.get_renderer(data=data, category=template.category) + renderer = provider.get_renderer(data=data) return renderer.render(data=data, rendered_template=rendered_template) @staticmethod diff --git a/src/sentry/notifications/platform/slack/provider.py b/src/sentry/notifications/platform/slack/provider.py index d441c674c1c9..dbd7ddb60dba 100644 --- a/src/sentry/notifications/platform/slack/provider.py +++ b/src/sentry/notifications/platform/slack/provider.py @@ -32,13 +32,11 @@ from sentry.notifications.platform.threading import ThreadContext from sentry.notifications.platform.types import ( LinkTextBlock, - NotificationCategory, NotificationData, NotificationProviderKey, NotificationRenderedTemplate, NotificationSection, NotificationSectionType, - NotificationSource, NotificationTarget, NotificationTargetResourceType, NotificationTextBlock, @@ -65,8 +63,6 @@ class SlackRenderable(TypedDict): class SlackRenderer(NotificationRenderer[SlackRenderable]): - provider_key = NotificationProviderKey.SLACK - @classmethod def render[DataT: NotificationData]( cls, *, data: DataT, rendered_template: NotificationRenderedTemplate @@ -144,31 +140,6 @@ def is_available(cls, *, organization: RpcOrganizationSummary | None = None) -> # I currently view this as akin to a rollout or feature flag for the registry return False - @classmethod - def get_renderer( - cls, *, data: NotificationData, category: NotificationCategory - ) -> type[NotificationRenderer[SlackRenderable]]: - from sentry.notifications.platform.slack.renderers.issue import ( - IssueSlackRenderer, - ) - from sentry.notifications.platform.slack.renderers.metric_alert import ( - SlackMetricAlertRenderer, - ) - from sentry.notifications.platform.slack.renderers.seer import SeerSlackRenderer - from sentry.notifications.platform.slack.renderers.seer_agent_write_approval import ( - SeerAgentWriteApprovalSlackRenderer, - ) - - if category == NotificationCategory.SEER: - if data.source == NotificationSource.SEER_AGENT_WRITE_APPROVAL: - return SeerAgentWriteApprovalSlackRenderer - return SeerSlackRenderer - if category == NotificationCategory.ISSUE: - return IssueSlackRenderer - if category == NotificationCategory.METRIC_ALERT: - return SlackMetricAlertRenderer - return cls.default_renderer - @classmethod def send( cls, diff --git a/src/sentry/notifications/platform/slack/renderers/issue.py b/src/sentry/notifications/platform/slack/renderers/issue.py index 096fd3b73513..0bf5fb099aa7 100644 --- a/src/sentry/notifications/platform/slack/renderers/issue.py +++ b/src/sentry/notifications/platform/slack/renderers/issue.py @@ -2,6 +2,7 @@ from sentry import eventstore from sentry.models.group import Group +from sentry.notifications.platform.registry import renderer_registry from sentry.notifications.platform.renderer import NotificationRenderer from sentry.notifications.platform.slack.provider import SlackRenderable from sentry.notifications.platform.templates.issue import IssueNotificationData @@ -9,12 +10,12 @@ NotificationData, NotificationProviderKey, NotificationRenderedTemplate, + NotificationSource, ) +@renderer_registry.register(NotificationProviderKey.SLACK, NotificationSource.ISSUE) class IssueSlackRenderer(NotificationRenderer[SlackRenderable]): - provider_key = NotificationProviderKey.SLACK - @classmethod def render[DataT: NotificationData]( cls, *, data: DataT, rendered_template: NotificationRenderedTemplate diff --git a/src/sentry/notifications/platform/slack/renderers/metric_alert.py b/src/sentry/notifications/platform/slack/renderers/metric_alert.py index 099a124d544e..501d0810cc76 100644 --- a/src/sentry/notifications/platform/slack/renderers/metric_alert.py +++ b/src/sentry/notifications/platform/slack/renderers/metric_alert.py @@ -7,6 +7,7 @@ from sentry.integrations.slack.message_builder.incidents import get_started_at from sentry.integrations.slack.message_builder.types import INCIDENT_COLOR_MAPPING from sentry.integrations.slack.utils.escape import escape_slack_text +from sentry.notifications.platform.registry import renderer_registry from sentry.notifications.platform.renderer import NotificationRenderer from sentry.notifications.platform.slack.provider import SlackRenderable from sentry.notifications.platform.templates.metric_alert import MetricAlertNotificationData @@ -14,12 +15,12 @@ NotificationData, NotificationProviderKey, NotificationRenderedTemplate, + NotificationSource, ) +@renderer_registry.register(NotificationProviderKey.SLACK, NotificationSource.METRIC_ALERT) class SlackMetricAlertRenderer(NotificationRenderer[SlackRenderable]): - provider_key = NotificationProviderKey.SLACK - @classmethod def render[DataT: NotificationData]( cls, *, data: DataT, rendered_template: NotificationRenderedTemplate diff --git a/src/sentry/notifications/platform/slack/renderers/seer.py b/src/sentry/notifications/platform/slack/renderers/seer.py index 8a6b9c30fe2e..a887254c42d9 100644 --- a/src/sentry/notifications/platform/slack/renderers/seer.py +++ b/src/sentry/notifications/platform/slack/renderers/seer.py @@ -21,6 +21,7 @@ SectionBlock, ) +from sentry.notifications.platform.registry import renderer_registry from sentry.notifications.platform.renderer import NotificationRenderer from sentry.notifications.platform.slack.provider import SlackRenderable from sentry.notifications.platform.templates.seer import ( @@ -32,7 +33,9 @@ ) from sentry.notifications.platform.types import ( NotificationData, + NotificationProviderKey, NotificationRenderedTemplate, + NotificationSource, ) from sentry.seer.autofix.utils import AutofixStoppingPoint, CodingAgentProviderType @@ -85,6 +88,15 @@ class AutofixStageConfig(TypedDict): } +@renderer_registry.register( + NotificationProviderKey.SLACK, + NotificationSource.SEER_AUTOFIX_TRIGGER, + NotificationSource.SEER_AUTOFIX_ERROR, + NotificationSource.SEER_AUTOFIX_SUCCESS, + NotificationSource.SEER_AUTOFIX_UPDATE, + NotificationSource.SEER_AGENT_RESPONSE, + NotificationSource.SEER_AGENT_ERROR, +) class SeerSlackRenderer(NotificationRenderer[SlackRenderable]): @classmethod def render[DataT: NotificationData]( diff --git a/src/sentry/notifications/platform/slack/renderers/seer_agent_write_approval.py b/src/sentry/notifications/platform/slack/renderers/seer_agent_write_approval.py index 9016e8ccc645..c2e652fa51c3 100644 --- a/src/sentry/notifications/platform/slack/renderers/seer_agent_write_approval.py +++ b/src/sentry/notifications/platform/slack/renderers/seer_agent_write_approval.py @@ -3,6 +3,7 @@ from sentry.integrations.slack.message_builder.routing import encode_action_id from sentry.integrations.slack.message_builder.types import SlackAction +from sentry.notifications.platform.registry import renderer_registry from sentry.notifications.platform.renderer import NotificationRenderer from sentry.notifications.platform.slack.provider import SlackRenderable from sentry.notifications.platform.templates.seer import SeerAgentWriteApproval @@ -10,12 +11,14 @@ NotificationData, NotificationProviderKey, NotificationRenderedTemplate, + NotificationSource, ) +@renderer_registry.register( + NotificationProviderKey.SLACK, NotificationSource.SEER_AGENT_WRITE_APPROVAL +) class SeerAgentWriteApprovalSlackRenderer(NotificationRenderer[SlackRenderable]): - provider_key = NotificationProviderKey.SLACK - @classmethod def render[DataT: NotificationData]( cls, *, data: DataT, rendered_template: NotificationRenderedTemplate diff --git a/tests/sentry/integrations/slack/test_integration.py b/tests/sentry/integrations/slack/test_integration.py index df2e6e02e7b7..fb96a94f767c 100644 --- a/tests/sentry/integrations/slack/test_integration.py +++ b/tests/sentry/integrations/slack/test_integration.py @@ -21,7 +21,6 @@ from sentry.notifications.platform.slack.provider import SlackNotificationProvider from sentry.notifications.platform.target import IntegrationNotificationTarget from sentry.notifications.platform.types import ( - NotificationCategory, NotificationProviderKey, NotificationTargetResourceType, ) @@ -316,9 +315,7 @@ def setUp(self) -> None: ) data = MockNotification(message="test") rendered_template = MockNotificationTemplate().render(data) - renderer = SlackNotificationProvider.get_renderer( - data=data, category=NotificationCategory.DEBUG - ) + renderer = SlackNotificationProvider.get_renderer(data=data) self.slack_renderable = renderer.render(data=data, rendered_template=rendered_template) @patch("sentry.integrations.slack.sdk_client.SlackSdkClient.chat_postMessage") diff --git a/tests/sentry/notifications/platform/discord/renderers/test_issue.py b/tests/sentry/notifications/platform/discord/renderers/test_issue.py index 0a54b939efdb..3fea480a9d8d 100644 --- a/tests/sentry/notifications/platform/discord/renderers/test_issue.py +++ b/tests/sentry/notifications/platform/discord/renderers/test_issue.py @@ -15,12 +15,12 @@ SerializableRuleProxy, ) from sentry.notifications.platform.types import ( - NotificationCategory, NotificationRenderedTemplate, NotificationSource, ) from sentry.services.eventstore.models import Event from sentry.testutils.cases import TestCase +from sentry.testutils.notifications.platform import MockNotification class IssueDiscordRendererTest(TestCase): @@ -133,22 +133,10 @@ def test_provider_returns_issue_renderer(self) -> None: id=1, label="Test Detector", data={}, project_id=self.project.id ), ) - renderer = DiscordNotificationProvider.get_renderer( - data=data, - category=NotificationCategory.ISSUE, - ) + renderer = DiscordNotificationProvider.get_renderer(data=data) assert renderer is IssueDiscordRenderer - def test_provider_returns_default_for_unknown_category(self) -> None: - data = IssueNotificationData( - group_id=self.group.id, - rule=SerializableRuleProxy( - id=1, label="Test Detector", data={}, project_id=self.project.id - ), - tags=["environment", "level"], - ) - renderer = DiscordNotificationProvider.get_renderer( - data=data, - category=NotificationCategory.DEBUG, - ) + def test_provider_returns_default_for_unregistered_source(self) -> None: + data = MockNotification(message="test") + renderer = DiscordNotificationProvider.get_renderer(data=data) assert renderer is DiscordNotificationProvider.default_renderer diff --git a/tests/sentry/notifications/platform/discord/renderers/test_metric_alert.py b/tests/sentry/notifications/platform/discord/renderers/test_metric_alert.py index 18c17d5d7557..a876041861ab 100644 --- a/tests/sentry/notifications/platform/discord/renderers/test_metric_alert.py +++ b/tests/sentry/notifications/platform/discord/renderers/test_metric_alert.py @@ -17,10 +17,10 @@ from sentry.notifications.platform.templates.metric_alert import MetricAlertNotificationData from sentry.notifications.platform.templates.seer import SeerAutofixError from sentry.notifications.platform.types import ( - NotificationCategory, NotificationRenderedTemplate, ) from sentry.testutils.cases import TestCase +from sentry.testutils.notifications.platform import MockNotification from tests.sentry.notifications.notification_action.test_metric_alert_registry_handlers import ( MetricAlertHandlerBase, ) @@ -62,18 +62,12 @@ def test_render_raises_on_invalid_data_type(self) -> None: class DiscordMetricAlertProviderDispatchTest(TestCase): def test_provider_returns_metric_alert_renderer(self) -> None: data = _make_notification_data() - renderer = DiscordNotificationProvider.get_renderer( - data=data, - category=NotificationCategory.METRIC_ALERT, - ) + renderer = DiscordNotificationProvider.get_renderer(data=data) assert renderer is DiscordMetricAlertRenderer - def test_provider_returns_default_for_unknown_category(self) -> None: - data = _make_notification_data() - renderer = DiscordNotificationProvider.get_renderer( - data=data, - category=NotificationCategory.DEBUG, - ) + def test_provider_returns_default_for_unregistered_source(self) -> None: + data = MockNotification(message="test") + renderer = DiscordNotificationProvider.get_renderer(data=data) assert renderer is DiscordNotificationProvider.default_renderer diff --git a/tests/sentry/notifications/platform/discord/test_provider.py b/tests/sentry/notifications/platform/discord/test_provider.py index 843a4c8f96ec..4a9679a9583d 100644 --- a/tests/sentry/notifications/platform/discord/test_provider.py +++ b/tests/sentry/notifications/platform/discord/test_provider.py @@ -18,7 +18,6 @@ ) from sentry.notifications.platform.target import IntegrationNotificationTarget from sentry.notifications.platform.types import ( - NotificationCategory, NotificationProviderKey, NotificationRenderedAction, NotificationRenderedImage, @@ -55,9 +54,7 @@ def test_default_renderer(self) -> None: data = MockNotification(message="test") template = MockNotificationTemplate() rendered_template = template.render(data) - renderer = DiscordNotificationProvider.get_renderer( - data=data, category=NotificationCategory.DEBUG - ) + renderer = DiscordNotificationProvider.get_renderer(data=data) renderable = renderer.render(data=data, rendered_template=rendered_template) @@ -106,9 +103,7 @@ def test_renderer_without_chart(self) -> None: ) data = MockNotification(message="test without chart") - renderer = DiscordNotificationProvider.get_renderer( - data=data, category=NotificationCategory.DEBUG - ) + renderer = DiscordNotificationProvider.get_renderer(data=data) renderable = renderer.render(data=data, rendered_template=rendered_template) @@ -130,9 +125,7 @@ def test_renderer_without_footer(self) -> None: ) data = MockNotification(message="test without footer") - renderer = DiscordNotificationProvider.get_renderer( - data=data, category=NotificationCategory.DEBUG - ) + renderer = DiscordNotificationProvider.get_renderer(data=data) renderable = renderer.render(data=data, rendered_template=rendered_template) @@ -152,9 +145,7 @@ def test_renderer_without_actions(self) -> None: ) data = MockNotification(message="test without actions") - renderer = DiscordNotificationProvider.get_renderer( - data=data, category=NotificationCategory.DEBUG - ) + renderer = DiscordNotificationProvider.get_renderer(data=data) renderable = renderer.render(data=data, rendered_template=rendered_template) @@ -182,9 +173,7 @@ def test_renderer_multiple_actions(self) -> None: ) data = MockNotification(message="test with multiple actions") - renderer = DiscordNotificationProvider.get_renderer( - data=data, category=NotificationCategory.DEBUG - ) + renderer = DiscordNotificationProvider.get_renderer(data=data) renderable = renderer.render(data=data, rendered_template=rendered_template) diff --git a/tests/sentry/notifications/platform/msteams/test_provider.py b/tests/sentry/notifications/platform/msteams/test_provider.py index 784213098047..a91c6ab287f7 100644 --- a/tests/sentry/notifications/platform/msteams/test_provider.py +++ b/tests/sentry/notifications/platform/msteams/test_provider.py @@ -16,7 +16,6 @@ from sentry.notifications.platform.provider import SendFailure, SendFailureStatus from sentry.notifications.platform.target import IntegrationNotificationTarget from sentry.notifications.platform.types import ( - NotificationCategory, NotificationProviderKey, NotificationRenderedAction, NotificationRenderedTemplate, @@ -32,9 +31,7 @@ def test_default_renderer(self) -> None: data = MockNotification(message="test") template = MockNotificationTemplate() rendered_template = template.render(data) - renderer = MSTeamsNotificationProvider.get_renderer( - data=data, category=NotificationCategory.DEBUG - ) + renderer = MSTeamsNotificationProvider.get_renderer(data=data) renderable = renderer.render(data=data, rendered_template=rendered_template) @@ -108,9 +105,7 @@ def test_renderer_without_chart(self) -> None: footer=base_template.footer, chart=None, # No chart ) - renderer = MSTeamsNotificationProvider.get_renderer( - data=data, category=NotificationCategory.DEBUG - ) + renderer = MSTeamsNotificationProvider.get_renderer(data=data) renderable = renderer.render(data=data, rendered_template=rendered_template) @@ -133,9 +128,7 @@ def test_renderer_without_footer(self) -> None: footer=None, # No footer chart=base_template.chart, ) - renderer = MSTeamsNotificationProvider.get_renderer( - data=data, category=NotificationCategory.DEBUG - ) + renderer = MSTeamsNotificationProvider.get_renderer(data=data) renderable = renderer.render(data=data, rendered_template=rendered_template) @@ -162,9 +155,7 @@ def test_renderer_without_actions(self) -> None: footer=base_template.footer, chart=base_template.chart, ) - renderer = MSTeamsNotificationProvider.get_renderer( - data=data, category=NotificationCategory.DEBUG - ) + renderer = MSTeamsNotificationProvider.get_renderer(data=data) renderable = renderer.render(data=data, rendered_template=rendered_template) @@ -200,9 +191,7 @@ def test_renderer_multiple_actions(self) -> None: footer=None, chart=None, ) - renderer = MSTeamsNotificationProvider.get_renderer( - data=data, category=NotificationCategory.DEBUG - ) + renderer = MSTeamsNotificationProvider.get_renderer(data=data) renderable = renderer.render(data=data, rendered_template=rendered_template) diff --git a/tests/sentry/notifications/platform/slack/renderers/test_issue.py b/tests/sentry/notifications/platform/slack/renderers/test_issue.py index 25c14fb3245f..70ea6a6e2b5a 100644 --- a/tests/sentry/notifications/platform/slack/renderers/test_issue.py +++ b/tests/sentry/notifications/platform/slack/renderers/test_issue.py @@ -16,11 +16,11 @@ SerializableRuleProxy, ) from sentry.notifications.platform.types import ( - NotificationCategory, NotificationRenderedTemplate, NotificationSource, ) from sentry.testutils.cases import TestCase +from sentry.testutils.notifications.platform import MockNotification from sentry.utils import json from sentry.workflow_engine.models import Action from sentry.workflow_engine.types import ActionInvocation, WorkflowEventData @@ -335,21 +335,10 @@ def test_provider_returns_issue_renderer(self) -> None: id=1, label="Test Detector", data={}, project_id=self.project.id ), ) - renderer = SlackNotificationProvider.get_renderer( - data=data, - category=NotificationCategory.ISSUE, - ) + renderer = SlackNotificationProvider.get_renderer(data=data) assert renderer is IssueSlackRenderer - def test_provider_returns_default_for_unknown_category(self) -> None: - data = IssueNotificationData( - group_id=self.group.id, - rule=SerializableRuleProxy( - id=1, label="Test Detector", data={}, project_id=self.project.id - ), - ) - renderer = SlackNotificationProvider.get_renderer( - data=data, - category=NotificationCategory.DEBUG, - ) + def test_provider_returns_default_for_unregistered_source(self) -> None: + data = MockNotification(message="test") + renderer = SlackNotificationProvider.get_renderer(data=data) assert renderer is SlackNotificationProvider.default_renderer diff --git a/tests/sentry/notifications/platform/slack/renderers/test_metric_alert.py b/tests/sentry/notifications/platform/slack/renderers/test_metric_alert.py index 55647d670411..2113f3acf149 100644 --- a/tests/sentry/notifications/platform/slack/renderers/test_metric_alert.py +++ b/tests/sentry/notifications/platform/slack/renderers/test_metric_alert.py @@ -12,10 +12,10 @@ from sentry.notifications.platform.templates.metric_alert import MetricAlertNotificationData from sentry.notifications.platform.templates.seer import SeerAutofixError from sentry.notifications.platform.types import ( - NotificationCategory, NotificationRenderedTemplate, ) from sentry.testutils.cases import TestCase +from sentry.testutils.notifications.platform import MockNotification from tests.sentry.notifications.notification_action.test_metric_alert_registry_handlers import ( MetricAlertHandlerBase, ) @@ -57,18 +57,12 @@ def test_render_raises_on_invalid_data_type(self) -> None: class SlackMetricAlertProviderDispatchTest(TestCase): def test_provider_returns_metric_alert_renderer(self) -> None: data = _make_notification_data() - renderer = SlackNotificationProvider.get_renderer( - data=data, - category=NotificationCategory.METRIC_ALERT, - ) + renderer = SlackNotificationProvider.get_renderer(data=data) assert renderer is SlackMetricAlertRenderer - def test_provider_returns_default_for_unknown_category(self) -> None: - data = _make_notification_data() - renderer = SlackNotificationProvider.get_renderer( - data=data, - category=NotificationCategory.DEBUG, - ) + def test_provider_returns_default_for_unregistered_source(self) -> None: + data = MockNotification(message="test") + renderer = SlackNotificationProvider.get_renderer(data=data) assert renderer is SlackNotificationProvider.default_renderer diff --git a/tests/sentry/notifications/platform/slack/renderers/test_seer.py b/tests/sentry/notifications/platform/slack/renderers/test_seer.py index 657ff15ce0ff..e8e9adc935c4 100644 --- a/tests/sentry/notifications/platform/slack/renderers/test_seer.py +++ b/tests/sentry/notifications/platform/slack/renderers/test_seer.py @@ -28,7 +28,7 @@ SeerAutofixPullRequest, SeerAutofixUpdate, ) -from sentry.notifications.platform.types import NotificationCategory, NotificationRenderedTemplate +from sentry.notifications.platform.types import NotificationRenderedTemplate from sentry.seer.autofix.utils import AutofixStoppingPoint from sentry.testutils.cases import TestCase @@ -409,9 +409,7 @@ def test_render_request_and_provider_dispatch(self) -> None: scopes=["org:write"], ) - renderer = SlackNotificationProvider.get_renderer( - data=data, category=NotificationCategory.SEER - ) + renderer = SlackNotificationProvider.get_renderer(data=data) assert renderer is SeerAgentWriteApprovalSlackRenderer renderable = renderer.render(data=data, rendered_template=self.rendered_template) diff --git a/tests/sentry/notifications/platform/slack/test_provider.py b/tests/sentry/notifications/platform/slack/test_provider.py index 3bc57a1f52c2..b81b1a6de31f 100644 --- a/tests/sentry/notifications/platform/slack/test_provider.py +++ b/tests/sentry/notifications/platform/slack/test_provider.py @@ -28,7 +28,6 @@ ) from sentry.notifications.platform.threading import ThreadContext, ThreadKey from sentry.notifications.platform.types import ( - NotificationCategory, NotificationProviderKey, NotificationSource, NotificationTargetResourceType, @@ -42,9 +41,7 @@ def test_default_renderer(self) -> None: data = MockNotification(message="test") template = MockNotificationTemplate() rendered_template = template.render(data) - renderer = SlackNotificationProvider.get_renderer( - data=data, category=NotificationCategory.DEBUG - ) + renderer = SlackNotificationProvider.get_renderer(data=data) rendererable = renderer.render(data=data, rendered_template=rendered_template) rendererable_dict = [block.to_dict() for block in rendererable.get("blocks", [])] diff --git a/tests/sentry/notifications/platform/test_provider.py b/tests/sentry/notifications/platform/test_provider.py index 3b2511f456ea..82474fc47c67 100644 --- a/tests/sentry/notifications/platform/test_provider.py +++ b/tests/sentry/notifications/platform/test_provider.py @@ -9,7 +9,6 @@ IntegrationNotificationTarget, ) from sentry.notifications.platform.types import ( - NotificationCategory, NotificationProviderKey, NotificationTargetResourceType, ) @@ -38,9 +37,7 @@ def test_all_registrants_follow_protocol(self) -> None: for resource_type in provider.target_resource_types: assert resource_type in NotificationTargetResourceType # Ensures the default renderer links back to its connected provider key - assert provider.default_renderer == provider.get_renderer( - data=self.data, category=NotificationCategory.DEBUG - ) + assert provider.default_renderer == provider.get_renderer(data=self.data) assert isinstance(provider.is_available(), bool) assert isinstance( provider.is_available(