Jeremy Stretch 5 лет назад
Родитель
Сommit
11a247edc2

+ 6 - 2
netbox/circuits/tests/test_views.py

@@ -17,6 +17,8 @@ class ProviderTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             Provider(name='Provider 3', slug='provider-3', asn=65003),
         ])
 
+        tags = cls.create_tags('Alpha', 'Bravo', 'Charlie')
+
         cls.form_data = {
             'name': 'Provider X',
             'slug': 'provider-x',
@@ -26,7 +28,7 @@ class ProviderTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             'noc_contact': 'noc@example.com',
             'admin_contact': 'admin@example.com',
             'comments': 'Another provider',
-            'tags': cls.create_tags('Alpha', 'Bravo', 'Charlie'),
+            'tags': [t.pk for t in tags],
         }
 
         cls.csv_data = (
@@ -96,6 +98,8 @@ class CircuitTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             Circuit(cid='Circuit 3', provider=providers[0], type=circuittypes[0]),
         ])
 
+        tags = cls.create_tags('Alpha', 'Bravo', 'Charlie')
+
         cls.form_data = {
             'cid': 'Circuit X',
             'provider': providers[1].pk,
@@ -106,7 +110,7 @@ class CircuitTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             'commit_rate': 1000,
             'description': 'A new circuit',
             'comments': 'Some comments',
-            'tags': cls.create_tags('Alpha', 'Bravo', 'Charlie'),
+            'tags': [t.pk for t in tags],
         }
 
         cls.csv_data = (

+ 42 - 26
netbox/dcim/tests/test_views.py

@@ -76,6 +76,8 @@ class SiteTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             Site(name='Site 3', slug='site-3', region=regions[0]),
         ])
 
+        tags = cls.create_tags('Alpha', 'Bravo', 'Charlie')
+
         cls.form_data = {
             'name': 'Site X',
             'slug': 'site-x',
@@ -94,7 +96,7 @@ class SiteTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             'contact_phone': '123-555-9999',
             'contact_email': 'hank@stricklandpropane.com',
             'comments': 'Test site',
-            'tags': cls.create_tags('Alpha', 'Bravo', 'Charlie'),
+            'tags': [t.pk for t in tags],
         }
 
         cls.csv_data = (
@@ -196,13 +198,15 @@ class RackReservationTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             RackReservation(rack=rack, user=user2, units=[7, 8, 9], description='Reservation 3'),
         ])
 
+        tags = cls.create_tags('Alpha', 'Bravo', 'Charlie')
+
         cls.form_data = {
             'rack': rack.pk,
             'units': "10,11,12",
             'user': user3.pk,
             'tenant': None,
             'description': 'Rack reservation',
-            'tags': cls.create_tags('Alpha', 'Bravo', 'Charlie'),
+            'tags': [t.pk for t in tags],
         }
 
         cls.csv_data = (
@@ -250,6 +254,8 @@ class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             Rack(name='Rack 3', site=sites[0]),
         ))
 
+        tags = cls.create_tags('Alpha', 'Bravo', 'Charlie')
+
         cls.form_data = {
             'name': 'Rack X',
             'facility_id': 'Facility X',
@@ -268,7 +274,7 @@ class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             'outer_depth': 500,
             'outer_unit': RackDimensionUnitChoices.UNIT_MILLIMETER,
             'comments': 'Some comments',
-            'tags': cls.create_tags('Alpha', 'Bravo', 'Charlie'),
+            'tags': [t.pk for t in tags],
         }
 
         cls.csv_data = (
@@ -350,6 +356,8 @@ class DeviceTypeTestCase(
             DeviceType(model='Device Type 3', slug='device-type-3', manufacturer=manufacturers[0]),
         ])
 
+        tags = cls.create_tags('Alpha', 'Bravo', 'Charlie')
+
         cls.form_data = {
             'manufacturer': manufacturers[1].pk,
             'model': 'Device Type X',
@@ -359,7 +367,7 @@ class DeviceTypeTestCase(
             'is_full_depth': True,
             'subdevice_role': '',  # CharField
             'comments': 'Some comments',
-            'tags': cls.create_tags('Alpha', 'Bravo', 'Charlie'),
+            'tags': [t.pk for t in tags],
         }
 
         cls.bulk_edit_data = {
@@ -947,6 +955,8 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             Device(name='Device 3', site=sites[0], rack=racks[0], device_type=devicetypes[0], device_role=deviceroles[0], platform=platforms[0]),
         ])
 
