From ce08e8d437d4e3d2202dca9da85728f28b45b595 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 20 Dec 2023 16:55:38 -0500 Subject: [PATCH] Add bulk edit M2M validation test --- netbox/extras/tests/test_api.py | 56 +----- netbox/extras/tests/test_custom_validation.py | 190 ++++++++++++++++++ netbox/extras/tests/test_forms.py | 57 +----- 3 files changed, 193 insertions(+), 110 deletions(-) create mode 100644 netbox/extras/tests/test_custom_validation.py diff --git a/netbox/extras/tests/test_api.py b/netbox/extras/tests/test_api.py index 52c988ed3..ddb1f2f2e 100644 --- a/netbox/extras/tests/test_api.py +++ b/netbox/extras/tests/test_api.py @@ -2,20 +2,16 @@ import datetime from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType -from django.test import override_settings from django.urls import reverse from django.utils.timezone import make_aware from rest_framework import status -from circuits.api.serializers import ProviderSerializer from core.choices import ManagedFileRootPathChoices from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Rack, Location, RackRole, Site from extras.models import * from extras.reports import Report from extras.scripts import BooleanVar, IntegerVar, Script, StringVar -from ipam.models import ASN, RIR -from utilities.testing import APITestCase, APIViewTestCases, create_tags - +from utilities.testing import APITestCase, APIViewTestCases User = get_user_model() @@ -832,53 +828,3 @@ class ContentTypeTest(APITestCase): url = reverse('extras-api:contenttype-detail', kwargs={'pk': contenttype.pk}) self.assertHttpStatus(self.client.get(url, **self.header), status.HTTP_200_OK) - - -class CustomValidationTest(APITestCase): - - @override_settings(CUSTOM_VALIDATORS={ - 'circuits.provider': [ - {'tags': {'required': True}} - ] - }) - def test_tags_validation(self): - """ - Check that custom validation rules work for tag assignment. - """ - data = { - 'name': 'Provider 1', - 'slug': 'provider-1', - } - serializer = ProviderSerializer(data=data) - self.assertFalse(serializer.is_valid()) - - tags = create_tags('Tag1', 'Tag2', 'Tag3') - data['tags'] = [tag.pk for tag in tags] - serializer = ProviderSerializer(data=data) - self.assertTrue(serializer.is_valid()) - - @override_settings(CUSTOM_VALIDATORS={ - 'circuits.provider': [ - {'asns': {'required': True}} - ] - }) - def test_m2m_validation(self): - """ - Check that custom validation rules work for many-to-many fields. - """ - data = { - 'name': 'Provider 1', - 'slug': 'provider-1', - } - serializer = ProviderSerializer(data=data) - self.assertFalse(serializer.is_valid()) - - rir = RIR.objects.create(name='RIR 1', slug='rir-1') - asns = ASN.objects.bulk_create(( - ASN(rir=rir, asn=65001), - ASN(rir=rir, asn=65002), - ASN(rir=rir, asn=65003), - )) - data['asns'] = [asn.pk for asn in asns] - serializer = ProviderSerializer(data=data) - self.assertTrue(serializer.is_valid()) diff --git a/netbox/extras/tests/test_custom_validation.py b/netbox/extras/tests/test_custom_validation.py new file mode 100644 index 000000000..93d28ca06 --- /dev/null +++ b/netbox/extras/tests/test_custom_validation.py @@ -0,0 +1,190 @@ +from django.test import TestCase +from django.test import override_settings + +from circuits.api.serializers import ProviderSerializer +from circuits.forms import ProviderForm, ProviderImportForm +from circuits.models import Provider +from extras.models import Tag +from ipam.models import ASN, RIR +from utilities.testing import APITestCase, ModelViewTestCase, create_tags, post_data + + +class ModelFormCustomValidationTest(TestCase): + + @override_settings(CUSTOM_VALIDATORS={ + 'circuits.provider': [ + {'tags': {'required': True}} + ] + }) + def test_tags_validation(self): + """ + Check that custom validation rules work for tag assignment. + """ + data = { + 'name': 'Provider 1', + 'slug': 'provider-1', + } + form = ProviderForm(data) + self.assertFalse(form.is_valid()) + + tags = create_tags('Tag1', 'Tag2', 'Tag3') + data['tags'] = [tag.pk for tag in tags] + form = ProviderForm(data) + self.assertTrue(form.is_valid()) + + @override_settings(CUSTOM_VALIDATORS={ + 'circuits.provider': [ + {'asns': {'required': True}} + ] + }) + def test_m2m_validation(self): + """ + Check that custom validation rules work for many-to-many fields. + """ + data = { + 'name': 'Provider 1', + 'slug': 'provider-1', + } + form = ProviderForm(data) + self.assertFalse(form.is_valid()) + + rir = RIR.objects.create(name='RIR 1', slug='rir-1') + asns = ASN.objects.bulk_create(( + ASN(rir=rir, asn=65001), + ASN(rir=rir, asn=65002), + ASN(rir=rir, asn=65003), + )) + data['asns'] = [asn.pk for asn in asns] + form = ProviderForm(data) + self.assertTrue(form.is_valid()) + + +class BulkEditCustomValidationTest(ModelViewTestCase): + model = Provider + + @classmethod + def setUpTestData(cls): + rir = RIR.objects.create(name='RIR 1', slug='rir-1') + asns = ASN.objects.bulk_create(( + ASN(rir=rir, asn=65001), + ASN(rir=rir, asn=65002), + ASN(rir=rir, asn=65003), + )) + tags = create_tags('Tag1', 'Tag2', 'Tag3') + + providers = ( + Provider(name='Provider 1', slug='provider-1'), + Provider(name='Provider 2', slug='provider-2'), + Provider(name='Provider 3', slug='provider-3'), + ) + Provider.objects.bulk_create(providers) + for provider in providers: + provider.asns.set(asns) + provider.tags.set(tags) + + @override_settings(CUSTOM_VALIDATORS={ + 'circuits.provider': [ + {'asns': {'required': True}} + ] + }) + def test_m2m_validation(self): + """ + Check that custom validation rules work for many-to-many fields. + """ + providers = Provider.objects.all() + data = { + 'pk': [provider.pk for provider in providers], + '_apply': '', + 'description': 'New description', + } + self.add_permissions( + 'circuits.view_provider', + 'circuits.change_provider', + 'ipam.view_asn', + ) + + # Bulk edit the description without changing ASN assignments + request = { + 'path': self._get_url('bulk_edit'), + 'data': post_data(data), + } + response = self.client.post(**request) + self.assertHttpStatus(response, 302) + self.assertEqual( + Provider.objects.filter(description=data['description']).count(), + len(providers) + ) + + # Change the ASN assignments + asn = ASN.objects.first() + data['asns'] = [asn.pk] + request = { + 'path': self._get_url('bulk_edit'), + 'data': post_data(data), + } + response = self.client.post(**request) + self.assertHttpStatus(response, 302) + for provider in Provider.objects.all(): + self.assertEqual(len(provider.asns.all()), 1) + + # Attempt to remove the ASN assignments + data.pop('asns') + data['_nullify'] = 'asns' + request = { + 'path': self._get_url('bulk_edit'), + 'data': post_data(data), + } + response = self.client.post(**request) + self.assertHttpStatus(response, 200) + for provider in Provider.objects.all(): + self.assertTrue(provider.asns.exists()) + + +class APISerializerCustomValidationTest(APITestCase): + + @override_settings(CUSTOM_VALIDATORS={ + 'circuits.provider': [ + {'tags': {'required': True}} + ] + }) + def test_tags_validation(self): + """ + Check that custom validation rules work for tag assignment. + """ + data = { + 'name': 'Provider 1', + 'slug': 'provider-1', + } + serializer = ProviderSerializer(data=data) + self.assertFalse(serializer.is_valid()) + + tags = create_tags('Tag1', 'Tag2', 'Tag3') + data['tags'] = [tag.pk for tag in tags] + serializer = ProviderSerializer(data=data) + self.assertTrue(serializer.is_valid()) + + @override_settings(CUSTOM_VALIDATORS={ + 'circuits.provider': [ + {'asns': {'required': True}} + ] + }) + def test_m2m_validation(self): + """ + Check that custom validation rules work for many-to-many fields. + """ + data = { + 'name': 'Provider 1', + 'slug': 'provider-1', + } + serializer = ProviderSerializer(data=data) + self.assertFalse(serializer.is_valid()) + + rir = RIR.objects.create(name='RIR 1', slug='rir-1') + asns = ASN.objects.bulk_create(( + ASN(rir=rir, asn=65001), + ASN(rir=rir, asn=65002), + ASN(rir=rir, asn=65003), + )) + data['asns'] = [asn.pk for asn in asns] + serializer = ProviderSerializer(data=data) + self.assertTrue(serializer.is_valid()) diff --git a/netbox/extras/tests/test_forms.py b/netbox/extras/tests/test_forms.py index ac94dba64..fce3a00cc 100644 --- a/netbox/extras/tests/test_forms.py +++ b/netbox/extras/tests/test_forms.py @@ -1,14 +1,11 @@ from django.contrib.contenttypes.models import ContentType -from django.test import TestCase, override_settings +from django.test import TestCase -from circuits.forms import ProviderForm from dcim.forms import SiteForm from dcim.models import Site from extras.choices import CustomFieldTypeChoices from extras.forms import SavedFilterForm -from extras.models import CustomField, CustomFieldChoiceSet -from ipam.models import ASN, RIR -from utilities.testing import create_tags +from extras.models import * class CustomFieldModelFormTest(TestCase): @@ -112,53 +109,3 @@ class SavedFilterFormTest(TestCase): }) self.assertTrue(form.is_valid()) form.save() - - -class CustomValidationTest(TestCase): - - @override_settings(CUSTOM_VALIDATORS={ - 'circuits.provider': [ - {'tags': {'required': True}} - ] - }) - def test_tags_validation(self): - """ - Check that custom validation rules work for tag assignment. - """ - data = { - 'name': 'Provider 1', - 'slug': 'provider-1', - } - form = ProviderForm(data) - self.assertFalse(form.is_valid()) - - tags = create_tags('Tag1', 'Tag2', 'Tag3') - data['tags'] = [tag.pk for tag in tags] - form = ProviderForm(data) - self.assertTrue(form.is_valid()) - - @override_settings(CUSTOM_VALIDATORS={ - 'circuits.provider': [ - {'asns': {'required': True}} - ] - }) - def test_m2m_validation(self): - """ - Check that custom validation rules work for many-to-many fields. - """ - data = { - 'name': 'Provider 1', - 'slug': 'provider-1', - } - form = ProviderForm(data) - self.assertFalse(form.is_valid()) - - rir = RIR.objects.create(name='RIR 1', slug='rir-1') - asns = ASN.objects.bulk_create(( - ASN(rir=rir, asn=65001), - ASN(rir=rir, asn=65002), - ASN(rir=rir, asn=65003), - )) - data['asns'] = [asn.pk for asn in asns] - form = ProviderForm(data) - self.assertTrue(form.is_valid())