Просмотр исходного кода

Migrate (most) DCIM view tests to use StandardTestCases

Jeremy Stretch 6 лет назад
Родитель
Сommit
86ef739c12
1 измененных файлов с 268 добавлено и 323 удалено
  1. 268 323
      netbox/dcim/tests/test_views.py

+ 268 - 323
netbox/dcim/tests/test_views.py

@@ -1,54 +1,53 @@
 import urllib.parse
 import urllib.parse
+from decimal import Decimal
 
 
+import pytz
 import yaml
 import yaml
 from django.contrib.auth.models import User
 from django.contrib.auth.models import User
+from django.contrib.contenttypes.models import ContentType
 from django.urls import reverse
 from django.urls import reverse
 
 
 from dcim.choices import *
 from dcim.choices import *
 from dcim.constants import *
 from dcim.constants import *
 from dcim.models import *
 from dcim.models import *
-from utilities.testing import TestCase
+from utilities.testing import StandardTestCases, TestCase
 
 
 
 
-class RegionTestCase(TestCase):
-    user_permissions = (
-        'dcim.view_region',
-    )
+class RegionTestCase(StandardTestCases.Views):
+    model = Region
+
+    # Disable inapplicable tests
+    test_get_object = None
+    test_delete_object = None
 
 
     @classmethod
     @classmethod
     def setUpTestData(cls):
     def setUpTestData(cls):
 
 
         # Create three Regions
         # Create three Regions
-        for i in range(1, 4):
-            Region(name='Region {}'.format(i), slug='region-{}'.format(i)).save()
-
-    def test_region_list(self):
-
-        url = reverse('dcim:region_list')
-
-        response = self.client.get(url)
-        self.assertHttpStatus(response, 200)
+        regions = (
+            Region(name='Region 1', slug='region-1'),
+            Region(name='Region 2', slug='region-2'),
+            Region(name='Region 3', slug='region-3'),
+        )
+        for region in regions:
+            region.save()
 
 
-    def test_region_import(self):
-        self.add_permissions('dcim.add_region')
+        cls.form_data = {
+            'name': 'Region X',
+            'slug': 'region-x',
+            'parent': regions[2].pk,
+        }
 
 
-        csv_data = (
+        cls.csv_data = (
             "name,slug",
             "name,slug",
             "Region 4,region-4",
             "Region 4,region-4",
             "Region 5,region-5",
             "Region 5,region-5",
             "Region 6,region-6",
             "Region 6,region-6",
         )
         )
 
 
-        response = self.client.post(reverse('dcim:region_import'), {'csv': '\n'.join(csv_data)})
-
-        self.assertHttpStatus(response, 200)
-        self.assertEqual(Region.objects.count(), 6)
-
 
 
-class SiteTestCase(TestCase):
-    user_permissions = (
-        'dcim.view_site',
-    )
+class SiteTestCase(StandardTestCases.Views):
+    model = Site
 
 
     @classmethod
     @classmethod
     def setUpTestData(cls):
     def setUpTestData(cls):
@@ -62,42 +61,41 @@ class SiteTestCase(TestCase):
             Site(name='Site 3', slug='site-3', region=region),
             Site(name='Site 3', slug='site-3', region=region),
         ])
         ])
 
 
-    def test_site_list(self):
-
-        url = reverse('dcim:site_list')
-        params = {
-            "region": Region.objects.first().slug,
+        cls.form_data = {
+            'name': 'Site X',
+            'slug': 'site-x',
+            'status': SiteStatusChoices.STATUS_PLANNED,
+            'region': region.pk,
+            'tenant': None,
+            'facility': 'Facility X',
+            'asn': 65001,
+            'time_zone': pytz.UTC,
+            'description': 'Site description',
+            'physical_address': '742 Evergreen Terrace, Springfield, USA',
+            'shipping_address': '742 Evergreen Terrace, Springfield, USA',
+            'latitude': Decimal('35.780000'),
+            'longitude': Decimal('-78.642000'),
+            'contact_name': 'Hank Hill',
+            'contact_phone': '123-555-9999',
+            'contact_email': 'hank@stricklandpropane.com',
+            'comments': 'Test site',
+            'tags': 'Alpha,Bravo,Charlie',
         }
         }
 
 
-        response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params)))
-        self.assertHttpStatus(response, 200)
-
-    def test_site(self):
-
-        site = Site.objects.first()
-        response = self.client.get(site.get_absolute_url())
-        self.assertHttpStatus(response, 200)
-
-    def test_site_import(self):
-        self.add_permissions('dcim.add_site')
-
-        csv_data = (
+        cls.csv_data = (
             "name,slug",
             "name,slug",
             "Site 4,site-4",
             "Site 4,site-4",
             "Site 5,site-5",
             "Site 5,site-5",
             "Site 6,site-6",
             "Site 6,site-6",
         )
         )
 
 
