InvenTree/InvenTree/InvenTree/test_api.py
2021-11-23 00:28:23 +01:00

313 lines
8.6 KiB
Python

""" Low level tests for the InvenTree API """
from rest_framework import status
from django.test import TestCase
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.urls import reverse
from InvenTree.api_tester import InvenTreeAPITestCase
from users.models import RuleSet
from base64 import b64encode
class HTMLAPITests(TestCase):
"""
Test that we can access the REST API endpoints via the HTML interface.
History: Discovered on 2021-06-28 a bug in InvenTreeModelSerializer,
which raised an AssertionError when using the HTML API interface,
while the regular JSON interface continued to work as expected.
"""
def setUp(self):
super().setUp()
# Create a user
user = get_user_model()
self.user = user.objects.create_user(
username='username',
email='user@email.com',
password='password'
)
# Put the user into a group with the correct permissions
group = Group.objects.create(name='mygroup')
self.user.groups.add(group)
# Give the group *all* the permissions!
for rule in group.rule_sets.all():
rule.can_view = True
rule.can_change = True
rule.can_add = True
rule.can_delete = True
rule.save()
self.client.login(username='username', password='password')
def test_part_api(self):
url = reverse('api-part-list')
# Check JSON response
response = self.client.get(url, HTTP_ACCEPT='application/json')
self.assertEqual(response.status_code, 200)
# Check HTTP response
response = self.client.get(url, HTTP_ACCEPT='text/html')
self.assertEqual(response.status_code, 200)
def test_build_api(self):
url = reverse('api-build-list')
# Check JSON response
response = self.client.get(url, HTTP_ACCEPT='application/json')
self.assertEqual(response.status_code, 200)
# Check HTTP response
response = self.client.get(url, HTTP_ACCEPT='text/html')
self.assertEqual(response.status_code, 200)
def test_stock_api(self):
url = reverse('api-stock-list')
# Check JSON response
response = self.client.get(url, HTTP_ACCEPT='application/json')
self.assertEqual(response.status_code, 200)
# Check HTTP response
response = self.client.get(url, HTTP_ACCEPT='text/html')
self.assertEqual(response.status_code, 200)
def test_company_list(self):
url = reverse('api-company-list')
# Check JSON response
response = self.client.get(url, HTTP_ACCEPT='application/json')
self.assertEqual(response.status_code, 200)
# Check HTTP response
response = self.client.get(url, HTTP_ACCEPT='text/html')
self.assertEqual(response.status_code, 200)
class APITests(InvenTreeAPITestCase):
""" Tests for the InvenTree API """
fixtures = [
'location',
'category',
'part',
'stock'
]
token = None
auto_login = False
def setUp(self):
super().setUp()
def basicAuth(self):
# Use basic authentication
authstring = bytes("{u}:{p}".format(u=self.username, p=self.password), "ascii")
# Use "basic" auth by default
auth = b64encode(authstring).decode("ascii")
self.client.credentials(HTTP_AUTHORIZATION="Basic {auth}".format(auth=auth))
def tokenAuth(self):
self.basicAuth()
token_url = reverse('api-token')
response = self.client.get(token_url, format='json', data={})
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertIn('token', response.data)
token = response.data['token']
self.token = token
def test_token_failure(self):
# Test token endpoint without basic auth
url = reverse('api-token')
response = self.client.get(url, format='json')
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
self.assertIsNone(self.token)
def test_token_success(self):
self.tokenAuth()
self.assertIsNotNone(self.token)
def test_info_view(self):
"""
Test that we can read the 'info-view' endpoint.
"""
url = reverse('api-inventree-info')
response = self.client.get(url, format='json')
data = response.json()
self.assertIn('server', data)
self.assertIn('version', data)
self.assertIn('instance', data)
self.assertEqual('InvenTree', data['server'])
def test_role_view(self):
"""
Test that we can access the 'roles' view for the logged in user.
Also tests that it is *not* accessible if the client is not logged in.
"""
url = reverse('api-user-roles')
response = self.client.get(url, format='json')
# Not logged in, so cannot access user role data
self.assertTrue(response.status_code in [401, 403])
# Now log in!
self.basicAuth()
response = self.get(url)
data = response.data
self.assertIn('user', data)
self.assertIn('username', data)
self.assertIn('is_staff', data)
self.assertIn('is_superuser', data)
self.assertIn('roles', data)
roles = data['roles']
role_names = roles.keys()
# By default, 'view' permissions are provided
for rule in RuleSet.RULESET_NAMES:
self.assertIn(rule, role_names)
self.assertIn('view', roles[rule])
self.assertNotIn('add', roles[rule])
self.assertNotIn('change', roles[rule])
self.assertNotIn('delete', roles[rule])
def test_with_superuser(self):
"""
Superuser should have *all* roles assigned
"""
self.user.is_superuser = True
self.user.save()
self.basicAuth()
response = self.get(reverse('api-user-roles'))
roles = response.data['roles']
for rule in RuleSet.RULESET_NAMES:
self.assertIn(rule, roles.keys())
for perm in ['view', 'add', 'change', 'delete']:
self.assertIn(perm, roles[rule])
def test_with_roles(self):
"""
Assign some roles to the user
"""
self.basicAuth()
response = self.get(reverse('api-user-roles'))
self.assignRole('part.delete')
self.assignRole('build.change')
response = self.get(reverse('api-user-roles'))
roles = response.data['roles']
# New role permissions should have been added now
self.assertIn('delete', roles['part'])
self.assertIn('change', roles['build'])
def test_list_endpoint_actions(self):
"""
Tests for the OPTIONS method for API endpoints.
"""
self.basicAuth()
# Without any 'part' permissions, we should not see any available actions
url = reverse('api-part-list')
actions = self.getActions(url)
# No actions, as there are no permissions!
self.assertEqual(len(actions), 0)
# Assign a new role
self.assignRole('part.view')
actions = self.getActions(url)
# As we don't have "add" permission, there should be no available API actions
self.assertEqual(len(actions), 0)
# But let's make things interesting...
# Why don't we treat ourselves to some "add" permissions
self.assignRole('part.add')
actions = self.getActions(url)
self.assertEqual(len(actions), 2)
self.assertIn('POST', actions)
self.assertIn('GET', actions)
def test_detail_endpoint_actions(self):
"""
Tests for detail API endpoint actions
"""
self.basicAuth()
url = reverse('api-part-detail', kwargs={'pk': 1})
actions = self.getActions(url)
# No actions, as we do not have any permissions!
self.assertEqual(len(actions), 0)
# Add a 'add' permission
# Note: 'add' permission automatically implies 'change' also
self.assignRole('part.add')
actions = self.getActions(url)
self.assertEqual(len(actions), 2)
self.assertIn('PUT', actions.keys())
self.assertIn('GET', actions.keys())
# Add some other permissions
self.assignRole('part.change')
self.assignRole('part.delete')
actions = self.getActions(url)
self.assertEqual(len(actions), 3)
self.assertIn('GET', actions.keys())
self.assertIn('PUT', actions.keys())
self.assertIn('DELETE', actions.keys())