Skip to content

Commit

Permalink
Move subdomains to query paths.
Browse files Browse the repository at this point in the history
In more detail:

- Use Django URL namespaces (e.g. `api:bot:infractions`) instead of
  `django_hosts` host argument.
- Update the hosts file setup documentation to remove subdomain entries.
- Update the hosts file setup documentation to mention that the entry of
  `pythondiscord.local` is not required and mainly for convenience.
- Rename the `APISubdomainTestCase` to the more fitting
  `AuthenticatedAPITestCase`, as authentication is all that is left that the
  class is doing.
- Drop dependency to `django_hosts`.
  • Loading branch information
jchristgit committed Jun 7, 2021
1 parent 512bd17 commit c998d47
Show file tree
Hide file tree
Showing 32 changed files with 311 additions and 367 deletions.
14 changes: 1 addition & 13 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pydis_site/apps/admin/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from django.urls import path


app_name = 'admin'
urlpatterns = (
path('', admin.site.urls),
)
4 changes: 2 additions & 2 deletions pydis_site/apps/api/models/bot/message_deletion_context.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from django.db import models
from django_hosts.resolvers import reverse
from django.urls import reverse

from pydis_site.apps.api.models.bot.user import User
from pydis_site.apps.api.models.mixins import ModelReprMixin
Expand Down Expand Up @@ -33,7 +33,7 @@ class MessageDeletionContext(ModelReprMixin, models.Model):
@property
def log_url(self) -> str:
"""Create the url for the deleted message logs."""
return reverse('logs', host="staff", args=(self.id,))
return reverse('staff:logs', args=(self.id,))

class Meta:
"""Set the ordering for list views to newest first."""
Expand Down
27 changes: 11 additions & 16 deletions pydis_site/apps/api/tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
)


class APISubdomainTestCase(APITestCase):
class AuthenticatedAPITestCase(APITestCase):
"""
Configures the test client.
Expand All @@ -24,14 +24,13 @@ class APISubdomainTestCase(APITestCase):
`self.client.force_authenticate(user=created_user)` to force authentication
through the created user.
Using this performs the following niceties for you which ease writing tests:
- setting the `HTTP_HOST` request header to `api.pythondiscord.local:8000`, and
Using this performs the following nicety for you which eases writing tests:
- forcing authentication for the test user.
If you don't want to force authentication (for example, to test a route's response
for an unauthenticated user), un-force authentication by using the following:
>>> from pydis_site.apps.api.tests.base import APISubdomainTestCase
>>> class UnauthedUserTestCase(APISubdomainTestCase):
>>> from pydis_site.apps.api.tests.base import AuthenticatedAPITestCase
>>> class UnauthedUserTestCase(AuthenticatedAPITestCase):
... def setUp(self):
... super().setUp()
... self.client.force_authentication(user=None)
Expand All @@ -42,30 +41,26 @@ class APISubdomainTestCase(APITestCase):
... resp = self.client.delete('/my-publicly-readable-endpoint/42')
... self.assertEqual(resp.status_code, 401)
Make sure to include the `super().setUp(self)` call, otherwise, you may get
status code 404 for some URLs due to the missing `HTTP_HOST` header.
## Example
Using this in a test case is rather straightforward:
>>> from pydis_site.apps.api.tests.base import APISubdomainTestCase
>>> class MyAPITestCase(APISubdomainTestCase):
>>> from pydis_site.apps.api.tests.base import AuthenticatedAPITestCase
>>> class MyAPITestCase(AuthenticatedAPITestCase):
... def test_that_it_works(self):
... response = self.client.get('/my-endpoint')
... self.assertEqual(response.status_code, 200)
To reverse URLs of the API host, you need to use `django_hosts`:
To reverse URLs of the API host, you need to use `django.urls`:
>>> from django_hosts.resolvers import reverse
>>> from pydis_site.apps.api.tests.base import APISubdomainTestCase
>>> class MyReversedTestCase(APISubdomainTestCase):
>>> from django.urls import reverse
>>> from pydis_site.apps.api.tests.base import AuthenticatedAPITestCase
>>> class MyReversedTestCase(AuthenticatedAPITestCase):
... def test_my_endpoint(self):
... url = reverse('user-detail', host='api')
... url = reverse('api:user-detail')
... response = self.client.get(url)
... self.assertEqual(response.status_code, 200)
"""