-        response = self.client.post(reverse('dcim:site_import'), {'csv': '\n'.join(csv_data)})
-
-        self.assertHttpStatus(response, 200)
-        self.assertEqual(Site.objects.count(), 6)
 
 
+class RackGroupTestCase(StandardTestCases.Views):
+    model = RackGroup
 
 
-class RackGroupTestCase(TestCase):
-    user_permissions = (
-        'dcim.view_rackgroup',
-    )
+    # Disable inapplicable tests
+    test_get_object = None
+    test_delete_object = None
 
 
     @classmethod
     @classmethod
     def setUpTestData(cls):
     def setUpTestData(cls):
@@ -111,33 +109,26 @@ class RackGroupTestCase(TestCase):
             RackGroup(name='Rack Group 3', slug='rack-group-3', site=site),
             RackGroup(name='Rack Group 3', slug='rack-group-3', site=site),
         ])
         ])
 
 
-    def test_rackgroup_list(self):
-
-        url = reverse('dcim:rackgroup_list')
-
-        response = self.client.get(url)
-        self.assertHttpStatus(response, 200)
-
-    def test_rackgroup_import(self):
-        self.add_permissions('dcim.add_rackgroup')
+        cls.form_data = {
+            'name': 'Rack Group X',
+            'slug': 'rack-group-x',
+            'site': site.pk,
+        }
 
 
-        csv_data = (
+        cls.csv_data = (
             "site,name,slug",
             "site,name,slug",
             "Site 1,Rack Group 4,rack-group-4",
             "Site 1,Rack Group 4,rack-group-4",
             "Site 1,Rack Group 5,rack-group-5",
             "Site 1,Rack Group 5,rack-group-5",
             "Site 1,Rack Group 6,rack-group-6",
             "Site 1,Rack Group 6,rack-group-6",
         )
         )
 
 
-        response = self.client.post(reverse('dcim:rackgroup_import'), {'csv': '\n'.join(csv_data)})
 
 
-        self.assertHttpStatus(response, 200)
-        self.assertEqual(RackGroup.objects.count(), 6)
+class RackRoleTestCase(StandardTestCases.Views):
+    model = RackRole
 
 
-
-class RackRoleTestCase(TestCase):
-    user_permissions = (
-        'dcim.view_rackrole',
-    )
+    # Disable inapplicable tests
+    test_get_object = None
+    test_delete_object = None
 
 
     @classmethod
     @classmethod
     def setUpTestData(cls):
     def setUpTestData(cls):
@@ -148,33 +139,28 @@ class RackRoleTestCase(TestCase):
             RackRole(name='Rack Role 3', slug='rack-role-3'),
             RackRole(name='Rack Role 3', slug='rack-role-3'),
         ])
         ])
 
 
-    def test_rackrole_list(self):
-
-        url = reverse('dcim:rackrole_list')
-
-        response = self.client.get(url)
-        self.assertHttpStatus(response, 200)
-
-    def test_rackrole_import(self):
-        self.add_permissions('dcim.add_rackrole')
+        cls.form_data = {
+            'name': 'Rack Role X',
+            'slug': 'rack-role-x',
+            'color': 'c0c0c0',
+            'description': 'New role',
+        }
 
 
-        csv_data = (
+        cls.csv_data = (
             "name,slug,color",
             "name,slug,color",
             "Rack Role 4,rack-role-4,ff0000",
             "Rack Role 4,rack-role-4,ff0000",
             "Rack Role 5,rack-role-5,00ff00",
             "Rack Role 5,rack-role-5,00ff00",
             "Rack Role 6,rack-role-6,0000ff",
             "Rack Role 6,rack-role-6,0000ff",
         )
         )
 
 
-        response = self.client.post(reverse('dcim:rackrole_import'), {'csv': '\n'.join(csv_data)})
-
-        self.assertHttpStatus(response, 200)
-        self.assertEqual(RackRole.objects.count(), 6)
 
 
+class RackReservationTestCase(StandardTestCases.Views):
+    model = RackReservation
 
 
-class RackReservationTestCase(TestCase):
-    user_permissions = (
-        'dcim.view_rackreservation',
-    )
+    # Disable inapplicable tests
+    test_get_object = None
+    test_create_object = None  # TODO: Fix URL name for view
+    test_import_objects = None
 
 
     @classmethod
     @classmethod
     def setUpTestData(cls):
     def setUpTestData(cls):
@@ -193,24 +179,27 @@ class RackReservationTestCase(TestCase):
             RackReservation(rack=rack, user=user, units=[7, 8, 9], description='Reservation 3'),
             RackReservation(rack=rack, user=user, units=[7, 8, 9], description='Reservation 3'),
         ])
         ])
 
 
