first commit
This commit is contained in:
205
netbox_librenms_plugin/tests/test_verify_views.py
Normal file
205
netbox_librenms_plugin/tests/test_verify_views.py
Normal file
@@ -0,0 +1,205 @@
|
||||
"""Tests for SingleCableVerifyView and SingleInterfaceVerifyView VC resolution.
|
||||
|
||||
Verifies that both views delegate VC device resolution to
|
||||
get_librenms_sync_device() and handle the None return gracefully
|
||||
(e.g. empty VC members or vc_position type errors).
|
||||
"""
|
||||
|
||||
import json
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
|
||||
def _make_request(body: dict) -> MagicMock:
|
||||
"""Create a mock POST request with JSON body."""
|
||||
request = MagicMock()
|
||||
request.body = json.dumps(body).encode()
|
||||
request.user.has_perm.return_value = True
|
||||
return request
|
||||
|
||||
|
||||
def _make_vc_device(pk=1, name="vc-device"):
|
||||
"""Create a mock Device that belongs to a virtual chassis."""
|
||||
device = MagicMock()
|
||||
device.pk = pk
|
||||
device.id = pk
|
||||
device.name = name
|
||||
device._meta.model_name = "device"
|
||||
device.virtual_chassis = MagicMock()
|
||||
device.interfaces.filter.return_value.first.return_value = None
|
||||
return device
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# SingleCableVerifyView
|
||||
# ---------------------------------------------------------------------------
|
||||
class TestSingleCableVerifyView:
|
||||
"""SingleCableVerifyView.post() VC resolution and None guard."""
|
||||
|
||||
def _make_view(self):
|
||||
from netbox_librenms_plugin.views.base.cables_view import SingleCableVerifyView
|
||||
|
||||
view = object.__new__(SingleCableVerifyView)
|
||||
view._librenms_api = MagicMock()
|
||||
return view
|
||||
|
||||
@patch("netbox_librenms_plugin.views.base.cables_view.get_object_or_404")
|
||||
@patch("netbox_librenms_plugin.views.base.cables_view.get_librenms_sync_device")
|
||||
@patch("netbox_librenms_plugin.views.base.cables_view.cache")
|
||||
def test_vc_no_resolvable_sync_device_returns_empty_row(self, mock_cache, mock_sync, mock_get_obj):
|
||||
"""VC where get_librenms_sync_device returns None → empty row, no crash."""
|
||||
device = _make_vc_device(pk=1)
|
||||
mock_get_obj.return_value = device
|
||||
mock_sync.return_value = None
|
||||
|
||||
view = self._make_view()
|
||||
request = _make_request({"device_id": 1, "local_port_id": "42"})
|
||||
response = view.post(request)
|
||||
|
||||
data = json.loads(response.content)
|
||||
assert data["status"] == "success"
|
||||
assert data["formatted_row"]["cable_status"] == "Missing Ports"
|
||||
mock_cache.get.assert_not_called()
|
||||
|
||||
@patch("netbox_librenms_plugin.views.base.cables_view.get_object_or_404")
|
||||
@patch("netbox_librenms_plugin.views.base.cables_view.get_librenms_sync_device")
|
||||
@patch("netbox_librenms_plugin.views.base.cables_view.cache")
|
||||
def test_vc_resolved_sync_device_uses_cache(self, mock_cache, mock_sync, mock_get_obj):
|
||||
"""VC with resolved sync device: cache is queried with that device's key."""
|
||||
device = _make_vc_device(pk=1)
|
||||
sync_device = _make_vc_device(pk=2, name="sync-device")
|
||||
mock_get_obj.return_value = device
|
||||
mock_sync.return_value = sync_device
|
||||
mock_cache.get.return_value = None # No cached data
|
||||
|
||||
view = self._make_view()
|
||||
request = _make_request({"device_id": 1, "local_port_id": "42"})
|
||||
view.post(request)
|
||||
|
||||
mock_sync.assert_called_once_with(device, server_key=view._librenms_api.server_key)
|
||||
mock_cache.get.assert_called_once()
|
||||
cache_key = mock_cache.get.call_args[0][0]
|
||||
assert "device" in cache_key
|
||||
assert "2" in cache_key
|
||||
|
||||
@patch("netbox_librenms_plugin.views.base.cables_view.get_object_or_404")
|
||||
@patch("netbox_librenms_plugin.views.base.cables_view.get_librenms_sync_device")
|
||||
@patch("netbox_librenms_plugin.views.base.cables_view.cache")
|
||||
def test_non_vc_device_skips_sync_device_lookup(self, mock_cache, mock_sync, mock_get_obj, mock_netbox_device):
|
||||
"""Non-VC device: get_librenms_sync_device is NOT called."""
|
||||
mock_netbox_device.virtual_chassis = None
|
||||
mock_get_obj.return_value = mock_netbox_device
|
||||
mock_cache.get.return_value = None
|
||||
|
||||
view = self._make_view()
|
||||
request = _make_request({"device_id": 5, "local_port_id": "10"})
|
||||
view.post(request)
|
||||
|
||||
mock_sync.assert_not_called()
|
||||
mock_cache.get.assert_called_once()
|
||||
|
||||
def test_no_device_id_returns_empty_row(self):
|
||||
"""Missing device_id: returns default empty formatted_row."""
|
||||
view = self._make_view()
|
||||
request = _make_request({"local_port_id": "42"})
|
||||
response = view.post(request)
|
||||
|
||||
data = json.loads(response.content)
|
||||
assert data["status"] == "success"
|
||||
assert data["formatted_row"]["cable_status"] == "Missing Ports"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# SingleInterfaceVerifyView
|
||||
# ---------------------------------------------------------------------------
|
||||
class TestSingleInterfaceVerifyView:
|
||||
"""SingleInterfaceVerifyView.post() VC resolution and None guard."""
|
||||
|
||||
def _make_view(self):
|
||||
from netbox_librenms_plugin.views.object_sync.devices import SingleInterfaceVerifyView
|
||||
|
||||
view = object.__new__(SingleInterfaceVerifyView)
|
||||
view._librenms_api = MagicMock()
|
||||
return view
|
||||
|
||||
@patch("netbox_librenms_plugin.views.object_sync.devices.get_object_or_404")
|
||||
@patch("netbox_librenms_plugin.views.object_sync.devices.get_librenms_sync_device")
|
||||
@patch("netbox_librenms_plugin.views.object_sync.devices.cache")
|
||||
def test_vc_no_resolvable_sync_device_returns_404(self, mock_cache, mock_sync, mock_get_obj):
|
||||
"""VC where get_librenms_sync_device returns None → 404 JSON error, no crash."""
|
||||
device = _make_vc_device(pk=1)
|
||||
mock_get_obj.return_value = device
|
||||
mock_sync.return_value = None
|
||||
|
||||
view = self._make_view()
|
||||
request = _make_request(
|
||||
{
|
||||
"device_id": 1,
|
||||
"interface_name": "eth0",
|
||||
"interface_name_field": "ifName",
|
||||
}
|
||||
)
|
||||
response = view.post(request)
|
||||
|
||||
assert response.status_code == 404
|
||||
data = json.loads(response.content)
|
||||
assert data["status"] == "error"
|
||||
assert "sync device" in data["message"].lower()
|
||||
mock_cache.get.assert_not_called()
|
||||
|
||||
@patch("netbox_librenms_plugin.views.object_sync.devices.get_object_or_404")
|
||||
@patch("netbox_librenms_plugin.views.object_sync.devices.get_librenms_sync_device")
|
||||
@patch("netbox_librenms_plugin.views.object_sync.devices.cache")
|
||||
def test_vc_resolved_sync_device_uses_cache(self, mock_cache, mock_sync, mock_get_obj):
|
||||
"""VC with resolved sync device: cache is queried with that device's key."""
|
||||
device = _make_vc_device(pk=1)
|
||||
sync_device = _make_vc_device(pk=3, name="sync-member")
|
||||
mock_get_obj.return_value = device
|
||||
mock_sync.return_value = sync_device
|
||||
mock_cache.get.return_value = None
|
||||
|
||||
view = self._make_view()
|
||||
request = _make_request(
|
||||
{
|
||||
"device_id": 1,
|
||||
"interface_name": "eth0",
|
||||
"interface_name_field": "ifName",
|
||||
}
|
||||
)
|
||||
view.post(request)
|
||||
|
||||
mock_sync.assert_called_once_with(device, server_key=view._librenms_api.server_key)
|
||||
mock_cache.get.assert_called_once()
|
||||
cache_key = mock_cache.get.call_args[0][0]
|
||||
assert "3" in cache_key
|
||||
|
||||
@patch("netbox_librenms_plugin.views.object_sync.devices.get_object_or_404")
|
||||
@patch("netbox_librenms_plugin.views.object_sync.devices.get_librenms_sync_device")
|
||||
@patch("netbox_librenms_plugin.views.object_sync.devices.cache")
|
||||
def test_non_vc_device_skips_sync_device_lookup(self, mock_cache, mock_sync, mock_get_obj, mock_netbox_device):
|
||||
"""Non-VC device: get_librenms_sync_device is NOT called."""
|
||||
mock_netbox_device.virtual_chassis = None
|
||||
mock_get_obj.return_value = mock_netbox_device
|
||||
mock_cache.get.return_value = None
|
||||
|
||||
view = self._make_view()
|
||||
request = _make_request(
|
||||
{
|
||||
"device_id": 5,
|
||||
"interface_name": "eth0",
|
||||
"interface_name_field": "ifName",
|
||||
}
|
||||
)
|
||||
view.post(request)
|
||||
|
||||
mock_sync.assert_not_called()
|
||||
mock_cache.get.assert_called_once()
|
||||
|
||||
def test_no_device_id_returns_400(self):
|
||||
"""Missing device_id: returns 400 error."""
|
||||
view = self._make_view()
|
||||
request = _make_request({"interface_name": "eth0"})
|
||||
response = view.post(request)
|
||||
|
||||
assert response.status_code == 400
|
||||
data = json.loads(response.content)
|
||||
assert data["status"] == "error"
|
||||
Reference in New Issue
Block a user