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
210 lines
8.5 KiB
Python
210 lines
8.5 KiB
Python
"""Tests for netbox_dns_bridge.utils: get_logger, build_dns_zone, export_bind_zone_file."""
|
|
import os
|
|
import tempfile
|
|
|
|
import dns.name
|
|
import dns.rdatatype
|
|
import dns.rdataclass
|
|
import pytest
|
|
|
|
from netbox_dns_bridge.utils import get_logger, build_dns_zone, export_bind_zone_file
|
|
|
|
|
|
class TestGetLogger:
|
|
def test_returns_dns_bridge_logger(self):
|
|
logger = get_logger("some.module")
|
|
assert logger.name == "dns-bridge"
|
|
|
|
def test_ignores_name_argument(self):
|
|
a = get_logger("module.a")
|
|
b = get_logger("module.b")
|
|
assert a is b
|
|
assert a.name == "dns-bridge"
|
|
|
|
def test_logger_is_singleton(self):
|
|
import logging
|
|
|
|
logger = get_logger("x")
|
|
assert logger is logging.getLogger("dns-bridge")
|
|
|
|
|
|
@pytest.mark.django_db
|
|
class TestBuildDnsZone:
|
|
def test_basic_a_record(self, make_zone, make_record):
|
|
zone = make_zone(name="a.test")
|
|
make_record(zone, name="www", type_="A", value="192.0.2.1")
|
|
dns_zone = build_dns_zone(zone)
|
|
origin = dns.name.from_text("a.test", dns.name.root)
|
|
rds = dns_zone.get_rdataset(origin, dns.rdatatype.SOA)
|
|
assert rds is not None
|
|
a_rds = dns_zone.get_rdataset(
|
|
dns.name.from_text("www", origin), dns.rdatatype.A
|
|
)
|
|
assert a_rds is not None
|
|
assert str(a_rds[0]) == "192.0.2.1"
|
|
|
|
def test_apex_record_empty_name(self, make_zone, make_record):
|
|
zone = make_zone(name="apex.test")
|
|
make_record(zone, name="@", type_="A", value="192.0.2.10")
|
|
dns_zone = build_dns_zone(zone)
|
|
origin = dns.name.from_text("apex.test", dns.name.root)
|
|
a_rds = dns_zone.get_rdataset(origin, dns.rdatatype.A)
|
|
assert a_rds is not None
|
|
assert str(a_rds[0]) == "192.0.2.10"
|
|
|
|
def test_ttl_fallback_to_zone_default(self, make_zone, make_record):
|
|
zone = make_zone(name="ttl.test", default_ttl=7200)
|
|
make_record(zone, name="host", type_="A", value="192.0.2.2", ttl=None)
|
|
dns_zone = build_dns_zone(zone)
|
|
origin = dns.name.from_text("ttl.test", dns.name.root)
|
|
a_rds = dns_zone.get_rdataset(
|
|
dns.name.from_text("host", origin), dns.rdatatype.A
|
|
)
|
|
assert a_rds.ttl == 7200
|
|
|
|
def test_record_ttl_overrides_zone_default(self, make_zone, make_record):
|
|
zone = make_zone(name="ttl2.test", default_ttl=7200)
|
|
make_record(zone, name="host", type_="A", value="192.0.2.3", ttl=300)
|
|
dns_zone = build_dns_zone(zone)
|
|
origin = dns.name.from_text("ttl2.test", dns.name.root)
|
|
a_rds = dns_zone.get_rdataset(
|
|
dns.name.from_text("host", origin), dns.rdatatype.A
|
|
)
|
|
assert a_rds.ttl == 300
|
|
|
|
def test_txt_record_quoting(self, make_zone, make_record):
|
|
zone = make_zone(name="txt.test")
|
|
make_record(zone, name="spf", type_="TXT", value="v=spf1 -all")
|
|
dns_zone = build_dns_zone(zone)
|
|
origin = dns.name.from_text("txt.test", dns.name.root)
|
|
txt_rds = dns_zone.get_rdataset(
|
|
dns.name.from_text("spf", origin), dns.rdatatype.TXT
|
|
)
|
|
assert txt_rds is not None
|
|
assert str(txt_rds[0]) == '"v=spf1 -all"'
|
|
|
|
def test_txt_record_already_quoted(self, make_zone, make_record):
|
|
zone = make_zone(name="txtq.test")
|
|
make_record(zone, name="dkim", type_="TXT", value='"k=rsa; p=MIGf"')
|
|
dns_zone = build_dns_zone(zone)
|
|
origin = dns.name.from_text("txtq.test", dns.name.root)
|
|
txt_rds = dns_zone.get_rdataset(
|
|
dns.name.from_text("dkim", origin), dns.rdatatype.TXT
|
|
)
|
|
assert txt_rds is not None
|
|
assert "k=rsa" in str(txt_rds[0])
|
|
|
|
def test_txt_record_long_value_chunked(self, make_zone, make_record):
|
|
zone = make_zone(name="longtxt.test")
|
|
long_val = "a" * 300
|
|
make_record(zone, name="big", type_="TXT", value=long_val)
|
|
dns_zone = build_dns_zone(zone)
|
|
origin = dns.name.from_text("longtxt.test", dns.name.root)
|
|
txt_rds = dns_zone.get_rdataset(
|
|
dns.name.from_text("big", origin), dns.rdatatype.TXT
|
|
)
|
|
assert txt_rds is not None
|
|
wire = str(txt_rds[0])
|
|
assert "a" * 300 in wire.replace('"', "").replace(" ", "")
|
|
|
|
def test_absolute_name_record(self, make_zone, make_record):
|
|
zone = make_zone(name="abs.test")
|
|
make_record(zone, name="out.abs.test.", type_="A", value="192.0.2.99")
|
|
dns_zone = build_dns_zone(zone)
|
|
abs_name = dns.name.from_text("out.abs.test", dns.name.root)
|
|
a_rds = dns_zone.get_rdataset(abs_name, dns.rdatatype.A)
|
|
assert a_rds is not None
|
|
assert str(a_rds[0]) == "192.0.2.99"
|
|
|
|
def test_multiple_records_same_name_type(self, make_zone, make_record):
|
|
zone = make_zone(name="multi.test")
|
|
make_record(zone, name="lb", type_="A", value="192.0.2.1")
|
|
make_record(zone, name="lb", type_="A", value="192.0.2.2")
|
|
dns_zone = build_dns_zone(zone)
|
|
origin = dns.name.from_text("multi.test", dns.name.root)
|
|
a_rds = dns_zone.get_rdataset(
|
|
dns.name.from_text("lb", origin), dns.rdatatype.A
|
|
)
|
|
assert a_rds is not None
|
|
assert len(a_rds) == 2
|
|
values = {str(r) for r in a_rds}
|
|
assert values == {"192.0.2.1", "192.0.2.2"}
|
|
|
|
def test_inactive_records_excluded(self, make_zone, make_record):
|
|
from netbox_dns.choices import RecordStatusChoices
|
|
|
|
zone = make_zone(name="inactive.test")
|
|
make_record(zone, name="active", type_="A", value="192.0.2.1",
|
|
status=RecordStatusChoices.STATUS_ACTIVE)
|
|
make_record(zone, name="inactive", type_="A", value="192.0.2.2",
|
|
status=RecordStatusChoices.STATUS_INACTIVE)
|
|
dns_zone = build_dns_zone(zone)
|
|
origin = dns.name.from_text("inactive.test", dns.name.root)
|
|
assert dns_zone.get_rdataset(
|
|
dns.name.from_text("active", origin), dns.rdatatype.A
|
|
) is not None
|
|
assert dns_zone.get_rdataset(
|
|
dns.name.from_text("inactive", origin), dns.rdatatype.A
|
|
) is None
|
|
|
|
def test_zone_rdclass_is_in(self, make_zone, make_record):
|
|
zone = make_zone(name="rdclass.test")
|
|
make_record(zone, name="x", type_="A", value="192.0.2.1")
|
|
dns_zone = build_dns_zone(zone)
|
|
assert dns_zone.rdclass == dns.rdataclass.IN
|
|
|
|
def test_aaaa_record(self, make_zone, make_record):
|
|
zone = make_zone(name="aaaa.test")
|
|
make_record(zone, name="v6", type_="AAAA", value="2001:db8::1")
|
|
dns_zone = build_dns_zone(zone)
|
|
origin = dns.name.from_text("aaaa.test", dns.name.root)
|
|
aaaa_rds = dns_zone.get_rdataset(
|
|
dns.name.from_text("v6", origin), dns.rdatatype.AAAA
|
|
)
|
|
assert aaaa_rds is not None
|
|
assert str(aaaa_rds[0]) == "2001:db8::1"
|
|
|
|
def test_cname_record(self, make_zone, make_record):
|
|
zone = make_zone(name="cname.test")
|
|
make_record(zone, name="alias", type_="CNAME", value="target.test.")
|
|
dns_zone = build_dns_zone(zone)
|
|
origin = dns.name.from_text("cname.test", dns.name.root)
|
|
cnames = dns_zone.get_rdataset(
|
|
dns.name.from_text("alias", origin), dns.rdatatype.CNAME
|
|
)
|
|
assert cnames is not None
|
|
assert str(cnames[0]) == "target.test."
|
|
|
|
def test_mx_record(self, make_zone, make_record):
|
|
zone = make_zone(name="mx.test")
|
|
make_record(zone, name="@", type_="MX", value="10 mail.test.")
|
|
dns_zone = build_dns_zone(zone)
|
|
origin = dns.name.from_text("mx.test", dns.name.root)
|
|
mx_rds = dns_zone.get_rdataset(origin, dns.rdatatype.MX)
|
|
assert mx_rds is not None
|
|
assert mx_rds[0].preference == 10
|
|
assert str(mx_rds[0].exchange) == "mail.test."
|
|
|
|
|
|
@pytest.mark.django_db
|
|
class TestExportBindZoneFile:
|
|
def test_writes_valid_zone_file(self, make_zone, make_record):
|
|
zone = make_zone(name="export.test")
|
|
make_record(zone, name="www", type_="A", value="192.0.2.1")
|
|
with tempfile.NamedTemporaryFile(mode="w", suffix=".zone", delete=False) as f:
|
|
path = f.name
|
|
try:
|
|
export_bind_zone_file(zone, path)
|
|
with open(path) as f:
|
|
content = f.read()
|
|
assert "SOA" in content
|
|
assert "192.0.2.1" in content
|
|
assert "www" in content
|
|
finally:
|
|
os.unlink(path)
|
|
|
|
def test_io_error_on_bad_path(self, make_zone):
|
|
zone = make_zone(name="badpath.test")
|
|
with pytest.raises(IOError):
|
|
export_bind_zone_file(zone, "/nonexistent/dir/zone.file")
|