From e80bdd3c97ddff198a3e10509c4987fe593fb400 Mon Sep 17 00:00:00 2001
From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu>
Date: Fri, 17 Jan 2025 16:09:18 +0000
Subject: [PATCH 1/6] =?UTF-8?q?=E2=9C=85=20Add=20API=20tests=20to=20Domain?=
 =?UTF-8?q?=20names?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 netbox_sys_plugin/api/serializers.py          |  12 +-
 netbox_sys_plugin/forms/machine.py            |   2 +-
 .../tests/vm_domain_names/__init__.py         |   0
 .../test_vm_domain_names_api.py               | 216 ++++++++++++++++++
 4 files changed, 227 insertions(+), 3 deletions(-)
 create mode 100644 netbox_sys_plugin/tests/vm_domain_names/__init__.py
 create mode 100644 netbox_sys_plugin/tests/vm_domain_names/test_vm_domain_names_api.py

diff --git a/netbox_sys_plugin/api/serializers.py b/netbox_sys_plugin/api/serializers.py
index 2c4bcbd..f9086f8 100644
--- a/netbox_sys_plugin/api/serializers.py
+++ b/netbox_sys_plugin/api/serializers.py
@@ -113,13 +113,21 @@ class DomainNamesSerializer(NetBoxModelSerializer):
     id = serializers.IntegerField(read_only=True)
     virtual_machine = NestedVirtualMachineSerializer(source='assigned_object', read_only=True)
     assigned_object_id = serializers.IntegerField(write_only=True)
-    assigned_object_type = serializers.CharField(write_only=True)
-    display = serializers.CharField(source="__str__")
+    assigned_object_type = serializers.PrimaryKeyRelatedField(
+        queryset=ContentType.objects.all(),
+        write_only=True,
+        )
+    display = serializers.CharField(source="__str__",read_only=True)
 
     class Meta:
         model = DomainNames
         fields = '__all__'
 
+    def create(self, validated_data):
+        assigned_object_type = validated_data.pop("assigned_object_type")
+        validated_data["assigned_object_type"] = assigned_object_type
+        return super().create(validated_data)
+
 class WebhookSettingsSerializer(NetBoxModelSerializer):
     id = serializers.IntegerField(read_only=True)
 
diff --git a/netbox_sys_plugin/forms/machine.py b/netbox_sys_plugin/forms/machine.py
index 36d18c3..2d9fb45 100644
--- a/netbox_sys_plugin/forms/machine.py
+++ b/netbox_sys_plugin/forms/machine.py
@@ -190,7 +190,7 @@ class DomainNamesForm(NetBoxModelForm):
         #Check if Virtual Machine is assigned corretly
         if not vm:
             raise ValidationError(
-                {"__all__": "Can't assign more than one Maintenance Window to the same Virtual Machine"},
+                {"__all__": "Can't assign more than one group of domain names to the same Virtual Machine"},
             )
 
     def save(self, *args, **kwargs):