-    def test_rackreservation_list(self):
+        cls.form_data = {
+            'rack': rack.pk,
+            'units': [10, 11, 12],
+            'user': user.pk,
+            'tenant': None,
+            'description': 'New reservation',
+        }
 
 
-        url = reverse('dcim:rackreservation_list')
 
 
-        response = self.client.get(url)
-        self.assertHttpStatus(response, 200)
+class RackTestCase(StandardTestCases.Views):
+    model = Rack
 
 
-
-class RackTestCase(TestCase):
-    user_permissions = (
-        'dcim.view_rack',
-    )
+    # TODO: Remove this when #4067 is fixed
+    test_create_object = None
 
 
     @classmethod
     @classmethod
     def setUpTestData(cls):
     def setUpTestData(cls):
 
 
-        site = Site(name='Site 1', slug='site-1')
-        site.save()
+        site = Site.objects.create(name='Site 1', slug='site-1')
+        rackgroup = RackGroup.objects.create(name='Rack Group 1', slug='rack-group-1', site=site)
+        rackrole = RackRole.objects.create(name='Rack Role 1', slug='rack-role-1')
 
 
         Rack.objects.bulk_create([
         Rack.objects.bulk_create([
             Rack(name='Rack 1', site=site),
             Rack(name='Rack 1', site=site),
@@ -218,42 +207,41 @@ class RackTestCase(TestCase):
             Rack(name='Rack 3', site=site),
             Rack(name='Rack 3', site=site),
         ])
         ])
 
 
-    def test_rack_list(self):
-
-        url = reverse('dcim:rack_list')
-        params = {
-            "site": Site.objects.first().slug,
+        cls.form_data = {
+            'name': 'Rack X',
+            'facility_id': 'Facility X',
+            'site': site.pk,
+            'group': rackgroup.pk,
+            'tenant': None,
+            'status': RackStatusChoices.STATUS_PLANNED,
+            'role': rackrole.pk,
+            'serial': '123456',
+            'asset_tag': 'ABCDEF',
+            'type': RackTypeChoices.TYPE_CABINET,
+            'width': RackWidthChoices.WIDTH_19IN,
+            'u_height': 48,
+            'desc_units': False,
+            'outer_width': 500,
+            'outer_depth': 500,
+            'outer_unit': RackDimensionUnitChoices.UNIT_MILLIMETER,
+            'comments': 'Some comments',
+            'tags': 'Alpha,Bravo,Charlie',
         }
         }
 
 
-        response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params)))
-        self.assertHttpStatus(response, 200)
-
-    def test_rack(self):
-
-        rack = Rack.objects.first()
-        response = self.client.get(rack.get_absolute_url())
-        self.assertHttpStatus(response, 200)
-
-    def test_rack_import(self):
-        self.add_permissions('dcim.add_rack')
-
-        csv_data = (
+        cls.csv_data = (
             "site,name,width,u_height",
             "site,name,width,u_height",
             "Site 1,Rack 4,19,42",
             "Site 1,Rack 4,19,42",
             "Site 1,Rack 5,19,42",
             "Site 1,Rack 5,19,42",
             "Site 1,Rack 6,19,42",
             "Site 1,Rack 6,19,42",
         )
         )
 
 
-        response = self.client.post(reverse('dcim:rack_import'), {'csv': '\n'.join(csv_data)})
-
-        self.assertHttpStatus(response, 200)
-        self.assertEqual(Rack.objects.count(), 6)
 
 
+class ManufacturerTestCase(StandardTestCases.Views):
+    model = Manufacturer
 
 
-class ManufacturerTypeTestCase(TestCase):
-    user_permissions = (
-        'dcim.view_manufacturer',
-    )
+    # Disable inapplicable tests
+    test_get_object = None
+    test_delete_object = None
 
 
     @classmethod
     @classmethod
     def setUpTestData(cls):
     def setUpTestData(cls):
@@ -264,33 +252,21 @@ class ManufacturerTypeTestCase(TestCase):
             Manufacturer(name='Manufacturer 3', slug='manufacturer-3'),
             Manufacturer(name='Manufacturer 3', slug='manufacturer-3'),
         ])
         ])
 
 
-    def test_manufacturer_list(self):
-
-        url = reverse('dcim:manufacturer_list')
-
-        response = self.client.get(url)
-        self.assertHttpStatus(response, 200)
-
-    def test_manufacturer_import(self):
-        self.add_permissions('dcim.add_manufacturer')
+        cls.form_data = {
+            'name': 'Manufacturer X',
+            'slug': 'manufacturer-x',
+        }
 
 
-        csv_data = (
+        cls.csv_data = (
             "name,slug",
             "name,slug",
             "Manufacturer 4,manufacturer-4",
             "Manufacturer 4,manufacturer-4",
             "Manufacturer 5,manufacturer-5",
             "Manufacturer 5,manufacturer-5",
             "Manufacturer 6,manufacturer-6",
             "Manufacturer 6,manufacturer-6",
         )
         )
 
 
