Browse Source

Merge pull request #3922 from netbox-community/3921-choices-tests

Closes #3921: Add tests for API _choices endpoints
Jeremy Stretch 6 years ago
parent
commit
b538495a29

+ 17 - 1
netbox/circuits/tests/test_api.py

@@ -6,7 +6,23 @@ from circuits.choices import *
 from circuits.models import Circuit, CircuitTermination, CircuitType, Provider
 from circuits.models import Circuit, CircuitTermination, CircuitType, Provider
 from dcim.models import Site
 from dcim.models import Site
 from extras.models import Graph
 from extras.models import Graph
-from utilities.testing import APITestCase
+from utilities.testing import APITestCase, choices_to_dict
+
+
+class ChoicesTest(APITestCase):
+
+    def test_choices(self):
+
+        url = reverse('circuits-api:field-choice-list')
+        response = self.client.get(url, **self.header)
+
+        self.assertEqual(response.status_code, 200)
+
+        # Circuit
+        self.assertEqual(choices_to_dict(response.data.get('circuit:status')), CircuitStatusChoices.as_dict())
+
+        # CircuitTermination
+        self.assertEqual(choices_to_dict(response.data.get('circuit-termination:term_side')), CircuitTerminationSideChoices.as_dict())
 
 
 
 
 class ProviderTest(APITestCase):
 class ProviderTest(APITestCase):

+ 1 - 0
netbox/dcim/api/views.py

@@ -52,6 +52,7 @@ class DCIMFieldChoicesViewSet(FieldChoicesViewSet):
         (FrontPortTemplate, ['type']),
         (FrontPortTemplate, ['type']),
         (Interface, ['type', 'mode']),
         (Interface, ['type', 'mode']),
         (InterfaceTemplate, ['type']),
         (InterfaceTemplate, ['type']),
+        (PowerFeed, ['phase', 'status', 'supply', 'type']),
         (PowerOutlet, ['type', 'feed_leg']),
         (PowerOutlet, ['type', 'feed_leg']),
         (PowerOutletTemplate, ['type', 'feed_leg']),
         (PowerOutletTemplate, ['type', 'feed_leg']),
         (PowerPort, ['type', 'connection_status']),
         (PowerPort, ['type', 'connection_status']),

+ 77 - 1
netbox/dcim/tests/test_api.py

@@ -14,10 +14,86 @@ from dcim.models import (
 )
 )
 from ipam.models import IPAddress, VLAN
 from ipam.models import IPAddress, VLAN
 from extras.models import Graph
 from extras.models import Graph
-from utilities.testing import APITestCase
+from utilities.testing import APITestCase, choices_to_dict
 from virtualization.models import Cluster, ClusterType
 from virtualization.models import Cluster, ClusterType
 
 
 
 
