From bda66c50a0e2ca237c442836e34b795a7c80b3c5 Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Thu, 23 Jan 2025 12:11:30 +0000 Subject: [PATCH 1/5] =?UTF-8?q?=E2=9C=85=20Add=20valid=20VIEW=20test=20for?= =?UTF-8?q?=20createvm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/tests/createvm/__init__.py | 0 .../tests/createvm/test_createvm_view.py | 86 +++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 netbox_sys_plugin/tests/createvm/__init__.py create mode 100644 netbox_sys_plugin/tests/createvm/test_createvm_view.py diff --git a/netbox_sys_plugin/tests/createvm/__init__.py b/netbox_sys_plugin/tests/createvm/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/netbox_sys_plugin/tests/createvm/test_createvm_view.py b/netbox_sys_plugin/tests/createvm/test_createvm_view.py new file mode 100644 index 0000000..34516ab --- /dev/null +++ b/netbox_sys_plugin/tests/createvm/test_createvm_view.py @@ -0,0 +1,86 @@ +# test_create_vm_form.py +from django.test import TestCase +from django.contrib.contenttypes.models import ContentType +from virtualization.models import ClusterType, Cluster, VirtualMachine, VMInterface +from ipam.models import Service +from dcim.models import DeviceRole, Platform +from extras.models import Tag +from netbox_sys_plugin.models import ProviderTypeExtraConfig, VirtualMachineType +from netbox_sys_plugin.forms import CreateVmForm + + +class CreateVmFormTestCase(TestCase): + """Test suite for the CreateVmForm.""" + + def setUp(self): + """Set up the test data.""" + + self.cluster_type = ClusterType.objects.create(name="Test Cluster Type", slug="test-cluster-type") + self.cluster = Cluster.objects.create(name="Test Cluster", type=self.cluster_type) + self.role = DeviceRole.objects.create(name="Test Role", slug="test-role") + self.platform = Platform.objects.create(name="Test Platform", slug="test-platform") + self.tag = Tag.objects.create(name="Test Tag", slug="test-tag") + self.provider_extra_config = ProviderTypeExtraConfig.objects.create( + extra_config_name="Test Config", + extra_config_structure={ + "config_structure": [{"field1": {"type": "string", "required": "True"}}] + }, + extra_config_description="Test description" + ) + self.vm_machine_type = VirtualMachineType.objects.create( + virtual_machine_type_name="BIG", + virtual_machine_type_desc="BIG", + assigned_object_type=ContentType.objects.get_for_model(ClusterType), + assigned_object_id=self.cluster_type.pk) + + def test_valid_form_submission_without_webhook(self): + """Test a valid form submission.""" + form_data = { + 'cl_list_new-cluster_type': self.cluster_type.id, + 'cl_list_new-cluster': self.cluster.id, + 'vms_new-0-name': 'TEST_DATA2', + 'vms_new-0-status': 'active', + 'vms_new-0-role': str(self.role.id), + 'vms_new-0-platform': str(self.platform.id), + 'vms_new-0-description': 'TEST_DATA', + 'vmassignedvmtype_new-virtual_machine_type': str(self.vm_machine_type.pk), + 'vmis_new-0-name': 'TEST_DATA', + 'ip_new-address': '100.0.0.1/24', + 'ip_new-status': 'active', + 'gateway_new-address': '100.2.3.4/24', + 'gateway_new-status': 'active', + 'domainnames_new-domain_names': '{"example_domain_name": "example_domain1","example_domain_name2": "example_domain2"}', + 'vmassignedextraconfig_new-provider_type_extra_config': str(self.provider_extra_config.pk), + 'vmassignedextraconfig_new-extra_config_values': '{"field1": "fieldvalue1"}', + 'service_ntp-0-name': 'TEST_DATA1', + 'service_ntp-0-protocol': 'tcp', + 'service_ntp-0-ports': '440', + 'service_dns-0-name': 'TEST_DATA2', + 'service_dns-0-protocol': 'tcp', + 'service_dns-0-ports': '44', + 'service_syslog-0-name': 'TEST_DATA3', + 'service_syslog-0-protocol': 'tcp', + 'service_syslog-0-ports': '111', + } + form = CreateVmForm(data=form_data) + vm = form.process_creation(form_data) + + + self.assertIsInstance(vm, VirtualMachine) + #Assert VM + self.assertEqual(VirtualMachine.objects.filter(id=vm.pk).count(), 1) + #Assert Interfaces + self.assertEqual(VMInterface.objects.filter(virtual_machine=vm).count(), 1) + #Assert Services + self.assertEqual(Service.objects.filter(virtual_machine=vm).count(), 3) + + + def tearDown(self): + """Clean up after tests.""" + VirtualMachine.objects.all().delete() + DeviceRole.objects.all().delete() + Platform.objects.all().delete() + ProviderTypeExtraConfig.objects.all().delete() + Service.objects.all().delete() + Cluster.objects.all().delete() + ClusterType.objects.all().delete() -- GitLab From 5cc5abc9a01cffa93616f499d96991c0dbc4e74a Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Thu, 23 Jan 2025 15:09:37 +0000 Subject: [PATCH 2/5] =?UTF-8?q?=E2=9C=85=20=F0=9F=90=9B=20Fix=20to=20form?= =?UTF-8?q?=20and=20add=20test=20validations=20for=20createvm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/forms/createvm.py | 24 ++++-- .../tests/createvm/test_createvm_view.py | 77 ++++++++++++++++++- 2 files changed, 90 insertions(+), 11 deletions(-) diff --git a/netbox_sys_plugin/forms/createvm.py b/netbox_sys_plugin/forms/createvm.py index aec6076..4b35f05 100644 --- a/netbox_sys_plugin/forms/createvm.py +++ b/netbox_sys_plugin/forms/createvm.py @@ -302,12 +302,22 @@ class CreateVmForm(NetBoxModelForm): @staticmethod def parse_ports(ports_field): """Parse the port numbers.""" - try: - ports = [int(port.strip()) for port in ports_field.split(',') if port.strip().isdigit()] - return ports - except ValueError as e: - raise ValueError(f"Invalid ports value: {ports_field}") from e - + if not ports_field.strip(): + return[] + ports =[] + invalid_ports=[] + + for port in ports_field.split(','): + port = port.strip() + if port.isdigit(): + ports.append(int(port)) + else: + invalid_ports.append(port) + + if invalid_ports: + raise ValueError(f"Invalid ports value: {ports_field}") + + return ports @staticmethod def get_parse_tags(data): """Parse Tags""" @@ -319,7 +329,7 @@ class CreateVmForm(NetBoxModelForm): tags_field = Tag.objects.get(pk=tag_id) return [tags_field] except Tag.DoesNotExist as e: - raise ValueError (f"Invalid tag: {tags_field}") from e + raise ValueError ("Invalid tag") from e @staticmethod def assign_tags(obj,data): diff --git a/netbox_sys_plugin/tests/createvm/test_createvm_view.py b/netbox_sys_plugin/tests/createvm/test_createvm_view.py index 34516ab..8cb1e09 100644 --- a/netbox_sys_plugin/tests/createvm/test_createvm_view.py +++ b/netbox_sys_plugin/tests/createvm/test_createvm_view.py @@ -1,6 +1,7 @@ # test_create_vm_form.py from django.test import TestCase from django.contrib.contenttypes.models import ContentType +from django.core.exceptions import ValidationError from virtualization.models import ClusterType, Cluster, VirtualMachine, VMInterface from ipam.models import Service from dcim.models import DeviceRole, Platform @@ -8,7 +9,7 @@ from extras.models import Tag from netbox_sys_plugin.models import ProviderTypeExtraConfig, VirtualMachineType from netbox_sys_plugin.forms import CreateVmForm - +# pylint: disable=W0201, R0902 class CreateVmFormTestCase(TestCase): """Test suite for the CreateVmForm.""" @@ -33,9 +34,7 @@ class CreateVmFormTestCase(TestCase): assigned_object_type=ContentType.objects.get_for_model(ClusterType), assigned_object_id=self.cluster_type.pk) - def test_valid_form_submission_without_webhook(self): - """Test a valid form submission.""" - form_data = { + self.form_data_template = { 'cl_list_new-cluster_type': self.cluster_type.id, 'cl_list_new-cluster': self.cluster.id, 'vms_new-0-name': 'TEST_DATA2', @@ -61,7 +60,12 @@ class CreateVmFormTestCase(TestCase): 'service_syslog-0-name': 'TEST_DATA3', 'service_syslog-0-protocol': 'tcp', 'service_syslog-0-ports': '111', + 'tag_new-tag':self.tag.id } + + def test_valid_form_submission_without_webhook(self): + """Test a valid form submission.""" + form_data = self.form_data_template form = CreateVmForm(data=form_data) vm = form.process_creation(form_data) @@ -74,6 +78,71 @@ class CreateVmFormTestCase(TestCase): #Assert Services self.assertEqual(Service.objects.filter(virtual_machine=vm).count(), 3) + def test_invalid_form(self): + """Test a valid form submission.""" + + #invalid json + self.invalid_ports_form_data = self.form_data_template.copy() + self.invalid_ports_form_data["domainnames_new-domain_names"] = "Invalid" # Invalid format + + form_data = self.invalid_ports_form_data + form = CreateVmForm(data=form_data) + with self.assertRaises(ValueError) as context: + form.process_creation(form_data) + self.assertIn( + "Invalid JSON format: Please provide a valid JSON object.", str(context.exception)) + + #black ports + self.invalid_ports_form_data = self.form_data_template.copy() + self.invalid_ports_form_data["service_ntp-0-ports"] = "" # Invalid format + form_data = self.invalid_ports_form_data + form = CreateVmForm(data=form_data) + with self.assertRaises(ValidationError) as context: + form.process_creation(form_data) + self.assertIn( + "{'ports': ['This field cannot be blank.']}", str(context.exception)) + + #invalid/black ports + self.invalid_ports_form_data = self.form_data_template.copy() + self.invalid_ports_form_data["service_ntp-0-ports"] = "1,A," # Invalid format + form_data = self.invalid_ports_form_data + form = CreateVmForm(data=form_data) + with self.assertRaises(ValueError) as context: + form.process_creation(form_data) + self.assertIn( + "Invalid ports value:", str(context.exception)) + + #invalid tag + self.invalid_ports_form_data = self.form_data_template.copy() + self.invalid_ports_form_data["tag_new-tag"] = "10" # Invalid format + form_data = self.invalid_ports_form_data + form = CreateVmForm(data=form_data) + with self.assertRaises(ValueError) as context: + form.process_creation(form_data) + self.assertIn( + "Invalid tag", str(context.exception)) + + #invalid role/owner + self.invalid_ports_form_data = self.form_data_template.copy() + self.invalid_ports_form_data["vms_new-0-role"] = "2" # Invalid format + form_data = self.invalid_ports_form_data + form = CreateVmForm(data=form_data) + with self.assertRaises(ValueError) as context: + form.process_creation(form_data) + self.assertIn( + "Error during creation: Invalid Device Role ID", str(context.exception)) + + #invalid platform + self.invalid_ports_form_data = self.form_data_template.copy() + self.invalid_ports_form_data["vms_new-0-platform"] = "2" # Invalid format + form_data = self.invalid_ports_form_data + form = CreateVmForm(data=form_data) + with self.assertRaises(ValueError) as context: + form.process_creation(form_data) + self.assertIn( + "Invalid Platform ID", str(context.exception)) + + def tearDown(self): """Clean up after tests.""" -- GitLab From add2dc815a80fb66f8e891a41cf8bd1b01c3642d Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Thu, 23 Jan 2025 15:47:05 +0000 Subject: [PATCH 3/5] =?UTF-8?q?=E2=9C=85=20add=20more=20validations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tests/createvm/test_createvm_view.py | 47 +++++++++++++++++-- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/netbox_sys_plugin/tests/createvm/test_createvm_view.py b/netbox_sys_plugin/tests/createvm/test_createvm_view.py index 8cb1e09..dff6958 100644 --- a/netbox_sys_plugin/tests/createvm/test_createvm_view.py +++ b/netbox_sys_plugin/tests/createvm/test_createvm_view.py @@ -81,9 +81,9 @@ class CreateVmFormTestCase(TestCase): def test_invalid_form(self): """Test a valid form submission.""" - #invalid json + #invalid domain names json self.invalid_ports_form_data = self.form_data_template.copy() - self.invalid_ports_form_data["domainnames_new-domain_names"] = "Invalid" # Invalid format + self.invalid_ports_form_data["domainnames_new-domain_names"] = "Invalid" # Invalid Json form_data = self.invalid_ports_form_data form = CreateVmForm(data=form_data) @@ -91,6 +91,17 @@ class CreateVmFormTestCase(TestCase): form.process_creation(form_data) self.assertIn( "Invalid JSON format: Please provide a valid JSON object.", str(context.exception)) + + #invalid structure + self.invalid_ports_form_data = self.form_data_template.copy() + self.invalid_ports_form_data["vmassignedextraconfig_new-extra_config_values"] = '{"field1": 1}' # Invalid Structure + + form_data = self.invalid_ports_form_data + form = CreateVmForm(data=form_data) + with self.assertRaises(ValueError) as context: + form.process_creation(form_data) + self.assertIn( + "Missing or empty required field: \'field1\' with type string", str(context.exception)) #black ports self.invalid_ports_form_data = self.form_data_template.copy() @@ -131,10 +142,20 @@ class CreateVmFormTestCase(TestCase): form.process_creation(form_data) self.assertIn( "Error during creation: Invalid Device Role ID", str(context.exception)) + + #blank role/owner + self.invalid_ports_form_data = self.form_data_template.copy() + self.invalid_ports_form_data["vms_new-0-role"] = "" # Invalid format + form_data = self.invalid_ports_form_data + form = CreateVmForm(data=form_data) + with self.assertRaises(ValueError) as context: + form.process_creation(form_data) + self.assertIn( + "Owner cannot be empty", str(context.exception)) #invalid platform self.invalid_ports_form_data = self.form_data_template.copy() - self.invalid_ports_form_data["vms_new-0-platform"] = "2" # Invalid format + self.invalid_ports_form_data["vms_new-0-platform"] = "2" # Invalid id form_data = self.invalid_ports_form_data form = CreateVmForm(data=form_data) with self.assertRaises(ValueError) as context: @@ -142,6 +163,26 @@ class CreateVmFormTestCase(TestCase): self.assertIn( "Invalid Platform ID", str(context.exception)) + #blank platform + self.invalid_ports_form_data = self.form_data_template.copy() + self.invalid_ports_form_data["vms_new-0-platform"] = "" # Invalid id + form_data = self.invalid_ports_form_data + form = CreateVmForm(data=form_data) + with self.assertRaises(ValueError) as context: + form.process_creation(form_data) + self.assertIn( + "Platform cannot be empty", str(context.exception)) + + #invalid Extra Config + self.invalid_ports_form_data = self.form_data_template.copy() + self.invalid_ports_form_data["vmassignedextraconfig_new-provider_type_extra_config"] = "2" # Invalid id + form_data = self.invalid_ports_form_data + form = CreateVmForm(data=form_data) + with self.assertRaises(ValueError) as context: + form.process_creation(form_data) + self.assertIn( + "Invalid Extra Config Structure", str(context.exception)) + def tearDown(self): -- GitLab From c48414ccb03d1aa9668eda542bfb2cb469f97433 Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Thu, 23 Jan 2025 16:02:25 +0000 Subject: [PATCH 4/5] =?UTF-8?q?=F0=9F=9A=A8=20Fix=20lint=20issues?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .pylintrc | 3 +++ netbox_sys_plugin/tests/createvm/test_createvm_view.py | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.pylintrc b/.pylintrc index 97d54e7..422a231 100644 --- a/.pylintrc +++ b/.pylintrc @@ -10,6 +10,9 @@ max-line-length=180 [FORMAT] max-line-length=180 +[DESIGN] +max-statements=100 + [MESSAGES CONTROL] diff --git a/netbox_sys_plugin/tests/createvm/test_createvm_view.py b/netbox_sys_plugin/tests/createvm/test_createvm_view.py index dff6958..c6dd424 100644 --- a/netbox_sys_plugin/tests/createvm/test_createvm_view.py +++ b/netbox_sys_plugin/tests/createvm/test_createvm_view.py @@ -91,7 +91,7 @@ class CreateVmFormTestCase(TestCase): form.process_creation(form_data) self.assertIn( "Invalid JSON format: Please provide a valid JSON object.", str(context.exception)) - + #invalid structure self.invalid_ports_form_data = self.form_data_template.copy() self.invalid_ports_form_data["vmassignedextraconfig_new-extra_config_values"] = '{"field1": 1}' # Invalid Structure @@ -142,7 +142,7 @@ class CreateVmFormTestCase(TestCase): form.process_creation(form_data) self.assertIn( "Error during creation: Invalid Device Role ID", str(context.exception)) - + #blank role/owner self.invalid_ports_form_data = self.form_data_template.copy() self.invalid_ports_form_data["vms_new-0-role"] = "" # Invalid format @@ -172,7 +172,7 @@ class CreateVmFormTestCase(TestCase): form.process_creation(form_data) self.assertIn( "Platform cannot be empty", str(context.exception)) - + #invalid Extra Config self.invalid_ports_form_data = self.form_data_template.copy() self.invalid_ports_form_data["vmassignedextraconfig_new-provider_type_extra_config"] = "2" # Invalid id -- GitLab From 5f4c17a5455e6d80c6d026785dce94e2c811dbf5 Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Thu, 23 Jan 2025 16:30:17 +0000 Subject: [PATCH 5/5] =?UTF-8?q?=F0=9F=93=9D=20Add=20better=20Create=20vm?= =?UTF-8?q?=20test=20doc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/tests/createvm/test_createvm_view.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/netbox_sys_plugin/tests/createvm/test_createvm_view.py b/netbox_sys_plugin/tests/createvm/test_createvm_view.py index c6dd424..5c09480 100644 --- a/netbox_sys_plugin/tests/createvm/test_createvm_view.py +++ b/netbox_sys_plugin/tests/createvm/test_createvm_view.py @@ -1,4 +1,5 @@ -# test_create_vm_form.py +"""SYS Plugin CreateVM Testing Test Case Class""" + from django.test import TestCase from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError -- GitLab