]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Convert dynamic zone test cases to pytest
authorMatthijs Mekking <matthijs@isc.org>
Fri, 14 Mar 2025 12:08:44 +0000 (13:08 +0100)
committerMatthijs Mekking <matthijs@isc.org>
Thu, 17 Apr 2025 11:50:49 +0000 (13:50 +0200)
This commit deals with converting the dynamic zone test cases to
pytest. The tests for 'inline-signing.kasp' are similar to the default
case, so these are added to 'test_kasp_default'.

Unfortunately I need to add sleep calls in between freezing, updating,
and thawing a zone. Without it the intermittent failures are too
frequent.

bin/tests/system/kasp/tests.sh
bin/tests/system/kasp/tests_kasp.py

index 305ae548ac03a99db259a9788431cc124dc00218..fd41fd231afdcedf508414ea516165d43da42c6c 100644 (file)
@@ -119,29 +119,6 @@ set_keystate "KEY1" "STATE_KRRSIG" "rumoured"
 set_keystate "KEY1" "STATE_ZRRSIG" "rumoured"
 set_keystate "KEY1" "STATE_DS" "hidden"
 
-update_is_signed() {
-  ip_a=$1
-  ip_d=$2
-
-  if [ "$ip_a" != "-" ]; then
-    dig_with_opts "a.${ZONE}" "@${SERVER}" A >"dig.out.$DIR.test$n.a" || return 1
-    grep "status: NOERROR" "dig.out.$DIR.test$n.a" >/dev/null || return 1
-    grep "a.${ZONE}\..*${DEFAULT_TTL}.*IN.*A.*${ip_a}" "dig.out.$DIR.test$n.a" >/dev/null || return 1
-    lines=$(get_keys_which_signed A 0 "dig.out.$DIR.test$n.a" | wc -l)
-    test "$lines" -eq 1 || return 1
-    get_keys_which_signed A 0 "dig.out.$DIR.test$n.a" | grep "^${KEY_ID}$" >/dev/null || return 1
-  fi
-
-  if [ "$ip_d" != "-" ]; then
-    dig_with_opts "d.${ZONE}" "@${SERVER}" A >"dig.out.$DIR.test$n".d || return 1
-    grep "status: NOERROR" "dig.out.$DIR.test$n".d >/dev/null || return 1
-    grep "d.${ZONE}\..*${DEFAULT_TTL}.*IN.*A.*${ip_d}" "dig.out.$DIR.test$n".d >/dev/null || return 1
-    lines=$(get_keys_which_signed A 0 "dig.out.$DIR.test$n".d | wc -l)
-    test "$lines" -eq 1 || return 1
-    get_keys_which_signed A 0 "dig.out.$DIR.test$n".d | grep "^${KEY_ID}$" >/dev/null || return 1
-  fi
-}
-
 #
 # A zone with special characters.
 #
@@ -152,129 +129,6 @@ set_server "ns3" "10.53.0.3"
 # escaping characters, so we will just try to verify the zone.
 dnssec_verify
 