+class ChoicesTest(APITestCase):
+
+    def test_choices(self):
+
+        url = reverse('dcim-api:field-choice-list')
+        response = self.client.get(url, **self.header)
+
+        self.assertEqual(response.status_code, 200)
+
+        # Cable
+        self.assertEqual(choices_to_dict(response.data.get('cable:length_unit')), CableLengthUnitChoices.as_dict())
+        self.assertEqual(choices_to_dict(response.data.get('cable:status')), CableStatusChoices.as_dict())
+        content_types = ContentType.objects.filter(model__in=CABLE_TERMINATION_TYPES)
+        cable_termination_choices = {
+            "{}.{}".format(ct.app_label, ct.model): ct.name for ct in content_types
+        }
+        self.assertEqual(choices_to_dict(response.data.get('cable:termination_a_type')), cable_termination_choices)
+        self.assertEqual(choices_to_dict(response.data.get('cable:termination_b_type')), cable_termination_choices)
+        self.assertEqual(choices_to_dict(response.data.get('cable:type')), CableTypeChoices.as_dict())
+
+        # Console ports
+        self.assertEqual(choices_to_dict(response.data.get('console-port:type')), ConsolePortTypeChoices.as_dict())
+        self.assertEqual(choices_to_dict(response.data.get('console-port:connection_status')), dict(CONNECTION_STATUS_CHOICES))
+        self.assertEqual(choices_to_dict(response.data.get('console-port-template:type')), ConsolePortTypeChoices.as_dict())
+
+        # Console server ports
+        self.assertEqual(choices_to_dict(response.data.get('console-server-port:type')), ConsolePortTypeChoices.as_dict())
+        self.assertEqual(choices_to_dict(response.data.get('console-server-port-template:type')), ConsolePortTypeChoices.as_dict())
+
+        # Device
+        self.assertEqual(choices_to_dict(response.data.get('device:face')), DeviceFaceChoices.as_dict())
+        self.assertEqual(choices_to_dict(response.data.get('device:status')), DeviceStatusChoices.as_dict())
+
+        # Device type
+        self.assertEqual(choices_to_dict(response.data.get('device-type:subdevice_role')), SubdeviceRoleChoices.as_dict())
+
+        # Front ports
+        self.assertEqual(choices_to_dict(response.data.get('front-port:type')), PortTypeChoices.as_dict())
+        self.assertEqual(choices_to_dict(response.data.get('front-port-template:type')), PortTypeChoices.as_dict())
+
+        # Interfaces
+        self.assertEqual(choices_to_dict(response.data.get('interface:type')), InterfaceTypeChoices.as_dict())
+        self.assertEqual(choices_to_dict(response.data.get('interface:mode')), InterfaceModeChoices.as_dict())
+        self.assertEqual(choices_to_dict(response.data.get('interface-template:type')), InterfaceTypeChoices.as_dict())
+
+        # Power feed
+        self.assertEqual(choices_to_dict(response.data.get('power-feed:phase')), PowerFeedPhaseChoices.as_dict())
+        self.assertEqual(choices_to_dict(response.data.get('power-feed:status')), PowerFeedStatusChoices.as_dict())
+        self.assertEqual(choices_to_dict(response.data.get('power-feed:supply')), PowerFeedSupplyChoices.as_dict())
+        self.assertEqual(choices_to_dict(response.data.get('power-feed:type')), PowerFeedTypeChoices.as_dict())
+
+        # Power outlets
+        self.assertEqual(choices_to_dict(response.data.get('power-outlet:type')), PowerOutletTypeChoices.as_dict())
+        self.assertEqual(choices_to_dict(response.data.get('power-outlet:feed_leg')), PowerOutletFeedLegChoices.as_dict())
+        self.assertEqual(choices_to_dict(response.data.get('power-outlet-template:type')), PowerOutletTypeChoices.as_dict())
+        self.assertEqual(choices_to_dict(response.data.get('power-outlet-template:feed_leg')), PowerOutletFeedLegChoices.as_dict())
+
+        # Power ports
+        self.assertEqual(choices_to_dict(response.data.get('power-port:type')), PowerPortTypeChoices.as_dict())
+        self.assertEqual(choices_to_dict(response.data.get('power-port:connection_status')), dict(CONNECTION_STATUS_CHOICES))
+        self.assertEqual(choices_to_dict(response.data.get('power-port-template:type')), PowerPortTypeChoices.as_dict())
+
+        # Rack
+        self.assertEqual(choices_to_dict(response.data.get('rack:type')), RackTypeChoices.as_dict())
+        self.assertEqual(choices_to_dict(response.data.get('rack:width')), RackWidthChoices.as_dict())
+        self.assertEqual(choices_to_dict(response.data.get('rack:status')), RackStatusChoices.as_dict())
+        self.assertEqual(choices_to_dict(response.data.get('rack:outer_unit')), RackDimensionUnitChoices.as_dict())
+
+        # Rear ports
+        self.assertEqual(choices_to_dict(response.data.get('rear-port:type')), PortTypeChoices.as_dict())
+        self.assertEqual(choices_to_dict(response.data.get('rear-port-template:type')), PortTypeChoices.as_dict())
+
+        # Site
+        self.assertEqual(choices_to_dict(response.data.get('site:status')), SiteStatusChoices.as_dict())
+
+
 class RegionTest(APITestCase):
 class RegionTest(APITestCase):
 
 
     def setUp(self):
     def setUp(self):

+ 28 - 1
netbox/extras/tests/test_api.py

@@ -7,10 +7,37 @@ from rest_framework import status
 
 
 from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Platform, Rack, RackGroup, RackRole, Region, Site
 from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Platform, Rack, RackGroup, RackRole, Region, Site
 from extras.api.views import ScriptViewSet
 from extras.api.views import ScriptViewSet
+from extras.choices import *
+from extras.constants import GRAPH_MODELS
 from extras.models import ConfigContext, Graph, ExportTemplate, Tag
 from extras.models import ConfigContext, Graph, ExportTemplate, Tag
 from extras.scripts import BooleanVar, IntegerVar, Script, StringVar
 from extras.scripts import BooleanVar, IntegerVar, Script, StringVar
 from tenancy.models import Tenant, TenantGroup
 from tenancy.models import Tenant, TenantGroup