def setUp(self):
super().setUp()
self.client.defaults['HTTP_HOST'] = 'api.pythondiscord.local:8000'
self.client.force_authenticate(test_user)
16 changes: 8 additions & 8 deletions pydis_site/apps/api/tests/test_deleted_messages.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from datetime import datetime

from django.urls import reverse
from django.utils import timezone
from django_hosts.resolvers import reverse

from .base import APISubdomainTestCase
from .base import AuthenticatedAPITestCase
from ..models import MessageDeletionContext, User


class DeletedMessagesWithoutActorTests(APISubdomainTestCase):
class DeletedMessagesWithoutActorTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.author = User.objects.create(
Expand Down Expand Up @@ -40,14 +40,14 @@ def setUpTestData(cls):
}

def test_accepts_valid_data(self):
url = reverse('bot:messagedeletioncontext-list', host='api')
url = reverse('api:bot:messagedeletioncontext-list')
response = self.client.post(url, data=self.data)
self.assertEqual(response.status_code, 201)
[context] = MessageDeletionContext.objects.all()
self.assertIsNone(context.actor)


class DeletedMessagesWithActorTests(APISubdomainTestCase):
class DeletedMessagesWithActorTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.author = cls.actor = User.objects.create(
Expand All @@ -72,14 +72,14 @@ def setUpTestData(cls):
}

def test_accepts_valid_data_and_sets_actor(self):
url = reverse('bot:messagedeletioncontext-list', host='api')
url = reverse('api:bot:messagedeletioncontext-list')
response = self.client.post(url, data=self.data)
self.assertEqual(response.status_code, 201)
[context] = MessageDeletionContext.objects.all()
self.assertEqual(context.actor.id, self.actor.id)


class DeletedMessagesLogURLTests(APISubdomainTestCase):
class DeletedMessagesLogURLTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.author = cls.actor = User.objects.create(
Expand All @@ -94,6 +94,6 @@ def setUpTestData(cls):
)

def test_valid_log_url(self):
expected_url = reverse('logs', host="staff", args=(1,))
expected_url = reverse('staff:logs', args=(1,))
[context] = MessageDeletionContext.objects.all()
self.assertEqual(context.log_url, expected_url)
50 changes: 25 additions & 25 deletions pydis_site/apps/api/tests/test_documentation_links.py
Original file line number Diff line number Diff line change
@@ -1,61 +1,61 @@
from django_hosts.resolvers import reverse
from django.urls import reverse

from .base import APISubdomainTestCase
from .base import AuthenticatedAPITestCase
from ..models import DocumentationLink


class UnauthedDocumentationLinkAPITests(APISubdomainTestCase):
class UnauthedDocumentationLinkAPITests(AuthenticatedAPITestCase):
def setUp(self):
super().setUp()
self.client.force_authenticate(user=None)

def test_detail_lookup_returns_401(self):
url = reverse('bot:documentationlink-detail', args=('whatever',), host='api')
url = reverse('api:bot:documentationlink-detail', args=('whatever',))
response = self.client.get(url)

self.assertEqual(response.status_code, 401)

def test_list_returns_401(self):
url = reverse('bot:documentationlink-list', host='api')
url = reverse('api:bot:documentationlink-list')
response = self.client.get(url)

self.assertEqual(response.status_code, 401)

def test_create_returns_401(self):
url = reverse('bot:documentationlink-list', host='api')
url = reverse('api:bot:documentationlink-list')
response = self.client.post(url, data={'hi': 'there'})

self.assertEqual(response.status_code, 401)

def test_delete_returns_401(self):
url = reverse('bot:documentationlink-detail', args=('whatever',), host='api')
url = reverse('api:bot:documentationlink-detail', args=('whatever',))
response = self.client.delete(url)

self.assertEqual(response.status_code, 401)


class EmptyDatabaseDocumentationLinkAPITests(APISubdomainTestCase):
class EmptyDatabaseDocumentationLinkAPITests(AuthenticatedAPITestCase):
def test_detail_lookup_returns_404(self):
url = reverse('bot:documentationlink-detail', args=('whatever',), host='api')
url = reverse('api:bot:documentationlink-detail', args=('whatever',))
response = self.client.get(url)

self.assertEqual(response.status_code, 404)

