test_plugin.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. from functools import cached_property
  2. from urllib.parse import parse_qs
  3. import orjson
  4. import pytest
  5. import responses
  6. from sentry.integrations.slack.message_builder.types import LEVEL_TO_COLOR
  7. from sentry.models.rule import Rule
  8. from sentry.plugins.base import Notification
  9. from sentry.shared_integrations.exceptions import ApiError
  10. from sentry.testutils.cases import PluginTestCase
  11. from sentry_plugins.slack.plugin import SlackPlugin
  12. class SlackPluginTest(PluginTestCase):
  13. @cached_property
  14. def plugin(self):
  15. return SlackPlugin()
  16. def test_conf_key(self):
  17. assert self.plugin.conf_key == "slack"
  18. def test_entry_point(self):
  19. self.assertPluginInstalled("slack", self.plugin)
  20. @responses.activate
  21. def test_simple_notification(self):
  22. responses.add("POST", "http://example.com/slack")
  23. self.plugin.set_option("webhook", "http://example.com/slack", self.project)
  24. event = self.store_event(
  25. data={"message": "Hello world", "level": "warning", "culprit": "foo.bar"},
  26. project_id=self.project.id,
  27. )
  28. group = event.group
  29. assert group is not None
  30. rule = Rule.objects.create(project=self.project, label="my rule")
  31. notification = Notification(event=event, rule=rule)
  32. self.plugin.notify(notification)
  33. request = responses.calls[0].request
  34. payload = orjson.loads(parse_qs(request.body)["payload"][0])
  35. assert payload == {
  36. "username": "Sentry",
  37. "attachments": [
  38. {
  39. "color": LEVEL_TO_COLOR["warning"],
  40. "fields": [
  41. {"short": False, "value": "foo.bar", "title": "Culprit"},
  42. {"short": True, "value": "bar", "title": "Project"},
  43. ],
  44. "fallback": "[bar] Hello world",
  45. "title": "Hello world",
  46. "title_link": group.get_absolute_url(params={"referrer": "slack"}),
  47. }
  48. ],
  49. }
  50. @responses.activate
  51. def test_notification_without_culprit(self):
  52. responses.add("POST", "http://example.com/slack")
  53. self.plugin.set_option("webhook", "http://example.com/slack", self.project)
  54. self.plugin.set_option("exclude_culprit", True, self.project)
  55. event = self.store_event(
  56. data={"message": "Hello world", "level": "warning"}, project_id=self.project.id
  57. )
  58. group = event.group
  59. assert group is not None
  60. rule = Rule.objects.create(project=self.project, label="my rule")
  61. notification = Notification(event=event, rule=rule)
  62. self.plugin.notify(notification)
  63. request = responses.calls[0].request
  64. payload = orjson.loads(parse_qs(request.body)["payload"][0])
  65. assert payload == {
  66. "username": "Sentry",
  67. "attachments": [
  68. {
  69. "color": LEVEL_TO_COLOR["warning"],
  70. "fields": [{"short": True, "value": "bar", "title": "Project"}],
  71. "fallback": "[bar] Hello world",
  72. "title": "Hello world",
  73. "title_link": group.get_absolute_url(params={"referrer": "slack"}),
  74. }
  75. ],
  76. }
  77. @responses.activate
  78. def test_notification_without_project(self):
  79. responses.add("POST", "http://example.com/slack")
  80. self.plugin.set_option("webhook", "http://example.com/slack", self.project)
  81. self.plugin.set_option("exclude_project", True, self.project)
  82. event = self.store_event(
  83. data={"message": "Hello world", "level": "warning", "culprit": "foo.bar"},
  84. project_id=self.project.id,
  85. )
  86. group = event.group
  87. assert group is not None
  88. rule = Rule.objects.create(project=self.project, label="my rule")
  89. notification = Notification(event=event, rule=rule)
  90. self.plugin.notify(notification)
  91. request = responses.calls[0].request
  92. payload = orjson.loads(parse_qs(request.body)["payload"][0])
  93. assert payload == {
  94. "username": "Sentry",
  95. "attachments": [
  96. {
  97. "color": LEVEL_TO_COLOR["warning"],
  98. "fields": [{"short": False, "value": "foo.bar", "title": "Culprit"}],
  99. "fallback": "[bar] Hello world",
  100. "title": "Hello world",
  101. "title_link": group.get_absolute_url(params={"referrer": "slack"}),
  102. }
  103. ],
  104. }
  105. @responses.activate
  106. def test_no_error_on_404(self):
  107. responses.add("POST", "http://example.com/slack", status=404)
  108. self.plugin.set_option("webhook", "http://example.com/slack", self.project)
  109. event = self.store_event(
  110. data={"message": "Hello world", "level": "warning", "culprit": "foo.bar"},
  111. project_id=self.project.id,
  112. )
  113. rule = Rule.objects.create(project=self.project, label="my rule")
  114. notification = Notification(event=event, rule=rule)
  115. # No exception since 404s are supposed to be ignored
  116. self.plugin.notify(notification)
  117. responses.replace("POST", "http://example.com/slack", status=400)
  118. # Other exceptions should not be ignored
  119. with pytest.raises(ApiError):
  120. self.plugin.notify(notification)
  121. @responses.activate
  122. def test_no_error_on_ignorable_slack_errors(self):
  123. responses.add("POST", "http://example.com/slack", status=403, body="action_prohibited")
  124. self.plugin.set_option("webhook", "http://example.com/slack", self.project)
  125. event = self.store_event(
  126. data={"message": "Hello world", "level": "warning", "culprit": "foo.bar"},
  127. project_id=self.project.id,
  128. )
  129. rule = Rule.objects.create(project=self.project, label="my rule")
  130. notification = Notification(event=event, rule=rule)
  131. # No exception since certain errors are supposed to be ignored
  132. with self.options({"system.url-prefix": "http://example.com"}):
  133. self.plugin.notify(notification)
  134. responses.replace("POST", "http://example.com/slack", status=403, body="some_other_error")
  135. # Other exceptions should not be ignored
  136. with pytest.raises(ApiError):
  137. self.plugin.notify(notification)