Просмотр исходного кода

test: Replace override_settings with explicit permission grants

Remove `@override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])` decorators
across test suites, replacing them with explicit `add_permissions()`
calls for required view permissions. Improves test clarity and ensures
permission checks are properly validated.

Fixes #22091
Martin Hauser 4 дней назад
Родитель
Сommit
9ec1633dac

+ 18 - 4
netbox/circuits/tests/test_views.py

@@ -1,7 +1,6 @@
 import datetime
 import datetime
 
 
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.models import ContentType
-from django.test import override_settings
 from django.urls import reverse
 from django.urls import reverse
 
 
 from circuits.choices import *
 from circuits.choices import *
@@ -210,8 +209,13 @@ class CircuitTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         self.assertContains(response, circuit_type.name)
         self.assertContains(response, circuit_type.name)
         self.assertContains(response, 'background-color: #12ab34')
         self.assertContains(response, 'background-color: #12ab34')
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'], EXEMPT_EXCLUDE_MODELS=[])
     def test_bulk_import_objects_with_terminations(self):
     def test_bulk_import_objects_with_terminations(self):
+        self.add_permissions(
+            'circuits.view_circuit',
+            'circuits.view_provider',
+            'circuits.view_circuittype',
+            'dcim.view_site',
+        )
         site = Site.objects.first()
         site = Site.objects.first()
         json_data = f"""
         json_data = f"""
             [
             [
@@ -420,8 +424,13 @@ class CircuitTerminationTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             'description': 'New description',
             'description': 'New description',
         }
         }
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_trace(self):
     def test_trace(self):
+        self.add_permissions(
+            'circuits.view_circuittermination',
+            'dcim.view_cable',
+            'dcim.view_interface',
+            'dcim.view_device',
+        )
         device = create_test_device('Device 1')
         device = create_test_device('Device 1')
 
 
         circuittermination = CircuitTermination.objects.first()
         circuittermination = CircuitTermination.objects.first()
@@ -711,8 +720,13 @@ class VirtualCircuitTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             'comments': 'New comments',
             'comments': 'New comments',
         }
         }
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'], EXEMPT_EXCLUDE_MODELS=[])
     def test_bulk_import_objects_with_terminations(self):
     def test_bulk_import_objects_with_terminations(self):
+        self.add_permissions(
+            'circuits.view_virtualcircuit',
+            'circuits.view_providernetwork',
+            'circuits.view_virtualcircuittype',
+            'dcim.view_interface',
+        )
         interfaces = Interface.objects.filter(type=InterfaceTypeChoices.TYPE_VIRTUAL)
         interfaces = Interface.objects.filter(type=InterfaceTypeChoices.TYPE_VIRTUAL)
         json_data = f"""
         json_data = f"""
             [
             [

+ 2 - 2
netbox/dcim/tests/test_api.py

@@ -1,7 +1,7 @@
 import json
 import json
 
 
 from django.conf import settings
 from django.conf import settings
-from django.test import override_settings, tag
+from django.test import tag
 from django.urls import reverse
 from django.urls import reverse
 from django.utils.translation import gettext as _
 from django.utils.translation import gettext as _
 from rest_framework import status
 from rest_framework import status
@@ -3525,8 +3525,8 @@ class ConnectedDeviceTestCase(APITestCase):
         cable = Cable(a_terminations=[interfaces[0]], b_terminations=[interfaces[1]])
         cable = Cable(a_terminations=[interfaces[0]], b_terminations=[interfaces[1]])
         cable.save()
         cable.save()
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_get_connected_device(self):
     def test_get_connected_device(self):
+        self.add_permissions('dcim.view_device', 'dcim.view_interface')
         url = reverse('dcim-api:connected-device-list')
         url = reverse('dcim-api:connected-device-list')
 
 
         url_params = '?peer_device=TestDevice1&peer_interface=eth0'
         url_params = '?peer_device=TestDevice1&peer_interface=eth0'

+ 139 - 57
netbox/dcim/tests/test_views.py

@@ -622,11 +622,11 @@ class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             'comments': 'New comments',
             'comments': 'New comments',
         }
         }
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_list_rack_elevations(self):
     def test_list_rack_elevations(self):
         """
         """
         Test viewing the list of rack elevations.
         Test viewing the list of rack elevations.
         """
         """
+        self.add_permissions('dcim.view_rack')
         response = self.client.get(reverse('dcim:rack_elevation_list'))
         response = self.client.get(reverse('dcim:rack_elevation_list'))
         self.assertHttpStatus(response, 200)
         self.assertHttpStatus(response, 200)
 
 
@@ -730,8 +730,8 @@ class DeviceTypeTestCase(
             'is_full_depth': False,
             'is_full_depth': False,
         }
         }
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_devicetype_consoleports(self):
     def test_devicetype_consoleports(self):