diff --git a/netbox_sys_plugin/tests/vm_domain_names/__init__.py b/netbox_sys_plugin/tests/vm_domain_names/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/netbox_sys_plugin/tests/vm_domain_names/test_vm_domain_names_api.py b/netbox_sys_plugin/tests/vm_domain_names/test_vm_domain_names_api.py
new file mode 100644
index 0000000..9240b0d
--- /dev/null
+++ b/netbox_sys_plugin/tests/vm_domain_names/test_vm_domain_names_api.py
@@ -0,0 +1,216 @@
+"""SYS Plugin VM domain names API Test Case Class"""
+
+from users.models import ObjectPermission
+from django.contrib.contenttypes.models import ContentType
+from rest_framework import status
+from virtualization.models import VirtualMachine, Cluster, ClusterType
+from netbox_sys_plugin.models import DomainNames
+from ..base import BaseAPITestCase
+
+class VirtualMachineMaintenanceApiTestCase(BaseAPITestCase):
+    """Test suite for VirtualMachineMaintenance API"""
+    model = DomainNames
+    brief_fields = ["domain_names", "assigned_object_id", "assigned_object_type"]
+
+
+    @classmethod
+    def setUpTestData(cls):
+
+        """Set up test data for DomainNames API"""
+        cls.vm_ct = ContentType.objects.get_for_model(VirtualMachine)
+
+        # Create a ClusterType
+        cls.cluster_type = ClusterType.objects.create(name="Test ClusterType")
+
+        # Create a Cluster linked to the ClusterType
+        cls.cluster = Cluster.objects.create(name="Test Cluster", type=cls.cluster_type)
+
+        # Create a VirtualMachine linked to the Cluster
+        cls.virtual_machine = VirtualMachine.objects.create(
+            name="Test VM",
+            status="active",
+            cluster=cls.cluster
+        )
+
+        # Create a VirtualMachine 2 linked to the Cluster
+        cls.virtual_machine2 = VirtualMachine.objects.create(
+            name="Test VM2",
+            status="active",
+            cluster=cls.cluster
+        )
+
+        # Create a VirtualMachine 3 linked to the Cluster
+        cls.virtual_machine3 = VirtualMachine.objects.create(
+            name="Test VM3",
+            status="active",
+            cluster=cls.cluster
+        )
+
+        # Create a VirtualMachine 4 linked to the Cluster
+        cls.virtual_machine4 = VirtualMachine.objects.create(
+            name="Test VM4",
+            status="active",
+            cluster=cls.cluster
+        )
+        # Create a VirtualMachine 5 linked to the Cluster
+        cls.virtual_machine5 = VirtualMachine.objects.create(
+            name="Test VM5",
+            status="active",
+            cluster=cls.cluster
+        )
+        # Create a VirtualMachine 6 linked to the Cluster
+        cls.virtual_machine6 = VirtualMachine.objects.create(
+            name="Test VM6",
+            status="active",
+            cluster=cls.cluster
+        )
+
+        # Create maintenance entries linked to the VirtualMachine
+        DomainNames.objects.create(
+            domain_names={'domain1':'ec.test.test','domain2':'ec.test2.test2'},
+            assigned_object=cls.virtual_machine
+        )
+        DomainNames.objects.create(
+            domain_names={'domain1':'ec.test.test','domain2':'ec.test2.test2'},
+            assigned_object=cls.virtual_machine2
+        )
+
+        # Data for valid creation
+        cls.valid_create_data = [
+            {
+                "domain_names": {'domain1':'ec.test.test','domain2':'ec.test2.test2'},
+                "assigned_object_type": cls.vm_ct.pk,
+                "assigned_object_id": cls.virtual_machine3.id,
+            }
+        ]
+
+        # Data for invalid creation
+        cls.invalid_create_data = [
+            #{
+            #    "domain_names": "invalid-format",
+            #    "assigned_object_type": cls.vm_ct.pk,
+            #    "assigned_object_id": cls.virtual_machine4.id,
+            #},
+            {
+                "domain_names": {'domain1':'ec.test.test','domain2':'ec.test2.test2'},
+                "assigned_object_type": cls.vm_ct.pk,
+                "assigned_object_id": None,  # Missing VirtualMachine
+            },
+        ]
+
+        # Data for checking  unique key
+        cls.valid_check_unique_data = [
+            {
+                "domain_names": {'domain1':'ec.test.test','domain2':'ec.test2.test2'},
+                "assigned_object_type": cls.vm_ct.pk,
+                "assigned_object_id": cls.virtual_machine6.id, # Same Virtual Machine
+            },
+            {
+                "domain_names": {'domain1':'ec.test.test','domain2':'ec.test2.test2'},
+                "assigned_object_type": cls.vm_ct.pk,
+                "assigned_object_id": cls.virtual_machine6.id, # Same Virtual Machine
+            }
+        ]
+
+    def test_create_valid_domain_names(self):
+        """Test creating a valid Domain Names"""
+        obj_perm = ObjectPermission(
+            name="Create Domain Names Permission",
+            actions=["add", "view"],
+        )
+        obj_perm.save()
+        obj_perm.users.add(self.user)
+        obj_perm.object_types.add(ContentType.objects.get_for_model(DomainNames))
+
+        form_data = self.valid_create_data[0]
+        response = self.client.post(self._get_list_url(), form_data, format="json", **self.header)
+        self.assertHttpStatus(response, status.HTTP_201_CREATED)
+        self.assertEqual(response.data["domain_names"], form_data["domain_names"])
+
+    def test_maintenance_window_unique_key(self):
+        """Test maintenance windows unique key"""
+        obj_perm = ObjectPermission(
+            name="Invalid Maintenance Permission",
+            actions=["add", "view"],
+        )
+        obj_perm.save()
+        obj_perm.users.add(self.user)
+        obj_perm.object_types.add(ContentType.objects.get_for_model(DomainNames))
+
+        for form_data in self.valid_check_unique_data:
+            response = self.client.post(self._get_list_url(), form_data, format="json", **self.header)
+        self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
+
+    def test_create_invalid_domain_names(self):
+        """Test creating invalid domain names"""
+        obj_perm = ObjectPermission(
+            name="Invalid domain names Permission",
+            actions=["add", "view"],
+        )
+        obj_perm.save()
+        obj_perm.users.add(self.user)
+        obj_perm.object_types.add(ContentType.objects.get_for_model(DomainNames))
+
+        for form_data in self.invalid_create_data:
+            response = self.client.post(self._get_list_url(), form_data, format="json", **self.header)
+            self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
+
+    def test_update_domain_names(self):
+        """Test updating an existing domain names"""
+        domain_names = DomainNames.objects.first()
+        obj_perm = ObjectPermission(
+            name="Update domain names Permission",
+            actions=["change", "view"],
+        )
+        obj_perm.save()
+        obj_perm.users.add(self.user)
+        obj_perm.object_types.add(ContentType.objects.get_for_model(DomainNames))
+
+        update_data = {'domain_names': {'domain1':'ec.test.test','domain2':'ec.test2.test2'}}
+        response = self.client.patch(self._get_detail_url(domain_names), update_data, format="json", **self.header)
+        self.assertHttpStatus(response, status.HTTP_200_OK)
+        self.assertEqual(response.data["domain_names"], update_data["domain_names"])
+
+    def test_delete_domain_names(self):
+        """Test deleting a domain names"""
+        maintenance = DomainNames.objects.first()
+        obj_perm = ObjectPermission(
+            name="Delete Maintenance Permission",
+            actions=["delete"],
+        )
+        obj_perm.save()
+        obj_perm.users.add(self.user)
+        obj_perm.object_types.add(ContentType.objects.get_for_model(DomainNames))
+
+        response = self.client.delete(self._get_detail_url(maintenance), **self.header)
+        self.assertHttpStatus(response, status.HTTP_204_NO_CONTENT)
+        self.assertFalse(DomainNames.objects.filter(id=maintenance.id).exists())
+
+    def test_get_all_maintenance_windows(self):
+        """Test fetching all maintenance windows"""
+        obj_perm = ObjectPermission(
+            name="View Maintenance Permission",
+            actions=["view"],
+        )
+        obj_perm.save()
+        obj_perm.users.add(self.user)
+        obj_perm.object_types.add(ContentType.objects.get_for_model(DomainNames))
+
+        response = self.client.get(self._get_list_url(), **self.header)
+        self.assertHttpStatus(response, status.HTTP_200_OK)
+        self.assertGreaterEqual(len(response.data), 2)
+
+    def test_get_single_domain_names(self):
+        """Test fetching a single domain names"""
+        obj_perm = ObjectPermission(
+            name="View domain names Permission",
+            actions=["view"],
+        )
+        obj_perm.save()
+        obj_perm.users.add(self.user)
+        obj_perm.object_types.add(ContentType.objects.get_for_model(DomainNames))
+
+        domain_names = DomainNames.objects.first()
+        response = self.client.get(self._get_detail_url(domain_names), **self.header)
+        self.assertHttpStatus(response, status.HTTP_200_OK)
+        self.assertEqual(response.data["domain_names"], domain_names.domain_names)
-- 
GitLab


