From 20ebc5e8de6815b905fa31f176587998be98ee6d Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 28 Aug 2024 09:53:49 -0400 Subject: [PATCH] Extend GraphQL API tests --- netbox/utilities/testing/api.py | 61 ++++++++++++++++++++++--------- netbox/utilities/testing/utils.py | 10 +++++ 2 files changed, 54 insertions(+), 17 deletions(-) diff --git a/netbox/utilities/testing/api.py b/netbox/utilities/testing/api.py index 7bb349a66..a3cfb9b2e 100644 --- a/netbox/utilities/testing/api.py +++ b/netbox/utilities/testing/api.py @@ -16,7 +16,7 @@ from extras.models import ObjectChange from users.models import ObjectPermission, Token from utilities.api import get_graphql_type_for_model from .base import ModelTestCase -from .utils import disable_warnings +from .utils import disable_logging, disable_warnings from ipam.graphql.types import IPAddressFamilyType from strawberry.types.lazy_type import LazyType @@ -523,7 +523,6 @@ class APIViewTestCases: return self._build_query_with_filter(name, filter_string) @override_settings(LOGIN_REQUIRED=True) - @override_settings(EXEMPT_VIEW_PERMISSIONS=['*', 'auth.user']) def test_graphql_get_object(self): url = reverse('graphql') field_name = self._get_graphql_base_name() @@ -531,57 +530,85 @@ class APIViewTestCases: query = self._build_query(field_name, id=object_id) # Non-authenticated requests should fail + header = { + 'HTTP_ACCEPT': 'application/json', + } with disable_warnings('django.request'): - header = { - 'HTTP_ACCEPT': 'application/json', - } - self.assertHttpStatus(self.client.post(url, data={'query': query}, format="json", **header), status.HTTP_403_FORBIDDEN) + response = self.client.post(url, data={'query': query}, format="json", **header) + self.assertHttpStatus(response, status.HTTP_403_FORBIDDEN) - # Add object-level permission + # Add constrained permission obj_perm = ObjectPermission( name='Test permission', - actions=['view'] + actions=['view'], + constraints={'id': 0} # Impossible constraint ) obj_perm.save() obj_perm.users.add(self.user) obj_perm.object_types.add(ObjectType.objects.get_for_model(self.model)) + # Request should succeed but return empty result + with disable_logging(): + response = self.client.post(url, data={'query': query}, format="json", **self.header) + self.assertHttpStatus(response, status.HTTP_200_OK) + data = json.loads(response.content) + self.assertIn('errors', data) + self.assertIsNone(data['data']) + + # Remove permission constraint + obj_perm.constraints = None + obj_perm.save() + + # Request should return requested object response = self.client.post(url, data={'query': query}, format="json", **self.header) self.assertHttpStatus(response, status.HTTP_200_OK) data = json.loads(response.content) self.assertNotIn('errors', data) + self.assertIsNotNone(data['data']) @override_settings(LOGIN_REQUIRED=True) - @override_settings(EXEMPT_VIEW_PERMISSIONS=['*', 'auth.user']) def test_graphql_list_objects(self): url = reverse('graphql') field_name = f'{self._get_graphql_base_name()}_list' query = self._build_query(field_name) # Non-authenticated requests should fail + header = { + 'HTTP_ACCEPT': 'application/json', + } with disable_warnings('django.request'): - header = { - 'HTTP_ACCEPT': 'application/json', - } - self.assertHttpStatus(self.client.post(url, data={'query': query}, format="json", **header), status.HTTP_403_FORBIDDEN) + response = self.client.post(url, data={'query': query}, format="json", **header) + self.assertHttpStatus(response, status.HTTP_403_FORBIDDEN) - # Add object-level permission + # Add constrained permission obj_perm = ObjectPermission( name='Test permission', - actions=['view'] + actions=['view'], + constraints={'id': 0} # Impossible constraint ) obj_perm.save() obj_perm.users.add(self.user) obj_perm.object_types.add(ObjectType.objects.get_for_model(self.model)) + # Request should succeed but return empty results list response = self.client.post(url, data={'query': query}, format="json", **self.header) self.assertHttpStatus(response, status.HTTP_200_OK) data = json.loads(response.content) self.assertNotIn('errors', data) - self.assertGreater(len(data['data'][field_name]), 0) + self.assertEqual(len(data['data'][field_name]), 0) + + # Remove permission constraint + obj_perm.constraints = None + obj_perm.save() + + # Request should return all objects + response = self.client.post(url, data={'query': query}, format="json", **self.header) + self.assertHttpStatus(response, status.HTTP_200_OK) + data = json.loads(response.content) + self.assertNotIn('errors', data) + self.assertEqual(len(data['data'][field_name]), self.model.objects.count()) @override_settings(LOGIN_REQUIRED=True) - @override_settings(EXEMPT_VIEW_PERMISSIONS=['*', 'auth.user']) def test_graphql_filter_objects(self): if not hasattr(self, 'graphql_filter'): return diff --git a/netbox/utilities/testing/utils.py b/netbox/utilities/testing/utils.py index 59bce2b7c..987e5ec35 100644 --- a/netbox/utilities/testing/utils.py +++ b/netbox/utilities/testing/utils.py @@ -107,6 +107,16 @@ def disable_warnings(logger_name): logger.setLevel(current_level) +@contextmanager +def disable_logging(level=logging.CRITICAL): + """ + Temporarily suppress log messages at or below the specified level (default: critical). + """ + logging.disable(level) + yield + logging.disable(logging.NOTSET) + + # # Custom field testing #