+        tags = cls.create_tags('Alpha', 'Bravo', 'Charlie')
+
         cls.form_data = {
             'device_type': devicetypes[1].pk,
             'device_role': deviceroles[1].pk,
@@ -967,7 +977,7 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             'vc_position': None,
             'vc_priority': None,
             'comments': 'A new device',
-            'tags': cls.create_tags('Alpha', 'Bravo', 'Charlie'),
+            'tags': [t.pk for t in tags],
             'local_context_data': None,
         }
 
@@ -1008,7 +1018,7 @@ class ConsolePortTestCase(ViewTestCases.DeviceComponentViewTestCase):
             'name': 'Console Port X',
             'type': ConsolePortTypeChoices.TYPE_RJ45,
             'description': 'A console port',
-            'tags': tags,
+            'tags': sorted([t.pk for t in tags]),
         }
 
         cls.bulk_create_data = {
@@ -1018,7 +1028,7 @@ class ConsolePortTestCase(ViewTestCases.DeviceComponentViewTestCase):
             'label_pattern': 'Serial[3-5]',
             'type': ConsolePortTypeChoices.TYPE_RJ45,
             'description': 'A console port',
-            'tags': tags,
+            'tags': sorted([t.pk for t in tags]),
         }
 
         cls.bulk_edit_data = {
@@ -1054,7 +1064,7 @@ class ConsoleServerPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
             'name': 'Console Server Port X',
             'type': ConsolePortTypeChoices.TYPE_RJ45,
             'description': 'A console server port',
-            'tags': tags,
+            'tags': [t.pk for t in tags],
         }
 
         cls.bulk_create_data = {
@@ -1062,7 +1072,7 @@ class ConsoleServerPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
             'name_pattern': 'Console Server Port [4-6]',
             'type': ConsolePortTypeChoices.TYPE_RJ45,
             'description': 'A console server port',
-            'tags': tags,
+            'tags': [t.pk for t in tags],
         }
 
         cls.bulk_edit_data = {
@@ -1100,7 +1110,7 @@ class PowerPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
             'maximum_draw': 100,
             'allocated_draw': 50,
             'description': 'A power port',
-            'tags': tags,
+            'tags': [t.pk for t in tags],
         }
 
         cls.bulk_create_data = {
@@ -1110,7 +1120,7 @@ class PowerPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
             'maximum_draw': 100,
             'allocated_draw': 50,
             'description': 'A power port',
-            'tags': tags,
+            'tags': [t.pk for t in tags],
         }
 
         cls.bulk_edit_data = {
@@ -1156,7 +1166,7 @@ class PowerOutletTestCase(ViewTestCases.DeviceComponentViewTestCase):
             'power_port': powerports[1].pk,
             'feed_leg': PowerOutletFeedLegChoices.FEED_LEG_B,
             'description': 'A power outlet',
-            'tags': tags,
+            'tags': [t.pk for t in tags],
         }
 
         cls.bulk_create_data = {
@@ -1166,7 +1176,7 @@ class PowerOutletTestCase(ViewTestCases.DeviceComponentViewTestCase):
             'power_port': powerports[1].pk,
             'feed_leg': PowerOutletFeedLegChoices.FEED_LEG_B,
             'description': 'A power outlet',
-            'tags': tags,
+            'tags': [t.pk for t in tags],
         }
 
         cls.bulk_edit_data = {
@@ -1226,7 +1236,7 @@ class InterfaceTestCase(
             'mode': InterfaceModeChoices.MODE_TAGGED,
             'untagged_vlan': vlans[0].pk,
             'tagged_vlans': [v.pk for v in vlans[1:4]],
-            'tags': tags,
+            'tags': [t.pk for t in tags],
         }
 
         cls.bulk_create_data = {
@@ -1242,7 +1252,7 @@ class InterfaceTestCase(
             'mode': InterfaceModeChoices.MODE_TAGGED,
             'untagged_vlan': vlans[0].pk,
             'tagged_vlans': [v.pk for v in vlans[1:4]],
-            'tags': tags,
+            'tags': [t.pk for t in tags],
         }
 
         cls.bulk_edit_data = {
@@ -1298,7 +1308,7 @@ class FrontPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
             'rear_port': rearports[3].pk,
             'rear_port_position': 1,
             'description': 'New description',
-            'tags': tags,
+            'tags': [t.pk for t in tags],
         }
 
         cls.bulk_create_data = {
@@ -1309,7 +1319,7 @@ class FrontPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
                 '{}:1'.format(rp.pk) for rp in rearports[3:6]
             ],
             'description': 'New description',
-            'tags': tags,
+            'tags': [t.pk for t in tags],
         }
 
         cls.bulk_edit_data = {
@@ -1346,7 +1356,7 @@ class RearPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
             'type': PortTypeChoices.TYPE_8P8C,
             'positions': 3,
             'description': 'A rear port',
-            'tags': tags,
+            'tags': [t.pk for t in tags],
         }
 
         cls.bulk_create_data = {
@@ -1355,7 +1365,7 @@ class RearPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
             'type': PortTypeChoices.TYPE_8P8C,
             'positions': 3,
             'description': 'A rear port',
-            'tags': tags,
+            'tags': [t.pk for t in tags],
         }
 
         cls.bulk_edit_data = {
@@ -1393,14 +1403,14 @@ class DeviceBayTestCase(ViewTestCases.DeviceComponentViewTestCase):
             'device': device.pk,
             'name': 'Device Bay X',
             'description': 'A device bay',
-            'tags': tags,
+            'tags': [t.pk for t in tags],
         }
 
         cls.bulk_create_data = {
             'device': device.pk,
             'name_pattern': 'Device Bay [4-6]',
             'description': 'A device bay',
-            'tags': tags,
+            'tags': [t.pk for t in tags],
         }
 
         cls.bulk_edit_data = {
@@ -1441,7 +1451,7 @@ class InventoryItemTestCase(ViewTestCases.DeviceComponentViewTestCase):
             'serial': '123ABC',
             'asset_tag': 'ABC123',
             'description': 'An inventory item',
-            'tags': tags,
+            'tags': [t.pk for t in tags],
         }
 
         cls.bulk_create_data = {
@@ -1453,7 +1463,7 @@ class InventoryItemTestCase(ViewTestCases.DeviceComponentViewTestCase):
             'part_id': '123456',
             'serial': '123ABC',
             'description': 'An inventory item',
-            'tags': tags,
+            'tags': [t.pk for t in tags],
         }
 
         cls.bulk_edit_data = {
@@ -1518,6 +1528,8 @@ class CableTestCase(
         Cable(termination_a=interfaces[1], termination_b=interfaces[4], type=CableTypeChoices.TYPE_CAT6).save()
         Cable(termination_a=interfaces[2], termination_b=interfaces[5], type=CableTypeChoices.TYPE_CAT6).save()
 
+        tags = cls.create_tags('Alpha', 'Bravo', 'Charlie')
+
         interface_ct = ContentType.objects.get_for_model(Interface)
         cls.form_data = {
             # Changing terminations not supported when editing an existing Cable
@@ -1531,7 +1543,7 @@ class CableTestCase(
             'color': 'c0c0c0',
             'length': 100,
             'length_unit': CableLengthUnitChoices.UNIT_FOOT,
-            'tags': cls.create_tags('Alpha', 'Bravo', 'Charlie'),
+            'tags': [t.pk for t in tags],
         }
 
         cls.csv_data = (
@@ -1640,11 +1652,13 @@ class PowerPanelTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             PowerPanel(site=sites[0], rack_group=rackgroups[0], name='Power Panel 3'),
         ))
 
+        tags = cls.create_tags('Alpha', 'Bravo', 'Charlie')
+
         cls.form_data = {
             'site': sites[1].pk,
             'rack_group': rackgroups[1].pk,
             'name': 'Power Panel X',
-            'tags': cls.create_tags('Alpha', 'Bravo', 'Charlie'),
+            'tags': [t.pk for t in tags],
         }
 
         cls.csv_data = (
@@ -1686,6 +1700,8 @@ class PowerFeedTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             PowerFeed(name='Power Feed 3', power_panel=powerpanels[0], rack=racks[0]),
         ))
 
+        tags = cls.create_tags('Alpha', 'Bravo', 'Charlie')
+
         cls.form_data = {
             'name': 'Power Feed X',
             'power_panel': powerpanels[1].pk,
@@ -1698,7 +1714,7 @@ class PowerFeedTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             'amperage': 100,
             'max_utilization': 50,
             'comments': 'New comments',
-            'tags': cls.create_tags('Alpha', 'Bravo', 'Charlie'),
+            'tags': [t.pk for t in tags],
 
             # Connection
             'cable': None,

+ 18 - 6
netbox/ipam/tests/test_views.py

@@ -27,13 +27,15 @@ class VRFTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             VRF(name='VRF 3', rd='65000:3'),
         ])
 
+        tags = cls.create_tags('Alpha', 'Bravo', 'Charlie')
+
         cls.form_data = {
             'name': 'VRF X',
             'rd': '65000:999',
             'tenant': tenants[0].pk,
             'enforce_unique': True,
             'description': 'A new VRF',
-            'tags': cls.create_tags('Alpha', 'Bravo', 'Charlie'),
+            'tags': [t.pk for t in tags],
         }
 
         cls.csv_data = (
@@ -95,12 +97,14 @@ class AggregateTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             Aggregate(prefix=IPNetwork('10.3.0.0/16'), rir=rirs[0]),
         ])
 
