mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-09-29 22:34:33 +00:00
1318 lines
52 KiB
Python
1318 lines
52 KiB
Python
import uuid
|
|
from datetime import datetime
|
|
from unittest import mock
|
|
from unittest.mock import patch
|
|
from urllib.parse import parse_qs
|
|
|
|
import responses
|
|
|
|
import sentry
|
|
from sentry.constants import ObjectStatus
|
|
from sentry.digests.backends.redis import RedisBackend
|
|
from sentry.digests.notifications import event_to_record
|
|
from sentry.integrations.slack.message_builder.issues import get_tags
|
|
from sentry.issues.grouptype import MonitorCheckInFailure
|
|
from sentry.issues.issue_occurrence import IssueEvidence, IssueOccurrence
|
|
from sentry.models.identity import Identity, IdentityStatus
|
|
from sentry.models.integrations.external_actor import ExternalActor
|
|
from sentry.models.integrations.organization_integration import OrganizationIntegration
|
|
from sentry.models.notificationsettingoption import NotificationSettingOption
|
|
from sentry.models.notificationsettingprovider import NotificationSettingProvider
|
|
from sentry.models.projectownership import ProjectOwnership
|
|
from sentry.models.rule import Rule
|
|
from sentry.notifications.notifications.rules import AlertRuleNotification
|
|
from sentry.notifications.types import ActionTargetType, FallthroughChoiceType
|
|
from sentry.ownership.grammar import Matcher, Owner
|
|
from sentry.ownership.grammar import Rule as GrammarRule
|
|
from sentry.ownership.grammar import dump_schema
|
|
from sentry.plugins.base import Notification
|
|
from sentry.silo import SiloMode
|
|
from sentry.tasks.digests import deliver_digest
|
|
from sentry.testutils.cases import PerformanceIssueTestCase, SlackActivityNotificationTest
|
|
from sentry.testutils.helpers.features import with_feature
|
|
from sentry.testutils.helpers.notifications import TEST_ISSUE_OCCURRENCE, TEST_PERF_ISSUE_OCCURRENCE
|
|
from sentry.testutils.helpers.slack import get_attachment, get_blocks_and_fallback_text
|
|
from sentry.testutils.silo import assume_test_silo_mode, region_silo_test
|
|
from sentry.testutils.skips import requires_snuba
|
|
from sentry.types.integrations import ExternalProviders
|
|
from sentry.utils import json
|
|
from sentry.utils.dates import ensure_aware
|
|
|
|
pytestmark = [requires_snuba]
|
|
|
|
|
|
old_get_tags = get_tags
|
|
|
|
|
|
def fake_get_tags(group, event_for_tags, tags):
|
|
return old_get_tags(group, event_for_tags, None)
|
|
|
|
|
|
@region_silo_test
|
|
class SlackIssueAlertNotificationTest(SlackActivityNotificationTest, PerformanceIssueTestCase):
|
|
def setUp(self):
|
|
super().setUp()
|
|
action_data = {
|
|
"id": "sentry.mail.actions.NotifyEmailAction",
|
|
"targetType": "Member",
|
|
"targetIdentifier": str(self.user.id),
|
|
}
|
|
self.rule = Rule.objects.create(
|
|
project=self.project,
|
|
label="ja rule",
|
|
data={
|
|
"match": "all",
|
|
"actions": [action_data],
|
|
},
|
|
)
|
|
|
|
@responses.activate
|
|
def test_issue_alert_user(self):
|
|
"""Test that issue alerts are sent to a Slack user."""
|
|
|
|
event = self.store_event(
|
|
data={"message": "Hello world", "level": "error"}, project_id=self.project.id
|
|
)
|
|
notification_uuid = str(uuid.uuid4())
|
|
notification = AlertRuleNotification(
|
|
Notification(event=event, rule=self.rule),
|
|
ActionTargetType.MEMBER,
|
|
self.user.id,
|
|
notification_uuid=notification_uuid,
|
|
)
|
|
|
|
with self.tasks():
|
|
notification.send()
|
|
|
|
attachment, text = get_attachment()
|
|
|
|
assert attachment["title"] == "Hello world"
|
|
assert (
|
|
attachment["footer"]
|
|
== f"{self.project.slug} | <http://testserver/settings/account/notifications/alerts/?referrer=issue_alert-slack-user¬ification_uuid={notification_uuid}|Notification Settings>"
|
|
)
|
|
assert event.group
|
|
assert (
|
|
attachment["title_link"]
|
|
== f"http://testserver/organizations/{self.organization.slug}/issues/{event.group.id}/?referrer=issue_alert-slack¬ification_uuid={notification_uuid}&alert_rule_id={self.rule.id}&alert_type=issue"
|
|
)
|
|
|
|
@responses.activate
|
|
@with_feature("organizations:slack-block-kit")
|
|
def test_issue_alert_user_block(self):
|
|
"""
|
|
Test that issues alert are sent to a Slack user with the proper payload when block kit is
|
|
enabled.
|
|
"""
|
|
event = self.store_event(
|
|
data={"message": "Hello world", "level": "error"}, project_id=self.project.id
|
|
)
|
|
notification_uuid = str(uuid.uuid4())
|
|
notification = AlertRuleNotification(
|
|
Notification(event=event, rule=self.rule),
|
|
ActionTargetType.MEMBER,
|
|
self.user.id,
|
|
notification_uuid=notification_uuid,
|
|
)
|
|
|
|
with self.tasks():
|
|
notification.send()
|
|
|
|
blocks, fallback_text = get_blocks_and_fallback_text()
|
|
assert (
|
|
fallback_text
|
|
== f"Alert triggered <http://testserver/organizations/{event.organization.slug}/alerts/rules/{event.project.slug}/{self.rule.id}/details/|ja rule>"
|
|
)
|
|
assert blocks[0]["text"]["text"] == fallback_text
|
|
assert event.group
|
|
assert (
|
|
blocks[1]["text"]["text"]
|
|
== f":exclamation: <http://testserver/organizations/{event.organization.slug}/issues/{event.group.id}/?referrer=issue_alert-slack¬ification_uuid={notification_uuid}&alert_rule_id={self.rule.id}&alert_type=issue|*Hello world*>"
|
|
)
|
|
assert (
|
|
blocks[4]["elements"][0]["text"]
|
|
== f"{event.project.slug} | <http://testserver/settings/account/notifications/alerts/?referrer=issue_alert-slack-user¬ification_uuid={notification_uuid}|Notification Settings>"
|
|
)
|
|
|
|
@responses.activate
|
|
@mock.patch(
|
|
"sentry.eventstore.models.GroupEvent.occurrence",
|
|
return_value=TEST_PERF_ISSUE_OCCURRENCE,
|
|
new_callable=mock.PropertyMock,
|
|
)
|
|
def test_performance_issue_alert_user(self, occurrence):
|
|
"""Test that performance issue alerts are sent to a Slack user."""
|
|
|
|
event = self.create_performance_issue()
|
|
|
|
notification = AlertRuleNotification(
|
|
Notification(event=event, rule=self.rule), ActionTargetType.MEMBER, self.user.id
|
|
)
|
|
with self.tasks():
|
|
notification.send()
|
|
|
|
attachment, text = get_attachment()
|
|
self.assert_performance_issue_attachments(
|
|
attachment, self.project.slug, "issue_alert-slack-user", "alerts"
|
|
)
|
|
|
|
@responses.activate
|
|
@mock.patch("sentry.integrations.slack.message_builder.issues.get_tags", new=fake_get_tags)
|
|
@mock.patch(
|
|
"sentry.eventstore.models.GroupEvent.occurrence",
|
|
return_value=TEST_PERF_ISSUE_OCCURRENCE,
|
|
new_callable=mock.PropertyMock,
|
|
)
|
|
@with_feature("organizations:slack-block-kit")
|
|
def test_performance_issue_alert_user_block(self, occurrence):
|
|
"""
|
|
Test that performance issue alerts are sent to a Slack user with the proper payload when
|
|
block kit is enabled.
|
|
"""
|
|
|
|
event = self.create_performance_issue()
|
|
# this is a PerformanceNPlusOneGroupType event
|
|
notification = AlertRuleNotification(
|
|
Notification(event=event, rule=self.rule), ActionTargetType.MEMBER, self.user.id
|
|
)
|
|
with self.tasks():
|
|
notification.send()
|
|
|
|
blocks, fallback_text = get_blocks_and_fallback_text()
|
|
assert (
|
|
fallback_text
|
|
== f"Alert triggered <http://testserver/organizations/{event.organization.slug}/alerts/rules/{event.project.slug}/{self.rule.id}/details/|ja rule>"
|
|
)
|
|
assert blocks[0]["text"]["text"] == fallback_text
|
|
self.assert_performance_issue_blocks(
|
|
blocks,
|
|
event.organization.slug,
|
|
event.project.slug,
|
|
event.group,
|
|
"issue_alert-slack",
|
|
alert_type="alerts",
|
|
issue_link_extra_params=f"&alert_rule_id={self.rule.id}&alert_type=issue",
|
|
)
|
|
assert "level" not in blocks[3]["text"]["text"]
|
|
assert "release" in blocks[3]["text"]["text"]
|
|
|
|
@mock.patch("sentry.integrations.slack.message_builder.issues.get_tags", new=fake_get_tags)
|
|
@responses.activate
|
|
@with_feature("organizations:slack-block-kit")
|
|
def test_crons_issue_alert_user_block(self):
|
|
orig_event = self.store_event(
|
|
data={"message": "Hello world", "level": "error"}, project_id=self.project.id
|
|
)
|
|
event = orig_event.for_group(orig_event.groups[0])
|
|
occurrence = IssueOccurrence(
|
|
uuid.uuid4().hex,
|
|
self.project.id,
|
|
uuid.uuid4().hex,
|
|
["some-fingerprint"],
|
|
"something bad happened",
|
|
"it was bad",
|
|
"1234",
|
|
{"Test": 123},
|
|
[
|
|
IssueEvidence("Evidence 1", "Value 1", True),
|
|
IssueEvidence("Evidence 2", "Value 2", False),
|
|
IssueEvidence("Evidence 3", "Value 3", False),
|
|
],
|
|
MonitorCheckInFailure,
|
|
ensure_aware(datetime.now()),
|
|
"info",
|
|
"/api/123",
|
|
)
|
|
occurrence.save()
|
|
event.occurrence = occurrence
|
|
|
|
event.group.type = MonitorCheckInFailure.type_id
|
|
notification = AlertRuleNotification(
|
|
Notification(event=event, rule=self.rule), ActionTargetType.MEMBER, self.user.id
|
|
)
|
|
with self.tasks():
|
|
notification.send()
|
|
|
|
blocks, fallback_text = get_blocks_and_fallback_text()
|
|
assert (
|
|
fallback_text
|
|
== f"Alert triggered <http://testserver/organizations/{event.organization.slug}/alerts/rules/{event.project.slug}/{self.rule.id}/details/|ja rule>"
|
|
)
|
|
assert len(blocks) == 5
|
|
|
|
@responses.activate
|
|
@mock.patch(
|
|
"sentry.eventstore.models.GroupEvent.occurrence",
|
|
return_value=TEST_ISSUE_OCCURRENCE,
|
|
new_callable=mock.PropertyMock,
|
|
)
|
|
def test_generic_issue_alert_user(self, occurrence):
|
|
"""Test that generic issue alerts are sent to a Slack user."""
|
|
event = self.store_event(
|
|
data={"message": "Hellboy's world", "level": "error"}, project_id=self.project.id
|
|
)
|
|
group_event = event.for_group(event.groups[0])
|
|
|
|
notification = AlertRuleNotification(
|
|
Notification(event=group_event, rule=self.rule), ActionTargetType.MEMBER, self.user.id
|
|
)
|
|
with self.tasks():
|
|
notification.send()
|
|
|
|
attachment, text = get_attachment()
|
|
self.assert_generic_issue_attachments(
|
|
attachment, self.project.slug, "issue_alert-slack-user", "alerts"
|
|
)
|
|
|
|
@responses.activate
|
|
@mock.patch(
|
|
"sentry.eventstore.models.GroupEvent.occurrence",
|
|
return_value=TEST_ISSUE_OCCURRENCE,
|
|
new_callable=mock.PropertyMock,
|
|
)
|
|
@with_feature("organizations:slack-block-kit")
|
|
def test_generic_issue_alert_user_block(self, occurrence):
|
|
"""
|
|
Test that generic issue alerts are sent to a Slack user with the proper payload when
|
|
block kit is enabled.
|
|
"""
|
|
event = self.store_event(
|
|
data={"message": "Hellboy's world", "level": "error"}, project_id=self.project.id
|
|
)
|
|
group_event = event.for_group(event.groups[0])
|
|
|
|
notification = AlertRuleNotification(
|
|
Notification(event=group_event, rule=self.rule), ActionTargetType.MEMBER, self.user.id
|
|
)
|
|
with self.tasks():
|
|
notification.send()
|
|
|
|
blocks, fallback_text = get_blocks_and_fallback_text()
|
|
assert (
|
|
fallback_text
|
|
== f"Alert triggered <http://testserver/organizations/{event.organization.slug}/alerts/rules/{event.project.slug}/{self.rule.id}/details/|ja rule>"
|
|
)
|
|
assert blocks[0]["text"]["text"] == fallback_text
|
|
|
|
self.assert_generic_issue_blocks(
|
|
blocks,
|
|
event.organization.slug,
|
|
event.project.slug,
|
|
event.group,
|
|
"issue_alert-slack",
|
|
alert_type="alerts",
|
|
issue_link_extra_params=f"&alert_rule_id={self.rule.id}&alert_type=issue",
|
|
)
|
|
|
|
@responses.activate
|
|
def test_disabled_org_integration_for_user(self):
|
|
with assume_test_silo_mode(SiloMode.CONTROL):
|
|
OrganizationIntegration.objects.get(integration=self.integration).update(
|
|
status=ObjectStatus.DISABLED
|
|
)
|
|
|
|
event = self.store_event(
|
|
data={"message": "Hello world", "level": "error"}, project_id=self.project.id
|
|
)
|
|
|
|
notification = AlertRuleNotification(
|
|
Notification(event=event, rule=self.rule), ActionTargetType.MEMBER, self.user.id
|
|
)
|
|
|
|
with self.tasks():
|
|
notification.send()
|
|
|
|
assert len(responses.calls) == 0
|
|
|
|
@responses.activate
|
|
def test_issue_alert_issue_owners(self):
|
|
"""Test that issue alerts are sent to issue owners in Slack."""
|
|
|
|
event = self.store_event(
|
|
data={"message": "Hello world", "level": "error"}, project_id=self.project.id
|
|
)
|
|
action_data = {
|
|
"id": "sentry.mail.actions.NotifyEmailAction",
|
|
"targetType": "IssueOwners",
|
|
"targetIdentifier": "",
|
|
}
|
|
rule = Rule.objects.create(
|
|
project=self.project,
|
|
label="ja rule",
|
|
data={
|
|
"match": "all",
|
|
"actions": [action_data],
|
|
},
|
|
)
|
|
ProjectOwnership.objects.create(project_id=self.project.id)
|
|
|
|
notification = AlertRuleNotification(
|
|
Notification(event=event, rule=rule),
|
|
ActionTargetType.ISSUE_OWNERS,
|
|
self.user.id,
|
|
FallthroughChoiceType.ACTIVE_MEMBERS,
|
|
)
|
|
|
|
with self.tasks():
|
|
notification.send()
|
|
|
|
attachment, text = get_attachment()
|
|
|
|
assert attachment["title"] == "Hello world"
|
|
notification_uuid = self.get_notification_uuid(attachment["title_link"])
|
|
assert (
|
|
attachment["title_link"]
|
|
== f"http://testserver/organizations/{self.organization.slug}/issues/{event.group_id}/?referrer=issue_alert-slack¬ification_uuid={notification_uuid}&alert_rule_id={rule.id}&alert_type=issue"
|
|
)
|
|
assert (
|
|
attachment["footer"]
|
|
== f"{self.project.slug} | <http://testserver/settings/account/notifications/alerts/?referrer=issue_alert-slack-user¬ification_uuid={notification_uuid}|Notification Settings>"
|
|
)
|
|
|
|
@responses.activate
|
|
@with_feature("organizations:slack-block-kit")
|
|
def test_issue_alert_issue_owners_block(self):
|
|
"""
|
|
Test that issue alerts are sent to issue owners in Slack with the proper payload when block
|
|
kit is enabled.
|
|
"""
|
|
|
|
event = self.store_event(
|
|
data={"message": "Hello world", "level": "error"}, project_id=self.project.id
|
|
)
|
|
action_data = {
|
|
"id": "sentry.mail.actions.NotifyEmailAction",
|
|
"targetType": "IssueOwners",
|
|
"targetIdentifier": "",
|
|
}
|
|
rule = Rule.objects.create(
|
|
project=self.project,
|
|
label="ja rule",
|
|
data={
|
|
"match": "all",
|
|
"actions": [action_data],
|
|
},
|
|
)
|
|
ProjectOwnership.objects.create(project_id=self.project.id)
|
|
|
|
notification = AlertRuleNotification(
|
|
Notification(event=event, rule=rule),
|
|
ActionTargetType.ISSUE_OWNERS,
|
|
self.user.id,
|
|
FallthroughChoiceType.ACTIVE_MEMBERS,
|
|
)
|
|
|
|
with self.tasks():
|
|
notification.send()
|
|
|
|
blocks, fallback_text = get_blocks_and_fallback_text()
|
|
notification_uuid = notification.notification_uuid
|
|
assert (
|
|
fallback_text
|
|
== f"Alert triggered <http://testserver/organizations/{event.organization.slug}/alerts/rules/{event.project.slug}/{rule.id}/details/|ja rule>"
|
|
)
|
|
assert blocks[0]["text"]["text"] == fallback_text
|
|
assert event.group
|
|
assert (
|
|
blocks[1]["text"]["text"]
|
|
== f":exclamation: <http://testserver/organizations/{event.organization.slug}/issues/{event.group.id}/?referrer=issue_alert-slack¬ification_uuid={notification_uuid}&alert_rule_id={rule.id}&alert_type=issue|*Hello world*>"
|
|
)
|
|
assert (
|
|
blocks[4]["elements"][0]["text"]
|
|
== f"{event.project.slug} | <http://testserver/settings/account/notifications/alerts/?referrer=issue_alert-slack-user¬ification_uuid={notification_uuid}|Notification Settings>"
|
|
)
|
|
|
|
@responses.activate
|
|
def test_issue_alert_issue_owners_environment(self):
|
|
"""Test that issue alerts are sent to issue owners in Slack with the environment in the query params when the alert rule filters by environment."""
|
|
|
|
environment = self.create_environment(self.project, name="production")
|
|
event = self.store_event(
|
|
data={"message": "Hello world", "level": "error", "environment": environment.name},
|
|
project_id=self.project.id,
|
|
)
|
|
action_data = {
|
|
"id": "sentry.mail.actions.NotifyEmailAction",
|
|
"targetType": "IssueOwners",
|
|
"targetIdentifier": "",
|
|
}
|
|
rule = Rule.objects.create(
|
|
project=self.project,
|
|
label="ja rule",
|
|
data={
|
|
"match": "all",
|
|
"actions": [action_data],
|
|
},
|
|
)
|
|
rule = self.create_project_rule(
|
|
project=self.project,
|
|
action_match=[action_data],
|
|
name="ja rule",
|
|
environment_id=environment.id,
|
|
)
|
|
ProjectOwnership.objects.create(project_id=self.project.id)
|
|
|
|
notification = AlertRuleNotification(
|
|
Notification(event=event, rule=rule),
|
|
ActionTargetType.ISSUE_OWNERS,
|
|
self.user.id,
|
|
FallthroughChoiceType.ACTIVE_MEMBERS,
|
|
)
|
|
|
|
with self.tasks():
|
|
notification.send()
|
|
|
|
attachment, text = get_attachment()
|
|
|
|
assert attachment["title"] == "Hello world"
|
|
notification_uuid = self.get_notification_uuid(attachment["title_link"])
|
|
assert (
|
|
attachment["title_link"]
|
|
== f"http://testserver/organizations/{self.organization.slug}/issues/{event.group_id}/?referrer=issue_alert-slack¬ification_uuid={notification_uuid}&environment={environment.name}&alert_rule_id={rule.id}&alert_type=issue"
|
|
)
|
|
assert (
|
|
attachment["footer"]
|
|
== f"{self.project.slug} | {environment.name} | <http://testserver/settings/account/notifications/alerts/?referrer=issue_alert-slack-user¬ification_uuid={notification_uuid}|Notification Settings>"
|
|
)
|
|
|
|
@responses.activate
|
|
@with_feature("organizations:slack-block-kit")
|
|
def test_issue_alert_issue_owners_environment_block(self):
|
|
"""
|
|
Test that issue alerts are sent to issue owners in Slack with the environment in the query
|
|
params when the alert rule filters by environment and block kit is enabled.
|
|
"""
|
|
|
|
environment = self.create_environment(self.project, name="production")
|
|
event = self.store_event(
|
|
data={"message": "Hello world", "level": "error", "environment": environment.name},
|
|
project_id=self.project.id,
|
|
)
|
|
action_data = {
|
|
"id": "sentry.mail.actions.NotifyEmailAction",
|
|
"targetType": "IssueOwners",
|
|
"targetIdentifier": "",
|
|
}
|
|
rule = Rule.objects.create(
|
|
project=self.project,
|
|
label="ja rule",
|
|
data={
|
|
"match": "all",
|
|
"actions": [action_data],
|
|
},
|
|
)
|
|
rule = self.create_project_rule(
|
|
project=self.project,
|
|
action_match=[action_data],
|
|
name="ja rule",
|
|
environment_id=environment.id,
|
|
)
|
|
ProjectOwnership.objects.create(project_id=self.project.id)
|
|
|
|
notification = AlertRuleNotification(
|
|
Notification(event=event, rule=rule),
|
|
ActionTargetType.ISSUE_OWNERS,
|
|
self.user.id,
|
|
FallthroughChoiceType.ACTIVE_MEMBERS,
|
|
)
|
|
|
|
with self.tasks():
|
|
notification.send()
|
|
|
|
blocks, fallback_text = get_blocks_and_fallback_text()
|
|
notification_uuid = notification.notification_uuid
|
|
assert (
|
|
fallback_text
|
|
== f"Alert triggered <http://testserver/organizations/{event.organization.slug}/alerts/rules/{event.project.slug}/{rule.id}/details/|ja rule>"
|
|
)
|
|
assert blocks[0]["text"]["text"] == fallback_text
|
|
assert event.group
|
|
assert (
|
|
blocks[1]["text"]["text"]
|
|
== f":exclamation: <http://testserver/organizations/{event.organization.slug}/issues/{event.group.id}/?referrer=issue_alert-slack¬ification_uuid={notification_uuid}&environment={environment.name}&alert_rule_id={rule.id}&alert_type=issue|*Hello world*>"
|
|
)
|
|
assert (
|
|
blocks[4]["elements"][0]["text"]
|
|
== f"{event.project.slug} | {environment.name} | <http://testserver/settings/account/notifications/alerts/?referrer=issue_alert-slack-user¬ification_uuid={notification_uuid}|Notification Settings>"
|
|
)
|
|
|
|
@responses.activate
|
|
def test_issue_alert_team_issue_owners(self):
|
|
"""Test that issue alerts are sent to a team in Slack via an Issue Owners rule action."""
|
|
|
|
# add a second user to the team so we can be sure it's only
|
|
# sent once (to the team, and not to each individual user)
|
|
user2 = self.create_user(is_superuser=False)
|
|
self.create_member(teams=[self.team], user=user2, organization=self.organization)
|
|
with assume_test_silo_mode(SiloMode.CONTROL):
|
|
self.idp = self.create_identity_provider(type="slack", external_id="TXXXXXXX2")
|
|
self.identity = Identity.objects.create(
|
|
external_id="UXXXXXXX2",
|
|
idp=self.idp,
|
|
user=user2,
|
|
status=IdentityStatus.VALID,
|
|
scopes=[],
|
|
)
|
|
# update the team's notification settings
|
|
ExternalActor.objects.create(
|
|
team_id=self.team.id,
|
|
organization=self.organization,
|
|
integration_id=self.integration.id,
|
|
provider=ExternalProviders.SLACK.value,
|
|
external_name="goma",
|
|
external_id="CXXXXXXX2",
|
|
)
|
|
with assume_test_silo_mode(SiloMode.CONTROL):
|
|
# provider is disabled by default
|
|
NotificationSettingProvider.objects.create(
|
|
team_id=self.team.id,
|
|
scope_type="team",
|
|
scope_identifier=self.team.id,
|
|
provider="slack",
|
|
type="alerts",
|
|
value="always",
|
|
)
|
|
|
|
rule = GrammarRule(Matcher("path", "*"), [Owner("team", self.team.slug)])
|
|
ProjectOwnership.objects.create(project_id=self.project.id, schema=dump_schema([rule]))
|
|
|
|
event = self.store_event(
|
|
data={
|
|
"message": "Hello world",
|
|
"level": "error",
|
|
"stacktrace": {"frames": [{"filename": "foo.py"}]},
|
|
},
|
|
project_id=self.project.id,
|
|
)
|
|
|
|
action_data = {
|
|
"id": "sentry.mail.actions.NotifyEmailAction",
|
|
"targetType": "IssueOwners",
|
|
"targetIdentifier": "",
|
|
}
|
|
rule = Rule.objects.create(
|
|
project=self.project,
|
|
label="ja rule",
|
|
data={
|
|
"match": "all",
|
|
"actions": [action_data],
|
|
},
|
|
)
|
|
|
|
notification = AlertRuleNotification(
|
|
Notification(event=event, rule=rule), ActionTargetType.ISSUE_OWNERS, self.team.id
|
|
)
|
|
|
|
with self.tasks():
|
|
notification.send()
|
|
|
|
# check that only one was sent out - more would mean each user is being notified
|
|
# rather than the team
|
|
assert len(responses.calls) == 1
|
|
|
|
# check that the team got a notification
|
|
data = parse_qs(responses.calls[0].request.body)
|
|
assert data["channel"] == ["CXXXXXXX2"]
|
|
assert "attachments" in data
|
|
attachments = json.loads(data["attachments"][0])
|
|
assert len(attachments) == 1
|
|
assert attachments[0]["title"] == "Hello world"
|
|
notification_uuid = self.get_notification_uuid(attachments[0]["title_link"])
|
|
assert (
|
|
attachments[0]["footer"]
|
|
== f"{self.project.slug} | <http://testserver/settings/{self.organization.slug}/teams/{self.team.slug}/notifications/?referrer=issue_alert-slack-team¬ification_uuid={notification_uuid}|Notification Settings>"
|
|
)
|
|
|
|
@responses.activate
|
|
@with_feature("organizations:slack-block-kit")
|
|
def test_issue_alert_team_issue_owners_block(self):
|
|
"""
|
|
Test that issue alerts are sent to a team in Slack via an Issue Owners rule action with the
|
|
proper payload when block kit is enabled.
|
|
"""
|
|
|
|
# add a second user to the team so we can be sure it's only
|
|
# sent once (to the team, and not to each individual user)
|
|
user2 = self.create_user(is_superuser=False)
|
|
self.create_member(teams=[self.team], user=user2, organization=self.organization)
|
|
with assume_test_silo_mode(SiloMode.CONTROL):
|
|
self.idp = self.create_identity_provider(type="slack", external_id="TXXXXXXX2")
|
|
self.identity = Identity.objects.create(
|
|
external_id="UXXXXXXX2",
|
|
idp=self.idp,
|
|
user=user2,
|
|
status=IdentityStatus.VALID,
|
|
scopes=[],
|
|
)
|
|
# update the team's notification settings
|
|
ExternalActor.objects.create(
|
|
team_id=self.team.id,
|
|
organization=self.organization,
|
|
integration_id=self.integration.id,
|
|
provider=ExternalProviders.SLACK.value,
|
|
external_name="goma",
|
|
external_id="CXXXXXXX2",
|
|
)
|
|
with assume_test_silo_mode(SiloMode.CONTROL):
|
|
# provider is disabled by default
|
|
NotificationSettingProvider.objects.create(
|
|
team_id=self.team.id,
|
|
scope_type="team",
|
|
scope_identifier=self.team.id,
|
|
provider="slack",
|
|
type="alerts",
|
|
value="always",
|
|
)
|
|
|
|
g_rule = GrammarRule(Matcher("path", "*"), [Owner("team", self.team.slug)])
|
|
ProjectOwnership.objects.create(project_id=self.project.id, schema=dump_schema([g_rule]))
|
|
|
|
event = self.store_event(
|
|
data={
|
|
"message": "Hello world",
|
|
"level": "error",
|
|
"stacktrace": {"frames": [{"filename": "foo.py"}]},
|
|
},
|
|
project_id=self.project.id,
|
|
)
|
|
|
|
action_data = {
|
|
"id": "sentry.mail.actions.NotifyEmailAction",
|
|
"targetType": "IssueOwners",
|
|
"targetIdentifier": "",
|
|
}
|
|
rule = Rule.objects.create(
|
|
project=self.project,
|
|
label="ja rule",
|
|
data={
|
|
"match": "all",
|
|
"actions": [action_data],
|
|
},
|
|
)
|
|
|
|
notification = AlertRuleNotification(
|
|
Notification(event=event, rule=rule), ActionTargetType.ISSUE_OWNERS, self.team.id
|
|
)
|
|
|
|
with self.tasks():
|
|
notification.send()
|
|
|
|
# check that only one was sent out - more would mean each user is being notified
|
|
# rather than the team
|
|
assert len(responses.calls) == 1
|
|
|
|
# check that the team got a notification
|
|
data = parse_qs(responses.calls[0].request.body)
|
|
assert data["channel"] == ["CXXXXXXX2"]
|
|
assert "blocks" in data
|
|
assert "text" in data
|
|
blocks = json.loads(data["blocks"][0])
|
|
fallback_text = data["text"][0]
|
|
notification_uuid = notification.notification_uuid
|
|
|
|
assert (
|
|
fallback_text
|
|
== f"Alert triggered <http://testserver/organizations/{event.organization.slug}/alerts/rules/{event.project.slug}/{rule.id}/details/|ja rule>"
|
|
)
|
|
assert blocks[0]["text"]["text"] == fallback_text
|
|
assert event.group
|
|
assert (
|
|
blocks[1]["text"]["text"]
|
|
== f":exclamation: <http://testserver/organizations/{event.organization.slug}/issues/{event.group.id}/?referrer=issue_alert-slack¬ification_uuid={notification_uuid}&alert_rule_id={rule.id}&alert_type=issue|*Hello world*>"
|
|
)
|
|
assert blocks[5]["elements"][0]["text"] == f"Suggested Assignees: #{self.team.slug}"
|
|
assert (
|
|
blocks[6]["elements"][0]["text"]
|
|
== f"{event.project.slug} | <http://testserver/settings/{event.organization.slug}/teams/{self.team.slug}/notifications/?referrer=issue_alert-slack-team¬ification_uuid={notification_uuid}|Notification Settings>"
|
|
)
|
|
|
|
@responses.activate
|
|
def test_disabled_org_integration_for_team(self):
|
|
# update the team's notification settings
|
|
ExternalActor.objects.create(
|
|
team_id=self.team.id,
|
|
organization=self.organization,
|
|
integration_id=self.integration.id,
|
|
provider=ExternalProviders.SLACK.value,
|
|
external_name="goma",
|
|
external_id="CXXXXXXX2",
|
|
)
|
|
|
|
with assume_test_silo_mode(SiloMode.CONTROL):
|
|
OrganizationIntegration.objects.get(integration=self.integration).update(
|
|
status=ObjectStatus.DISABLED
|
|
)
|
|
|
|
rule = GrammarRule(Matcher("path", "*"), [Owner("team", self.team.slug)])
|
|
ProjectOwnership.objects.create(project_id=self.project.id, schema=dump_schema([rule]))
|
|
|
|
event = self.store_event(
|
|
data={
|
|
"message": "Hello world",
|
|
"level": "error",
|
|
"stacktrace": {"frames": [{"filename": "foo.py"}]},
|
|
},
|
|
project_id=self.project.id,
|
|
)
|
|
|
|
action_data = {
|
|
"id": "sentry.mail.actions.NotifyEmailAction",
|
|
"targetType": "IssueOwners",
|
|
"targetIdentifier": "",
|
|
}
|
|
rule = Rule.objects.create(
|
|
project=self.project,
|
|
label="ja rule",
|
|
data={
|
|
"match": "all",
|
|
"actions": [action_data],
|
|
},
|
|
)
|
|
|
|
notification = AlertRuleNotification(
|
|
Notification(event=event, rule=rule), ActionTargetType.ISSUE_OWNERS, self.team.id
|
|
)
|
|
|
|
with self.tasks():
|
|
notification.send()
|
|
|
|
# org integrationon disabled
|
|
assert len(responses.calls) == 0
|
|
|
|
@responses.activate
|
|
@patch.object(sentry, "digests")
|
|
def test_issue_alert_team_issue_owners_user_settings_off_digests(self, digests):
|
|
"""Test that issue alerts are sent to a team in Slack via an Issue Owners rule action
|
|
even when the users' issue alert notification settings are off and digests are triggered."""
|
|
|
|
backend = RedisBackend()
|
|
digests.digest = backend.digest
|
|
digests.enabled.return_value = True
|
|
|
|
# turn off the user's issue alert notification settings
|
|
# there was a bug where issue alerts to a team's Slack channel
|
|
# were only firing if this was set to ALWAYS
|
|
with assume_test_silo_mode(SiloMode.CONTROL):
|
|
NotificationSettingOption.objects.create(
|
|
user_id=self.user.id,
|
|
scope_type="user",
|
|
scope_identifier=self.user.id,
|
|
type="alerts",
|
|
value="never",
|
|
)
|
|
# add a second user to the team so we can be sure it's only
|
|
# sent once (to the team, and not to each individual user)
|
|
user2 = self.create_user(is_superuser=False)
|
|
self.create_member(teams=[self.team], user=user2, organization=self.organization)
|
|
with assume_test_silo_mode(SiloMode.CONTROL):
|
|
self.idp = self.create_identity_provider(type="slack", external_id="TXXXXXXX2")
|
|
self.identity = Identity.objects.create(
|
|
external_id="UXXXXXXX2",
|
|
idp=self.idp,
|
|
user=user2,
|
|
status=IdentityStatus.VALID,
|
|
scopes=[],
|
|
)
|
|
# update the team's notification settings
|
|
ExternalActor.objects.create(
|
|
team_id=self.team.id,
|
|
organization=self.organization,
|
|
integration_id=self.integration.id,
|
|
provider=ExternalProviders.SLACK.value,
|
|
external_name="goma",
|
|
external_id="CXXXXXXX2",
|
|
)
|
|
with assume_test_silo_mode(SiloMode.CONTROL):
|
|
NotificationSettingProvider.objects.create(
|
|
team_id=self.team.id,
|
|
scope_type="team",
|
|
scope_identifier=self.team.id,
|
|
provider="slack",
|
|
type="alerts",
|
|
value="always",
|
|
)
|
|
|
|
g_rule = GrammarRule(Matcher("path", "*"), [Owner("team", self.team.slug)])
|
|
ProjectOwnership.objects.create(project_id=self.project.id, schema=dump_schema([g_rule]))
|
|
|
|
event = self.store_event(
|
|
data={
|
|
"message": "Hello world",
|
|
"level": "error",
|
|
"stacktrace": {"frames": [{"filename": "foo.py"}]},
|
|
},
|
|
project_id=self.project.id,
|
|
)
|
|
|
|
action_data = {
|
|
"id": "sentry.mail.actions.NotifyEmailAction",
|
|
"targetType": "IssueOwners",
|
|
"targetIdentifier": "",
|
|
}
|
|
rule = Rule.objects.create(
|
|
project=self.project,
|
|
label="ja rule",
|
|
data={
|
|
"match": "all",
|
|
"actions": [action_data],
|
|
},
|
|
)
|
|
|
|
key = f"mail:p:{self.project.id}"
|
|
backend.add(key, event_to_record(event, [rule]), increment_delay=0, maximum_delay=0)
|
|
|
|
with self.tasks():
|
|
deliver_digest(key)
|
|
|
|
# check that only one was sent out - more would mean each user is being notified
|
|
# rather than the team
|
|
assert len(responses.calls) == 1
|
|
|
|
# check that the team got a notification
|
|
data = parse_qs(responses.calls[0].request.body)
|
|
assert data["channel"] == ["CXXXXXXX2"]
|
|
assert "attachments" in data
|
|
attachments = json.loads(data["attachments"][0])
|
|
assert len(attachments) == 1
|
|
assert attachments[0]["title"] == "Hello world"
|
|
notification_uuid = self.get_notification_uuid(attachments[0]["title_link"])
|
|
assert (
|
|
attachments[0]["footer"]
|
|
== f"{self.project.slug} | <http://testserver/settings/{self.organization.slug}/teams/{self.team.slug}/notifications/?referrer=issue_alert-slack-team¬ification_uuid={notification_uuid}|Notification Settings>"
|
|
)
|
|
|
|
@responses.activate
|
|
def test_issue_alert_team(self):
|
|
"""Test that issue alerts are sent to a team in Slack."""
|
|
# add a second organization
|
|
org = self.create_organization(owner=self.user)
|
|
with assume_test_silo_mode(SiloMode.CONTROL):
|
|
self.create_organization_integration(
|
|
organization_id=org.id, integration=self.integration
|
|
)
|
|
|
|
# add a second user to the team so we can be sure it's only
|
|
# sent once (to the team, and not to each individual user)
|
|
user2 = self.create_user(is_superuser=False)
|
|
self.create_member(teams=[self.team], user=user2, organization=self.organization)
|
|
with assume_test_silo_mode(SiloMode.CONTROL):
|
|
self.idp = self.create_identity_provider(type="slack", external_id="TXXXXXXX2")
|
|
self.identity = Identity.objects.create(
|
|
external_id="UXXXXXXX2",
|
|
idp=self.idp,
|
|
user=user2,
|
|
status=IdentityStatus.VALID,
|
|
scopes=[],
|
|
)
|
|
# update the team's notification settings
|
|
ExternalActor.objects.create(
|
|
team_id=self.team.id,
|
|
organization=self.organization,
|
|
integration_id=self.integration.id,
|
|
provider=ExternalProviders.SLACK.value,
|
|
external_name="goma",
|
|
external_id="CXXXXXXX2",
|
|
)
|
|
with assume_test_silo_mode(SiloMode.CONTROL):
|
|
NotificationSettingProvider.objects.create(
|
|
team_id=self.team.id,
|
|
scope_type="team",
|
|
scope_identifier=self.team.id,
|
|
provider="slack",
|
|
type="alerts",
|
|
value="always",
|
|
)
|
|
|
|
event = self.store_event(
|
|
data={"message": "Hello world", "level": "error"}, project_id=self.project.id
|
|
)
|
|
action_data = {
|
|
"id": "sentry.mail.actions.NotifyEmailAction",
|
|
"targetType": "Team",
|
|
"targetIdentifier": str(self.team.id),
|
|
}
|
|
rule = Rule.objects.create(
|
|
project=self.project,
|
|
label="ja rule",
|
|
data={
|
|
"match": "all",
|
|
"actions": [action_data],
|
|
},
|
|
)
|
|
notification = Notification(event=event, rule=rule)
|
|
|
|
with self.options({"system.url-prefix": "http://example.com"}), self.tasks():
|
|
self.adapter.notify(notification, ActionTargetType.TEAM, self.team.id)
|
|
|
|
# check that only one was sent out - more would mean each user is being notified
|
|
# rather than the team
|
|
assert len(responses.calls) == 1
|
|
|
|
# check that the team got a notification
|
|
data = parse_qs(responses.calls[0].request.body)
|
|
assert data["channel"] == ["CXXXXXXX2"]
|
|
assert "attachments" in data
|
|
attachments = json.loads(data["attachments"][0])
|
|
assert len(attachments) == 1
|
|
assert attachments[0]["title"] == "Hello world"
|
|
notification_uuid = self.get_notification_uuid(attachments[0]["title_link"])
|
|
assert (
|
|
attachments[0]["footer"]
|
|
== f"{self.project.slug} | <http://example.com/settings/{self.organization.slug}/teams/{self.team.slug}/notifications/?referrer=issue_alert-slack-team¬ification_uuid={notification_uuid}|Notification Settings>"
|
|
)
|
|
|
|
@responses.activate
|
|
@with_feature("organizations:slack-block-kit")
|
|
def test_issue_alert_team_block(self):
|
|
"""Test that issue alerts are sent to a team in Slack when block kit is enabled."""
|
|
# add a second organization
|
|
org = self.create_organization(owner=self.user)
|
|
with assume_test_silo_mode(SiloMode.CONTROL):
|
|
self.create_organization_integration(
|
|
organization_id=org.id, integration=self.integration
|
|
)
|
|
|
|
# add a second user to the team so we can be sure it's only
|
|
# sent once (to the team, and not to each individual user)
|
|
user2 = self.create_user(is_superuser=False)
|
|
self.create_member(teams=[self.team], user=user2, organization=self.organization)
|
|
with assume_test_silo_mode(SiloMode.CONTROL):
|
|
self.idp = self.create_identity_provider(type="slack", external_id="TXXXXXXX2")
|
|
self.identity = Identity.objects.create(
|
|
external_id="UXXXXXXX2",
|
|
idp=self.idp,
|
|
user=user2,
|
|
status=IdentityStatus.VALID,
|
|
scopes=[],
|
|
)
|
|
# update the team's notification settings
|
|
ExternalActor.objects.create(
|
|
team_id=self.team.id,
|
|
organization=self.organization,
|
|
integration_id=self.integration.id,
|
|
provider=ExternalProviders.SLACK.value,
|
|
external_name="goma",
|
|
external_id="CXXXXXXX2",
|
|
)
|
|
with assume_test_silo_mode(SiloMode.CONTROL):
|
|
NotificationSettingProvider.objects.create(
|
|
team_id=self.team.id,
|
|
scope_type="team",
|
|
scope_identifier=self.team.id,
|
|
provider="slack",
|
|
type="alerts",
|
|
value="always",
|
|
)
|
|
|
|
event = self.store_event(
|
|
data={"message": "Hello world", "level": "error"}, project_id=self.project.id
|
|
)
|
|
action_data = {
|
|
"id": "sentry.mail.actions.NotifyEmailAction",
|
|
"targetType": "Team",
|
|
"targetIdentifier": str(self.team.id),
|
|
}
|
|
rule = Rule.objects.create(
|
|
project=self.project,
|
|
label="ja rule",
|
|
data={
|
|
"match": "all",
|
|
"actions": [action_data],
|
|
},
|
|
)
|
|
notification = Notification(event=event, rule=rule)
|
|
|
|
with self.options({"system.url-prefix": "http://example.com"}), self.tasks():
|
|
self.adapter.notify(notification, ActionTargetType.TEAM, self.team.id)
|
|
|
|
# check that only one was sent out - more would mean each user is being notified
|
|
# rather than the team
|
|
assert len(responses.calls) == 1
|
|
|
|
# check that the team got a notification
|
|
data = parse_qs(responses.calls[0].request.body)
|
|
assert data["channel"] == ["CXXXXXXX2"]
|
|
assert "blocks" in data
|
|
assert "text" in data
|
|
blocks = json.loads(data["blocks"][0])
|
|
fallback_text = data["text"][0]
|
|
notification_uuid = self.get_notification_uuid(blocks[1]["text"]["text"])
|
|
|
|
assert (
|
|
fallback_text
|
|
== f"Alert triggered <http://example.com/organizations/{event.organization.slug}/alerts/rules/{event.project.slug}/{rule.id}/details/|ja rule>"
|
|
)
|
|
assert blocks[0]["text"]["text"] == fallback_text
|
|
assert event.group
|
|
assert (
|
|
blocks[1]["text"]["text"]
|
|
== f":exclamation: <http://example.com/organizations/{event.organization.slug}/issues/{event.group.id}/?referrer=issue_alert-slack¬ification_uuid={notification_uuid}&alert_rule_id={rule.id}&alert_type=issue|*Hello world*>"
|
|
)
|
|
assert (
|
|
blocks[5]["elements"][0]["text"]
|
|
== f"{event.project.slug} | <http://example.com/settings/{event.organization.slug}/teams/{self.team.slug}/notifications/?referrer=issue_alert-slack-team¬ification_uuid={notification_uuid}|Notification Settings>"
|
|
)
|
|
|
|
@responses.activate
|
|
def test_issue_alert_team_new_project(self):
|
|
"""Test that issue alerts are sent to a team in Slack when the team has added a new project"""
|
|
|
|
# add a second user to the team so we can be sure it's only
|
|
# sent once (to the team, and not to each individual user)
|
|
user2 = self.create_user(is_superuser=False)
|
|
self.create_member(teams=[self.team], user=user2, organization=self.organization)
|
|
with assume_test_silo_mode(SiloMode.CONTROL):
|
|
self.idp = self.create_identity_provider(type="slack", external_id="TXXXXXXX2")
|
|
self.identity = Identity.objects.create(
|
|
external_id="UXXXXXXX2",
|
|
idp=self.idp,
|
|
user=user2,
|
|
status=IdentityStatus.VALID,
|
|
scopes=[],
|
|
)
|
|
# update the team's notification settings
|
|
ExternalActor.objects.create(
|
|
team_id=self.team.id,
|
|
organization=self.organization,
|
|
integration_id=self.integration.id,
|
|
provider=ExternalProviders.SLACK.value,
|
|
external_name="goma",
|
|
external_id="CXXXXXXX2",
|
|
)
|
|
with assume_test_silo_mode(SiloMode.CONTROL):
|
|
NotificationSettingProvider.objects.create(
|
|
team_id=self.team.id,
|
|
scope_type="team",
|
|
scope_identifier=self.team.id,
|
|
provider="slack",
|
|
type="alerts",
|
|
value="always",
|
|
)
|
|
# add a new project
|
|
project2 = self.create_project(
|
|
name="hellboy", organization=self.organization, teams=[self.team]
|
|
)
|
|
|
|
event = self.store_event(
|
|
data={"message": "Hello world", "level": "error"}, project_id=project2.id
|
|
)
|
|
action_data = {
|
|
"id": "sentry.mail.actions.NotifyEmailAction",
|
|
"targetType": "Team",
|
|
"targetIdentifier": str(self.team.id),
|
|
}
|
|
rule = Rule.objects.create(
|
|
project=project2,
|
|
label="ja rule",
|
|
data={
|
|
"match": "all",
|
|
"actions": [action_data],
|
|
},
|
|
)
|
|
notification = Notification(event=event, rule=rule)
|
|
|
|
with self.options({"system.url-prefix": "http://example.com"}), self.tasks():
|
|
self.adapter.notify(notification, ActionTargetType.TEAM, self.team.id)
|
|
|
|
# check that only one was sent out - more would mean each user is being notified
|
|
# rather than the team
|
|
assert len(responses.calls) == 1
|
|
|
|
# check that the team got a notification
|
|
data = parse_qs(responses.calls[0].request.body)
|
|
assert data["channel"] == ["CXXXXXXX2"]
|
|
assert "attachments" in data
|
|
attachments = json.loads(data["attachments"][0])
|
|
assert len(attachments) == 1
|
|
assert attachments[0]["title"] == "Hello world"
|
|
notification_uuid = self.get_notification_uuid(attachments[0]["title_link"])
|
|
assert (
|
|
attachments[0]["footer"]
|
|
== f"{project2.slug} | <http://example.com/settings/{self.organization.slug}/teams/{self.team.slug}/notifications/?referrer=issue_alert-slack-team¬ification_uuid={notification_uuid}|Notification Settings>"
|
|
)
|
|
|
|
@responses.activate
|
|
def test_not_issue_alert_team_removed_project(self):
|
|
"""Test that issue alerts are not sent to a team in Slack when the team has removed the project the issue belongs to"""
|
|
|
|
# create the team's notification settings
|
|
ExternalActor.objects.create(
|
|
team_id=self.team.id,
|
|
organization=self.organization,
|
|
integration_id=self.integration.id,
|
|
provider=ExternalProviders.SLACK.value,
|
|
external_name="goma",
|
|
external_id="CXXXXXXX2",
|
|
)
|
|
with assume_test_silo_mode(SiloMode.CONTROL):
|
|
NotificationSettingProvider.objects.create(
|
|
team_id=self.team.id,
|
|
scope_type="team",
|
|
scope_identifier=self.team.id,
|
|
provider="slack",
|
|
type="alerts",
|
|
value="always",
|
|
)
|
|
# remove the project from the team
|
|
self.project.remove_team(self.team)
|
|
|
|
event = self.store_event(
|
|
data={"message": "Hello world", "level": "error"}, project_id=self.project.id
|
|
)
|
|
action_data = {
|
|
"id": "sentry.mail.actions.NotifyEmailAction",
|
|
"targetType": "Team",
|
|
"targetIdentifier": str(self.team.id),
|
|
}
|
|
rule = Rule.objects.create(
|
|
project=self.project,
|
|
label="ja rule",
|
|
data={
|
|
"match": "all",
|
|
"actions": [action_data],
|
|
},
|
|
)
|
|
notification = Notification(event=event, rule=rule)
|
|
|
|
with self.options({"system.url-prefix": "http://example.com"}), self.tasks():
|
|
self.adapter.notify(notification, ActionTargetType.TEAM, self.team.id)
|
|
|
|
assert len(responses.calls) == 0
|
|
|
|
@responses.activate
|
|
def test_issue_alert_team_fallback(self):
|
|
"""Test that issue alerts are sent to each member of a team in Slack."""
|
|
|
|
user2 = self.create_user(is_superuser=False)
|
|
self.create_member(teams=[self.team], user=user2, organization=self.organization)
|
|
with assume_test_silo_mode(SiloMode.CONTROL):
|
|
self.identity = Identity.objects.create(
|
|
external_id="UXXXXXXX2",
|
|
idp=self.idp,
|
|
user=user2,
|
|
status=IdentityStatus.VALID,
|
|
scopes=[],
|
|
)
|
|
|
|
event = self.store_event(
|
|
data={"message": "Hello world", "level": "error"}, project_id=self.project.id
|
|
)
|
|
action_data = {
|
|
"id": "sentry.mail.actions.NotifyEmailAction",
|
|
"targetType": "Team",
|
|
"targetIdentifier": str(self.team.id),
|
|
}
|
|
rule = Rule.objects.create(
|
|
project=self.project,
|
|
label="ja rule",
|
|
data={
|
|
"match": "all",
|
|
"actions": [action_data],
|
|
},
|
|
)
|
|
notification = Notification(event=event, rule=rule)
|
|
|
|
with self.options({"system.url-prefix": "http://example.com"}), self.tasks():
|
|
self.adapter.notify(notification, ActionTargetType.TEAM, self.team.id)
|
|
|
|
assert len(responses.calls) == 2
|
|
|
|
# check that self.user got a notification
|
|
call1 = parse_qs(responses.calls[0].request.body)
|
|
call2 = parse_qs(responses.calls[1].request.body)
|
|
|
|
# don't assume a particular order
|
|
data = call1 if call1["channel"] == ["UXXXXXXX1"] else call2
|
|
data2 = call2 if call2["channel"] == ["UXXXXXXX2"] else call1
|
|
|
|
assert data["channel"] == ["UXXXXXXX1"]
|
|
assert "attachments" in data
|
|
attachments = json.loads(data["attachments"][0])
|
|
assert len(attachments) == 1
|
|
assert attachments[0]["title"] == "Hello world"
|
|
notification_uuid = self.get_notification_uuid(attachments[0]["title_link"])
|
|
assert (
|
|
attachments[0]["footer"]
|
|
== f"{self.project.slug} | <http://example.com/settings/account/notifications/alerts/?referrer=issue_alert-slack-user¬ification_uuid={notification_uuid}|Notification Settings>"
|
|
)
|
|
|
|
# check that user2 got a notification as well
|
|
assert data2["channel"] == ["UXXXXXXX2"]
|
|
assert "attachments" in data2
|
|
attachments = json.loads(data2["attachments"][0])
|
|
assert len(attachments) == 1
|
|
assert attachments[0]["title"] == "Hello world"
|
|
assert (
|
|
attachments[0]["footer"]
|
|
== f"{self.project.slug} | <http://example.com/settings/account/notifications/alerts/?referrer=issue_alert-slack-user¬ification_uuid={notification_uuid}|Notification Settings>"
|
|
)
|
|
|
|
@responses.activate
|
|
@patch.object(sentry, "digests")
|
|
def test_digest_enabled(self, digests):
|
|
"""
|
|
Test that with digests enabled, but Slack notification settings
|
|
(and not email settings), we send a Slack notification
|
|
"""
|
|
backend = RedisBackend()
|
|
digests.digest = backend.digest
|
|
digests.enabled.return_value = True
|
|
|
|
rule = Rule.objects.create(project=self.project, label="my rule")
|
|
ProjectOwnership.objects.create(project_id=self.project.id)
|
|
event = self.store_event(
|
|
data={"message": "Hello world", "level": "error"}, project_id=self.project.id
|
|
)
|
|
key = f"mail:p:{self.project.id}:IssueOwners::AllMembers"
|
|
backend.add(key, event_to_record(event, [rule]), increment_delay=0, maximum_delay=0)
|
|
|
|
with self.tasks():
|
|
deliver_digest(key)
|
|
|
|
attachment, text = get_attachment()
|
|
|
|
assert attachment["title"] == "Hello world"
|
|
assert attachment["text"] == ""
|
|
|
|
@responses.activate
|
|
@patch.object(sentry, "digests")
|
|
@with_feature("organizations:slack-block-kit")
|
|
def test_digest_enabled_block(self, digests):
|
|
"""
|
|
Test that with digests enabled, but Slack notification settings
|
|
(and not email settings) enabled, we send a Slack notification with the proper
|
|
payload when block kit is enabled.
|
|
"""
|
|
backend = RedisBackend()
|
|
digests.digest = backend.digest
|
|
digests.enabled.return_value = True
|
|
|
|
rule = Rule.objects.create(project=self.project, label="my rule")
|
|
ProjectOwnership.objects.create(project_id=self.project.id)
|
|
event = self.store_event(
|
|
data={"message": "Hello world", "level": "error"}, project_id=self.project.id
|
|
)
|
|
|
|
key = f"mail:p:{self.project.id}:IssueOwners::AllMembers"
|
|
backend.add(key, event_to_record(event, [rule]), increment_delay=0, maximum_delay=0)
|
|
|
|
with self.tasks():
|
|
deliver_digest(key)
|
|
|
|
blocks, fallback_text = get_blocks_and_fallback_text()
|
|
notification_uuid = self.get_notification_uuid(blocks[1]["text"]["text"])
|
|
assert (
|
|
fallback_text
|
|
== f"Alert triggered <http://testserver/organizations/{event.organization.slug}/alerts/rules/{event.project.slug}/{rule.id}/details/|my rule>"
|
|
)
|
|
assert blocks[0]["text"]["text"] == fallback_text
|
|
assert event.group
|
|
assert (
|
|
blocks[1]["text"]["text"]
|
|
== f":exclamation: <http://testserver/organizations/{event.organization.slug}/issues/{event.group.id}/?referrer=issue_alert-slack¬ification_uuid={notification_uuid}&alert_rule_id={rule.id}&alert_type=issue|*Hello world*>"
|
|
)
|
|
assert (
|
|
blocks[4]["elements"][0]["text"]
|
|
== f"{event.project.slug} | <http://testserver/settings/account/notifications/alerts/?referrer=issue_alert-slack-user¬ification_uuid={notification_uuid}|Notification Settings>"
|
|
)
|