Establish standard test cases for all models

This commit is contained in:
Jeremy Stretch 2020-02-12 12:33:27 -05:00
parent e4b910fe87
commit 3b1128f8f3
8 changed files with 253 additions and 390 deletions

View File

@ -2,10 +2,10 @@ import datetime
from circuits.choices import *
from circuits.models import Circuit, CircuitType, Provider
from utilities.testing import StandardTestCases
from utilities.testing import ViewTestCases
class ProviderTestCase(StandardTestCases.Views):
class ProviderTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = Provider
@classmethod
@ -46,14 +46,9 @@ class ProviderTestCase(StandardTestCases.Views):
}
class CircuitTypeTestCase(StandardTestCases.Views):
class CircuitTypeTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
model = CircuitType
# Disable inapplicable tests
test_get_object = None
test_delete_object = None
test_bulk_edit_objects = None
@classmethod
def setUpTestData(cls):
@ -77,7 +72,7 @@ class CircuitTypeTestCase(StandardTestCases.Views):
)
class CircuitTestCase(StandardTestCases.Views):
class CircuitTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = Circuit
@classmethod

View File

@ -11,7 +11,7 @@ from dcim.choices import *
from dcim.constants import *
from dcim.models import *
from ipam.models import VLAN
from utilities.testing import StandardTestCases
from utilities.testing import ViewTestCases
def create_test_device(name):
@ -27,14 +27,9 @@ def create_test_device(name):
return device
class RegionTestCase(StandardTestCases.Views):
class RegionTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
model = Region
# Disable inapplicable tests
test_get_object = None
test_delete_object = None
test_bulk_edit_objects = None
@classmethod
def setUpTestData(cls):
@ -61,7 +56,7 @@ class RegionTestCase(StandardTestCases.Views):
)
class SiteTestCase(StandardTestCases.Views):
class SiteTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = Site
@classmethod
@ -118,14 +113,9 @@ class SiteTestCase(StandardTestCases.Views):
}
class RackGroupTestCase(StandardTestCases.Views):
class RackGroupTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
model = RackGroup
# Disable inapplicable tests
test_get_object = None
test_delete_object = None
test_bulk_edit_objects = None
@classmethod
def setUpTestData(cls):
@ -152,14 +142,9 @@ class RackGroupTestCase(StandardTestCases.Views):
)
class RackRoleTestCase(StandardTestCases.Views):
class RackRoleTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
model = RackRole
# Disable inapplicable tests
test_get_object = None
test_delete_object = None
test_bulk_edit_objects = None
@classmethod
def setUpTestData(cls):
@ -184,7 +169,7 @@ class RackRoleTestCase(StandardTestCases.Views):
)
class RackReservationTestCase(StandardTestCases.Views):
class RackReservationTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = RackReservation
# Disable inapplicable tests
@ -226,7 +211,7 @@ class RackReservationTestCase(StandardTestCases.Views):
}
class RackTestCase(StandardTestCases.Views):
class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = Rack
@classmethod
@ -302,14 +287,9 @@ class RackTestCase(StandardTestCases.Views):
}
class ManufacturerTestCase(StandardTestCases.Views):
class ManufacturerTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
model = Manufacturer
# Disable inapplicable tests
test_get_object = None
test_delete_object = None
test_bulk_edit_objects = None
@classmethod
def setUpTestData(cls):
@ -332,7 +312,7 @@ class ManufacturerTestCase(StandardTestCases.Views):
)
class DeviceTypeTestCase(StandardTestCases.Views):
class DeviceTypeTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = DeviceType
@classmethod
@ -528,18 +508,9 @@ device-bays:
# DeviceType components
#
class ConsolePortTemplateTestCase(StandardTestCases.Views):
class ConsolePortTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
model = ConsolePortTemplate
# Disable inapplicable views
test_get_object = None
test_list_objects = None
test_create_object = None
test_import_objects = None
def test_bulk_create_objects(self):
return self._test_bulk_create_objects(expected_count=3)
@classmethod
def setUpTestData(cls):
manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
@ -572,18 +543,9 @@ class ConsolePortTemplateTestCase(StandardTestCases.Views):
}
class ConsoleServerPortTemplateTestCase(StandardTestCases.Views):
class ConsoleServerPortTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
model = ConsoleServerPortTemplate
# Disable inapplicable views
test_get_object = None
test_list_objects = None
test_create_object = None
test_import_objects = None
def test_bulk_create_objects(self):
return self._test_bulk_create_objects(expected_count=3)
@classmethod
def setUpTestData(cls):
manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
@ -616,18 +578,9 @@ class ConsoleServerPortTemplateTestCase(StandardTestCases.Views):
}
class PowerPortTemplateTestCase(StandardTestCases.Views):
class PowerPortTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
model = PowerPortTemplate
# Disable inapplicable views
test_get_object = None
test_list_objects = None
test_create_object = None
test_import_objects = None
def test_bulk_create_objects(self):
return self._test_bulk_create_objects(expected_count=3)
@classmethod
def setUpTestData(cls):
manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
@ -666,18 +619,9 @@ class PowerPortTemplateTestCase(StandardTestCases.Views):
}
class PowerOutletTemplateTestCase(StandardTestCases.Views):
class PowerOutletTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
model = PowerOutletTemplate
# Disable inapplicable views
test_get_object = None
test_list_objects = None
test_create_object = None
test_import_objects = None
def test_bulk_create_objects(self):
return self._test_bulk_create_objects(expected_count=3)
@classmethod
def setUpTestData(cls):
manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
@ -716,18 +660,9 @@ class PowerOutletTemplateTestCase(StandardTestCases.Views):
}
class InterfaceTemplateTestCase(StandardTestCases.Views):
class InterfaceTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
model = InterfaceTemplate
# Disable inapplicable views
test_get_object = None
test_list_objects = None
test_create_object = None
test_import_objects = None
def test_bulk_create_objects(self):
return self._test_bulk_create_objects(expected_count=3)
@classmethod
def setUpTestData(cls):
manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
@ -763,18 +698,9 @@ class InterfaceTemplateTestCase(StandardTestCases.Views):
}
class FrontPortTemplateTestCase(StandardTestCases.Views):
class FrontPortTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
model = FrontPortTemplate
# Disable inapplicable views
test_get_object = None
test_list_objects = None
test_create_object = None
test_import_objects = None
def test_bulk_create_objects(self):
return self._test_bulk_create_objects(expected_count=3)
@classmethod
def setUpTestData(cls):
manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
@ -818,18 +744,9 @@ class FrontPortTemplateTestCase(StandardTestCases.Views):
}
class RearPortTemplateTestCase(StandardTestCases.Views):
class RearPortTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
model = RearPortTemplate
# Disable inapplicable views
test_get_object = None
test_list_objects = None
test_create_object = None
test_import_objects = None
def test_bulk_create_objects(self):
return self._test_bulk_create_objects(expected_count=3)
@classmethod
def setUpTestData(cls):
manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
@ -864,19 +781,12 @@ class RearPortTemplateTestCase(StandardTestCases.Views):
}
class DeviceBayTemplateTestCase(StandardTestCases.Views):
class DeviceBayTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
model = DeviceBayTemplate
# Disable inapplicable views
test_get_object = None
test_list_objects = None
test_create_object = None
test_import_objects = None
test_bulk_edit_objects = None
def test_bulk_create_objects(self):
return self._test_bulk_create_objects(expected_count=3)
@classmethod
def setUpTestData(cls):
manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
@ -903,14 +813,9 @@ class DeviceBayTemplateTestCase(StandardTestCases.Views):
}
class DeviceRoleTestCase(StandardTestCases.Views):
class DeviceRoleTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
model = DeviceRole
# Disable inapplicable tests
test_get_object = None
test_delete_object = None
test_bulk_edit_objects = None
@classmethod
def setUpTestData(cls):
@ -936,14 +841,9 @@ class DeviceRoleTestCase(StandardTestCases.Views):
)
class PlatformTestCase(StandardTestCases.Views):
class PlatformTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
model = Platform
# Disable inapplicable tests
test_get_object = None
test_delete_object = None
test_bulk_edit_objects = None
@classmethod
def setUpTestData(cls):
@ -971,7 +871,7 @@ class PlatformTestCase(StandardTestCases.Views):
)
class DeviceTestCase(StandardTestCases.Views):
class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = Device
@classmethod
@ -1056,16 +956,9 @@ class DeviceTestCase(StandardTestCases.Views):
}
class ConsolePortTestCase(StandardTestCases.Views):
class ConsolePortTestCase(ViewTestCases.DeviceComponentViewTestCase):
model = ConsolePort
# Disable inapplicable views
test_get_object = None
test_create_object = None
def test_bulk_create_objects(self):
return self._test_bulk_create_objects(expected_count=3)
@classmethod
def setUpTestData(cls):
device = create_test_device('Device 1')
@ -1105,16 +998,9 @@ class ConsolePortTestCase(StandardTestCases.Views):
)
class ConsoleServerPortTestCase(StandardTestCases.Views):
class ConsoleServerPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
model = ConsoleServerPort
# Disable inapplicable views
test_get_object = None
test_create_object = None
def test_bulk_create_objects(self):
return self._test_bulk_create_objects(expected_count=3)
@classmethod
def setUpTestData(cls):
device = create_test_device('Device 1')
@ -1155,16 +1041,9 @@ class ConsoleServerPortTestCase(StandardTestCases.Views):
)
class PowerPortTestCase(StandardTestCases.Views):
class PowerPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
model = PowerPort
# Disable inapplicable views
test_get_object = None
test_create_object = None
def test_bulk_create_objects(self):
return self._test_bulk_create_objects(expected_count=3)
@classmethod
def setUpTestData(cls):
device = create_test_device('Device 1')
@ -1210,16 +1089,9 @@ class PowerPortTestCase(StandardTestCases.Views):
)
class PowerOutletTestCase(StandardTestCases.Views):
class PowerOutletTestCase(ViewTestCases.DeviceComponentViewTestCase):
model = PowerOutlet
# Disable inapplicable views
test_get_object = None
test_create_object = None
def test_bulk_create_objects(self):
return self._test_bulk_create_objects(expected_count=3)
@classmethod
def setUpTestData(cls):
device = create_test_device('Device 1')
@ -1272,15 +1144,12 @@ class PowerOutletTestCase(StandardTestCases.Views):
)
class InterfaceTestCase(StandardTestCases.Views):
class InterfaceTestCase(
ViewTestCases.GetObjectViewTestCase,
ViewTestCases.DeviceComponentViewTestCase,
):
model = Interface
# Disable inapplicable views
test_create_object = None
def test_bulk_create_objects(self):
return self._test_bulk_create_objects(expected_count=3)
@classmethod
def setUpTestData(cls):
device = create_test_device('Device 1')
@ -1356,16 +1225,9 @@ class InterfaceTestCase(StandardTestCases.Views):
)
class FrontPortTestCase(StandardTestCases.Views):
class FrontPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
model = FrontPort
# Disable inapplicable views
test_get_object = None
test_create_object = None
def test_bulk_create_objects(self):
return self._test_bulk_create_objects(expected_count=3)
@classmethod
def setUpTestData(cls):
device = create_test_device('Device 1')
@ -1420,16 +1282,9 @@ class FrontPortTestCase(StandardTestCases.Views):
)
class RearPortTestCase(StandardTestCases.Views):
class RearPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
model = RearPort
# Disable inapplicable views
test_get_object = None
test_create_object = None
def test_bulk_create_objects(self):
return self._test_bulk_create_objects(expected_count=3)
@classmethod
def setUpTestData(cls):
device = create_test_device('Device 1')
@ -1471,19 +1326,12 @@ class RearPortTestCase(StandardTestCases.Views):
)
class DeviceBayTestCase(StandardTestCases.Views):
class DeviceBayTestCase(ViewTestCases.DeviceComponentViewTestCase):
model = DeviceBay
# Disable inapplicable views
test_get_object = None
test_create_object = None
# TODO
test_bulk_edit_objects = None
def test_bulk_create_objects(self):
return self._test_bulk_create_objects(expected_count=3)
@classmethod
def setUpTestData(cls):
device1 = create_test_device('Device 1')
@ -1520,16 +1368,9 @@ class DeviceBayTestCase(StandardTestCases.Views):
)
class InventoryItemTestCase(StandardTestCases.Views):
class InventoryItemTestCase(ViewTestCases.DeviceComponentViewTestCase):
model = InventoryItem
# Disable inapplicable views
test_get_object = None
test_create_object = None
def test_bulk_create_objects(self):
return self._test_bulk_create_objects(expected_count=3)
@classmethod
def setUpTestData(cls):
device = create_test_device('Device 1')
@ -1581,7 +1422,7 @@ class InventoryItemTestCase(StandardTestCases.Views):
)
class CableTestCase(StandardTestCases.Views):
class CableTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = Cable
# TODO: Creation URL needs termination context
@ -1655,7 +1496,7 @@ class CableTestCase(StandardTestCases.Views):
}
class VirtualChassisTestCase(StandardTestCases.Views):
class VirtualChassisTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = VirtualChassis
# Disable inapplicable tests
@ -1709,7 +1550,7 @@ class VirtualChassisTestCase(StandardTestCases.Views):
Device.objects.filter(pk=device6.pk).update(virtual_chassis=vc3, vc_position=2)
class PowerPanelTestCase(StandardTestCases.Views):
class PowerPanelTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = PowerPanel
# Disable inapplicable tests
@ -1750,7 +1591,7 @@ class PowerPanelTestCase(StandardTestCases.Views):
)
class PowerFeedTestCase(StandardTestCases.Views):
class PowerFeedTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = PowerFeed
@classmethod