+        self.add_permissions('dcim.view_devicetype', 'dcim.view_consoleporttemplate')
         devicetype = DeviceType.objects.first()
         devicetype = DeviceType.objects.first()
         console_ports = (
         console_ports = (
             ConsolePortTemplate(device_type=devicetype, name='Console Port 1'),
             ConsolePortTemplate(device_type=devicetype, name='Console Port 1'),
@@ -743,8 +743,8 @@ class DeviceTypeTestCase(
         url = reverse('dcim:devicetype_consoleports', kwargs={'pk': devicetype.pk})
         url = reverse('dcim:devicetype_consoleports', kwargs={'pk': devicetype.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_devicetype_consoleserverports(self):
     def test_devicetype_consoleserverports(self):
+        self.add_permissions('dcim.view_devicetype', 'dcim.view_consoleserverporttemplate')
         devicetype = DeviceType.objects.first()
         devicetype = DeviceType.objects.first()
         console_server_ports = (
         console_server_ports = (
             ConsoleServerPortTemplate(device_type=devicetype, name='Console Server Port 1'),
             ConsoleServerPortTemplate(device_type=devicetype, name='Console Server Port 1'),
@@ -756,8 +756,8 @@ class DeviceTypeTestCase(
         url = reverse('dcim:devicetype_consoleserverports', kwargs={'pk': devicetype.pk})
         url = reverse('dcim:devicetype_consoleserverports', kwargs={'pk': devicetype.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_devicetype_powerports(self):
     def test_devicetype_powerports(self):
+        self.add_permissions('dcim.view_devicetype', 'dcim.view_powerporttemplate')
         devicetype = DeviceType.objects.first()
         devicetype = DeviceType.objects.first()
         power_ports = (
         power_ports = (
             PowerPortTemplate(device_type=devicetype, name='Power Port 1'),
             PowerPortTemplate(device_type=devicetype, name='Power Port 1'),
@@ -769,8 +769,8 @@ class DeviceTypeTestCase(
         url = reverse('dcim:devicetype_powerports', kwargs={'pk': devicetype.pk})
         url = reverse('dcim:devicetype_powerports', kwargs={'pk': devicetype.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_devicetype_poweroutlets(self):
     def test_devicetype_poweroutlets(self):
+        self.add_permissions('dcim.view_devicetype', 'dcim.view_poweroutlettemplate')
         devicetype = DeviceType.objects.first()
         devicetype = DeviceType.objects.first()
         power_outlets = (
         power_outlets = (
             PowerOutletTemplate(device_type=devicetype, name='Power Outlet 1'),
             PowerOutletTemplate(device_type=devicetype, name='Power Outlet 1'),
@@ -782,8 +782,8 @@ class DeviceTypeTestCase(
         url = reverse('dcim:devicetype_poweroutlets', kwargs={'pk': devicetype.pk})
         url = reverse('dcim:devicetype_poweroutlets', kwargs={'pk': devicetype.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_devicetype_interfaces(self):
     def test_devicetype_interfaces(self):
+        self.add_permissions('dcim.view_devicetype', 'dcim.view_interfacetemplate')
         devicetype = DeviceType.objects.first()
         devicetype = DeviceType.objects.first()
         interfaces = (
         interfaces = (
             InterfaceTemplate(device_type=devicetype, name='Interface 1'),
             InterfaceTemplate(device_type=devicetype, name='Interface 1'),
@@ -795,8 +795,8 @@ class DeviceTypeTestCase(
         url = reverse('dcim:devicetype_interfaces', kwargs={'pk': devicetype.pk})
         url = reverse('dcim:devicetype_interfaces', kwargs={'pk': devicetype.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_devicetype_rearports(self):
     def test_devicetype_rearports(self):
+        self.add_permissions('dcim.view_devicetype', 'dcim.view_rearporttemplate')
         devicetype = DeviceType.objects.first()
         devicetype = DeviceType.objects.first()
         rear_ports = (
         rear_ports = (
             RearPortTemplate(device_type=devicetype, name='Rear Port 1'),
             RearPortTemplate(device_type=devicetype, name='Rear Port 1'),
@@ -808,8 +808,12 @@ class DeviceTypeTestCase(
         url = reverse('dcim:devicetype_rearports', kwargs={'pk': devicetype.pk})
         url = reverse('dcim:devicetype_rearports', kwargs={'pk': devicetype.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_devicetype_frontports(self):
     def test_devicetype_frontports(self):
+        self.add_permissions(
+            'dcim.view_devicetype',
+            'dcim.view_frontporttemplate',
+            'dcim.view_rearporttemplate',
+        )
         devicetype = DeviceType.objects.first()
         devicetype = DeviceType.objects.first()
         rear_ports = (
         rear_ports = (
             RearPortTemplate(device_type=devicetype, name='Rear Port 1'),
             RearPortTemplate(device_type=devicetype, name='Rear Port 1'),
@@ -832,8 +836,8 @@ class DeviceTypeTestCase(
         url = reverse('dcim:devicetype_frontports', kwargs={'pk': devicetype.pk})
         url = reverse('dcim:devicetype_frontports', kwargs={'pk': devicetype.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_devicetype_modulebays(self):
     def test_devicetype_modulebays(self):
+        self.add_permissions('dcim.view_devicetype', 'dcim.view_modulebaytemplate')
         devicetype = DeviceType.objects.first()
         devicetype = DeviceType.objects.first()
         module_bays = (
         module_bays = (
             ModuleBayTemplate(device_type=devicetype, name='Module Bay 1'),
             ModuleBayTemplate(device_type=devicetype, name='Module Bay 1'),
@@ -845,8 +849,8 @@ class DeviceTypeTestCase(
         url = reverse('dcim:devicetype_modulebays', kwargs={'pk': devicetype.pk})
         url = reverse('dcim:devicetype_modulebays', kwargs={'pk': devicetype.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_devicetype_devicebays(self):
     def test_devicetype_devicebays(self):
+        self.add_permissions('dcim.view_devicetype', 'dcim.view_devicebaytemplate')
         devicetype = DeviceType.objects.first()
         devicetype = DeviceType.objects.first()
         device_bays = (
         device_bays = (
             DeviceBayTemplate(device_type=devicetype, name='Device Bay 1'),
             DeviceBayTemplate(device_type=devicetype, name='Device Bay 1'),
@@ -858,8 +862,8 @@ class DeviceTypeTestCase(
         url = reverse('dcim:devicetype_devicebays', kwargs={'pk': devicetype.pk})
         url = reverse('dcim:devicetype_devicebays', kwargs={'pk': devicetype.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_devicetype_inventoryitems(self):
     def test_devicetype_inventoryitems(self):
+        self.add_permissions('dcim.view_devicetype', 'dcim.view_inventoryitemtemplate')
         devicetype = DeviceType.objects.first()
         devicetype = DeviceType.objects.first()
         inventory_items = (
         inventory_items = (
             DeviceBayTemplate(device_type=devicetype, name='Device Bay 1'),
             DeviceBayTemplate(device_type=devicetype, name='Device Bay 1'),
@@ -872,11 +876,11 @@ class DeviceTypeTestCase(
         url = reverse('dcim:devicetype_inventoryitems', kwargs={'pk': devicetype.pk})
         url = reverse('dcim:devicetype_inventoryitems', kwargs={'pk': devicetype.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_import_objects(self):
     def test_import_objects(self):
         """
         """
         Custom import test for YAML-based imports (versus CSV)
         Custom import test for YAML-based imports (versus CSV)
         """
         """
+        self.add_permissions('dcim.view_manufacturer', 'dcim.view_platform')
         IMPORT_DATA = """
         IMPORT_DATA = """
 manufacturer: Generic
 manufacturer: Generic
 model: TEST-1000
 model: TEST-1000
@@ -1070,12 +1074,12 @@ inventory-items:
         ii1 = InventoryItemTemplate.objects.first()
         ii1 = InventoryItemTemplate.objects.first()
         self.assertEqual(ii1.name, 'Inventory Item 1')
         self.assertEqual(ii1.name, 'Inventory Item 1')
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_import_error_numbering(self):
     def test_import_error_numbering(self):
         # Add all required permissions to the test user
         # Add all required permissions to the test user
         self.add_permissions(
         self.add_permissions(
             'dcim.view_devicetype',
             'dcim.view_devicetype',
             'dcim.add_devicetype',
             'dcim.add_devicetype',
+            'dcim.view_manufacturer',
             'dcim.add_consoleporttemplate',
             'dcim.add_consoleporttemplate',
             'dcim.add_consoleserverporttemplate',
             'dcim.add_consoleserverporttemplate',
             'dcim.add_powerporttemplate',
             'dcim.add_powerporttemplate',
@@ -1122,12 +1126,12 @@ module-bays:
         self.assertHttpStatus(response, 200)
         self.assertHttpStatus(response, 200)
         self.assertContains(response, "Record 2 module-bays[3].name: This field is required.")
         self.assertContains(response, "Record 2 module-bays[3].name: This field is required.")
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_import_nolist(self):
     def test_import_nolist(self):
         # Add all required permissions to the test user
         # Add all required permissions to the test user
         self.add_permissions(
         self.add_permissions(
             'dcim.view_devicetype',
             'dcim.view_devicetype',
             'dcim.add_devicetype',
             'dcim.add_devicetype',
+            'dcim.view_manufacturer',
             'dcim.add_consoleporttemplate',
             'dcim.add_consoleporttemplate',
             'dcim.add_consoleserverporttemplate',
             'dcim.add_consoleserverporttemplate',
             'dcim.add_powerporttemplate',
             'dcim.add_powerporttemplate',
@@ -1158,12 +1162,12 @@ console-ports: {value}
                 self.assertHttpStatus(response, 200)
                 self.assertHttpStatus(response, 200)
                 self.assertContains(response, "Record 1 console-ports: Must be a list.")
                 self.assertContains(response, "Record 1 console-ports: Must be a list.")
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_import_nodict(self):
     def test_import_nodict(self):
         # Add all required permissions to the test user
         # Add all required permissions to the test user
         self.add_permissions(
         self.add_permissions(
             'dcim.view_devicetype',
             'dcim.view_devicetype',
             'dcim.add_devicetype',
             'dcim.add_devicetype',
+            'dcim.view_manufacturer',
             'dcim.add_consoleporttemplate',
             'dcim.add_consoleporttemplate',
             'dcim.add_consoleserverporttemplate',
             'dcim.add_consoleserverporttemplate',
             'dcim.add_powerporttemplate',
             'dcim.add_powerporttemplate',
@@ -1264,7 +1268,6 @@ class ModuleTypeTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             f"{module_types[0].id},test model",
             f"{module_types[0].id},test model",
         )
         )
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_bulk_update_objects_with_permission(self):
     def test_bulk_update_objects_with_permission(self):
         self.add_permissions(
         self.add_permissions(
             'dcim.add_consoleporttemplate',
             'dcim.add_consoleporttemplate',
@@ -1281,7 +1284,6 @@ class ModuleTypeTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         super().test_bulk_update_objects_with_permission()
         super().test_bulk_update_objects_with_permission()
 
 
     @tag('regression')
     @tag('regression')
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'], EXEMPT_EXCLUDE_MODELS=[])
     def test_bulk_import_objects_with_permission(self):
     def test_bulk_import_objects_with_permission(self):
         self.add_permissions(
         self.add_permissions(
             'dcim.add_consoleporttemplate',
             'dcim.add_consoleporttemplate',
@@ -1303,7 +1305,6 @@ class ModuleTypeTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         # run base test
         # run base test
         super().test_bulk_import_objects_with_permission(post_import_callback=verify_module_type_profile)
         super().test_bulk_import_objects_with_permission(post_import_callback=verify_module_type_profile)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'], EXEMPT_EXCLUDE_MODELS=[])
     def test_bulk_import_objects_with_constrained_permission(self):
     def test_bulk_import_objects_with_constrained_permission(self):
         self.add_permissions(
         self.add_permissions(
             'dcim.add_consoleporttemplate',
             'dcim.add_consoleporttemplate',
@@ -1318,8 +1319,8 @@ class ModuleTypeTestCase(ViewTestCases.PrimaryObjectViewTestCase):
 
 
         super().test_bulk_import_objects_with_constrained_permission()
         super().test_bulk_import_objects_with_constrained_permission()
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_moduletype_consoleports(self):
     def test_moduletype_consoleports(self):
+        self.add_permissions('dcim.view_moduletype', 'dcim.view_consoleporttemplate')
         moduletype = ModuleType.objects.first()
         moduletype = ModuleType.objects.first()
         console_ports = (
         console_ports = (
             ConsolePortTemplate(module_type=moduletype, name='Console Port 1'),
             ConsolePortTemplate(module_type=moduletype, name='Console Port 1'),
@@ -1331,8 +1332,8 @@ class ModuleTypeTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         url = reverse('dcim:moduletype_consoleports', kwargs={'pk': moduletype.pk})
         url = reverse('dcim:moduletype_consoleports', kwargs={'pk': moduletype.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_moduletype_consoleserverports(self):
     def test_moduletype_consoleserverports(self):
+        self.add_permissions('dcim.view_moduletype', 'dcim.view_consoleserverporttemplate')
         moduletype = ModuleType.objects.first()
         moduletype = ModuleType.objects.first()
         console_server_ports = (
         console_server_ports = (
             ConsoleServerPortTemplate(module_type=moduletype, name='Console Server Port 1'),
             ConsoleServerPortTemplate(module_type=moduletype, name='Console Server Port 1'),
@@ -1344,8 +1345,8 @@ class ModuleTypeTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         url = reverse('dcim:moduletype_consoleserverports', kwargs={'pk': moduletype.pk})
         url = reverse('dcim:moduletype_consoleserverports', kwargs={'pk': moduletype.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_moduletype_powerports(self):
     def test_moduletype_powerports(self):
+        self.add_permissions('dcim.view_moduletype', 'dcim.view_powerporttemplate')
         moduletype = ModuleType.objects.first()
         moduletype = ModuleType.objects.first()
         power_ports = (
         power_ports = (
             PowerPortTemplate(module_type=moduletype, name='Power Port 1'),
             PowerPortTemplate(module_type=moduletype, name='Power Port 1'),
@@ -1357,8 +1358,8 @@ class ModuleTypeTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         url = reverse('dcim:moduletype_powerports', kwargs={'pk': moduletype.pk})
         url = reverse('dcim:moduletype_powerports', kwargs={'pk': moduletype.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_moduletype_poweroutlets(self):
     def test_moduletype_poweroutlets(self):
+        self.add_permissions('dcim.view_moduletype', 'dcim.view_poweroutlettemplate')
         moduletype = ModuleType.objects.first()
         moduletype = ModuleType.objects.first()
         power_outlets = (
         power_outlets = (
             PowerOutletTemplate(module_type=moduletype, name='Power Outlet 1'),
             PowerOutletTemplate(module_type=moduletype, name='Power Outlet 1'),
@@ -1370,8 +1371,8 @@ class ModuleTypeTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         url = reverse('dcim:moduletype_poweroutlets', kwargs={'pk': moduletype.pk})
         url = reverse('dcim:moduletype_poweroutlets', kwargs={'pk': moduletype.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_moduletype_interfaces(self):
     def test_moduletype_interfaces(self):
+        self.add_permissions('dcim.view_moduletype', 'dcim.view_interfacetemplate')
         moduletype = ModuleType.objects.first()
         moduletype = ModuleType.objects.first()
         interfaces = (
         interfaces = (
             InterfaceTemplate(module_type=moduletype, name='Interface 1'),
             InterfaceTemplate(module_type=moduletype, name='Interface 1'),
@@ -1383,8 +1384,8 @@ class ModuleTypeTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         url = reverse('dcim:moduletype_interfaces', kwargs={'pk': moduletype.pk})
         url = reverse('dcim:moduletype_interfaces', kwargs={'pk': moduletype.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_moduletype_rearports(self):
     def test_moduletype_rearports(self):
+        self.add_permissions('dcim.view_moduletype', 'dcim.view_rearporttemplate')
         moduletype = ModuleType.objects.first()
         moduletype = ModuleType.objects.first()
         rear_ports = (
         rear_ports = (
             RearPortTemplate(module_type=moduletype, name='Rear Port 1'),
             RearPortTemplate(module_type=moduletype, name='Rear Port 1'),
@@ -1396,8 +1397,12 @@ class ModuleTypeTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         url = reverse('dcim:moduletype_rearports', kwargs={'pk': moduletype.pk})
         url = reverse('dcim:moduletype_rearports', kwargs={'pk': moduletype.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_moduletype_frontports(self):
     def test_moduletype_frontports(self):
+        self.add_permissions(
+            'dcim.view_moduletype',
+            'dcim.view_frontporttemplate',
+            'dcim.view_rearporttemplate',
+        )
         moduletype = ModuleType.objects.first()
         moduletype = ModuleType.objects.first()
         rear_ports = (
         rear_ports = (
             RearPortTemplate(module_type=moduletype, name='Rear Port 1'),
             RearPortTemplate(module_type=moduletype, name='Rear Port 1'),
@@ -1420,11 +1425,11 @@ class ModuleTypeTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         url = reverse('dcim:moduletype_frontports', kwargs={'pk': moduletype.pk})
         url = reverse('dcim:moduletype_frontports', kwargs={'pk': moduletype.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_import_objects(self):
     def test_import_objects(self):
         """
         """
         Custom import test for YAML-based imports (versus CSV)
         Custom import test for YAML-based imports (versus CSV)
         """
         """
+        self.add_permissions('dcim.view_manufacturer')
         IMPORT_DATA = """
         IMPORT_DATA = """
 manufacturer: Generic
 manufacturer: Generic
 model: TEST-1000
 model: TEST-1000
@@ -2289,8 +2294,8 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             'status': DeviceStatusChoices.STATUS_DECOMMISSIONING,
             'status': DeviceStatusChoices.STATUS_DECOMMISSIONING,
         }
         }
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_device_consoleports(self):
     def test_device_consoleports(self):
+        self.add_permissions('dcim.view_device', 'dcim.view_consoleport')
         device = Device.objects.first()
         device = Device.objects.first()
         console_ports = (
         console_ports = (
             ConsolePort(device=device, name='Console Port 1'),
             ConsolePort(device=device, name='Console Port 1'),
@@ -2302,8 +2307,8 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         url = reverse('dcim:device_consoleports', kwargs={'pk': device.pk})
         url = reverse('dcim:device_consoleports', kwargs={'pk': device.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_device_consoleserverports(self):
     def test_device_consoleserverports(self):
+        self.add_permissions('dcim.view_device', 'dcim.view_consoleserverport')
         device = Device.objects.first()
         device = Device.objects.first()
         console_server_ports = (
         console_server_ports = (
             ConsoleServerPort(device=device, name='Console Server Port 1'),
             ConsoleServerPort(device=device, name='Console Server Port 1'),
@@ -2315,8 +2320,8 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         url = reverse('dcim:device_consoleserverports', kwargs={'pk': device.pk})
         url = reverse('dcim:device_consoleserverports', kwargs={'pk': device.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_device_powerports(self):
     def test_device_powerports(self):
+        self.add_permissions('dcim.view_device', 'dcim.view_powerport')
         device = Device.objects.first()
         device = Device.objects.first()
         power_ports = (
         power_ports = (
             PowerPort(device=device, name='Power Port 1'),
             PowerPort(device=device, name='Power Port 1'),
@@ -2328,8 +2333,8 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         url = reverse('dcim:device_powerports', kwargs={'pk': device.pk})
         url = reverse('dcim:device_powerports', kwargs={'pk': device.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_device_poweroutlets(self):
     def test_device_poweroutlets(self):
+        self.add_permissions('dcim.view_device', 'dcim.view_poweroutlet')
         device = Device.objects.first()
         device = Device.objects.first()
         power_outlets = (
         power_outlets = (
             PowerOutlet(device=device, name='Power Outlet 1'),
             PowerOutlet(device=device, name='Power Outlet 1'),
@@ -2341,8 +2346,8 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         url = reverse('dcim:device_poweroutlets', kwargs={'pk': device.pk})
         url = reverse('dcim:device_poweroutlets', kwargs={'pk': device.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_device_interfaces(self):
     def test_device_interfaces(self):
+        self.add_permissions('dcim.view_device', 'dcim.view_interface')
         device = Device.objects.first()
         device = Device.objects.first()
         interfaces = (
         interfaces = (
             Interface(device=device, name='Interface 1'),
             Interface(device=device, name='Interface 1'),
@@ -2354,8 +2359,8 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         url = reverse('dcim:device_interfaces', kwargs={'pk': device.pk})
         url = reverse('dcim:device_interfaces', kwargs={'pk': device.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_device_rearports(self):
     def test_device_rearports(self):
+        self.add_permissions('dcim.view_device', 'dcim.view_rearport')
         device = Device.objects.first()
         device = Device.objects.first()
         rear_ports = (
         rear_ports = (
             RearPort(device=device, name='Rear Port 1'),
             RearPort(device=device, name='Rear Port 1'),
@@ -2367,8 +2372,8 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         url = reverse('dcim:device_rearports', kwargs={'pk': device.pk})
         url = reverse('dcim:device_rearports', kwargs={'pk': device.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_device_frontports(self):
     def test_device_frontports(self):
+        self.add_permissions('dcim.view_device', 'dcim.view_frontport', 'dcim.view_rearport')
         device = Device.objects.first()
         device = Device.objects.first()
         rear_ports = (
         rear_ports = (
             RearPort(device=device, name='Rear Port 1'),
             RearPort(device=device, name='Rear Port 1'),
@@ -2391,8 +2396,8 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         url = reverse('dcim:device_frontports', kwargs={'pk': device.pk})
         url = reverse('dcim:device_frontports', kwargs={'pk': device.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_device_modulebays(self):
     def test_device_modulebays(self):
+        self.add_permissions('dcim.view_device', 'dcim.view_modulebay')
         device = Device.objects.first()
         device = Device.objects.first()
         ModuleBay.objects.create(device=device, name='Module Bay 1')
         ModuleBay.objects.create(device=device, name='Module Bay 1')
         ModuleBay.objects.create(device=device, name='Module Bay 2')
         ModuleBay.objects.create(device=device, name='Module Bay 2')
@@ -2401,8 +2406,8 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         url = reverse('dcim:device_modulebays', kwargs={'pk': device.pk})
         url = reverse('dcim:device_modulebays', kwargs={'pk': device.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_device_devicebays(self):
     def test_device_devicebays(self):
+        self.add_permissions('dcim.view_device', 'dcim.view_devicebay')
         device = Device.objects.first()
         device = Device.objects.first()
         device_bays = (
         device_bays = (
             DeviceBay(device=device, name='Device Bay 1'),
             DeviceBay(device=device, name='Device Bay 1'),
@@ -2414,8 +2419,8 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         url = reverse('dcim:device_devicebays', kwargs={'pk': device.pk})
         url = reverse('dcim:device_devicebays', kwargs={'pk': device.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_device_inventory(self):
     def test_device_inventory(self):
+        self.add_permissions('dcim.view_device', 'dcim.view_inventoryitem')
         device = Device.objects.first()
         device = Device.objects.first()
         inventory_items = (
         inventory_items = (
             InventoryItem(device=device, name='Inventory Item 1'),
             InventoryItem(device=device, name='Inventory Item 1'),
@@ -2504,7 +2509,6 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         self.assertContains(response, 'background-color: #aa00bb')
         self.assertContains(response, 'background-color: #aa00bb')
         self.assertNotContains(response, 'background-color: #111111')
         self.assertNotContains(response, 'background-color: #111111')
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_bulk_import_duplicate_ids_error_message(self):
     def test_bulk_import_duplicate_ids_error_message(self):
         device = Device.objects.first()
         device = Device.objects.first()
         csv_data = (
         csv_data = (
@@ -2513,7 +2517,12 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             f"{device.pk},Device Role 2",
             f"{device.pk},Device Role 2",
         )
         )
 
 
-        self.add_permissions('dcim.add_device', 'dcim.change_device')
+        self.add_permissions(
+            'dcim.view_device',
+            'dcim.add_device',
+            'dcim.change_device',
+            'dcim.view_devicerole',
+        )
         response = self.client.post(
         response = self.client.post(
             self._get_url('bulk_import'),
             self._get_url('bulk_import'),
             {
             {
@@ -2615,15 +2624,26 @@ class ModuleTestCase(
             f"{modules[2].pk},offline,Serial 1",
             f"{modules[2].pk},offline,Serial 1",
         )
         )
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_module_detail_includes_module_type_profile(self):
     def test_module_detail_includes_module_type_profile(self):
+        self.add_permissions(
+            'dcim.view_module',
+            'dcim.view_moduletype',
+            'dcim.view_moduletypeprofile',
+        )
         response = self.client.get(self._get_queryset().first().get_absolute_url())
         response = self.client.get(self._get_queryset().first().get_absolute_url())
 
 
         self.assertContains(response, 'Module Type Profile 1')
         self.assertContains(response, 'Module Type Profile 1')
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_module_component_replication(self):
     def test_module_component_replication(self):
-        self.add_permissions('dcim.add_module')
+        self.add_permissions(
+            'dcim.view_module',
+            'dcim.add_module',
+            'dcim.view_moduletype',
+            'dcim.view_device',
+            'dcim.view_modulebay',
+            'dcim.view_interface',
+            'extras.view_tag',
+        )
 
 
         # Add 5 InterfaceTemplates to a ModuleType
         # Add 5 InterfaceTemplates to a ModuleType
         module_type = ModuleType.objects.first()
         module_type = ModuleType.objects.first()
@@ -2654,9 +2674,15 @@ class ModuleTestCase(
         self.assertHttpStatus(self.client.post(**request), 302)
         self.assertHttpStatus(self.client.post(**request), 302)
         self.assertEqual(Interface.objects.filter(device=device).count(), 5)
         self.assertEqual(Interface.objects.filter(device=device).count(), 5)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_module_bulk_replication(self):
     def test_module_bulk_replication(self):
-        self.add_permissions('dcim.add_module')
+        self.add_permissions(
+            'dcim.view_module',
+            'dcim.add_module',
+            'dcim.view_moduletype',
+            'dcim.view_device',
+            'dcim.view_modulebay',
+            'dcim.view_interface',
+        )
 
 
         # Add 5 InterfaceTemplates to a ModuleType
         # Add 5 InterfaceTemplates to a ModuleType
         module_type = ModuleType.objects.first()
         module_type = ModuleType.objects.first()
@@ -2704,9 +2730,17 @@ class ModuleTestCase(
         self.assertEqual(Module.objects.count(), initial_count + len(csv_data) - 1)
         self.assertEqual(Module.objects.count(), initial_count + len(csv_data) - 1)
         self.assertEqual(Interface.objects.filter(device=device).count(), 5)
         self.assertEqual(Interface.objects.filter(device=device).count(), 5)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_module_component_adoption(self):
     def test_module_component_adoption(self):
-        self.add_permissions('dcim.add_module')
+        self.add_permissions(
+            'dcim.view_module',
+            'dcim.add_module',
+            'dcim.view_moduletype',
+            'dcim.view_device',
+            'dcim.view_modulebay',
+            'dcim.view_interface',
+            'dcim.change_interface',
+            'extras.view_tag',
+        )
 
 
         interface_name = "Interface-1"
         interface_name = "Interface-1"
 
 
@@ -2741,9 +2775,16 @@ class ModuleTestCase(
         # Check that the Interface now has a module
         # Check that the Interface now has a module
         self.assertIsNotNone(interface.module)
         self.assertIsNotNone(interface.module)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_module_bulk_adoption(self):
     def test_module_bulk_adoption(self):
-        self.add_permissions('dcim.add_module')
+        self.add_permissions(
+            'dcim.view_module',
+            'dcim.add_module',
+            'dcim.view_moduletype',
+            'dcim.view_device',
+            'dcim.view_modulebay',
+            'dcim.view_interface',
+            'dcim.change_interface',
+        )
 
 
         interface_name = "Interface-1"
         interface_name = "Interface-1"
 
 
@@ -2841,8 +2882,8 @@ class ConsolePortTestCase(ViewTestCases.DeviceComponentViewTestCase):
             f"{console_ports[2].pk},Console Port 9,New description9",
             f"{console_ports[2].pk},Console Port 9,New description9",
         )
         )
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'], EXEMPT_EXCLUDE_MODELS=[])
     def test_bulk_add_components_with_changelog_message(self):
     def test_bulk_add_components_with_changelog_message(self):
+        self.add_permissions('dcim.view_consoleport', 'dcim.view_device')
         device1 = Device.objects.get(name='Device 1')
         device1 = Device.objects.get(name='Device 1')
         device2 = create_test_device('Device 2')
         device2 = create_test_device('Device 2')
         changelog_message = 'Bulk-created console ports'
         changelog_message = 'Bulk-created console ports'
@@ -2885,8 +2926,13 @@ class ConsolePortTestCase(ViewTestCases.DeviceComponentViewTestCase):
         for objectchange in objectchanges:
         for objectchange in objectchanges:
             self.assertEqual(objectchange.message, changelog_message)
             self.assertEqual(objectchange.message, changelog_message)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_trace(self):
     def test_trace(self):
+        self.add_permissions(
+            'dcim.view_consoleport',
+            'dcim.view_consoleserverport',
+            'dcim.view_cable',
+            'dcim.view_device',
+        )
         consoleport = ConsolePort.objects.first()
         consoleport = ConsolePort.objects.first()
         consoleserverport = ConsoleServerPort.objects.create(
         consoleserverport = ConsoleServerPort.objects.create(
             device=consoleport.device,
             device=consoleport.device,
@@ -2950,8 +2996,13 @@ class ConsoleServerPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
             f"{console_server_ports[2].pk},Console Server Port 9,New description 9",
             f"{console_server_ports[2].pk},Console Server Port 9,New description 9",
         )
         )
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_trace(self):
     def test_trace(self):
+        self.add_permissions(
+            'dcim.view_consoleserverport',
+            'dcim.view_consoleport',
+            'dcim.view_cable',
+            'dcim.view_device',
+        )
         consoleserverport = ConsoleServerPort.objects.first()
         consoleserverport = ConsoleServerPort.objects.first()
         consoleport = ConsolePort.objects.create(
         consoleport = ConsolePort.objects.create(
             device=consoleserverport.device,
             device=consoleserverport.device,
@@ -3021,8 +3072,13 @@ class PowerPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
             f"{power_ports[2].pk},Power Port 9,New description9",
             f"{power_ports[2].pk},Power Port 9,New description9",
         )
         )
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_trace(self):
     def test_trace(self):
+        self.add_permissions(
+            'dcim.view_powerport',
+            'dcim.view_poweroutlet',
+            'dcim.view_cable',
+            'dcim.view_device',
+        )
         powerport = PowerPort.objects.first()
         powerport = PowerPort.objects.first()
         poweroutlet = PowerOutlet.objects.create(
         poweroutlet = PowerOutlet.objects.create(
             device=powerport.device,
             device=powerport.device,
@@ -3101,8 +3157,13 @@ class PowerOutletTestCase(ViewTestCases.DeviceComponentViewTestCase):
             f"{power_outlets[2].pk},Power Outlet 9,New description9",
             f"{power_outlets[2].pk},Power Outlet 9,New description9",
         )
         )
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_trace(self):
     def test_trace(self):
+        self.add_permissions(
+            'dcim.view_poweroutlet',
+            'dcim.view_powerport',
+            'dcim.view_cable',
+            'dcim.view_device',
+        )
         poweroutlet = PowerOutlet.objects.first()
         poweroutlet = PowerOutlet.objects.first()
         powerport = PowerPort.objects.first()
         powerport = PowerPort.objects.first()
         Cable(a_terminations=[poweroutlet], b_terminations=[powerport]).save()
         Cable(a_terminations=[poweroutlet], b_terminations=[powerport]).save()
@@ -3240,8 +3301,12 @@ class InterfaceTestCase(ViewTestCases.DeviceComponentViewTestCase):
             f"{interfaces[2].pk},Interface 9,New description9",
             f"{interfaces[2].pk},Interface 9,New description9",
         )
         )
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_trace(self):
     def test_trace(self):
+        self.add_permissions(
+            'dcim.view_interface',
+            'dcim.view_cable',
+            'dcim.view_device',
+        )
         interface1, interface2 = Interface.objects.all()[:2]
         interface1, interface2 = Interface.objects.all()[:2]
         Cable(a_terminations=[interface1], b_terminations=[interface2]).save()
         Cable(a_terminations=[interface1], b_terminations=[interface2]).save()
 
 
@@ -3387,8 +3452,14 @@ class FrontPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
             f"{front_ports[2].pk},Front Port 9,New description9",
             f"{front_ports[2].pk},Front Port 9,New description9",
         )
         )
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_trace(self):
     def test_trace(self):
+        self.add_permissions(
+            'dcim.view_frontport',
+            'dcim.view_rearport',
+            'dcim.view_interface',
+            'dcim.view_cable',
+            'dcim.view_device',
+        )
         frontport = FrontPort.objects.first()
         frontport = FrontPort.objects.first()
         interface = Interface.objects.create(
         interface = Interface.objects.create(
             device=frontport.device,
             device=frontport.device,
@@ -3454,8 +3525,14 @@ class RearPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
             f"{rear_ports[2].pk},Rear Port 9,New description9",
             f"{rear_ports[2].pk},Rear Port 9,New description9",
         )
         )
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_trace(self):
     def test_trace(self):
+        self.add_permissions(
+            'dcim.view_rearport',
+            'dcim.view_frontport',
+            'dcim.view_interface',
+            'dcim.view_cable',
+            'dcim.view_device',
+        )
         rearport = RearPort.objects.first()
         rearport = RearPort.objects.first()
         interface = Interface.objects.create(
         interface = Interface.objects.create(
             device=rearport.device,
             device=rearport.device,
@@ -4108,8 +4185,13 @@ class PowerFeedTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             'comments': 'New comments',
             'comments': 'New comments',
         }
         }
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_trace(self):
     def test_trace(self):
+        self.add_permissions(
+            'dcim.view_powerfeed',
+            'dcim.view_powerport',
+            'dcim.view_cable',
+            'dcim.view_device',
+        )
         manufacturer = Manufacturer.objects.create(name='Manufacturer', slug='manufacturer-1')
         manufacturer = Manufacturer.objects.create(name='Manufacturer', slug='manufacturer-1')
         device_type = DeviceType.objects.create(
         device_type = DeviceType.objects.create(
             manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'
             manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'
@@ -4255,12 +4337,12 @@ class MACAddressTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         }
         }
 
 
     @tag('regression')  # Issue #20542
     @tag('regression')  # Issue #20542
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'], EXEMPT_EXCLUDE_MODELS=[])
     def test_create_macaddress_via_quickadd(self):
     def test_create_macaddress_via_quickadd(self):
         """
         """
         Test creating a MAC address via quick-add modal (e.g., from Interface form).
         Test creating a MAC address via quick-add modal (e.g., from Interface form).
         Regression test for issue #20542 where form prefix was missing in POST handler.
         Regression test for issue #20542 where form prefix was missing in POST handler.
         """
         """
+        self.add_permissions('dcim.view_macaddress', 'dcim.view_interface', 'extras.view_tag')
         obj_perm = ObjectPermission(name='Test permission', actions=['add'])
         obj_perm = ObjectPermission(name='Test permission', actions=['add'])
         obj_perm.save()
         obj_perm.save()
         obj_perm.users.add(self.user)
         obj_perm.users.add(self.user)

+ 24 - 21
netbox/ipam/tests/test_views.py

@@ -1,7 +1,6 @@
 import datetime
 import datetime
 
 
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.models import ContentType
-from django.test import override_settings
 from django.urls import reverse
 from django.urls import reverse
 from netaddr import IPNetwork
 from netaddr import IPNetwork
 
 
@@ -339,8 +338,8 @@ class AggregateTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             'description': 'New description',
             'description': 'New description',
         }
         }
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_aggregate_prefixes(self):
     def test_aggregate_prefixes(self):
+        self.add_permissions('ipam.view_aggregate', 'ipam.view_prefix')
         rir = RIR.objects.first()
         rir = RIR.objects.first()
         aggregate = Aggregate.objects.create(prefix=IPNetwork('192.168.0.0/16'), rir=rir)
         aggregate = Aggregate.objects.create(prefix=IPNetwork('192.168.0.0/16'), rir=rir)
         prefixes = (
         prefixes = (
@@ -476,9 +475,9 @@ class PrefixTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             'description': 'New description',
             'description': 'New description',
         }
         }
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_bulk_add_ipv4_prefixes(self):
     def test_bulk_add_ipv4_prefixes(self):
         """Test bulk creating IPv4 prefixes using a pattern."""
         """Test bulk creating IPv4 prefixes using a pattern."""
+        self.add_permissions('ipam.view_prefix')
         obj_perm = ObjectPermission(name='Test permission', actions=['add'])
         obj_perm = ObjectPermission(name='Test permission', actions=['add'])
         obj_perm.save()
         obj_perm.save()
         obj_perm.users.add(self.user)
         obj_perm.users.add(self.user)
@@ -497,9 +496,9 @@ class PrefixTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         for i in range(3):
         for i in range(3):
             self.assertTrue(Prefix.objects.filter(prefix=IPNetwork(f'10.0.{i}.0/24')).exists())
             self.assertTrue(Prefix.objects.filter(prefix=IPNetwork(f'10.0.{i}.0/24')).exists())
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_bulk_add_ipv6_prefixes(self):
     def test_bulk_add_ipv6_prefixes(self):
         """Test bulk creating IPv6 prefixes using a pattern."""
         """Test bulk creating IPv6 prefixes using a pattern."""
+        self.add_permissions('ipam.view_prefix')
         obj_perm = ObjectPermission(name='Test permission', actions=['add'])
         obj_perm = ObjectPermission(name='Test permission', actions=['add'])
         obj_perm.save()
         obj_perm.save()
         obj_perm.users.add(self.user)
         obj_perm.users.add(self.user)
@@ -518,9 +517,9 @@ class PrefixTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         for i in range(4):
         for i in range(4):
             self.assertTrue(Prefix.objects.filter(prefix=IPNetwork(f'fd00:db8:{i}::/48')).exists())
             self.assertTrue(Prefix.objects.filter(prefix=IPNetwork(f'fd00:db8:{i}::/48')).exists())
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_bulk_add_ipv6_prefixes_uppercase_hex(self):
     def test_bulk_add_ipv6_prefixes_uppercase_hex(self):
         """Test bulk creating IPv6 prefixes using uppercase hex in the pattern."""
         """Test bulk creating IPv6 prefixes using uppercase hex in the pattern."""
+        self.add_permissions('ipam.view_prefix')
         obj_perm = ObjectPermission(name='Test permission', actions=['add'])
         obj_perm = ObjectPermission(name='Test permission', actions=['add'])
         obj_perm.save()
         obj_perm.save()
         obj_perm.users.add(self.user)
         obj_perm.users.add(self.user)
@@ -544,8 +543,8 @@ class PrefixTestCase(ViewTestCases.PrimaryObjectViewTestCase):
                 f'Expected prefix {prefix_str} was not created'
                 f'Expected prefix {prefix_str} was not created'
             )
             )
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_bulk_add_prefixes_with_changelog_message(self):
     def test_bulk_add_prefixes_with_changelog_message(self):
+        self.add_permissions('ipam.view_prefix')
         obj_perm = ObjectPermission(name='Test permission', actions=['add'])
         obj_perm = ObjectPermission(name='Test permission', actions=['add'])
         obj_perm.save()
         obj_perm.save()
         obj_perm.users.add(self.user)
         obj_perm.users.add(self.user)
@@ -575,8 +574,8 @@ class PrefixTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         for objectchange in objectchanges:
         for objectchange in objectchanges:
             self.assertEqual(objectchange.message, changelog_message)
             self.assertEqual(objectchange.message, changelog_message)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_prefix_prefixes(self):
     def test_prefix_prefixes(self):
+        self.add_permissions('ipam.view_prefix')
         prefixes = (
         prefixes = (
             Prefix(prefix=IPNetwork('192.168.0.0/16')),
             Prefix(prefix=IPNetwork('192.168.0.0/16')),
             Prefix(prefix=IPNetwork('192.168.1.0/24')),
             Prefix(prefix=IPNetwork('192.168.1.0/24')),
@@ -589,8 +588,8 @@ class PrefixTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         url = reverse('ipam:prefix_prefixes', kwargs={'pk': prefixes[0].pk})
         url = reverse('ipam:prefix_prefixes', kwargs={'pk': prefixes[0].pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_prefix_ipranges(self):
     def test_prefix_ipranges(self):
+        self.add_permissions('ipam.view_prefix', 'ipam.view_iprange')
         prefix = Prefix.objects.create(prefix=IPNetwork('192.168.0.0/16'))
         prefix = Prefix.objects.create(prefix=IPNetwork('192.168.0.0/16'))
         ip_ranges = (
         ip_ranges = (
             IPRange(start_address='192.168.0.1/24', end_address='192.168.0.100/24', size=99),
             IPRange(start_address='192.168.0.1/24', end_address='192.168.0.100/24', size=99),
@@ -603,8 +602,8 @@ class PrefixTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         url = reverse('ipam:prefix_ipranges', kwargs={'pk': prefix.pk})
         url = reverse('ipam:prefix_ipranges', kwargs={'pk': prefix.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_prefix_ipaddresses(self):
     def test_prefix_ipaddresses(self):
+        self.add_permissions('ipam.view_prefix', 'ipam.view_ipaddress', 'ipam.view_iprange')
         prefix = Prefix.objects.create(prefix=IPNetwork('192.168.0.0/16'))
         prefix = Prefix.objects.create(prefix=IPNetwork('192.168.0.0/16'))
         ip_addresses = (
         ip_addresses = (
             IPAddress(address=IPNetwork('192.168.0.1/16')),
             IPAddress(address=IPNetwork('192.168.0.1/16')),
@@ -617,8 +616,8 @@ class PrefixTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         url = reverse('ipam:prefix_ipaddresses', kwargs={'pk': prefix.pk})
         url = reverse('ipam:prefix_ipaddresses', kwargs={'pk': prefix.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_prefix_ipaddresses_with_single_address_range(self):
     def test_prefix_ipaddresses_with_single_address_range(self):
+        self.add_permissions('ipam.view_prefix', 'ipam.view_ipaddress', 'ipam.view_iprange')
         # The IP Addresses tab annotates child IP addresses alongside any
         # The IP Addresses tab annotates child IP addresses alongside any
         # mark-populated child IP ranges. Make sure a single-address range
         # mark-populated child IP ranges. Make sure a single-address range
         # (start_address == end_address) renders without errors and is shown
         # (start_address == end_address) renders without errors and is shown
@@ -639,11 +638,11 @@ class PrefixTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         # IPAddress row in this mixed-record view).
         # IPAddress row in this mixed-record view).
         self.assertContains(response, '192.168.0.50-192.168.0.50/16')
         self.assertContains(response, '192.168.0.50-192.168.0.50/16')
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_prefix_import(self):
     def test_prefix_import(self):
         """
         """
         Custom import test for YAML-based imports (versus CSV)
         Custom import test for YAML-based imports (versus CSV)
         """
         """
+        self.add_permissions('dcim.view_site', 'ipam.view_vlan')
         site = Site.objects.get(name='Site 1')
         site = Site.objects.get(name='Site 1')
         IMPORT_DATA = f"""
         IMPORT_DATA = f"""
 prefix: 10.1.1.0/24
 prefix: 10.1.1.0/24
@@ -670,11 +669,11 @@ scope_id: {site.pk}
         self.assertEqual(prefix.vlan.vid, 101)
         self.assertEqual(prefix.vlan.vid, 101)
         self.assertEqual(prefix.scope, site)
         self.assertEqual(prefix.scope, site)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_prefix_import_with_scope_name(self):
     def test_prefix_import_with_scope_name(self):
         """
         """
         Test YAML-based import using scope_name instead of scope_id.
         Test YAML-based import using scope_name instead of scope_id.
         """
         """
+        self.add_permissions('dcim.view_site')
         site = Site.objects.get(name='Site 1')
         site = Site.objects.get(name='Site 1')
         IMPORT_DATA = """
         IMPORT_DATA = """
 prefix: 10.1.3.0/24
 prefix: 10.1.3.0/24
@@ -696,11 +695,11 @@ scope_name: Site 1
         self.assertEqual(prefix.status, PrefixStatusChoices.STATUS_ACTIVE)
         self.assertEqual(prefix.status, PrefixStatusChoices.STATUS_ACTIVE)
         self.assertEqual(prefix.scope, site)
         self.assertEqual(prefix.scope, site)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_prefix_import_with_vlan_group(self):
     def test_prefix_import_with_vlan_group(self):
         """
         """
         This test covers a unique import edge case where VLAN group is specified during the import.
         This test covers a unique import edge case where VLAN group is specified during the import.
         """
         """
+        self.add_permissions('dcim.view_site', 'ipam.view_vlan', 'ipam.view_vlangroup')
         site = Site.objects.get(name='Site 1')
         site = Site.objects.get(name='Site 1')
         IMPORT_DATA = f"""
         IMPORT_DATA = f"""
 prefix: 10.1.2.0/24
 prefix: 10.1.2.0/24
@@ -728,12 +727,12 @@ vlan: 102
         self.assertEqual(prefix.vlan.vid, 102)
         self.assertEqual(prefix.vlan.vid, 102)
         self.assertEqual(prefix.scope, site)
         self.assertEqual(prefix.scope, site)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_prefix_import_with_vlan_site_multiple_vlans_same_vid(self):
     def test_prefix_import_with_vlan_site_multiple_vlans_same_vid(self):
         """
         """
         Test import when multiple VLANs exist with the same vid but different sites.
         Test import when multiple VLANs exist with the same vid but different sites.
         Ref: #20560
         Ref: #20560
         """
         """
+        self.add_permissions('dcim.view_site', 'ipam.view_vlan')
         site1 = Site.objects.get(name='Site 1')
         site1 = Site.objects.get(name='Site 1')
         site2 = Site.objects.get(name='Site 2')
         site2 = Site.objects.get(name='Site 2')
 
 
@@ -766,13 +765,13 @@ description: LOC02-MGMT
         prefix = Prefix.objects.get(prefix='10.11.0.0/22')
         prefix = Prefix.objects.get(prefix='10.11.0.0/22')
         self.assertEqual(prefix.vlan, vlan1)
         self.assertEqual(prefix.vlan, vlan1)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_prefix_import_with_vlan_site_and_global_vlan(self):
     def test_prefix_import_with_vlan_site_and_global_vlan(self):
         """
         """
         Test import when a global VLAN (no site) and site-specific VLAN exist with same vid.
         Test import when a global VLAN (no site) and site-specific VLAN exist with same vid.
         When vlan_site is specified, should prefer the site-specific VLAN.
         When vlan_site is specified, should prefer the site-specific VLAN.
         Ref: #20560
         Ref: #20560
         """
         """
+        self.add_permissions('dcim.view_site', 'ipam.view_vlan')
         site1 = Site.objects.get(name='Site 1')
         site1 = Site.objects.get(name='Site 1')
 
 
         # Create a global VLAN (no site) and a site-specific VLAN with the same vid
         # Create a global VLAN (no site) and a site-specific VLAN with the same vid
@@ -871,8 +870,8 @@ class IPRangeTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             'description': 'New description',
             'description': 'New description',
         }
         }
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_iprange_ipaddresses(self):
     def test_iprange_ipaddresses(self):
+        self.add_permissions('ipam.view_iprange', 'ipam.view_ipaddress')
         iprange = IPRange.objects.create(
         iprange = IPRange.objects.create(
             start_address=IPNetwork('192.168.0.1/24'),
             start_address=IPNetwork('192.168.0.1/24'),
             end_address=IPNetwork('192.168.0.100/24'),
             end_address=IPNetwork('192.168.0.100/24'),
@@ -986,8 +985,8 @@ class IPAddressTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             'description': 'New description',
             'description': 'New description',
         }
         }
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_bulk_add_ipaddresses_with_changelog_message(self):
     def test_bulk_add_ipaddresses_with_changelog_message(self):
+        self.add_permissions('ipam.view_ipaddress', 'ipam.view_vrf')
         obj_perm = ObjectPermission(name='Test permission', actions=['add'])
         obj_perm = ObjectPermission(name='Test permission', actions=['add'])
         obj_perm.save()
         obj_perm.save()
         obj_perm.users.add(self.user)
         obj_perm.users.add(self.user)
@@ -1425,8 +1424,8 @@ class ServiceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             'description': 'New description',
             'description': 'New description',
         }
         }
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'], EXEMPT_EXCLUDE_MODELS=[])
     def test_unassigned_ip_addresses(self):
     def test_unassigned_ip_addresses(self):
+        self.add_permissions('ipam.view_service', 'dcim.view_device', 'ipam.view_ipaddress')
         device = Device.objects.first()
         device = Device.objects.first()
         addr = IPAddress.objects.create(address='192.0.2.4/24')
         addr = IPAddress.objects.create(address='192.0.2.4/24')
         csv_data = (
         csv_data = (
@@ -1455,8 +1454,8 @@ class ServiceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         self.assertIn(addr.address, form_errors['__all__'][0])
         self.assertIn(addr.address, form_errors['__all__'][0])
         self.assertEqual(self._get_queryset().count(), initial_count)
         self.assertEqual(self._get_queryset().count(), initial_count)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'], EXEMPT_EXCLUDE_MODELS=[])
     def test_alternate_csv_import(self):
     def test_alternate_csv_import(self):
+        self.add_permissions('ipam.view_service', 'dcim.view_device', 'ipam.view_ipaddress')
         device = Device.objects.first()
         device = Device.objects.first()
         interface = device.interfaces.first()
         interface = device.interfaces.first()
         addr = IPAddress.objects.create(assigned_object=interface, address='192.0.2.3/24')
         addr = IPAddress.objects.create(assigned_object=interface, address='192.0.2.3/24')
@@ -1485,9 +1484,13 @@ class ServiceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         self.assertHttpStatus(response, 302)
         self.assertHttpStatus(response, 302)
         self.assertEqual(self._get_queryset().count(), initial_count + len(csv_data) - 1)
         self.assertEqual(self._get_queryset().count(), initial_count + len(csv_data) - 1)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_create_from_template(self):
     def test_create_from_template(self):
-        self.add_permissions('ipam.add_service')
+        self.add_permissions(
+            'ipam.view_service',
+            'ipam.add_service',
+            'dcim.view_device',
+            'ipam.view_servicetemplate',
+        )
 
 
         device = Device.objects.first()
         device = Device.objects.first()
         service_template = ServiceTemplate.objects.create(
         service_template = ServiceTemplate.objects.create(

+ 3 - 6
netbox/netbox/tests/test_import.py

@@ -1,5 +1,3 @@
-from django.test import override_settings
-
 from core.models import ObjectType
 from core.models import ObjectType
 from dcim.models import *
 from dcim.models import *
 from extras.models import CustomField
 from extras.models import CustomField
@@ -48,8 +46,8 @@ class CSVImportTestCase(ModelViewTestCase):
         self.assertHttpStatus(self.client.post(self._get_url('bulk_import'), data), 302)
         self.assertHttpStatus(self.client.post(self._get_url('bulk_import'), data), 302)
         self.assertEqual(Region.objects.count(), 3)
         self.assertEqual(Region.objects.count(), 3)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_valid_tags(self):
     def test_valid_tags(self):
+        self.add_permissions('dcim.view_region', 'extras.view_tag')
         csv_data = (
         csv_data = (
             'name,slug,tags',
             'name,slug,tags',
             'Region 1,region-1,"alpha,bravo"',
             'Region 1,region-1,"alpha,bravo"',
@@ -91,8 +89,8 @@ class CSVImportTestCase(ModelViewTestCase):
         )
         )
         self.assertEqual(regions[3].tags.count(), 0)
         self.assertEqual(regions[3].tags.count(), 0)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_invalid_tags(self):
     def test_invalid_tags(self):
+        self.add_permissions('dcim.view_region', 'extras.view_tag')
         csv_data = (
         csv_data = (
             'name,slug,tags',
             'name,slug,tags',
             'Region 1,region-1,"Alpha,Bravo"',  # Valid
             'Region 1,region-1,"Alpha,Bravo"',  # Valid
@@ -117,9 +115,8 @@ class CSVImportTestCase(ModelViewTestCase):
         self.assertHttpStatus(self.client.post(self._get_url('bulk_import'), data), 200)
         self.assertHttpStatus(self.client.post(self._get_url('bulk_import'), data), 200)
         self.assertEqual(Region.objects.count(), 0)
         self.assertEqual(Region.objects.count(), 0)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_custom_field_defaults(self):
     def test_custom_field_defaults(self):
-        self.add_permissions('dcim.add_region')
+        self.add_permissions('dcim.view_region', 'dcim.add_region')
         csv_data = [
         csv_data = [
             'name,slug,description',
             'name,slug,description',
             'Region 1,region-1,abc',
             'Region 1,region-1,abc',

+ 1 - 1
netbox/netbox/tests/test_views.py

@@ -62,8 +62,8 @@ class SearchViewTestCase(TestCase):
         self.assertNotIn('Site Echo', content)
         self.assertNotIn('Site Echo', content)
         self.assertNotIn('Site Foxtrot', content)
         self.assertNotIn('Site Foxtrot', content)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_search_no_results(self):
     def test_search_no_results(self):
+        self.add_permissions('dcim.view_site')
         url = reverse('search')
         url = reverse('search')
         params = {
         params = {
             'q': 'xxxxxxxxx',  # Matches nothing
             'q': 'xxxxxxxxx',  # Matches nothing

+ 0 - 3
netbox/users/tests/test_views.py

@@ -1,4 +1,3 @@
-from django.test import override_settings
 from django.urls import reverse
 from django.urls import reverse
 
 
 from core.models import ObjectType
 from core.models import ObjectType
@@ -268,7 +267,6 @@ class TokenOneTimeAuthStringTestCase(TestCase):
     """
     """
     user_permissions = ('users.add_token', 'users.view_token', 'users.view_user')
     user_permissions = ('users.add_token', 'users.view_token', 'users.view_user')
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_create_stashes_plaintext_and_detail_view_renders_it_once(self):
     def test_create_stashes_plaintext_and_detail_view_renders_it_once(self):
         target_user = create_test_user('token_owner')
         target_user = create_test_user('token_owner')
 
 
@@ -310,7 +308,6 @@ class TokenOneTimeAuthStringTestCase(TestCase):
         # Specifically, the banner element must be gone
         # Specifically, the banner element must be gone
         self.assertNotContains(response, 'id="new-token-auth-string"')
         self.assertNotContains(response, 'id="new-token-auth-string"')
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_form_ignores_user_supplied_token_field(self):
     def test_form_ignores_user_supplied_token_field(self):
         """
         """
         Submitting a 'token' POST parameter should be silently ignored: the model auto-generates plaintext on save.
         Submitting a 'token' POST parameter should be silently ignored: the model auto-generates plaintext on save.

+ 1 - 3
netbox/utilities/tests/test_counters.py

@@ -1,4 +1,3 @@
-from django.test import override_settings
 from django.urls import reverse
 from django.urls import reverse
 
 
 from dcim.models import *
 from dcim.models import *
@@ -82,7 +81,6 @@ class CountersTestCase(TestCase):
         self.assertEqual(device1.interface_count, 1)
         self.assertEqual(device1.interface_count, 1)
         self.assertEqual(device2.interface_count, 3)
         self.assertEqual(device2.interface_count, 3)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_mptt_child_delete(self):
     def test_mptt_child_delete(self):
         device1 = Device.objects.first()
         device1 = Device.objects.first()
         inventory_item1 = InventoryItem.objects.create(device=device1, name='Inventory Item 1')
         inventory_item1 = InventoryItem.objects.create(device=device1, name='Inventory Item 1')
@@ -91,7 +89,7 @@ class CountersTestCase(TestCase):
         self.assertEqual(device1.inventory_item_count, 2)
         self.assertEqual(device1.inventory_item_count, 2)
 
 
         # Setup bulk_delete for the inventory items
         # Setup bulk_delete for the inventory items
-        self.add_permissions('dcim.delete_inventoryitem')
+        self.add_permissions('dcim.view_inventoryitem', 'dcim.delete_inventoryitem')
         pk_list = device1.inventoryitems.values_list('pk', flat=True)
         pk_list = device1.inventoryitems.values_list('pk', flat=True)
         data = {
         data = {
             'pk': pk_list,
             'pk': pk_list,

+ 11 - 6
netbox/virtualization/tests/test_views.py

@@ -1,7 +1,6 @@
 from decimal import Decimal
 from decimal import Decimal
 
 
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.models import ContentType
-from django.test import override_settings
 from django.urls import reverse
 from django.urls import reverse
 
 
 from dcim.choices import InterfaceModeChoices
 from dcim.choices import InterfaceModeChoices
@@ -189,15 +188,15 @@ class ClusterTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             'comments': 'New comments',
             'comments': 'New comments',
         }
         }
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_cluster_virtualmachines(self):
     def test_cluster_virtualmachines(self):
+        self.add_permissions('virtualization.view_cluster', 'virtualization.view_virtualmachine')
         cluster = Cluster.objects.first()
         cluster = Cluster.objects.first()
 
 
         url = reverse('virtualization:cluster_virtualmachines', kwargs={'pk': cluster.pk})
         url = reverse('virtualization:cluster_virtualmachines', kwargs={'pk': cluster.pk})
         self.assertHttpStatus(self.client.get(url), 200)
         self.assertHttpStatus(self.client.get(url), 200)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_cluster_devices(self):
     def test_cluster_devices(self):
+        self.add_permissions('virtualization.view_cluster', 'dcim.view_device')
         cluster = Cluster.objects.first()
         cluster = Cluster.objects.first()
 
 
         url = reverse('virtualization:cluster_devices', kwargs={'pk': cluster.pk})
         url = reverse('virtualization:cluster_devices', kwargs={'pk': cluster.pk})
@@ -423,9 +422,15 @@ class VirtualMachineTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             'start_on_boot': VirtualMachineStartOnBootChoices.STATUS_OFF,
             'start_on_boot': VirtualMachineStartOnBootChoices.STATUS_OFF,
         }
         }
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'], EXEMPT_EXCLUDE_MODELS=[])
     def test_create_virtualmachine_with_type_defaults(self):
     def test_create_virtualmachine_with_type_defaults(self):
-        self.add_permissions('virtualization.add_virtualmachine')
+        self.add_permissions(
+            'virtualization.view_virtualmachine',
+            'virtualization.add_virtualmachine',
+            'virtualization.view_cluster',
+            'virtualization.view_virtualmachinetype',
+            'dcim.view_site',
+            'dcim.view_platform',
+        )
 
 
         response = self.client.post(
         response = self.client.post(
             self._get_url('add'),
             self._get_url('add'),
@@ -449,8 +454,8 @@ class VirtualMachineTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         self.assertEqual(vm.vcpus, self.vm_types[0].default_vcpus)
         self.assertEqual(vm.vcpus, self.vm_types[0].default_vcpus)
         self.assertEqual(vm.memory, self.vm_types[0].default_memory)
         self.assertEqual(vm.memory, self.vm_types[0].default_memory)
 
 
-    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
     def test_virtualmachine_interfaces(self):
     def test_virtualmachine_interfaces(self):
+        self.add_permissions('virtualization.view_virtualmachine', 'virtualization.view_vminterface')
         virtualmachine = VirtualMachine.objects.first()
         virtualmachine = VirtualMachine.objects.first()
         vminterfaces = (
         vminterfaces = (
             VMInterface(virtual_machine=virtualmachine, name='Interface 1'),
             VMInterface(virtual_machine=virtualmachine, name='Interface 1'),