tests.py 8.3 KB

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