Files
netbox-plugin-dns-bridge/netbox_dns_bridge/tests/test_management_commands.py
T
sven 4ad110ca53 new file: conftest.py
new file:   netbox_dns_bridge/tests/__init__.py
new file:   netbox_dns_bridge/tests/_helpers.py
new file:   netbox_dns_bridge/tests/conftest.py
new file:   netbox_dns_bridge/tests/test_bootstrap.py
new file:   netbox_dns_bridge/tests/test_catalog_zone_manager.py
new file:   netbox_dns_bridge/tests/test_dns_server.py
new file:   netbox_dns_bridge/tests/test_management_commands.py
new file:   netbox_dns_bridge/tests/test_models.py
new file:   netbox_dns_bridge/tests/test_notify_handler.py
new file:   netbox_dns_bridge/tests/test_request_handler_integration.py
new file:   netbox_dns_bridge/tests/test_request_handler_unit.py
new file:   netbox_dns_bridge/tests/test_signals.py
new file:   netbox_dns_bridge/tests/test_smoke.py
new file:   netbox_dns_bridge/tests/test_utils.py
new file:   netbox_dns_bridge/tests/test_views.py
modified:   pyproject.toml
Add some tests. #AI generated
2026-08-12 12:25:46 +02:00

198 lines
7.5 KiB
Python

