test_plugin.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. from functools import cached_property
  2. from urllib.parse import parse_qs
  3. import pytest
  4. import responses
  5. from sentry.integrations.slack.message_builder import LEVEL_TO_COLOR
  6. from sentry.models import Rule
  7. from sentry.plugins.base import Notification
  8. from sentry.shared_integrations.exceptions import ApiError
  9. from sentry.testutils import PluginTestCase
  10. from sentry.utils import json
  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. rule = Rule.objects.create(project=self.project, label="my rule")
  30. notification = Notification(event=event, rule=rule)
  31. with self.options({"system.url-prefix": "http://example.com"}):
  32. self.plugin.notify(notification)
  33. request = responses.calls[0].request
  34. payload = json.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": "http://example.com/organizations/baz/issues/%s/?referrer=slack"
  47. % group.id,
  48. }
  49. ],
  50. }
  51. @responses.activate
  52. def test_notification_without_culprit(self):
  53. responses.add("POST", "http://example.com/slack")
  54. self.plugin.set_option("webhook", "http://example.com/slack", self.project)
  55. self.plugin.set_option("exclude_culprit", True, self.project)
  56. event = self.store_event(
  57. data={"message": "Hello world", "level": "warning"}, project_id=self.project.id
  58. )
  59. group = event.group
  60. rule = Rule.objects.create(project=self.project, label="my rule")
  61. notification = Notification(event=event, rule=rule)
  62. with self.options({"system.url-prefix": "http://example.com"}):
  63. self.plugin.notify(notification)
  64. request = responses.calls[0].request
  65. payload = json.loads(parse_qs(request.body)["payload"][0])
  66. assert payload == {
  67. "username": "Sentry",
  68. "attachments": [
  69. {
  70. "color": LEVEL_TO_COLOR["warning"],
  71. "fields": [{"short": True, "value": "bar", "title": "Project"}],
  72. "fallback": "[bar] Hello world",
  73. "title": "Hello world",
  74. "title_link": "http://example.com/organizations/baz/issues/%s/?referrer=slack"
  75. % group.id,
  76. }
  77. ],
  78. }
  79. @responses.activate
  80. def test_notification_without_project(self):
  81. responses.add("POST", "http://example.com/slack")
  82. self.plugin.set_option("webhook", "http://example.com/slack", self.project)
  83. self.plugin.set_option("exclude_project", True, self.project)
  84. event = self.store_event(
  85. data={"message": "Hello world", "level": "warning", "culprit": "foo.bar"},
  86. project_id=self.project.id,
  87. )
  88. group = event.group
  89. rule = Rule.objects.create(project=self.project, label="my rule")
  90. notification = Notification(event=event, rule=rule)
  91. with self.options({"system.url-prefix": "http://example.com"}):
  92. self.plugin.notify(notification)
  93. request = responses.calls[0].request
  94. payload = json.loads(parse_qs(request.body)["payload"][0])
  95. assert payload == {
  96. "username": "Sentry",
  97. "attachments": [
  98. {
  99. "color": LEVEL_TO_COLOR["warning"],
  100. "fields": [{"short": False, "value": "foo.bar", "title": "Culprit"}],
  101. "fallback": "[bar] Hello world",
  102. "title": "Hello world",
  103. "title_link": "http://example.com/organizations/baz/issues/%s/?referrer=slack"
  104. % group.id,
  105. }
  106. ],
  107. }
  108. @responses.activate
  109. def test_no_error_on_404(self):
  110. responses.add("POST", "http://example.com/slack", status=404)
  111. self.plugin.set_option("webhook", "http://example.com/slack", self.project)
  112. event = self.store_event(
  113. data={"message": "Hello world", "level": "warning", "culprit": "foo.bar"},
  114. project_id=self.project.id,
  115. )
  116. rule = Rule.objects.create(project=self.project, label="my rule")
  117. notification = Notification(event=event, rule=rule)
  118. # No exception since 404s are supposed to be ignored
  119. with self.options({"system.url-prefix": "http://example.com"}):
  120. self.plugin.notify(notification)
  121. responses.replace("POST", "http://example.com/slack", status=400)
  122. # Other exceptions should not be ignored
  123. with self.options({"system.url-prefix": "http://example.com"}):
  124. with pytest.raises(ApiError):
  125. self.plugin.notify(notification)
  126. @responses.activate
  127. def test_no_error_on_ignorable_slack_errors(self):
  128. responses.add("POST", "http://example.com/slack", status=403, body="action_prohibited")
  129. self.plugin.set_option("webhook", "http://example.com/slack", self.project)
  130. event = self.store_event(
  131. data={"message": "Hello world", "level": "warning", "culprit": "foo.bar"},
  132. project_id=self.project.id,
  133. )
  134. rule = Rule.objects.create(project=self.project, label="my rule")
  135. notification = Notification(event=event, rule=rule)
  136. # No exception since certain errors are supposed to be ignored
  137. with self.options({"system.url-prefix": "http://example.com"}):
  138. self.plugin.notify(notification)
  139. responses.replace("POST", "http://example.com/slack", status=403, body="some_other_error")
  140. # Other exceptions should not be ignored
  141. with self.options({"system.url-prefix": "http://example.com"}):
  142. with pytest.raises(ApiError):
  143. self.plugin.notify(notification)