fix: prevent module component duplication during import
This commit is contained in:
@@ -5,7 +5,11 @@ import pytest
|
||||
from django.db import connection, models
|
||||
|
||||
from netbox_export.services import importer as importer_module
|
||||
from netbox_export.services.importer import _field_kwargs, _find_existing
|
||||
from netbox_export.services.importer import (
|
||||
_field_kwargs,
|
||||
_find_existing,
|
||||
_identity_lookup,
|
||||
)
|
||||
from netbox_export.services.plugin_compat import PluginCompatibility
|
||||
from netbox_export.services.references import ReferenceResolver
|
||||
|
||||
@@ -73,6 +77,27 @@ class RearPort(models.Model):
|
||||
]
|
||||
|
||||
|
||||
class Module(models.Model):
|
||||
class Meta:
|
||||
app_label = "dcim"
|
||||
|
||||
|
||||
class ModuleBay(models.Model):
|
||||
device = models.ForeignKey(Device, on_delete=models.CASCADE)
|
||||
module = models.ForeignKey(Module, on_delete=models.CASCADE)
|
||||
name = models.CharField(max_length=64)
|
||||
|
||||
class Meta:
|
||||
app_label = "dcim"
|
||||
|
||||
|
||||
class ModularRearPort(models.Model):
|
||||
module = models.ForeignKey(Module, on_delete=models.SET_NULL, null=True)
|
||||
|
||||
class Meta:
|
||||
app_label = "compat_tests"
|
||||
|
||||
|
||||
def tenant_record():
|
||||
return {
|
||||
"fields": {},
|
||||
@@ -132,6 +157,50 @@ def test_unresolved_relation_in_check_constraint_blocks_initial_save():
|
||||
assert missing_required == []
|
||||
|
||||
|
||||
def test_modular_component_waits_for_module_before_initial_save():
|
||||
resolver = ReferenceResolver({}, [], lambda label: None)
|
||||
record = {
|
||||
"fields": {},
|
||||
"relations": {"module": {"ref": "dcim.module:12"}},
|
||||
}
|
||||
|
||||
kwargs, unresolved, unresolved_values, missing_required = _field_kwargs(
|
||||
ModularRearPort,
|
||||
record,
|
||||
resolver,
|
||||
tenant_required=False,
|
||||
)
|
||||
|
||||
assert kwargs is None
|
||||
assert unresolved == []
|
||||
assert unresolved_values == []
|
||||
assert missing_required == []
|
||||
|
||||
|
||||
def test_module_bay_identity_includes_owning_module():
|
||||
device = Device(pk=210)
|
||||
module = Module(pk=12)
|
||||
resolver = ReferenceResolver(
|
||||
{
|
||||
"dcim.device:210": device,
|
||||
"dcim.module:12": module,
|
||||
},
|
||||
[],
|
||||
lambda label: None,
|
||||
)
|
||||
record = {
|
||||
"fields": {"name": "3-LC"},
|
||||
"relations": {
|
||||
"device": {"ref": "dcim.device:210"},
|
||||
"module": {"ref": "dcim.module:12"},
|
||||
},
|
||||
}
|
||||
|
||||
lookup = _identity_lookup(ModuleBay, record, resolver)
|
||||
|
||||
assert lookup == {"device": device, "module": module, "name": "3-LC"}
|
||||
|
||||
|
||||
def test_resolved_nullable_unique_relation_is_deferred():
|
||||
address = UniqueAddress(pk=50)
|
||||
resolver = ReferenceResolver(
|
||||
|
||||
@@ -7,6 +7,7 @@ from netbox_export.services.plugin_compat import (
|
||||
MISSING_TENANT_MESSAGE,
|
||||
PluginCompatibility,
|
||||
check_constraint_field_names,
|
||||
is_module_relation,
|
||||
is_tenant_relation,
|
||||
relation_required_before_save,
|
||||
relation_should_be_deferred,
|
||||
@@ -86,6 +87,27 @@ def test_identifies_tenant_relation():
|
||||
assert is_tenant_relation(relation_field("site", "dcim.site")) is False
|
||||
|
||||
|
||||
def test_identifies_module_component_relation():
|
||||
assert is_module_relation(relation_field("module", "dcim.module")) is True
|
||||
assert is_module_relation(relation_field("device", "dcim.device")) is False
|
||||
|
||||
|
||||
def test_new_module_disables_automatic_component_replication():
|
||||
module = SimpleNamespace(_meta=SimpleNamespace(label_lower="dcim.module"))
|
||||
|
||||
PluginCompatibility.prepare_initial_save(module, is_new=True)
|
||||
|
||||
assert module._disable_replication is True
|
||||
|
||||
|
||||
def test_existing_module_keeps_normal_save_behavior():
|
||||
module = SimpleNamespace(_meta=SimpleNamespace(label_lower="dcim.module"))
|
||||
|
||||
PluginCompatibility.prepare_initial_save(module, is_new=False)
|
||||
|
||||
assert not hasattr(module, "_disable_replication")
|
||||
|
||||
|
||||
def test_identifies_relations_used_by_check_constraint():
|
||||
constraint = models.CheckConstraint(
|
||||
condition=(
|
||||
|
||||
Reference in New Issue
Block a user