Kaynağa Gözat

5509 Add Test cases for Custom Fields (#12312)

* 5509 add content type data to model tests create and update

* 5509 update use cf form data

* 5509 update tests to use CustomFieldTypeChoices

* 5509 update tests to check custom fields

* Simplify custom fields used for testing

* Move custom field data functions to testing.utils

* Move validate_custom_field_data() into assertInstanceEqual()

---------

Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>
Arthur Hanson 1 yıl önce
ebeveyn
işleme
928014c766

+ 8 - 3
netbox/utilities/testing/base.py

@@ -10,10 +10,11 @@ from django.test import Client, TestCase as _TestCase
 from netaddr import IPNetwork
 from netaddr import IPNetwork
 from taggit.managers import TaggableManager
 from taggit.managers import TaggableManager
 
 
+from netbox.models.features import CustomFieldsMixin
 from users.models import ObjectPermission
 from users.models import ObjectPermission
 from utilities.permissions import resolve_permission_ct
 from utilities.permissions import resolve_permission_ct
 from utilities.utils import content_type_identifier
 from utilities.utils import content_type_identifier
-from .utils import extract_form_failures
+from .utils import DUMMY_CF_DATA, extract_form_failures
 
 
 __all__ = (
 __all__ = (
     'ModelTestCase',
     'ModelTestCase',
@@ -166,8 +167,12 @@ class ModelTestCase(TestCase):
         model_dict = self.model_to_dict(instance, fields=fields, api=api)
         model_dict = self.model_to_dict(instance, fields=fields, api=api)
 
 
         # Omit any dictionary keys which are not instance attributes or have been excluded
         # Omit any dictionary keys which are not instance attributes or have been excluded
-        relevant_data = {
+        model_data = {
             k: v for k, v in data.items() if hasattr(instance, k) and k not in exclude
             k: v for k, v in data.items() if hasattr(instance, k) and k not in exclude
         }
         }
 
 
-        self.assertDictEqual(model_dict, relevant_data)
+        self.assertDictEqual(model_dict, model_data)
+
+        # Validate any custom field data, if present
+        if getattr(instance, 'custom_field_data', None):
+            self.assertDictEqual(instance.custom_field_data, DUMMY_CF_DATA)

+ 43 - 1
netbox/utilities/testing/utils.py

@@ -1,13 +1,16 @@
+import json
 import logging
 import logging
 import re
 import re
 from contextlib import contextmanager
 from contextlib import contextmanager
 
 
 from django.contrib.auth import get_user_model
 from django.contrib.auth import get_user_model
 from django.contrib.auth.models import Permission
 from django.contrib.auth.models import Permission
+from django.contrib.contenttypes.models import ContentType
 from django.utils.text import slugify
 from django.utils.text import slugify
 
 
 from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site
 from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site
-from extras.models import Tag
+from extras.choices import CustomFieldTypeChoices
+from extras.models import CustomField, Tag
 from virtualization.models import Cluster, ClusterType, VirtualMachine
 from virtualization.models import Cluster, ClusterType, VirtualMachine
 
 
 
 
@@ -102,3 +105,42 @@ def disable_warnings(logger_name):
     logger.setLevel(logging.ERROR)
     logger.setLevel(logging.ERROR)
     yield
     yield
     logger.setLevel(current_level)
     logger.setLevel(current_level)
+
+
+#
+# Custom field testing
+#
+
+DUMMY_CF_DATA = {
+    'text_field': 'foo123',
+    'integer_field': 456,
+    'decimal_field': 456.12,
+    'boolean_field': True,
+    'json_field': {'abc': 123},
+}
+
+
+def add_custom_field_data(form_data, model):
+    """
+    Create some custom fields for the model and add a value for each to the form data.
+
+    Args:
+        form_data: The dictionary of form data to be updated
+        model: The model of the object the form seeks to create or modify
+    """
+    content_type = ContentType.objects.get_for_model(model)
+    custom_fields = (
+        CustomField(type=CustomFieldTypeChoices.TYPE_TEXT, name='text_field', default='foo'),
+        CustomField(type=CustomFieldTypeChoices.TYPE_INTEGER, name='integer_field', default=123),
+        CustomField(type=CustomFieldTypeChoices.TYPE_DECIMAL, name='decimal_field', default=123.45),
+        CustomField(type=CustomFieldTypeChoices.TYPE_BOOLEAN, name='boolean_field', default=False),
+        CustomField(type=CustomFieldTypeChoices.TYPE_JSON, name='json_field', default='{"x": "y"}'),
+    )
+    CustomField.objects.bulk_create(custom_fields)
+    for cf in custom_fields:
+        cf.content_types.set([content_type])
+
+    form_data.update({
+        f'cf_{k}': v if type(v) is str else json.dumps(v)
+        for k, v in DUMMY_CF_DATA.items()
+    })

+ 10 - 3
netbox/utilities/testing/views.py

@@ -10,11 +10,11 @@ from django.utils.translation import gettext as _
 
 
 from extras.choices import ObjectChangeActionChoices
 from extras.choices import ObjectChangeActionChoices
 from extras.models import ObjectChange
 from extras.models import ObjectChange
-from netbox.models.features import ChangeLoggingMixin
+from netbox.models.features import ChangeLoggingMixin, CustomFieldsMixin
 from users.models import ObjectPermission
 from users.models import ObjectPermission
 from utilities.choices import CSVDelimiterChoices, ImportFormatChoices
 from utilities.choices import CSVDelimiterChoices, ImportFormatChoices
 from .base import ModelTestCase
 from .base import ModelTestCase
-from .utils import disable_warnings, post_data
+from .utils import add_custom_field_data, disable_warnings, post_data
 
 
 __all__ = (
 __all__ = (
     'ModelViewTestCase',
     'ModelViewTestCase',
@@ -26,7 +26,6 @@ __all__ = (
 # UI Tests
 # UI Tests
 #
 #
 
 
-
 class ModelViewTestCase(ModelTestCase):
 class ModelViewTestCase(ModelTestCase):
     """
     """
     Base TestCase for model views. Subclass to test individual views.
     Base TestCase for model views. Subclass to test individual views.
@@ -166,6 +165,10 @@ class ViewTestCases:
             # Try GET with model-level permission
             # Try GET with model-level permission
             self.assertHttpStatus(self.client.get(self._get_url('add')), 200)
             self.assertHttpStatus(self.client.get(self._get_url('add')), 200)
 
 
+            # Add custom field data if the model supports it
+            if issubclass(self.model, CustomFieldsMixin):
+                add_custom_field_data(self.form_data, self.model)
+
             # Try POST with model-level permission
             # Try POST with model-level permission
             initial_count = self._get_queryset().count()
             initial_count = self._get_queryset().count()
             request = {
             request = {
@@ -265,6 +268,10 @@ class ViewTestCases:
             # Try GET with model-level permission
             # Try GET with model-level permission
             self.assertHttpStatus(self.client.get(self._get_url('edit', instance)), 200)
             self.assertHttpStatus(self.client.get(self._get_url('edit', instance)), 200)
 
 
+            # Add custom field data if the model supports it
+            if issubclass(self.model, CustomFieldsMixin):
+                add_custom_field_data(self.form_data, self.model)
+
             # Try POST with model-level permission
             # Try POST with model-level permission
             request = {
             request = {
                 'path': self._get_url('edit', instance),
                 'path': self._get_url('edit', instance),