"""Tests for management commands: dns-settings, dns-export-zone, dns-export-zones,
dns-transfer-endpoint."""
import os
import tempfile
from io import StringIO
from unittest.mock import patch, MagicMock
import pytest
from django.core.management import call_command
from django.core.management.base import CommandError
from netbox_dns_bridge.models import IntegerKeyValueSetting
@pytest.mark.django_db
class TestDnsSettingsCommand:
def test_list_empty(self):
IntegerKeyValueSetting.objects.all().delete()
out = StringIO()
call_command("dns-settings", "list", stdout=out)
assert "No settings found" in out.getvalue()
def test_list_with_entries(self):
IntegerKeyValueSetting.objects.create(key="k1", value=10)
IntegerKeyValueSetting.objects.create(key="k2", value=20)
out = StringIO()
call_command("dns-settings", "list", stdout=out)
output = out.getvalue()
assert "k1: 10" in output
assert "k2: 20" in output
def test_get_existing(self):
IntegerKeyValueSetting.objects.create(key="serial", value=42)
out = StringIO()
call_command("dns-settings", "get", "serial", stdout=out)
assert "serial: 42" in out.getvalue()
def test_get_missing_raises(self):
with pytest.raises(CommandError, match="No setting"):
call_command("dns-settings", "get", "nonexistent")
def test_get_without_key_raises(self):
with pytest.raises(CommandError, match="key is required"):
call_command("dns-settings", "get")
def test_set_existing(self):
IntegerKeyValueSetting.objects.create(key="counter", value=5)
out = StringIO()
call_command("dns-settings", "set", "counter", 99, stdout=out)
assert "Updated counter from 5 to 99" in out.getvalue()
assert IntegerKeyValueSetting.objects.get(key="counter").value == 99
def test_set_missing_key_raises(self):
with pytest.raises(CommandError, match="setting is required"):
call_command("dns-settings", "set")
def test_set_without_value_raises(self):
IntegerKeyValueSetting.objects.create(key="needval", value=1)
with pytest.raises(CommandError, match="value is required"):
call_command("dns-settings", "set", "needval")
def test_set_nonexistent_setting_raises(self):
with pytest.raises(CommandError, match="No setting found"):
call_command("dns-settings", "set", "ghost", 1)
@pytest.mark.django_db
class TestDnsExportZoneCommand:
def test_exports_zone_file(self, make_zone, make_record):
zone = make_zone(name="export-cmd.test")
make_record(zone, name="www", type_="A", value="192.0.2.1")
with tempfile.TemporaryDirectory() as td:
path = os.path.join(td, "zone.db")
out = StringIO()
call_command(
"dns-export-zone",
"--view", zone.view.name,
"--zone", "export-cmd.test",
"--file", path,
stdout=out,
)
assert os.path.exists(path)
with open(path) as f:
content = f.read()
assert "SOA" in content
assert "192.0.2.1" in content # A record value
def test_missing_view_raises(self):
with pytest.raises(CommandError, match="--view"):
call_command("dns-export-zone", "--zone", "z.test", "--file", "/tmp/x")
def test_missing_zone_raises(self):
with pytest.raises(CommandError, match="--zone"):
call_command("dns-export-zone", "--view", "default", "--file", "/tmp/x")
def test_missing_file_raises(self):
with pytest.raises(CommandError, match="--file"):
call_command("dns-export-zone", "--view", "default", "--zone", "z.test")
def test_nonexistent_zone_raises(self, make_view):
make_view(name="default")
with pytest.raises(CommandError, match="Failed to export zone"):
call_command(
"dns-export-zone",
"--view", "default",
"--zone", "does-not-exist.test",
"--file", "/tmp/x.zone",
)
@pytest.mark.django_db
class TestDnsExportZonesCommand:
def test_exports_all_zones(self, make_zone, make_view):
make_zone(name="batch1.test")
make_zone(name="batch2.test")
with tempfile.TemporaryDirectory() as td:
out = StringIO()
call_command("dns-export-zones", "--path", td, stdout=out)
output = out.getvalue()
assert "batch1.test" in output
assert "batch2.test" in output
for zone_name in ("batch1.test", "batch2.test"):
for root, dirs, files in os.walk(td):
if zone_name in files:
break
else:
pytest.fail(f"Zone file for {zone_name} not found")
def test_creates_view_subdirectories(self, make_zone, make_view):
make_zone(name="subdir.test")
with tempfile.TemporaryDirectory() as td:
out = StringIO()
call_command("dns-export-zones", "--path", td, stdout=out)
view_dirs = os.listdir(td)
assert len(view_dirs) > 0
def test_missing_path_raises(self):
with pytest.raises(CommandError, match="--path"):
call_command("dns-export-zones")
def test_no_zones_warning(self):
from netbox_dns.models import Zone
Zone.objects.all().delete()
with tempfile.TemporaryDirectory() as td:
out = StringIO()
call_command("dns-export-zones", "--path", td, stdout=out)
assert "No zones found" in out.getvalue()
def test_creates_path_if_not_exists(self, make_zone):
make_zone(name="mkpath.test")
with tempfile.TemporaryDirectory() as td:
path = os.path.join(td, "subdir1", "subdir2")
out = StringIO()
call_command("dns-export-zones", "--path", path, stdout=out)
assert os.path.isdir(path)
@pytest.mark.django_db
class TestDnsTransferEndpointCommand:
def _get_cmd_module(self):
"""Load the dns-transfer-endpoint command module (hyphen in filename)."""
import sys
from django.core.management import load_command_class
cmd = load_command_class("netbox_dns_bridge", "dns-transfer-endpoint")
return sys.modules[cmd.__module__]
def test_missing_tsig_keys_raises(self, monkeypatch):
cmd_mod = self._get_cmd_module()
monkeypatch.setattr(cmd_mod, "SETTINGS", {})
with pytest.raises(RuntimeError, match="tsig_keys variable not set"):
call_command("dns-transfer-endpoint")
def test_loads_tsig_keys_and_starts_servers(
self, monkeypatch, make_view
):
cmd_mod = self._get_cmd_module()
view = make_view(name="ep-view")
monkeypatch.setattr(cmd_mod, "SETTINGS", {
"tsig_keys": {
"ep-view": {
"keyname": "epkey.",
"secret": "YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWE=",
"algorithm": "hmac-sha256",
}
}
})
with patch.object(cmd_mod, "TCPDNSServer") as mock_tcp, \
patch.object(cmd_mod, "UDPDNSServer") as mock_udp:
mock_tcp.return_value.serve_forever = MagicMock()
mock_udp.return_value.serve_forever = MagicMock()
call_command("dns-transfer-endpoint", "--port", "0", "--address", "127.0.0.1")
assert mock_tcp.called
assert mock_udp.called