diff --git a/netbox/circuits/tests/test_views.py b/netbox/circuits/tests/test_views.py index fa6146b93..61e8cbbd1 100644 --- a/netbox/circuits/tests/test_views.py +++ b/netbox/circuits/tests/test_views.py @@ -200,6 +200,7 @@ class ProviderNetworkTestCase(ViewTestCases.PrimaryObjectViewTestCase): class CircuitTerminationTestCase( ViewTestCases.EditObjectViewTestCase, ViewTestCases.DeleteObjectViewTestCase, + ViewTestCases.CustomFieldViewTestCase, ): model = CircuitTermination diff --git a/netbox/extras/tests/test_views.py b/netbox/extras/tests/test_views.py index 936213cbf..5856ec632 100644 --- a/netbox/extras/tests/test_views.py +++ b/netbox/extras/tests/test_views.py @@ -11,7 +11,7 @@ from extras.models import * from utilities.testing import ViewTestCases, TestCase -class CustomFieldTestCase(ViewTestCases.PrimaryObjectViewTestCase): +class CustomFieldTestCase(ViewTestCases.BaseObjectViewTestCase, ViewTestCases.CreateObjectViewTestCase): model = CustomField @classmethod @@ -53,7 +53,7 @@ class CustomFieldTestCase(ViewTestCases.PrimaryObjectViewTestCase): } -class CustomLinkTestCase(ViewTestCases.PrimaryObjectViewTestCase): +class CustomLinkTestCase(ViewTestCases.BaseObjectViewTestCase, ViewTestCases.CreateObjectViewTestCase): model = CustomLink @classmethod @@ -90,7 +90,7 @@ class CustomLinkTestCase(ViewTestCases.PrimaryObjectViewTestCase): } -class ExportTemplateTestCase(ViewTestCases.PrimaryObjectViewTestCase): +class ExportTemplateTestCase(ViewTestCases.BaseObjectViewTestCase, ViewTestCases.CreateObjectViewTestCase): model = ExportTemplate @classmethod @@ -124,7 +124,7 @@ class ExportTemplateTestCase(ViewTestCases.PrimaryObjectViewTestCase): } -class WebhookTestCase(ViewTestCases.PrimaryObjectViewTestCase): +class WebhookTestCase(ViewTestCases.BaseObjectViewTestCase, ViewTestCases.CreateObjectViewTestCase): model = Webhook @classmethod @@ -168,7 +168,7 @@ class WebhookTestCase(ViewTestCases.PrimaryObjectViewTestCase): } -class TagTestCase(ViewTestCases.OrganizationalObjectViewTestCase): +class TagTestCase(ViewTestCases.BaseObjectViewTestCase, ViewTestCases.CreateObjectViewTestCase): model = Tag @classmethod @@ -291,7 +291,8 @@ class JournalEntryTestCase( ViewTestCases.DeleteObjectViewTestCase, ViewTestCases.ListObjectsViewTestCase, ViewTestCases.BulkEditObjectsViewTestCase, - ViewTestCases.BulkDeleteObjectsViewTestCase + ViewTestCases.BulkDeleteObjectsViewTestCase, + ViewTestCases.CustomFieldViewTestCase, ): model = JournalEntry diff --git a/netbox/utilities/testing/views.py b/netbox/utilities/testing/views.py index 7fa9f66bc..f148780df 100644 --- a/netbox/utilities/testing/views.py +++ b/netbox/utilities/testing/views.py @@ -3,8 +3,8 @@ from django.core.exceptions import ObjectDoesNotExist from django.test import override_settings from django.urls import reverse -from extras.choices import ObjectChangeActionChoices -from extras.models import ObjectChange +from extras.choices import ObjectChangeActionChoices, CustomFieldTypeChoices +from extras.models import ObjectChange, CustomField from users.models import ObjectPermission from .base import ModelTestCase from .utils import disable_warnings, post_data @@ -857,16 +857,62 @@ class ViewTestCases: for i, instance in enumerate(self._get_queryset().filter(pk__in=pk_list)): self.assertEqual(instance.name, f'{objects[i].name}X') - class PrimaryObjectViewTestCase( + class CustomFieldViewTestCase(ModelViewTestCase): + """ + Edit a single existing instance. + + :form_data: Data to be used when updating the first existing object. + """ + form_data = {} + + @override_settings(EXEMPT_VIEW_PERMISSIONS=['*']) + def test_save_custom_field(self): + initial_count = self._get_queryset().count() + + # Assign unconstrained permission + obj_perm = ObjectPermission( + name='Test permission', + actions=['add'] + ) + obj_perm.save() + obj_perm.users.add(self.user) + obj_perm.object_types.add(ContentType.objects.get_for_model(self.model)) + + cf = CustomField.objects.create(type=CustomFieldTypeChoices.TYPE_TEXT, name='testcf_field', default='foo', required=False) + cf.content_types.set([ContentType.objects.get_for_model(self.model)]) + data = self.form_data + cf_name = f'cf_{cf.name}' + data[cf_name] = "XYZZY" + + # Try POST with custom field data + request = { + 'path': self._get_url('add'), + 'data': post_data(data), + } + self.assertHttpStatus(self.client.post(**request), 302) + self.assertEqual(initial_count + 1, self._get_queryset().count()) + instance = self._get_queryset().order_by('pk').last() + self.assertEqual(instance.custom_field_data[cf.name], data[cf_name]) + + class BaseObjectViewTestCase( GetObjectViewTestCase, GetObjectChangelogViewTestCase, - CreateObjectViewTestCase, EditObjectViewTestCase, DeleteObjectViewTestCase, ListObjectsViewTestCase, BulkImportObjectsViewTestCase, BulkEditObjectsViewTestCase, BulkDeleteObjectsViewTestCase, + ): + """ + Base TestCase suitable for most views + """ + maxDiff = None + + class PrimaryObjectViewTestCase( + BaseObjectViewTestCase, + CreateObjectViewTestCase, + CustomFieldViewTestCase, ): """ TestCase suitable for testing all standard View functions for primary objects @@ -874,15 +920,9 @@ class ViewTestCases: maxDiff = None class OrganizationalObjectViewTestCase( - GetObjectViewTestCase, - GetObjectChangelogViewTestCase, + BaseObjectViewTestCase, CreateObjectViewTestCase, - EditObjectViewTestCase, - DeleteObjectViewTestCase, - ListObjectsViewTestCase, - BulkImportObjectsViewTestCase, - BulkEditObjectsViewTestCase, - BulkDeleteObjectsViewTestCase, + CustomFieldViewTestCase, ): """ TestCase suitable for all organizational objects @@ -903,16 +943,9 @@ class ViewTestCases: maxDiff = None class DeviceComponentViewTestCase( - GetObjectViewTestCase, - GetObjectChangelogViewTestCase, - EditObjectViewTestCase, - DeleteObjectViewTestCase, - ListObjectsViewTestCase, + BaseObjectViewTestCase, CreateMultipleObjectsViewTestCase, - BulkImportObjectsViewTestCase, - BulkEditObjectsViewTestCase, BulkRenameObjectsViewTestCase, - BulkDeleteObjectsViewTestCase, ): """ TestCase suitable for testing device component models (ConsolePorts, Interfaces, etc.)