mirror of
https://github.com/netbox-community/netbox.git
synced 2026-01-15 08:12:18 -06:00
Add initial cable path tests for profiles
This commit is contained in:
@@ -32,7 +32,7 @@ class BaseCableProfile:
|
|||||||
'Maximum B side connections for profile {profile}: {max}'
|
'Maximum B side connections for profile {profile}: {max}'
|
||||||
).format(
|
).format(
|
||||||
profile=cable.get_profile_display(),
|
profile=cable.get_profile_display(),
|
||||||
max=self.a_max_connections,
|
max=self.b_max_connections,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
if self.symmetrical and len(cable.a_terminations) != len(cable.b_terminations):
|
if self.symmetrical and len(cable.a_terminations) != len(cable.b_terminations):
|
||||||
|
|||||||
@@ -1,100 +1,21 @@
|
|||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
from circuits.models import *
|
from circuits.models import *
|
||||||
from dcim.choices import LinkStatusChoices
|
from dcim.choices import LinkStatusChoices
|
||||||
from dcim.models import *
|
from dcim.models import *
|
||||||
from dcim.svg import CableTraceSVG
|
from dcim.svg import CableTraceSVG
|
||||||
from dcim.utils import object_to_path_node
|
from dcim.tests.utils import CablePathTestCase
|
||||||
from utilities.exceptions import AbortRequest
|
from utilities.exceptions import AbortRequest
|
||||||
|
|
||||||
|
|
||||||
class CablePathTestCase(TestCase):
|
class LegacyCablePathTests(CablePathTestCase):
|
||||||
"""
|
"""
|
||||||
Test NetBox's ability to trace and retrace CablePaths in response to data model changes. Tests are numbered
|
Test NetBox's ability to trace and retrace CablePaths in response to data model changes, without cable profiles.
|
||||||
as follows:
|
|
||||||
|
|
||||||
|
Tests are numbered as follows:
|
||||||
1XX: Test direct connections between different endpoint types
|
1XX: Test direct connections between different endpoint types
|
||||||
2XX: Test different cable topologies
|
2XX: Test different cable topologies
|
||||||
3XX: Test responses to changes in existing objects
|
3XX: Test responses to changes in existing objects
|
||||||
4XX: Test to exclude specific cable topologies
|
4XX: Test to exclude specific cable topologies
|
||||||
"""
|
"""
|
||||||
@classmethod
|
|
||||||
def setUpTestData(cls):
|
|
||||||
|
|
||||||
# Create a single device that will hold all components
|
|
||||||
cls.site = Site.objects.create(name='Site', slug='site')
|
|
||||||
|
|
||||||
manufacturer = Manufacturer.objects.create(name='Generic', slug='generic')
|
|
||||||
device_type = DeviceType.objects.create(manufacturer=manufacturer, model='Test Device')
|
|
||||||
role = DeviceRole.objects.create(name='Device Role', slug='device-role')
|
|
||||||
cls.device = Device.objects.create(site=cls.site, device_type=device_type, role=role, name='Test Device')
|
|
||||||
|
|
||||||
cls.powerpanel = PowerPanel.objects.create(site=cls.site, name='Power Panel')
|
|
||||||
|
|
||||||
provider = Provider.objects.create(name='Provider', slug='provider')
|
|
||||||
circuit_type = CircuitType.objects.create(name='Circuit Type', slug='circuit-type')
|
|
||||||
cls.circuit = Circuit.objects.create(provider=provider, type=circuit_type, cid='Circuit 1')
|
|
||||||
|
|
||||||
def _get_cablepath(self, nodes, **kwargs):
|
|
||||||
"""
|
|
||||||
Return a given cable path
|
|
||||||
|
|
||||||
:param nodes: Iterable of steps, with each step being either a single node or a list of nodes
|
|
||||||
|
|
||||||
:return: The matching CablePath (if any)
|
|
||||||
"""
|
|
||||||
path = []
|
|
||||||
for step in nodes:
|
|
||||||
if type(step) in (list, tuple):
|
|
||||||
path.append([object_to_path_node(node) for node in step])
|
|
||||||
else:
|
|
||||||
path.append([object_to_path_node(step)])
|
|
||||||
return CablePath.objects.filter(path=path, **kwargs).first()
|
|
||||||
|
|
||||||
def assertPathExists(self, nodes, **kwargs):
|
|
||||||
"""
|
|
||||||
Assert that a CablePath from origin to destination with a specific intermediate path exists. Returns the
|
|
||||||
first matching CablePath, if found.
|
|
||||||
|
|
||||||
:param nodes: Iterable of steps, with each step being either a single node or a list of nodes
|
|
||||||
"""
|
|
||||||
cablepath = self._get_cablepath(nodes, **kwargs)
|
|
||||||
self.assertIsNotNone(cablepath, msg='CablePath not found')
|
|
||||||
|
|
||||||
return cablepath
|
|
||||||
|
|
||||||
def assertPathDoesNotExist(self, nodes, **kwargs):
|
|
||||||
"""
|
|
||||||
Assert that a specific CablePath does *not* exist.
|
|
||||||
|
|
||||||
:param nodes: Iterable of steps, with each step being either a single node or a list of nodes
|
|
||||||
"""
|
|
||||||
cablepath = self._get_cablepath(nodes, **kwargs)
|
|
||||||
self.assertIsNone(cablepath, msg='Unexpected CablePath found')
|
|
||||||
|
|
||||||
def assertPathIsSet(self, origin, cablepath, msg=None):
|
|
||||||
"""
|
|
||||||
Assert that a specific CablePath instance is set as the path on the origin.
|
|
||||||
|
|
||||||
:param origin: The originating path endpoint
|
|
||||||
:param cablepath: The CablePath instance originating from this endpoint
|
|
||||||
:param msg: Custom failure message (optional)
|
|
||||||
"""
|
|
||||||
if msg is None:
|
|
||||||
msg = f"Path #{cablepath.pk} not set on originating endpoint {origin}"
|
|
||||||
self.assertEqual(origin._path_id, cablepath.pk, msg=msg)
|
|
||||||
|
|
||||||
def assertPathIsNotSet(self, origin, msg=None):
|
|
||||||
"""
|
|
||||||
Assert that a specific CablePath instance is set as the path on the origin.
|
|
||||||
|
|
||||||
:param origin: The originating path endpoint
|
|
||||||
:param msg: Custom failure message (optional)
|
|
||||||
"""
|
|
||||||
if msg is None:
|
|
||||||
msg = f"Path #{origin._path_id} set as origin on {origin}; should be None!"
|
|
||||||
self.assertIsNone(origin._path_id, msg=msg)
|
|
||||||
|
|
||||||
def test_101_interface_to_interface(self):
|
def test_101_interface_to_interface(self):
|
||||||
"""
|
"""
|
||||||
[IF1] --C1-- [IF2]
|
[IF1] --C1-- [IF2]
|
||||||
|
|||||||
371
netbox/dcim/tests/test_cablepaths2.py
Normal file
371
netbox/dcim/tests/test_cablepaths2.py
Normal file
@@ -0,0 +1,371 @@
|
|||||||
|
from dcim.choices import CableProfileChoices
|
||||||
|
from dcim.models import *
|
||||||
|
from dcim.svg import CableTraceSVG
|
||||||
|
from dcim.tests.utils import CablePathTestCase
|
||||||
|
|
||||||
|
|
||||||
|
class CablePathTests(CablePathTestCase):
|
||||||
|
"""
|
||||||
|
Test the creation of CablePaths for Cables with different profiles applied.
|
||||||
|
|
||||||
|
Tests are numbered as follows:
|
||||||
|
1XX: Test direct connections using each profile
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_101_cable_profile_straight_single(self):
|
||||||
|
"""
|
||||||
|
[IF1] --C1-- [IF2]
|
||||||
|
|
||||||
|
Cable profile: Straight single
|
||||||
|
"""
|
||||||
|
interfaces = [
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 1'),
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 2'),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Create cable 1
|
||||||
|
cable1 = Cable(
|
||||||
|
profile=CableProfileChoices.STRAIGHT_SINGLE,
|
||||||
|
a_terminations=[interfaces[0]],
|
||||||
|
b_terminations=[interfaces[1]],
|
||||||
|
)
|
||||||
|
cable1.clean()
|
||||||
|
cable1.save()
|
||||||
|
|
||||||
|
path1 = self.assertPathExists(
|
||||||
|
(interfaces[0], cable1, interfaces[1]),
|
||||||
|
is_complete=True,
|
||||||
|
is_active=True
|
||||||
|
)
|
||||||
|
path2 = self.assertPathExists(
|
||||||
|
(interfaces[1], cable1, interfaces[0]),
|
||||||
|
is_complete=True,
|
||||||
|
is_active=True
|
||||||
|
)
|
||||||
|
self.assertEqual(CablePath.objects.count(), 2)
|
||||||
|
interfaces[0].refresh_from_db()
|
||||||
|
interfaces[1].refresh_from_db()
|
||||||
|
self.assertPathIsSet(interfaces[0], path1)
|
||||||
|
self.assertPathIsSet(interfaces[1], path2)
|
||||||
|
self.assertEqual(interfaces[0].cable_position, 1)
|
||||||
|
self.assertEqual(interfaces[1].cable_position, 1)
|
||||||
|
|
||||||
|
# Test SVG generation
|
||||||
|
CableTraceSVG(interfaces[0]).render()
|
||||||
|
|
||||||
|
# Delete cable 1
|
||||||
|
cable1.delete()
|
||||||
|
|
||||||
|
# Check that all CablePaths have been deleted
|
||||||
|
self.assertEqual(CablePath.objects.count(), 0)
|
||||||
|
|
||||||
|
def test_102_cable_profile_straight_multi(self):
|
||||||
|
"""
|
||||||
|
[IF1] --C1-- [IF3]
|
||||||
|
[IF2] [IF4]
|
||||||
|
|
||||||
|
Cable profile: Straight multi
|
||||||
|
"""
|
||||||
|
interfaces = [
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 1'),
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 2'),
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 3'),
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 4'),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Create cable 1
|
||||||
|
cable1 = Cable(
|
||||||
|
profile=CableProfileChoices.STRAIGHT_MULTI,
|
||||||
|
a_terminations=[interfaces[0], interfaces[1]],
|
||||||
|
b_terminations=[interfaces[2], interfaces[3]],
|
||||||
|
)
|
||||||
|
cable1.clean()
|
||||||
|
cable1.save()
|
||||||
|
|
||||||
|
path1 = self.assertPathExists(
|
||||||
|
(interfaces[0], cable1, interfaces[2]),
|
||||||
|
is_complete=True,
|
||||||
|
is_active=True
|
||||||
|
)
|
||||||
|
path2 = self.assertPathExists(
|
||||||
|
(interfaces[1], cable1, interfaces[3]),
|
||||||
|
is_complete=True,
|
||||||
|
is_active=True
|
||||||
|
)
|
||||||
|
path3 = self.assertPathExists(
|
||||||
|
(interfaces[2], cable1, interfaces[0]),
|
||||||
|
is_complete=True,
|
||||||
|
is_active=True
|
||||||
|
)
|
||||||
|
path4 = self.assertPathExists(
|
||||||
|
(interfaces[3], cable1, interfaces[1]),
|
||||||
|
is_complete=True,
|
||||||
|
is_active=True
|
||||||
|
)
|
||||||
|
self.assertEqual(CablePath.objects.count(), 4)
|
||||||
|
|
||||||
|
for interface in interfaces:
|
||||||
|
interface.refresh_from_db()
|
||||||
|
self.assertPathIsSet(interfaces[0], path1)
|
||||||
|
self.assertPathIsSet(interfaces[1], path2)
|
||||||
|
self.assertPathIsSet(interfaces[2], path3)
|
||||||
|
self.assertPathIsSet(interfaces[3], path4)
|
||||||
|
self.assertEqual(interfaces[0].cable_position, 1)
|
||||||
|
self.assertEqual(interfaces[1].cable_position, 2)
|
||||||
|
self.assertEqual(interfaces[2].cable_position, 1)
|
||||||
|
self.assertEqual(interfaces[3].cable_position, 2)
|
||||||
|
|
||||||
|
# Test SVG generation
|
||||||
|
CableTraceSVG(interfaces[0]).render()
|
||||||
|
|
||||||
|
# Delete cable 1
|
||||||
|
cable1.delete()
|
||||||
|
|
||||||
|
# Check that all CablePaths have been deleted
|
||||||
|
self.assertEqual(CablePath.objects.count(), 0)
|
||||||
|
|
||||||
|
def test_103_cable_profile_a_to_many(self):
|
||||||
|
"""
|
||||||
|
[IF1] --C1-- [IF2]
|
||||||
|
[IF3]
|
||||||
|
[IF4]
|
||||||
|
|
||||||
|
Cable profile: A to many
|
||||||
|
"""
|
||||||
|
interfaces = [
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 1'),
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 2'),
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 3'),
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 4'),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Create cable 1
|
||||||
|
cable1 = Cable(
|
||||||
|
profile=CableProfileChoices.A_TO_MANY,
|
||||||
|
a_terminations=[interfaces[0]],
|
||||||
|
b_terminations=[interfaces[1], interfaces[2], interfaces[3]],
|
||||||
|
)
|
||||||
|
cable1.clean()
|
||||||
|
cable1.save()
|
||||||
|
|
||||||
|
# A-to-B path leads to all interfaces
|
||||||
|
path1 = self.assertPathExists(
|
||||||
|
(interfaces[0], cable1, [interfaces[1], interfaces[2], interfaces[3]]),
|
||||||
|
is_complete=True,
|
||||||
|
is_active=True
|
||||||
|
)
|
||||||
|
# B-to-A paths are incomplete because A side has null position
|
||||||
|
path2 = self.assertPathExists(
|
||||||
|
(interfaces[1], cable1, []),
|
||||||
|
is_complete=False,
|
||||||
|
is_active=True
|
||||||
|
)
|
||||||
|
path3 = self.assertPathExists(
|
||||||
|
(interfaces[2], cable1, []),
|
||||||
|
is_complete=False,
|
||||||
|
is_active=True
|
||||||
|
)
|
||||||
|
path4 = self.assertPathExists(
|
||||||
|
(interfaces[3], cable1, []),
|
||||||
|
is_complete=False,
|
||||||
|
is_active=True
|
||||||
|
)
|
||||||
|
self.assertEqual(CablePath.objects.count(), 4)
|
||||||
|
|
||||||
|
for interface in interfaces:
|
||||||
|
interface.refresh_from_db()
|
||||||
|
self.assertPathIsSet(interfaces[0], path1)
|
||||||
|
self.assertPathIsSet(interfaces[1], path2)
|
||||||
|
self.assertPathIsSet(interfaces[2], path3)
|
||||||
|
self.assertPathIsSet(interfaces[3], path4)
|
||||||
|
self.assertIsNone(interfaces[0].cable_position)
|
||||||
|
self.assertEqual(interfaces[1].cable_position, 1)
|
||||||
|
self.assertEqual(interfaces[2].cable_position, 2)
|
||||||
|
self.assertEqual(interfaces[3].cable_position, 3)
|
||||||
|
|
||||||
|
# Test SVG generation
|
||||||
|
CableTraceSVG(interfaces[0]).render()
|
||||||
|
|
||||||
|
# Delete cable 1
|
||||||
|
cable1.delete()
|
||||||
|
|
||||||
|
# Check that all CablePaths have been deleted
|
||||||
|
self.assertEqual(CablePath.objects.count(), 0)
|
||||||
|
|
||||||
|
def test_104_cable_profile_b_to_many(self):
|
||||||
|
"""
|
||||||
|
[IF1] --C1-- [IF4]
|
||||||
|
[IF2]
|
||||||
|
[IF3]
|
||||||
|
|
||||||
|
Cable profile: B to many
|
||||||
|
"""
|
||||||
|
interfaces = [
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 1'),
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 2'),
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 3'),
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 4'),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Create cable 1
|
||||||
|
cable1 = Cable(
|
||||||
|
profile=CableProfileChoices.B_TO_MANY,
|
||||||
|
a_terminations=[interfaces[0], interfaces[1], interfaces[2]],
|
||||||
|
b_terminations=[interfaces[3]],
|
||||||
|
)
|
||||||
|
cable1.clean()
|
||||||
|
cable1.save()
|
||||||
|
|
||||||
|
# A-to-B paths are incomplete because A side has null position
|
||||||
|
path1 = self.assertPathExists(
|
||||||
|
(interfaces[0], cable1, []),
|
||||||
|
is_complete=False,
|
||||||
|
is_active=True
|
||||||
|
)
|
||||||
|
path2 = self.assertPathExists(
|
||||||
|
(interfaces[1], cable1, []),
|
||||||
|
is_complete=False,
|
||||||
|
is_active=True
|
||||||
|
)
|
||||||
|
path3 = self.assertPathExists(
|
||||||
|
(interfaces[2], cable1, []),
|
||||||
|
is_complete=False,
|
||||||
|
is_active=True
|
||||||
|
)
|
||||||
|
# B-to-A path leads to all interfaces
|
||||||
|
path4 = self.assertPathExists(
|
||||||
|
(interfaces[3], cable1, [interfaces[0], interfaces[1], interfaces[2]]),
|
||||||
|
is_complete=True,
|
||||||
|
is_active=True
|
||||||
|
)
|
||||||
|
self.assertEqual(CablePath.objects.count(), 4)
|
||||||
|
|
||||||
|
for interface in interfaces:
|
||||||
|
interface.refresh_from_db()
|
||||||
|
self.assertPathIsSet(interfaces[0], path1)
|
||||||
|
self.assertPathIsSet(interfaces[1], path2)
|
||||||
|
self.assertPathIsSet(interfaces[2], path3)
|
||||||
|
self.assertPathIsSet(interfaces[3], path4)
|
||||||
|
self.assertEqual(interfaces[0].cable_position, 1)
|
||||||
|
self.assertEqual(interfaces[1].cable_position, 2)
|
||||||
|
self.assertEqual(interfaces[2].cable_position, 3)
|
||||||
|
self.assertIsNone(interfaces[3].cable_position)
|
||||||
|
|
||||||
|
# Test SVG generation
|
||||||
|
CableTraceSVG(interfaces[0]).render()
|
||||||
|
|
||||||
|
# Delete cable 1
|
||||||
|
cable1.delete()
|
||||||
|
|
||||||
|
# Check that all CablePaths have been deleted
|
||||||
|
self.assertEqual(CablePath.objects.count(), 0)
|
||||||
|
|
||||||
|
def test_105_cable_profile_2x2_mpo(self):
|
||||||
|
"""
|
||||||
|
[IF1:1] --C1-- [IF3:1]
|
||||||
|
[IF1:2] [IF3:2]
|
||||||
|
[IF1:3] [IF3:3]
|
||||||
|
[IF1:4] [IF3:4]
|
||||||
|
[IF2:1] [IF4:1]
|
||||||
|
[IF2:2] [IF4:2]
|
||||||
|
[IF2:3] [IF4:3]
|
||||||
|
[IF2:4] [IF4:4]
|
||||||
|
|
||||||
|
Cable profile: Shuffle (2x2 MPO)
|
||||||
|
"""
|
||||||
|
interfaces = [
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 1:1'),
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 1:2'),
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 1:3'),
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 1:4'),
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 2:1'),
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 2:2'),
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 2:3'),
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 2:4'),
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 3:1'),
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 3:2'),
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 3:3'),
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 3:4'),
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 4:1'),
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 4:2'),
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 4:3'),
|
||||||
|
Interface.objects.create(device=self.device, name='Interface 4:4'),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Create cable 1
|
||||||
|
cable1 = Cable(
|
||||||
|
profile=CableProfileChoices.SHUFFLE_2X2_MPO,
|
||||||
|
a_terminations=interfaces[0:8],
|
||||||
|
b_terminations=interfaces[8:16],
|
||||||
|
)
|
||||||
|
cable1.clean()
|
||||||
|
cable1.save()
|
||||||
|
|
||||||
|
paths = [
|
||||||
|
# A-to-B paths
|
||||||
|
self.assertPathExists(
|
||||||
|
(interfaces[0], cable1, interfaces[8]), is_complete=True, is_active=True
|
||||||
|
),
|
||||||
|
self.assertPathExists(
|
||||||
|
(interfaces[1], cable1, interfaces[9]), is_complete=True, is_active=True
|
||||||
|
),
|
||||||
|
self.assertPathExists(
|
||||||
|
(interfaces[2], cable1, interfaces[12]), is_complete=True, is_active=True
|
||||||
|
),
|
||||||
|
self.assertPathExists(
|
||||||
|
(interfaces[3], cable1, interfaces[13]), is_complete=True, is_active=True
|
||||||
|
),
|
||||||
|
self.assertPathExists(
|
||||||
|
(interfaces[4], cable1, interfaces[10]), is_complete=True, is_active=True
|
||||||
|
),
|
||||||
|
self.assertPathExists(
|
||||||
|
(interfaces[5], cable1, interfaces[11]), is_complete=True, is_active=True
|
||||||
|
),
|
||||||
|
self.assertPathExists(
|
||||||
|
(interfaces[6], cable1, interfaces[14]), is_complete=True, is_active=True
|
||||||
|
),
|
||||||
|
self.assertPathExists(
|
||||||
|
(interfaces[7], cable1, interfaces[15]), is_complete=True, is_active=True
|
||||||
|
),
|
||||||
|
# B-to-A paths
|
||||||
|
self.assertPathExists(
|
||||||
|
(interfaces[8], cable1, interfaces[0]), is_complete=True, is_active=True
|
||||||
|
),
|
||||||
|
self.assertPathExists(
|
||||||
|
(interfaces[9], cable1, interfaces[1]), is_complete=True, is_active=True
|
||||||
|
),
|
||||||
|
self.assertPathExists(
|
||||||
|
(interfaces[10], cable1, interfaces[4]), is_complete=True, is_active=True
|
||||||
|
),
|
||||||
|
self.assertPathExists(
|
||||||
|
(interfaces[11], cable1, interfaces[5]), is_complete=True, is_active=True
|
||||||
|
),
|
||||||
|
self.assertPathExists(
|
||||||
|
(interfaces[12], cable1, interfaces[2]), is_complete=True, is_active=True
|
||||||
|
),
|
||||||
|
self.assertPathExists(
|
||||||
|
(interfaces[13], cable1, interfaces[3]), is_complete=True, is_active=True
|
||||||
|
),
|
||||||
|
self.assertPathExists(
|
||||||
|
(interfaces[14], cable1, interfaces[6]), is_complete=True, is_active=True
|
||||||
|
),
|
||||||
|
self.assertPathExists(
|
||||||
|
(interfaces[15], cable1, interfaces[7]), is_complete=True, is_active=True
|
||||||
|
),
|
||||||
|
]
|
||||||
|
self.assertEqual(CablePath.objects.count(), len(paths))
|
||||||
|
|
||||||
|
for i, (interface, path) in enumerate(zip(interfaces, paths)):
|
||||||
|
interface.refresh_from_db()
|
||||||
|
self.assertPathIsSet(interface, path)
|
||||||
|
self.assertEqual(interface.cable_end, 'A' if i < 8 else 'B')
|
||||||
|
self.assertEqual(interface.cable_position, (i % 8) + 1)
|
||||||
|
|
||||||
|
# Test SVG generation
|
||||||
|
CableTraceSVG(interfaces[0]).render()
|
||||||
|
|
||||||
|
# Delete cable 1
|
||||||
|
cable1.delete()
|
||||||
|
|
||||||
|
# Check that all CablePaths have been deleted
|
||||||
|
self.assertEqual(CablePath.objects.count(), 0)
|
||||||
88
netbox/dcim/tests/utils.py
Normal file
88
netbox/dcim/tests/utils.py
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from circuits.models import *
|
||||||
|
from dcim.models import *
|
||||||
|
from dcim.utils import object_to_path_node
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
'CablePathTestCase',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CablePathTestCase(TestCase):
|
||||||
|
"""
|
||||||
|
Base class for test cases for cable paths.
|
||||||
|
"""
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
manufacturer = Manufacturer.objects.create(name='Generic', slug='generic')
|
||||||
|
device_type = DeviceType.objects.create(manufacturer=manufacturer, model='Test Device')
|
||||||
|
role = DeviceRole.objects.create(name='Device Role', slug='device-role')
|
||||||
|
provider = Provider.objects.create(name='Provider', slug='provider')
|
||||||
|
circuit_type = CircuitType.objects.create(name='Circuit Type', slug='circuit-type')
|
||||||
|
|
||||||
|
# Create reusable test objects
|
||||||
|
cls.site = Site.objects.create(name='Site', slug='site')
|
||||||
|
cls.device = Device.objects.create(site=cls.site, device_type=device_type, role=role, name='Test Device')
|
||||||
|
cls.powerpanel = PowerPanel.objects.create(site=cls.site, name='Power Panel')
|
||||||
|
cls.circuit = Circuit.objects.create(provider=provider, type=circuit_type, cid='Circuit 1')
|
||||||
|
|
||||||
|
def _get_cablepath(self, nodes, **kwargs):
|
||||||
|
"""
|
||||||
|
Return a given cable path
|
||||||
|
|
||||||
|
:param nodes: Iterable of steps, with each step being either a single node or a list of nodes
|
||||||
|
|
||||||
|
:return: The matching CablePath (if any)
|
||||||
|
"""
|
||||||
|
path = []
|
||||||
|
for step in nodes:
|
||||||
|
if type(step) in (list, tuple):
|
||||||
|
path.append([object_to_path_node(node) for node in step])
|
||||||
|
else:
|
||||||
|
path.append([object_to_path_node(step)])
|
||||||
|
return CablePath.objects.filter(path=path, **kwargs).first()
|
||||||
|
|
||||||
|
def assertPathExists(self, nodes, **kwargs):
|
||||||
|
"""
|
||||||
|
Assert that a CablePath from origin to destination with a specific intermediate path exists. Returns the
|
||||||
|
first matching CablePath, if found.
|
||||||
|
|
||||||
|
:param nodes: Iterable of steps, with each step being either a single node or a list of nodes
|
||||||
|
"""
|
||||||
|
cablepath = self._get_cablepath(nodes, **kwargs)
|
||||||
|
self.assertIsNotNone(cablepath, msg='CablePath not found')
|
||||||
|
|
||||||
|
return cablepath
|
||||||
|
|
||||||
|
def assertPathDoesNotExist(self, nodes, **kwargs):
|
||||||
|
"""
|
||||||
|
Assert that a specific CablePath does *not* exist.
|
||||||
|
|
||||||
|
:param nodes: Iterable of steps, with each step being either a single node or a list of nodes
|
||||||
|
"""
|
||||||
|
cablepath = self._get_cablepath(nodes, **kwargs)
|
||||||
|
self.assertIsNone(cablepath, msg='Unexpected CablePath found')
|
||||||
|
|
||||||
|
def assertPathIsSet(self, origin, cablepath, msg=None):
|
||||||
|
"""
|
||||||
|
Assert that a specific CablePath instance is set as the path on the origin.
|
||||||
|
|
||||||
|
:param origin: The originating path endpoint
|
||||||
|
:param cablepath: The CablePath instance originating from this endpoint
|
||||||
|
:param msg: Custom failure message (optional)
|
||||||
|
"""
|
||||||
|
if msg is None:
|
||||||
|
msg = f"Path #{cablepath.pk} not set on originating endpoint {origin}"
|
||||||
|
self.assertEqual(origin._path_id, cablepath.pk, msg=msg)
|
||||||
|
|
||||||
|
def assertPathIsNotSet(self, origin, msg=None):
|
||||||
|
"""
|
||||||
|
Assert that a specific CablePath instance is set as the path on the origin.
|
||||||
|
|
||||||
|
:param origin: The originating path endpoint
|
||||||
|
:param msg: Custom failure message (optional)
|
||||||
|
"""
|
||||||
|
if msg is None:
|
||||||
|
msg = f"Path #{origin._path_id} set as origin on {origin}; should be None!"
|
||||||
|
self.assertIsNone(origin._path_id, msg=msg)
|
||||||
Reference in New Issue
Block a user