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