Browse Source

Implement hc.api.views.ping_by_slug

pull/563/head
Pēteris Caune 3 years ago
parent
commit
688aa5b3c3
No known key found for this signature in database GPG Key ID: E28D7679E9A9EDE2
5 changed files with 130 additions and 29 deletions
  1. +20
    -19
      hc/api/tests/test_ping.py
  2. +82
    -0
      hc/api/tests/test_ping_by_slug.py
  3. +17
    -6
      hc/api/urls.py
  4. +10
    -4
      hc/api/views.py
  5. +1
    -0
      hc/test.py

+ 20
- 19
hc/api/tests/test_ping.py View File

@ -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
- 0
hc/api/tests/test_ping_by_slug.py View 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)

+ 17
- 6
hc/api/urls.py View File

@ -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),


+ 10
- 4
hc/api/views.py View File

@ -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):


+ 1
- 0
hc/test.py View File

@ -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…
Cancel
Save