View File

@ -7,10 +7,10 @@ from django.urls import reverse
from dcim.models import Site
from extras.choices import ObjectChangeActionChoices
from extras.models import ConfigContext, ObjectChange, Tag
from utilities.testing import StandardTestCases, TestCase
from utilities.testing import ViewTestCases, TestCase
class TagTestCase(StandardTestCases.Views):
class TagTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = Tag
# Disable inapplicable tests
@ -38,7 +38,7 @@ class TagTestCase(StandardTestCases.Views):
}
class ConfigContextTestCase(StandardTestCases.Views):
class ConfigContextTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = ConfigContext
# Disable inapplicable tests

View File

@ -5,10 +5,10 @@ from netaddr import IPNetwork
from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site
from ipam.choices import *
from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
from utilities.testing import StandardTestCases
from utilities.testing import ViewTestCases
class VRFTestCase(StandardTestCases.Views):
class VRFTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = VRF
@classmethod
@ -43,14 +43,9 @@ class VRFTestCase(StandardTestCases.Views):
}
class RIRTestCase(StandardTestCases.Views):
class RIRTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
model = RIR
# Disable inapplicable tests
test_get_object = None
test_delete_object = None
test_bulk_edit_objects = None
@classmethod
def setUpTestData(cls):
@ -74,7 +69,7 @@ class RIRTestCase(StandardTestCases.Views):
)
class AggregateTestCase(StandardTestCases.Views):
class AggregateTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = Aggregate
@classmethod
@ -115,14 +110,9 @@ class AggregateTestCase(StandardTestCases.Views):
}
class RoleTestCase(StandardTestCases.Views):
class RoleTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
model = Role
# Disable inapplicable tests
test_get_object = None
test_delete_object = None
test_bulk_edit_objects = None
@classmethod
def setUpTestData(cls):
@ -147,7 +137,7 @@ class RoleTestCase(StandardTestCases.Views):
)
class PrefixTestCase(StandardTestCases.Views):
class PrefixTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = Prefix
@classmethod
@ -207,7 +197,7 @@ class PrefixTestCase(StandardTestCases.Views):
}
class IPAddressTestCase(StandardTestCases.Views):
class IPAddressTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = IPAddress
@classmethod
@ -254,14 +244,9 @@ class IPAddressTestCase(StandardTestCases.Views):
}
class VLANGroupTestCase(StandardTestCases.Views):
class VLANGroupTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
model = VLANGroup
# Disable inapplicable tests
test_get_object = None
test_delete_object = None
test_bulk_edit_objects = None
@classmethod
def setUpTestData(cls):
@ -287,7 +272,7 @@ class VLANGroupTestCase(StandardTestCases.Views):
)
class VLANTestCase(StandardTestCases.Views):
class VLANTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = VLAN
@classmethod
@ -346,7 +331,7 @@ class VLANTestCase(StandardTestCases.Views):
}
class ServiceTestCase(StandardTestCases.Views):
class ServiceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = Service
# Disable inapplicable tests

