Upgrade models to full NetboxModel to allow UI/API interaction:

modified:   netbox_dns_bridge/models.py
deleted:    netbox_dns_bridge/migrations/0003_catalogzone_and_per_zone_identifier.py
new file:   netbox_dns_bridge/migrations/0003_full_netbox_models.py

Adjust model access and function calls to match new models:
modified:   netbox_dns_bridge/signals/netbox_dns_zones.py
modified:   netbox_dns_bridge/management/commands/dns_transfer_endpoint/catalog_zone_manager.py
modified:   netbox_dns_bridge/management/commands/dns_transfer_endpoint/request_handler.py

Update UI elements and permission interactions:
modified:   netbox_dns_bridge/filtersets.py
modified:   netbox_dns_bridge/forms.py
modified:   netbox_dns_bridge/jobs/notify.py
modified:   netbox_dns_bridge/navigation.py
modified:   netbox_dns_bridge/tables.py
deleted:    netbox_dns_bridge/templates/netbox_dns_bridge/catalog_zone_members.html
new file:   netbox_dns_bridge/templates/netbox_dns_bridge/catalogzone.html
new file:   netbox_dns_bridge/templates/netbox_dns_bridge/catalogzonemember.html
deleted:    netbox_dns_bridge/templates/netbox_dns_bridge/notify_overview.html
new file:   netbox_dns_bridge/templates/netbox_dns_bridge/seentransferclient.html
modified:   netbox_dns_bridge/urls.py
modified:   netbox_dns_bridge/views.py

AI/LLM updated tests (Not verified):
modified:   netbox_dns_bridge/tests/conftest.py
modified:   netbox_dns_bridge/tests/test_catalog_zone_manager.py
modified:   netbox_dns_bridge/tests/test_models.py
modified:   netbox_dns_bridge/tests/test_notify.py
modified:   netbox_dns_bridge/tests/test_request_handler_integration.py
modified:   netbox_dns_bridge/tests/test_signals.py
modified:   netbox_dns_bridge/tests/test_smoke.py
modified:   netbox_dns_bridge/tests/test_views.py
This commit is contained in:
sven committed 2026-08-17 17:05:25 +02:00
1 parent 14805ed32b
commit 1c51206196
26 files changed
+813 -451

No files matched your search

