test_api.py 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. from unittest import mock
  2. from django.shortcuts import reverse
  3. from django.utils import timezone
  4. from django.utils.dateparse import parse_datetime
  5. from freezegun import freeze_time
  6. from model_bakery import baker
  7. from glitchtip.test_utils.test_case import GlitchTipTestCase
  8. from glitchtip.uptime.models import Monitor
  9. class UptimeAPITestCase(GlitchTipTestCase):
  10. def setUp(self):
  11. self.create_user_and_project()
  12. self.list_url = reverse(
  13. "organization-monitors-list",
  14. kwargs={"organization_slug": self.organization.slug},
  15. )
  16. @mock.patch("glitchtip.uptime.tasks.perform_checks.run")
  17. def test_list(self, mocked):
  18. monitor = baker.make(
  19. "uptime.Monitor", organization=self.organization, url="http://example.com"
  20. )
  21. baker.make(
  22. "uptime.MonitorCheck",
  23. monitor=monitor,
  24. is_up=False,
  25. start_check="2021-09-19T15:39:31Z",
  26. )
  27. baker.make(
  28. "uptime.MonitorCheck",
  29. monitor=monitor,
  30. is_up=True,
  31. is_change=True,
  32. start_check="2021-09-19T15:40:31Z",
  33. )
  34. res = self.client.get(self.list_url)
  35. self.assertContains(res, monitor.name)
  36. self.assertEqual(res.data[0]["isUp"], True)
  37. self.assertEqual(res.data[0]["lastChange"], "2021-09-19T15:40:31Z")
  38. def test_list_aggregation(self):
  39. """Test up and down event aggregations"""
  40. monitor = baker.make(
  41. "uptime.Monitor", organization=self.organization, url="http://example.com"
  42. )
  43. start_time = timezone.now()
  44. # Make 100 events, 50 up and then 50 up and down every minute
  45. for i in range(99):
  46. is_up = i % 2
  47. if i < 50:
  48. is_up = True
  49. current_time = start_time + timezone.timedelta(minutes=i)
  50. with freeze_time(current_time):
  51. baker.make(
  52. "uptime.MonitorCheck",
  53. monitor=monitor,
  54. is_up=is_up,
  55. start_check=current_time,
  56. )
  57. with freeze_time(current_time):
  58. res = self.client.get(self.list_url)
  59. self.assertEqual(len(res.data[0]["checks"]), 60)
  60. @mock.patch("glitchtip.uptime.tasks.perform_checks.run")
  61. def test_create_http_monitor(self, mocked):
  62. data = {
  63. "monitorType": "Ping",
  64. "name": "Test",
  65. "url": "https://www.google.com",
  66. "expectedStatus": 200,
  67. "interval": "00:01:00",
  68. "project": self.project.pk,
  69. "timeout": 25,
  70. }
  71. res = self.client.post(self.list_url, data)
  72. self.assertEqual(res.status_code, 201)
  73. monitor = Monitor.objects.all().first()
  74. self.assertEqual(monitor.name, data["name"])
  75. self.assertEqual(monitor.timeout, data["timeout"])
  76. self.assertEqual(monitor.organization, self.organization)
  77. self.assertEqual(monitor.project, self.project)
  78. mocked.assert_called_once()
  79. @mock.patch("glitchtip.uptime.tasks.perform_checks.run")
  80. def test_create_port_monitor(self, mocked):
  81. """Port monitor URLs should be converted to domain:port format, with protocol removed"""
  82. data = {
  83. "monitorType": "TCP Port",
  84. "name": "Test",
  85. "url": "http://example.com:80",
  86. "expectedStatus": "",
  87. "interval": "00:01:00",
  88. }
  89. res = self.client.post(self.list_url, data)
  90. self.assertEqual(res.status_code, 201)
  91. monitor = Monitor.objects.all().first()
  92. self.assertEqual(monitor.url, "example.com:80")
  93. mocked.assert_called_once()
  94. def test_create_port_monitor_validation(self):
  95. """Port monitor URLs should be converted to domain:port format, with protocol removed"""
  96. data = {
  97. "monitorType": "TCP Port",
  98. "name": "Test",
  99. "url": "example:80:",
  100. "expectedStatus": "",
  101. "interval": "00:01:00",
  102. }
  103. res = self.client.post(self.list_url, data)
  104. self.assertEqual(res.status_code, 400)
  105. def test_create_invalid(self):
  106. data = {
  107. "monitorType": "Ping",
  108. "name": "Test",
  109. "url": "foo:80:",
  110. "expectedStatus": 200,
  111. "interval": "00:01:00",
  112. "project": self.project.pk,
  113. }
  114. res = self.client.post(self.list_url, data)
  115. self.assertEqual(res.status_code, 400)
  116. data = {
  117. "monitorType": "Ping",
  118. "name": "Test",
  119. "url": "https://www.google.com",
  120. "expectedStatus": 200,
  121. "interval": "00:01:00",
  122. "project": self.project.pk,
  123. "timeout": 999,
  124. }
  125. res = self.client.post(self.list_url, data)
  126. self.assertEqual(res.status_code, 400)
  127. def test_create_expected_status(self):
  128. data = {
  129. "monitorType": "Ping",
  130. "name": "Test",
  131. "url": "http://example.com",
  132. "expectedStatus": None,
  133. "interval": "00:01:00",
  134. "project": self.project.pk,
  135. }
  136. res = self.client.post(self.list_url, data, format="json")
  137. self.assertEqual(res.status_code, 201)
  138. self.assertTrue(Monitor.objects.filter(expected_status=None).exists())
  139. @mock.patch("glitchtip.uptime.tasks.perform_checks.run")
  140. def test_monitor_retrieve(self, mocked):
  141. """Test monitor details endpoint. Unlike the list view,
  142. checks here should include response time for the frontend graph"""
  143. environment = baker.make(
  144. "environments.Environment", organization=self.organization
  145. )
  146. monitor = baker.make(
  147. "uptime.Monitor",
  148. organization=self.organization,
  149. url="http://example.com",
  150. environment=environment,
  151. )
  152. now = timezone.now()
  153. baker.make(
  154. "uptime.MonitorCheck",
  155. monitor=monitor,
  156. is_up=False,
  157. is_change=True,
  158. start_check="2021-09-19T15:39:31Z",
  159. )
  160. baker.make(
  161. "uptime.MonitorCheck",
  162. monitor=monitor,
  163. is_up=True,
  164. is_change=True,
  165. start_check=now,
  166. )
  167. url = reverse(
  168. "organization-monitors-detail",
  169. kwargs={"organization_slug": self.organization.slug, "pk": monitor.pk},
  170. )
  171. res = self.client.get(url)
  172. self.assertEqual(res.data["isUp"], True)
  173. self.assertEqual(parse_datetime(res.data["lastChange"]), now)
  174. self.assertEqual(res.data["environment"], environment.pk)
  175. self.assertIn("responseTime", res.data["checks"][0])
  176. def test_monitor_checks_list(self):
  177. monitor = baker.make(
  178. "uptime.Monitor",
  179. organization=self.organization,
  180. url="http://example.com",
  181. )
  182. baker.make(
  183. "uptime.MonitorCheck",
  184. monitor=monitor,
  185. is_up=False,
  186. start_check="2021-09-19T15:39:31Z",
  187. )
  188. url = reverse(
  189. "organization-monitor-checks-list",
  190. kwargs={
  191. "organization_slug": self.organization.slug,
  192. "monitor_pk": monitor.pk,
  193. },
  194. )
  195. res = self.client.get(url)
  196. self.assertContains(res, "2021-09-19T15:39:31Z")
  197. def test_monitor_update(self):
  198. monitor = baker.make(
  199. "uptime.Monitor",
  200. organization=self.organization,
  201. url="http://example.com",
  202. interval="60",
  203. monitor_type="Ping",
  204. expected_status="200",
  205. )
  206. url = reverse(
  207. "organization-monitors-detail",
  208. kwargs={"organization_slug": self.organization.slug, "pk": monitor.pk},
  209. )
  210. data = {
  211. "name": "New name",
  212. "url": "https://differentexample.com",
  213. "monitorType": "GET",
  214. "expectedStatus": "200",
  215. "interval": "60",
  216. }
  217. res = self.client.put(url, data, format="json")
  218. self.assertEqual(res.data["monitorType"], "GET")
  219. self.assertEqual(res.data["url"], "https://differentexample.com")
  220. @mock.patch("glitchtip.uptime.tasks.perform_checks.run")
  221. def test_list_isolation(self, _):
  222. """Users should only access monitors in their organization"""
  223. user2 = baker.make("users.user")
  224. org2 = baker.make("organizations_ext.Organization")
  225. org2.add_user(user2)
  226. monitor1 = baker.make(
  227. "uptime.Monitor", url="http://example.com", organization=self.organization
  228. )
  229. monitor2 = baker.make(
  230. "uptime.Monitor", url="http://example.com", organization=org2
  231. )
  232. res = self.client.get(self.list_url)
  233. self.assertContains(res, monitor1.name)
  234. self.assertNotContains(res, monitor2.name)
  235. def test_create_isolation(self):
  236. """Users should only make monitors in their organization"""
  237. org2 = baker.make("organizations_ext.Organization")
  238. url = reverse(
  239. "organization-monitors-list",
  240. kwargs={"organization_slug": org2.slug},
  241. )
  242. data = {
  243. "monitorType": "Ping",
  244. "name": "Test",
  245. "url": "https://www.google.com",
  246. "expectedStatus": 200,
  247. "interval": "00:01:00",
  248. "project": self.project.pk,
  249. }
  250. res = self.client.post(url, data)
  251. self.assertEqual(res.status_code, 400)