mirror of
https://github.com/netbox-community/netbox.git
synced 2026-04-06 00:32:08 +02:00
test(tables): Add reusable OrderableColumnsTestCase
Introduce `TableTestCases.OrderableColumnsTestCase`, a shared base class that automatically discovers sortable columns from list-view querysets and verifies each renders without exceptions in both ascending and descending order. Add per-table smoke tests across circuits, core, dcim, extras, ipam, tenancy, users, virtualization, vpn, and wireless apps. Fixes #21766
This commit is contained in:
@@ -1,48 +1,46 @@
|
|||||||
from django.test import RequestFactory, TestCase, tag
|
from circuits.tables import *
|
||||||
|
from utilities.testing import TableTestCases
|
||||||
from circuits.models import CircuitGroupAssignment, CircuitTermination
|
|
||||||
from circuits.tables import CircuitGroupAssignmentTable, CircuitTerminationTable
|
|
||||||
|
|
||||||
|
|
||||||
@tag('regression')
|
class CircuitTypeTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
class CircuitTerminationTableTest(TestCase):
|
table = CircuitTypeTable
|
||||||
def test_every_orderable_field_does_not_throw_exception(self):
|
|
||||||
terminations = CircuitTermination.objects.all()
|
|
||||||
disallowed = {
|
|
||||||
'actions',
|
|
||||||
}
|
|
||||||
|
|
||||||
orderable_columns = [
|
|
||||||
column.name
|
|
||||||
for column in CircuitTerminationTable(terminations).columns
|
|
||||||
if column.orderable and column.name not in disallowed
|
|
||||||
]
|
|
||||||
fake_request = RequestFactory().get('/')
|
|
||||||
|
|
||||||
for col in orderable_columns:
|
|
||||||
for direction in ('-', ''):
|
|
||||||
table = CircuitTerminationTable(terminations)
|
|
||||||
table.order_by = f'{direction}{col}'
|
|
||||||
table.as_html(fake_request)
|
|
||||||
|
|
||||||
|
|
||||||
@tag('regression')
|
class CircuitTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
class CircuitGroupAssignmentTableTest(TestCase):
|
table = CircuitTable
|
||||||
def test_every_orderable_field_does_not_throw_exception(self):
|
|
||||||
assignment = CircuitGroupAssignment.objects.all()
|
|
||||||
disallowed = {
|
|
||||||
'actions',
|
|
||||||
}
|
|
||||||
|
|
||||||
orderable_columns = [
|
|
||||||
column.name
|
|
||||||
for column in CircuitGroupAssignmentTable(assignment).columns
|
|
||||||
if column.orderable and column.name not in disallowed
|
|
||||||
]
|
|
||||||
fake_request = RequestFactory().get('/')
|
|
||||||
|
|
||||||
for col in orderable_columns:
|
class CircuitTerminationTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
for direction in ('-', ''):
|
table = CircuitTerminationTable
|
||||||
table = CircuitGroupAssignmentTable(assignment)
|
|
||||||
table.order_by = f'{direction}{col}'
|
|
||||||
table.as_html(fake_request)
|
class CircuitGroupTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = CircuitGroupTable
|
||||||
|
|
||||||
|
|
||||||
|
class CircuitGroupAssignmentTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = CircuitGroupAssignmentTable
|
||||||
|
|
||||||
|
|
||||||
|
class ProviderTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ProviderTable
|
||||||
|
|
||||||
|
|
||||||
|
class ProviderAccountTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ProviderAccountTable
|
||||||
|
|
||||||
|
|
||||||
|
class ProviderNetworkTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ProviderNetworkTable
|
||||||
|
|
||||||
|
|
||||||
|
class VirtualCircuitTypeTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = VirtualCircuitTypeTable
|
||||||
|
|
||||||
|
|
||||||
|
class VirtualCircuitTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = VirtualCircuitTable
|
||||||
|
|
||||||
|
|
||||||
|
class VirtualCircuitTerminationTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = VirtualCircuitTerminationTable
|
||||||
|
|||||||
26
netbox/core/tests/test_tables.py
Normal file
26
netbox/core/tests/test_tables.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
from core.models import ObjectChange
|
||||||
|
from core.tables import *
|
||||||
|
from utilities.testing import TableTestCases
|
||||||
|
|
||||||
|
|
||||||
|
class DataSourceTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = DataSourceTable
|
||||||
|
|
||||||
|
|
||||||
|
class DataFileTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = DataFileTable
|
||||||
|
|
||||||
|
|
||||||
|
class JobTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = JobTable
|
||||||
|
|
||||||
|
|
||||||
|
class ObjectChangeTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ObjectChangeTable
|
||||||
|
queryset_sources = [
|
||||||
|
('ObjectChangeListView', ObjectChange.objects.valid_models()),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigRevisionTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ConfigRevisionTable
|
||||||
204
netbox/dcim/tests/test_tables.py
Normal file
204
netbox/dcim/tests/test_tables.py
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
from dcim.models import ConsolePort, Interface, PowerPort
|
||||||
|
from dcim.tables import *
|
||||||
|
from utilities.testing import TableTestCases
|
||||||
|
|
||||||
|
#
|
||||||
|
# Sites
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
class RegionTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = RegionTable
|
||||||
|
|
||||||
|
|
||||||
|
class SiteGroupTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = SiteGroupTable
|
||||||
|
|
||||||
|
|
||||||
|
class SiteTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = SiteTable
|
||||||
|
|
||||||
|
|
||||||
|
class LocationTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = LocationTable
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Racks
|
||||||
|
#
|
||||||
|
|
||||||
|
class RackRoleTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = RackRoleTable
|
||||||
|
|
||||||
|
|
||||||
|
class RackTypeTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = RackTypeTable
|
||||||
|
|
||||||
|
|
||||||
|
class RackTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = RackTable
|
||||||
|
|
||||||
|
|
||||||
|
class RackReservationTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = RackReservationTable
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Device types
|
||||||
|
#
|
||||||
|
|
||||||
|
class ManufacturerTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ManufacturerTable
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceTypeTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = DeviceTypeTable
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Module types
|
||||||
|
#
|
||||||
|
|
||||||
|
class ModuleTypeProfileTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ModuleTypeProfileTable
|
||||||
|
|
||||||
|
|
||||||
|
class ModuleTypeTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ModuleTypeTable
|
||||||
|
|
||||||
|
|
||||||
|
class ModuleTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ModuleTable
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Devices
|
||||||
|
#
|
||||||
|
|
||||||
|
class DeviceRoleTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = DeviceRoleTable
|
||||||
|
|
||||||
|
|
||||||
|
class PlatformTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = PlatformTable
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = DeviceTable
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Device components
|
||||||
|
#
|
||||||
|
|
||||||
|
class ConsolePortTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ConsolePortTable
|
||||||
|
|
||||||
|
|
||||||
|
class ConsoleServerPortTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ConsoleServerPortTable
|
||||||
|
|
||||||
|
|
||||||
|
class PowerPortTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = PowerPortTable
|
||||||
|
|
||||||
|
|
||||||
|
class PowerOutletTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = PowerOutletTable
|
||||||
|
|
||||||
|
|
||||||
|
class InterfaceTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = InterfaceTable
|
||||||
|
|
||||||
|
|
||||||
|
class FrontPortTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = FrontPortTable
|
||||||
|
|
||||||
|
|
||||||
|
class RearPortTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = RearPortTable
|
||||||
|
|
||||||
|
|
||||||
|
class ModuleBayTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ModuleBayTable
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceBayTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = DeviceBayTable
|
||||||
|
|
||||||
|
|
||||||
|
class InventoryItemTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = InventoryItemTable
|
||||||
|
|
||||||
|
|
||||||
|
class InventoryItemRoleTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = InventoryItemRoleTable
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Connections
|
||||||
|
#
|
||||||
|
|
||||||
|
class ConsoleConnectionTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ConsoleConnectionTable
|
||||||
|
queryset_sources = [
|
||||||
|
('ConsoleConnectionsListView', ConsolePort.objects.filter(_path__is_complete=True)),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class PowerConnectionTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = PowerConnectionTable
|
||||||
|
queryset_sources = [
|
||||||
|
('PowerConnectionsListView', PowerPort.objects.filter(_path__is_complete=True)),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class InterfaceConnectionTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = InterfaceConnectionTable
|
||||||
|
queryset_sources = [
|
||||||
|
('InterfaceConnectionsListView', Interface.objects.filter(_path__is_complete=True)),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Cables
|
||||||
|
#
|
||||||
|
|
||||||
|
class CableTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = CableTable
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Power
|
||||||
|
#
|
||||||
|
|
||||||
|
class PowerPanelTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = PowerPanelTable
|
||||||
|
|
||||||
|
|
||||||
|
class PowerFeedTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = PowerFeedTable
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Virtual chassis
|
||||||
|
#
|
||||||
|
|
||||||
|
class VirtualChassisTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = VirtualChassisTable
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Virtual device contexts
|
||||||
|
#
|
||||||
|
|
||||||
|
class VirtualDeviceContextTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = VirtualDeviceContextTable
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# MAC addresses
|
||||||
|
#
|
||||||
|
|
||||||
|
class MACAddressTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = MACAddressTable
|
||||||
@@ -1,24 +1,84 @@
|
|||||||
from django.test import RequestFactory, TestCase, tag
|
from extras.models import Bookmark, Notification, Subscription
|
||||||
|
from extras.tables import *
|
||||||
from extras.models import EventRule
|
from utilities.testing import TableTestCases
|
||||||
from extras.tables import EventRuleTable
|
|
||||||
|
|
||||||
|
|
||||||
@tag('regression')
|
class CustomFieldTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
class EventRuleTableTest(TestCase):
|
table = CustomFieldTable
|
||||||
def test_every_orderable_field_does_not_throw_exception(self):
|
|
||||||
rule = EventRule.objects.all()
|
|
||||||
disallowed = {
|
|
||||||
'actions',
|
|
||||||
}
|
|
||||||
|
|
||||||
orderable_columns = [
|
|
||||||
column.name for column in EventRuleTable(rule).columns if column.orderable and column.name not in disallowed
|
|
||||||
]
|
|
||||||
fake_request = RequestFactory().get('/')
|
|
||||||
|
|
||||||
for col in orderable_columns:
|
class CustomFieldChoiceSetTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
for direction in ('-', ''):
|
table = CustomFieldChoiceSetTable
|
||||||
table = EventRuleTable(rule)
|
|
||||||
table.order_by = f'{direction}{col}'
|
|
||||||
table.as_html(fake_request)
|
class CustomLinkTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = CustomLinkTable
|
||||||
|
|
||||||
|
|
||||||
|
class ExportTemplateTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ExportTemplateTable
|
||||||
|
|
||||||
|
|
||||||
|
class SavedFilterTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = SavedFilterTable
|
||||||
|
|
||||||
|
|
||||||
|
class TableConfigTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = TableConfigTable
|
||||||
|
|
||||||
|
|
||||||
|
class BookmarkTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = BookmarkTable
|
||||||
|
queryset_sources = [
|
||||||
|
('BookmarkListView', Bookmark.objects.all()),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class NotificationGroupTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = NotificationGroupTable
|
||||||
|
|
||||||
|
|
||||||
|
class NotificationTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = NotificationTable
|
||||||
|
queryset_sources = [
|
||||||
|
('NotificationListView', Notification.objects.all()),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class SubscriptionTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = SubscriptionTable
|
||||||
|
queryset_sources = [
|
||||||
|
('SubscriptionListView', Subscription.objects.all()),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class WebhookTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = WebhookTable
|
||||||
|
|
||||||
|
|
||||||
|
class EventRuleTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = EventRuleTable
|
||||||
|
|
||||||
|
|
||||||
|
class TagTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = TagTable
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigContextProfileTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ConfigContextProfileTable
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigContextTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ConfigContextTable
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigTemplateTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ConfigTemplateTable
|
||||||
|
|
||||||
|
|
||||||
|
class ImageAttachmentTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ImageAttachmentTable
|
||||||
|
|
||||||
|
|
||||||
|
class JournalEntryTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = JournalEntryTable
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
from django.test import RequestFactory, TestCase
|
from django.test import RequestFactory, TestCase
|
||||||
from netaddr import IPNetwork
|
from netaddr import IPNetwork
|
||||||
|
|
||||||
from ipam.models import IPAddress, IPRange, Prefix
|
from ipam.models import FHRPGroupAssignment, IPAddress, IPRange, Prefix
|
||||||
from ipam.tables import AnnotatedIPAddressTable
|
from ipam.tables import *
|
||||||
from ipam.utils import annotate_ip_space
|
from ipam.utils import annotate_ip_space
|
||||||
|
from utilities.testing import TableTestCases
|
||||||
|
|
||||||
|
|
||||||
class AnnotatedIPAddressTableTest(TestCase):
|
class AnnotatedIPAddressTableTest(TestCase):
|
||||||
@@ -168,3 +169,82 @@ class AnnotatedIPAddressTableTest(TestCase):
|
|||||||
# Pools are fully usable
|
# Pools are fully usable
|
||||||
self.assertEqual(available.first_ip, '2001:db8:1::/126')
|
self.assertEqual(available.first_ip, '2001:db8:1::/126')
|
||||||
self.assertEqual(available.size, 4)
|
self.assertEqual(available.size, 4)
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Table ordering tests
|
||||||
|
#
|
||||||
|
|
||||||
|
class VRFTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = VRFTable
|
||||||
|
|
||||||
|
|
||||||
|
class RouteTargetTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = RouteTargetTable
|
||||||
|
|
||||||
|
|
||||||
|
class RIRTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = RIRTable
|
||||||
|
|
||||||
|
|
||||||
|
class AggregateTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = AggregateTable
|
||||||
|
|
||||||
|
|
||||||
|
class RoleTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = RoleTable
|
||||||
|
|
||||||
|
|
||||||
|
class PrefixTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = PrefixTable
|
||||||
|
|
||||||
|
|
||||||
|
class IPRangeTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = IPRangeTable
|
||||||
|
|
||||||
|
|
||||||
|
class IPAddressTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = IPAddressTable
|
||||||
|
|
||||||
|
|
||||||
|
class FHRPGroupTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = FHRPGroupTable
|
||||||
|
|
||||||
|
|
||||||
|
class FHRPGroupAssignmentTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = FHRPGroupAssignmentTable
|
||||||
|
queryset_sources = [
|
||||||
|
('FHRPGroupAssignmentTable', FHRPGroupAssignment.objects.all()),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class VLANGroupTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = VLANGroupTable
|
||||||
|
|
||||||
|
|
||||||
|
class VLANTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = VLANTable
|
||||||
|
|
||||||
|
|
||||||
|
class VLANTranslationPolicyTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = VLANTranslationPolicyTable
|
||||||
|
|
||||||
|
|
||||||
|
class VLANTranslationRuleTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = VLANTranslationRuleTable
|
||||||
|
|
||||||
|
|
||||||
|
class ASNRangeTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ASNRangeTable
|
||||||
|
|
||||||
|
|
||||||
|
class ASNTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ASNTable
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceTemplateTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ServiceTemplateTable
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ServiceTable
|
||||||
|
|||||||
26
netbox/tenancy/tests/test_tables.py
Normal file
26
netbox/tenancy/tests/test_tables.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
from tenancy.tables import *
|
||||||
|
from utilities.testing import TableTestCases
|
||||||
|
|
||||||
|
|
||||||
|
class TenantGroupTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = TenantGroupTable
|
||||||
|
|
||||||
|
|
||||||
|
class TenantTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = TenantTable
|
||||||
|
|
||||||
|
|
||||||
|
class ContactGroupTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ContactGroupTable
|
||||||
|
|
||||||
|
|
||||||
|
class ContactRoleTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ContactRoleTable
|
||||||
|
|
||||||
|
|
||||||
|
class ContactTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ContactTable
|
||||||
|
|
||||||
|
|
||||||
|
class ContactAssignmentTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ContactAssignmentTable
|
||||||
@@ -1,24 +1,26 @@
|
|||||||
from django.test import RequestFactory, TestCase, tag
|
from users.tables import *
|
||||||
|
from utilities.testing import TableTestCases
|
||||||
from users.models import Token
|
|
||||||
from users.tables import TokenTable
|
|
||||||
|
|
||||||
|
|
||||||
class TokenTableTest(TestCase):
|
class TokenTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
@tag('regression')
|
table = TokenTable
|
||||||
def test_every_orderable_field_does_not_throw_exception(self):
|
|
||||||
tokens = Token.objects.all()
|
|
||||||
disallowed = {'actions'}
|
|
||||||
|
|
||||||
orderable_columns = [
|
|
||||||
column.name for column in TokenTable(tokens).columns
|
|
||||||
if column.orderable and column.name not in disallowed
|
|
||||||
]
|
|
||||||
fake_request = RequestFactory().get("/")
|
|
||||||
|
|
||||||
for col in orderable_columns:
|
class UserTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
for direction in ('-', ''):
|
table = UserTable
|
||||||
with self.subTest(col=col, direction=direction):
|
|
||||||
table = TokenTable(tokens)
|
|
||||||
table.order_by = f'{direction}{col}'
|
class GroupTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
table.as_html(fake_request)
|
table = GroupTable
|
||||||
|
|
||||||
|
|
||||||
|
class ObjectPermissionTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ObjectPermissionTable
|
||||||
|
|
||||||
|
|
||||||
|
class OwnerGroupTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = OwnerGroupTable
|
||||||
|
|
||||||
|
|
||||||
|
class OwnerTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = OwnerTable
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from .api import *
|
from .api import *
|
||||||
from .base import *
|
from .base import *
|
||||||
from .filtersets import *
|
from .filtersets import *
|
||||||
|
from .tables import *
|
||||||
from .utils import *
|
from .utils import *
|
||||||
from .views import *
|
from .views import *
|
||||||
|
|||||||
130
netbox/utilities/testing/tables.py
Normal file
130
netbox/utilities/testing/tables.py
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
import inspect
|
||||||
|
from importlib import import_module
|
||||||
|
|
||||||
|
from django.test import RequestFactory
|
||||||
|
|
||||||
|
from netbox.views import generic
|
||||||
|
|
||||||
|
from .base import TestCase
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
"ModelTableTestCase",
|
||||||
|
"TableTestCases",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ModelTableTestCase(TestCase):
|
||||||
|
"""
|
||||||
|
Shared helpers for model-backed table tests.
|
||||||
|
|
||||||
|
Concrete subclasses should set `table` and may override `get_queryset()`
|
||||||
|
or `excluded_orderable_columns` as needed.
|
||||||
|
"""
|
||||||
|
table = None
|
||||||
|
excluded_orderable_columns = frozenset({"actions"})
|
||||||
|
|
||||||
|
# Optional explicit override for odd cases
|
||||||
|
queryset_sources = None
|
||||||
|
|
||||||
|
# Only these view types are considered sortable queryset sources by default
|
||||||
|
queryset_source_view_classes = (generic.ObjectListView,)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def validate_table_test_case(cls):
|
||||||
|
if cls.table is None:
|
||||||
|
raise AssertionError(f"{cls.__name__} must define `table`")
|
||||||
|
if getattr(cls.table._meta, "model", None) is None:
|
||||||
|
raise AssertionError(f"{cls.__name__}.table must be model-backed")
|
||||||
|
|
||||||
|
def get_request(self):
|
||||||
|
request = RequestFactory().get("/")
|
||||||
|
request.user = self.user
|
||||||
|
return request
|
||||||
|
|
||||||
|
def get_table(self, queryset):
|
||||||
|
return self.table(queryset)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def is_queryset_source_view(cls, view):
|
||||||
|
model = cls.table._meta.model
|
||||||
|
app_label = model._meta.app_label
|
||||||
|
|
||||||
|
return (
|
||||||
|
inspect.isclass(view)
|
||||||
|
and view.__module__.startswith(f"{app_label}.views")
|
||||||
|
and getattr(view, "table", None) is cls.table
|
||||||
|
and getattr(view, "queryset", None) is not None
|
||||||
|
and issubclass(view, cls.queryset_source_view_classes)
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_queryset_sources(cls):
|
||||||
|
"""
|
||||||
|
Return iterable of (label, queryset) pairs to test.
|
||||||
|
|
||||||
|
By default, only discover list-style views that declare this table.
|
||||||
|
That keeps bulk edit/delete confirmation tables out of the ordering
|
||||||
|
smoke test.
|
||||||
|
"""
|
||||||
|
if cls.queryset_sources is not None:
|
||||||
|
return tuple(cls.queryset_sources)
|
||||||
|
|
||||||
|
model = cls.table._meta.model
|
||||||
|
app_label = model._meta.app_label
|
||||||
|
module = import_module(f"{app_label}.views")
|
||||||
|
|
||||||
|
sources = []
|
||||||
|
for _, view in inspect.getmembers(module, inspect.isclass):
|
||||||
|
if not cls.is_queryset_source_view(view):
|
||||||
|
continue
|
||||||
|
|
||||||
|
queryset = view.queryset
|
||||||
|
if hasattr(queryset, "all"):
|
||||||
|
queryset = queryset.all()
|
||||||
|
|
||||||
|
sources.append((view.__name__, queryset))
|
||||||
|
|
||||||
|
if not sources:
|
||||||
|
raise AssertionError(
|
||||||
|
f"{cls.__name__} could not find any list-style queryset source for "
|
||||||
|
f"{cls.table.__module__}.{cls.table.__name__}; "
|
||||||
|
"set `queryset_sources` explicitly if needed."
|
||||||
|
)
|
||||||
|
|
||||||
|
return tuple(sources)
|
||||||
|
|
||||||
|
def iter_orderable_columns(self, queryset):
|
||||||
|
for column in self.get_table(queryset).columns:
|
||||||
|
if not column.orderable:
|
||||||
|
continue
|
||||||
|
if column.name in self.excluded_orderable_columns:
|
||||||
|
continue
|
||||||
|
yield column.name
|
||||||
|
|
||||||
|
|
||||||
|
class TableTestCases:
|
||||||
|
"""
|
||||||
|
Keep test_* methods nested to avoid unittest auto-discovering the reusable
|
||||||
|
base classes directly.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class OrderableColumnsTestCase(ModelTableTestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super().setUpClass()
|
||||||
|
cls.validate_table_test_case()
|
||||||
|
|
||||||
|
def test_every_orderable_column_renders(self):
|
||||||
|
request = self.get_request()
|
||||||
|
|
||||||
|
for source_name, queryset in self.get_queryset_sources():
|
||||||
|
for column_name in self.iter_orderable_columns(queryset):
|
||||||
|
for direction, prefix in (("asc", ""), ("desc", "-")):
|
||||||
|
with self.cleanupSubTest(
|
||||||
|
source=source_name,
|
||||||
|
column=column_name,
|
||||||
|
direction=direction,
|
||||||
|
):
|
||||||
|
table = self.get_table(queryset)
|
||||||
|
table.order_by = f"{prefix}{column_name}"
|
||||||
|
table.as_html(request)
|
||||||
26
netbox/virtualization/tests/test_tables.py
Normal file
26
netbox/virtualization/tests/test_tables.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
from utilities.testing import TableTestCases
|
||||||
|
from virtualization.tables import *
|
||||||
|
|
||||||
|
|
||||||
|
class ClusterTypeTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ClusterTypeTable
|
||||||
|
|
||||||
|
|
||||||
|
class ClusterGroupTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ClusterGroupTable
|
||||||
|
|
||||||
|
|
||||||
|
class ClusterTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = ClusterTable
|
||||||
|
|
||||||
|
|
||||||
|
class VirtualMachineTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = VirtualMachineTable
|
||||||
|
|
||||||
|
|
||||||
|
class VMInterfaceTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = VMInterfaceTable
|
||||||
|
|
||||||
|
|
||||||
|
class VirtualDiskTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = VirtualDiskTable
|
||||||
@@ -1,23 +1,42 @@
|
|||||||
from django.test import RequestFactory, TestCase, tag
|
from utilities.testing import TableTestCases
|
||||||
|
from vpn.tables import *
|
||||||
from vpn.models import TunnelTermination
|
|
||||||
from vpn.tables import TunnelTerminationTable
|
|
||||||
|
|
||||||
|
|
||||||
@tag('regression')
|
class TunnelGroupTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
class TunnelTerminationTableTest(TestCase):
|
table = TunnelGroupTable
|
||||||
def test_every_orderable_field_does_not_throw_exception(self):
|
|
||||||
terminations = TunnelTermination.objects.all()
|
|
||||||
fake_request = RequestFactory().get("/")
|
|
||||||
disallowed = {'actions'}
|
|
||||||
|
|
||||||
orderable_columns = [
|
|
||||||
column.name for column in TunnelTerminationTable(terminations).columns
|
|
||||||
if column.orderable and column.name not in disallowed
|
|
||||||
]
|
|
||||||
|
|
||||||
for col in orderable_columns:
|
class TunnelTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
for dir in ('-', ''):
|
table = TunnelTable
|
||||||
table = TunnelTerminationTable(terminations)
|
|
||||||
table.order_by = f'{dir}{col}'
|
|
||||||
table.as_html(fake_request)
|
class TunnelTerminationTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = TunnelTerminationTable
|
||||||
|
|
||||||
|
|
||||||
|
class IKEProposalTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = IKEProposalTable
|
||||||
|
|
||||||
|
|
||||||
|
class IKEPolicyTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = IKEPolicyTable
|
||||||
|
|
||||||
|
|
||||||
|
class IPSecProposalTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = IPSecProposalTable
|
||||||
|
|
||||||
|
|
||||||
|
class IPSecPolicyTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = IPSecPolicyTable
|
||||||
|
|
||||||
|
|
||||||
|
class IPSecProfileTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = IPSecProfileTable
|
||||||
|
|
||||||
|
|
||||||
|
class L2VPNTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = L2VPNTable
|
||||||
|
|
||||||
|
|
||||||
|
class L2VPNTerminationTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = L2VPNTerminationTable
|
||||||
|
|||||||
14
netbox/wireless/tests/test_tables.py
Normal file
14
netbox/wireless/tests/test_tables.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
from utilities.testing import TableTestCases
|
||||||
|
from wireless.tables import *
|
||||||
|
|
||||||
|
|
||||||
|
class WirelessLANGroupTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = WirelessLANGroupTable
|
||||||
|
|
||||||
|
|
||||||
|
class WirelessLANTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = WirelessLANTable
|
||||||
|
|
||||||
|
|
||||||
|
class WirelessLinkTableTest(TableTestCases.OrderableColumnsTestCase):
|
||||||
|
table = WirelessLinkTable
|
||||||
Reference in New Issue
Block a user