test_webhooks.py 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. import json
  2. from datetime import datetime
  3. from unittest import mock
  4. from model_bakery import baker
  5. from apps.issue_events.constants import LogLevel
  6. from apps.uptime.constants import MonitorType
  7. from apps.uptime.models import Monitor, MonitorCheck
  8. from apps.uptime.webhooks import send_uptime_as_webhook
  9. from glitchtip.test_utils.test_case import GlitchTipTestCase
  10. from ..constants import RecipientType
  11. from ..models import AlertRecipient, Notification
  12. from ..tasks import process_event_alerts
  13. from ..webhooks import (
  14. send_issue_as_discord_webhook,
  15. send_issue_as_googlechat_webhook,
  16. send_issue_as_webhook,
  17. send_webhook,
  18. )
  19. TEST_URL = "https://burkesoftware.rocket.chat/hooks/Y8TttGY7RvN7Qm3gD/rqhHLiRSvYRZ8BhbhhhLYumdMksWnyj3Dqsqt8QKrmbNndXH"
  20. DISCORD_TEST_URL = "https://discord.com/api/webhooks/not_real_id/not_real_token"
  21. GOOGLE_CHAT_TEST_URL = "https://chat.googleapis.com/v1/spaces/space_id/messages?key=api_key&token=api_token"
  22. class WebhookTestCase(GlitchTipTestCase):
  23. def setUp(self):
  24. self.environment_name = "test-environment"
  25. self.release_name = "test-release"
  26. self.create_user_and_project()
  27. self.monitor = baker.make(Monitor, name="Example Monitor", url="https://example.com", monitor_type=MonitorType.GET, project=self.project)
  28. self.monitor_check = baker.make(MonitorCheck, monitor=self.monitor)
  29. self.expected_subject = "GlitchTip Uptime Alert"
  30. self.expected_message_down = "The monitored site has gone down."
  31. self.expected_message_up = "The monitored site is back up."
  32. def generate_issue_with_tags(self):
  33. key_environment = baker.make("issue_events.TagKey", key="environment")
  34. environment_value = baker.make(
  35. "issue_events.TagValue", value=self.environment_name
  36. )
  37. key_release = baker.make("issue_events.TagKey", key="release")
  38. release_value = baker.make("issue_events.TagValue", value=self.release_name)
  39. issue = baker.make("issue_events.Issue", level=LogLevel.ERROR)
  40. baker.make(
  41. "issue_events.IssueTag",
  42. issue=issue,
  43. tag_key=key_environment,
  44. tag_value=environment_value,
  45. )
  46. baker.make(
  47. "issue_events.IssueTag",
  48. issue=issue,
  49. tag_key=key_release,
  50. tag_value=release_value,
  51. )
  52. return issue
  53. @mock.patch("requests.post")
  54. def test_send_webhook(self, mock_post):
  55. send_webhook(
  56. TEST_URL,
  57. "from unit test",
  58. )
  59. mock_post.assert_called_once()
  60. @mock.patch("requests.post")
  61. def test_send_issue_as_webhook(self, mock_post):
  62. issue = self.generate_issue_with_tags()
  63. issue2 = baker.make("issue_events.Issue", level=LogLevel.ERROR, short_id=2)
  64. issue3 = baker.make("issue_events.Issue", level=LogLevel.NOTSET)
  65. send_issue_as_webhook(TEST_URL, [issue, issue2, issue3], 3)
  66. mock_post.assert_called_once()
  67. first_issue_json_data = json.dumps(
  68. mock_post.call_args.kwargs["json"]["attachments"][0]
  69. )
  70. self.assertIn(
  71. f'"title": "Environment", "value": "{self.environment_name}"',
  72. first_issue_json_data,
  73. )
  74. self.assertIn(
  75. f'"title": "Release", "value": "{self.release_name}"', first_issue_json_data
  76. )
  77. @mock.patch("requests.post")
  78. def test_trigger_webhook(self, mock_post):
  79. project = baker.make("projects.Project")
  80. alert = baker.make(
  81. "alerts.ProjectAlert",
  82. project=project,
  83. timespan_minutes=1,
  84. quantity=2,
  85. )
  86. baker.make(
  87. "alerts.AlertRecipient",
  88. alert=alert,
  89. recipient_type=RecipientType.GENERAL_WEBHOOK,
  90. url="example.com",
  91. )
  92. issue = baker.make("issue_events.Issue", project=project)
  93. baker.make("issue_events.IssueEvent", issue=issue)
  94. process_event_alerts()
  95. self.assertEqual(Notification.objects.count(), 0)
  96. baker.make("issue_events.IssueEvent", issue=issue)
  97. process_event_alerts()
  98. self.assertEqual(
  99. Notification.objects.filter(
  100. project_alert__alertrecipient__recipient_type=RecipientType.GENERAL_WEBHOOK
  101. ).count(),
  102. 1,
  103. )
  104. mock_post.assert_called_once()
  105. self.assertIn(
  106. issue.title, mock_post.call_args[1]["json"]["sections"][0]["activityTitle"]
  107. )
  108. @mock.patch("requests.post")
  109. def test_send_issue_with_tags_as_discord_webhook(self, mock_post):
  110. issue = self.generate_issue_with_tags()
  111. send_issue_as_discord_webhook(DISCORD_TEST_URL, [issue])
  112. mock_post.assert_called_once()
  113. json_data = json.dumps(mock_post.call_args.kwargs["json"])
  114. self.assertIn(
  115. f'"name": "Environment", "value": "{self.environment_name}"', json_data
  116. )
  117. self.assertIn(f'"name": "Release", "value": "{self.release_name}"', json_data)
  118. @mock.patch("requests.post")
  119. def test_send_issue_with_tags_as_googlechat_webhook(self, mock_post):
  120. issue = self.generate_issue_with_tags()
  121. send_issue_as_googlechat_webhook(GOOGLE_CHAT_TEST_URL, [issue])
  122. mock_post.assert_called_once()
  123. json_data = json.dumps(mock_post.call_args.kwargs["json"])
  124. self.assertIn(
  125. f'"topLabel": "Release", "text": "{self.release_name}"', json_data
  126. )
  127. self.assertIn(
  128. f'"topLabel": "Environment", "text": "{self.environment_name}"',
  129. json_data,
  130. )
  131. @mock.patch("requests.post")
  132. def test_send_uptime_events_generic_webhook(self, mock_post):
  133. recipient = baker.make(AlertRecipient, recipient_type=RecipientType.GENERAL_WEBHOOK, url=TEST_URL)
  134. send_uptime_as_webhook(
  135. recipient,
  136. self.monitor_check.id,
  137. True,
  138. datetime.now(),
  139. )
  140. mock_post.assert_called_once()
  141. json_data = json.dumps(mock_post.call_args.kwargs["json"])
  142. self.assertIn(f'"text": "{self.expected_subject}"', json_data)
  143. self.assertIn(f'"title": "{self.monitor.name}"', json_data)
  144. self.assertIn(f'"text": "{self.expected_message_down}"', json_data)
  145. mock_post.reset_mock()
  146. send_uptime_as_webhook(
  147. recipient,
  148. self.monitor_check.id,
  149. False,
  150. datetime.now(),
  151. )
  152. mock_post.assert_called_once()
  153. json_data = json.dumps(mock_post.call_args.kwargs["json"])
  154. self.assertIn(f'"text": "{self.expected_subject}"', json_data)
  155. self.assertIn(f'"title": "{self.monitor.name}"', json_data)
  156. self.assertIn(f'"text": "{self.expected_message_up}"', json_data)
  157. @mock.patch("requests.post")
  158. def test_send_uptime_events_google_chat_webhook(self, mock_post):
  159. recipient = baker.make(AlertRecipient, recipient_type=RecipientType.GOOGLE_CHAT, url=GOOGLE_CHAT_TEST_URL)
  160. send_uptime_as_webhook(
  161. recipient,
  162. self.monitor_check.id,
  163. True,
  164. datetime.now(),
  165. )
  166. mock_post.assert_called_once()
  167. json_data = json.dumps(mock_post.call_args.kwargs["json"])
  168. self.assertIn(f'"title": "{self.expected_subject}", "subtitle": "{self.monitor.name}"', json_data)
  169. self.assertIn(f'"text": "{self.expected_message_down}"', json_data)
  170. mock_post.reset_mock()
  171. send_uptime_as_webhook(
  172. recipient,
  173. self.monitor_check.id,
  174. False,
  175. datetime.now(),
  176. )
  177. mock_post.assert_called_once()
  178. json_data = json.dumps(mock_post.call_args.kwargs["json"])
  179. self.assertIn(f'"title": "{self.expected_subject}", "subtitle": "{self.monitor.name}"', json_data)
  180. self.assertIn(f'"text": "{self.expected_message_up}"', json_data)
  181. @mock.patch("requests.post")
  182. def test_send_uptime_events_discord_webhook(self, mock_post):
  183. recipient = baker.make(AlertRecipient, recipient_type=RecipientType.DISCORD, url=DISCORD_TEST_URL)
  184. send_uptime_as_webhook(
  185. recipient,
  186. self.monitor_check.id,
  187. True,
  188. datetime.now(),
  189. )
  190. mock_post.assert_called_once()
  191. json_data = json.dumps(mock_post.call_args.kwargs["json"])
  192. self.assertIn(f'"content": "{self.expected_subject}"', json_data)
  193. self.assertIn(f'"title": "{self.monitor.name}", "description": "{self.expected_message_down}"', json_data)
  194. mock_post.reset_mock()
  195. send_uptime_as_webhook(
  196. recipient,
  197. self.monitor_check.id,
  198. False,
  199. datetime.now(),
  200. )
  201. mock_post.assert_called_once()
  202. json_data = json.dumps(mock_post.call_args.kwargs["json"])
  203. self.assertIn(f'"content": "{self.expected_subject}"', json_data)
  204. self.assertIn(f'"title": "{self.monitor.name}", "description": "{self.expected_message_up}"', json_data)