-        response = self.client.post(reverse('dcim:manufacturer_import'), {'csv': '\n'.join(csv_data)})
-
-        self.assertHttpStatus(response, 200)
-        self.assertEqual(Manufacturer.objects.count(), 6)
 
 
-
-class DeviceTypeTestCase(TestCase):
-    user_permissions = (
-        'dcim.view_devicetype',
-    )
+class DeviceTypeTestCase(StandardTestCases.Views):
+    model = DeviceType
 
 
     @classmethod
     @classmethod
     def setUpTestData(cls):
     def setUpTestData(cls):
@@ -304,35 +280,22 @@ class DeviceTypeTestCase(TestCase):
             DeviceType(model='Device Type 3', slug='device-type-3', manufacturer=manufacturer),
             DeviceType(model='Device Type 3', slug='device-type-3', manufacturer=manufacturer),
         ])
         ])
 
 
-    def test_devicetype_list(self):
-
-        url = reverse('dcim:devicetype_list')
-        params = {
-            "manufacturer": Manufacturer.objects.first().slug,
+        cls.form_data = {
+            'manufacturer': manufacturer.pk,
+            'model': 'Device Type X',
+            'slug': 'device-type-x',
+            'part_number': '123ABC',
+            'u_height': 2,
+            'is_full_depth': True,
+            'subdevice_role': '',  # CharField
+            'comments': 'Some comments',
+            'tags': 'Alpha,Bravo,Charlie',
         }
         }
 
 
-        response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params)))
-        self.assertHttpStatus(response, 200)
-
-    def test_devicetype_export(self):
-
-        url = reverse('dcim:devicetype_list')
-
-        response = self.client.get('{}?export'.format(url))
-        self.assertHttpStatus(response, 200)
-        data = list(yaml.load_all(response.content, Loader=yaml.SafeLoader))
-        self.assertEqual(len(data), 3)
-        self.assertEqual(data[0]['manufacturer'], 'Manufacturer 1')
-        self.assertEqual(data[0]['model'], 'Device Type 1')
-
-    def test_devicetype(self):
-
-        devicetype = DeviceType.objects.first()
-        response = self.client.get(devicetype.get_absolute_url())
-        self.assertHttpStatus(response, 200)
-
-    def test_devicetype_import(self):
-
+    def test_import_objects(self):
+        """
+        Custom import test for YAML-based imports (versus CSV)
+        """
         IMPORT_DATA = """
         IMPORT_DATA = """
 manufacturer: Generic
 manufacturer: Generic
 model: TEST-1000
 model: TEST-1000
@@ -471,11 +434,24 @@ device-bays:
         db1 = DeviceBayTemplate.objects.first()
         db1 = DeviceBayTemplate.objects.first()
         self.assertEqual(db1.name, 'Device Bay 1')
         self.assertEqual(db1.name, 'Device Bay 1')
 
 
+    def test_devicetype_export(self):
+
+        url = reverse('dcim:devicetype_list')
+
+        response = self.client.get('{}?export'.format(url))
+        self.assertEqual(response.status_code, 200)
+        data = list(yaml.load_all(response.content, Loader=yaml.SafeLoader))
+        self.assertEqual(len(data), 3)
+        self.assertEqual(data[0]['manufacturer'], 'Manufacturer 1')
+        self.assertEqual(data[0]['model'], 'Device Type 1')
 
 
-class DeviceRoleTestCase(TestCase):
-    user_permissions = (
-        'dcim.view_devicerole',
-    )
+
+class DeviceRoleTestCase(StandardTestCases.Views):
+    model = DeviceRole
+
+    # Disable inapplicable tests
+    test_get_object = None
+    test_delete_object = None
 
 
     @classmethod
     @classmethod
     def setUpTestData(cls):
     def setUpTestData(cls):
@@ -486,85 +462,68 @@ class DeviceRoleTestCase(TestCase):
             DeviceRole(name='Device Role 3', slug='device-role-3'),
             DeviceRole(name='Device Role 3', slug='device-role-3'),
         ])
         ])
 
 
-    def test_devicerole_list(self):
-
-        url = reverse('dcim:devicerole_list')
-
-        response = self.client.get(url)
-        self.assertHttpStatus(response, 200)
-
-    def test_devicerole_import(self):
-        self.add_permissions('dcim.add_devicerole')
+        cls.form_data = {
+            'name': 'Devie Role X',
+            'slug': 'device-role-x',
+            'color': 'c0c0c0',
+            'vm_role': False,
+            'description': 'New device role',
+        }
 
 
-        csv_data = (
+        cls.csv_data = (
             "name,slug,color",
             "name,slug,color",
             "Device Role 4,device-role-4,ff0000",
             "Device Role 4,device-role-4,ff0000",
             "Device Role 5,device-role-5,00ff00",
             "Device Role 5,device-role-5,00ff00",
             "Device Role 6,device-role-6,0000ff",
             "Device Role 6,device-role-6,0000ff",
         )
         )
 
 
