first commit
This commit is contained in:
368
netbox_librenms_plugin/tests/test_import_validation_helpers.py
Normal file
368
netbox_librenms_plugin/tests/test_import_validation_helpers.py
Normal file
@@ -0,0 +1,368 @@
|
||||
"""
|
||||
Tests for netbox_librenms_plugin.import_validation_helpers module.
|
||||
|
||||
Phase 2 tests covering validation state updates, model retrieval,
|
||||
and selection extraction functions.
|
||||
"""
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
# =============================================================================
|
||||
# TestGetModelById - 4 tests
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class TestFetchModelById:
|
||||
"""Test generic model retrieval helper."""
|
||||
|
||||
def test_fetch_model_by_id_success(self):
|
||||
"""Return model instance when found."""
|
||||
mock_model_class = MagicMock()
|
||||
mock_instance = MagicMock(id=1, name="Access Switch")
|
||||
mock_model_class.objects.get.return_value = mock_instance
|
||||
|
||||
from netbox_librenms_plugin.import_validation_helpers import fetch_model_by_id
|
||||
|
||||
result = fetch_model_by_id(mock_model_class, 1)
|
||||
|
||||
assert result == mock_instance
|
||||
mock_model_class.objects.get.assert_called_once_with(pk=1)
|
||||
|
||||
def test_fetch_model_by_id_not_found(self):
|
||||
"""Return None when ID doesn't exist."""
|
||||
mock_model_class = MagicMock()
|
||||
mock_model_class.DoesNotExist = Exception
|
||||
mock_model_class.objects.get.side_effect = mock_model_class.DoesNotExist
|
||||
|
||||
from netbox_librenms_plugin.import_validation_helpers import fetch_model_by_id
|
||||
|
||||
result = fetch_model_by_id(mock_model_class, 999)
|
||||
|
||||
assert result is None
|
||||
|
||||
def test_fetch_model_by_id_invalid_id(self):
|
||||
"""Handle invalid ID gracefully."""
|
||||
mock_model_class = MagicMock()
|
||||
mock_model_class.DoesNotExist = type("DoesNotExist", (Exception,), {})
|
||||
|
||||
from netbox_librenms_plugin.import_validation_helpers import fetch_model_by_id
|
||||
|
||||
result = fetch_model_by_id(mock_model_class, "not-a-number")
|
||||
|
||||
assert result is None
|
||||
|
||||
def test_fetch_model_by_id_none_id(self):
|
||||
"""Handle None ID gracefully."""
|
||||
mock_model_class = MagicMock()
|
||||
|
||||
from netbox_librenms_plugin.import_validation_helpers import fetch_model_by_id
|
||||
|
||||
result = fetch_model_by_id(mock_model_class, None)
|
||||
|
||||
assert result is None
|
||||
mock_model_class.objects.get.assert_not_called()
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# TestExtractSelections - 4 tests
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class TestExtractDeviceSelections:
|
||||
"""Test extraction of device selections from request."""
|
||||
|
||||
def test_extract_selections_all_present(self):
|
||||
"""All selections extracted from POST request."""
|
||||
from netbox_librenms_plugin.import_validation_helpers import (
|
||||
extract_device_selections,
|
||||
)
|
||||
|
||||
mock_request = MagicMock()
|
||||
mock_request.method = "POST"
|
||||
mock_request.POST = {
|
||||
"cluster_1234": "5",
|
||||
"role_1234": "10",
|
||||
"rack_1234": "15",
|
||||
}
|
||||
|
||||
result = extract_device_selections(mock_request, device_id=1234)
|
||||
|
||||
assert result["cluster_id"] == "5"
|
||||
assert result["role_id"] == "10"
|
||||
assert result["rack_id"] == "15"
|
||||
|
||||
def test_extract_selections_partial(self):
|
||||
"""Missing fields return None."""
|
||||
from netbox_librenms_plugin.import_validation_helpers import (
|
||||
extract_device_selections,
|
||||
)
|
||||
|
||||
mock_request = MagicMock()
|
||||
mock_request.method = "POST"
|
||||
mock_request.POST = {
|
||||
"role_1234": "10",
|
||||
}
|
||||
|
||||
result = extract_device_selections(mock_request, device_id=1234)
|
||||
|
||||
assert result["cluster_id"] is None
|
||||
assert result["role_id"] == "10"
|
||||
assert result["rack_id"] is None
|
||||
|
||||
def test_extract_selections_from_get(self):
|
||||
"""Selections extracted from GET request."""
|
||||
from netbox_librenms_plugin.import_validation_helpers import (
|
||||
extract_device_selections,
|
||||
)
|
||||
|
||||
mock_request = MagicMock()
|
||||
mock_request.method = "GET"
|
||||
mock_request.GET = {
|
||||
"cluster_999": "3",
|
||||
"role_999": "7",
|
||||
"rack_999": "11",
|
||||
}
|
||||
|
||||
result = extract_device_selections(mock_request, device_id=999)
|
||||
|
||||
assert result["cluster_id"] == "3"
|
||||
assert result["role_id"] == "7"
|
||||
assert result["rack_id"] == "11"
|
||||
|
||||
def test_extract_selections_empty_values(self):
|
||||
"""Empty strings handled correctly."""
|
||||
from netbox_librenms_plugin.import_validation_helpers import (
|
||||
extract_device_selections,
|
||||
)
|
||||
|
||||
mock_request = MagicMock()
|
||||
mock_request.method = "POST"
|
||||
mock_request.POST = {
|
||||
"cluster_1234": "",
|
||||
"role_1234": "",
|
||||
"rack_1234": "",
|
||||
}
|
||||
|
||||
result = extract_device_selections(mock_request, device_id=1234)
|
||||
|
||||
# Empty strings are returned as-is (caller decides meaning)
|
||||
assert result["cluster_id"] == ""
|
||||
assert result["role_id"] == ""
|
||||
assert result["rack_id"] == ""
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# TestValidationStateUpdates - 10 tests
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class TestValidationStateUpdates:
|
||||
"""Test validation state mutation functions."""
|
||||
|
||||
def test_apply_role_to_validation_success(self):
|
||||
"""Role selection updates state correctly."""
|
||||
from netbox_librenms_plugin.import_validation_helpers import (
|
||||
apply_role_to_validation,
|
||||
)
|
||||
|
||||
mock_role = MagicMock(id=1, name="Access Switch")
|
||||
validation = {
|
||||
"device_role": {"found": False, "role": None},
|
||||
"issues": ["Device role must be manually selected before import"],
|
||||
"can_import": False,
|
||||
"is_ready": False,
|
||||
"site": {"found": True},
|
||||
"device_type": {"found": True},
|
||||
}
|
||||
|
||||
apply_role_to_validation(validation, mock_role, is_vm=False)
|
||||
|
||||
assert validation["device_role"]["found"] is True
|
||||
assert validation["device_role"]["role"] == mock_role
|
||||
|
||||
def test_apply_role_to_validation_clears_issue(self):
|
||||
"""Selecting role should clear 'role' related validation issue."""
|
||||
from netbox_librenms_plugin.import_validation_helpers import (
|
||||
apply_role_to_validation,
|
||||
)
|
||||
|
||||
mock_role = MagicMock(id=1, name="Access Switch")
|
||||
validation = {
|
||||
"device_role": {"found": False, "role": None},
|
||||
"issues": ["Device role must be manually selected before import"],
|
||||
"can_import": False,
|
||||
"is_ready": False,
|
||||
"site": {"found": True},
|
||||
"device_type": {"found": True},
|
||||
}
|
||||
|
||||
apply_role_to_validation(validation, mock_role, is_vm=False)
|
||||
|
||||
assert len(validation["issues"]) == 0
|
||||
|
||||
def test_apply_cluster_to_validation_success(self):
|
||||
"""Cluster selection updates state for VM import."""
|
||||
from netbox_librenms_plugin.import_validation_helpers import (
|
||||
apply_cluster_to_validation,
|
||||
)
|
||||
|
||||
mock_cluster = MagicMock(id=1, name="VMware Cluster 1")
|
||||
validation = {
|
||||
"cluster": {"found": False, "cluster": None},
|
||||
"issues": ["Cluster must be manually selected before import"],
|
||||
"can_import": False,
|
||||
"is_ready": False,
|
||||
}
|
||||
|
||||
apply_cluster_to_validation(validation, mock_cluster)
|
||||
|
||||
assert validation["cluster"]["found"] is True
|
||||
assert validation["cluster"]["cluster"] == mock_cluster
|
||||
|
||||
def test_apply_rack_to_validation_success(self):
|
||||
"""Rack selection updates state for device import."""
|
||||
from netbox_librenms_plugin.import_validation_helpers import (
|
||||
apply_rack_to_validation,
|
||||
)
|
||||
|
||||
mock_rack = MagicMock(id=1, name="Rack A1")
|
||||
validation = {
|
||||
"issues": [],
|
||||
"can_import": True,
|
||||
"is_ready": True,
|
||||
}
|
||||
|
||||
apply_rack_to_validation(validation, mock_rack)
|
||||
|
||||
assert validation["rack"]["found"] is True
|
||||
assert validation["rack"]["rack"] == mock_rack
|
||||
|
||||
def test_remove_validation_issue_single(self):
|
||||
"""Remove single issue by keyword."""
|
||||
from netbox_librenms_plugin.import_validation_helpers import (
|
||||
remove_validation_issue,
|
||||
)
|
||||
|
||||
validation = {
|
||||
"issues": [
|
||||
"Device role must be manually selected before import",
|
||||
"Site not found for location 'DC1'",
|
||||
]
|
||||
}
|
||||
|
||||
remove_validation_issue(validation, "role")
|
||||
|
||||
assert len(validation["issues"]) == 1
|
||||
assert "Site not found" in validation["issues"][0]
|
||||
|
||||
def test_remove_validation_issue_multiple(self):
|
||||
"""Remove multiple matching issues."""
|
||||
from netbox_librenms_plugin.import_validation_helpers import (
|
||||
remove_validation_issue,
|
||||
)
|
||||
|
||||
validation = {
|
||||
"issues": [
|
||||
"Device role must be selected",
|
||||
"Role is required for import",
|
||||
"Site not found",
|
||||
]
|
||||
}
|
||||
|
||||
remove_validation_issue(validation, "role")
|
||||
|
||||
assert len(validation["issues"]) == 1
|
||||
assert "Site not found" in validation["issues"][0]
|
||||
|
||||
def test_remove_validation_issue_no_match(self):
|
||||
"""No change when keyword not found."""
|
||||
from netbox_librenms_plugin.import_validation_helpers import (
|
||||
remove_validation_issue,
|
||||
)
|
||||
|
||||
validation = {
|
||||
"issues": [
|
||||
"Site not found for location 'DC1'",
|
||||
"Device type not matched",
|
||||
]
|
||||
}
|
||||
|
||||
remove_validation_issue(validation, "cluster")
|
||||
|
||||
assert len(validation["issues"]) == 2
|
||||
|
||||
def test_recalculate_can_import_all_ready_device(self):
|
||||
"""can_import=True when all requirements met for device."""
|
||||
from netbox_librenms_plugin.import_validation_helpers import (
|
||||
recalculate_validation_status,
|
||||
)
|
||||
|
||||
validation = {
|
||||
"issues": [],
|
||||
"can_import": False,
|
||||
"is_ready": False,
|
||||
"site": {"found": True},
|
||||
"device_type": {"found": True},
|
||||
"device_role": {"found": True},
|
||||
}
|
||||
|
||||
recalculate_validation_status(validation, is_vm=False)
|
||||
|
||||
assert validation["can_import"] is True
|
||||
assert validation["is_ready"] is True
|
||||
|
||||
def test_recalculate_can_import_missing_required_device(self):
|
||||
"""can_import=False when required field missing for device."""
|
||||
from netbox_librenms_plugin.import_validation_helpers import (
|
||||
recalculate_validation_status,
|
||||
)
|
||||
|
||||
validation = {
|
||||
"issues": ["Site not found"],
|
||||
"can_import": True, # Should become False
|
||||
"is_ready": True,
|
||||
"site": {"found": False},
|
||||
"device_type": {"found": True},
|
||||
"device_role": {"found": True},
|
||||
}
|
||||
|
||||
recalculate_validation_status(validation, is_vm=False)
|
||||
|
||||
assert validation["can_import"] is False
|
||||
assert validation["is_ready"] is False
|
||||
|
||||
def test_recalculate_can_import_vm_cluster_required(self):
|
||||
"""VM import requires cluster to be ready."""
|
||||
from netbox_librenms_plugin.import_validation_helpers import (
|
||||
recalculate_validation_status,
|
||||
)
|
||||
|
||||
validation = {
|
||||
"issues": [],
|
||||
"can_import": False,
|
||||
"is_ready": False,
|
||||
"cluster": {"found": True},
|
||||
}
|
||||
|
||||
recalculate_validation_status(validation, is_vm=True)
|
||||
|
||||
assert validation["can_import"] is True
|
||||
assert validation["is_ready"] is True
|
||||
|
||||
def test_recalculate_can_import_vm_missing_cluster(self):
|
||||
"""VM import not ready without cluster."""
|
||||
from netbox_librenms_plugin.import_validation_helpers import (
|
||||
recalculate_validation_status,
|
||||
)
|
||||
|
||||
validation = {
|
||||
"issues": [],
|
||||
"can_import": False,
|
||||
"is_ready": False,
|
||||
"cluster": {"found": False},
|
||||
}
|
||||
|
||||
recalculate_validation_status(validation, is_vm=True)
|
||||
|
||||
assert validation["can_import"] is True # No issues
|
||||
assert validation["is_ready"] is False # But not ready without cluster
|
||||
Reference in New Issue
Block a user