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.
241 lines
9.1 KiB
Python
241 lines
9.1 KiB
Python
"""Tests for signal handlers: zone_pre_save, zone_post_save, zone_post_delete.
|
|
|
|
Uses ``captureOnCommitCallbacks(execute=True)`` to fire ``transaction.on_commit``
|
|
callbacks inside the transaction-wrapped ``@pytest.mark.django_db`` test scope.
|
|
"""
|
|
from unittest.mock import patch, MagicMock
|
|
|
|
import pytest
|
|
from django.test.testcases import TestCase as _DjangoTestCase
|
|
|
|
# captureOnCommitCallbacks is a classmethod on TestCase in Django 6.x
|
|
captureOnCommitCallbacks = _DjangoTestCase.captureOnCommitCallbacks
|
|
|
|
from netbox_dns_bridge.models import (
|
|
CatalogZone,
|
|
CatalogZoneMemberIdentifier,
|
|
)
|
|
|
|
|
|
@pytest.mark.django_db
|
|
class TestZonePreSave:
|
|
def test_stores_old_name_and_serial_on_existing_zone(self, make_zone):
|
|
zone = make_zone(name="presave.test", soa_serial=100)
|
|
zone.refresh_from_db()
|
|
zone.soa_serial = 200
|
|
zone.save()
|
|
assert getattr(zone, "_old_name", None) == "presave.test"
|
|
assert getattr(zone, "_old_soa_serial", None) == 100
|
|
|
|
def test_old_attrs_none_on_new_zone(self, make_zone):
|
|
zone = make_zone(name="newzone.test")
|
|
assert getattr(zone, "_old_name", None) is None
|
|
assert getattr(zone, "_old_soa_serial", None) is None
|
|
|
|
|
|
@pytest.mark.django_db
|
|
class TestZonePostSaveCreate:
|
|
def test_creates_catz_member_identifier_on_new_zone(self, make_zone):
|
|
zone = make_zone(name="postcreate.test")
|
|
assert CatalogZoneMemberIdentifier.objects.filter(zone=zone).exists()
|
|
|
|
def test_increments_soa_serial_on_commit(self, make_zone, catz_serial):
|
|
with captureOnCommitCallbacks(execute=True):
|
|
zone = make_zone(name="serial-inc.test")
|
|
obj = CatalogZone.objects.get(view=zone.view)
|
|
assert obj.soa_serial == catz_serial + 1
|
|
|
|
def test_does_not_increment_without_on_commit(self, make_zone, catz_serial):
|
|
zone = make_zone(name="no-commit.test")
|
|
obj = CatalogZone.objects.get(view=zone.view)
|
|
assert obj.soa_serial == catz_serial
|
|
|
|
def test_schedule_client_notify_always_called(self, make_zone, patch_settings):
|
|
patch_settings({"notify_clients": True})
|
|
with patch(
|
|
"netbox_dns_bridge.jobs.notify.schedule_client_notify"
|
|
) as mock_notify:
|
|
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
|
|
):
|
|
patch_settings({
|
|
"notify_clients": False,
|
|
"notify_ns_all_zones": True,
|
|
})
|
|
with patch(
|
|
"netbox_dns_bridge.jobs.notify.schedule_ns_notify"
|
|
) as mock_ns_notify:
|
|
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_serial_unchanged(
|
|
self, make_zone, patch_settings
|
|
):
|
|
patch_settings({"notify_ns_all_zones": True})
|
|
with patch(
|
|
"netbox_dns_bridge.jobs.notify.schedule_ns_notify"
|
|
) as mock_ns_notify:
|
|
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
|
|
class TestZonePostSaveUpdate:
|
|
def test_updates_catz_identifier_on_name_change(self, make_zone):
|
|
zone = make_zone(name="rename-old.test")
|
|
old_name = CatalogZoneMemberIdentifier.objects.get(zone=zone).name
|
|
|
|
zone.name = "rename-new.test"
|
|
zone.save()
|
|
|
|
new_name = CatalogZoneMemberIdentifier.objects.get(zone=zone).name
|
|
assert old_name != new_name
|
|
|
|
def test_no_identifier_update_when_name_unchanged(self, make_zone):
|
|
zone = make_zone(name="nochange.test")
|
|
ident = CatalogZoneMemberIdentifier.objects.get(zone=zone)
|
|
original_name = ident.name
|
|
|
|
zone.soa_serial = zone.soa_serial + 1
|
|
zone.save()
|
|
ident.refresh_from_db()
|
|
assert ident.name == original_name
|
|
|
|
def test_increments_serial_on_commit_on_update(self, make_zone, catz_serial):
|
|
zone = make_zone(name="update-serial.test")
|
|
with captureOnCommitCallbacks(execute=True):
|
|
zone.soa_serial = zone.soa_serial + 1
|
|
zone.save()
|
|
obj = CatalogZone.objects.get(view=zone.view)
|
|
assert obj.soa_serial == catz_serial + 1
|
|
|
|
|
|
@pytest.mark.django_db
|
|
class TestZonePostDelete:
|
|
def test_increments_soa_serial_on_commit_on_delete(self, make_zone, catz_serial):
|
|
zone = make_zone(name="delete-serial.test")
|
|
view = zone.view
|
|
with captureOnCommitCallbacks(execute=True):
|
|
zone.delete()
|
|
obj = CatalogZone.objects.get(view=view)
|
|
assert obj.soa_serial == catz_serial + 1
|
|
|
|
def test_does_not_increment_without_on_commit(self, make_zone, catz_serial):
|
|
zone = make_zone(name="delete-no-commit.test")
|
|
view = zone.view
|
|
zone.delete()
|
|
obj = CatalogZone.objects.get(view=view)
|
|
assert obj.soa_serial == catz_serial
|
|
|
|
|
|
@pytest.mark.django_db
|
|
class TestZoneViewChange:
|
|
def test_increments_both_catalog_zone_serials(self, make_zone, make_view, catz_serial):
|
|
view_a = make_view(name="view-a")
|
|
view_b = make_view(name="view-b")
|
|
# view_b has no zones yet, so no CatalogZone was auto-created for it.
|
|
CatalogZone.objects.create(view=view_b, soa_serial=5)
|
|
|
|
zone = make_zone(name="move.test", view=view_a)
|
|
|
|
serial_a_before = CatalogZone.objects.get(view=view_a).soa_serial
|
|
serial_b_before = CatalogZone.objects.get(view=view_b).soa_serial
|
|
|
|
with captureOnCommitCallbacks(execute=True):
|
|
zone.view = view_b
|
|
zone.save()
|
|
|
|
serial_a_after = CatalogZone.objects.get(view=view_a).soa_serial
|
|
serial_b_after = CatalogZone.objects.get(view=view_b).soa_serial
|
|
assert serial_a_after == serial_a_before + 1
|
|
assert serial_b_after == serial_b_before + 1
|
|
|
|
def test_updates_identifier_catalog_zone_fk(self, make_zone, make_view):
|
|
view_a = make_view(name="fk-view-a")
|
|
view_b = make_view(name="fk-view-b")
|
|
zone = make_zone(name="fk-move.test", view=view_a)
|
|
|
|
ident = CatalogZoneMemberIdentifier.objects.get(zone=zone)
|
|
assert ident.catalog_zone == CatalogZone.objects.get(view=view_a)
|
|
|
|
zone.view = view_b
|
|
zone.save()
|
|
|
|
ident.refresh_from_db()
|
|
assert ident.catalog_zone == CatalogZone.objects.get(view=view_b)
|
|
|
|
|
|
@pytest.mark.django_db
|
|
class TestSignalDedup:
|
|
def test_dedup_skips_second_save_in_same_request(self, make_zone):
|
|
from netbox.context import current_request
|
|
from django.contrib.auth import get_user_model
|
|
|
|
zone = make_zone(name="dedup.test")
|
|
original_serial = CatalogZone.objects.get(
|
|
view=zone.view
|
|
).soa_serial
|
|
|
|
User = get_user_model()
|
|
user = User(username="dedup-user", is_superuser=True)
|
|
user.save()
|
|
|
|
request = MagicMock()
|
|
request._handled_zones = set()
|
|
request.user = user
|
|
import uuid as _uuid
|
|
request.id = _uuid.uuid4()
|
|
|
|
with current_request.set(request):
|
|
with captureOnCommitCallbacks(execute=True):
|
|
zone.soa_serial = zone.soa_serial + 1
|
|
zone.save()
|
|
with captureOnCommitCallbacks(execute=True):
|
|
zone.soa_serial = zone.soa_serial + 2
|
|
zone.save()
|
|
|
|
new_serial = CatalogZone.objects.get(
|
|
view=zone.view
|
|
).soa_serial
|
|
assert new_serial == original_serial + 1
|
|
|
|
def test_no_dedup_without_request(self, make_zone):
|
|
zone = make_zone(name="nodedup.test")
|
|
original_serial = CatalogZone.objects.get(
|
|
view=zone.view
|
|
).soa_serial
|
|
|
|
with captureOnCommitCallbacks(execute=True):
|
|
zone.soa_serial = zone.soa_serial + 1
|
|
zone.save()
|
|
with captureOnCommitCallbacks(execute=True):
|
|
zone.soa_serial = zone.soa_serial + 2
|
|
zone.save()
|
|
|
|
new_serial = CatalogZone.objects.get(
|
|
view=zone.view
|
|
).soa_serial
|
|
assert new_serial == original_serial + 2
|