"""Tests for management commands: 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 @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