fix: preserve cable paths across export and import
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from netbox_export.services import importer
|
||||
from netbox_export.services.importer import (
|
||||
_rebuild_imported_cable_paths,
|
||||
_release_port_mapping_conflicts,
|
||||
)
|
||||
|
||||
|
||||
class FakeQuerySet(list):
|
||||
def exclude(self, **kwargs):
|
||||
return FakeQuerySet(item for item in self if item.pk != kwargs["pk"])
|
||||
|
||||
def order_by(self, *args):
|
||||
return self
|
||||
|
||||
|
||||
class FakeManager:
|
||||
def __init__(self, objects):
|
||||
self.objects = FakeQuerySet(objects)
|
||||
self.filters = []
|
||||
|
||||
def select_for_update(self):
|
||||
return self
|
||||
|
||||
def filter(self, *args, **kwargs):
|
||||
self.filters.append((args, kwargs))
|
||||
return FakeQuerySet(self.objects)
|
||||
|
||||
|
||||
def test_port_mapping_conflicts_are_replaced_before_save():
|
||||
deleted = []
|
||||
conflict = SimpleNamespace(pk=12, delete=lambda: deleted.append(12))
|
||||
|
||||
class PortMapping:
|
||||
_meta = SimpleNamespace(label_lower="dcim.portmapping")
|
||||
_default_manager = FakeManager([conflict])
|
||||
|
||||
mapping = PortMapping()
|
||||
mapping.pk = 11
|
||||
mapping.front_port_id = 21
|
||||
mapping.front_port_position = 1
|
||||
mapping.rear_port_id = 31
|
||||
mapping.rear_port_position = 1
|
||||
resolver = SimpleNamespace(warn=MagicMock())
|
||||
|
||||
_release_port_mapping_conflicts(mapping, resolver, "dcim.portmapping:99")
|
||||
|
||||
assert deleted == [12]
|
||||
resolver.warn.assert_called_once()
|
||||
assert "Front-/Rear-Port-Verkabelung" in resolver.warn.call_args.args[1]
|
||||
|
||||
|
||||
def test_imported_cable_terminations_trigger_netbox_path_rebuild(monkeypatch):
|
||||
cables = [SimpleNamespace(pk=7), SimpleNamespace(pk=9)]
|
||||
|
||||
class Cable:
|
||||
_default_manager = FakeManager(cables)
|
||||
|
||||
trace_paths = SimpleNamespace(send=MagicMock())
|
||||
monkeypatch.setattr(importer, "_model_for", lambda label: Cable)
|
||||
monkeypatch.setattr(importer, "_trace_paths_signal", lambda: trace_paths)
|
||||
records = {
|
||||
"dcim.cabletermination:1": {"model": "dcim.cabletermination"},
|
||||
"dcim.cabletermination:2": {"model": "dcim.cabletermination"},
|
||||
"dcim.device:3": {"model": "dcim.device"},
|
||||
}
|
||||
resolved = {
|
||||
"dcim.cabletermination:1": SimpleNamespace(cable_id=7),
|
||||
"dcim.cabletermination:2": SimpleNamespace(cable_id=9),
|
||||
"dcim.device:3": object(),
|
||||
}
|
||||
|
||||
_rebuild_imported_cable_paths(records, resolved)
|
||||
|
||||
assert all(cable._terminations_modified is True for cable in cables)
|
||||
assert trace_paths.send.call_count == 2
|
||||
trace_paths.send.assert_any_call(Cable, instance=cables[0], created=False)
|
||||
trace_paths.send.assert_any_call(Cable, instance=cables[1], created=False)
|
||||
@@ -43,10 +43,29 @@ class PrivateGraphModel(models.Model):
|
||||
app_label = "graph_tests"
|
||||
|
||||
|
||||
class PortMapping(models.Model):
|
||||
_netbox_private = True
|
||||
|
||||
class Meta:
|
||||
app_label = "dcim"
|
||||
|
||||
|
||||
class CablePath(models.Model):
|
||||
_netbox_private = True
|
||||
|
||||
class Meta:
|
||||
app_label = "dcim"
|
||||
|
||||
|
||||
def test_private_plugin_models_are_not_exportable():
|
||||
assert graph_module.is_exportable_model(PrivateGraphModel) is False
|
||||
|
||||
|
||||
def test_private_port_mappings_are_exported_but_cable_paths_are_not():
|
||||
assert graph_module.is_exportable_model(PortMapping) is True
|
||||
assert graph_module.is_exportable_model(CablePath) is False
|
||||
|
||||
|
||||
def test_batched_graph_collects_members_and_dependencies(monkeypatch):
|
||||
graph_models = (GraphParent, GraphReference, GraphChild, GraphDetail)
|
||||
with connection.schema_editor() as schema_editor:
|
||||
|
||||
Reference in New Issue
Block a user