+        tags = cls.create_tags('Alpha', 'Bravo', 'Charlie')
+
         cls.form_data = {
             'prefix': IPNetwork('10.99.0.0/16'),
             'rir': rirs[1].pk,
             'date_added': datetime.date(2020, 1, 1),
             'description': 'A new aggregate',
-            'tags': cls.create_tags('Alpha', 'Bravo', 'Charlie'),
+            'tags': [t.pk for t in tags],
         }
 
         cls.csv_data = (
@@ -173,6 +177,8 @@ class PrefixTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             Prefix(prefix=IPNetwork('10.3.0.0/16'), vrf=vrfs[0], site=sites[0], role=roles[0]),
         ])
 
+        tags = cls.create_tags('Alpha', 'Bravo', 'Charlie')
+
         cls.form_data = {
             'prefix': IPNetwork('192.0.2.0/24'),
             'site': sites[1].pk,
@@ -183,7 +189,7 @@ class PrefixTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             'role': roles[1].pk,
             'is_pool': True,
             'description': 'A new prefix',
-            'tags': cls.create_tags('Alpha', 'Bravo', 'Charlie'),
+            'tags': [t.pk for t in tags],
         }
 
         cls.csv_data = (
@@ -222,6 +228,8 @@ class IPAddressTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             IPAddress(address=IPNetwork('192.0.2.3/24'), vrf=vrfs[0]),
         ])
 