View File

@ -4,18 +4,13 @@ from django.urls import reverse
from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site
from secrets.models import Secret, SecretRole, SessionKey, UserKey
from utilities.testing import StandardTestCases
from utilities.testing import ViewTestCases
from .constants import PRIVATE_KEY, PUBLIC_KEY
class SecretRoleTestCase(StandardTestCases.Views):
class SecretRoleTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
model = SecretRole
# Disable inapplicable tests
test_get_object = None
test_delete_object = None
test_bulk_edit_objects = None
@classmethod
def setUpTestData(cls):
@ -41,7 +36,7 @@ class SecretRoleTestCase(StandardTestCases.Views):
)
class SecretTestCase(StandardTestCases.Views):
class SecretTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = Secret
# Disable inapplicable tests

View File

@ -1,15 +1,10 @@
from tenancy.models import Tenant, TenantGroup
from utilities.testing import StandardTestCases
from utilities.testing import ViewTestCases
class TenantGroupTestCase(StandardTestCases.Views):
class TenantGroupTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
model = TenantGroup
# Disable inapplicable tests
test_get_object = None
test_delete_object = None
test_bulk_edit_objects = None
@classmethod
def setUpTestData(cls):
@ -32,7 +27,7 @@ class TenantGroupTestCase(StandardTestCases.Views):
)
class TenantTestCase(StandardTestCases.Views):
class TenantTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = Tenant
@classmethod

