Files
Netbox-Utilities/netbox_utilities/tests/test_topology_views.py
T

159 lines
7.1 KiB
Python

from pathlib import Path
from types import SimpleNamespace
from unittest.mock import MagicMock, patch
from django.test import RequestFactory, SimpleTestCase
from netbox_utilities.topology_views import (
get_topology_rack_width_data,
is_topology_rack_elevation_request,
serialize_topology_placement,
topology_rack_width_enabled,
)
class TopologyViewsRackWidthTest(SimpleTestCase):
def setUp(self):
self.request = RequestFactory().get("/plugins/netbox_topology_views/rack-elevation/?rack_id=3")
self.request.user = MagicMock()
def test_detects_only_topology_rack_elevation_route(self):
self.request.resolver_match = SimpleNamespace(view_name="plugins:netbox_topology_views:rack_elevation")
self.assertTrue(is_topology_rack_elevation_request(self.request))
self.request.resolver_match = SimpleNamespace(view_name="dcim:rack_list")
self.assertFalse(is_topology_rack_elevation_request(self.request))
def test_skips_integration_when_optional_plugin_is_missing(self):
self.request.resolver_match = SimpleNamespace(view_name="plugins:netbox_topology_views:rack_elevation")
with (
patch("netbox_utilities.topology_views.apps.is_installed", return_value=False),
patch("netbox_utilities.topology_views.get_plugin_config", return_value=True),
):
self.assertFalse(topology_rack_width_enabled(self.request))
def test_skips_integration_when_admin_disabled_it(self):
self.request.resolver_match = SimpleNamespace(view_name="plugins:netbox_topology_views:rack_elevation")
with (
patch("netbox_utilities.topology_views.apps.is_installed", return_value=True),
patch("netbox_utilities.topology_views.get_plugin_config", return_value=False),
):
self.assertFalse(topology_rack_width_enabled(self.request))
def test_serializes_fractional_width_geometry_and_device_url(self):
placement = SimpleNamespace(
device_id=17,
device=SimpleNamespace(pk=17, get_absolute_url=lambda: "/dcim/devices/17/"),
width=3,
horizontal_position=2,
)
self.assertEqual(
serialize_topology_placement(placement),
{
"device_id": 17,
"url": "/dcim/devices/17/",
"width": 3,
"horizontal_position": 2,
"left_percent": 33.33333333,
"width_percent": 33.33333333,
"width_source": "stored",
},
)
@patch("netbox_utilities.topology_views.topology_rack_width_enabled", return_value=True)
def test_queries_all_permitted_devices_and_infers_shared_unit_widths(self, _enabled):
self.request.resolver_match = SimpleNamespace(view_name="plugins:netbox_topology_views:rack_elevation")
rack_queryset = MagicMock()
rack_queryset.filter.return_value = rack_queryset
rack_queryset.values.return_value = "selected-rack-query"
rack_model = MagicMock()
rack_model.objects.restrict.return_value = rack_queryset
device_queryset = MagicMock()
selected_devices = MagicMock()
device_queryset.filter.return_value = selected_devices
device_model = MagicMock()
device_model.objects.restrict.return_value = device_queryset
devices = [
SimpleNamespace(
pk=17,
rack_id=3,
face="front",
position=11,
device_type=SimpleNamespace(u_height=1),
netbox_utilities_rack_placement=None,
get_absolute_url=lambda: "/dcim/devices/17/",
),
SimpleNamespace(
pk=18,
rack_id=3,
face="front",
position=11,
device_type=SimpleNamespace(u_height=1),
netbox_utilities_rack_placement=None,
get_absolute_url=lambda: "/dcim/devices/18/",
),
]
selected_devices.select_related.return_value.order_by.return_value = devices
with patch.dict("sys.modules", {"dcim.models": SimpleNamespace(Device=device_model, Rack=rack_model)}):
result = get_topology_rack_width_data(self.request)
rack_queryset.filter.assert_called_once_with(pk__in=["3"])
device_queryset.filter.assert_called_once_with(
rack_id__in="selected-rack-query",
position__gt=0,
device_type__u_height__gt=0,
)
self.assertEqual(result["status"], "ready")
self.assertEqual(result["schema_version"], 3)
self.assertTrue(result["complete"])
self.assertEqual(len(result["devices"]), 2)
self.assertEqual(result["devices"][0]["width"], 2)
self.assertEqual(result["devices"][0]["horizontal_position"], 1)
self.assertEqual(result["devices"][1]["horizontal_position"], 2)
self.assertEqual(result["devices"][0]["width_source"], "inferred")
def test_frontend_supports_live_view_and_all_rack_export_formats(self):
script = (Path(__file__).parents[1] / "static" / "netbox_utilities" / "topology-rack-width.js").read_text(
encoding="utf-8"
)
self.assertIn("netbox-utilities-partial-width", script)
self.assertIn("horizontalGeometry", script)
self.assertIn("buildRackSvg", script)
self.assertIn("buildRackDrawio", script)
self.assertIn("format === 'svg'", script)
self.assertIn("format === 'drawio'", script)
self.assertIn("canvas.toBlob", script)
self.assertIn("event.stopImmediatePropagation()", script)
self.assertIn("rackExportCompatible", script)
self.assertIn("liveViewCompatible", script)
self.assertIn("payload?.devices", script)
self.assertIn("payload.status !== 'ready'", script)
self.assertIn("payload?.schema_version !== 3", script)
self.assertIn("placement.source", script)
self.assertLess(script.index("liveViewCompatible"), script.index("netbox-utilities-partial-width"))
self.assertLess(script.index("exportGraphic(graphic"), script.index("event.preventDefault()"))
@patch("netbox_utilities.topology_views.topology_rack_width_enabled", return_value=True)
def test_malformed_partial_placement_fails_open(self, _enabled):
self.request.resolver_match = SimpleNamespace(view_name="plugins:netbox_topology_views:rack_elevation")
with patch("dcim.models.Rack.objects.restrict", side_effect=AttributeError("stale")):
result = get_topology_rack_width_data(self.request)
self.assertEqual(result["status"], "native-fallback")
self.assertEqual(result["devices"], [])
self.assertFalse(result["complete"])
def test_partial_width_css_uses_topology_device_slot_geometry(self):
stylesheet = (Path(__file__).parents[1] / "static" / "netbox_utilities" / "netbox_utilities.css").read_text(
encoding="utf-8"
)
self.assertIn(".rack-device.netbox-utilities-partial-width", stylesheet)
self.assertIn("--netbox-utilities-rack-device-left", stylesheet)
self.assertIn("--netbox-utilities-rack-device-width", stylesheet)