BIND 10 master, updated. 6ac000df85625f5921e8895a1aafff5e4be3ba9c Merge branch 'master' of ssh://bind10.isc.org/var/bind10/git/bind10
BIND 10 source code commits
bind10-changes at lists.isc.org
Tue Mar 8 09:47:39 UTC 2011
The branch, master has been updated
via 6ac000df85625f5921e8895a1aafff5e4be3ba9c (commit)
via 7fef6a88c5ab2cedc5f2fa0003ae1beb7a380b9c (commit)
via e49c4b5a038981cea80bf81613efa2c538c8b3e0 (commit)
via ccd3fea75828ec4e0e2b20d8bba1d7b103164141 (commit)
via a663b567f5a57c19c033de049219e4a5eb6d936b (commit)
via 4cf5938f86b3c1a54beac417f6723505183ddf11 (commit)
via 977a6a742c821ed49fc7d977f917b47f23563bdb (commit)
via bdc63200a7e2adcde2b0ce44aaeb8477fb059d17 (commit)
via e0d5584bdb3ca05b078693787c35d8f8f9228040 (commit)
via 4596c143eadfb9d67c5395bb6fa367470976d0cb (commit)
via f3bd834c8e9334004994c33d0798ed6b61a7a99b (commit)
via 860a2965d04f80fd0e90d3c5100332a8bb2ae9d8 (commit)
via c4f4d32eed0f4c26e4968336179a1e749e925aa7 (commit)
via 26582526e20e56ea4547a447cfa93e122af0f0e1 (commit)
via 6934390c92855d4006b727e1c8c1c89688afeb5f (commit)
via 333edc6244dafdab42258b84a46237c6dcf936a0 (commit)
via 8af2ccd45c7f070d2aa168763815fe8a82808e79 (commit)
via 19f9f10fa5594bfe311688823fba5dd149e76a59 (commit)
via 5851a6cc19356b49fcc2500f5d40e7861874561e (commit)
via 8be2bf19228473f5d54f5015e893b44791a5c0c2 (commit)
via edfcbcaccbf4b8098f5cfc1bd1943fe4542b3306 (commit)
via 7396247046ccc046d711265100aa8d46be057626 (commit)
via 9c3f27137967b5f92c430baab6ab442258d9d692 (commit)
via 56df4f9ab31b300b83c26fbeb1a7cf7951f8338e (commit)
via 2298392e3ce9b5a470f4c0e3b2a22ba571f9b8ab (commit)
via 309d02a51ee22ff4c0226784ecd7bb4394d19542 (commit)
via ddd7b7c3dfdebae68e3742e175e4931f0a5f6c5e (commit)
via a2609d0762b9dfdf2750a1bc44ea33525c634f5b (commit)
via de130e6d9b6dec3586126f660123a905cc9a284a (commit)
via 53b5297513ee2320556dead019f268e79b49f77a (commit)
via a9211d7973042503353e61f0e16ea092c0f621bf (commit)
via 48211526895ce56de771e65a7e6d23892c639660 (commit)
from b0c4e1599b68046bbd72455ce90433285b226ffe (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 6ac000df85625f5921e8895a1aafff5e4be3ba9c
Merge: 7fef6a8 b0c4e15
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Tue Mar 8 01:47:28 2011 -0800
Merge branch 'master' of ssh://bind10.isc.org/var/bind10/git/bind10
commit 7fef6a88c5ab2cedc5f2fa0003ae1beb7a380b9c
Merge: e49c4b5 56f0f77
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Tue Mar 8 01:46:48 2011 -0800
Merge branch 'master' of ssh://bind10.isc.org/var/bind10/git/bind10
commit e49c4b5a038981cea80bf81613efa2c538c8b3e0
Merge: 2495b96 ccd3fea
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Tue Mar 8 01:34:49 2011 -0800
[master] Merge branch 'trac606' with resolving (strange) conflicts.
Conflicts:
tests/system/{cleanall.sh, conf.sh.in, ifconfig.sh, run.sh, runall.sh}
These were actually re-added to the tree.
-----------------------------------------------------------------------
Summary of changes:
Makefile.am | 7 +-
configure.ac | 13 ++
src/bin/auth/main.cc | 8 +-
src/bin/bind10/bind10.py.in | 34 +++
.../tests/{bind10_test.py => bind10_test.py.in} | 51 +++++-
src/bin/cfgmgr/b10-cfgmgr.py.in | 14 +-
src/bin/xfrout/xfrout.py.in | 6 +-
tests/Makefile.am | 1 +
tests/system/Makefile.am | 13 ++
tests/system/README | 62 ++++++
tests/system/cleanall.sh | 33 +++
tests/system/conf.sh.in | 54 +++++
tests/system/glue/auth.good | 15 ++
tests/system/glue/clean.sh | 23 ++
tests/system/glue/example.good | 19 ++
tests/system/glue/noglue.good | 14 ++
tests/system/glue/nsx1/b10-config.db.in | 9 +
tests/system/glue/nsx1/com.db | 31 +++
tests/system/glue/nsx1/net.db | 32 +++
tests/system/glue/nsx1/root-servers.nil.db | 26 +++
tests/system/glue/nsx1/root.db | 55 +++++
tests/system/glue/setup.sh.in | 29 +++
tests/system/glue/test.good | 19 ++
tests/system/glue/tests.sh | 66 ++++++
tests/system/ifconfig.sh | 226 ++++++++++++++++++++
tests/system/run.sh | 125 +++++++++++
tests/system/runall.sh | 44 ++++
tests/system/start.pl | 226 ++++++++++++++++++++
tests/system/stop.pl | 188 ++++++++++++++++
29 files changed, 1435 insertions(+), 8 deletions(-)
rename src/bin/bind10/tests/{bind10_test.py => bind10_test.py.in} (88%)
create mode 100644 tests/Makefile.am
create mode 100644 tests/system/Makefile.am
create mode 100644 tests/system/README
create mode 100755 tests/system/cleanall.sh
create mode 100755 tests/system/conf.sh.in
create mode 100644 tests/system/glue/auth.good
create mode 100755 tests/system/glue/clean.sh
create mode 100644 tests/system/glue/example.good
create mode 100644 tests/system/glue/noglue.good
create mode 100644 tests/system/glue/nsx1/b10-config.db.in
create mode 100644 tests/system/glue/nsx1/com.db
create mode 100644 tests/system/glue/nsx1/net.db
create mode 100644 tests/system/glue/nsx1/root-servers.nil.db
create mode 100644 tests/system/glue/nsx1/root.db
create mode 100755 tests/system/glue/setup.sh.in
create mode 100644 tests/system/glue/test.good
create mode 100755 tests/system/glue/tests.sh
create mode 100755 tests/system/ifconfig.sh
create mode 100755 tests/system/run.sh
create mode 100755 tests/system/runall.sh
create mode 100755 tests/system/start.pl
create mode 100755 tests/system/stop.pl
-----------------------------------------------------------------------
diff --git a/Makefile.am b/Makefile.am
index 9a28f20..e31a1a5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = doc src
+SUBDIRS = doc src tests
USE_LCOV=@USE_LCOV@
LCOV=@LCOV@
GENHTML=@GENHTML@
@@ -77,6 +77,11 @@ cppcheck:
--template '{file}:{line}: check_fail: {message} ({severity},{id})' \
src
+# system tests
+systest:
+ cd tests/system; \
+ sh $(abs_srcdir)/tests/system/runall.sh
+
#### include external sources in the distributed tarball:
EXTRA_DIST = ext/asio/README
EXTRA_DIST += ext/asio/asio/local/stream_protocol.hpp
diff --git a/configure.ac b/configure.ac
index 0f34b0d..56a5744 100644
--- a/configure.ac
+++ b/configure.ac
@@ -583,6 +583,12 @@ if test "X$ac_cv_have_devpoll" = "Xyes" -a "X$GXX" = "Xyes"; then
CPPFLAGS="$CPPFLAGS -DASIO_DISABLE_DEV_POLL=1"
fi
+#
+# Perl is optional; it is used only by some of the system test scripts.
+#
+AC_PATH_PROGS(PERL, perl5 perl)
+AC_SUBST(PERL)
+
AC_ARG_ENABLE(man, [AC_HELP_STRING([--enable-man],
[regenerate man pages [default=no]])], enable_man=yes, enable_man=no)
@@ -683,6 +689,8 @@ AC_CONFIG_FILES([Makefile
src/lib/cache/tests/Makefile
src/lib/server_common/Makefile
src/lib/server_common/tests/Makefile
+ tests/Makefile
+ tests/system/Makefile
])
AC_OUTPUT([doc/version.ent
src/bin/cfgmgr/b10-cfgmgr.py
@@ -712,6 +720,7 @@ AC_OUTPUT([doc/version.ent
src/bin/stats/tests/stats_test
src/bin/bind10/bind10.py
src/bin/bind10/tests/bind10_test
+ src/bin/bind10/tests/bind10_test.py
src/bin/bind10/run_bind10.sh
src/bin/bindctl/run_bindctl.sh
src/bin/bindctl/bindctl-source.py
@@ -739,6 +748,9 @@ AC_OUTPUT([doc/version.ent
src/lib/cc/session_config.h.pre
src/lib/cc/tests/session_unittests_config.h
src/lib/log/tests/run_time_init_test.sh
+ tests/system/conf.sh
+ tests/system/glue/setup.sh
+ tests/system/glue/nsx1/b10-config.db
], [
chmod +x src/bin/cmdctl/run_b10-cmdctl.sh
chmod +x src/bin/xfrin/run_b10-xfrin.sh
@@ -763,6 +775,7 @@ AC_OUTPUT([doc/version.ent
chmod +x src/lib/dns/gen-rdatacode.py
chmod +x src/lib/dns/tests/testdata/gen-wiredata.py
chmod +x src/lib/log/tests/run_time_init_test.sh
+ chmod +x tests/system/conf.sh
])
AC_OUTPUT
diff --git a/src/bin/auth/main.cc b/src/bin/auth/main.cc
index 275ae7d..0701b94 100644
--- a/src/bin/auth/main.cc
+++ b/src/bin/auth/main.cc
@@ -122,7 +122,13 @@ main(int argc, char* argv[]) {
ModuleCCSession* config_session = NULL;
string xfrout_socket_path;
if (getenv("B10_FROM_BUILD") != NULL) {
- xfrout_socket_path = string(getenv("B10_FROM_BUILD")) + "/auth_xfrout_conn";
+ if (getenv("B10_FROM_SOURCE_LOCALSTATEDIR")) {
+ xfrout_socket_path = string("B10_FROM_SOURCE_LOCALSTATEDIR") +
+ "/auth_xfrout_conn";
+ } else {
+ xfrout_socket_path = string(getenv("B10_FROM_BUILD")) +
+ "/auth_xfrout_conn";
+ }
} else {
xfrout_socket_path = UNIX_SOCKET_FILE;
}
diff --git a/src/bin/bind10/bind10.py.in b/src/bin/bind10/bind10.py.in
index 83acf1f..ce6e523 100755
--- a/src/bin/bind10/bind10.py.in
+++ b/src/bin/bind10/bind10.py.in
@@ -785,6 +785,35 @@ def process_rename(option, opt_str, value, parser):
"""Function that renames the process if it is requested by a option."""
isc.util.process.rename(value)
+def dump_pid(pid_file):
+ """
+ Dump the PID of the current process to the specified file. If the given
+ file is None this function does nothing. If the file already exists,
+ the existing content will be removed. If a system error happens in
+ creating or writing to the file, the corresponding exception will be
+ propagated to the caller.
+ """
+ if pid_file is None:
+ return
+ f = open(pid_file, "w")
+ f.write('%d\n' % os.getpid())
+ f.close()
+
+def unlink_pid_file(pid_file):
+ """
+ Remove the given file, which is basically expected to be the PID file
+ created by dump_pid(). The specified may or may not exist; if it
+ doesn't this function does nothing. Other system level errors in removing
+ the file will be propagated as the corresponding exception.
+ """
+ if pid_file is None:
+ return
+ try:
+ os.unlink(pid_file)
+ except OSError as error:
+ if error.errno is not errno.ENOENT:
+ raise
+
def main():
global options
global boss_of_bind
@@ -805,6 +834,9 @@ def main():
parser.add_option("--pretty-name", type="string", action="callback",
callback=process_rename,
help="Set the process name (displayed in ps, top, ...)")
+ parser.add_option("--pid-file", dest="pid_file", type="string",
+ default=None,
+ help="file to dump the PID of the BIND 10 process")
(options, args) = parser.parse_args()
if args:
parser.print_help()
@@ -865,6 +897,7 @@ def main():
sys.stderr.write("[bind10] Error on startup: %s\n" % startup_result)
sys.exit(1)
sys.stdout.write("[bind10] BIND 10 started\n")
+ dump_pid(options.pid_file)
# send "bind10.boot_time" to b10-stats
time.sleep(1) # wait a second
@@ -918,6 +951,7 @@ def main():
signal.signal(signal.SIGCHLD, signal.SIG_DFL)
boss_of_bind.shutdown()
sys.stdout.write("[bind10] BIND 10 exiting\n");
+ unlink_pid_file(options.pid_file)
sys.exit(0)
if __name__ == "__main__":
diff --git a/src/bin/bind10/tests/bind10_test.py b/src/bin/bind10/tests/bind10_test.py
deleted file mode 100644
index f3fe949..0000000
--- a/src/bin/bind10/tests/bind10_test.py
+++ /dev/null
@@ -1,416 +0,0 @@
-from bind10 import ProcessInfo, BoB
-
-# XXX: environment tests are currently disabled, due to the preprocessor
-# setup that we have now complicating the environment
-
-import unittest
-import sys
-import os
-import signal
-import socket
-from isc.net.addr import IPAddr
-
-class TestProcessInfo(unittest.TestCase):
- def setUp(self):
- # redirect stdout to a pipe so we can check that our
- # process spawning is doing the right thing with stdout
- self.old_stdout = os.dup(sys.stdout.fileno())
- self.pipes = os.pipe()
- os.dup2(self.pipes[1], sys.stdout.fileno())
- os.close(self.pipes[1])
- # note that we use dup2() to restore the original stdout
- # to the main program ASAP in each test... this prevents
- # hangs reading from the child process (as the pipe is only
- # open in the child), and also insures nice pretty output
-
- def tearDown(self):
- # clean up our stdout munging
- os.dup2(self.old_stdout, sys.stdout.fileno())
- os.close(self.pipes[0])
-
- def test_init(self):
- pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ])
- os.dup2(self.old_stdout, sys.stdout.fileno())
- self.assertEqual(pi.name, 'Test Process')
- self.assertEqual(pi.args, [ '/bin/echo', 'foo' ])
-# self.assertEqual(pi.env, { 'PATH': os.environ['PATH'],
-# 'PYTHON_EXEC': os.environ['PYTHON_EXEC'] })
- self.assertEqual(pi.dev_null_stdout, False)
- self.assertEqual(os.read(self.pipes[0], 100), b"foo\n")
- self.assertNotEqual(pi.process, None)
- self.assertTrue(type(pi.pid) is int)
-
-# def test_setting_env(self):
-# pi = ProcessInfo('Test Process', [ '/bin/true' ], env={'FOO': 'BAR'})
-# os.dup2(self.old_stdout, sys.stdout.fileno())
-# self.assertEqual(pi.env, { 'PATH': os.environ['PATH'],
-# 'PYTHON_EXEC': os.environ['PYTHON_EXEC'],
-# 'FOO': 'BAR' })
-
- def test_setting_null_stdout(self):
- pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ],
- dev_null_stdout=True)
- os.dup2(self.old_stdout, sys.stdout.fileno())
- self.assertEqual(pi.dev_null_stdout, True)
- self.assertEqual(os.read(self.pipes[0], 100), b"")
-
- def test_respawn(self):
- pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ])
- # wait for old process to work...
- self.assertEqual(os.read(self.pipes[0], 100), b"foo\n")
- # respawn it
- old_pid = pi.pid
- pi.respawn()
- os.dup2(self.old_stdout, sys.stdout.fileno())
- # make sure the new one started properly
- self.assertEqual(pi.name, 'Test Process')
- self.assertEqual(pi.args, [ '/bin/echo', 'foo' ])
-# self.assertEqual(pi.env, { 'PATH': os.environ['PATH'],
-# 'PYTHON_EXEC': os.environ['PYTHON_EXEC'] })
- self.assertEqual(pi.dev_null_stdout, False)
- self.assertEqual(os.read(self.pipes[0], 100), b"foo\n")
- self.assertNotEqual(pi.process, None)
- self.assertTrue(type(pi.pid) is int)
- self.assertNotEqual(pi.pid, old_pid)
-
-class TestBoB(unittest.TestCase):
- def test_init(self):
- bob = BoB()
- self.assertEqual(bob.verbose, False)
- self.assertEqual(bob.msgq_socket_file, None)
- self.assertEqual(bob.cc_session, None)
- self.assertEqual(bob.ccs, None)
- self.assertEqual(bob.processes, {})
- self.assertEqual(bob.dead_processes, {})
- self.assertEqual(bob.runnable, False)
- self.assertEqual(bob.uid, None)
- self.assertEqual(bob.username, None)
- self.assertEqual(bob.nocache, False)
- self.assertEqual(bob.cfg_start_auth, True)
- self.assertEqual(bob.cfg_start_resolver, False)
-
- def test_init_alternate_socket(self):
- bob = BoB("alt_socket_file")
- self.assertEqual(bob.verbose, False)
- self.assertEqual(bob.msgq_socket_file, "alt_socket_file")
- self.assertEqual(bob.cc_session, None)
- self.assertEqual(bob.ccs, None)
- self.assertEqual(bob.processes, {})
- self.assertEqual(bob.dead_processes, {})
- self.assertEqual(bob.runnable, False)
- self.assertEqual(bob.uid, None)
- self.assertEqual(bob.username, None)
- self.assertEqual(bob.nocache, False)
- self.assertEqual(bob.cfg_start_auth, True)
- self.assertEqual(bob.cfg_start_resolver, False)
-
-# Class for testing the BoB start/stop components routines.
-#
-# Although testing that external processes start is outside the scope
-# of the unit test, by overriding the process start methods we can check
-# that the right processes are started depending on the configuration
-# options.
-class StartStopCheckBob(BoB):
- def __init__(self):
- BoB.__init__(self)
-
-# Set flags as to which of the overridden methods has been run.
- self.msgq = False
- self.cfgmgr = False
- self.ccsession = False
- self.auth = False
- self.resolver = False
- self.xfrout = False
- self.xfrin = False
- self.zonemgr = False
- self.stats = False
- self.cmdctl = False
- self.c_channel_env = {}
-
- def read_bind10_config(self):
- # Configuration options are set directly
- pass
-
- def start_msgq(self, c_channel_env):
- self.msgq = True
-
- def start_cfgmgr(self, c_channel_env):
- self.cfgmgr = True
-
- def start_ccsession(self, c_channel_env):
- self.ccsession = True
-
- def start_auth(self, c_channel_env):
- self.auth = True
-
- def start_resolver(self, c_channel_env):
- self.resolver = True
-
- def start_xfrout(self, c_channel_env):
- self.xfrout = True
-
- def start_xfrin(self, c_channel_env):
- self.xfrin = True
-
- def start_zonemgr(self, c_channel_env):
- self.zonemgr = True
-
- def start_stats(self, c_channel_env):
- self.stats = True
-
- def start_cmdctl(self, c_channel_env):
- self.cmdctl = True
-
- # We don't really use all of these stop_ methods. But it might turn out
- # someone would add some stop_ method to BoB and we want that one overriden
- # in case he forgets to update the tests.
- def stop_msgq(self):
- self.msgq = False
-
- def stop_cfgmgr(self):
- self.cfgmgr = False
-
- def stop_ccsession(self):
- self.ccsession = False
-
- def stop_auth(self):
- self.auth = False
-
- def stop_resolver(self):
- self.resolver = False
-
- def stop_xfrout(self):
- self.xfrout = False
-
- def stop_xfrin(self):
- self.xfrin = False
-
- def stop_zonemgr(self):
- self.zonemgr = False
-
- def stop_stats(self):
- self.stats = False
-
- def stop_cmdctl(self):
- self.cmdctl = False
-
-class TestStartStopProcessesBob(unittest.TestCase):
- """
- Check that the start_all_processes method starts the right combination
- of processes and that the right processes are started and stopped
- according to changes in configuration.
- """
- def check_started(self, bob, core, auth, resolver):
- """
- Check that the right sets of services are started. The ones that
- should be running are specified by the core, auth and resolver parameters
- (they are groups of processes, eg. auth means b10-auth, -xfrout, -xfrin
- and -zonemgr).
- """
- self.assertEqual(bob.msgq, core)
- self.assertEqual(bob.cfgmgr, core)
- self.assertEqual(bob.ccsession, core)
- self.assertEqual(bob.auth, auth)
- self.assertEqual(bob.resolver, resolver)
- self.assertEqual(bob.xfrout, auth)
- self.assertEqual(bob.xfrin, auth)
- self.assertEqual(bob.zonemgr, auth)
- self.assertEqual(bob.stats, core)
- self.assertEqual(bob.cmdctl, core)
-
- def check_preconditions(self, bob):
- self.check_started(bob, False, False, False)
-
- def check_started_none(self, bob):
- """
- Check that the situation is according to configuration where no servers
- should be started. Some processes still need to be running.
- """
- self.check_started(bob, True, False, False)
-
- def check_started_both(self, bob):
- """
- Check the situation is according to configuration where both servers
- (auth and resolver) are enabled.
- """
- self.check_started(bob, True, True, True)
-
- def check_started_auth(self, bob):
- """
- Check the set of processes needed to run auth only is started.
- """
- self.check_started(bob, True, True, False)
-
- def check_started_resolver(self, bob):
- """
- Check the set of processes needed to run resolver only is started.
- """
- self.check_started(bob, True, False, True)
-
- # Checks the processes started when starting neither auth nor resolver
- # is specified.
- def test_start_none(self):
- # Create BoB and ensure correct initialization
- bob = StartStopCheckBob()
- self.check_preconditions(bob)
-
- # Start processes and check what was started
- bob.cfg_start_auth = False
- bob.cfg_start_resolver = False
-
- bob.start_all_processes()
- self.check_started_none(bob)
-
- # Checks the processes started when starting only the auth process
- def test_start_auth(self):
- # Create BoB and ensure correct initialization
- bob = StartStopCheckBob()
- self.check_preconditions(bob)
-
- # Start processes and check what was started
- bob.cfg_start_auth = True
- bob.cfg_start_resolver = False
-
- bob.start_all_processes()
-
- self.check_started_auth(bob)
-
- # Checks the processes started when starting only the resolver process
- def test_start_resolver(self):
- # Create BoB and ensure correct initialization
- bob = StartStopCheckBob()
- self.check_preconditions(bob)
-
- # Start processes and check what was started
- bob.cfg_start_auth = False
- bob.cfg_start_resolver = True
-
- bob.start_all_processes()
-
- self.check_started_resolver(bob)
-
- # Checks the processes started when starting both auth and resolver process
- def test_start_both(self):
- # Create BoB and ensure correct initialization
- bob = StartStopCheckBob()
- self.check_preconditions(bob)
-
- # Start processes and check what was started
- bob.cfg_start_auth = True
- bob.cfg_start_resolver = True
-
- bob.start_all_processes()
-
- self.check_started_both(bob)
-
- def test_config_start(self):
- """
- Test that the configuration starts and stops processes according
- to configuration changes.
- """
-
- # Create BoB and ensure correct initialization
- bob = StartStopCheckBob()
- self.check_preconditions(bob)
-
- # Start processes (nothing much should be started, as in
- # test_start_none)
- bob.cfg_start_auth = False
- bob.cfg_start_resolver = False
-
- bob.start_all_processes()
- bob.runnable = True
- self.check_started_none(bob)
-
- # Enable both at once
- bob.config_handler({'start_auth': True, 'start_resolver': True})
- self.check_started_both(bob)
-
- # Not touched by empty change
- bob.config_handler({})
- self.check_started_both(bob)
-
- # Not touched by change to the same configuration
- bob.config_handler({'start_auth': True, 'start_resolver': True})
- self.check_started_both(bob)
-
- # Turn them both off again
- bob.config_handler({'start_auth': False, 'start_resolver': False})
- self.check_started_none(bob)
-
- # Not touched by empty change
- bob.config_handler({})
- self.check_started_none(bob)
-
- # Not touched by change to the same configuration
- bob.config_handler({'start_auth': False, 'start_resolver': False})
- self.check_started_none(bob)
-
- # Start and stop auth separately
- bob.config_handler({'start_auth': True})
- self.check_started_auth(bob)
-
- bob.config_handler({'start_auth': False})
- self.check_started_none(bob)
-
- # Start and stop resolver separately
- bob.config_handler({'start_resolver': True})
- self.check_started_resolver(bob)
-
- bob.config_handler({'start_resolver': False})
- self.check_started_none(bob)
-
- # Alternate
- bob.config_handler({'start_auth': True})
- self.check_started_auth(bob)
-
- bob.config_handler({'start_auth': False, 'start_resolver': True})
- self.check_started_resolver(bob)
-
- bob.config_handler({'start_auth': True, 'start_resolver': False})
- self.check_started_auth(bob)
-
- def test_config_start_once(self):
- """
- Tests that a process is started only once.
- """
- # Create BoB and ensure correct initialization
- bob = StartStopCheckBob()
- self.check_preconditions(bob)
-
- # Start processes (both)
- bob.cfg_start_auth = True
- bob.cfg_start_resolver = True
-
- bob.start_all_processes()
- bob.runnable = True
- self.check_started_both(bob)
-
- bob.start_auth = lambda: self.fail("Started auth again")
- bob.start_xfrout = lambda: self.fail("Started xfrout again")
- bob.start_xfrin = lambda: self.fail("Started xfrin again")
- bob.start_zonemgr = lambda: self.fail("Started zonemgr again")
- bob.start_resolver = lambda: self.fail("Started resolver again")
-
- # Send again we want to start them. Should not do it, as they are.
- bob.config_handler({'start_auth': True})
- bob.config_handler({'start_resolver': True})
-
- def test_config_not_started_early(self):
- """
- Test that processes are not started by the config handler before
- startup.
- """
- bob = StartStopCheckBob()
- self.check_preconditions(bob)
-
- bob.start_auth = lambda: self.fail("Started auth again")
- bob.start_xfrout = lambda: self.fail("Started xfrout again")
- bob.start_xfrin = lambda: self.fail("Started xfrin again")
- bob.start_zonemgr = lambda: self.fail("Started zonemgr again")
- bob.start_resolver = lambda: self.fail("Started resolver again")
-
- bob.config_handler({'start_auth': True, 'start_resolver': True})
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/src/bin/bind10/tests/bind10_test.py.in b/src/bin/bind10/tests/bind10_test.py.in
new file mode 100644
index 0000000..0603443
--- /dev/null
+++ b/src/bin/bind10/tests/bind10_test.py.in
@@ -0,0 +1,463 @@
+from bind10 import ProcessInfo, BoB, dump_pid, unlink_pid_file
+
+# XXX: environment tests are currently disabled, due to the preprocessor
+# setup that we have now complicating the environment
+
+import unittest
+import sys
+import os
+import signal
+import socket
+from isc.net.addr import IPAddr
+
+class TestProcessInfo(unittest.TestCase):
+ def setUp(self):
+ # redirect stdout to a pipe so we can check that our
+ # process spawning is doing the right thing with stdout
+ self.old_stdout = os.dup(sys.stdout.fileno())
+ self.pipes = os.pipe()
+ os.dup2(self.pipes[1], sys.stdout.fileno())
+ os.close(self.pipes[1])
+ # note that we use dup2() to restore the original stdout
+ # to the main program ASAP in each test... this prevents
+ # hangs reading from the child process (as the pipe is only
+ # open in the child), and also insures nice pretty output
+
+ def tearDown(self):
+ # clean up our stdout munging
+ os.dup2(self.old_stdout, sys.stdout.fileno())
+ os.close(self.pipes[0])
+
+ def test_init(self):
+ pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ])
+ os.dup2(self.old_stdout, sys.stdout.fileno())
+ self.assertEqual(pi.name, 'Test Process')
+ self.assertEqual(pi.args, [ '/bin/echo', 'foo' ])
+# self.assertEqual(pi.env, { 'PATH': os.environ['PATH'],
+# 'PYTHON_EXEC': os.environ['PYTHON_EXEC'] })
+ self.assertEqual(pi.dev_null_stdout, False)
+ self.assertEqual(os.read(self.pipes[0], 100), b"foo\n")
+ self.assertNotEqual(pi.process, None)
+ self.assertTrue(type(pi.pid) is int)
+
+# def test_setting_env(self):
+# pi = ProcessInfo('Test Process', [ '/bin/true' ], env={'FOO': 'BAR'})
+# os.dup2(self.old_stdout, sys.stdout.fileno())
+# self.assertEqual(pi.env, { 'PATH': os.environ['PATH'],
+# 'PYTHON_EXEC': os.environ['PYTHON_EXEC'],
+# 'FOO': 'BAR' })
+
+ def test_setting_null_stdout(self):
+ pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ],
+ dev_null_stdout=True)
+ os.dup2(self.old_stdout, sys.stdout.fileno())
+ self.assertEqual(pi.dev_null_stdout, True)
+ self.assertEqual(os.read(self.pipes[0], 100), b"")
+
+ def test_respawn(self):
+ pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ])
+ # wait for old process to work...
+ self.assertEqual(os.read(self.pipes[0], 100), b"foo\n")
+ # respawn it
+ old_pid = pi.pid
+ pi.respawn()
+ os.dup2(self.old_stdout, sys.stdout.fileno())
+ # make sure the new one started properly
+ self.assertEqual(pi.name, 'Test Process')
+ self.assertEqual(pi.args, [ '/bin/echo', 'foo' ])
+# self.assertEqual(pi.env, { 'PATH': os.environ['PATH'],
+# 'PYTHON_EXEC': os.environ['PYTHON_EXEC'] })
+ self.assertEqual(pi.dev_null_stdout, False)
+ self.assertEqual(os.read(self.pipes[0], 100), b"foo\n")
+ self.assertNotEqual(pi.process, None)
+ self.assertTrue(type(pi.pid) is int)
+ self.assertNotEqual(pi.pid, old_pid)
+
+class TestBoB(unittest.TestCase):
+ def test_init(self):
+ bob = BoB()
+ self.assertEqual(bob.verbose, False)
+ self.assertEqual(bob.msgq_socket_file, None)
+ self.assertEqual(bob.cc_session, None)
+ self.assertEqual(bob.ccs, None)
+ self.assertEqual(bob.processes, {})
+ self.assertEqual(bob.dead_processes, {})
+ self.assertEqual(bob.runnable, False)
+ self.assertEqual(bob.uid, None)
+ self.assertEqual(bob.username, None)
+ self.assertEqual(bob.nocache, False)
+ self.assertEqual(bob.cfg_start_auth, True)
+ self.assertEqual(bob.cfg_start_resolver, False)
+
+ def test_init_alternate_socket(self):
+ bob = BoB("alt_socket_file")
+ self.assertEqual(bob.verbose, False)
+ self.assertEqual(bob.msgq_socket_file, "alt_socket_file")
+ self.assertEqual(bob.cc_session, None)
+ self.assertEqual(bob.ccs, None)
+ self.assertEqual(bob.processes, {})
+ self.assertEqual(bob.dead_processes, {})
+ self.assertEqual(bob.runnable, False)
+ self.assertEqual(bob.uid, None)
+ self.assertEqual(bob.username, None)
+ self.assertEqual(bob.nocache, False)
+ self.assertEqual(bob.cfg_start_auth, True)
+ self.assertEqual(bob.cfg_start_resolver, False)
+
+# Class for testing the BoB start/stop components routines.
+#
+# Although testing that external processes start is outside the scope
+# of the unit test, by overriding the process start methods we can check
+# that the right processes are started depending on the configuration
+# options.
+class StartStopCheckBob(BoB):
+ def __init__(self):
+ BoB.__init__(self)
+
+# Set flags as to which of the overridden methods has been run.
+ self.msgq = False
+ self.cfgmgr = False
+ self.ccsession = False
+ self.auth = False
+ self.resolver = False
+ self.xfrout = False
+ self.xfrin = False
+ self.zonemgr = False
+ self.stats = False
+ self.cmdctl = False
+ self.c_channel_env = {}
+
+ def read_bind10_config(self):
+ # Configuration options are set directly
+ pass
+
+ def start_msgq(self, c_channel_env):
+ self.msgq = True
+
+ def start_cfgmgr(self, c_channel_env):
+ self.cfgmgr = True
+
+ def start_ccsession(self, c_channel_env):
+ self.ccsession = True
+
+ def start_auth(self, c_channel_env):
+ self.auth = True
+
+ def start_resolver(self, c_channel_env):
+ self.resolver = True
+
+ def start_xfrout(self, c_channel_env):
+ self.xfrout = True
+
+ def start_xfrin(self, c_channel_env):
+ self.xfrin = True
+
+ def start_zonemgr(self, c_channel_env):
+ self.zonemgr = True
+
+ def start_stats(self, c_channel_env):
+ self.stats = True
+
+ def start_cmdctl(self, c_channel_env):
+ self.cmdctl = True
+
+ # We don't really use all of these stop_ methods. But it might turn out
+ # someone would add some stop_ method to BoB and we want that one overriden
+ # in case he forgets to update the tests.
+ def stop_msgq(self):
+ self.msgq = False
+
+ def stop_cfgmgr(self):
+ self.cfgmgr = False
+
+ def stop_ccsession(self):
+ self.ccsession = False
+
+ def stop_auth(self):
+ self.auth = False
+
+ def stop_resolver(self):
+ self.resolver = False
+
+ def stop_xfrout(self):
+ self.xfrout = False
+
+ def stop_xfrin(self):
+ self.xfrin = False
+
+ def stop_zonemgr(self):
+ self.zonemgr = False
+
+ def stop_stats(self):
+ self.stats = False
+
+ def stop_cmdctl(self):
+ self.cmdctl = False
+
+class TestStartStopProcessesBob(unittest.TestCase):
+ """
+ Check that the start_all_processes method starts the right combination
+ of processes and that the right processes are started and stopped
+ according to changes in configuration.
+ """
+ def check_started(self, bob, core, auth, resolver):
+ """
+ Check that the right sets of services are started. The ones that
+ should be running are specified by the core, auth and resolver parameters
+ (they are groups of processes, eg. auth means b10-auth, -xfrout, -xfrin
+ and -zonemgr).
+ """
+ self.assertEqual(bob.msgq, core)
+ self.assertEqual(bob.cfgmgr, core)
+ self.assertEqual(bob.ccsession, core)
+ self.assertEqual(bob.auth, auth)
+ self.assertEqual(bob.resolver, resolver)
+ self.assertEqual(bob.xfrout, auth)
+ self.assertEqual(bob.xfrin, auth)
+ self.assertEqual(bob.zonemgr, auth)
+ self.assertEqual(bob.stats, core)
+ self.assertEqual(bob.cmdctl, core)
+
+ def check_preconditions(self, bob):
+ self.check_started(bob, False, False, False)
+
+ def check_started_none(self, bob):
+ """
+ Check that the situation is according to configuration where no servers
+ should be started. Some processes still need to be running.
+ """
+ self.check_started(bob, True, False, False)
+
+ def check_started_both(self, bob):
+ """
+ Check the situation is according to configuration where both servers
+ (auth and resolver) are enabled.
+ """
+ self.check_started(bob, True, True, True)
+
+ def check_started_auth(self, bob):
+ """
+ Check the set of processes needed to run auth only is started.
+ """
+ self.check_started(bob, True, True, False)
+
+ def check_started_resolver(self, bob):
+ """
+ Check the set of processes needed to run resolver only is started.
+ """
+ self.check_started(bob, True, False, True)
+
+ # Checks the processes started when starting neither auth nor resolver
+ # is specified.
+ def test_start_none(self):
+ # Create BoB and ensure correct initialization
+ bob = StartStopCheckBob()
+ self.check_preconditions(bob)
+
+ # Start processes and check what was started
+ bob.cfg_start_auth = False
+ bob.cfg_start_resolver = False
+
+ bob.start_all_processes()
+ self.check_started_none(bob)
+
+ # Checks the processes started when starting only the auth process
+ def test_start_auth(self):
+ # Create BoB and ensure correct initialization
+ bob = StartStopCheckBob()
+ self.check_preconditions(bob)
+
+ # Start processes and check what was started
+ bob.cfg_start_auth = True
+ bob.cfg_start_resolver = False
+
+ bob.start_all_processes()
+
+ self.check_started_auth(bob)
+
+ # Checks the processes started when starting only the resolver process
+ def test_start_resolver(self):
+ # Create BoB and ensure correct initialization
+ bob = StartStopCheckBob()
+ self.check_preconditions(bob)
+
+ # Start processes and check what was started
+ bob.cfg_start_auth = False
+ bob.cfg_start_resolver = True
+
+ bob.start_all_processes()
+
+ self.check_started_resolver(bob)
+
+ # Checks the processes started when starting both auth and resolver process
+ def test_start_both(self):
+ # Create BoB and ensure correct initialization
+ bob = StartStopCheckBob()
+ self.check_preconditions(bob)
+
+ # Start processes and check what was started
+ bob.cfg_start_auth = True
+ bob.cfg_start_resolver = True
+
+ bob.start_all_processes()
+
+ self.check_started_both(bob)
+
+ def test_config_start(self):
+ """
+ Test that the configuration starts and stops processes according
+ to configuration changes.
+ """
+
+ # Create BoB and ensure correct initialization
+ bob = StartStopCheckBob()
+ self.check_preconditions(bob)
+
+ # Start processes (nothing much should be started, as in
+ # test_start_none)
+ bob.cfg_start_auth = False
+ bob.cfg_start_resolver = False
+
+ bob.start_all_processes()
+ bob.runnable = True
+ self.check_started_none(bob)
+
+ # Enable both at once
+ bob.config_handler({'start_auth': True, 'start_resolver': True})
+ self.check_started_both(bob)
+
+ # Not touched by empty change
+ bob.config_handler({})
+ self.check_started_both(bob)
+
+ # Not touched by change to the same configuration
+ bob.config_handler({'start_auth': True, 'start_resolver': True})
+ self.check_started_both(bob)
+
+ # Turn them both off again
+ bob.config_handler({'start_auth': False, 'start_resolver': False})
+ self.check_started_none(bob)
+
+ # Not touched by empty change
+ bob.config_handler({})
+ self.check_started_none(bob)
+
+ # Not touched by change to the same configuration
+ bob.config_handler({'start_auth': False, 'start_resolver': False})
+ self.check_started_none(bob)
+
+ # Start and stop auth separately
+ bob.config_handler({'start_auth': True})
+ self.check_started_auth(bob)
+
+ bob.config_handler({'start_auth': False})
+ self.check_started_none(bob)
+
+ # Start and stop resolver separately
+ bob.config_handler({'start_resolver': True})
+ self.check_started_resolver(bob)
+
+ bob.config_handler({'start_resolver': False})
+ self.check_started_none(bob)
+
+ # Alternate
+ bob.config_handler({'start_auth': True})
+ self.check_started_auth(bob)
+
+ bob.config_handler({'start_auth': False, 'start_resolver': True})
+ self.check_started_resolver(bob)
+
+ bob.config_handler({'start_auth': True, 'start_resolver': False})
+ self.check_started_auth(bob)
+
+ def test_config_start_once(self):
+ """
+ Tests that a process is started only once.
+ """
+ # Create BoB and ensure correct initialization
+ bob = StartStopCheckBob()
+ self.check_preconditions(bob)
+
+ # Start processes (both)
+ bob.cfg_start_auth = True
+ bob.cfg_start_resolver = True
+
+ bob.start_all_processes()
+ bob.runnable = True
+ self.check_started_both(bob)
+
+ bob.start_auth = lambda: self.fail("Started auth again")
+ bob.start_xfrout = lambda: self.fail("Started xfrout again")
+ bob.start_xfrin = lambda: self.fail("Started xfrin again")
+ bob.start_zonemgr = lambda: self.fail("Started zonemgr again")
+ bob.start_resolver = lambda: self.fail("Started resolver again")
+
+ # Send again we want to start them. Should not do it, as they are.
+ bob.config_handler({'start_auth': True})
+ bob.config_handler({'start_resolver': True})
+
+ def test_config_not_started_early(self):
+ """
+ Test that processes are not started by the config handler before
+ startup.
+ """
+ bob = StartStopCheckBob()
+ self.check_preconditions(bob)
+
+ bob.start_auth = lambda: self.fail("Started auth again")
+ bob.start_xfrout = lambda: self.fail("Started xfrout again")
+ bob.start_xfrin = lambda: self.fail("Started xfrin again")
+ bob.start_zonemgr = lambda: self.fail("Started zonemgr again")
+ bob.start_resolver = lambda: self.fail("Started resolver again")
+
+ bob.config_handler({'start_auth': True, 'start_resolver': True})
+
+class TestPIDFile(unittest.TestCase):
+ def setUp(self):
+ self.pid_file = '@builddir@' + os.sep + 'bind10.pid'
+ if os.path.exists(self.pid_file):
+ os.unlink(self.pid_file)
+
+ def tearDown(self):
+ if os.path.exists(self.pid_file):
+ os.unlink(self.pid_file)
+
+ def check_pid_file(self):
+ # dump PID to the file, and confirm the content is correct
+ dump_pid(self.pid_file)
+ my_pid = os.getpid()
+ self.assertEqual(my_pid, int(open(self.pid_file, "r").read()))
+
+ def test_dump_pid(self):
+ self.check_pid_file()
+
+ # make sure any existing content will be removed
+ open(self.pid_file, "w").write('dummy data\n')
+ self.check_pid_file()
+
+ def test_unlink_pid_file_notexist(self):
+ dummy_data = 'dummy_data\n'
+ open(self.pid_file, "w").write(dummy_data)
+ unlink_pid_file("no_such_pid_file")
+ # the file specified for unlink_pid_file doesn't exist,
+ # and the original content of the file should be intact.
+ self.assertEqual(dummy_data, open(self.pid_file, "r").read())
+
+ def test_dump_pid_with_none(self):
+ # Check the behavior of dump_pid() and unlink_pid_file() with None.
+ # This should be no-op.
+ dump_pid(None)
+ self.assertFalse(os.path.exists(self.pid_file))
+
+ dummy_data = 'dummy_data\n'
+ open(self.pid_file, "w").write(dummy_data)
+ unlink_pid_file(None)
+ self.assertEqual(dummy_data, open(self.pid_file, "r").read())
+
+ def test_dump_pid_failure(self):
+ # the attempt to open file will fail, which should result in exception.
+ self.assertRaises(IOError, dump_pid,
+ 'nonexistent_dir' + os.sep + 'bind10.pid')
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/src/bin/cfgmgr/b10-cfgmgr.py.in b/src/bin/cfgmgr/b10-cfgmgr.py.in
index 659426d..e37ec48 100755
--- a/src/bin/cfgmgr/b10-cfgmgr.py.in
+++ b/src/bin/cfgmgr/b10-cfgmgr.py.in
@@ -26,10 +26,18 @@ import os
isc.util.process.rename()
# If B10_FROM_SOURCE is set in the environment, we use data files
-# from a directory relative to that, otherwise we use the ones
-# installed on the system
+# from a directory relative to the value of that variable, or, if defined,
+# relative to the value of B10_FROM_SOURCE_LOCALSTATEDIR. Otherwise
+# we use the ones installed on the system.
+# B10_FROM_SOURCE_LOCALSTATEDIR is specifically intended to be used for
+# tests where we want to use variuos types of configuration within the test
+# environment. (We may want to make it even more generic so that the path is
+# passed from the boss process)
if "B10_FROM_SOURCE" in os.environ:
- DATA_PATH = os.environ["B10_FROM_SOURCE"]
+ if "B10_FROM_SOURCE_LOCALSTATEDIR" in os.environ:
+ DATA_PATH = os.environ["B10_FROM_SOURCE_LOCALSTATEDIR"]
+ else:
+ DATA_PATH = os.environ["B10_FROM_SOURCE"]
else:
PREFIX = "@prefix@"
DATA_PATH = "@localstatedir@/@PACKAGE@".replace("${prefix}", PREFIX)
diff --git a/src/bin/xfrout/xfrout.py.in b/src/bin/xfrout/xfrout.py.in
index fd1288d..f420d4b 100755
--- a/src/bin/xfrout/xfrout.py.in
+++ b/src/bin/xfrout/xfrout.py.in
@@ -50,7 +50,11 @@ isc.util.process.rename()
if "B10_FROM_BUILD" in os.environ:
SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/xfrout"
AUTH_SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/auth"
- UNIX_SOCKET_FILE= os.environ["B10_FROM_BUILD"] + "/auth_xfrout_conn"
+ if "B10_FROM_SOURCE_LOCALSTATEDIR" in os.environ:
+ UNIX_SOCKET_FILE = os.environ["B10_FROM_SOURCE_LOCALSTATEDIR"] + \
+ "/auth_xfrout_conn"
+ else:
+ UNIX_SOCKET_FILE = os.environ["B10_FROM_BUILD"] + "/auth_xfrout_conn"
else:
PREFIX = "@prefix@"
DATAROOTDIR = "@datarootdir@"
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 0000000..d4008c0
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = system
diff --git a/tests/system/Makefile.am b/tests/system/Makefile.am
new file mode 100644
index 0000000..efd5d7f
--- /dev/null
+++ b/tests/system/Makefile.am
@@ -0,0 +1,13 @@
+systest:
+ sh $(srcdir)/runall.sh
+
+distclean-local:
+ sh $(srcdir)/cleanall.sh
+
+# Most of the files under this directory (including test subdirectories)
+# must be listed in EXTRA_DIST.
+EXTRA_DIST = README cleanall.sh ifconfig.sh start.pl stop.pl run.sh runall.sh
+EXTRA_DIST += glue/auth.good glue/example.good glue/noglue.good glue/test.good
+EXTRA_DIST += glue/tests.sh glue/clean.sh
+EXTRA_DIST += glue/nsx1/com.db glue/nsx1/net.db glue/nsx1/root-servers.nil.db
+EXTRA_DIST += glue/nsx1/root.db
diff --git a/tests/system/README b/tests/system/README
new file mode 100644
index 0000000..080652d
--- /dev/null
+++ b/tests/system/README
@@ -0,0 +1,62 @@
+Copyright (C) 2004, 2010, 2011 Internet Systems Consortium, Inc. ("ISC")
+Copyright (C) 2000, 2001 Internet Software Consortium.
+See COPYRIGHT in the source root or http://isc.org/copyright.html for terms.
+
+This is a simple test environment for running BIND 10 system tests
+involving multiple name servers. It was originally developed for BIND
+9, and has been ported to test BIND 10 implementations. Ideally we
+should share the same framework for both versions, so some part of
+the original setup are kept, even though they are BIND 9 specific and
+not currently used.
+
+Also, these tests generally rely on BIND 9 programs, most commonly its
+dig, and will sometimes be its name server (named). So, the test
+environment assumes that there's a source tree of BIND 9 where its
+programs are built, and that an environment variable "BIND9_TOP" is
+set to point to the top directory of the source tree.
+
+There are multiple test suites, each in a separate subdirectory and
+involving a different DNS setup. They are:
+
+ glue/ Glue handling tests
+(the following tests are planned to be added soon)
+ dnssec/ DNSSEC tests
+ masterfile/ Master file parser
+ xfer/ Zone transfer tests
+
+Typically each test suite sets up 2-5 instances of BIND 10 (or BIND 9
+named) and then performs one or more tests against them. Within the
+test suite subdirectory, each instance has a separate subdirectory
+containing its configuration data. By convention, these
+subdirectories are named "nsx1", "nsx2", etc for BIND 10 ("x" means
+BIND 10), and "ns1", "ns2", etc. for BIND 9.
+
+The tests are completely self-contained and do not require access to
+the real DNS. Generally, one of the test servers (ns[x]1) is set up
+as a root name server and is listed in the hints file of the others.
+
+To enable all servers to run on the same machine, they bind to
+separate virtual IP address on the loopback interface. ns[x]1 runs on
+10.53.0.1, ns[x]2 on 10.53.0.2, etc. Before running any tests, you
+must set up these addresses by running "ifconfig.sh up" as root.
+
+Mac OS X:
+If you wish to make the interfaces survive across reboots
+copy org.isc.bind.system and org.isc.bind.system to
+/Library/LaunchDaemons then run
+"launchctl load /Library/LaunchDaemons/org.isc.bind.system.plist" as
+root.
+
+The servers use port 53210 instead of the usual port 53, so they can be
+run without root privileges once the interfaces have been set up.
+
+The tests can be run individually like this:
+
+ sh run.sh xfer
+ sh run.sh glue
+ etc.
+
+To run all the tests, just type "make systest" either on this directory
+or on the top source directory. Note: currently these tests cannot be
+run when built under a separate build directory. Everything must be
+run within the original source tree.
diff --git a/tests/system/cleanall.sh b/tests/system/cleanall.sh
new file mode 100755
index 0000000..17c3d4a
--- /dev/null
+++ b/tests/system/cleanall.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+#
+# Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2000, 2001 Internet Software Consortium.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+#
+# Clean up after system tests.
+#
+
+find . -type f \( \
+ -name 'K*' -o -name '*~' -o -name '*.core' -o -name '*.log' \
+ -o -name '*.pid' -o -name '*.keyset' -o -name named.run \
+ -o -name bind10.run -o -name lwresd.run -o -name ans.run \) -print | \
+ xargs rm -f
+
+status=0
+
+for d in `find . -type d -maxdepth 1 -mindepth 1 -print`
+do
+ test ! -f $d/clean.sh || ( cd $d && sh clean.sh )
+done
diff --git a/tests/system/conf.sh.in b/tests/system/conf.sh.in
new file mode 100755
index 0000000..29d959a
--- /dev/null
+++ b/tests/system/conf.sh.in
@@ -0,0 +1,54 @@
+#!/bin/sh
+#
+# Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2000-2003 Internet Software Consortium.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+#
+# Common configuration data for system tests, to be sourced into
+# other shell scripts.
+#
+
+# Prerequisite check
+if [ @srcdir@ != @builddir@ ]; then
+ echo "Currently systest doesn't work for a separate build tree."
+ echo "Rebuild BIND 10 on the source tree and run the tests."
+ exit 1
+fi
+
+if [ -z $BIND9_TOP ]; then
+ echo "systest assumes there's a compiled tree of BIND 9 which can be"
+ echo "accessed via the BIND9_TOP environment variable."
+ echo "Please make sure this assumption is met."
+ exit 1
+fi
+
+# Find the top of the source tree.
+TOP=@abs_top_srcdir@
+
+RUN_BIND10=$TOP/src/bin/bind10/run_bind10.sh
+B10_LOADZONE=$TOP/src/bin/loadzone/run_loadzone.sh
+BIND9_NAMED=$BIND9_TOP/bin/named/named
+DIG=$BIND9_TOP/bin/dig/dig
+# Test tools borrowed from BIND 9's system test (without change).
+TESTSOCK=$BIND9_TOP/bin/tests/system/testsock.pl
+DIGCOMP=$BIND9_TOP/bin/tests/system/digcomp.pl
+
+SUBDIRS="glue"
+#SUBDIRS="dnssec glue masterfile xfer"
+
+# PERL will be an empty string if no perl interpreter was found.
+PERL=@PERL@
+
+export RUN_BIND10 BIND9_NAMED DIG SUBDIRS PERL TESTSOCK
diff --git a/tests/system/glue/auth.good b/tests/system/glue/auth.good
new file mode 100644
index 0000000..2c619f6
--- /dev/null
+++ b/tests/system/glue/auth.good
@@ -0,0 +1,15 @@
+
+; <<>> DiG 9.0 <<>> +norec @10.53.0.1 -p 5300 foo.bar.example.org. a
+;; global options: printcmd
+;; Got answer:
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41239
+;; flags: qr ad; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
+
+;; QUESTION SECTION:
+;foo.bar.example.org. IN A
+
+;; AUTHORITY SECTION:
+example.org. 172800 IN NS b.root-servers.nil.
+
+;; ADDITIONAL SECTION:
+b.root-servers.nil. 300 IN A 10.53.0.2
diff --git a/tests/system/glue/clean.sh b/tests/system/glue/clean.sh
new file mode 100755
index 0000000..b2c1e02
--- /dev/null
+++ b/tests/system/glue/clean.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+#
+# Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2000, 2001 Internet Software Consortium.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+#
+# Clean up after glue tests.
+#
+
+rm -f dig.out.*
+rm -f */msgq_socket */zone.sqlite3
diff --git a/tests/system/glue/example.good b/tests/system/glue/example.good
new file mode 100644
index 0000000..3b7bbb8
--- /dev/null
+++ b/tests/system/glue/example.good
@@ -0,0 +1,19 @@
+
+; <<>> DiG 9.0 <<>> +norec @10.53.0.1 -p 5300 foo.bar.example. A
+;; global options: printcmd
+;; Got answer:
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58772
+;; flags: qr ad; QUERY: 1, ANSWER: 0, AUTHORITY: 6, ADDITIONAL: 7
+
+;; QUESTION SECTION:
+;foo.bar.example. IN A
+
+;; AUTHORITY SECTION:
+example. 172800 IN NS NS1.example.COM.
+example. 172800 IN NS NS.example.
+
+;; ADDITIONAL SECTION:
+NS.example. 172800 IN A 192.0.2.1
+NS.example. 172800 IN A 192.0.2.2
+NS1.example.COM. 172800 IN A 192.0.2.101
+NS1.example.COM. 172800 IN AAAA 2001:db8::1
diff --git a/tests/system/glue/noglue.good b/tests/system/glue/noglue.good
new file mode 100644
index 0000000..57a2211
--- /dev/null
+++ b/tests/system/glue/noglue.good
@@ -0,0 +1,14 @@
+
+; <<>> DiG 9.0 <<>> @10.53.0.1 -p 5300 example.net a
+;; global options: printcmd
+;; Got answer:
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 29409
+;; flags: qr rd ad; QUERY: 1, ANSWER: 0, AUTHORITY: 2, ADDITIONAL: 0
+
+;; QUESTION SECTION:
+;example.net. IN A
+
+;; AUTHORITY SECTION:
+example.net. 300 IN NS ns2.example.info.
+example.net. 300 IN NS ns1.example.info.
+
diff --git a/tests/system/glue/nsx1/b10-config.db.in b/tests/system/glue/nsx1/b10-config.db.in
new file mode 100644
index 0000000..acd040c
--- /dev/null
+++ b/tests/system/glue/nsx1/b10-config.db.in
@@ -0,0 +1,9 @@
+{"version": 2,
+ "Auth": {
+ "listen_on": [{"address": "10.53.0.1", "port": 53210}],
+ "database_file": "@abs_builddir@/zone.sqlite3"
+ },
+ "Xfrout": {
+ "log_file": "@abs_builddir@/Xfrout.log"
+ }
+}
diff --git a/tests/system/glue/nsx1/com.db b/tests/system/glue/nsx1/com.db
new file mode 100644
index 0000000..c4b94e1
--- /dev/null
+++ b/tests/system/glue/nsx1/com.db
@@ -0,0 +1,31 @@
+; Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC")
+; Copyright (C) 2000, 2001 Internet Software Consortium.
+;
+; Permission to use, copy, modify, and/or distribute this software for any
+; purpose with or without fee is hereby granted, provided that the above
+; copyright notice and this permission notice appear in all copies.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+$ORIGIN com.
+$TTL 300
+@ IN SOA root.example.com. a.root.servers.nil. (
+ 2000042100 ; serial
+ 600 ; refresh
+ 600 ; retry
+ 1200 ; expire
+ 600 ; minimum
+ )
+@ NS a.root-servers.nil.
+
+example.com. NS ns1.example.com.
+example.com. NS ns2.example.com.
+ns1.example.com. 172800 IN A 192.0.2.101
+ns1.example.com. 172800 IN AAAA 2001:db8::1
+ns2.example.com. 172800 IN A 192.0.2.102
diff --git a/tests/system/glue/nsx1/net.db b/tests/system/glue/nsx1/net.db
new file mode 100644
index 0000000..8b66521
--- /dev/null
+++ b/tests/system/glue/nsx1/net.db
@@ -0,0 +1,32 @@
+; Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC")
+; Copyright (C) 2000, 2001 Internet Software Consortium.
+;
+; Permission to use, copy, modify, and/or distribute this software for any
+; purpose with or without fee is hereby granted, provided that the above
+; copyright notice and this permission notice appear in all copies.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+$ORIGIN net.
+$TTL 300
+@ IN SOA root.example.net. a.root.servers.nil. (
+ 2000042100 ; serial
+ 600 ; refresh
+ 600 ; retry
+ 1200 ; expire
+ 600 ; minimum
+ )
+@ NS a.root-servers.nil.
+
+; Referral outside of server authority, but with glue records present.
+; Don't hand out the glue.
+example.net. NS ns1.example.info.
+example.net. NS ns2.example.info.
+ns1.example.info. 172800 IN A 192.0.2.101
+ns2.example.info. 172800 IN A 192.0.2.102
diff --git a/tests/system/glue/nsx1/root-servers.nil.db b/tests/system/glue/nsx1/root-servers.nil.db
new file mode 100644
index 0000000..45050a9
--- /dev/null
+++ b/tests/system/glue/nsx1/root-servers.nil.db
@@ -0,0 +1,26 @@
+; Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC")
+; Copyright (C) 2000, 2001 Internet Software Consortium.
+;
+; Permission to use, copy, modify, and/or distribute this software for any
+; purpose with or without fee is hereby granted, provided that the above
+; copyright notice and this permission notice appear in all copies.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+$TTL 300
+@ IN SOA ns hostmaster (
+ 1
+ 3600
+ 1800
+ 1814400
+ 3600
+ )
+ NS a
+a A 10.53.0.1
+b A 10.53.0.2
diff --git a/tests/system/glue/nsx1/root.db b/tests/system/glue/nsx1/root.db
new file mode 100644
index 0000000..e43f2d2
--- /dev/null
+++ b/tests/system/glue/nsx1/root.db
@@ -0,0 +1,55 @@
+; Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC")
+; Copyright (C) 2000, 2001 Internet Software Consortium.
+;
+; Permission to use, copy, modify, and/or distribute this software for any
+; purpose with or without fee is hereby granted, provided that the above
+; copyright notice and this permission notice appear in all copies.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+$TTL 300
+. IN SOA postmaster.example. a.root.servers.nil. (
+ 2000042100 ; serial
+ 600 ; refresh
+ 600 ; retry
+ 1200 ; expire
+ 600 ; minimum
+ )
+. NS a.root-servers.nil.
+
+root-servers.nil. NS a.root-servers.nil.
+a.root-servers.nil. A 10.53.0.1
+
+; Delegate some domains that contain name servers for the sample
+; ccTLDs below.
+com. 172800 IN NS a.root-servers.nil.
+
+;
+; A sample TLD
+;
+example. 172800 IN NS NS.example.
+example. 172800 IN NS NS1.example.COM.
+NS.example. 172800 IN A 192.0.2.1
+NS.example. 172800 IN A 192.0.2.2
+; this "glue" is below a zone cut for com. BIND 9 still uses it for
+; the delegation to example. BIND 10 (with sqlite3 data source) doesn't.
+NS1.example.COM. 172800 IN A 192.0.2.3
+
+;
+;
+;
+test. 172800 IN NS ns.test.
+test. 172800 IN NS ns1.example.net.
+ns.test. 172800 IN A 192.0.2.200
+ns1.example.net. 172800 IN A 192.0.2.201
+
+;
+; A hypothetical ccTLD where we are authoritative for the NS glue.
+;
+example.org 172800 IN NS b.root-servers.nil.
diff --git a/tests/system/glue/setup.sh.in b/tests/system/glue/setup.sh.in
new file mode 100755
index 0000000..4e19588
--- /dev/null
+++ b/tests/system/glue/setup.sh.in
@@ -0,0 +1,29 @@
+#!/bin/sh
+#
+# Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+SYSTEMTESTTOP=..
+. $SYSTEMTESTTOP/conf.sh
+
+#
+# Clean up after glue tests.
+#
+
+rm -f */zone.sqlite3
+${B10_LOADZONE} -o . -d @builddir@/nsx1/zone.sqlite3 @builddir@/nsx1/root.db
+${B10_LOADZONE} -o root-servers.nil -d @builddir@/nsx1/zone.sqlite3 \
+ @builddir@/nsx1/root-servers.nil.db
+${B10_LOADZONE} -o com -d @builddir@/nsx1/zone.sqlite3 @builddir@/nsx1/com.db
+${B10_LOADZONE} -o net -d @builddir@/nsx1/zone.sqlite3 @builddir@/nsx1/net.db
diff --git a/tests/system/glue/test.good b/tests/system/glue/test.good
new file mode 100644
index 0000000..b9b4719
--- /dev/null
+++ b/tests/system/glue/test.good
@@ -0,0 +1,19 @@
+
+; <<>> DiG 9.8.0 <<>> @127.0.0.1 -p 5300 foo.bar.test
+; (1 server found)
+;; global options: +cmd
+;; Got answer:
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 55069
+;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 2, ADDITIONAL: 2
+;; WARNING: recursion requested but not available
+
+;; QUESTION SECTION:
+;foo.bar.test. IN A
+
+;; AUTHORITY SECTION:
+test. 172800 IN NS ns.test.
+test. 172800 IN NS ns1.example.net.
+
+;; ADDITIONAL SECTION:
+ns.test. 172800 IN A 192.0.2.200
+ns1.example.net. 172800 IN A 192.0.2.201
diff --git a/tests/system/glue/tests.sh b/tests/system/glue/tests.sh
new file mode 100755
index 0000000..50b2330
--- /dev/null
+++ b/tests/system/glue/tests.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+#
+# Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2000, 2001, 2003 Internet Software Consortium.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+SYSTEMTESTTOP=..
+. $SYSTEMTESTTOP/conf.sh
+
+#
+# Do glue tests.
+#
+
+status=0
+n=0
+
+# This query should result in a delegation with two NS; one in the delegated
+# zone and one in a so called out-of-bailiwick zone for which the auth server
+# has authority, too. For the former, the server should return glue in the
+# parent zone. For the latter, BIND 9 and BIND 10 behave differently; BIND 9
+# uses "glue" in the parent zone (since this is the root zone everything can
+# be considered a valid glue). BIND 10 (using sqlite3 data source) searches
+# the other zone and uses the authoritative data in that zone (which is
+# intentionally different from the glue in the root zone).
+echo "I:testing that a TLD referral gets a full glue set from the root zone ($n)"
+$DIG +norec @10.53.0.1 -p 53210 foo.bar.example. A >dig.out.$n || status=1
+$PERL $DIGCOMP example.good dig.out.$n || status=1
+n=`expr $n + 1`
+
+echo "I:testing that we find glue A RRs we are authoritative for ($n)"
+$DIG +norec @10.53.0.1 -p 53210 foo.bar.example.org. a >dig.out.$n || status=1
+$PERL $DIGCOMP auth.good dig.out.$n || status=1
+n=`expr $n + 1`
+
+# We cannot do this test for BIND 10 because b10-auth doesn't act as a
+# recursive (caching) server (by design)
+# echo "I:testing that we find glue A/AAAA RRs in the cache ($n)"
+# $DIG +norec @10.53.0.1 -p 53210 foo.bar.yy. a >dig.out.$n || status=1
+# $PERL $DIGCOMP yy.good dig.out.$n || status=1
+# n=`expr $n + 1`
+
+echo "I:testing that we don't find out-of-zone glue ($n)"
+$DIG +norec @10.53.0.1 -p 53210 example.net. a > dig.out.$n || status=1
+$PERL $DIGCOMP noglue.good dig.out.$n || status=1
+n=`expr $n + 1`
+
+# This test currently fails (additional section will be empty, which is
+# incorrect). See Trac ticket #646.
+#echo "I:testing that we are finding partial out-of-zone glue ($n)"
+#$DIG +norec @10.53.0.1 -p 53210 foo.bar.test. a >dig.out.$n || status=1
+#$PERL $DIGCOMP test.good dig.out.$n || status=1
+#n=`expr $n + 1`
+
+echo "I:exit status: $status"
+exit $status
diff --git a/tests/system/ifconfig.sh b/tests/system/ifconfig.sh
new file mode 100755
index 0000000..c0c365a
--- /dev/null
+++ b/tests/system/ifconfig.sh
@@ -0,0 +1,226 @@
+#!/bin/sh
+#
+# Copyright (C) 2004, 2007-2010 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2000-2003 Internet Software Consortium.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+#
+# Set up interface aliases for bind9 system tests.
+#
+# IPv4: 10.53.0.{1..7} RFC 1918
+# IPv6: fd92:7065:b8e:ffff::{1..7} ULA
+#
+
+config_guess=""
+for f in ./config.guess ../../config.guess
+do
+ if test -f $f
+ then
+ config_guess=$f
+ fi
+done
+
+if test "X$config_guess" = "X"
+then
+ cat <<EOF >&2
+$0: must be run from the top level source directory or the
+bin/tests/system directory
+EOF
+ exit 1
+fi
+
+# If running on hp-ux, don't even try to run config.guess.
+# It will try to create a temporary file in the current directory,
+# which fails when running as root with the current directory
+# on a NFS mounted disk.
+
+case `uname -a` in
+ *HP-UX*) sys=hpux ;;
+ *) sys=`sh $config_guess` ;;
+esac
+
+case "$2" in
+[0-9]|[1-9][0-9]|[1-9][0-9][0-9]) base=$2;;
+*) base=""
+esac
+
+case "$3" in
+[0-9]|[1-9][0-9]|[1-9][0-9][0-9]) base6=$2;;
+*) base6=""
+esac
+
+case "$1" in
+
+ start|up)
+ for ns in 1 2 3 4 5 6 7
+ do
+ if test -n "$base"
+ then
+ int=`expr $ns + $base - 1`
+ else
+ int=$ns
+ fi
+ if test -n "$base6"
+ then
+ int6=`expr $ns + $base6 - 1`
+ else
+ int6=$ns
+ fi
+ case "$sys" in
+ *-pc-solaris2.5.1)
+ ifconfig lo0:$int 10.53.0.$ns netmask 0xffffffff up
+ ;;
+ *-sun-solaris2.[6-7])
+ ifconfig lo0:$int 10.53.0.$ns netmask 0xffffffff up
+ ;;
+ *-*-solaris2.[8-9]|*-*-solaris2.1[0-9])
+ /sbin/ifconfig lo0:$int plumb
+ /sbin/ifconfig lo0:$int 10.53.0.$ns up
+ if test -n "$int6"
+ then
+ /sbin/ifconfig lo0:$int6 inet6 plumb
+ /sbin/ifconfig lo0:$int6 \
+ inet6 fd92:7065:b8e:ffff::$ns up
+ fi
+ ;;
+ *-*-linux*)
+ ifconfig lo:$int 10.53.0.$ns up netmask 255.255.255.0
+ ifconfig lo inet6 add fd92:7065:b8e:ffff::$ns/64
+ ;;
+ *-unknown-freebsd*)
+ ifconfig lo0 10.53.0.$ns alias netmask 0xffffffff
+ ifconfig lo0 inet6 fd92:7065:b8e:ffff::$ns alias
+ ;;
+ *-unknown-netbsd*)
+ ifconfig lo0 10.53.0.$ns alias netmask 255.255.255.0
+ ifconfig lo0 inet6 fd92:7065:b8e:ffff::$ns alias
+ ;;
+ *-unknown-openbsd*)
+ ifconfig lo0 10.53.0.$ns alias netmask 255.255.255.0
+ ifconfig lo0 inet6 fd92:7065:b8e:ffff::$ns alias
+ ;;
+ *-*-bsdi[3-5].*)
+ ifconfig lo0 add 10.53.0.$ns netmask 255.255.255.0
+ ;;
+ *-dec-osf[4-5].*)
+ ifconfig lo0 alias 10.53.0.$ns
+ ;;
+ *-sgi-irix6.*)
+ ifconfig lo0 alias 10.53.0.$ns
+ ;;
+ *-*-sysv5uw7*|*-*-sysv*UnixWare*|*-*-sysv*OpenUNIX*)
+ ifconfig lo0 10.53.0.$ns alias netmask 0xffffffff
+ ;;
+ *-ibm-aix4.*|*-ibm-aix5.*)
+ ifconfig lo0 alias 10.53.0.$ns
+ ifconfig lo0 inet6 alias -dad fd92:7065:b8e:ffff::$ns/64
+ ;;
+ hpux)
+ ifconfig lo0:$int 10.53.0.$ns netmask 255.255.255.0 up
+ ifconfig lo0:$int inet6 fd92:7065:b8e:ffff::$ns up
+ ;;
+ *-sco3.2v*)
+ ifconfig lo0 alias 10.53.0.$ns
+ ;;
+ *-darwin*)
+ ifconfig lo0 alias 10.53.0.$ns
+ ifconfig lo0 inet6 fd92:7065:b8e:ffff::$ns alias
+ ;;
+ *)
+ echo "Don't know how to set up interface. Giving up."
+ exit 1
+ esac
+ done
+ ;;
+
+ stop|down)
+ for ns in 7 6 5 4 3 2 1
+ do
+ if test -n "$base"
+ then
+ int=`expr $ns + $base - 1`
+ else
+ int=$ns
+ fi
+ case "$sys" in
+ *-pc-solaris2.5.1)
+ ifconfig lo0:$int 0.0.0.0 down
+ ;;
+ *-sun-solaris2.[6-7])
+ ifconfig lo0:$int 10.53.0.$ns down
+ ;;
+ *-*-solaris2.[8-9]|*-*-solaris2.1[0-9])
+ ifconfig lo0:$int 10.53.0.$ns down
+ ifconfig lo0:$int 10.53.0.$ns unplumb
+ if test -n "$int6"
+ then
+ ifconfig lo0:$int6 inet6 down
+ ifconfig lo0:$int6 inet6 unplumb
+ fi
+ ;;
+ *-*-linux*)
+ ifconfig lo:$int 10.53.0.$ns down
+ ifconfig lo inet6 del fd92:7065:b8e:ffff::$ns/64
+ ;;
+ *-unknown-freebsd*)
+ ifconfig lo0 10.53.0.$ns delete
+ ifconfig lo0 inet6 fd92:7065:b8e:ffff::$ns delete
+ ;;
+ *-unknown-netbsd*)
+ ifconfig lo0 10.53.0.$ns delete
+ ifconfig lo0 inet6 fd92:7065:b8e:ffff::$ns delete
+ ;;
+ *-unknown-openbsd*)
+ ifconfig lo0 10.53.0.$ns delete
+ ifconfig lo0 inet6 fd92:7065:b8e:ffff::$ns delete
+ ;;
+ *-*-bsdi[3-5].*)
+ ifconfig lo0 remove 10.53.0.$ns
+ ;;
+ *-dec-osf[4-5].*)
+ ifconfig lo0 -alias 10.53.0.$ns
+ ;;
+ *-sgi-irix6.*)
+ ifconfig lo0 -alias 10.53.0.$ns
+ ;;
+ *-*-sysv5uw7*|*-*-sysv*UnixWare*|*-*-sysv*OpenUNIX*)
+ ifconfig lo0 -alias 10.53.0.$ns
+ ;;
+ *-ibm-aix4.*|*-ibm-aix5.*)
+ ifconfig lo0 delete 10.53.0.$ns
+ ifconfig lo0 delete inet6 fd92:7065:b8e:ffff::$ns/64
+ ;;
+ hpux)
+ ifconfig lo0:$int 0.0.0.0
+ ifconfig lo0:$int inet6 ::
+ ;;
+ *-sco3.2v*)
+ ifconfig lo0 -alias 10.53.0.$ns
+ ;;
+ *darwin*)
+ ifconfig lo0 -alias 10.53.0.$ns
+ ifconfig lo0 inet6 fd92:7065:b8e:ffff::$ns delete
+ ;;
+ *)
+ echo "Don't know how to destroy interface. Giving up."
+ exit 1
+ esac
+ done
+
+ ;;
+
+ *)
+ echo "Usage: $0 { up | down } [base]"
+ exit 1
+esac
diff --git a/tests/system/run.sh b/tests/system/run.sh
new file mode 100755
index 0000000..4f852f4
--- /dev/null
+++ b/tests/system/run.sh
@@ -0,0 +1,125 @@
+#!/bin/sh
+#
+# Copyright (C) 2004, 2007, 2010 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2000, 2001 Internet Software Consortium.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+#
+# Run a system test.
+#
+
+SYSTEMTESTTOP=.
+. $SYSTEMTESTTOP/conf.sh
+
+stopservers=true
+
+case $1 in
+ --keep) stopservers=false; shift ;;
+esac
+
+test $# -gt 0 || { echo "usage: $0 [--keep] test-directory" >&2; exit 1; }
+
+test=$1
+shift
+
+test -d $test || { echo "$0: $test: no such test" >&2; exit 1; }
+
+echo "S:$test:`date`" >&2
+echo "T:$test:1:A" >&2
+echo "A:System test $test" >&2
+
+if [ x$PERL = x ]
+then
+ echo "I:Perl not available. Skipping test." >&2
+ echo "R:UNTESTED" >&2
+ echo "E:$test:`date`" >&2
+ exit 0;
+fi
+
+$PERL $TESTSOCK || {
+ echo "I:Network interface aliases not set up. Skipping test." >&2;
+ echo "R:UNTESTED" >&2;
+ echo "E:$test:`date`" >&2;
+ exit 0;
+}
+
+
+# Check for test-specific prerequisites.
+test ! -f $test/prereq.sh || ( cd $test && sh prereq.sh "$@" )
+result=$?
+
+if [ $result -eq 0 ]; then
+ : prereqs ok
+else
+ echo "I:Prerequisites for $test missing, skipping test." >&2
+ [ $result -eq 255 ] && echo "R:SKIPPED" || echo "R:UNTESTED"
+ echo "E:$test:`date`" >&2
+ exit 0
+fi
+
+# Check for PKCS#11 support
+if
+ test ! -f $test/usepkcs11 || sh cleanpkcs11.sh
+then
+ : pkcs11 ok
+else
+ echo "I:Need PKCS#11 for $test, skipping test." >&2
+ echo "R:PKCS11ONLY" >&2
+ echo "E:$test:`date`" >&2
+ exit 0
+fi
+
+# Set up any dynamically generated test data
+if test -f $test/setup.sh
+then
+ ( cd $test && sh setup.sh "$@" )
+fi
+
+# Start name servers running
+$PERL start.pl $test || exit 1
+
+# Run the tests
+( cd $test ; sh tests.sh )
+
+status=$?
+
+if $stopservers
+then
+ :
+else
+ exit $status
+fi
+
+# Shutdown
+$PERL stop.pl $test
+
+status=`expr $status + $?`
+
+if [ $status != 0 ]; then
+ echo "R:FAIL"
+ # Don't clean up - we need the evidence.
+ find . -name core -exec chmod 0644 '{}' \;
+else
+ echo "R:PASS"
+
+ # Clean up.
+ if test -f $test/clean.sh
+ then
+ ( cd $test && sh clean.sh "$@" )
+ fi
+fi
+
+echo "E:$test:`date`"
+
+exit $status
diff --git a/tests/system/runall.sh b/tests/system/runall.sh
new file mode 100755
index 0000000..5d0fe9b
--- /dev/null
+++ b/tests/system/runall.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+#
+# Copyright (C) 2004, 2007, 2010 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2000, 2001 Internet Software Consortium.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+#
+# Run all the system tests.
+#
+
+SYSTEMTESTTOP=.
+. $SYSTEMTESTTOP/conf.sh
+
+status=0
+
+for d in $SUBDIRS
+do
+ sh run.sh $d || status=1
+done
+
+$PERL $TESTSOCK || {
+ cat <<EOF >&2
+I:
+I:NOTE: Many of the tests were skipped because they require that
+I: the IP addresses 10.53.0.1 through 10.53.0.7 are configured
+I: as alias addresses on the loopback interface. Please run
+I: "tests/system/ifconfig.sh up" as root to configure them
+I: and rerun the tests.
+EOF
+ exit 0;
+}
+
+exit $status
diff --git a/tests/system/start.pl b/tests/system/start.pl
new file mode 100755
index 0000000..56f00c4
--- /dev/null
+++ b/tests/system/start.pl
@@ -0,0 +1,226 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2004-2008, 2010 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2001 Internet Software Consortium.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# Framework for starting test servers.
+# Based on the type of server specified, check for port availability, remove
+# temporary files, start the server, and verify that the server is running.
+# If a server is specified, start it. Otherwise, start all servers for test.
+
+use strict;
+use Cwd 'abs_path';
+use Getopt::Long;
+
+# Option handling
+# --noclean test [server [options]]
+#
+# --noclean - Do not cleanup files in server directory
+# test - name of the test directory
+# server - name of the server directory
+# options - alternate options for the server
+
+my $usage = "usage: $0 [--noclean] test-directory [server-directory [server-options]]";
+my $noclean;
+GetOptions('noclean' => \$noclean);
+my $test = $ARGV[0];
+my $server = $ARGV[1];
+my $options = $ARGV[2];
+
+if (!$test) {
+ print "$usage\n";
+}
+if (!-d $test) {
+ print "No test directory: \"$test\"\n";
+}
+if ($server && !-d "$test/$server") {
+ print "No server directory: \"$test/$server\"\n";
+}
+
+# Global variables
+my $topdir = abs_path("$test/..");
+my $testdir = abs_path("$test");
+my $RUN_BIND10 = $ENV{'RUN_BIND10'};
+my $NAMED = $ENV{'NAMED'};
+my $LWRESD = $ENV{'LWRESD'};
+my $DIG = $ENV{'DIG'};
+my $PERL = $ENV{'PERL'};
+my $TESTSOCK = $ENV{'TESTSOCK'};
+
+# Start the server(s)
+
+if ($server) {
+ if ($server =~ /^ns/) {
+ &check_ports($server);
+ }
+ &start_server($server, $options);
+ if ($server =~ /^ns/) {
+ &verify_server($server);
+ }
+} else {
+ # Determine which servers need to be started for this test.
+ opendir DIR, $testdir;
+ my @files = sort readdir DIR;
+ closedir DIR;
+
+ my @ns = grep /^nsx?[0-9]*$/, @files;
+ my @lwresd = grep /^lwresd[0-9]*$/, @files;
+ my @ans = grep /^ans[0-9]*$/, @files;
+
+ # Start the servers we found.
+ &check_ports();
+ foreach my $s (@ns, @lwresd, @ans) {
+ &start_server($s);
+ }
+ foreach my $s (@ns) {
+ &verify_server($s);
+ }
+}
+
+# Subroutines
+
+sub check_ports {
+ my $server = shift;
+ my $options = "";
+
+ if ($server && $server =~ /(\d+)$/) {
+ $options = "-i $1";
+ }
+
+ my $tries = 0;
+ while (1) {
+ my $return = system("$PERL $TESTSOCK -p 53210 $options");
+ last if ($return == 0);
+ if (++$tries > 4) {
+ print "$0: could not bind to server addresses, still running?\n";
+ print "I:server sockets not available\n";
+ print "R:FAIL\n";
+ system("$PERL $topdir/stop.pl $testdir"); # Is this the correct behavior?
+ exit 1;
+ }
+ print "I:Couldn't bind to socket (yet)\n";
+ sleep 2;
+ }
+}
+
+sub start_server {
+ my $server = shift;
+ my $options = shift;
+
+ my $cleanup_files;
+ my $command;
+ my $pid_file;
+
+ if ($server =~ /^nsx/) {
+ $cleanup_files = "{bind10.run}";
+ $command = "B10_FROM_SOURCE_LOCALSTATEDIR=$testdir/$server/ ";
+ $command .= "$RUN_BIND10 ";
+ if ($options) {
+ $command .= "$options";
+ } else {
+ $command .= "--msgq-socket-file=$testdir/$server/msgq_socket ";
+ $command .= "--pid-file=$testdir/$server/bind10.pid ";
+ $command .= "-v";
+ }
+ $command .= " >bind10.run 2>&1 &";
+ $pid_file = "bind10.pid";
+ } elsif ($server =~ /^ns/) {
+ $cleanup_files = "{*.jnl,*.bk,*.st,named.run}";
+ $command = "$NAMED ";
+ if ($options) {
+ $command .= "$options";
+ } else {
+ $command .= "-m record,size,mctx ";
+ $command .= "-T clienttest ";
+ $command .= "-T nosoa "
+ if (-e "$testdir/$server/named.nosoa");
+ $command .= "-T noaa "
+ if (-e "$testdir/$server/named.noaa");
+ $command .= "-c named.conf -d 99 -g";
+ }
+ $command .= " >named.run 2>&1 &";
+ $pid_file = "named.pid";
+ } elsif ($server =~ /^lwresd/) {
+ $cleanup_files = "{lwresd.run}";
+ $command = "$LWRESD ";
+ if ($options) {
+ $command .= "$options";
+ } else {
+ $command .= "-m record,size,mctx ";
+ $command .= "-T clienttest ";
+ $command .= "-C resolv.conf -d 99 -g ";
+ $command .= "-i lwresd.pid -P 9210 -p 53210";
+ }
+ $command .= " >lwresd.run 2>&1 &";
+ $pid_file = "lwresd.pid";
+ } elsif ($server =~ /^ans/) {
+ $cleanup_files = "{ans.run}";
+ $command = "$PERL ./ans.pl ";
+ if ($options) {
+ $command .= "$options";
+ } else {
+ $command .= "";
+ }
+ $command .= " >ans.run 2>&1 &";
+ $pid_file = "ans.pid";
+ } else {
+ print "I:Unknown server type $server\n";
+ print "R:FAIL\n";
+ system "$PERL $topdir/stop.pl $testdir";
+ exit 1;
+ }
+
+ # print "I:starting server $server\n";
+
+ chdir "$testdir/$server";
+
+ unless ($noclean) {
+ unlink glob $cleanup_files;
+ }
+
+ system "$command";
+
+ my $tries = 0;
+ while (!-f $pid_file) {
+ if (++$tries > 14) {
+ print "I:Couldn't start server $server\n";
+ print "R:FAIL\n";
+ system "$PERL $topdir/stop.pl $testdir";
+ exit 1;
+ }
+ sleep 1;
+ }
+}
+
+sub verify_server {
+ my $server = shift;
+ my $n = $server;
+ $n =~ s/^nsx?//;
+
+ my $tries = 0;
+ while (1) {
+ my $return = system("$DIG +tcp +noadd +nosea +nostat +noquest +nocomm +nocmd -p 53210 version.bind. chaos txt \@10.53.0.$n > dig.out");
+ last if ($return == 0);
+ print `grep ";" dig.out`;
+ if (++$tries >= 30) {
+ print "I:no response from $server\n";
+ print "R:FAIL\n";
+ system("$PERL $topdir/stop.pl $testdir");
+ exit 1;
+ }
+ sleep 2;
+ }
+ unlink "dig.out";
+}
diff --git a/tests/system/stop.pl b/tests/system/stop.pl
new file mode 100755
index 0000000..a803f52
--- /dev/null
+++ b/tests/system/stop.pl
@@ -0,0 +1,188 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2001 Internet Software Consortium.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# Framework for stopping test servers
+# Based on the type of server specified, signal the server to stop, wait
+# briefly for it to die, and then kill it if it is still alive.
+# If a server is specified, stop it. Otherwise, stop all servers for test.
+
+use strict;
+use Cwd 'abs_path';
+
+# Option handling
+# [--use-rndc] test [server]
+#
+# test - name of the test directory
+# server - name of the server directory
+
+my $usage = "usage: $0 [--use-rndc] test-directory [server-directory]";
+my $use_rndc;
+
+while (@ARGV && $ARGV[0] =~ /^-/) {
+ my $opt = shift @ARGV;
+ if ($opt eq '--use-rndc') {
+ $use_rndc = 1;
+ } else {
+ die "$usage\n";
+ }
+}
+
+my $test = $ARGV[0];
+my $server = $ARGV[1];
+
+my $errors = 0;
+
+die "$usage\n" unless defined($test);
+die "No test directory: \"$test\"\n" unless (-d $test);
+die "No server directory: \"$server\"\n" if (defined($server) && !-d "$test/$server");
+
+# Global variables
+my $testdir = abs_path($test);
+my @servers;
+
+
+# Determine which servers need to be stopped.
+if (defined $server) {
+ @servers = ($server);
+} else {
+ local *DIR;
+ opendir DIR, $testdir or die "$testdir: $!\n";
+ my @files = sort readdir DIR;
+ closedir DIR;
+
+ my @ns = grep /^nsx?[0-9]*$/, @files;
+ my @lwresd = grep /^lwresd[0-9]*$/, @files;
+ my @ans = grep /^ans[0-9]*$/, @files;
+
+ push @servers, @ns, @lwresd, @ans;
+}
+
+
+# Stop the server(s), pass 1: rndc.
+if ($use_rndc) {
+ foreach my $server (grep /^ns/, @servers) {
+ stop_rndc($server);
+ }
+
+ wait_for_servers(30, grep /^ns/, @servers);
+}
+
+
+# Pass 2: SIGTERM
+foreach my $server (@servers) {
+ stop_signal($server, "TERM");
+}
+
+wait_for_servers(60, @servers);
+
+# Pass 3: SIGABRT
+foreach my $server (@servers) {
+ stop_signal($server, "ABRT");
+}
+
+exit($errors ? 1 : 0);
+
+# Subroutines
+
+# Return the full path to a given server's PID file.
+sub server_pid_file {
+ my($server) = @_;
+
+ my $pid_file;
+ if ($server =~ /^nsx/) {
+ $pid_file = "bind10.pid";
+ } elsif ($server =~ /^ns/) {
+ $pid_file = "named.pid";
+ } elsif ($server =~ /^lwresd/) {
+ $pid_file = "lwresd.pid";
+ } elsif ($server =~ /^ans/) {
+ $pid_file = "ans.pid";
+ } else {
+ print "I:Unknown server type $server\n";
+ exit 1;
+ }
+ $pid_file = "$testdir/$server/$pid_file";
+}
+
+# Read a PID.
+sub read_pid {
+ my($pid_file) = @_;
+
+ local *FH;
+ my $result = open FH, "< $pid_file";
+ if (!$result) {
+ print "I:$pid_file: $!\n";
+ unlink $pid_file;
+ return;
+ }
+
+ my $pid = <FH>;
+ chomp($pid);
+ return $pid;
+}
+
+# Stop a named process with rndc.
+sub stop_rndc {
+ my($server) = @_;
+
+ return unless ($server =~ /^ns(\d+)$/);
+ my $ip = "10.53.0.$1";
+
+ # Ugly, but should work.
+ system("$ENV{RNDC} -c $testdir/../common/rndc.conf -s $ip -p 9953 stop | sed 's/^/I:$server /'");
+ return;
+}
+
+# Stop a server by sending a signal to it.
+sub stop_signal {
+ my($server, $sig) = @_;
+
+ my $pid_file = server_pid_file($server);
+ return unless -f $pid_file;
+
+ my $pid = read_pid($pid_file);
+ return unless defined($pid);
+
+ if ($sig eq 'ABRT') {
+ print "I:$server didn't die when sent a SIGTERM\n";
+ $errors++;
+ }
+
+ my $result = kill $sig, $pid;
+ if (!$result) {
+ print "I:$server died before a SIG$sig was sent\n";
+ unlink $pid_file;
+ $errors++;
+ }
+
+ return;
+}
+
+sub wait_for_servers {
+ my($timeout, @servers) = @_;
+
+ my @pid_files = grep { defined($_) }
+ map { server_pid_file($_) } @servers;
+
+ while ($timeout > 0 && @pid_files > 0) {
+ @pid_files = grep { -f $_ } @pid_files;
+ sleep 1 if (@pid_files > 0);
+ $timeout--;
+ }
+
+ return;
+}
More information about the bind10-changes
mailing list