mirror of
https://github.com/healthchecks/healthchecks.git
synced 2025-04-08 14:40:05 +00:00
Implement hc.api.views.ping_by_slug
This commit is contained in:
parent
9517035501
commit
688aa5b3c3
5 changed files with 130 additions and 29 deletions
|
@ -11,7 +11,7 @@ class PingTestCase(BaseTestCase):
|
|||
def setUp(self):
|
||||
super().setUp()
|
||||
self.check = Check.objects.create(project=self.project)
|
||||
self.url = "/ping/%s" % self.check.code
|
||||
self.url = f"/ping/{self.check.code}"
|
||||
|
||||
def test_it_works(self):
|
||||
r = self.client.get(self.url)
|
||||
|
@ -23,7 +23,7 @@ class PingTestCase(BaseTestCase):
|
|||
expected_aa = self.check.last_ping + td(days=1, hours=1)
|
||||
self.assertEqual(self.check.alert_after, expected_aa)
|
||||
|
||||
ping = Ping.objects.latest("id")
|
||||
ping = Ping.objects.get()
|
||||
self.assertEqual(ping.scheme, "http")
|
||||
self.assertEqual(ping.kind, None)
|
||||
self.assertEqual(ping.created, self.check.last_ping)
|
||||
|
@ -54,7 +54,7 @@ class PingTestCase(BaseTestCase):
|
|||
r = csrf_client.post(self.url, "hello world", content_type="text/plain")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
ping = Ping.objects.latest("id")
|
||||
ping = Ping.objects.get()
|
||||
self.assertEqual(ping.method, "POST")
|
||||
self.assertEqual(ping.body, "hello world")
|
||||
|
||||
|
@ -87,7 +87,7 @@ class PingTestCase(BaseTestCase):
|
|||
r = self.client.get(self.url, HTTP_USER_AGENT=ua)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
ping = Ping.objects.latest("id")
|
||||
ping = Ping.objects.get()
|
||||
self.assertEqual(ping.ua, ua)
|
||||
|
||||
def test_it_truncates_long_ua(self):
|
||||
|
@ -96,26 +96,27 @@ class PingTestCase(BaseTestCase):
|
|||
r = self.client.get(self.url, HTTP_USER_AGENT=ua)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
ping = Ping.objects.latest("id")
|
||||
ping = Ping.objects.get()
|
||||
self.assertEqual(len(ping.ua), 200)
|
||||
assert ua.startswith(ping.ua)
|
||||
|
||||
def test_it_reads_forwarded_ip(self):
|
||||
ip = "1.1.1.1"
|
||||
r = self.client.get(self.url, HTTP_X_FORWARDED_FOR=ip)
|
||||
ping = Ping.objects.latest("id")
|
||||
ping = Ping.objects.get()
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(ping.remote_addr, "1.1.1.1")
|
||||
|
||||
def test_it_reads_first_forwarded_ip(self):
|
||||
ip = "1.1.1.1, 2.2.2.2"
|
||||
r = self.client.get(self.url, HTTP_X_FORWARDED_FOR=ip, REMOTE_ADDR="3.3.3.3",)
|
||||
ping = Ping.objects.latest("id")
|
||||
ping = Ping.objects.get()
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(ping.remote_addr, "1.1.1.1")
|
||||
|
||||
def test_it_reads_forwarded_protocol(self):
|
||||
r = self.client.get(self.url, HTTP_X_FORWARDED_PROTO="https")
|
||||
ping = Ping.objects.latest("id")
|
||||
ping = Ping.objects.get()
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(ping.scheme, "https")
|
||||
|
||||
|
@ -132,7 +133,7 @@ class PingTestCase(BaseTestCase):
|
|||
self.assertTrue(self.check.has_confirmation_link)
|
||||
|
||||
def test_fail_endpoint_works(self):
|
||||
r = self.client.get("/ping/%s/fail" % self.check.code)
|
||||
r = self.client.get(self.url + "/fail")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
self.check.refresh_from_db()
|
||||
|
@ -151,7 +152,7 @@ class PingTestCase(BaseTestCase):
|
|||
self.check.last_ping = last_ping
|
||||
self.check.save()
|
||||
|
||||
r = self.client.get("/ping/%s/start" % self.check.code)
|
||||
r = self.client.get(self.url + "/start")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
self.check.refresh_from_db()
|
||||
|
@ -165,7 +166,7 @@ class PingTestCase(BaseTestCase):
|
|||
self.check.status = "paused"
|
||||
self.check.save()
|
||||
|
||||
r = self.client.get("/ping/%s/start" % self.check.code)
|
||||
r = self.client.get(self.url + "/start")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
self.check.refresh_from_db()
|
||||
|
@ -193,7 +194,7 @@ class PingTestCase(BaseTestCase):
|
|||
self.assertEqual(self.check.status, "new")
|
||||
self.assertIsNone(self.check.last_ping)
|
||||
|
||||
ping = Ping.objects.latest("id")
|
||||
ping = Ping.objects.get()
|
||||
self.assertEqual(ping.scheme, "http")
|
||||
self.assertEqual(ping.kind, "ign")
|
||||
|
||||
|
@ -201,7 +202,7 @@ class PingTestCase(BaseTestCase):
|
|||
def test_it_chops_long_body(self):
|
||||
self.client.post(self.url, "hello world", content_type="text/plain")
|
||||
|
||||
ping = Ping.objects.latest("id")
|
||||
ping = Ping.objects.get()
|
||||
self.assertEqual(ping.method, "POST")
|
||||
self.assertEqual(ping.body, "hello")
|
||||
|
||||
|
@ -209,7 +210,7 @@ class PingTestCase(BaseTestCase):
|
|||
def test_it_allows_unlimited_body(self):
|
||||
self.client.post(self.url, "A" * 20000, content_type="text/plain")
|
||||
|
||||
ping = Ping.objects.latest("id")
|
||||
ping = Ping.objects.get()
|
||||
self.assertEqual(len(ping.body), 20000)
|
||||
|
||||
def test_it_handles_manual_resume_flag(self):
|
||||
|
@ -223,28 +224,28 @@ class PingTestCase(BaseTestCase):
|
|||
self.check.refresh_from_db()
|
||||
self.assertEqual(self.check.status, "paused")
|
||||
|
||||
ping = Ping.objects.latest("id")
|
||||
ping = Ping.objects.get()
|
||||
self.assertEqual(ping.scheme, "http")
|
||||
self.assertEqual(ping.kind, "ign")
|
||||
|
||||
def test_zero_exit_status_works(self):
|
||||
r = self.client.get("/ping/%s/0" % self.check.code)
|
||||
r = self.client.get(self.url + "/0")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
self.check.refresh_from_db()
|
||||
self.assertEqual(self.check.status, "up")
|
||||
|
||||
ping = Ping.objects.latest("id")
|
||||
ping = Ping.objects.get()
|
||||
self.assertEqual(ping.kind, None)
|
||||
self.assertEqual(ping.exitstatus, 0)
|
||||
|
||||
def test_nonzero_exit_status_works(self):
|
||||
r = self.client.get("/ping/%s/123" % self.check.code)
|
||||
r = self.client.get(self.url + "/123")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
self.check.refresh_from_db()
|
||||
self.assertEqual(self.check.status, "down")
|
||||
|
||||
ping = Ping.objects.latest("id")
|
||||
ping = Ping.objects.get()
|
||||
self.assertEqual(ping.kind, "fail")
|
||||
self.assertEqual(ping.exitstatus, 123)
|
||||
|
|
82
hc/api/tests/test_ping_by_slug.py
Normal file
82
hc/api/tests/test_ping_by_slug.py
Normal file
|
@ -0,0 +1,82 @@
|
|||
from django.test import Client
|
||||
from hc.api.models import Check, Ping
|
||||
from hc.test import BaseTestCase
|
||||
|
||||
|
||||
class PingBySlugTestCase(BaseTestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.check = Check.objects.create(project=self.project, name="foo", slug="foo")
|
||||
self.url = f"/ping/{self.project.ping_key}/foo"
|
||||
|
||||
def test_it_works(self):
|
||||
r = self.client.get(self.url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.headers["Access-Control-Allow-Origin"], "*")
|
||||
|
||||
ping = Ping.objects.get()
|
||||
self.assertEqual(ping.kind, None)
|
||||
|
||||
def test_post_works(self):
|
||||
csrf_client = Client(enforce_csrf_checks=True)
|
||||
r = csrf_client.post(self.url, "hello world", content_type="text/plain")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
ping = Ping.objects.get()
|
||||
self.assertEqual(ping.method, "POST")
|
||||
self.assertEqual(ping.body, "hello world")
|
||||
|
||||
def test_head_works(self):
|
||||
csrf_client = Client(enforce_csrf_checks=True)
|
||||
r = csrf_client.head(self.url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(Ping.objects.count(), 1)
|
||||
|
||||
def test_it_handles_missing_check(self):
|
||||
r = self.client.get(f"/ping/{self.project.ping_key}/bar")
|
||||
self.assertEqual(r.status_code, 404)
|
||||
|
||||
def test_it_never_caches(self):
|
||||
r = self.client.get(self.url)
|
||||
assert "no-cache" in r.get("Cache-Control")
|
||||
|
||||
def test_fail_endpoint_works(self):
|
||||
r = self.client.get(self.url + "/fail")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
ping = Ping.objects.get()
|
||||
self.assertEqual(ping.kind, "fail")
|
||||
|
||||
def test_start_endpoint_works(self):
|
||||
r = self.client.get(self.url + "/start")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
ping = Ping.objects.get()
|
||||
self.assertEqual(ping.kind, "start")
|
||||
|
||||
def test_zero_exit_status_works(self):
|
||||
r = self.client.get(self.url + "/0")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
ping = Ping.objects.get()
|
||||
self.assertEqual(ping.kind, None)
|
||||
self.assertEqual(ping.exitstatus, 0)
|
||||
|
||||
def test_nonzero_exit_status_works(self):
|
||||
r = self.client.get(self.url + "/123")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
ping = Ping.objects.get()
|
||||
self.assertEqual(ping.kind, "fail")
|
||||
self.assertEqual(ping.exitstatus, 123)
|
||||
|
||||
def test_it_handles_duplicates(self):
|
||||
# Another check with the same slug:
|
||||
Check.objects.create(project=self.project, name="foo", slug="foo")
|
||||
|
||||
r = self.client.get(self.url)
|
||||
self.assertEqual(r.status_code, 409)
|
||||
|
||||
def test_it_handles_wrong_ping_key(self):
|
||||
r = self.client.get("/ping/rrrrrrrrrrrrrrrrrrrrrr/foo")
|
||||
self.assertEqual(r.status_code, 404)
|
|
@ -1,6 +1,6 @@
|
|||
from urllib.parse import quote, unquote
|
||||
|
||||
from django.urls import path, register_converter
|
||||
from django.urls import include, path, register_converter
|
||||
from hc.api import views
|
||||
|
||||
|
||||
|
@ -27,13 +27,24 @@ class SHA1Converter:
|
|||
register_converter(QuoteConverter, "quoted")
|
||||
register_converter(SHA1Converter, "sha1")
|
||||
|
||||
uuid_urls = [
|
||||
path("", views.ping, name="hc-ping"),
|
||||
path("fail", views.ping, {"action": "fail"}),
|
||||
path("start", views.ping, {"action": "start"}),
|
||||
path("<int:exitstatus>", views.ping),
|
||||
]
|
||||
|
||||
slug_urls = [
|
||||
path("fail", views.ping_by_slug, {"action": "fail"}),
|
||||
path("start", views.ping_by_slug, {"action": "start"}),
|
||||
path("<int:exitstatus>", views.ping_by_slug),
|
||||
]
|
||||
|
||||
urlpatterns = [
|
||||
path("ping/<uuid:code>/", views.ping, name="hc-ping-slash"),
|
||||
path("ping/<uuid:code>", views.ping, name="hc-ping"),
|
||||
path("ping/<uuid:code>/fail", views.ping, {"action": "fail"}, name="hc-fail"),
|
||||
path("ping/<uuid:code>/start", views.ping, {"action": "start"}, name="hc-start"),
|
||||
path("ping/<uuid:code>/<int:exitstatus>", views.ping),
|
||||
path("ping/<uuid:code>", views.ping),
|
||||
path("ping/<uuid:code>/", include(uuid_urls)),
|
||||
path("ping/<slug:ping_key>/<slug:slug>", views.ping_by_slug),
|
||||
path("ping/<slug:ping_key>/<slug:slug>/", include(slug_urls)),
|
||||
path("api/v1/checks/", views.checks),
|
||||
path("api/v1/checks/<uuid:code>", views.single, name="hc-api-single"),
|
||||
path("api/v1/checks/<sha1:unique_key>", views.get_check_by_unique_key),
|
||||
|
|
|
@ -31,8 +31,9 @@ class BadChannelException(Exception):
|
|||
|
||||
@csrf_exempt
|
||||
@never_cache
|
||||
def ping(request, code, action="success", exitstatus=None):
|
||||
check = get_object_or_404(Check, code=code)
|
||||
def ping(request, code, check=None, action="success", exitstatus=None):
|
||||
if check is None:
|
||||
check = get_object_or_404(Check, code=code)
|
||||
|
||||
headers = request.META
|
||||
remote_addr = headers.get("HTTP_X_FORWARDED_FOR", headers["REMOTE_ADDR"])
|
||||
|
@ -55,9 +56,14 @@ def ping(request, code, action="success", exitstatus=None):
|
|||
return response
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def ping_by_slug(request, ping_key, slug, action="success", exitstatus=None):
|
||||
check = get_object_or_404(Check, slug=slug, project__ping_key=ping_key)
|
||||
return ping(request, check.code, action, exitstatus)
|
||||
try:
|
||||
check = get_object_or_404(Check, slug=slug, project__ping_key=ping_key)
|
||||
except Check.MultipleObjectsReturned:
|
||||
return HttpResponse("ambiguous slug", status=409)
|
||||
|
||||
return ping(request, check.code, check, action, exitstatus)
|
||||
|
||||
|
||||
def _lookup(project, spec):
|
||||
|
|
|
@ -17,6 +17,7 @@ class BaseTestCase(TestCase):
|
|||
self.project = Project(owner=self.alice, api_key="X" * 32)
|
||||
self.project.name = "Alices Project"
|
||||
self.project.badge_key = self.alice.username
|
||||
self.project.ping_key = "p" * 22
|
||||
self.project.save()
|
||||
|
||||
self.profile = Profile(user=self.alice)
|
||||
|
|
Loading…
Add table
Reference in a new issue