From 2b24f4134da9aa0af1c0cbd61a758eab6ecfd776 Mon Sep 17 00:00:00 2001
From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu>
Date: Fri, 17 Jan 2025 17:10:02 +0000
Subject: [PATCH 2/6] =?UTF-8?q?=E2=9C=85=20=F0=9F=90=9B=20Add=20working=20?=
 =?UTF-8?q?API=20tests=20and=20bug=20fixes?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 netbox_sys_plugin/forms/machine.py            |  8 ++-
 .../0004_alter_domainnames_domain_names.py    | 19 +++++++
 netbox_sys_plugin/models/machine.py           |  2 +-
 .../test_provider_type_extra_config_view.py   |  2 +-
 .../test_vm_domain_names_api.py               | 51 +++++++++++--------
 5 files changed, 58 insertions(+), 24 deletions(-)
 create mode 100644 netbox_sys_plugin/migrations/0004_alter_domainnames_domain_names.py

diff --git a/netbox_sys_plugin/forms/machine.py b/netbox_sys_plugin/forms/machine.py
index 2d9fb45..e78e861 100644
--- a/netbox_sys_plugin/forms/machine.py
+++ b/netbox_sys_plugin/forms/machine.py
@@ -152,7 +152,7 @@ class DomainNamesForm(NetBoxModelForm):
     )
     domain_names = JSONField(
         label=_('Domain Names'),
-        required=False
+        required=True
     )
 
     def __init__(self, *args, **kwargs):
@@ -186,6 +186,7 @@ class DomainNamesForm(NetBoxModelForm):
         super().clean()
 
         vm = self.cleaned_data.get("virtual_machine")
+        domain_names = self.cleaned_data.get("domain_names")
 
         #Check if Virtual Machine is assigned corretly
         if not vm:
@@ -193,6 +194,11 @@ class DomainNamesForm(NetBoxModelForm):
                 {"__all__": "Can't assign more than one group of domain names to the same Virtual Machine"},
             )
 
