2024-03-23 20:53:23 +03:00
|
|
|
''' Utils: base tester class for endpoints. '''
|
|
|
|
from rest_framework import status
|
2024-05-26 00:46:58 +03:00
|
|
|
from rest_framework.test import APIClient, APIRequestFactory, APITestCase
|
2024-03-23 20:53:23 +03:00
|
|
|
|
2024-06-02 23:41:46 +03:00
|
|
|
from apps.rsform.models import Editor, LibraryItem
|
2024-03-23 20:53:23 +03:00
|
|
|
from apps.users.models import User
|
|
|
|
|
|
|
|
|
|
|
|
def decl_endpoint(endpoint: str, method: str):
|
|
|
|
''' Decorator for EndpointTester methods to provide API attributes. '''
|
|
|
|
def set_endpoint_inner(function):
|
|
|
|
def wrapper(*args, **kwargs):
|
|
|
|
if '{' in endpoint:
|
|
|
|
args[0].endpoint = 'UNRESOLVED'
|
|
|
|
args[0].endpoint_mask = endpoint
|
|
|
|
else:
|
|
|
|
args[0].endpoint_mask = None
|
|
|
|
args[0].endpoint = endpoint
|
|
|
|
args[0].method = method
|
|
|
|
return function(*args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
return set_endpoint_inner
|
|
|
|
|
|
|
|
|
|
|
|
class EndpointTester(APITestCase):
|
|
|
|
''' Abstract base class for Testing endpoints. '''
|
2024-05-26 00:46:58 +03:00
|
|
|
|
2024-03-23 20:53:23 +03:00
|
|
|
def setUp(self):
|
2024-07-15 12:36:18 +03:00
|
|
|
self.factory = APIRequestFactory()
|
|
|
|
self.user = User.objects.create(
|
|
|
|
username='UserTest',
|
|
|
|
email='blank@test.com',
|
|
|
|
password='password'
|
|
|
|
)
|
|
|
|
self.user2 = User.objects.create(
|
|
|
|
username='UserTest2',
|
|
|
|
email='another@test.com',
|
|
|
|
password='password'
|
|
|
|
)
|
|
|
|
self.client = APIClient()
|
|
|
|
self.client.force_authenticate(user=self.user)
|
|
|
|
|
|
|
|
def setUpFullUsers(self):
|
2024-03-23 20:53:23 +03:00
|
|
|
self.factory = APIRequestFactory()
|
2024-05-28 14:26:44 +03:00
|
|
|
self.user = User.objects.create_user(
|
|
|
|
username='UserTest',
|
|
|
|
email='blank@test.com',
|
|
|
|
password='password'
|
|
|
|
)
|
|
|
|
self.user2 = User.objects.create_user(
|
|
|
|
username='UserTest2',
|
|
|
|
email='another@test.com',
|
|
|
|
password='password'
|
|
|
|
)
|
2024-03-23 20:53:23 +03:00
|
|
|
self.client = APIClient()
|
|
|
|
self.client.force_authenticate(user=self.user)
|
|
|
|
|
2024-04-28 21:07:04 +03:00
|
|
|
def toggle_admin(self, value: bool = True):
|
2024-03-23 20:53:23 +03:00
|
|
|
self.user.is_staff = value
|
|
|
|
self.user.save()
|
|
|
|
|
2024-06-02 23:41:46 +03:00
|
|
|
def toggle_editor(self, item: LibraryItem, value: bool = True):
|
|
|
|
if value:
|
|
|
|
Editor.add(item, self.user)
|
|
|
|
else:
|
|
|
|
Editor.remove(item, self.user)
|
|
|
|
|
2024-03-23 20:53:23 +03:00
|
|
|
def login(self):
|
|
|
|
self.client.force_authenticate(user=self.user)
|
|
|
|
|
|
|
|
def logout(self):
|
|
|
|
self.client.logout()
|
|
|
|
|
|
|
|
def set_params(self, **kwargs):
|
|
|
|
''' Given named argument values resolve current endpoint_mask. '''
|
|
|
|
if self.endpoint_mask and len(kwargs) > 0:
|
|
|
|
self.endpoint = _resolve_url(self.endpoint_mask, **kwargs)
|
|
|
|
|
|
|
|
def get(self, endpoint: str = '', **kwargs):
|
|
|
|
if endpoint != '':
|
|
|
|
return self.client.get(endpoint)
|
|
|
|
else:
|
|
|
|
self.set_params(**kwargs)
|
|
|
|
return self.client.get(self.endpoint)
|
|
|
|
|
|
|
|
def post(self, data=None, **kwargs):
|
|
|
|
self.set_params(**kwargs)
|
|
|
|
if not data is None:
|
|
|
|
return self.client.post(self.endpoint, data=data, format='json')
|
|
|
|
else:
|
|
|
|
return self.client.post(self.endpoint)
|
|
|
|
|
|
|
|
def patch(self, data=None, **kwargs):
|
|
|
|
self.set_params(**kwargs)
|
|
|
|
if not data is None:
|
|
|
|
return self.client.patch(self.endpoint, data=data, format='json')
|
|
|
|
else:
|
|
|
|
return self.client.patch(self.endpoint)
|
|
|
|
|
|
|
|
def put(self, data, **kwargs):
|
|
|
|
self.set_params(**kwargs)
|
|
|
|
return self.client.get(self.endpoint, data=data, format='json')
|
|
|
|
|
|
|
|
def delete(self, data=None, **kwargs):
|
|
|
|
self.set_params(**kwargs)
|
|
|
|
if not data is None:
|
|
|
|
return self.client.delete(self.endpoint, data=data, format='json')
|
|
|
|
else:
|
|
|
|
return self.client.delete(self.endpoint)
|
|
|
|
|
2024-05-28 14:26:44 +03:00
|
|
|
def execute(self, data=None, **kwargs):
|
|
|
|
if self.method == 'get':
|
|
|
|
return self.get(**kwargs)
|
|
|
|
if self.method == 'post':
|
|
|
|
return self.post(data, **kwargs)
|
|
|
|
if self.method == 'put':
|
|
|
|
return self.put(data, **kwargs)
|
|
|
|
if self.method == 'patch':
|
|
|
|
return self.patch(data, **kwargs)
|
|
|
|
if self.method == 'delete':
|
|
|
|
return self.delete(data, **kwargs)
|
|
|
|
return None
|
|
|
|
|
|
|
|
def executeOK(self, data=None, **kwargs):
|
2024-03-23 20:53:23 +03:00
|
|
|
response = self.execute(data, **kwargs)
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
2024-05-28 14:26:44 +03:00
|
|
|
return response
|
2024-03-23 20:53:23 +03:00
|
|
|
|
2024-05-28 14:26:44 +03:00
|
|
|
def executeCreated(self, data=None, **kwargs):
|
2024-04-04 14:34:25 +03:00
|
|
|
response = self.execute(data, **kwargs)
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
2024-05-28 14:26:44 +03:00
|
|
|
return response
|
|
|
|
|
|
|
|
def executeAccepted(self, data=None, **kwargs):
|
|
|
|
response = self.execute(data, **kwargs)
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)
|
|
|
|
return response
|
2024-04-04 14:34:25 +03:00
|
|
|
|
2024-05-28 14:26:44 +03:00
|
|
|
def executeNoContent(self, data=None, **kwargs):
|
|
|
|
response = self.execute(data, **kwargs)
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
|
|
|
|
return response
|
|
|
|
|
|
|
|
def executeBadData(self, data=None, **kwargs):
|
2024-03-23 20:53:23 +03:00
|
|
|
response = self.execute(data, **kwargs)
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
2024-05-28 14:26:44 +03:00
|
|
|
return response
|
2024-03-23 20:53:23 +03:00
|
|
|
|
2024-05-28 14:26:44 +03:00
|
|
|
def executeForbidden(self, data=None, **kwargs):
|
2024-03-23 20:53:23 +03:00
|
|
|
response = self.execute(data, **kwargs)
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
2024-05-28 14:26:44 +03:00
|
|
|
return response
|
2024-03-23 20:53:23 +03:00
|
|
|
|
2024-05-28 14:26:44 +03:00
|
|
|
def executeNotModified(self, data=None, **kwargs):
|
2024-03-23 20:53:23 +03:00
|
|
|
response = self.execute(data, **kwargs)
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_304_NOT_MODIFIED)
|
2024-05-28 14:26:44 +03:00
|
|
|
return response
|
2024-03-23 20:53:23 +03:00
|
|
|
|
2024-05-28 14:26:44 +03:00
|
|
|
def executeNotFound(self, data=None, **kwargs):
|
2024-03-23 20:53:23 +03:00
|
|
|
response = self.execute(data, **kwargs)
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
2024-05-28 14:26:44 +03:00
|
|
|
return response
|
2024-03-23 20:53:23 +03:00
|
|
|
|
|
|
|
|
|
|
|
def _resolve_url(url: str, **kwargs) -> str:
|
|
|
|
if url == '' or len(kwargs) == 0:
|
|
|
|
return url
|
|
|
|
pos_input: int = 0
|
|
|
|
pos_start: int = 0
|
|
|
|
pos_end: int = 0
|
|
|
|
arg_names = set()
|
|
|
|
output: str = ''
|
|
|
|
while True:
|
|
|
|
pos_start = url.find('{', pos_input)
|
|
|
|
if pos_start == -1:
|
|
|
|
break
|
|
|
|
pos_end = url.find('}', pos_start)
|
|
|
|
if pos_end == -1:
|
|
|
|
break
|
2024-05-26 00:46:58 +03:00
|
|
|
name = url[(pos_start + 1): pos_end]
|
2024-03-23 20:53:23 +03:00
|
|
|
arg_names.add(name)
|
|
|
|
if not name in kwargs:
|
|
|
|
raise KeyError(f'Missing argument: {name} | Mask: {url}')
|
2024-05-26 00:46:58 +03:00
|
|
|
output += url[pos_input: pos_start]
|
2024-03-23 20:53:23 +03:00
|
|
|
output += str(kwargs[name])
|
|
|
|
pos_input = pos_end + 1
|
|
|
|
if pos_input < len(url):
|
2024-05-26 00:46:58 +03:00
|
|
|
output += url[pos_input: len(url)]
|
2024-03-23 20:53:23 +03:00
|
|
|
for (key, _) in kwargs.items():
|
|
|
|
if key not in arg_names:
|
|
|
|
raise KeyError(f'Unused argument: {name} | Mask: {url}')
|
|
|
|
return output
|