+        tags = cls.create_tags('Alpha', 'Bravo', 'Charlie')
+
         cls.form_data = {
             'vrf': vrfs[1].pk,
             'address': IPNetwork('192.0.2.99/24'),
@@ -232,7 +240,7 @@ class IPAddressTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             'nat_inside': None,
             'dns_name': 'example',
             'description': 'A new IP address',
-            'tags': cls.create_tags('Alpha', 'Bravo', 'Charlie'),
+            'tags': [t.pk for t in tags],
         }
 
         cls.csv_data = (
@@ -311,6 +319,8 @@ class VLANTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             VLAN(group=vlangroups[0], vid=103, name='VLAN103', site=sites[0], role=roles[0]),
         ])
 
+        tags = cls.create_tags('Alpha', 'Bravo', 'Charlie')
+
         cls.form_data = {
             'site': sites[1].pk,
             'group': vlangroups[1].pk,
@@ -320,7 +330,7 @@ class VLANTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             'status': VLANStatusChoices.STATUS_RESERVED,
             'role': roles[1].pk,
             'description': 'A new VLAN',
-            'tags': cls.create_tags('Alpha', 'Bravo', 'Charlie'),
+            'tags': [t.pk for t in tags],
         }
 
         cls.csv_data = (
@@ -368,6 +378,8 @@ class ServiceTestCase(
             Service(device=device, name='Service 3', protocol=ServiceProtocolChoices.PROTOCOL_TCP, port=103),
         ])
 
+        tags = cls.create_tags('Alpha', 'Bravo', 'Charlie')
+
         cls.form_data = {
             'device': device.pk,
             'virtual_machine': None,
@@ -376,7 +388,7 @@ class ServiceTestCase(
             'port': 999,
             'ipaddresses': [],
             'description': 'A new service',
-            'tags': cls.create_tags('Alpha', 'Bravo', 'Charlie'),
+            'tags': [t.pk for t in tags],
         }
 
         cls.csv_data = (

+ 3 - 1
netbox/tenancy/tests/test_views.py

@@ -49,13 +49,15 @@ class TenantTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             Tenant(name='Tenant 3', slug='tenant-3', group=tenant_groups[0]),
         ])
 
