mirror of
https://github.com/Steffo99/sophon.git
synced 2024-12-22 14:54:22 +00:00
🧪 Improve tests significantly
This commit is contained in:
parent
72d8146765
commit
667bfe9e16
1 changed files with 334 additions and 223 deletions
|
@ -2,11 +2,14 @@ import abc
|
||||||
import contextlib
|
import contextlib
|
||||||
import typing as t
|
import typing as t
|
||||||
|
|
||||||
|
import django.urls.exceptions
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.test import APITestCase
|
from rest_framework.test import APITestCase
|
||||||
|
from rest_framework.utils.serializer_helpers import ReturnDict
|
||||||
|
|
||||||
|
from . import errors
|
||||||
from . import models
|
from . import models
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,16 +19,29 @@ class BetterAPITestCase(APITestCase):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def as_user(self, username: str, password: str) -> t.ContextManager[None]:
|
def as_user(self, username: str, password: str = None) -> t.ContextManager[None]:
|
||||||
"""
|
"""
|
||||||
**Context manager** which runs tests as a specific user.
|
**Context manager** which runs tests as a specific user.
|
||||||
|
|
||||||
:param username: The username of the user to login as.
|
:param username: The username of the user to login as.
|
||||||
:param password: The password of the user to login as.
|
:param password: The password of the user to login as. If not specified, the username is used as password.
|
||||||
"""
|
"""
|
||||||
yield self.client.login(username, password)
|
yield self.client.login(username=username, password=password or username)
|
||||||
self.client.logout()
|
self.client.logout()
|
||||||
|
|
||||||
|
def assertData(self, data: ReturnDict, expected: dict):
|
||||||
|
"""
|
||||||
|
Assert that the returned data includes the key-value pairs of the second.
|
||||||
|
|
||||||
|
:param data: The "larger" dictionary.
|
||||||
|
:param expected: The "smaller" dictionary.
|
||||||
|
|
||||||
|
.. seealso:: https://stackoverflow.com/a/59777678/4334568, https://www.python.org/dev/peps/pep-0584/
|
||||||
|
"""
|
||||||
|
# Convert the ReturnDict to a regular dict, otherwise DRF will include some garbage
|
||||||
|
data = dict(data)
|
||||||
|
self.assertEqual(data, data | expected)
|
||||||
|
|
||||||
|
|
||||||
class ReadSophonTestCase(BetterAPITestCase, metaclass=abc.ABCMeta):
|
class ReadSophonTestCase(BetterAPITestCase, metaclass=abc.ABCMeta):
|
||||||
"""
|
"""
|
||||||
|
@ -51,7 +67,10 @@ class ReadSophonTestCase(BetterAPITestCase, metaclass=abc.ABCMeta):
|
||||||
:return: The URL corresponding to the action with all parameters filled in.
|
:return: The URL corresponding to the action with all parameters filled in.
|
||||||
"""
|
"""
|
||||||
basename = cls.get_basename()
|
basename = cls.get_basename()
|
||||||
|
try:
|
||||||
return reverse(f"{basename}-{action}", args=args, kwargs=kwargs)
|
return reverse(f"{basename}-{action}", args=args, kwargs=kwargs)
|
||||||
|
except django.urls.exceptions.NoReverseMatch:
|
||||||
|
raise errors.HTTPException(404)
|
||||||
|
|
||||||
def list(self) -> Response:
|
def list(self) -> Response:
|
||||||
"""
|
"""
|
||||||
|
@ -63,15 +82,20 @@ class ReadSophonTestCase(BetterAPITestCase, metaclass=abc.ABCMeta):
|
||||||
return self.client.get(url, {}, format="json")
|
return self.client.get(url, {}, format="json")
|
||||||
|
|
||||||
# I hate how unittest doesn't follow PEP8 when naming methods
|
# I hate how unittest doesn't follow PEP8 when naming methods
|
||||||
def assertActionList(self, code: int = 200) -> t.Any:
|
def assertActionList(self, code: int = 200) -> t.Optional[ReturnDict]:
|
||||||
"""
|
"""
|
||||||
Perform the ``list`` action, and assert that it will return a specific status code.
|
Perform the ``list`` action, and assert that it will return a specific status code.
|
||||||
|
|
||||||
:param code: The expected status code.
|
:param code: The expected status code.
|
||||||
:return: The data the server responded with, or :data:`None` if the data evaluates to :data:`False`.
|
:return: The data the server responded with, or :data:`None` if the data evaluates to :data:`False`.
|
||||||
"""
|
"""
|
||||||
|
try:
|
||||||
response = self.list()
|
response = self.list()
|
||||||
self.assertEqual(response.status_code, code, msg=f"`list` did not return {code}")
|
except errors.HTTPException as exc:
|
||||||
|
self.assertEqual(exc.status, code, msg=f"`list` did not return {code}: {exc!r}")
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
self.assertEqual(response.status_code, code, msg=f"`list` did not return {code}: {response.data!r}")
|
||||||
return response.data or None
|
return response.data or None
|
||||||
|
|
||||||
def retrieve(self, pk) -> Response:
|
def retrieve(self, pk) -> Response:
|
||||||
|
@ -84,7 +108,7 @@ class ReadSophonTestCase(BetterAPITestCase, metaclass=abc.ABCMeta):
|
||||||
url = self.get_url("detail", pk=pk)
|
url = self.get_url("detail", pk=pk)
|
||||||
return self.client.get(url, {}, format="json")
|
return self.client.get(url, {}, format="json")
|
||||||
|
|
||||||
def assertActionRetrieve(self, pk, code: int = 200) -> t.Any:
|
def assertActionRetrieve(self, pk, code: int = 200) -> t.Optional[ReturnDict]:
|
||||||
"""
|
"""
|
||||||
Perform the ``retrieve`` action, and assert that it will return a specific status code.
|
Perform the ``retrieve`` action, and assert that it will return a specific status code.
|
||||||
|
|
||||||
|
@ -92,8 +116,13 @@ class ReadSophonTestCase(BetterAPITestCase, metaclass=abc.ABCMeta):
|
||||||
:param code: The expected status code.
|
:param code: The expected status code.
|
||||||
:return: The data the server responded with, or :data:`None` if the data evaluates to :data:`False`.
|
:return: The data the server responded with, or :data:`None` if the data evaluates to :data:`False`.
|
||||||
"""
|
"""
|
||||||
|
try:
|
||||||
response = self.retrieve(pk=pk)
|
response = self.retrieve(pk=pk)
|
||||||
self.assertEqual(response.status_code, code, msg=f"`retrieve` did not return {code}")
|
except errors.HTTPException as exc:
|
||||||
|
self.assertEqual(exc.status, code, msg=f"`retrieve` did not return {code}: {exc!r}")
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
self.assertEqual(response.status_code, code, msg=f"`retrieve` did not return {code}: {response.data!r}")
|
||||||
return response.data
|
return response.data
|
||||||
|
|
||||||
|
|
||||||
|
@ -112,7 +141,7 @@ class WriteSophonTestCase(ReadSophonTestCase, metaclass=abc.ABCMeta):
|
||||||
url = self.get_url("list")
|
url = self.get_url("list")
|
||||||
return self.client.post(url, data, format="json")
|
return self.client.post(url, data, format="json")
|
||||||
|
|
||||||
def assertActionCreate(self, data, code: int = 201) -> t.Any:
|
def assertActionCreate(self, data, code: int = 201) -> t.Optional[ReturnDict]:
|
||||||
"""
|
"""
|
||||||
Perform the ``create`` action, and assert that it will return a specific status code.
|
Perform the ``create`` action, and assert that it will return a specific status code.
|
||||||
|
|
||||||
|
@ -120,8 +149,13 @@ class WriteSophonTestCase(ReadSophonTestCase, metaclass=abc.ABCMeta):
|
||||||
:param code: The expected status code.
|
:param code: The expected status code.
|
||||||
:return: The data the server responded with, or :data:`None` if the data evaluates to :data:`False`.
|
:return: The data the server responded with, or :data:`None` if the data evaluates to :data:`False`.
|
||||||
"""
|
"""
|
||||||
|
try:
|
||||||
response = self.create(data=data)
|
response = self.create(data=data)
|
||||||
self.assertEqual(response.status_code, code, msg=f"`create` did not return {code}")
|
except errors.HTTPException as exc:
|
||||||
|
self.assertEqual(exc.status, code, msg=f"`create` did not return {code}: {exc!r}")
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
self.assertEqual(response.status_code, code, msg=f"`create` did not return {code}: {response.data!r}")
|
||||||
return response.data
|
return response.data
|
||||||
|
|
||||||
def update(self, pk, data) -> Response:
|
def update(self, pk, data) -> Response:
|
||||||
|
@ -135,7 +169,7 @@ class WriteSophonTestCase(ReadSophonTestCase, metaclass=abc.ABCMeta):
|
||||||
url = self.get_url("detail", pk=pk)
|
url = self.get_url("detail", pk=pk)
|
||||||
return self.client.put(url, data, format="json")
|
return self.client.put(url, data, format="json")
|
||||||
|
|
||||||
def assertActionUpdate(self, pk, data, code: int = 200) -> t.Any:
|
def assertActionUpdate(self, pk, data, code: int = 200) -> t.Optional[ReturnDict]:
|
||||||
"""
|
"""
|
||||||
Perform the ``update`` action, and assert that it will return a specific status code.
|
Perform the ``update`` action, and assert that it will return a specific status code.
|
||||||
|
|
||||||
|
@ -144,8 +178,13 @@ class WriteSophonTestCase(ReadSophonTestCase, metaclass=abc.ABCMeta):
|
||||||
:param code: The expected status code.
|
:param code: The expected status code.
|
||||||
:return: The data the server responded with, or :data:`None` if the data evaluates to :data:`False`.
|
:return: The data the server responded with, or :data:`None` if the data evaluates to :data:`False`.
|
||||||
"""
|
"""
|
||||||
|
try:
|
||||||
response = self.update(pk=pk, data=data)
|
response = self.update(pk=pk, data=data)
|
||||||
self.assertEqual(response.status_code, code, msg=f"`update` did not return {code}")
|
except errors.HTTPException as exc:
|
||||||
|
self.assertEqual(exc.status, code, msg=f"`update` did not return {code}: {exc!r}")
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
self.assertEqual(response.status_code, code, msg=f"`update` did not return {code}: {response.data!r}")
|
||||||
return response.data
|
return response.data
|
||||||
|
|
||||||
def destroy(self, pk) -> Response:
|
def destroy(self, pk) -> Response:
|
||||||
|
@ -158,7 +197,7 @@ class WriteSophonTestCase(ReadSophonTestCase, metaclass=abc.ABCMeta):
|
||||||
url = self.get_url("detail", pk=pk)
|
url = self.get_url("detail", pk=pk)
|
||||||
return self.client.delete(url, {}, format="json")
|
return self.client.delete(url, {}, format="json")
|
||||||
|
|
||||||
def assertActionDestroy(self, pk, code: int = 200) -> t.Any:
|
def assertActionDestroy(self, pk, code: int = 200) -> t.Optional[ReturnDict]:
|
||||||
"""
|
"""
|
||||||
Perform the ``destroy`` action, and assert that it will return a specific status code.
|
Perform the ``destroy`` action, and assert that it will return a specific status code.
|
||||||
|
|
||||||
|
@ -166,250 +205,322 @@ class WriteSophonTestCase(ReadSophonTestCase, metaclass=abc.ABCMeta):
|
||||||
:param code: The expected status code.
|
:param code: The expected status code.
|
||||||
:return: The data the server responded with, or :data:`None` if the data evaluates to :data:`False`.
|
:return: The data the server responded with, or :data:`None` if the data evaluates to :data:`False`.
|
||||||
"""
|
"""
|
||||||
|
try:
|
||||||
response = self.destroy(pk=pk)
|
response = self.destroy(pk=pk)
|
||||||
self.assertEqual(response.status_code, code, msg=f"`destroy` did not return {code}")
|
except errors.HTTPException as exc:
|
||||||
|
self.assertEqual(exc.status, code, msg=f"`create` did not return {code}: {exc!r}")
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
self.assertEqual(response.status_code, code, msg=f"`destroy` did not return {code}: {response.data!r}")
|
||||||
return response.data
|
return response.data
|
||||||
|
|
||||||
|
|
||||||
class ResearchGroupTests(WriteSophonTestCase):
|
class UsersByIdTestCase(ReadSophonTestCase):
|
||||||
"""
|
"""
|
||||||
:class:`APITestCase` for the :class:`ResearchGroupViewSet`.
|
Tests for :class:`sophon.core.views.UsersByIdViewSet`.
|
||||||
|
|
||||||
|
Since the viewset by itself is trivial, these tests are to verify that DRF is working as expected.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_basename(cls) -> str:
|
||||||
|
return "user-by-id"
|
||||||
|
|
||||||
|
first_user: User = None
|
||||||
|
second_user: User = None
|
||||||
|
third_user: User = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
cls.first_user = User.objects.create_user(username="first", password="One")
|
||||||
|
cls.second_user = User.objects.create_user(username="second", password="Two")
|
||||||
|
cls.third_user = User.objects.create_user(username="third", password="Three")
|
||||||
|
|
||||||
|
def test_list_200(self):
|
||||||
|
data = self.assertActionList(200)
|
||||||
|
self.assertEqual(3, data["count"], msg="`list` did not return 3 users")
|
||||||
|
self.assertEqual(3, len(data["results"]), msg="`list` results did not match count")
|
||||||
|
self.assertData(data["results"][0], {"username": "first"})
|
||||||
|
self.assertData(data["results"][1], {"username": "second"})
|
||||||
|
self.assertData(data["results"][2], {"username": "third"})
|
||||||
|
|
||||||
|
def test_retrieve_200(self):
|
||||||
|
data = self.assertActionRetrieve(self.first_user.id)
|
||||||
|
self.assertData(data, {"username": "first"})
|
||||||
|
data = self.assertActionRetrieve(self.second_user.id)
|
||||||
|
self.assertData(data, {"username": "second"})
|
||||||
|
data = self.assertActionRetrieve(self.third_user.id)
|
||||||
|
self.assertData(data, {"username": "third"})
|
||||||
|
|
||||||
|
def test_retrieve_400(self):
|
||||||
|
self.assertActionRetrieve("qwerty", code=400)
|
||||||
|
self.assertActionRetrieve(1.0, code=400)
|
||||||
|
self.assertActionRetrieve("xyzzy", code=400)
|
||||||
|
|
||||||
|
def test_retrieve_404(self):
|
||||||
|
self.assertActionRetrieve(100, code=404)
|
||||||
|
self.assertActionRetrieve(-1, code=404)
|
||||||
|
self.assertActionRetrieve(999999, code=404)
|
||||||
|
|
||||||
|
|
||||||
|
class UsersByUsernameTestCase(ReadSophonTestCase):
|
||||||
|
"""
|
||||||
|
Tests for :class:`sophon.core.views.UsersByUsernameViewSet`.
|
||||||
|
|
||||||
|
Basically the same as the UsersByIdTestCase, except that it checks for alphabetical ordering.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_basename(cls) -> str:
|
||||||
|
return "user-by-username"
|
||||||
|
|
||||||
|
first_user: User = None
|
||||||
|
second_user: User = None
|
||||||
|
third_user: User = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
cls.first_user = User.objects.create_user(username="zzzzzz", password="zzzzzz")
|
||||||
|
cls.second_user = User.objects.create_user(username="wwwwww", password="wwwwww")
|
||||||
|
cls.third_user = User.objects.create_user(username="aaaaaa", password="aaaaaa")
|
||||||
|
|
||||||
|
def test_list_200(self):
|
||||||
|
data = self.assertActionList(200)
|
||||||
|
self.assertEqual(3, data["count"], msg="`list` did not return 3 users")
|
||||||
|
self.assertEqual(3, len(data["results"]), msg="`list` results did not match count")
|
||||||
|
self.assertData(data["results"][0], {"username": "aaaaaa"})
|
||||||
|
self.assertData(data["results"][1], {"username": "wwwwww"})
|
||||||
|
self.assertData(data["results"][2], {"username": "zzzzzz"})
|
||||||
|
|
||||||
|
def test_retrieve_200(self):
|
||||||
|
data = self.assertActionRetrieve(self.first_user.username)
|
||||||
|
self.assertData(data, {"username": "zzzzzz"})
|
||||||
|
data = self.assertActionRetrieve(self.second_user.username)
|
||||||
|
self.assertData(data, {"username": "wwwwww"})
|
||||||
|
data = self.assertActionRetrieve(self.third_user.username)
|
||||||
|
self.assertData(data, {"username": "aaaaaa"})
|
||||||
|
|
||||||
|
def test_retrieve_400(self):
|
||||||
|
self.assertActionRetrieve(1, code=400)
|
||||||
|
self.assertActionRetrieve(-1, code=400)
|
||||||
|
self.assertActionRetrieve(1.0, code=400)
|
||||||
|
|
||||||
|
def test_retrieve_404(self):
|
||||||
|
self.assertActionRetrieve("sas", code=404)
|
||||||
|
self.assertActionRetrieve("sos", code=404)
|
||||||
|
self.assertActionRetrieve("sus", code=404)
|
||||||
|
|
||||||
|
|
||||||
|
class ResearchGroupTestCase(WriteSophonTestCase):
|
||||||
|
"""
|
||||||
|
Tests for :class:`sophon.core.views.UsersByUsernameViewSet`.
|
||||||
|
|
||||||
|
These tests verify that :class:`sophon.core.views.SophonGroupViewSet` is working as intended.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_basename(cls) -> str:
|
def get_basename(cls) -> str:
|
||||||
return "research-group"
|
return "research-group"
|
||||||
|
|
||||||
test_user: User = None
|
owner_user: User = None
|
||||||
other_user: User = None
|
member_user: User = None
|
||||||
|
outside_user: User = None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
cls.test_user = User.objects.create_user(username="TEST", password="TheGreatDjangoTest")
|
cls.owner_user = User.objects.create_user(username="owner", password="owner")
|
||||||
cls.other_user = User.objects.create_user(username="TAST", password="TheGreatDjangoTast")
|
cls.member_user = User.objects.create_user(username="member", password="member")
|
||||||
|
cls.outside_user = User.objects.create_user(username="outside", password="outside")
|
||||||
|
|
||||||
models.ResearchGroup.objects.create(
|
alpha = models.ResearchGroup.objects.create(
|
||||||
slug="alpha",
|
slug="alpha",
|
||||||
name="Alpha",
|
name="Alpha",
|
||||||
description="First test group.",
|
description="First test group.",
|
||||||
owner=cls.test_user,
|
owner=cls.owner_user,
|
||||||
access="MANUAL",
|
access="MANUAL",
|
||||||
)
|
)
|
||||||
|
alpha.members.set([cls.member_user])
|
||||||
|
|
||||||
models.ResearchGroup.objects.create(
|
beta = models.ResearchGroup.objects.create(
|
||||||
slug="beta",
|
slug="beta",
|
||||||
name="Beta",
|
name="Beta",
|
||||||
description="Second test group.",
|
description="Second test group.",
|
||||||
owner=cls.test_user,
|
owner=cls.owner_user,
|
||||||
access="OPEN",
|
access="OPEN",
|
||||||
)
|
)
|
||||||
|
beta.members.set([])
|
||||||
|
|
||||||
def test_list(self):
|
def test_list_200(self):
|
||||||
r = self.list_unwrap()
|
data = self.assertActionList()
|
||||||
|
self.assertEqual(2, data["count"])
|
||||||
count = r["count"]
|
self.assertEqual(2, len(data["results"]))
|
||||||
self.assertEqual(count, 2)
|
self.assertData(data["results"][0], {
|
||||||
|
"slug": "alpha",
|
||||||
list_page = r["results"]
|
"name": "Alpha",
|
||||||
|
"description": "First test group.",
|
||||||
self.assertIn("slug", list_page[0])
|
"owner": self.owner_user.id,
|
||||||
self.assertIn("name", list_page[0])
|
"members": [self.member_user.id],
|
||||||
self.assertIn("description", list_page[0])
|
"access": "MANUAL",
|
||||||
self.assertIn("owner", list_page[0])
|
})
|
||||||
self.assertIn("members", list_page[0])
|
self.assertData(data["results"][1], {
|
||||||
self.assertIn("access", list_page[0])
|
"slug": "beta",
|
||||||
|
"name": "Beta",
|
||||||
def test_retrieve_valid(self):
|
"description": "Second test group.",
|
||||||
retrieved = self.retrieve_unwrap("alpha")
|
"owner": self.owner_user.id,
|
||||||
|
|
||||||
self.assertIn("slug", retrieved)
|
|
||||||
self.assertIn("name", retrieved)
|
|
||||||
self.assertIn("description", retrieved)
|
|
||||||
self.assertIn("owner", retrieved)
|
|
||||||
self.assertIn("members", retrieved)
|
|
||||||
self.assertIn("access", retrieved)
|
|
||||||
|
|
||||||
self.assertEqual(retrieved["slug"], "alpha")
|
|
||||||
self.assertEqual(retrieved["name"], "Alpha")
|
|
||||||
self.assertEqual(retrieved["description"], "First test group.")
|
|
||||||
self.assertEqual(retrieved["owner"], self.test_user.id)
|
|
||||||
self.assertEqual(retrieved["members"], [])
|
|
||||||
self.assertEqual(retrieved["access"], "MANUAL")
|
|
||||||
|
|
||||||
def test_retrieve_not_existing(self):
|
|
||||||
self.retrieve_fail("banana", 404)
|
|
||||||
|
|
||||||
def test_create_valid(self):
|
|
||||||
self.client.login(username="TEST", password="TheGreatDjangoTest")
|
|
||||||
|
|
||||||
created = self.create_unwrap({
|
|
||||||
"slug": "omega",
|
|
||||||
"name": "Omega",
|
|
||||||
"description": "Last test group.",
|
|
||||||
"members": [],
|
"members": [],
|
||||||
"access": "OPEN",
|
"access": "OPEN",
|
||||||
})
|
})
|
||||||
self.assertIn("slug", created)
|
|
||||||
self.assertIn("name", created)
|
|
||||||
self.assertIn("description", created)
|
|
||||||
self.assertIn("owner", created)
|
|
||||||
self.assertIn("members", created)
|
|
||||||
self.assertIn("access", created)
|
|
||||||
|
|
||||||
retrieved = self.retrieve_unwrap("omega")
|
def test_retrieve_200(self):
|
||||||
|
data = self.assertActionRetrieve("alpha")
|
||||||
|
self.assertData(data, {
|
||||||
|
"slug": "alpha",
|
||||||
|
"name": "Alpha",
|
||||||
|
"description": "First test group.",
|
||||||
|
"owner": self.owner_user.id,
|
||||||
|
"members": [self.member_user.id],
|
||||||
|
"access": "MANUAL",
|
||||||
|
})
|
||||||
|
|
||||||
self.assertIn("slug", retrieved)
|
data = self.assertActionRetrieve("beta")
|
||||||
self.assertIn("name", retrieved)
|
self.assertData(data, {
|
||||||
self.assertIn("description", retrieved)
|
"slug": "beta",
|
||||||
self.assertIn("owner", retrieved)
|
"name": "Beta",
|
||||||
self.assertIn("members", retrieved)
|
"description": "Second test group.",
|
||||||
self.assertIn("access", retrieved)
|
"owner": self.owner_user.id,
|
||||||
|
|
||||||
self.assertEqual(retrieved["slug"], "omega")
|
|
||||||
self.assertEqual(retrieved["name"], "Omega")
|
|
||||||
self.assertEqual(retrieved["description"], "Last test group.")
|
|
||||||
self.assertEqual(retrieved["owner"], self.test_user.id)
|
|
||||||
self.assertEqual(retrieved["members"], [])
|
|
||||||
self.assertEqual(retrieved["access"], "OPEN")
|
|
||||||
|
|
||||||
def test_create_not_logged_in(self):
|
|
||||||
self.create_fail({
|
|
||||||
"slug": "fail",
|
|
||||||
"name": "Failure",
|
|
||||||
"description": "This creation should fail.",
|
|
||||||
"members": [],
|
"members": [],
|
||||||
"access": "OPEN",
|
"access": "OPEN",
|
||||||
|
})
|
||||||
|
|
||||||
|
def test_retrieve_404(self):
|
||||||
|
self.assertActionRetrieve("banana", 404)
|
||||||
|
self.assertActionRetrieve("tomato", 404)
|
||||||
|
self.assertActionRetrieve("potato", 404)
|
||||||
|
# Since these are path parameters, they are interpreted as strings
|
||||||
|
self.assertActionRetrieve(1, 404)
|
||||||
|
self.assertActionRetrieve(-1, 404)
|
||||||
|
self.assertActionRetrieve(1.0, 404)
|
||||||
|
|
||||||
|
def test_create_201(self):
|
||||||
|
with self.as_user(self.owner_user.username):
|
||||||
|
# Ensure the group doesn't already exist
|
||||||
|
self.assertActionRetrieve("gamma", 404)
|
||||||
|
# Create the group
|
||||||
|
created = self.assertActionCreate({
|
||||||
|
"slug": "gamma",
|
||||||
|
"name": "Gamma",
|
||||||
|
"description": "Third test group.",
|
||||||
|
"members": [self.member_user.id],
|
||||||
|
"access": "OPEN",
|
||||||
|
}, 201)
|
||||||
|
self.assertData(created, {
|
||||||
|
"slug": "gamma",
|
||||||
|
"name": "Gamma",
|
||||||
|
"description": "Third test group.",
|
||||||
|
"owner": self.owner_user.id,
|
||||||
|
"members": [self.member_user.id],
|
||||||
|
"access": "OPEN",
|
||||||
|
})
|
||||||
|
# Ensure the group now exists
|
||||||
|
retrieved = self.assertActionRetrieve("gamma")
|
||||||
|
self.assertData(retrieved, {
|
||||||
|
"slug": "gamma",
|
||||||
|
"name": "Gamma",
|
||||||
|
"description": "Third test group.",
|
||||||
|
"owner": self.owner_user.id,
|
||||||
|
"members": [self.member_user.id],
|
||||||
|
"access": "OPEN",
|
||||||
|
})
|
||||||
|
|
||||||
|
def test_create_400(self):
|
||||||
|
self.assertActionCreate({}, 400)
|
||||||
|
self.assertActionCreate({
|
||||||
|
"slug": 1,
|
||||||
|
"name": 213478,
|
||||||
|
"description": 384592,
|
||||||
|
"members": {
|
||||||
|
"why not": "a dict"
|
||||||
|
},
|
||||||
|
"access": "yes",
|
||||||
|
}, 400)
|
||||||
|
|
||||||
|
def test_create_401(self):
|
||||||
|
self.assertActionCreate({
|
||||||
|
"slug": "delta",
|
||||||
|
"name": "Delta",
|
||||||
|
"description": "Fourth test group.",
|
||||||
|
"members": [self.member_user.id],
|
||||||
|
"access": "OPEN",
|
||||||
}, 401)
|
}, 401)
|
||||||
|
|
||||||
def test_create_invalid_schema(self):
|
def test_update_200(self):
|
||||||
self.client.login(username="TEST", password="TheGreatDjangoTest")
|
with self.as_user(self.owner_user.username):
|
||||||
|
updated = self.assertActionUpdate("beta", {
|
||||||
self.create_fail({
|
"slug": "beta",
|
||||||
"potato": "sweet",
|
"name": "Beta",
|
||||||
|
"description": "Second test group.",
|
||||||
|
"owner": self.owner_user.id,
|
||||||
|
"members": [self.member_user.id], # <-
|
||||||
"access": "OPEN",
|
"access": "OPEN",
|
||||||
|
})
|
||||||
|
self.assertData(updated, {
|
||||||
|
"slug": "beta",
|
||||||
|
"name": "Beta",
|
||||||
|
"description": "Second test group.",
|
||||||
|
"owner": self.owner_user.id,
|
||||||
|
"members": [self.member_user.id],
|
||||||
|
"access": "OPEN",
|
||||||
|
})
|
||||||
|
|
||||||
|
def test_update_400(self):
|
||||||
|
with self.as_user(self.owner_user.username):
|
||||||
|
self.assertActionUpdate("beta", {
|
||||||
|
"members": {
|
||||||
|
"nobody expects": "the dict inquisition",
|
||||||
|
}
|
||||||
}, 400)
|
}, 400)
|
||||||
|
|
||||||
def test_update_valid(self):
|
# Using AllowAny, update always succeeds, even if permissions are missing, but won't apply any changes due to the access serializer
|
||||||
self.client.login(username="TEST", password="TheGreatDjangoTest")
|
def test_update_unauthenticated(self):
|
||||||
|
self.assertActionUpdate("beta", {
|
||||||
|
"members": [self.outside_user.id],
|
||||||
|
})
|
||||||
|
|
||||||
self.create_unwrap({
|
retrieved = self.assertActionRetrieve("beta")
|
||||||
"slug": "gamma",
|
self.assertData(retrieved, {
|
||||||
"name": "Gamma",
|
"slug": "beta",
|
||||||
"description": "A test group to update.",
|
"name": "Beta",
|
||||||
|
"description": "Second test group.",
|
||||||
|
"owner": self.owner_user.id,
|
||||||
"members": [],
|
"members": [],
|
||||||
"access": "OPEN",
|
"access": "OPEN",
|
||||||
})
|
})
|
||||||
|
|
||||||
retrieved = self.retrieve_unwrap("gamma")
|
# Using AllowAny, update always succeeds, even if permissions are missing, but won't apply any changes due to the access serializer
|
||||||
|
def test_update_forbidden(self):
|
||||||
self.assertEqual(retrieved["slug"], "gamma")
|
with self.as_user(self.outside_user.username):
|
||||||
self.assertEqual(retrieved["name"], "Gamma")
|
self.assertActionUpdate("beta", {
|
||||||
self.assertEqual(retrieved["description"], "A test group to update.")
|
"name": "Bbbbbbbbb",
|
||||||
self.assertEqual(retrieved["owner"], self.test_user.id)
|
|
||||||
self.assertEqual(retrieved["members"], [])
|
|
||||||
self.assertEqual(retrieved["access"], "OPEN")
|
|
||||||
|
|
||||||
updated = self.update_unwrap("gamma", {
|
|
||||||
"slug": "gamma",
|
|
||||||
"name": "Gamma",
|
|
||||||
"description": "An updated test group.",
|
|
||||||
"members": [],
|
|
||||||
"access": "MANUAL",
|
|
||||||
})
|
})
|
||||||
|
|
||||||
self.assertIn("slug", updated)
|
retrieved = self.assertActionRetrieve("beta")
|
||||||
self.assertIn("name", updated)
|
self.assertData(retrieved, {
|
||||||
self.assertIn("description", updated)
|
"slug": "beta",
|
||||||
self.assertIn("owner", updated)
|
"name": "Beta",
|
||||||
self.assertIn("members", updated)
|
"description": "Second test group.",
|
||||||
self.assertIn("access", updated)
|
"owner": self.owner_user.id,
|
||||||
|
|
||||||
self.assertEqual(updated["slug"], "gamma")
|
|
||||||
self.assertEqual(updated["name"], "Gamma")
|
|
||||||
self.assertEqual(updated["description"], "An updated test group.")
|
|
||||||
self.assertEqual(updated["owner"], self.test_user.id)
|
|
||||||
self.assertEqual(updated["members"], [])
|
|
||||||
self.assertEqual(updated["access"], "MANUAL")
|
|
||||||
|
|
||||||
retrieved2 = self.retrieve_unwrap("gamma")
|
|
||||||
|
|
||||||
self.assertEqual(retrieved2["slug"], "gamma")
|
|
||||||
self.assertEqual(retrieved2["name"], "Gamma")
|
|
||||||
self.assertEqual(retrieved2["description"], "An updated test group.")
|
|
||||||
self.assertEqual(retrieved2["owner"], self.test_user.id)
|
|
||||||
self.assertEqual(retrieved2["members"], [])
|
|
||||||
self.assertEqual(retrieved2["access"], "MANUAL")
|
|
||||||
|
|
||||||
def test_update_not_logged_in(self):
|
|
||||||
self.update_fail("alpha", {
|
|
||||||
"slug": "alpha",
|
|
||||||
"name": "AAAAA",
|
|
||||||
"description": "An hacker has updated the Alpha group without permissions!",
|
|
||||||
"members": [],
|
|
||||||
"access": "MANUAL",
|
|
||||||
}, 401)
|
|
||||||
|
|
||||||
def test_update_unauthorized(self):
|
|
||||||
self.client.login(username="TAST", password="TheGreatDjangoTast")
|
|
||||||
|
|
||||||
self.update_fail("alpha", {
|
|
||||||
"slug": "alpha",
|
|
||||||
"name": "AAAAA",
|
|
||||||
"description": "An hacker has updated the Alpha group without permissions!",
|
|
||||||
"members": [],
|
|
||||||
"access": "MANUAL",
|
|
||||||
}, 403)
|
|
||||||
|
|
||||||
def test_update_invalid_schema(self):
|
|
||||||
self.client.login(username="TEST", password="TheGreatDjangoTest")
|
|
||||||
|
|
||||||
self.update_fail("alpha", {
|
|
||||||
"hahaha": "soccer",
|
|
||||||
}, 400)
|
|
||||||
|
|
||||||
def test_destroy_valid(self):
|
|
||||||
self.client.login(username="TEST", password="TheGreatDjangoTest")
|
|
||||||
|
|
||||||
self.create_unwrap({
|
|
||||||
"slug": "boom",
|
|
||||||
"name": "Boom!!!",
|
|
||||||
"description": "A group that should explode.",
|
|
||||||
"members": [],
|
"members": [],
|
||||||
"access": "OPEN",
|
"access": "OPEN",
|
||||||
})
|
})
|
||||||
|
|
||||||
self.destroy_unwrap("boom")
|
def test_destroy_204(self):
|
||||||
self.retrieve_fail("boom", 404)
|
with self.as_user(self.owner_user.username):
|
||||||
|
self.assertActionDestroy("beta", 204)
|
||||||
|
self.assertActionRetrieve("beta", 404)
|
||||||
|
|
||||||
def test_destroy_not_logged_in(self):
|
def test_destroy_401(self):
|
||||||
self.client.login(username="TEST", password="TheGreatDjangoTest")
|
self.assertActionDestroy("alpha", 401)
|
||||||
|
|
||||||
self.create_unwrap({
|
def test_destroy_403(self):
|
||||||
"slug": "boom",
|
with self.as_user(self.outside_user.username):
|
||||||
"name": "Boom!!!",
|
self.assertActionDestroy("alpha", 403)
|
||||||
"description": "A group that should explode.",
|
|
||||||
"members": [],
|
|
||||||
"access": "OPEN",
|
|
||||||
})
|
|
||||||
|
|
||||||
self.client.logout()
|
|
||||||
|
|
||||||
self.destroy_fail("boom", 401)
|
|
||||||
self.retrieve_unwrap("boom")
|
|
||||||
|
|
||||||
def test_destroy_unauthorized(self):
|
|
||||||
self.client.login(username="TEST", password="TheGreatDjangoTest")
|
|
||||||
|
|
||||||
self.create_unwrap({
|
|
||||||
"slug": "doom",
|
|
||||||
"name": "Doom!!!",
|
|
||||||
"description": "A group about a game.",
|
|
||||||
"members": [],
|
|
||||||
"access": "OPEN",
|
|
||||||
})
|
|
||||||
|
|
||||||
self.client.logout()
|
|
||||||
self.client.login(username="TAST", password="TheGreatDjangoTast")
|
|
||||||
|
|
||||||
self.destroy_fail("doom", 403)
|
|
||||||
self.retrieve_unwrap("doom")
|
|
||||||
|
|
Loading…
Reference in a new issue