-#
-# Zone: dynamic.kasp
-#
-set_zone "dynamic.kasp"
-set_dynamic
-set_policy "default" "1" "3600"
-set_server "ns3" "10.53.0.3"
-# Key properties, timings and states same as above.
-check_keys
-check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
-set_keytimes_csk_policy
-check_keytimes
-check_apex
-check_subdomain
-dnssec_verify
-
-# Update zone with nsupdate.
-n=$((n + 1))
-echo_i "nsupdate zone and check that new record is signed for zone ${ZONE} ($n)"
-ret=0
-(
-  echo zone ${ZONE}
-  echo server 10.53.0.3 "$PORT"
-  echo update del "a.${ZONE}" 300 A 10.0.0.1
-  echo update add "a.${ZONE}" 300 A 10.0.0.101
-  echo update add "d.${ZONE}" 300 A 10.0.0.4
-  echo send
-) | $NSUPDATE
-
-retry_quiet 10 update_is_signed "10.0.0.101" "10.0.0.4" || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-
-# Update zone with nsupdate (reverting the above change).
-n=$((n + 1))
-echo_i "nsupdate zone and check that new record is signed for zone ${ZONE} ($n)"
-ret=0
-(
-  echo zone ${ZONE}
-  echo server 10.53.0.3 "$PORT"
-  echo update add "a.${ZONE}" 300 A 10.0.0.1
-  echo update del "a.${ZONE}" 300 A 10.0.0.101
-  echo update del "d.${ZONE}" 300 A 10.0.0.4
-  echo send
-) | $NSUPDATE
-
-retry_quiet 10 update_is_signed "10.0.0.1" "-" || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-
-# Update zone with freeze/thaw.
-n=$((n + 1))
-echo_i "modify zone file and check that new record is signed for zone ${ZONE} ($n)"
-ret=0
-rndccmd 10.53.0.3 freeze "$ZONE" >/dev/null || log_error "rndc freeze zone ${ZONE} failed"
-sleep 1
-echo "d.${ZONE}. 300 A 10.0.0.44" >>"${DIR}/${ZONE}.db"
-rndccmd 10.53.0.3 thaw "$ZONE" >/dev/null || log_error "rndc thaw zone ${ZONE} failed"
-
-retry_quiet 10 update_is_signed "10.0.0.1" "10.0.0.44" || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-
-#
-# Zone: dynamic-inline-signing.kasp
-#
-set_zone "dynamic-inline-signing.kasp"
-set_dynamic
-set_policy "default" "1" "3600"
-set_server "ns3" "10.53.0.3"
-# Key properties, timings and states same as above.
-check_keys
-check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
-set_keytimes_csk_policy
-check_keytimes
-check_apex
-check_subdomain
-dnssec_verify
-
-# Update zone with freeze/thaw.
-n=$((n + 1))
-echo_i "modify unsigned zone file and check that new record is signed for zone ${ZONE} ($n)"
-ret=0
-rndccmd 10.53.0.3 freeze "$ZONE" >/dev/null || log_error "rndc freeze zone ${ZONE} failed"
-sleep 1
-cp "${DIR}/template2.db.in" "${DIR}/${ZONE}.db"
-rndccmd 10.53.0.3 thaw "$ZONE" >/dev/null || log_error "rndc thaw zone ${ZONE} failed"
-
-retry_quiet 10 update_is_signed || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-
-#
-# Zone: dynamic-signed-inline-signing.kasp
-#
-set_zone "dynamic-signed-inline-signing.kasp"
-set_dynamic
-set_policy "default" "1" "3600"
-set_server "ns3" "10.53.0.3"
-dnssec_verify
-# Ensure no zone_resigninc for the unsigned version of the zone is triggered.
-n=$((n + 1))
-echo_i "check if resigning the raw version of the zone is prevented for zone ${ZONE} ($n)"
-ret=0
-grep "zone_resigninc: zone $ZONE/IN (unsigned): enter" $DIR/named.run && ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-
-#
-# Zone: inline-signing.kasp
-#
-set_zone "inline-signing.kasp"
-set_policy "default" "1" "3600"
-set_server "ns3" "10.53.0.3"
-# Key properties, timings and states same as above.
-check_keys
-check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
-set_keytimes_csk_policy
-check_keytimes
-check_apex
-check_subdomain
-dnssec_verify
-
 #
 # Zone: checkds-ksk.kasp.
 #
index ba9217b3ee3bfb4b7ffe96b0f0dd0a76ff7037fc..3daa5eebcc7b190c24a9dd82e7fb4d03c40864af 100644 (file)
 
 import os
 import shutil
+import time
 
 from datetime import timedelta
 
 import dns
+import dns.update
 import pytest
 
 import isctest
@@ -180,6 +182,161 @@ def test_kasp_default(servers):
     isctest.kasp.check_keytimes(keys, expected)
     check_all(server, zone, policy, keys, [])
 