-from utilities.testing import APITestCase
+from utilities.testing import APITestCase, choices_to_dict
+from utilities.utils import model_names_to_filter_dict
+
+
+class ChoicesTest(APITestCase):
+
+    def test_choices(self):
+
+        url = reverse('extras-api:field-choice-list')
+        response = self.client.get(url, **self.header)
+
+        self.assertEqual(response.status_code, 200)
+
+        # ExportTemplate
+        self.assertEqual(choices_to_dict(response.data.get('export-template:template_language')), ExportTemplateLanguageChoices.as_dict())
+
+        # Graph
+        content_types = ContentType.objects.filter(**model_names_to_filter_dict(GRAPH_MODELS))
+        graph_type_choices = {
+            "{}.{}".format(ct.app_label, ct.model): ct.name for ct in content_types
+        }
+        self.assertEqual(choices_to_dict(response.data.get('graph:type')), graph_type_choices)
+        self.assertEqual(choices_to_dict(response.data.get('graph:template_language')), ExportTemplateLanguageChoices.as_dict())
+
+        # ObjectChange
+        self.assertEqual(choices_to_dict(response.data.get('object-change:action')), ObjectChangeActionChoices.as_dict())
 
 
 
 
 class GraphTest(APITestCase):
 class GraphTest(APITestCase):

+ 1 - 1
netbox/ipam/choices.py

@@ -111,7 +111,7 @@ class VLANStatusChoices(ChoiceSet):
 
 
 
 
 #
 #
-# VLANs
+# Services
 #
 #
 
 
 class ServiceProtocolChoices(ChoiceSet):
 class ServiceProtocolChoices(ChoiceSet):

+ 30 - 2
netbox/ipam/tests/test_api.py

@@ -5,9 +5,37 @@ from netaddr import IPNetwork
 from rest_framework import status
 from rest_framework import status
 
 
 from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site
 from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site
-from ipam.choices import ServiceProtocolChoices
+from ipam.choices import *
 from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
 from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
-from utilities.testing import APITestCase
+from utilities.testing import APITestCase, choices_to_dict
+
+
+class ChoicesTest(APITestCase):
+
+    def test_choices(self):
+
+        url = reverse('ipam-api:field-choice-list')
+        response = self.client.get(url, **self.header)
+
+        self.assertEqual(response.status_code, 200)
+
+        # Aggregate
+        # self.assertEqual(choices_to_dict(response.data.get('aggregate:family')), )
+
+        # Prefix
+        # self.assertEqual(choices_to_dict(response.data.get('prefix:family')), )
+        self.assertEqual(choices_to_dict(response.data.get('prefix:status')), PrefixStatusChoices.as_dict())
+
+        # IPAddress
+        # self.assertEqual(choices_to_dict(response.data.get('ip-address:family')), )
+        self.assertEqual(choices_to_dict(response.data.get('ip-address:role')), IPAddressRoleChoices.as_dict())
+        self.assertEqual(choices_to_dict(response.data.get('ip-address:status')), IPAddressStatusChoices.as_dict())
+
+        # VLAN
+        self.assertEqual(choices_to_dict(response.data.get('vlan:status')), VLANStatusChoices.as_dict())
+
+        # Service
+        self.assertEqual(choices_to_dict(response.data.get('service:protocol')), ServiceProtocolChoices.as_dict())
 
 
 
 
 class VRFTest(APITestCase):
 class VRFTest(APITestCase):

+ 10 - 0
netbox/secrets/tests/test_api.py

@@ -9,6 +9,16 @@ from utilities.testing import APITestCase
 from .constants import PRIVATE_KEY, PUBLIC_KEY
 from .constants import PRIVATE_KEY, PUBLIC_KEY
 
 
 
 
+class ChoicesTest(APITestCase):
+
+    def test_choices(self):
+
+        url = reverse('secrets-api:field-choice-list')
+        response = self.client.get(url, **self.header)
+
+        self.assertEqual(response.status_code, 200)
+
+
 class SecretRoleTest(APITestCase):
 class SecretRoleTest(APITestCase):
 
 
     def setUp(self):
     def setUp(self):

+ 10 - 0
netbox/tenancy/tests/test_api.py

@@ -5,6 +5,16 @@ from tenancy.models import Tenant, TenantGroup
 from utilities.testing import APITestCase
 from utilities.testing import APITestCase
 
 
 
 