+        tags = cls.create_tags('Alpha', 'Bravo', 'Charlie')
+
         cls.form_data = {
             'name': 'Tenant X',
             'slug': 'tenant-x',
             'group': tenant_groups[1].pk,
             'description': 'A new tenant',
             'comments': 'Some comments',
-            'tags': cls.create_tags('Alpha', 'Bravo', 'Charlie'),
+            'tags': [t.pk for t in tags],
         }
 
         cls.csv_data = (

+ 15 - 9
netbox/utilities/testing/views.py

@@ -1,13 +1,14 @@
 from django.contrib.auth.models import User
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.postgres.fields import ArrayField
-from django.core.exceptions import ObjectDoesNotExist
-from django.db.models import ForeignKey, ManyToManyField
+from django.core.exceptions import FieldDoesNotExist, ObjectDoesNotExist
+from django.db.models import ManyToManyField
 from django.forms.models import model_to_dict
 from django.test import Client, TestCase as _TestCase, override_settings
 from django.urls import reverse, NoReverseMatch
 from django.utils.text import slugify
 from netaddr import IPNetwork
+from taggit.managers import TaggableManager
 
 from extras.models import Tag
 from users.models import ObjectPermission
@@ -55,14 +56,19 @@ class TestCase(_TestCase):
                 model_dict[attr] = getattr(instance, attr)
 
         for key, value in list(model_dict.items()):
+            try:
+                field = instance._meta.get_field(key)
+            except FieldDoesNotExist:
+                # Attribute is not a model field
+                continue
 
-            # TODO: Differentiate between tags assigned to the instance and a M2M field for tags (ex: ConfigContext)
-            if key == 'tags':
-                model_dict[key] = sorted(value, key=lambda t: t.name)
+            # Handle ManyToManyFields
+            if value and type(field) in (ManyToManyField, TaggableManager):
 
-            # Convert ManyToManyField to list of instance PKs
-            elif model_dict[key] and type(value) in (list, tuple) and hasattr(value[0], 'pk'):
-                model_dict[key] = [obj.pk for obj in value]
+                if field.related_model is ContentType:
+                    model_dict[key] = sorted([f'{ct.app_label}.{ct.model}' for ct in value])
+                else:
+                    model_dict[key] = sorted([obj.pk for obj in value])
 
             if api:
 
@@ -72,7 +78,7 @@ class TestCase(_TestCase):
                     model_dict[key] = f'{ct.app_label}.{ct.model}'
 
                 # Convert IPNetwork instances to strings
-                if type(value) is IPNetwork:
+                elif type(value) is IPNetwork:
                     model_dict[key] = str(value)
 
             else:

+ 8 - 4
netbox/virtualization/tests/test_views.py

@@ -90,6 +90,8 @@ class ClusterTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             Cluster(name='Cluster 3', group=clustergroups[0], type=clustertypes[0], site=sites[0]),
         ])
 
+        tags = cls.create_tags('Alpha', 'Bravo', 'Charlie')
+
         cls.form_data = {
             'name': 'Cluster X',
             'group': clustergroups[1].pk,
@@ -97,7 +99,7 @@ class ClusterTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             'tenant': None,
             'site': sites[1].pk,
             'comments': 'Some comments',
-            'tags': cls.create_tags('Alpha', 'Bravo', 'Charlie'),
+            'tags': [t.pk for t in tags],
         }
 
         cls.csv_data = (
@@ -148,6 +150,8 @@ class VirtualMachineTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             VirtualMachine(name='Virtual Machine 3', cluster=clusters[0], role=deviceroles[0], platform=platforms[0]),
         ])
 
+        tags = cls.create_tags('Alpha', 'Bravo', 'Charlie')
+
         cls.form_data = {
             'cluster': clusters[1].pk,
             'tenant': None,
@@ -161,7 +165,7 @@ class VirtualMachineTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             'memory': 32768,
             'disk': 4000,
             'comments': 'Some comments',
-            'tags': cls.create_tags('Alpha', 'Bravo', 'Charlie'),
+            'tags': [t.pk for t in tags],
             'local_context_data': None,
         }
 
@@ -242,7 +246,7 @@ class InterfaceTestCase(
             'mode': InterfaceModeChoices.MODE_TAGGED,
             'untagged_vlan': vlans[0].pk,
             'tagged_vlans': [v.pk for v in vlans[1:4]],
-            'tags': tags,
+            'tags': [t.pk for t in tags],
         }
 
         cls.bulk_create_data = {
@@ -257,7 +261,7 @@ class InterfaceTestCase(
             'mode': InterfaceModeChoices.MODE_TAGGED,
             'untagged_vlan': vlans[0].pk,
             'tagged_vlans': [v.pk for v in vlans[1:4]],
-            'tags': tags,
+            'tags': [t.pk for t in tags],
         }
 
         cls.bulk_edit_data = {