mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
d884e62be1
Fixes #2335
313 lines
8.6 KiB
Python
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())
|