modified: CHANGELOG.md

new file:   netbox_dns_bridge/jobs/__init__.py
renamed:    netbox_dns_bridge/signals/notify_handler.py -> netbox_dns_bridge/jobs/notify.py
modified:   netbox_dns_bridge/management/commands/dns_transfer_endpoint/catalog_zone_manager.py
modified:   netbox_dns_bridge/signals/netbox_dns_zones.py
Restructuring

modified:   netbox_dns_bridge/tests/conftest.py
renamed:    netbox_dns_bridge/tests/test_notify_handler.py -> netbox_dns_bridge/tests/test_notify.py
modified:   netbox_dns_bridge/tests/test_signals.py
AI updated tests, not manually verified.
This commit is contained in:
sven committed 2026-08-17 10:07:46 +02:00
1 parent 9f5e40ae48
commit 3c3a1834bc
8 files changed
+295 -204

No files matched your search

+2 -3
View File
@@ -27,11 +27,10 @@ def default_view(db):
def _settings_modules():
from netbox_dns_bridge.management.commands.dns_transfer_endpoint import (
request_handler,
catalog_zone_manager as catzm, # noqa: F401
)
from netbox_dns_bridge.signals import netbox_dns_zones, notify_handler
from netbox_dns_bridge.jobs import notify
return [netbox_dns_zones, notify_handler, request_handler]
return [notify, request_handler]
@pytest.fixture
@@ -1,5 +1,5 @@
"""Tests for notify_handler: _load_tsig_key, _get_soa_serial, _resolve_zone_nameserver_ips,
schedule_client_notify, schedule_ns_notify, and job classes."""
"""Tests for notify: _load_tsig_key, _get_soa_serial, _resolve_zone_nameserver_ips,
schedule_client_notify, schedule_ns_notify, schedule_catalog_zone_notify, and job classes."""
from unittest.mock import patch, MagicMock
import dns.name
@@ -7,7 +7,7 @@ import dns.rdatatype
import dns.tsig
import pytest
import netbox_dns_bridge.signals.notify_handler as nh
import netbox_dns_bridge.jobs.notify as nh
class TestLoadTsigKey:
@@ -156,9 +156,10 @@ class TestResolveZoneNameserverIps:
@pytest.mark.django_db
class TestScheduleClientNotify:
def test_enqueues_job_when_soa_exists(self, make_zone):
def test_enqueues_job_when_enabled(self, make_zone, monkeypatch):
zone = make_zone(name="sched-client.test", soa_serial=77)
with patch.object(nh.SendClientDNSNotify, "enqueue") as mock_enq:
monkeypatch.setattr(nh, "SETTINGS", {"notify_clients": True})
with patch.object(nh.SendClientNotify, "enqueue") as mock_enq:
nh.schedule_client_notify(zone)
mock_enq.assert_called_once_with(
zone_name="sched-client.test",
@@ -166,20 +167,29 @@ class TestScheduleClientNotify:
soa_serial=77,
)
def test_does_not_enqueue_when_no_soa(self, make_zone):
def test_does_not_enqueue_when_no_soa(self, make_zone, monkeypatch):
from netbox_dns.models import Record
zone = make_zone(name="sched-client-nosoa.test")
Record.objects.filter(zone=zone, type="SOA").delete()
with patch.object(nh.SendClientDNSNotify, "enqueue") as mock_enq:
monkeypatch.setattr(nh, "SETTINGS", {"notify_clients": True})
with patch.object(nh.SendClientNotify, "enqueue") as mock_enq:
nh.schedule_client_notify(zone)
mock_enq.assert_not_called()
def test_does_not_enqueue_when_notify_clients_disabled(self, make_zone, monkeypatch):
zone = make_zone(name="sched-client-disabled.test", soa_serial=77)
monkeypatch.setattr(nh, "SETTINGS", {"notify_clients": False})
with patch.object(nh.SendClientNotify, "enqueue") as mock_enq:
nh.schedule_client_notify(zone)
mock_enq.assert_not_called()
@pytest.mark.django_db
class TestScheduleNsNotify:
def test_enqueues_job_when_soa_exists(self, make_zone):
def test_enqueues_job_when_enabled(self, make_zone, monkeypatch):
zone = make_zone(name="sched-ns.test", soa_serial=88)
monkeypatch.setattr(nh, "SETTINGS", {"notify_ns_all_zones": True})
with patch.object(nh.SendNSNotify, "enqueue") as mock_enq:
nh.schedule_ns_notify(zone)
mock_enq.assert_called_once_with(
@@ -189,33 +199,75 @@ class TestScheduleNsNotify:
soa_serial=88,
)
def test_does_not_enqueue_when_no_soa(self, make_zone):
def test_does_not_enqueue_when_no_soa(self, make_zone, monkeypatch):
from netbox_dns.models import Record
zone = make_zone(name="sched-ns-nosoa.test")
Record.objects.filter(zone=zone, type="SOA").delete()
monkeypatch.setattr(nh, "SETTINGS", {"notify_ns_all_zones": True})
with patch.object(nh.SendNSNotify, "enqueue") as mock_enq:
nh.schedule_ns_notify(zone)
mock_enq.assert_not_called()
def test_does_not_enqueue_when_ns_notify_disabled(self, make_zone, monkeypatch):
zone = make_zone(name="sched-ns-disabled.test", soa_serial=88)
monkeypatch.setattr(nh, "SETTINGS", {})
with patch.object(nh.SendNSNotify, "enqueue") as mock_enq:
nh.schedule_ns_notify(zone)
mock_enq.assert_not_called()
@pytest.mark.django_db
class TestSendClientDNSNotifyRun:
def test_sends_notify_to_seen_clients(self, make_zone, make_view, monkeypatch):
import netbox_dns_bridge.signals.notify_handler as nh
from netbox_dns_bridge.models import SeenTransferClients, CatalogZone
class TestScheduleCatalogZoneNotify:
def test_enqueues_two_jobs_when_enabled(self, make_view, monkeypatch):
from netbox_dns_bridge.models import CatalogZone
view = make_view(name="catz-notify-view")
CatalogZone.objects.create(view=view, soa_serial=42)
monkeypatch.setattr(nh, "SETTINGS", {"notify_clients": True})
with patch.object(nh.SendClientNotify, "enqueue") as mock_enq:
nh.schedule_catalog_zone_notify(view)
assert mock_enq.call_count == 2
mock_enq.assert_any_call(
zone_name="catz", soa_serial=42, view_name="catz-notify-view"
)
mock_enq.assert_any_call(
zone_name="catz-notify-view.catz",
soa_serial=42,
view_name="catz-notify-view",
)
def test_does_not_enqueue_when_notify_clients_disabled(self, make_view, monkeypatch):
from netbox_dns_bridge.models import CatalogZone
view = make_view(name="catz-notify-disabled")
CatalogZone.objects.create(view=view, soa_serial=42)
monkeypatch.setattr(nh, "SETTINGS", {"notify_clients": False})
with patch.object(nh.SendClientNotify, "enqueue") as mock_enq:
nh.schedule_catalog_zone_notify(view)
mock_enq.assert_not_called()
def test_does_not_enqueue_when_no_catalog_zone(self, make_view, monkeypatch):
view = make_view(name="catz-notify-no-cz")
monkeypatch.setattr(nh, "SETTINGS", {"notify_clients": True})
with patch.object(nh.SendClientNotify, "enqueue") as mock_enq:
nh.schedule_catalog_zone_notify(view)
mock_enq.assert_not_called()
@pytest.mark.django_db
class TestSendClientNotifyRun:
def test_sends_single_notify_to_seen_clients(self, make_zone, make_view, monkeypatch):
import netbox_dns_bridge.jobs.notify as nh
from netbox_dns_bridge.models import SeenTransferClients
from django.utils import timezone
view = make_view(name="notify-run-view")
CatalogZone.objects.update_or_create(
view=view, defaults={"soa_serial": 42}
)
SeenTransferClients.objects.create(
source_ip="192.0.2.99", view=view, last_seen=timezone.now()
)
monkeypatch.setattr(nh, "SETTINGS", {
"notify_clients": True,
"tsig_keys": {
"notify-run-view": {
"keyname": "nk.",
@@ -229,21 +281,23 @@ class TestSendClientDNSNotifyRun:
})
job = MagicMock()
job.run.__wrapped__ = nh.SendClientDNSNotify.run
with patch("dns.query.udp") as mock_udp:
nh.SendClientDNSNotify.run(job,
nh.SendClientNotify.run(job,
zone_name="z.test", soa_serial=10, view_name="notify-run-view")
assert mock_udp.call_count >= 3 # zone + catz + view.catz
assert mock_udp.call_count == 1
def test_handles_missing_serial_setting(self, monkeypatch, make_view):
# When the CatalogZone for the view doesn't exist,
# the job should log an error and not send any notifies
view = make_view(name="missing-serial-view")
def test_sends_notify_without_catalog_zone(self, monkeypatch, make_view):
from netbox_dns_bridge.models import SeenTransferClients
from django.utils import timezone
view = make_view(name="no-catz-view")
SeenTransferClients.objects.create(
source_ip="192.0.2.1", view=view, last_seen=timezone.now()
)
monkeypatch.setattr(nh, "SETTINGS", {
"notify_clients": True,
"tsig_keys": {
"missing-serial-view": {
"no-catz-view": {
"keyname": "nk.",
"secret": "YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWE=",
"algorithm": "hmac-sha256",
@@ -256,15 +310,15 @@ class TestSendClientDNSNotifyRun:
job = MagicMock()
with patch("dns.query.udp") as mock_udp:
nh.SendClientDNSNotify.run(job,
zone_name="z.test", soa_serial=1, view_name="missing-serial-view")
mock_udp.assert_not_called()
nh.SendClientNotify.run(job,
zone_name="z.test", soa_serial=1, view_name="no-catz-view")
assert mock_udp.call_count == 1
@pytest.mark.django_db
class TestSendNSNotifyRun:
def test_sends_notify_to_nameserver_ips(self, make_zone, make_record, make_nameserver, monkeypatch):
import netbox_dns_bridge.signals.notify_handler as nh
import netbox_dns_bridge.jobs.notify as nh
zone = make_zone(name="ns-notify-run.test", soa_serial=55)
ns = make_nameserver("ns1.ns-notify-run.test")
@@ -319,3 +373,44 @@ class TestSendNSNotifyRun:
zone_id=zone.pk, zone_name="ns-notify-empty.test",
view_name=zone.view.name, soa_serial=1)
mock_udp.assert_not_called()
@pytest.mark.django_db
class TestNotifyNsEnabled:
def test_enabled_by_all_zones_flag(self, make_zone, monkeypatch):
monkeypatch.setattr(nh, "SETTINGS", {"notify_ns_all_zones": True})
from netbox_dns_bridge.jobs.notify import _notify_ns_enabled
zone = make_zone(name="nsflag.test")
assert _notify_ns_enabled(zone) is True
def test_disabled_by_default(self, make_zone, monkeypatch):
monkeypatch.setattr(nh, "SETTINGS", {})
from netbox_dns_bridge.jobs.notify import _notify_ns_enabled
zone = make_zone(name="nsdisabled.test")
assert _notify_ns_enabled(zone) is False
def test_enabled_by_custom_field(self, make_zone, monkeypatch):
monkeypatch.setattr(nh, "SETTINGS", {"notify_ns_custom_field_name": "enable_notify"})
from netbox_dns_bridge.jobs.notify import _notify_ns_enabled
zone = make_zone(name="nscf.test")
zone.custom_field_data = {"enable_notify": True}
assert _notify_ns_enabled(zone) is True
def test_disabled_when_custom_field_false(self, make_zone, monkeypatch):
monkeypatch.setattr(nh, "SETTINGS", {"notify_ns_custom_field_name": "enable_notify"})
from netbox_dns_bridge.jobs.notify import _notify_ns_enabled
zone = make_zone(name="nscf-false.test")
zone.custom_field_data = {"enable_notify": False}
assert _notify_ns_enabled(zone) is False
def test_disabled_when_custom_field_missing(self, make_zone, monkeypatch):
monkeypatch.setattr(nh, "SETTINGS", {"notify_ns_custom_field_name": "enable_notify"})
from netbox_dns_bridge.jobs.notify import _notify_ns_enabled
zone = make_zone(name="nscf-missing.test")
zone.custom_field_data = {}
assert _notify_ns_enabled(zone) is False
+36 -63
View File
@@ -50,41 +50,55 @@ class TestZonePostSaveCreate:
obj = CatalogZone.objects.get(view=zone.view)
assert obj.soa_serial == catz_serial
def test_schedule_client_notify_called_when_enabled(self, make_zone, patch_settings):
def test_schedule_client_notify_always_called(self, make_zone, patch_settings):
patch_settings({"notify_clients": True})
with patch(
"netbox_dns_bridge.signals.netbox_dns_zones.notify_handler.schedule_client_notify"
"netbox_dns_bridge.jobs.notify.schedule_client_notify"
) as mock_notify:
with patch(
"netbox_dns_bridge.signals.netbox_dns_zones.notify_handler.schedule_ns_notify"
):
with captureOnCommitCallbacks(execute=True):
make_zone(name="notify.test")
mock_notify.assert_called_once()
with patch("netbox_dns_bridge.jobs.notify.schedule_ns_notify"):
with patch(
"netbox_dns_bridge.management.commands.dns_transfer_endpoint."
"catalog_zone_manager.notify.schedule_catalog_zone_notify"
):
with captureOnCommitCallbacks(execute=True):
make_zone(name="notify.test")
mock_notify.assert_called_once()
def test_schedule_ns_notify_called_when_serial_changed(self, make_zone, patch_settings):
def test_schedule_ns_notify_called_when_serial_changed(
self, make_zone, patch_settings
):
patch_settings({
"notify_clients": False,
"notify_ns_all_zones": True,
})
with patch(
"netbox_dns_bridge.signals.netbox_dns_zones.notify_handler.schedule_ns_notify"
"netbox_dns_bridge.jobs.notify.schedule_ns_notify"
) as mock_ns_notify:
with captureOnCommitCallbacks(execute=True):
make_zone(name="nsnotify.test")
mock_ns_notify.assert_called_once()
with patch("netbox_dns_bridge.jobs.notify.schedule_client_notify"):
with patch(
"netbox_dns_bridge.management.commands.dns_transfer_endpoint."
"catalog_zone_manager.notify.schedule_catalog_zone_notify"
):
with captureOnCommitCallbacks(execute=True):
make_zone(name="nsnotify.test")
mock_ns_notify.assert_called_once()
def test_schedule_ns_notify_not_called_when_disabled(self, make_zone, patch_settings):
patch_settings({
"notify_clients": False,
"notify_ns_all_zones": False,
})
def test_schedule_ns_notify_not_called_when_serial_unchanged(
self, make_zone, patch_settings
):
patch_settings({"notify_ns_all_zones": True})
with patch(
"netbox_dns_bridge.signals.netbox_dns_zones.notify_handler.schedule_ns_notify"
"netbox_dns_bridge.jobs.notify.schedule_ns_notify"
) as mock_ns_notify:
with captureOnCommitCallbacks(execute=True):
make_zone(name="nonsnotify.test")
mock_ns_notify.assert_not_called()
with patch("netbox_dns_bridge.jobs.notify.schedule_client_notify"):
with patch(
"netbox_dns_bridge.management.commands.dns_transfer_endpoint."
"catalog_zone_manager.notify.schedule_catalog_zone_notify"
):
zone = make_zone(name="noserialchange.test")
with captureOnCommitCallbacks(execute=True):
zone.save()
mock_ns_notify.assert_not_called()
@pytest.mark.django_db
@@ -224,44 +238,3 @@ class TestSignalDedup:
view=zone.view
).soa_serial
assert new_serial == original_serial + 2
@pytest.mark.django_db
class TestNotifyNsEnabled:
def test_enabled_by_all_zones_flag(self, make_zone, patch_settings):
patch_settings({"notify_ns_all_zones": True})
from netbox_dns_bridge.signals.netbox_dns_zones import _notify_ns_enabled
zone = make_zone(name="nsflag.test")
assert _notify_ns_enabled(zone) is True
def test_disabled_by_default(self, make_zone, patch_settings):
patch_settings({})
from netbox_dns_bridge.signals.netbox_dns_zones import _notify_ns_enabled
zone = make_zone(name="nsdisabled.test")
assert _notify_ns_enabled(zone) is False
def test_enabled_by_custom_field(self, make_zone, patch_settings):
patch_settings({"notify_ns_custom_field_name": "enable_notify"})
from netbox_dns_bridge.signals.netbox_dns_zones import _notify_ns_enabled
zone = make_zone(name="nscf.test")
zone.custom_field_data = {"enable_notify": True}
assert _notify_ns_enabled(zone) is True
def test_disabled_when_custom_field_false(self, make_zone, patch_settings):
patch_settings({"notify_ns_custom_field_name": "enable_notify"})
from netbox_dns_bridge.signals.netbox_dns_zones import _notify_ns_enabled
zone = make_zone(name="nscf-false.test")
zone.custom_field_data = {"enable_notify": False}
assert _notify_ns_enabled(zone) is False
def test_disabled_when_custom_field_missing(self, make_zone, patch_settings):
patch_settings({"notify_ns_custom_field_name": "enable_notify"})
from netbox_dns_bridge.signals.netbox_dns_zones import _notify_ns_enabled
zone = make_zone(name="nscf-missing.test")
zone.custom_field_data = {}
assert _notify_ns_enabled(zone) is False