The wait loop in test_checkds() called "rndc loadkeys" once per
second while polling ns9.log for expected parental-agent response
lines. Under load (notably the rbt CI job), responses to one query
batch could land after a subsequent loadkeys had already reset the
per-key DSPUBCOUNT counter in lib/dns/zone.c without cancelling the
in-flight requests. Stragglers from the earlier round then bumped the
new round's counter to parentalscnt and BIND finalized DSPublish for
zones where one parental-agent legitimately serves no DS, spuriously
failing the !DSPublish keystate assertion.
Trigger at most one loadkeys per test case and wait passively via
watch_log_from_start() / wait_for_all(). Watching from the start
of the log preserves the original implicit semantics for zones
whose DS state was already finalized by BIND's automatic checkds
polling at zone-load time -- the expected lines are already
present and the watcher returns immediately.
Assisted-by: Claude:claude-opus-4-7
(cherry picked from commit
02b6239489549e44daac123f556f851dd9949b27)
# Wait until the provided zone is signed and then verify its DNSSEC data.
zone_check(ns9, params.zone)
- # Wait up to 10 seconds until all the expected log lines are found in the
- # log file for the provided server. Rekey every second if necessary.
- time_remaining = 10
- for log_string in params.logs_to_wait_for:
- line = f"zone {params.zone}/IN (signed): checkds: {log_string}"
- while line not in ns9.log:
- ns9.rndc(f"loadkeys {params.zone}")
- time_remaining -= 1
- assert time_remaining, f'Timed out waiting for "{log_string}" to be logged'
- time.sleep(1)
+ # Trigger a single checkds round and wait for all expected parental-
+ # agent response lines.
+ patterns = [
+ f"zone {params.zone}/IN (signed): checkds: {s}" for s in params.logs_to_wait_for
+ ]
+ with ns9.watch_log_from_start() as watcher:
+ ns9.rndc(f"loadkeys {params.zone}")
+ watcher.wait_for_all(patterns)
# Check whether key states on the parent server provided match
# expectations.