You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

256 lines
8.5 KiB

  1. from datetime import timedelta as td
  2. from django.test import Client
  3. from django.test.utils import override_settings
  4. from django.utils.timezone import now
  5. from hc.api.models import Check, Flip, Ping
  6. from hc.test import BaseTestCase
  7. class PingTestCase(BaseTestCase):
  8. def setUp(self):
  9. super().setUp()
  10. self.check = Check.objects.create(project=self.project)
  11. self.url = f"/ping/{self.check.code}"
  12. def test_it_works(self):
  13. r = self.client.get(self.url)
  14. self.assertEqual(r.status_code, 200)
  15. self.assertEqual(r.headers["Access-Control-Allow-Origin"], "*")
  16. self.check.refresh_from_db()
  17. self.assertEqual(self.check.status, "up")
  18. expected_aa = self.check.last_ping + td(days=1, hours=1)
  19. self.assertEqual(self.check.alert_after, expected_aa)
  20. ping = Ping.objects.get()
  21. self.assertEqual(ping.scheme, "http")
  22. self.assertEqual(ping.kind, None)
  23. self.assertEqual(ping.created, self.check.last_ping)
  24. self.assertIsNone(ping.exitstatus)
  25. def test_it_changes_status_of_paused_check(self):
  26. self.check.status = "paused"
  27. self.check.save()
  28. r = self.client.get(self.url)
  29. self.assertEqual(r.status_code, 200)
  30. self.check.refresh_from_db()
  31. self.assertEqual(self.check.status, "up")
  32. def test_it_clears_last_start(self):
  33. self.check.last_start = now()
  34. self.check.save()
  35. r = self.client.get(self.url)
  36. self.assertEqual(r.status_code, 200)
  37. self.check.refresh_from_db()
  38. self.assertEqual(self.check.last_start, None)
  39. def test_post_works(self):
  40. csrf_client = Client(enforce_csrf_checks=True)
  41. r = csrf_client.post(self.url, "hello world", content_type="text/plain")
  42. self.assertEqual(r.status_code, 200)
  43. ping = Ping.objects.get()
  44. self.assertEqual(ping.method, "POST")
  45. self.assertEqual(ping.body, "hello world")
  46. def test_head_works(self):
  47. csrf_client = Client(enforce_csrf_checks=True)
  48. r = csrf_client.head(self.url)
  49. self.assertEqual(r.status_code, 200)
  50. self.assertEqual(Ping.objects.count(), 1)
  51. def test_it_handles_bad_uuid(self):
  52. r = self.client.get("/ping/not-uuid/")
  53. self.assertEqual(r.status_code, 404)
  54. def test_it_rejects_alternative_uuid_formats(self):
  55. # This uuid is missing separators. uuid.UUID() would accept it.
  56. r = self.client.get("/ping/07c2f54898504b27af5d6c9dc157ec02/")
  57. self.assertEqual(r.status_code, 404)
  58. def test_it_handles_missing_check(self):
  59. r = self.client.get("/ping/07c2f548-9850-4b27-af5d-6c9dc157ec02/")
  60. self.assertEqual(r.status_code, 404)
  61. self.assertEqual(r.content.decode(), "not found")
  62. def test_it_handles_120_char_ua(self):
  63. ua = (
  64. "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) "
  65. "AppleWebKit/537.36 (KHTML, like Gecko) "
  66. "Chrome/44.0.2403.89 Safari/537.36"
  67. )
  68. r = self.client.get(self.url, HTTP_USER_AGENT=ua)
  69. self.assertEqual(r.status_code, 200)
  70. ping = Ping.objects.get()
  71. self.assertEqual(ping.ua, ua)
  72. def test_it_truncates_long_ua(self):
  73. ua = "01234567890" * 30
  74. r = self.client.get(self.url, HTTP_USER_AGENT=ua)
  75. self.assertEqual(r.status_code, 200)
  76. ping = Ping.objects.get()
  77. self.assertEqual(len(ping.ua), 200)
  78. assert ua.startswith(ping.ua)
  79. def test_it_reads_forwarded_ip(self):
  80. ip = "1.1.1.1"
  81. r = self.client.get(self.url, HTTP_X_FORWARDED_FOR=ip)
  82. ping = Ping.objects.get()
  83. self.assertEqual(r.status_code, 200)
  84. self.assertEqual(ping.remote_addr, "1.1.1.1")
  85. def test_it_reads_first_forwarded_ip(self):
  86. ip = "1.1.1.1, 2.2.2.2"
  87. r = self.client.get(self.url, HTTP_X_FORWARDED_FOR=ip, REMOTE_ADDR="3.3.3.3",)
  88. ping = Ping.objects.get()
  89. self.assertEqual(r.status_code, 200)
  90. self.assertEqual(ping.remote_addr, "1.1.1.1")
  91. def test_it_reads_forwarded_protocol(self):
  92. r = self.client.get(self.url, HTTP_X_FORWARDED_PROTO="https")
  93. ping = Ping.objects.get()
  94. self.assertEqual(r.status_code, 200)
  95. self.assertEqual(ping.scheme, "https")
  96. def test_it_never_caches(self):
  97. r = self.client.get(self.url)
  98. assert "no-cache" in r.get("Cache-Control")
  99. def test_it_updates_confirmation_flag(self):
  100. payload = "Please Confirm ..."
  101. r = self.client.post(self.url, data=payload, content_type="text/plain")
  102. self.assertEqual(r.status_code, 200)
  103. self.check.refresh_from_db()
  104. self.assertTrue(self.check.has_confirmation_link)
  105. def test_fail_endpoint_works(self):
  106. r = self.client.get(self.url + "/fail")
  107. self.assertEqual(r.status_code, 200)
  108. self.check.refresh_from_db()
  109. self.assertEqual(self.check.status, "down")
  110. self.assertEqual(self.check.alert_after, None)
  111. ping = Ping.objects.get()
  112. self.assertEqual(ping.kind, "fail")
  113. flip = Flip.objects.get()
  114. self.assertEqual(flip.owner, self.check)
  115. self.assertEqual(flip.new_status, "down")
  116. def test_start_endpoint_works(self):
  117. last_ping = now() - td(hours=2)
  118. self.check.last_ping = last_ping
  119. self.check.save()
  120. r = self.client.get(self.url + "/start")
  121. self.assertEqual(r.status_code, 200)
  122. self.check.refresh_from_db()
  123. self.assertTrue(self.check.last_start)
  124. self.assertEqual(self.check.last_ping, last_ping)
  125. ping = Ping.objects.get()
  126. self.assertEqual(ping.kind, "start")
  127. def test_start_does_not_change_status_of_paused_check(self):
  128. self.check.status = "paused"
  129. self.check.save()
  130. r = self.client.get(self.url + "/start")
  131. self.assertEqual(r.status_code, 200)
  132. self.check.refresh_from_db()
  133. self.assertTrue(self.check.last_start)
  134. self.assertEqual(self.check.status, "paused")
  135. def test_it_sets_last_duration(self):
  136. self.check.last_start = now() - td(seconds=10)
  137. self.check.save()
  138. r = self.client.get(self.url)
  139. self.assertEqual(r.status_code, 200)
  140. self.check.refresh_from_db()
  141. self.assertTrue(self.check.last_duration.total_seconds() >= 10)
  142. def test_it_requires_post(self):
  143. self.check.methods = "POST"
  144. self.check.save()
  145. r = self.client.get(self.url)
  146. self.assertEqual(r.status_code, 200)
  147. self.check.refresh_from_db()
  148. self.assertEqual(self.check.status, "new")
  149. self.assertIsNone(self.check.last_ping)
  150. ping = Ping.objects.get()
  151. self.assertEqual(ping.scheme, "http")
  152. self.assertEqual(ping.kind, "ign")
  153. @override_settings(PING_BODY_LIMIT=5)
  154. def test_it_chops_long_body(self):
  155. self.client.post(self.url, "hello world", content_type="text/plain")
  156. ping = Ping.objects.get()
  157. self.assertEqual(ping.method, "POST")
  158. self.assertEqual(ping.body, "hello")
  159. @override_settings(PING_BODY_LIMIT=None)
  160. def test_it_allows_unlimited_body(self):
  161. self.client.post(self.url, "A" * 20000, content_type="text/plain")
  162. ping = Ping.objects.get()
  163. self.assertEqual(len(ping.body), 20000)
  164. def test_it_handles_manual_resume_flag(self):
  165. self.check.status = "paused"
  166. self.check.manual_resume = True
  167. self.check.save()
  168. r = self.client.get(self.url)
  169. self.assertEqual(r.status_code, 200)
  170. self.check.refresh_from_db()
  171. self.assertEqual(self.check.status, "paused")
  172. ping = Ping.objects.get()
  173. self.assertEqual(ping.scheme, "http")
  174. self.assertEqual(ping.kind, "ign")
  175. def test_zero_exit_status_works(self):
  176. r = self.client.get(self.url + "/0")
  177. self.assertEqual(r.status_code, 200)
  178. self.check.refresh_from_db()
  179. self.assertEqual(self.check.status, "up")
  180. ping = Ping.objects.get()
  181. self.assertEqual(ping.kind, None)
  182. self.assertEqual(ping.exitstatus, 0)
  183. def test_nonzero_exit_status_works(self):
  184. r = self.client.get(self.url + "/123")
  185. self.assertEqual(r.status_code, 200)
  186. self.check.refresh_from_db()
  187. self.assertEqual(self.check.status, "down")
  188. ping = Ping.objects.get()
  189. self.assertEqual(ping.kind, "fail")
  190. self.assertEqual(ping.exitstatus, 123)
  191. def test_it_rejects_exit_status_over_255(self):
  192. r = self.client.get(self.url + "/256")
  193. self.assertEqual(r.status_code, 400)