-        response = self.client.post(reverse('dcim:devicerole_import'), {'csv': '\n'.join(csv_data)})
-
-        self.assertHttpStatus(response, 200)
-        self.assertEqual(DeviceRole.objects.count(), 6)
 
 
+class PlatformTestCase(StandardTestCases.Views):
+    model = Platform
 
 
-class PlatformTestCase(TestCase):
-    user_permissions = (
-        'dcim.view_platform',
-    )
+    # Disable inapplicable tests
+    test_get_object = None
+    test_delete_object = None
 
 
     @classmethod
     @classmethod
     def setUpTestData(cls):
     def setUpTestData(cls):
 
 
+        manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
+
         Platform.objects.bulk_create([
         Platform.objects.bulk_create([
-            Platform(name='Platform 1', slug='platform-1'),
-            Platform(name='Platform 2', slug='platform-2'),
-            Platform(name='Platform 3', slug='platform-3'),
+            Platform(name='Platform 1', slug='platform-1', manufacturer=manufacturer),
+            Platform(name='Platform 2', slug='platform-2', manufacturer=manufacturer),
+            Platform(name='Platform 3', slug='platform-3', manufacturer=manufacturer),
         ])
         ])
 
 
-    def test_platform_list(self):
-
-        url = reverse('dcim:platform_list')
-
-        response = self.client.get(url)
-        self.assertHttpStatus(response, 200)
-
-    def test_platform_import(self):
-        self.add_permissions('dcim.add_platform')
+        cls.form_data = {
+            'name': 'Platform X',
+            'slug': 'platform-x',
+            'manufacturer': manufacturer.pk,
+            'napalm_driver': 'junos',
+            'napalm_args': None,
+        }
 
 
-        csv_data = (
+        cls.csv_data = (
             "name,slug",
             "name,slug",
             "Platform 4,platform-4",
             "Platform 4,platform-4",
             "Platform 5,platform-5",
             "Platform 5,platform-5",
             "Platform 6,platform-6",
             "Platform 6,platform-6",
         )
         )
 
 
-        response = self.client.post(reverse('dcim:platform_import'), {'csv': '\n'.join(csv_data)})
 
 
-        self.assertHttpStatus(response, 200)
-        self.assertEqual(Platform.objects.count(), 6)
-
-
-class DeviceTestCase(TestCase):
-    user_permissions = (
-        'dcim.view_device',
-    )
+class DeviceTestCase(StandardTestCases.Views):
+    model = Device
 
 
     @classmethod
     @classmethod
     def setUpTestData(cls):
     def setUpTestData(cls):
 
 
-        site = Site(name='Site 1', slug='site-1')
-        site.save()
-
-        manufacturer = Manufacturer(name='Manufacturer 1', slug='manufacturer-1')
-        manufacturer.save()
-
-        devicetype = DeviceType(model='Device Type 1', manufacturer=manufacturer)
-        devicetype.save()
-
-        devicerole = DeviceRole(name='Device Role 1', slug='device-role-1')
-        devicerole.save()
+        site = Site.objects.create(name='Site 1', slug='site-1')
+        rack = Rack.objects.create(name='Rack 1', site=site)
+        manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
+        devicetype = DeviceType.objects.create(model='Device Type 1', manufacturer=manufacturer)
+        devicerole = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1')
+        platform = Platform.objects.create(name='Platform 1', slug='platform-1')
 
 
         Device.objects.bulk_create([
         Device.objects.bulk_create([
             Device(name='Device 1', site=site, device_type=devicetype, device_role=devicerole),
             Device(name='Device 1', site=site, device_type=devicetype, device_role=devicerole),
@@ -572,39 +531,39 @@ class DeviceTestCase(TestCase):
             Device(name='Device 3', site=site, device_type=devicetype, device_role=devicerole),
             Device(name='Device 3', site=site, device_type=devicetype, device_role=devicerole),
         ])
         ])
 
 
-    def test_device_list(self):
-
-        url = reverse('dcim:device_list')
-        params = {
-            "device_type_id": DeviceType.objects.first().pk,
-            "role": DeviceRole.objects.first().slug,
+        cls.form_data = {
+            'device_type': devicetype.pk,
+            'device_role': devicerole.pk,
+            'tenant': None,
+            'platform': platform.pk,
+            'name': 'Device X',
+            'serial': '123456',
+            'asset_tag': 'ABCDEF',
+            'site': site.pk,
+            'rack': rack.pk,
+            'position': 1,
+            'face': DeviceFaceChoices.FACE_FRONT,
+            'status': DeviceStatusChoices.STATUS_PLANNED,
+            'primary_ip4': None,
+            'primary_ip6': None,
+            'cluster': None,
+            'virtual_chassis': None,
+            'vc_position': None,
+            'vc_priority': None,
+            'comments': 'A new device',
+            'tags': 'Alpha,Bravo,Charlie',
+            'local_context_data': None,
         }
         }
 
 