+        if not domain_names:
+            raise ValidationError(
+                {"__all__": "Domain names should not be empty"},
+            )
+
     def save(self, *args, **kwargs):
         """Set assigned object and save"""
         # Set assigned object
diff --git a/netbox_sys_plugin/migrations/0004_alter_domainnames_domain_names.py b/netbox_sys_plugin/migrations/0004_alter_domainnames_domain_names.py
new file mode 100644
index 0000000..561c270
--- /dev/null
+++ b/netbox_sys_plugin/migrations/0004_alter_domainnames_domain_names.py
@@ -0,0 +1,19 @@
+# Generated by Django 4.2.16 on 2025-01-17 17:00
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('netbox_sys_plugin', '0003_alter_providertypeextraconfig_assigned_object_type_and_more'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='domainnames',
+            name='domain_names',
+            field=models.JSONField(blank=True, default={}),
+            preserve_default=False,
+        ),
+    ]
diff --git a/netbox_sys_plugin/models/machine.py b/netbox_sys_plugin/models/machine.py
index 6ffd6d9..9dc3495 100644
--- a/netbox_sys_plugin/models/machine.py
+++ b/netbox_sys_plugin/models/machine.py
@@ -120,7 +120,7 @@ class DomainNames(NetBoxModel):
 
     domain_names = models.JSONField(
         blank=True,
-        null=True,
+        null=False,
     )
 
     assigned_object_type = models.ForeignKey(
diff --git a/netbox_sys_plugin/tests/provider_type_extra_config/test_provider_type_extra_config_view.py b/netbox_sys_plugin/tests/provider_type_extra_config/test_provider_type_extra_config_view.py
index 243f050..d0c1218 100644
--- a/netbox_sys_plugin/tests/provider_type_extra_config/test_provider_type_extra_config_view.py
+++ b/netbox_sys_plugin/tests/provider_type_extra_config/test_provider_type_extra_config_view.py
@@ -78,7 +78,7 @@ class ProviderTypeExtraConfigFormTestCase(
 
     def test_invalid_extra_config_format(self):
         """
-        Test invalid maintenance window invalid format.
+        Test invalid extra config invalid format.
         """
 
         # Create VLAN and VLANGroup for testing
diff --git a/netbox_sys_plugin/tests/vm_domain_names/test_vm_domain_names_api.py b/netbox_sys_plugin/tests/vm_domain_names/test_vm_domain_names_api.py
index 9240b0d..0117333 100644
--- a/netbox_sys_plugin/tests/vm_domain_names/test_vm_domain_names_api.py
+++ b/netbox_sys_plugin/tests/vm_domain_names/test_vm_domain_names_api.py
@@ -7,8 +7,8 @@ from virtualization.models import VirtualMachine, Cluster, ClusterType
 from netbox_sys_plugin.models import DomainNames
 from ..base import BaseAPITestCase
 
-class VirtualMachineMaintenanceApiTestCase(BaseAPITestCase):
-    """Test suite for VirtualMachineMaintenance API"""
+class VirtualMachinedomain_namesApiTestCase(BaseAPITestCase):
+    """Test suite for VirtualMachinedomain_names API"""
     model = DomainNames
     brief_fields = ["domain_names", "assigned_object_id", "assigned_object_type"]
 
@@ -65,7 +65,7 @@ class VirtualMachineMaintenanceApiTestCase(BaseAPITestCase):
             cluster=cls.cluster
         )
 
-        # Create maintenance entries linked to the VirtualMachine
+        # Create domain_names entries linked to the VirtualMachine
         DomainNames.objects.create(
             domain_names={'domain1':'ec.test.test','domain2':'ec.test2.test2'},
             assigned_object=cls.virtual_machine
@@ -86,11 +86,11 @@ class VirtualMachineMaintenanceApiTestCase(BaseAPITestCase):
 
         # Data for invalid creation
         cls.invalid_create_data = [
-            #{
-            #    "domain_names": "invalid-format",
-            #    "assigned_object_type": cls.vm_ct.pk,
-            #    "assigned_object_id": cls.virtual_machine4.id,
-            #},
+            {
+                "domain_names": None,
+                "assigned_object_type": cls.vm_ct.pk,
+                "assigned_object_id": cls.virtual_machine4.id,
+            },
             {
                 "domain_names": {'domain1':'ec.test.test','domain2':'ec.test2.test2'},
                 "assigned_object_type": cls.vm_ct.pk,
@@ -127,10 +127,10 @@ class VirtualMachineMaintenanceApiTestCase(BaseAPITestCase):
         self.assertHttpStatus(response, status.HTTP_201_CREATED)
         self.assertEqual(response.data["domain_names"], form_data["domain_names"])
 
-    def test_maintenance_window_unique_key(self):
-        """Test maintenance windows unique key"""
+    def test_domain_names_unique_key(self):
+        """Test domain names unique key"""
         obj_perm = ObjectPermission(
-            name="Invalid Maintenance Permission",
+            name="Invalid domain names Permission",
             actions=["add", "view"],
         )
         obj_perm.save()
@@ -151,9 +151,18 @@ class VirtualMachineMaintenanceApiTestCase(BaseAPITestCase):
         obj_perm.users.add(self.user)
         obj_perm.object_types.add(ContentType.objects.get_for_model(DomainNames))
 
-        for form_data in self.invalid_create_data:
-            response = self.client.post(self._get_list_url(), form_data, format="json", **self.header)
-            self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
+        form_data = self.invalid_create_data[0]
+        print("form_data",form_data)
+        response = self.client.post(self._get_list_url(), form_data, format="json", **self.header)
+        print("RESPONSE API 1",response.data)
+        self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
+        self.assertIn('This field may not be null.',str(response.data))
+
+        form_data = self.invalid_create_data[1]
+        response = self.client.post(self._get_list_url(), form_data, format="json", **self.header)
+        print("RESPONSE API 2",response.data)
+        self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
+        self.assertIn('This field may not be null.',str(response.data))
 
     def test_update_domain_names(self):
         """Test updating an existing domain names"""
@@ -173,23 +182,23 @@ class VirtualMachineMaintenanceApiTestCase(BaseAPITestCase):
 
     def test_delete_domain_names(self):
         """Test deleting a domain names"""
-        maintenance = DomainNames.objects.first()
+        domain_names = DomainNames.objects.first()
         obj_perm = ObjectPermission(
-            name="Delete Maintenance Permission",
+            name="Delete domain names Permission",
             actions=["delete"],
         )
         obj_perm.save()
         obj_perm.users.add(self.user)
         obj_perm.object_types.add(ContentType.objects.get_for_model(DomainNames))
 
-        response = self.client.delete(self._get_detail_url(maintenance), **self.header)
+        response = self.client.delete(self._get_detail_url(domain_names), **self.header)
         self.assertHttpStatus(response, status.HTTP_204_NO_CONTENT)
-        self.assertFalse(DomainNames.objects.filter(id=maintenance.id).exists())
+        self.assertFalse(DomainNames.objects.filter(id=domain_names.id).exists())
 
-    def test_get_all_maintenance_windows(self):
-        """Test fetching all maintenance windows"""
+    def test_get_all_domain_names(self):
+        """Test fetching all domain names"""
         obj_perm = ObjectPermission(
-            name="View Maintenance Permission",
+            name="View domain_names Permission",
             actions=["view"],
         )
         obj_perm.save()
-- 
GitLab


From c6f182c5822885a42e73ec6e920eeb9fa08c6bb5 Mon Sep 17 00:00:00 2001
From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu>
Date: Mon, 20 Jan 2025 10:24:30 +0000
Subject: [PATCH 3/6] =?UTF-8?q?=E2=9C=85=20Add=20view=20test=20for=20Domai?=
 =?UTF-8?q?n=20Names?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../test_vm_domain_names_view.py              | 129 ++++++++++++++++++
 1 file changed, 129 insertions(+)
 create mode 100644 netbox_sys_plugin/tests/vm_domain_names/test_vm_domain_names_view.py

diff --git a/netbox_sys_plugin/tests/vm_domain_names/test_vm_domain_names_view.py b/netbox_sys_plugin/tests/vm_domain_names/test_vm_domain_names_view.py
new file mode 100644
index 0000000..c6f7b99
--- /dev/null
+++ b/netbox_sys_plugin/tests/vm_domain_names/test_vm_domain_names_view.py
@@ -0,0 +1,129 @@
+"""VM domain names Views Test Case Class"""
+
+from django.contrib.contenttypes.models import ContentType
+from users.models import ObjectPermission
+from virtualization.models import VirtualMachine, Cluster, ClusterType
+from netbox_sys_plugin.models import DomainNames
+from netbox_sys_plugin.forms import DomainNamesForm
+from .. base import BaseModelViewTestCase
+
+
+
+class DomainNamesFormTestCase(
+    BaseModelViewTestCase,
+):
+    """VM domain names Test Case Class"""
+
+    model = DomainNames
+    form = DomainNamesForm
+
+
+    @classmethod
+    # pylint: disable=invalid-name
+    def setUpTestData(cls):
+        """ SetUp Test Data """
+        #Create Cluster type, Cluster and VMs
+        vm_content_type = ContentType.objects.get_for_model(VirtualMachine)
+        cluster_type = ClusterType.objects.create(name="Test ClusterType1", slug="ClusterType1")
+        cluster = Cluster.objects.create(name="Test Cluster1", type=cluster_type)
+        virtual_machine = VirtualMachine.objects.create(name="Test VM",status="active",cluster=cluster)
+        virtual_machine2 = VirtualMachine.objects.create(name="Test VM2",status="active",cluster=cluster)
+        DomainNames.objects.create(domain_names={'test_valid': [{'id': {'required': 'true','type': 'String'}}]},assigned_object_type=vm_content_type, assigned_object_id=virtual_machine.pk)
+        DomainNames.objects.create(domain_names={'test_valid': [{'id': {'required': 'true','type': 'String'}}]},assigned_object_type=vm_content_type, assigned_object_id=virtual_machine2.pk)
+
+        cls.form_data = {
+            "domain_names": {'test_valid': [{'id': {'required': 'true','type': 'String'}}]},
+            "virtual_machine": virtual_machine2.pk,
+
+        }
+
+    def test_create_domain_names_with_no_assigment(self):
+        """Test the creation a VM domain names with no VM assignement"""
+
+        form = DomainNamesForm(data= {
+            "domain_names": {'test_valid': [{'id': {'required': 'true','type': 'String'}}]},
+        })
+
+        self.assertFalse(form.is_valid())
+        # Setup object permissions for the test user
+        obj_perm = ObjectPermission(
+            name='Test permission',
+            actions=['add', 'change']
+        )
+        obj_perm.save()
+        obj_perm.users.add(self.user)  # pylint: disable=no-member
+        obj_perm.object_types.add(ContentType.objects.get_for_model(self.model)) # pylint: disable=no-member
+
+
+    def test_create_vm_with_two_assigment(self):
+        """Test the assignment of 2 domain namess to the same VM """
+        # pylint: disable=W0201
+        self.vm_content_type = ContentType.objects.get_for_model(VirtualMachine)
+        # pylint: disable=W0201
+        self.cluster_type = ClusterType.objects.create(name="Test ClusterType2", slug="ClusterType2")
+        # pylint: disable=W0201
+        self.cluster = Cluster.objects.create(name="Test Cluster2", type=self.cluster_type)
+        # pylint: disable=W0201
+        self.virtual_machine = VirtualMachine.objects.create(name="Test VM",status="active",cluster=self.cluster)
+        # pylint: disable=W0201
+        self.domain_names = DomainNames.objects.create(
+            domain_names={'test_valid': [{'id': {'required': 'true','type': 'String'}}]},
+            assigned_object_type=self.vm_content_type,
+            assigned_object_id=self.virtual_machine.pk
+            )
+
+        form = DomainNamesForm(data= {
+            "domain_names": {'test_valid': [{'id': {'required': 'true','type': 'String'}}]},
+            "virtual_machine": self.virtual_machine.pk,
+        })
+
+        self.assertFalse(form.is_valid())
+        # Setup object permissions for the test user
+        obj_perm = ObjectPermission(
+            name='Test permission',
+            actions=['add', 'change']
+        )
+        obj_perm.save()
+        obj_perm.users.add(self.user)  # pylint: disable=no-member
+        obj_perm.object_types.add(ContentType.objects.get_for_model(self.model)) # pylint: disable=no-member
+
+        self.assertIn(
+            "Can't assign more than one group of domain names to the same Virtual Machine",
+            form.errors.get("__all__",[])
+        )
+
+    def test_invalid_domain_names_format(self):
+        """
+        Test invalid domain names invalid format.
+        """
+
+        # Create VLAN and VLANGroup for testing
+        # pylint: disable=W0201
+        self.vm_content_type = ContentType.objects.get_for_model(VirtualMachine)
+        # pylint: disable=W0201
+        self.cluster_type = ClusterType.objects.create(name="Test ClusterType3", slug="ClusterType3")
+        # pylint: disable=W0201
+        self.cluster = Cluster.objects.create(name="Test Cluster3", type=self.cluster_type)
+        # pylint: disable=W0201
+        self.virtual_machine = VirtualMachine.objects.create(name="Test VM",status="active",cluster=self.cluster)
+
+        # Set up valid form data
+        self.valid_form_data = {
+            "virtual_machine": self.virtual_machine.pk,
+            "domain_names": {'test_valid': [{'id': {'required': 'true','type': 'String'}}]},
+            "tags": "",
+        }
+
+        invalid_form_data = self.valid_form_data.copy()
+        invalid_form_data["domain_names"] = "invalid"  # Invalid format
+        form = self.form(data=invalid_form_data)
+        self.assertFalse(form.is_valid())
+        self.assertIn(
+            "Enter a valid JSON.",
+            form.errors.get("domain_names", []),
+        )
+
+    def tearDown(self) -> None:# pylint: disable=invalid-name
+        """Method called immediately after the test method has been called and the result recorded."""
+        DomainNames.objects.all().delete()
+        super().tearDown()
-- 
GitLab


From 1c50cc0d94c46cbde4ac9552393e8361e869b3a7 Mon Sep 17 00:00:00 2001
From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu>
Date: Mon, 20 Jan 2025 10:34:24 +0000
Subject: [PATCH 4/6] =?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

---
 .../tests/vm_domain_names/test_vm_domain_names_view.py | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/netbox_sys_plugin/tests/vm_domain_names/test_vm_domain_names_view.py b/netbox_sys_plugin/tests/vm_domain_names/test_vm_domain_names_view.py
index c6f7b99..fb05def 100644
--- a/netbox_sys_plugin/tests/vm_domain_names/test_vm_domain_names_view.py
+++ b/netbox_sys_plugin/tests/vm_domain_names/test_vm_domain_names_view.py
@@ -28,8 +28,14 @@ class DomainNamesFormTestCase(
         cluster = Cluster.objects.create(name="Test Cluster1", type=cluster_type)
         virtual_machine = VirtualMachine.objects.create(name="Test VM",status="active",cluster=cluster)
         virtual_machine2 = VirtualMachine.objects.create(name="Test VM2",status="active",cluster=cluster)
-        DomainNames.objects.create(domain_names={'test_valid': [{'id': {'required': 'true','type': 'String'}}]},assigned_object_type=vm_content_type, assigned_object_id=virtual_machine.pk)
-        DomainNames.objects.create(domain_names={'test_valid': [{'id': {'required': 'true','type': 'String'}}]},assigned_object_type=vm_content_type, assigned_object_id=virtual_machine2.pk)
+        DomainNames.objects.create(
+            domain_names={'test_valid': [{'id': {'required': 'true','type': 'String'}}]},
+            assigned_object_type=vm_content_type, 
+            assigned_object_id=virtual_machine.pk)
+        DomainNames.objects.create(
+            domain_names={'test_valid': [{'id': {'required': 'true','type': 'String'}}]},
+            assigned_object_type=vm_content_type,
+            assigned_object_id=virtual_machine2.pk)
 
         cls.form_data = {
             "domain_names": {'test_valid': [{'id': {'required': 'true','type': 'String'}}]},
-- 
GitLab


From a2ac97bcf770523cca997caabda1d6fc49ff0d2f Mon Sep 17 00:00:00 2001
From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu>
Date: Mon, 20 Jan 2025 10:46:17 +0000
Subject: [PATCH 5/6] =?UTF-8?q?=F0=9F=9A=A8=20Fix=20Trailing=20whitespace?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../tests/vm_domain_names/test_vm_domain_names_view.py          | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/netbox_sys_plugin/tests/vm_domain_names/test_vm_domain_names_view.py b/netbox_sys_plugin/tests/vm_domain_names/test_vm_domain_names_view.py
index fb05def..21f3053 100644
--- a/netbox_sys_plugin/tests/vm_domain_names/test_vm_domain_names_view.py
+++ b/netbox_sys_plugin/tests/vm_domain_names/test_vm_domain_names_view.py
@@ -30,7 +30,7 @@ class DomainNamesFormTestCase(
         virtual_machine2 = VirtualMachine.objects.create(name="Test VM2",status="active",cluster=cluster)
         DomainNames.objects.create(
             domain_names={'test_valid': [{'id': {'required': 'true','type': 'String'}}]},
-            assigned_object_type=vm_content_type, 
+            assigned_object_type=vm_content_type,
             assigned_object_id=virtual_machine.pk)
         DomainNames.objects.create(
             domain_names={'test_valid': [{'id': {'required': 'true','type': 'String'}}]},
-- 
GitLab


From d55f82903208391181ec48226735064851dcf992 Mon Sep 17 00:00:00 2001
From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu>
Date: Mon, 20 Jan 2025 11:40:07 +0000
Subject: [PATCH 6/6] =?UTF-8?q?=E2=9C=85=20Add=20new=20test?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../test_vm_domain_names_view.py              | 45 +++++++++++++++----
 1 file changed, 36 insertions(+), 9 deletions(-)

diff --git a/netbox_sys_plugin/tests/vm_domain_names/test_vm_domain_names_view.py b/netbox_sys_plugin/tests/vm_domain_names/test_vm_domain_names_view.py
index 21f3053..7757766 100644
--- a/netbox_sys_plugin/tests/vm_domain_names/test_vm_domain_names_view.py
+++ b/netbox_sys_plugin/tests/vm_domain_names/test_vm_domain_names_view.py
@@ -29,25 +29,52 @@ class DomainNamesFormTestCase(
         virtual_machine = VirtualMachine.objects.create(name="Test VM",status="active",cluster=cluster)
         virtual_machine2 = VirtualMachine.objects.create(name="Test VM2",status="active",cluster=cluster)
         DomainNames.objects.create(
-            domain_names={'test_valid': [{'id': {'required': 'true','type': 'String'}}]},
+            domain_names={'test_setup': [{'id': {'required': 'true','type': 'String'}}]},
             assigned_object_type=vm_content_type,
             assigned_object_id=virtual_machine.pk)
         DomainNames.objects.create(
-            domain_names={'test_valid': [{'id': {'required': 'true','type': 'String'}}]},
+            domain_names={'test_setup': [{'id': {'required': 'true','type': 'String'}}]},
             assigned_object_type=vm_content_type,
             assigned_object_id=virtual_machine2.pk)
 
         cls.form_data = {
-            "domain_names": {'test_valid': [{'id': {'required': 'true','type': 'String'}}]},
+            "domain_names": {'test_setup': [{'id': {'required': 'true','type': 'String'}}]},
             "virtual_machine": virtual_machine2.pk,
 
         }
 
+    def test_create_valid_domain_names(self):
+        """Test domain name valid creation"""
+        # pylint: disable=W0201
+        self.vm_content_type = ContentType.objects.get_for_model(VirtualMachine)
+        # pylint: disable=W0201
+        self.cluster_type = ClusterType.objects.create(name="Test ClusterType2", slug="ClusterType2")
+        # pylint: disable=W0201
+        self.cluster = Cluster.objects.create(name="Test Cluster2", type=self.cluster_type)
+        # pylint: disable=W0201
+        self.virtual_machine_valid = VirtualMachine.objects.create(name="Test VM",status="active",cluster=self.cluster)
+
+        form = DomainNamesForm(data= {
+            "domain_names": {'test_valid': [{'id': {'required': 'true','type': 'String'}}]},
+            "virtual_machine": self.virtual_machine_valid.pk,
+        })
+
+        self.assertTrue(form.is_valid())
+        # Setup object permissions for the test user
+        obj_perm = ObjectPermission(
+            name='Test permission',
+            actions=['add', 'change']
+        )
+        obj_perm.save()
+        obj_perm.users.add(self.user)  # pylint: disable=no-member
+        obj_perm.object_types.add(ContentType.objects.get_for_model(self.model)) # pylint: disable=no-member
+
+
     def test_create_domain_names_with_no_assigment(self):
         """Test the creation a VM domain names with no VM assignement"""
 
         form = DomainNamesForm(data= {
-            "domain_names": {'test_valid': [{'id': {'required': 'true','type': 'String'}}]},
+            "domain_names": {'test_no_assignment': [{'id': {'required': 'true','type': 'String'}}]},
         })
 
         self.assertFalse(form.is_valid())
@@ -66,14 +93,14 @@ class DomainNamesFormTestCase(
         # pylint: disable=W0201
         self.vm_content_type = ContentType.objects.get_for_model(VirtualMachine)
         # pylint: disable=W0201
-        self.cluster_type = ClusterType.objects.create(name="Test ClusterType2", slug="ClusterType2")
+        self.cluster_type = ClusterType.objects.create(name="Test ClusterType3", slug="ClusterType3")
         # pylint: disable=W0201
-        self.cluster = Cluster.objects.create(name="Test Cluster2", type=self.cluster_type)
+        self.cluster = Cluster.objects.create(name="Test Cluster3", type=self.cluster_type)
         # pylint: disable=W0201
         self.virtual_machine = VirtualMachine.objects.create(name="Test VM",status="active",cluster=self.cluster)
         # pylint: disable=W0201
         self.domain_names = DomainNames.objects.create(
-            domain_names={'test_valid': [{'id': {'required': 'true','type': 'String'}}]},
+            domain_names={'test_2_assignment': [{'id': {'required': 'true','type': 'String'}}]},
             assigned_object_type=self.vm_content_type,
             assigned_object_id=self.virtual_machine.pk
             )
@@ -107,9 +134,9 @@ class DomainNamesFormTestCase(
         # pylint: disable=W0201
         self.vm_content_type = ContentType.objects.get_for_model(VirtualMachine)
         # pylint: disable=W0201
-        self.cluster_type = ClusterType.objects.create(name="Test ClusterType3", slug="ClusterType3")
+        self.cluster_type = ClusterType.objects.create(name="Test ClusterType4", slug="ClusterType4")
         # pylint: disable=W0201
-        self.cluster = Cluster.objects.create(name="Test Cluster3", type=self.cluster_type)
+        self.cluster = Cluster.objects.create(name="Test Cluster4", type=self.cluster_type)
         # pylint: disable=W0201
         self.virtual_machine = VirtualMachine.objects.create(name="Test VM",status="active",cluster=self.cluster)
 
-- 
GitLab