+    # A zone that uses inline-signing.
+    isctest.log.info("check an inline-signed zone with the default policy is signed")
+    zone = "inline-signing.kasp"
+    # Key properties.
+    key1 = KeyProperties.default()
+    keys = isctest.kasp.keydir_to_keylist(zone, "ns3")
+    expected = [key1]
+    isctest.kasp.check_zone_is_signed(server, zone)
+    isctest.kasp.check_keys(zone, keys, expected)
+    set_keytimes_default_policy(key1)
+    isctest.kasp.check_keytimes(keys, expected)
+    check_all(server, zone, policy, keys, [])
+
+
+def test_kasp_dynamic(servers):
+    # Dynamic update test cases.
+    server = servers["ns3"]
+
+    # Standard dynamic zone.
+    isctest.log.info("check dynamic zone is updated and signed after update")
+    zone = "dynamic.kasp"
+    policy = "default"
+    # Key properties.
+    key1 = KeyProperties.default()
+    expected = [key1]
+    keys = isctest.kasp.keydir_to_keylist(zone, "ns3")
+    isctest.kasp.check_zone_is_signed(server, zone)
+    isctest.kasp.check_keys(zone, keys, expected)
+    set_keytimes_default_policy(key1)
+    expected = [key1]
+    isctest.kasp.check_keytimes(keys, expected)
+    check_all(server, zone, policy, keys, [])
+
+    # Update zone with nsupdate.
+    def nsupdate(updates):
+        message = dns.update.UpdateMessage(zone)
+        for update in updates:
+            if update[0] == "del":
+                message.delete(update[1], update[2], update[3])
+            else:
+                assert update[0] == "add"
+                message.add(update[1], update[2], update[3], update[4])
+
+        try:
+            response = isctest.query.udp(
+                message, server.ip, server.ports.dns, timeout=3
+            )
+            assert response.rcode() == dns.rcode.NOERROR
+        except dns.exception.Timeout:
+            assert False, f"update timeout for {zone}"
+
+        isctest.log.debug(f"update of zone {zone} to server {server.ip} successful")
+
+    def update_is_signed():
+        parts = update.split()
+        qname = parts[0]
+        qtype = dns.rdatatype.from_text(parts[1])
+        rdata = parts[2]
+        return isctest.kasp.verify_update_is_signed(
+            server, zone, qname, qtype, rdata, keys, []
+        )
+
+    updates = [
+        ["del", f"a.{zone}.", "A", "10.0.0.1"],
+        ["add", f"a.{zone}.", 300, "A", "10.0.0.101"],
+        ["add", f"d.{zone}.", 300, "A", "10.0.0.4"],
+    ]
+    nsupdate(updates)
+
+    expected_updates = [f"a.{zone}. A 10.0.0.101", f"d.{zone}. A 10.0.0.4"]
+    for update in expected_updates:
+        isctest.run.retry_with_timeout(update_is_signed, timeout=5)
+
+    # Update zone with nsupdate (reverting the above change).
+    updates = [
+        ["add", f"a.{zone}.", 300, "A", "10.0.0.1"],
+        ["del", f"a.{zone}.", "A", "10.0.0.101"],
+        ["del", f"d.{zone}.", "A", "10.0.0.4"],
+    ]
+    nsupdate(updates)
+
+    update = f"a.{zone}. A 10.0.0.1"
+    isctest.run.retry_with_timeout(update_is_signed, timeout=5)
+
+    # Update zone with freeze/thaw.
+    isctest.log.info("check dynamic zone is updated and signed after freeze and thaw")
+    with server.watch_log_from_here() as watcher:
+        server.rndc(f"freeze {zone}", log=False)
+        watcher.wait_for_line(f"freezing zone '{zone}/IN': success")
+
+    time.sleep(1)
+    with open(f"ns3/{zone}.db", "a", encoding="utf-8") as zonefile:
+        zonefile.write(f"d.{zone}. 300 A 10.0.0.44\n")
+    time.sleep(1)
+
+    with server.watch_log_from_here() as watcher:
+        server.rndc(f"thaw {zone}", log=False)
+        watcher.wait_for_line(f"thawing zone '{zone}/IN': success")
+
+    expected_updates = [f"a.{zone}. A 10.0.0.1", f"d.{zone}. A 10.0.0.44"]
+
+    for update in expected_updates:
+        isctest.run.retry_with_timeout(update_is_signed, timeout=5)
+
+    # Dynamic, and inline-signing.
+    zone = "dynamic-inline-signing.kasp"
+    # Key properties.
+    key1 = KeyProperties.default()
+    expected = [key1]
+    keys = isctest.kasp.keydir_to_keylist(zone, "ns3")
+    isctest.kasp.check_zone_is_signed(server, zone)
+    isctest.kasp.check_keys(zone, keys, expected)
+    set_keytimes_default_policy(key1)
+    expected = [key1]
+    isctest.kasp.check_keytimes(keys, expected)
+    check_all(server, zone, policy, keys, [])
+
+    # Update zone with freeze/thaw.
+    isctest.log.info(
+        "check dynamic inline-signed zone is updated and signed after freeze and thaw"
+    )
+    with server.watch_log_from_here() as watcher:
+        server.rndc(f"freeze {zone}", log=False)
+        watcher.wait_for_line(f"freezing zone '{zone}/IN': success")
+
+    time.sleep(1)
+    shutil.copyfile("ns3/template2.db.in", f"ns3/{zone}.db")
+    time.sleep(1)
+
+    with server.watch_log_from_here() as watcher:
+        server.rndc(f"thaw {zone}", log=False)
+        watcher.wait_for_line(f"thawing zone '{zone}/IN': success")
+
+    expected_updates = [f"a.{zone}. A 10.0.0.11", f"d.{zone}. A 10.0.0.44"]
+    for update in expected_updates:
+        isctest.run.retry_with_timeout(update_is_signed, timeout=5)
+
+    # Dynamic, signed, and inline-signing.
+    isctest.log.info("check dynamic signed, and inline-signed zone")
+    zone = "dynamic-signed-inline-signing.kasp"
+    # Key properties.
+    key1 = KeyProperties.default()
+    # The ns3/setup.sh script sets all states to omnipresent.
+    key1.metadata["DNSKEYState"] = "omnipresent"
+    key1.metadata["KRRSIGState"] = "omnipresent"
+    key1.metadata["ZRRSIGState"] = "omnipresent"
+    key1.metadata["DSState"] = "omnipresent"
+    expected = [key1]
+    keys = isctest.kasp.keydir_to_keylist(zone, "ns3/keys")
+    isctest.kasp.check_zone_is_signed(server, zone)
+    isctest.kasp.check_keys(zone, keys, expected)
+    check_all(server, zone, policy, keys, [])
+    # Ensure no zone_resigninc for the unsigned version of the zone is triggered.
+    assert f"zone_resigninc: zone {zone}/IN (unsigned): enter" not in "ns3/named.run"
+
 
 def test_kasp_dnssec_keygen():
     def keygen(zone, policy, keydir=None):