From f17bbe610eda143dad3a07499981fd120199eb14 Mon Sep 17 00:00:00 2001 From: Martin Hauser Date: Wed, 2 Apr 2025 14:29:21 +0200 Subject: [PATCH] Fixes #19041: Call super().clean() in FrontPortCreateForm (#19051) * fix(forms): Call super().clean() in clean methods Adds a call to super().clean() in the clean methods of object creation forms. This ensures base class validation logic is executed properly before custom logic is applied. Fixes #19041 * test(forms): Add tests for front port form validation Introduces unit tests for validating FrontPortCreateForm behavior. Tests include scenarios for matching and mismatched name-label pairs to ensure proper form validation logic. Fixes #19041 * Omit errant print statement --------- Co-authored-by: Jeremy Stretch --- netbox/dcim/forms/object_create.py | 2 ++ netbox/dcim/tests/test_forms.py | 53 +++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/netbox/dcim/forms/object_create.py b/netbox/dcim/forms/object_create.py index 6f6cd8f7c..b279aec9b 100644 --- a/netbox/dcim/forms/object_create.py +++ b/netbox/dcim/forms/object_create.py @@ -153,6 +153,7 @@ class FrontPortTemplateCreateForm(ComponentCreateForm, model_forms.FrontPortTemp self.fields['rear_port'].choices = choices def clean(self): + super().clean() # Check that the number of FrontPortTemplates to be created matches the selected number of RearPortTemplate # positions @@ -302,6 +303,7 @@ class FrontPortCreateForm(ComponentCreateForm, model_forms.FrontPortForm): self.fields['rear_port'].choices = choices def clean(self): + super().clean() # Check that the number of FrontPorts to be created matches the selected number of RearPort positions frontport_count = len(self.cleaned_data['name']) diff --git a/netbox/dcim/tests/test_forms.py b/netbox/dcim/tests/test_forms.py index 89b7508f3..73d5dbd98 100644 --- a/netbox/dcim/tests/test_forms.py +++ b/netbox/dcim/tests/test_forms.py @@ -1,6 +1,12 @@ from django.test import TestCase -from dcim.choices import DeviceFaceChoices, DeviceStatusChoices, InterfaceTypeChoices, InterfaceModeChoices +from dcim.choices import ( + DeviceFaceChoices, + DeviceStatusChoices, + InterfaceModeChoices, + InterfaceTypeChoices, + PortTypeChoices, +) from dcim.forms import * from dcim.models import * from ipam.models import VLAN @@ -118,6 +124,51 @@ class DeviceTestCase(TestCase): self.assertIn('position', form.errors) +class FrontPortTestCase(TestCase): + + @classmethod + def setUpTestData(cls): + cls.device = create_test_device('Panel Device 1') + cls.rear_ports = ( + RearPort(name='RearPort1', device=cls.device, type=PortTypeChoices.TYPE_8P8C), + RearPort(name='RearPort2', device=cls.device, type=PortTypeChoices.TYPE_8P8C), + RearPort(name='RearPort3', device=cls.device, type=PortTypeChoices.TYPE_8P8C), + RearPort(name='RearPort4', device=cls.device, type=PortTypeChoices.TYPE_8P8C), + ) + RearPort.objects.bulk_create(cls.rear_ports) + + def test_front_port_label_count_valid(self): + """ + Test that generating an equal number of names and labels passes form validation. + """ + front_port_data = { + 'device': self.device.pk, + 'name': 'FrontPort[1-4]', + 'label': 'Port[1-4]', + 'type': PortTypeChoices.TYPE_8P8C, + 'rear_port': [f'{rear_port.pk}:1' for rear_port in self.rear_ports], + } + form = FrontPortCreateForm(front_port_data) + + self.assertTrue(form.is_valid()) + + def test_front_port_label_count_mismatch(self): + """ + Check that attempting to generate a differing number of names and labels results in a validation error. + """ + bad_front_port_data = { + 'device': self.device.pk, + 'name': 'FrontPort[1-4]', + 'label': 'Port[1-2]', + 'type': PortTypeChoices.TYPE_8P8C, + 'rear_port': [f'{rear_port.pk}:1' for rear_port in self.rear_ports], + } + form = FrontPortCreateForm(bad_front_port_data) + + self.assertFalse(form.is_valid()) + self.assertIn('label', form.errors) + + class InterfaceTestCase(TestCase): @classmethod