-        response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params)))
-        self.assertHttpStatus(response, 200)
-
-    def test_device(self):
-
-        device = Device.objects.first()
-        response = self.client.get(device.get_absolute_url())
-        self.assertHttpStatus(response, 200)
-
-    def test_device_import(self):
-        self.add_permissions('dcim.add_device')
-
-        csv_data = (
+        cls.csv_data = (
             "device_role,manufacturer,model_name,status,site,name",
             "device_role,manufacturer,model_name,status,site,name",
             "Device Role 1,Manufacturer 1,Device Type 1,Active,Site 1,Device 4",
             "Device Role 1,Manufacturer 1,Device Type 1,Active,Site 1,Device 4",
             "Device Role 1,Manufacturer 1,Device Type 1,Active,Site 1,Device 5",
             "Device Role 1,Manufacturer 1,Device Type 1,Active,Site 1,Device 5",
             "Device Role 1,Manufacturer 1,Device Type 1,Active,Site 1,Device 6",
             "Device Role 1,Manufacturer 1,Device Type 1,Active,Site 1,Device 6",
         )
         )
 
 
-        response = self.client.post(reverse('dcim:device_import'), {'csv': '\n'.join(csv_data)})
-
-        self.assertHttpStatus(response, 200)
-        self.assertEqual(Device.objects.count(), 6)
-
 
 
+# TODO: Convert to StandardTestCases.Views
 class ConsolePortTestCase(TestCase):
 class ConsolePortTestCase(TestCase):
     user_permissions = (
     user_permissions = (
         'dcim.view_consoleport',
         'dcim.view_consoleport',
@@ -657,6 +616,7 @@ class ConsolePortTestCase(TestCase):
         self.assertEqual(ConsolePort.objects.count(), 6)
         self.assertEqual(ConsolePort.objects.count(), 6)
 
 
 
 
+# TODO: Convert to StandardTestCases.Views
 class ConsoleServerPortTestCase(TestCase):
 class ConsoleServerPortTestCase(TestCase):
     user_permissions = (
     user_permissions = (
         'dcim.view_consoleserverport',
         'dcim.view_consoleserverport',
@@ -709,6 +669,7 @@ class ConsoleServerPortTestCase(TestCase):
         self.assertEqual(ConsoleServerPort.objects.count(), 6)
         self.assertEqual(ConsoleServerPort.objects.count(), 6)
 
 
 
 
+# TODO: Convert to StandardTestCases.Views
 class PowerPortTestCase(TestCase):
 class PowerPortTestCase(TestCase):
     user_permissions = (
     user_permissions = (
         'dcim.view_powerport',
         'dcim.view_powerport',
@@ -761,6 +722,7 @@ class PowerPortTestCase(TestCase):
         self.assertEqual(PowerPort.objects.count(), 6)
         self.assertEqual(PowerPort.objects.count(), 6)
 
 
 
 
+# TODO: Convert to StandardTestCases.Views
 class PowerOutletTestCase(TestCase):
 class PowerOutletTestCase(TestCase):
     user_permissions = (
     user_permissions = (
         'dcim.view_poweroutlet',
         'dcim.view_poweroutlet',
@@ -813,6 +775,7 @@ class PowerOutletTestCase(TestCase):
         self.assertEqual(PowerOutlet.objects.count(), 6)
         self.assertEqual(PowerOutlet.objects.count(), 6)
 
 
 
 
+# TODO: Convert to StandardTestCases.Views
 class InterfaceTestCase(TestCase):
 class InterfaceTestCase(TestCase):
     user_permissions = (
     user_permissions = (
         'dcim.view_interface',
         'dcim.view_interface',
@@ -865,6 +828,7 @@ class InterfaceTestCase(TestCase):
         self.assertEqual(Interface.objects.count(), 6)
         self.assertEqual(Interface.objects.count(), 6)
 
 
 
 
+# TODO: Convert to StandardTestCases.Views
 class FrontPortTestCase(TestCase):
 class FrontPortTestCase(TestCase):
     user_permissions = (
     user_permissions = (
         'dcim.view_frontport',
         'dcim.view_frontport',
@@ -929,6 +893,7 @@ class FrontPortTestCase(TestCase):
         self.assertEqual(FrontPort.objects.count(), 6)
         self.assertEqual(FrontPort.objects.count(), 6)
 
 
 
 
+# TODO: Convert to StandardTestCases.Views
 class RearPortTestCase(TestCase):
 class RearPortTestCase(TestCase):
     user_permissions = (
     user_permissions = (
         'dcim.view_rearport',
         'dcim.view_rearport',
@@ -981,6 +946,7 @@ class RearPortTestCase(TestCase):
         self.assertEqual(RearPort.objects.count(), 6)
         self.assertEqual(RearPort.objects.count(), 6)
 
 
 
 
+# TODO: Convert to StandardTestCases.Views
 class DeviceBayTestCase(TestCase):
 class DeviceBayTestCase(TestCase):
     user_permissions = (
     user_permissions = (
         'dcim.view_devicebay',
         'dcim.view_devicebay',
@@ -1037,6 +1003,7 @@ class DeviceBayTestCase(TestCase):
         self.assertEqual(DeviceBay.objects.count(), 6)
         self.assertEqual(DeviceBay.objects.count(), 6)
 
 
 
 
+# TODO: Convert to StandardTestCases.Views
 class InventoryItemTestCase(TestCase):
 class InventoryItemTestCase(TestCase):
     user_permissions = (
     user_permissions = (
         'dcim.view_inventoryitem',
         'dcim.view_inventoryitem',
@@ -1092,26 +1059,19 @@ class InventoryItemTestCase(TestCase):
         self.assertEqual(InventoryItem.objects.count(), 6)
         self.assertEqual(InventoryItem.objects.count(), 6)
 
 
 
 
-class CableTestCase(TestCase):
-    user_permissions = (
-        'dcim.view_cable',
-    )
+class CableTestCase(StandardTestCases.Views):
+    model = Cable
+
+    # TODO: Creation URL needs termination context
+    test_create_object = None
 
 
     @classmethod
     @classmethod
     def setUpTestData(cls):
     def setUpTestData(cls):
 
 
-        site = Site(name='Site 1', slug='site-1')
-        site.save()
-
-        manufacturer = Manufacturer(name='Manufacturer 1', slug='manufacturer-1')
-        manufacturer.save()
-
-        devicetype = DeviceType(model='Device Type 1', manufacturer=manufacturer)
-        devicetype.save()
-
-        devicerole = DeviceRole(name='Device Role 1', slug='device-role-1')
-        devicerole.save()
-
+        site = Site.objects.create(name='Site 1', slug='site-1')
+        manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
+        devicetype = DeviceType.objects.create(model='Device Type 1', manufacturer=manufacturer)
+        devicerole = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1')
         device1 = Device(name='Device 1', site=site, device_type=devicetype, device_role=devicerole)
         device1 = Device(name='Device 1', site=site, device_type=devicetype, device_role=devicerole)
         device1.save()
         device1.save()
         device2 = Device(name='Device 2', site=site, device_type=devicetype, device_role=devicerole)
         device2 = Device(name='Device 2', site=site, device_type=devicetype, device_role=devicerole)
@@ -1121,67 +1081,59 @@ class CableTestCase(TestCase):
         device4 = Device(name='Device 4', site=site, device_type=devicetype, device_role=devicerole)
         device4 = Device(name='Device 4', site=site, device_type=devicetype, device_role=devicerole)
         device4.save()
         device4.save()
 
 
-        iface1 = Interface(device=device1, name='Interface 1', type=InterfaceTypeChoices.TYPE_1GE_FIXED)
-        iface1.save()
-        iface2 = Interface(device=device1, name='Interface 2', type=InterfaceTypeChoices.TYPE_1GE_FIXED)
-        iface2.save()
-        iface3 = Interface(device=device1, name='Interface 3', type=InterfaceTypeChoices.TYPE_1GE_FIXED)
-        iface3.save()
-        iface4 = Interface(device=device2, name='Interface 1', type=InterfaceTypeChoices.TYPE_1GE_FIXED)
-        iface4.save()
-        iface5 = Interface(device=device2, name='Interface 2', type=InterfaceTypeChoices.TYPE_1GE_FIXED)
-        iface5.save()
-        iface6 = Interface(device=device2, name='Interface 3', type=InterfaceTypeChoices.TYPE_1GE_FIXED)
-        iface6.save()
-
-        # Interfaces for CSV import testing
-        Interface(device=device3, name='Interface 1', type=InterfaceTypeChoices.TYPE_1GE_FIXED).save()
-        Interface(device=device3, name='Interface 2', type=InterfaceTypeChoices.TYPE_1GE_FIXED).save()
-        Interface(device=device3, name='Interface 3', type=InterfaceTypeChoices.TYPE_1GE_FIXED).save()
-        Interface(device=device4, name='Interface 1', type=InterfaceTypeChoices.TYPE_1GE_FIXED).save()
-        Interface(device=device4, name='Interface 2', type=InterfaceTypeChoices.TYPE_1GE_FIXED).save()
-        Interface(device=device4, name='Interface 3', type=InterfaceTypeChoices.TYPE_1GE_FIXED).save()
-
-        Cable(termination_a=iface1, termination_b=iface4, type=CableTypeChoices.TYPE_CAT6).save()
-        Cable(termination_a=iface2, termination_b=iface5, type=CableTypeChoices.TYPE_CAT6).save()
-        Cable(termination_a=iface3, termination_b=iface6, type=CableTypeChoices.TYPE_CAT6).save()
-
-    def test_cable_list(self):
-
-        url = reverse('dcim:cable_list')
-        params = {
-            "type": CableTypeChoices.TYPE_CAT6,
+        interfaces = (
+            Interface(device=device1, name='Interface 1', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
+            Interface(device=device1, name='Interface 2', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
+            Interface(device=device1, name='Interface 3', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
+            Interface(device=device2, name='Interface 1', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
+            Interface(device=device2, name='Interface 2', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
+            Interface(device=device2, name='Interface 3', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
+            Interface(device=device3, name='Interface 1', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
+            Interface(device=device3, name='Interface 2', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
+            Interface(device=device3, name='Interface 3', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
+            Interface(device=device4, name='Interface 1', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
+            Interface(device=device4, name='Interface 2', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
+            Interface(device=device4, name='Interface 3', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
+        )
+        Interface.objects.bulk_create(interfaces)
+
+        Cable(termination_a=interfaces[0], termination_b=interfaces[3], type=CableTypeChoices.TYPE_CAT6).save()
+        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()
+
+        interface_ct = ContentType.objects.get_for_model(Interface)
+        cls.form_data = {
+            # Changing terminations not supported when editing an existing Cable
+            'termination_a_type': interface_ct.pk,
+            'termination_a_id': interfaces[0].pk,
+            'termination_b_type': interface_ct.pk,
+            'termination_b_id': interfaces[3].pk,
+            'type': CableTypeChoices.TYPE_CAT6,
+            'status': CableStatusChoices.STATUS_PLANNED,
+            'label': 'New cable',
+            'color': 'c0c0c0',
+            'length': 100,
+            'length_unit': CableLengthUnitChoices.UNIT_FOOT,
         }
         }
 
 
-        response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params)))
-        self.assertHttpStatus(response, 200)
-
-    def test_cable(self):
-
-        cable = Cable.objects.first()
-        response = self.client.get(cable.get_absolute_url())
-        self.assertHttpStatus(response, 200)
-
-    def test_cable_import(self):
-        self.add_permissions('dcim.add_cable')
-
-        csv_data = (
+        cls.csv_data = (
             "side_a_device,side_a_type,side_a_name,side_b_device,side_b_type,side_b_name",
             "side_a_device,side_a_type,side_a_name,side_b_device,side_b_type,side_b_name",
             "Device 3,interface,Interface 1,Device 4,interface,Interface 1",
             "Device 3,interface,Interface 1,Device 4,interface,Interface 1",
             "Device 3,interface,Interface 2,Device 4,interface,Interface 2",
             "Device 3,interface,Interface 2,Device 4,interface,Interface 2",
             "Device 3,interface,Interface 3,Device 4,interface,Interface 3",
             "Device 3,interface,Interface 3,Device 4,interface,Interface 3",
         )
         )
 
 
-        response = self.client.post(reverse('dcim:cable_import'), {'csv': '\n'.join(csv_data)})
 
 
-        self.assertHttpStatus(response, 200)
-        self.assertEqual(Cable.objects.count(), 6)
+class VirtualChassisTestCase(StandardTestCases.Views):
+    model = VirtualChassis
 
 
+    # Disable inapplicable tests
+    test_get_object = None
+    test_import_objects = None
 
 
-class VirtualChassisTestCase(TestCase):
-    user_permissions = (
-        'dcim.view_virtualchassis',
-    )
+    # TODO: Requires special form handling
+    test_create_object = None
+    test_edit_object = None
 
 
     @classmethod
     @classmethod
     def setUpTestData(cls):
     def setUpTestData(cls):
@@ -1222,10 +1174,3 @@ class VirtualChassisTestCase(TestCase):
         Device.objects.filter(pk=device4.pk).update(virtual_chassis=vc2, vc_position=2)
         Device.objects.filter(pk=device4.pk).update(virtual_chassis=vc2, vc_position=2)
         vc3 = VirtualChassis.objects.create(master=device5, domain='test-domain-3')
         vc3 = VirtualChassis.objects.create(master=device5, domain='test-domain-3')
         Device.objects.filter(pk=device6.pk).update(virtual_chassis=vc3, vc_position=2)
         Device.objects.filter(pk=device6.pk).update(virtual_chassis=vc3, vc_position=2)
-
-    def test_virtualchassis_list(self):
-
-        url = reverse('dcim:virtualchassis_list')
-
-        response = self.client.get(url)
-        self.assertHttpStatus(response, 200)