+49 -27
View File
@@ -3,8 +3,8 @@ import pytest
from netbox_dns_bridge.models import (
CatalogZone,
CatalogZoneMemberIdentifier,
SeenTransferClients,
CatalogZoneMember,
SeenTransferClient,
)
@@ -42,6 +42,15 @@ class TestCatalogZone:
assert cz.soa_expire == 86400
assert cz.soa_minimum == 3600
def test_is_full_netbox_model(self, make_view):
view = make_view(name="cz-netbox-model-view")
cz = CatalogZone.objects.create(view=view)
assert cz.created is not None
assert cz.last_updated is not None
assert cz.custom_field_data == {}
assert hasattr(cz, "tags")
assert cz.get_absolute_url() == f"/plugins/dns-bridge/catalog-zones/{cz.pk}/"
def test_one_to_one_relationship(self, make_view):
view = make_view(name="cz-oto-view")
cz = CatalogZone.objects.create(view=view, soa_serial=7)
@@ -67,10 +76,10 @@ class TestCatalogZone:
@pytest.mark.django_db
class TestCatalogZoneMemberIdentifier:
class TestCatalogZoneMember:
def test_str_representation(self, make_zone):
zone = make_zone(name="str.test")
m = CatalogZoneMemberIdentifier.objects.get(zone=zone)
m = CatalogZoneMember.objects.get(zone=zone)
assert str(m) == m.name
def test_unique_name_per_catalog_zone(self, make_zone, make_view):
@@ -78,11 +87,11 @@ class TestCatalogZoneMemberIdentifier:
zone1 = make_zone(name="uniq1.test", view=view)
zone2 = make_zone(name="uniq2.test", view=view)
ident1 = CatalogZoneMemberIdentifier.objects.get(zone=zone1)
ident1 = CatalogZoneMember.objects.get(zone=zone1)
ident1.name = "shared-name"
ident1.save()
ident2 = CatalogZoneMemberIdentifier.objects.get(zone=zone2)
ident2 = CatalogZoneMember.objects.get(zone=zone2)
from django.db import IntegrityError
with pytest.raises(IntegrityError):
@@ -95,36 +104,36 @@ class TestCatalogZoneMemberIdentifier:
zone1 = make_zone(name="diff1.test", view=view1)
zone2 = make_zone(name="diff2.test", view=view2)
ident1 = CatalogZoneMemberIdentifier.objects.get(zone=zone1)
ident1 = CatalogZoneMember.objects.get(zone=zone1)
ident1.name = "shared-name"
ident1.save()
ident2 = CatalogZoneMemberIdentifier.objects.get(zone=zone2)
ident2 = CatalogZoneMember.objects.get(zone=zone2)
ident2.name = "shared-name"
ident2.save()
def test_cascade_delete_when_zone_deleted(self, make_zone):
zone = make_zone(name="cascade.test")
m = CatalogZoneMemberIdentifier.objects.get(zone=zone)
assert CatalogZoneMemberIdentifier.objects.filter(pk=m.pk).exists()
m = CatalogZoneMember.objects.get(zone=zone)
assert CatalogZoneMember.objects.filter(pk=m.pk).exists()
zone.delete()
assert not CatalogZoneMemberIdentifier.objects.filter(pk=m.pk).exists()
assert not CatalogZoneMember.objects.filter(pk=m.pk).exists()
def test_one_to_one_relationship(self, make_zone):
zone = make_zone(name="oto.test")
m = CatalogZoneMemberIdentifier.objects.get(zone=zone)
assert zone.catz_identifier == m
m = CatalogZoneMember.objects.get(zone=zone)
assert zone.catalog_zone_member == m
def test_ordering_by_name(self, make_zone, make_view):
view = make_view(name="ord-view")
z1 = make_zone(name="z1.test", view=view)
z2 = make_zone(name="z2.test", view=view)
z3 = make_zone(name="z3.test", view=view)
CatalogZoneMemberIdentifier.objects.filter(zone=z3).update(name="gamma")
CatalogZoneMemberIdentifier.objects.filter(zone=z1).update(name="alpha")
CatalogZoneMemberIdentifier.objects.filter(zone=z2).update(name="beta")
CatalogZoneMember.objects.filter(zone=z3).update(name="gamma")
CatalogZoneMember.objects.filter(zone=z1).update(name="alpha")
CatalogZoneMember.objects.filter(zone=z2).update(name="beta")
names = list(
CatalogZoneMemberIdentifier.objects.filter(
CatalogZoneMember.objects.filter(
zone__in=[z1, z2, z3]
).values_list("name", flat=True)
)
@@ -132,10 +141,10 @@ class TestCatalogZoneMemberIdentifier:
@pytest.mark.django_db
class TestSeenTransferClients:
class TestSeenTransferClient:
def test_str_representation(self, make_view):
view = make_view(name="str-view")
client = SeenTransferClients.objects.create(
client = SeenTransferClient.objects.create(
source_ip="192.0.2.1",
view=view,
last_seen="2026-01-01T00:00:00Z",
@@ -146,13 +155,13 @@ class TestSeenTransferClients:
from django.db import IntegrityError
view = make_view(name="uniq-view")
SeenTransferClients.objects.create(
SeenTransferClient.objects.create(
source_ip="10.0.0.1",
view=view,
last_seen="2026-01-01T00:00:00Z",
)
with pytest.raises(IntegrityError):
SeenTransferClients.objects.create(
SeenTransferClient.objects.create(
source_ip="10.0.0.1",
view=view,
last_seen="2026-01-02T00:00:00Z",
@@ -161,19 +170,19 @@ class TestSeenTransferClients:
def test_same_ip_different_views_allowed(self, make_view):
v1 = make_view(name="v1")
v2 = make_view(name="v2")
SeenTransferClients.objects.create(
SeenTransferClient.objects.create(
source_ip="10.0.0.5", view=v1, last_seen="2026-01-01T00:00:00Z"
)
SeenTransferClients.objects.create(
SeenTransferClient.objects.create(
source_ip="10.0.0.5", view=v2, last_seen="2026-01-01T00:00:00Z"
)
assert SeenTransferClients.objects.filter(source_ip="10.0.0.5").count() == 2
assert SeenTransferClient.objects.filter(source_ip="10.0.0.5").count() == 2
def test_protect_on_view_delete(self, make_view):
from django.db.models import ProtectedError
view = make_view(name="protected-view")
SeenTransferClients.objects.create(
SeenTransferClient.objects.create(
source_ip="10.0.0.9",
view=view,
last_seen="2026-01-01T00:00:00Z",
@@ -187,6 +196,19 @@ class TestSeenTransferClients:
v = make_view(name="ord-view")
now = timezone.now()
for ip in ["10.0.0.3", "10.0.0.1", "10.0.0.2"]:
SeenTransferClients.objects.create(source_ip=ip, view=v, last_seen=now)
ips = list(SeenTransferClients.objects.values_list("source_ip", flat=True))
SeenTransferClient.objects.create(source_ip=ip, view=v, last_seen=now)
ips = list(SeenTransferClient.objects.values_list("source_ip", flat=True))
assert ips == ["10.0.0.1", "10.0.0.2", "10.0.0.3"]
def test_is_full_netbox_model(self, make_view):
from django.utils import timezone
view = make_view(name="stc-netbox-model-view")
c = SeenTransferClient.objects.create(
source_ip="192.0.2.1", view=view, last_seen=timezone.now()
)
assert c.created is not None
assert c.last_updated is not None
assert c.custom_field_data == {}
assert hasattr(c, "tags")
assert c.get_absolute_url() == f"/plugins/dns-bridge/seen-transfer-clients/{c.pk}/"