def test_list_all_returns_empty_list(self):
url = reverse('bot:documentationlink-list', host='api')
url = reverse('api:bot:documentationlink-list')
response = self.client.get(url)

self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), [])

def test_delete_returns_404(self):
url = reverse('bot:documentationlink-detail', args=('whatever',), host='api')
url = reverse('api:bot:documentationlink-detail', args=('whatever',))
response = self.client.delete(url)

self.assertEqual(response.status_code, 404)


class DetailLookupDocumentationLinkAPITests(APISubdomainTestCase):
class DetailLookupDocumentationLinkAPITests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.doc_link = DocumentationLink.objects.create(
Expand All @@ -71,27 +71,27 @@ def setUpTestData(cls):
}

def test_detail_lookup_unknown_package_returns_404(self):
url = reverse('bot:documentationlink-detail', args=('whatever',), host='api')
url = reverse('api:bot:documentationlink-detail', args=('whatever',))
response = self.client.get(url)

self.assertEqual(response.status_code, 404)

def test_detail_lookup_created_package_returns_package(self):
url = reverse('bot:documentationlink-detail', args=(self.doc_link.package,), host='api')
url = reverse('api:bot:documentationlink-detail', args=(self.doc_link.package,))
response = self.client.get(url)

self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), self.doc_json)

def test_list_all_packages_shows_created_package(self):
url = reverse('bot:documentationlink-list', host='api')
url = reverse('api:bot:documentationlink-list')
response = self.client.get(url)

self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), [self.doc_json])

def test_create_invalid_body_returns_400(self):
url = reverse('bot:documentationlink-list', host='api')
url = reverse('api:bot:documentationlink-list')
response = self.client.post(url, data={'i': 'am', 'totally': 'valid'})

self.assertEqual(response.status_code, 400)
Expand All @@ -103,7 +103,7 @@ def test_create_invalid_url_returns_400(self):
'inventory_url': 'totally an url'
}

url = reverse('bot:documentationlink-list', host='api')
url = reverse('api:bot:documentationlink-list')
response = self.client.post(url, data=body)

self.assertEqual(response.status_code, 400)
Expand All @@ -114,13 +114,13 @@ def test_create_invalid_package_name_returns_400(self):
with self.subTest(package_name=case):
body = self.doc_json.copy()
body['package'] = case
url = reverse('bot:documentationlink-list', host='api')
url = reverse('api:bot:documentationlink-list')
response = self.client.post(url, data=body)

self.assertEqual(response.status_code, 400)


class DocumentationLinkCreationTests(APISubdomainTestCase):
class DocumentationLinkCreationTests(AuthenticatedAPITestCase):
def setUp(self):
super().setUp()

Expand All @@ -130,27 +130,27 @@ def setUp(self):
'inventory_url': 'https://docs.example.com'
}

url = reverse('bot:documentationlink-list', host='api')
url = reverse('api:bot:documentationlink-list')
response = self.client.post(url, data=self.body)

self.assertEqual(response.status_code, 201)

def test_package_in_full_list(self):
url = reverse('bot:documentationlink-list', host='api')
url = reverse('api:bot:documentationlink-list')
response = self.client.get(url)

self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), [self.body])

def test_detail_lookup_works_with_package(self):
url = reverse('bot:documentationlink-detail', args=(self.body['package'],), host='api')
url = reverse('api:bot:documentationlink-detail', args=(self.body['package'],))
response = self.client.get(url)

self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), self.body)


class DocumentationLinkDeletionTests(APISubdomainTestCase):
class DocumentationLinkDeletionTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.doc_link = DocumentationLink.objects.create(
Expand All @@ -160,13 +160,13 @@ def setUpTestData(cls):
)

def test_unknown_package_returns_404(self):
url = reverse('bot:documentationlink-detail', args=('whatever',), host='api')
url = reverse('api:bot:documentationlink-detail', args=('whatever',))
response = self.client.delete(url)

self.assertEqual(response.status_code, 404)

def test_delete_known_package_returns_204(self):
url = reverse('bot:documentationlink-detail', args=(self.doc_link.package,), host='api')
url = reverse('api:bot:documentationlink-detail', args=(self.doc_link.package,))
response = self.client.delete(url)

self.assertEqual(response.status_code, 204)
Loading

0 comments on commit c998d47

Please sign in to comment.