test_plugin.py 6.9 KB

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