+class ChoicesTest(APITestCase):
+
+    def test_choices(self):
+
+        url = reverse('tenancy-api:field-choice-list')
+        response = self.client.get(url, **self.header)
+
+        self.assertEqual(response.status_code, 200)
+
+
 class TenantGroupTest(APITestCase):
 class TenantGroupTest(APITestCase):
 
 
     def setUp(self):
     def setUp(self):

+ 8 - 0
netbox/utilities/choices.py

@@ -1,3 +1,6 @@
+from utilities.forms import unpack_grouped_choices
+
+
 class ChoiceSetMeta(type):
 class ChoiceSetMeta(type):
     """
     """
     Metaclass for ChoiceSet
     Metaclass for ChoiceSet
@@ -20,6 +23,11 @@ class ChoiceSet(metaclass=ChoiceSetMeta):
     def values(cls):
     def values(cls):
         return [c[0] for c in cls.CHOICES]
         return [c[0] for c in cls.CHOICES]
 
 
+    @classmethod
+    def as_dict(cls):
+        # Unpack grouped choices before casting as a dict
+        return dict(unpack_grouped_choices(cls.CHOICES))
+
     @classmethod
     @classmethod
     def slug_to_id(cls, slug):
     def slug_to_id(cls, slug):
         """
         """

+ 27 - 0
netbox/utilities/testing.py

@@ -35,3 +35,30 @@ def create_test_user(username='testuser', permissions=list()):
         user.user_permissions.add(perm)
         user.user_permissions.add(perm)
 
 
     return user
     return user
+
+
+def choices_to_dict(choices_list):
+    """
+    Convert a list of field choices to a dictionary suitable for direct comparison with a ChoiceSet. For example:
+
+        [
+            {
+                "value": "choice-1",
+                "label": "First Choice"
+            },
+            {
+                "value": "choice-2",
+                "label": "Second Choice"
+            }
+        ]
+
+    Becomes:
+
+        {
+            "choice-1": "First Choice",
+            "choice-2": "Second Choice
+        }
+    """
+    return {
+        choice['value']: choice['label'] for choice in choices_list
+    }

+ 8 - 8
netbox/virtualization/migrations/0010_cluster_add_tenant_squashed_0012_vm_name_nonunique.py

@@ -30,14 +30,6 @@ class Migration(migrations.Migration):
             name='tenant',
             name='tenant',
             field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='clusters', to='tenancy.Tenant'),
             field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='clusters', to='tenancy.Tenant'),
         ),
         ),
-        migrations.AlterField(
-            model_name='virtualmachine',
-            name='status',
-            field=models.CharField(default='active', max_length=50),
-        ),
-        migrations.RunPython(
-            code=virtualmachine_status_to_slug,
-        ),
         migrations.AlterField(
         migrations.AlterField(
             model_name='virtualmachine',
             model_name='virtualmachine',
             name='name',
             name='name',
@@ -47,4 +39,12 @@ class Migration(migrations.Migration):
             name='virtualmachine',
             name='virtualmachine',
             unique_together={('cluster', 'tenant', 'name')},
             unique_together={('cluster', 'tenant', 'name')},
         ),
         ),
+        migrations.AlterField(
+            model_name='virtualmachine',
+            name='status',
+            field=models.CharField(default='active', max_length=50),
+        ),
+        migrations.RunPython(
+            code=virtualmachine_status_to_slug,
+        ),
     ]
     ]

+ 15 - 1
netbox/virtualization/tests/test_api.py

@@ -5,10 +5,24 @@ from rest_framework import status
 from dcim.choices import InterfaceModeChoices, InterfaceTypeChoices
 from dcim.choices import InterfaceModeChoices, InterfaceTypeChoices
 from dcim.models import Interface
 from dcim.models import Interface
 from ipam.models import IPAddress, VLAN
 from ipam.models import IPAddress, VLAN
-from utilities.testing import APITestCase
+from utilities.testing import APITestCase, choices_to_dict
+from virtualization.choices import *
 from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine
 from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine
 
 
 
 
+class ChoicesTest(APITestCase):
+
+    def test_choices(self):
+
+        url = reverse('virtualization-api:field-choice-list')
+        response = self.client.get(url, **self.header)
+
+        self.assertEqual(response.status_code, 200)
+
+        # VirtualMachine
+        self.assertEqual(choices_to_dict(response.data.get('virtual-machine:status')), VirtualMachineStatusChoices.as_dict())
+
+
 class ClusterTypeTest(APITestCase):
 class ClusterTypeTest(APITestCase):
 
 
     def setUp(self):
     def setUp(self):