View File

@ -57,6 +57,53 @@ class TestCase(_TestCase):
expected_status, response.status_code, getattr(response, 'data', 'No data')
))
class ModelViewTestCase(TestCase):
"""
Base TestCase for model views. Subclass to test individual views.
"""
model = None
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.model is None:
raise Exception("Test case requires model to be defined")
def _get_base_url(self):
"""
Return the base format for a URL for the test's model. Override this to test for a model which belongs
to a different app (e.g. testing Interfaces within the virtualization app).
"""
return '{}:{}_{{}}'.format(
self.model._meta.app_label,
self.model._meta.model_name
)
def _get_url(self, action, instance=None):
"""
Return the URL name for a specific action. An instance must be specified for
get/edit/delete views.
"""
url_format = self._get_base_url()
if action in ('list', 'add', 'import', 'bulk_edit', 'bulk_delete'):
return reverse(url_format.format(action))
elif action in ('get', 'edit', 'delete'):
if instance is None:
raise Exception("Resolving {} URL requires specifying an instance".format(action))
# Attempt to resolve using slug first
if hasattr(self.model, 'slug'):
try:
return reverse(url_format.format(action), kwargs={'slug': instance.slug})
except NoReverseMatch:
pass
return reverse(url_format.format(action), kwargs={'pk': instance.pk})
else:
raise Exception("Invalid action for URL resolution: {}".format(action))
def assertInstanceEqual(self, instance, data):
"""
Compare a model instance to a dictionary, checking that its attribute values match those specified
@ -94,108 +141,14 @@ class APITestCase(TestCase):
self.header = {'HTTP_AUTHORIZATION': 'Token {}'.format(self.token.key)}
class StandardTestCases:
class ViewTestCases:
"""
We keep any TestCases with test_* methods inside a class to prevent unittest from trying to run them.
"""
class Views(TestCase):
class GetObjectViewTestCase(ModelViewTestCase):
"""
Stock TestCase suitable for testing all standard View functions:
- List objects
- View single object
- Create new object
- Modify existing object
- Delete existing object
- Import multiple new objects
Retrieve a single instance.
"""
model = None
# Data to be sent when creating/editing individual objects
form_data = {}
# CSV lines used for bulk import of new objects
csv_data = ()
# Form data used when creating multiple objects
bulk_create_data = {}
# Form data to be used when editing multiple objects at once
bulk_edit_data = {}
maxDiff = None
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.model is None:
raise Exception("Test case requires model to be defined")
#
# URL functions
#
def _get_base_url(self):
"""
Return the base format for a URL for the test's model. Override this to test for a model which belongs
to a different app (e.g. testing Interfaces within the virtualization app).
"""
return '{}:{}_{{}}'.format(
self.model._meta.app_label,
self.model._meta.model_name
)
def _get_url(self, action, instance=None):
"""
Return the URL name for a specific action. An instance must be specified for
get/edit/delete views.
"""
url_format = self._get_base_url()
if action in ('list', 'add', 'import', 'bulk_edit', 'bulk_delete'):
return reverse(url_format.format(action))
elif action in ('get', 'edit', 'delete'):
if instance is None:
raise Exception("Resolving {} URL requires specifying an instance".format(action))
# Attempt to resolve using slug first
if hasattr(self.model, 'slug'):
try:
return reverse(url_format.format(action), kwargs={'slug': instance.slug})
except NoReverseMatch:
pass
return reverse(url_format.format(action), kwargs={'pk': instance.pk})
else:
raise Exception("Invalid action for URL resolution: {}".format(action))
#
# Standard view tests
# These methods will run by default. To disable a test, nullify its method on the subclasses TestCase:
#
# test_list_objects = None
#
@override_settings(EXEMPT_VIEW_PERMISSIONS=[])
def test_list_objects(self):
# Attempt to make the request without required permissions
with disable_warnings('django.request'):
self.assertHttpStatus(self.client.get(self._get_url('list')), 403)
# Assign the required permission and submit again
self.add_permissions(
'{}.view_{}'.format(self.model._meta.app_label, self.model._meta.model_name)
)
response = self.client.get(self._get_url('list'))
self.assertHttpStatus(response, 200)
# Built-in CSV export
if hasattr(self.model, 'csv_headers'):
response = self.client.get('{}?export'.format(self._get_url('list')))
self.assertHttpStatus(response, 200)
self.assertEqual(response.get('Content-Type'), 'text/csv')
@override_settings(EXEMPT_VIEW_PERMISSIONS=[])
def test_get_object(self):
instance = self.model.objects.first()
@ -211,6 +164,12 @@ class StandardTestCases:
response = self.client.get(instance.get_absolute_url())
self.assertHttpStatus(response, 200)
class CreateObjectViewTestCase(ModelViewTestCase):
"""
Create a single new instance.
"""
form_data = {}
@override_settings(EXEMPT_VIEW_PERMISSIONS=[])
def test_create_object(self):
initial_count = self.model.objects.count()
@ -235,6 +194,12 @@ class StandardTestCases:
instance = self.model.objects.order_by('-pk').first()
self.assertInstanceEqual(instance, self.form_data)
class EditObjectViewTestCase(ModelViewTestCase):
"""
Edit a single existing instance.
"""
form_data = {}
@override_settings(EXEMPT_VIEW_PERMISSIONS=[])
def test_edit_object(self):
instance = self.model.objects.first()
@ -259,6 +224,10 @@ class StandardTestCases:
instance = self.model.objects.get(pk=instance.pk)
self.assertInstanceEqual(instance, self.form_data)
class DeleteObjectViewTestCase(ModelViewTestCase):
"""
Delete a single instance.
"""
@override_settings(EXEMPT_VIEW_PERMISSIONS=[])
def test_delete_object(self):
instance = self.model.objects.first()
@ -283,6 +252,66 @@ class StandardTestCases:
with self.assertRaises(ObjectDoesNotExist):
self.model.objects.get(pk=instance.pk)
class ListObjectsViewTestCase(ModelViewTestCase):
"""
Retrieve multiple instances.
"""
@override_settings(EXEMPT_VIEW_PERMISSIONS=[])
def test_list_objects(self):
# Attempt to make the request without required permissions
with disable_warnings('django.request'):
self.assertHttpStatus(self.client.get(self._get_url('list')), 403)
# Assign the required permission and submit again
self.add_permissions(
'{}.view_{}'.format(self.model._meta.app_label, self.model._meta.model_name)
)
response = self.client.get(self._get_url('list'))
self.assertHttpStatus(response, 200)
# Built-in CSV export
if hasattr(self.model, 'csv_headers'):
response = self.client.get('{}?export'.format(self._get_url('list')))
self.assertHttpStatus(response, 200)
self.assertEqual(response.get('Content-Type'), 'text/csv')
class BulkCreateObjectsViewTestCase(ModelViewTestCase):
"""
Create multiple instances using a single form. Expects the creation of three new instances by default.
"""
bulk_create_count = 3
bulk_create_data = {}
@override_settings(EXEMPT_VIEW_PERMISSIONS=[])
def test_bulk_create_objects(self):
initial_count = self.model.objects.count()
request = {
'path': self._get_url('add'),
'data': post_data(self.bulk_create_data),
'follow': False, # Do not follow 302 redirects
}
# Attempt to make the request without required permissions
with disable_warnings('django.request'):
self.assertHttpStatus(self.client.post(**request), 403)
# Assign the required permission and submit again
self.add_permissions(
'{}.add_{}'.format(self.model._meta.app_label, self.model._meta.model_name)
)
response = self.client.post(**request)
self.assertHttpStatus(response, 302)
self.assertEqual(initial_count + self.bulk_create_count, self.model.objects.count())
for instance in self.model.objects.order_by('-pk')[:self.bulk_create_count]:
self.assertInstanceEqual(instance, self.bulk_create_data)
class ImportObjectsViewTestCase(ModelViewTestCase):
"""
Create multiple instances from imported data.
"""
csv_data = ()
@override_settings(EXEMPT_VIEW_PERMISSIONS=[])
def test_import_objects(self):
initial_count = self.model.objects.count()
@ -307,6 +336,12 @@ class StandardTestCases:
self.assertEqual(self.model.objects.count(), initial_count + len(self.csv_data) - 1)
class BulkEditObjectsViewTestCase(ModelViewTestCase):
"""
Edit multiple instances.
"""
bulk_edit_data = {}
@override_settings(EXEMPT_VIEW_PERMISSIONS=[])
def test_bulk_edit_objects(self):
# Bulk edit the first three objects only
@ -338,6 +373,10 @@ class StandardTestCases:
for i, instance in enumerate(self.model.objects.filter(pk__in=pk_list)):
self.assertInstanceEqual(instance, self.bulk_edit_data)
class BulkDeleteObjectsViewTestCase(ModelViewTestCase):
"""
Delete multiple instances.
"""
@override_settings(EXEMPT_VIEW_PERMISSIONS=[])
def test_bulk_delete_objects(self):
pk_list = self.model.objects.values_list('pk', flat=True)
@ -366,31 +405,55 @@ class StandardTestCases:
# Check that all objects were deleted
self.assertEqual(self.model.objects.count(), 0)
#
# Optional view tests
# These methods will run only if the required data
#
class PrimaryObjectViewTestCase(
GetObjectViewTestCase,
CreateObjectViewTestCase,
EditObjectViewTestCase,
DeleteObjectViewTestCase,
ListObjectsViewTestCase,
ImportObjectsViewTestCase,
BulkEditObjectsViewTestCase,
BulkDeleteObjectsViewTestCase,
):
"""
TestCase suitable for testing all standard View functions for primary objects
"""
maxDiff = None
@override_settings(EXEMPT_VIEW_PERMISSIONS=[])
def _test_bulk_create_objects(self, expected_count):
initial_count = self.model.objects.count()
request = {
'path': self._get_url('add'),
'data': post_data(self.bulk_create_data),
'follow': False, # Do not follow 302 redirects
}
class OrganizationalObjectViewTestCase(
CreateObjectViewTestCase,
EditObjectViewTestCase,
ListObjectsViewTestCase,
ImportObjectsViewTestCase,
BulkDeleteObjectsViewTestCase,
):
"""
TestCase suitable for all organizational objects
"""
maxDiff = None
# Attempt to make the request without required permissions
with disable_warnings('django.request'):
self.assertHttpStatus(self.client.post(**request), 403)
class DeviceComponentTemplateViewTestCase(
EditObjectViewTestCase,
DeleteObjectViewTestCase,
BulkCreateObjectsViewTestCase,
BulkEditObjectsViewTestCase,
BulkDeleteObjectsViewTestCase,
):
"""
TestCase suitable for testing device component template models (ConsolePortTemplates, InterfaceTemplates, etc.)
"""
maxDiff = None
# Assign the required permission and submit again
self.add_permissions(
'{}.add_{}'.format(self.model._meta.app_label, self.model._meta.model_name)
)
response = self.client.post(**request)
self.assertHttpStatus(response, 302)
self.assertEqual(initial_count + expected_count, self.model.objects.count())
for instance in self.model.objects.order_by('-pk')[:expected_count]:
self.assertInstanceEqual(instance, self.bulk_create_data)
class DeviceComponentViewTestCase(
EditObjectViewTestCase,
DeleteObjectViewTestCase,
ListObjectsViewTestCase,
BulkCreateObjectsViewTestCase,
ImportObjectsViewTestCase,
BulkEditObjectsViewTestCase,
BulkDeleteObjectsViewTestCase,
):
"""
TestCase suitable for testing device component models (ConsolePorts, Interfaces, etc.)
"""
maxDiff = None

View File

@ -3,19 +3,14 @@ from netaddr import EUI
from dcim.choices import InterfaceModeChoices
from dcim.models import DeviceRole, Interface, Platform, Site
from ipam.models import VLAN
from utilities.testing import StandardTestCases
from utilities.testing import ViewTestCases
from virtualization.choices import *
from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine
class ClusterGroupTestCase(StandardTestCases.Views):
class ClusterGroupTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
model = ClusterGroup
# Disable inapplicable tests
test_get_object = None
test_delete_object = None
test_bulk_edit_objects = None
@classmethod
def setUpTestData(cls):
@ -38,14 +33,9 @@ class ClusterGroupTestCase(StandardTestCases.Views):
)
class ClusterTypeTestCase(StandardTestCases.Views):
class ClusterTypeTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
model = ClusterType
# Disable inapplicable tests
test_get_object = None
test_delete_object = None
test_bulk_edit_objects = None
@classmethod
def setUpTestData(cls):
@ -68,7 +58,7 @@ class ClusterTypeTestCase(StandardTestCases.Views):
)
class ClusterTestCase(StandardTestCases.Views):
class ClusterTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = Cluster
@classmethod
@ -124,7 +114,7 @@ class ClusterTestCase(StandardTestCases.Views):
}
class VirtualMachineTestCase(StandardTestCases.Views):
class VirtualMachineTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = VirtualMachine
@classmethod
@ -193,17 +183,16 @@ class VirtualMachineTestCase(StandardTestCases.Views):
}
class InterfaceTestCase(StandardTestCases.Views):
class InterfaceTestCase(
ViewTestCases.GetObjectViewTestCase,
ViewTestCases.DeviceComponentViewTestCase,
):
model = Interface
# Disable inapplicable tests
test_list_objects = None
test_create_object = None
test_import_objects = None
def test_bulk_create_objects(self):
return self._test_bulk_create_objects(expected_count=3)
def _get_base_url(self):
# Interface belongs to the DCIM app, so we have to override the base URL
return 'virtualization:interface_{}'