tests.py 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. import asyncio
  2. from unittest import mock
  3. from aioresponses import aioresponses
  4. from django.core import mail
  5. from django.urls import reverse
  6. from freezegun import freeze_time
  7. from model_bakery import baker
  8. from glitchtip.test_utils.test_case import GlitchTipTestCase
  9. from organizations_ext.models import OrganizationUserRole
  10. from projects.models import ProjectAlertStatus
  11. from ..constants import MonitorType
  12. from ..models import Monitor, MonitorCheck
  13. from ..tasks import dispatch_checks
  14. from ..utils import fetch_all
  15. class UptimeTestCase(GlitchTipTestCase):
  16. @mock.patch("glitchtip.uptime.tasks.perform_checks.run")
  17. def test_dispatch_checks(self, mocked):
  18. mock.return_value = None
  19. test_url = "https://example.com"
  20. with freeze_time("2020-01-01"):
  21. mon1 = baker.make(Monitor, url=test_url, monitor_type=MonitorType.GET)
  22. mon2 = baker.make(Monitor, url=test_url, monitor_type=MonitorType.GET)
  23. baker.make(MonitorCheck, monitor=mon1)
  24. self.assertEqual(mocked.call_count, 2)
  25. with freeze_time("2020-01-02"):
  26. baker.make(MonitorCheck, monitor=mon2)
  27. dispatch_checks()
  28. self.assertEqual(mocked.call_count, 3)
  29. @aioresponses()
  30. def test_fetch_all(self, mocked):
  31. test_url = "https://example.com"
  32. mocked.get(test_url, status=200)
  33. mon1 = baker.make(Monitor, url=test_url, monitor_type=MonitorType.GET)
  34. mocked.get(test_url, status=200)
  35. monitors = list(Monitor.objects.all().values())
  36. results = asyncio.run(fetch_all(monitors))
  37. self.assertEqual(results[0]["id"], mon1.pk)
  38. @aioresponses()
  39. def test_monitor_checks_integration(self, mocked):
  40. test_url = "https://example.com"
  41. mocked.get(test_url, status=200)
  42. with freeze_time("2020-01-01"):
  43. mon = baker.make(Monitor, url=test_url, monitor_type=MonitorType.GET)
  44. self.assertEqual(mon.checks.count(), 1)
  45. mocked.get(test_url, status=200)
  46. with freeze_time("2020-01-01"):
  47. dispatch_checks()
  48. self.assertEqual(mon.checks.count(), 1)
  49. with freeze_time("2020-01-02"):
  50. with self.assertNumQueries(5):
  51. dispatch_checks()
  52. self.assertEqual(mon.checks.count(), 2)
  53. @aioresponses()
  54. @mock.patch("requests.post")
  55. def test_monitor_notifications(self, mocked, mock_post):
  56. self.create_user_and_project()
  57. test_url = "https://example.com"
  58. mocked.get(test_url, status=200)
  59. with freeze_time("2020-01-01"):
  60. baker.make(
  61. Monitor,
  62. name=test_url,
  63. url=test_url,
  64. monitor_type=MonitorType.GET,
  65. project=self.project,
  66. )
  67. baker.make(
  68. "alerts.AlertRecipient",
  69. alert__uptime=True,
  70. alert__project=self.project,
  71. recipient_type="email",
  72. )
  73. baker.make(
  74. "alerts.AlertRecipient",
  75. alert__uptime=True,
  76. alert__project=self.project,
  77. recipient_type="webhook",
  78. url="https://example.com",
  79. )
  80. mocked.get(test_url, status=500)
  81. with freeze_time("2020-01-02"):
  82. dispatch_checks()
  83. self.assertEqual(len(mail.outbox), 1)
  84. self.assertIn("is down", mail.outbox[0].body)
  85. mock_post.assert_called_once()
  86. mocked.get(test_url, status=500)
  87. with freeze_time("2020-01-03"):
  88. dispatch_checks()
  89. self.assertEqual(len(mail.outbox), 1)
  90. mocked.get(test_url, status=200)
  91. with freeze_time("2020-01-04"):
  92. dispatch_checks()
  93. self.assertEqual(len(mail.outbox), 2)
  94. self.assertIn("is back up", mail.outbox[1].body)
  95. @aioresponses()
  96. def test_notification_default_scope(self, mocked):
  97. """Subscribe by default should not result in alert emails for non-team members"""
  98. self.create_user_and_project()
  99. test_url = "https://example.com"
  100. # user2 is an org member but not in a relevant team, should not receive alerts
  101. user2 = baker.make("users.user")
  102. org_user2 = self.organization.add_user(user2, OrganizationUserRole.MEMBER)
  103. team2 = baker.make("teams.Team", organization=self.organization)
  104. team2.members.add(org_user2)
  105. # user3 is in team3 which should receive alerts
  106. user3 = baker.make("users.user")
  107. org_user3 = self.organization.add_user(user3, OrganizationUserRole.MEMBER)
  108. self.team.members.add(org_user3)
  109. team3 = baker.make("teams.Team", organization=self.organization)
  110. team3.members.add(org_user3)
  111. team3.projects.add(self.project)
  112. baker.make(
  113. "alerts.AlertRecipient",
  114. alert__uptime=True,
  115. alert__project=self.project,
  116. recipient_type="email",
  117. )
  118. mocked.get(test_url, status=200)
  119. with freeze_time("2020-01-01"):
  120. baker.make(
  121. Monitor,
  122. name=test_url,
  123. url=test_url,
  124. monitor_type=MonitorType.GET,
  125. project=self.project,
  126. )
  127. mocked.get(test_url, status=500)
  128. with self.assertNumQueries(12):
  129. with freeze_time("2020-01-02"):
  130. dispatch_checks()
  131. self.assertNotIn(user2.email, mail.outbox[0].to)
  132. self.assertIn(user3.email, mail.outbox[0].to)
  133. self.assertEqual(len(mail.outbox[0].to), 2)
  134. @aioresponses()
  135. def test_user_project_alert_scope(self, mocked):
  136. """User project alert should not result in alert emails for non-team members"""
  137. self.create_user_and_project()
  138. test_url = "https://example.com"
  139. baker.make(
  140. "alerts.AlertRecipient",
  141. alert__uptime=True,
  142. alert__project=self.project,
  143. recipient_type="email",
  144. )
  145. user2 = baker.make("users.user")
  146. self.organization.add_user(user2, OrganizationUserRole.MEMBER)
  147. baker.make(
  148. "projects.UserProjectAlert",
  149. user=user2,
  150. project=self.project,
  151. status=ProjectAlertStatus.ON,
  152. )
  153. mocked.get(test_url, status=200)
  154. with freeze_time("2020-01-01"):
  155. baker.make(
  156. Monitor,
  157. name=test_url,
  158. url=test_url,
  159. monitor_type=MonitorType.GET,
  160. project=self.project,
  161. )
  162. mocked.get(test_url, status=500)
  163. with self.assertNumQueries(12):
  164. with freeze_time("2020-01-02"):
  165. dispatch_checks()
  166. self.assertNotIn(user2.email, mail.outbox[0].to)
  167. def test_heartbeat(self):
  168. self.create_user_and_project()
  169. with freeze_time("2020-01-01"):
  170. monitor = baker.make(
  171. Monitor,
  172. monitor_type=MonitorType.HEARTBEAT,
  173. project=self.project,
  174. )
  175. baker.make(
  176. "alerts.AlertRecipient",
  177. alert__uptime=True,
  178. alert__project=self.project,
  179. recipient_type="email",
  180. )
  181. url = reverse(
  182. "heartbeat-check",
  183. kwargs={
  184. "organization_slug": monitor.organization.slug,
  185. "endpoint_id": monitor.endpoint_id,
  186. },
  187. )
  188. self.assertFalse(monitor.checks.exists())
  189. self.client.post(url)
  190. self.assertTrue(monitor.checks.filter(is_up=True).exists())
  191. dispatch_checks()
  192. self.assertTrue(monitor.checks.filter(is_up=True).exists())
  193. self.assertEqual(len(mail.outbox), 0)
  194. with freeze_time("2020-01-02"):
  195. dispatch_checks()
  196. self.assertEqual(len(mail.outbox), 1)
  197. with freeze_time("2020-01-03"):
  198. dispatch_checks() # Still down
  199. self.assertEqual(len(mail.outbox), 1)
  200. with freeze_time("2020-01-04"):
  201. self.client.post(url) # Back up
  202. self.assertEqual(len(mail.outbox), 2)
  203. def test_heartbeat_grace_period(self):
  204. # Don't alert users when heartbeat check has never come in
  205. self.create_user_and_project()
  206. baker.make(Monitor, monitor_type=MonitorType.HEARTBEAT, project=self.project)
  207. dispatch_checks()
  208. self.assertEqual(len(mail.outbox), 0)