--- /dev/null
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+from re import compile as Re
+
+import time
+
+import isctest
+
+DUMP_FILE_NAME = "ns2/named_dump.db"
+
+
+def warmup_cache(ns):
+ # Let's flush all caches first so we're sure the query will fully run into the resolver.
+ flush_caches(ns, "flush", "", "flushing caches in all views succeeded")
+ msg = isctest.query.create("gee.foo.bar.com.", "A")
+ res = isctest.query.udp(msg, ns.ip)
+ isctest.check.noerror(res)
+ msg = isctest.query.create("whatever.lame-and-expired-soon.bar.com.", "A")
+ # This will fail, we don't care, this is just to have the entry in the cache
+ isctest.query.udp(msg, ns.ip)
+ assert len(res.answer) == 1
+
+
+def check_cache_expired(ns):
+ time.sleep(2)
+ with ns.watch_log_from_here() as watcher:
+ ns.rndc("dumpdb -expired")
+ watcher.wait_for_line("dumpdb complete")
+ with isctest.log.WatchLogFromStart(DUMP_FILE_NAME) as watcher:
+ patterns = [
+ Re("lame-and-expired-soon.bar.com. 0 DELEG server-name=ns.somehost.com."),
+ Re("foo.bar.com. 99999[5-9] DELEG server-name=ns.somehost.com."),
+ ]
+ watcher.wait_for_all(patterns)
+
+
+def check_cache(ns, hit):
+ with ns.watch_log_from_here() as watcher:
+ ns.rndc("dumpdb -deleg")
+ watcher.wait_for_line("dumpdb complete")
+ with isctest.log.WatchLogFromStart(DUMP_FILE_NAME) as watcher:
+ if hit:
+ pattern = Re("foo.bar.com. 99999[5-9] DELEG server-name=ns.somehost.com.")
+ watcher.wait_for_line(pattern)
+ else:
+ seq = ["; Delegation cache", ";", ";", "; Start view _bind"]
+ watcher.wait_for_sequence(seq)
+
+
+def reload_server(ns):
+ with ns.watch_log_from_here() as watcher:
+ ns.rndc("reload")
+ watcher.wait_for_line("running")
+ with ns.watch_log_from_here() as watcher:
+ ns.rndc("reconfig")
+ watcher.wait_for_line("running")
+
+
+def flush_caches(ns, flushcmd, flusharg, confirm):
+ with ns.watch_log_from_here() as watcher:
+ ns.rndc(f"{flushcmd} {flusharg}")
+ watcher.wait_for_line(confirm)
+
+
+def test_cacheclean_deleg(ns2):
+ # Make sure the delegation cache has foo.bar.com.
+ warmup_cache(ns2)
+
+ # Flushing the cache
+ check_cache(ns2, True)
+
+ # Reloading the server keeps the cache hot
+ reload_server(ns2)
+
+ # The cache is still hot
+ check_cache(ns2, True)
+
+ # Flush the cache, and its now cold
+ flush_caches(ns2, "flush", "", "flushing caches in all views succeeded")
+ check_cache(ns2, False)
+
+ # Flush just the name foo.bar.com.
+ warmup_cache(ns2)
+ check_cache(ns2, True)
+ flush_caches(
+ ns2,
+ "flushname",
+ "foo.bar.com.",
+ "flushing name 'foo.bar.com.' in delegation cache for all views succeeded",
+ )
+ check_cache(ns2, False)
+
+ # Flush the whole .com. tree (need to flush
+ warmup_cache(ns2)
+ check_cache(ns2, True)
+ flush_caches(
+ ns2,
+ "flushtree",
+ "com.",
+ "flushing tree 'com.' in DNS cache for all views succeeded",
+ )
+ check_cache(ns2, False)
+
+ # Check -expired
+ warmup_cache(ns2)
+ check_cache(ns2, True)
+ check_cache_expired(ns2)