Browse Source

[trac617] Merge branch 'master' into trac617

Jeremy C. Reed 14 years ago
parent
commit
17f4eab177

+ 17 - 2
ChangeLog

@@ -1,7 +1,22 @@
-  184.	[func]*		jreed
+  192.	[func]*		jreed
 	Listen on standard domain port 53 for b10-auth and
 	Listen on standard domain port 53 for b10-auth and
 	b10-resolver.
 	b10-resolver.
-	(Trac #617, #618)
+	(Trac #617, #618, git 137a6934a14cf0c5b5c065e910b8b364beb0973f)
+
+  191.	[func]		jinmei
+	Imported system test framework of BIND 9.  It can be run by
+	'make systest' at the top source directory.  Notes: currently it
+	doesn't work when built in a separate tree.  It also requires
+	perl, an inherited dependency from the original framework.
+	Also, mainly for the purpose of tests, a new option "--pid-file"
+	was added to BoB, with which the boss process will dump its PID
+	to the specified file.
+	(Trac #606, git 6ac000df85625f5921e8895a1aafff5e4be3ba9c)
+
+  190.	[func]		jelte
+	Resolver now sets random qids on outgoing queries using
+	the boost::mt19937 prng.
+	(Trac #583, git 5222b51a047d8f2352bc9f92fd022baf1681ed81)
 
 
   189.	[bug]		jreed
   189.	[bug]		jreed
 	Do not install the log message compiler.
 	Do not install the log message compiler.

+ 6 - 1
Makefile.am

@@ -1,4 +1,4 @@
-SUBDIRS = doc src
+SUBDIRS = doc src tests
 USE_LCOV=@USE_LCOV@
 USE_LCOV=@USE_LCOV@
 LCOV=@LCOV@
 LCOV=@LCOV@
 GENHTML=@GENHTML@
 GENHTML=@GENHTML@
@@ -77,6 +77,11 @@ cppcheck:
 		--template '{file}:{line}: check_fail: {message} ({severity},{id})' \
 		--template '{file}:{line}: check_fail: {message} ({severity},{id})' \
 		src
 		src
 
 
+# system tests
+systest:
+	cd tests/system; \
+	sh $(abs_srcdir)/tests/system/runall.sh
+
 #### include external sources in the distributed tarball:
 #### include external sources in the distributed tarball:
 EXTRA_DIST = ext/asio/README
 EXTRA_DIST = ext/asio/README
 EXTRA_DIST += ext/asio/asio/local/stream_protocol.hpp
 EXTRA_DIST += ext/asio/asio/local/stream_protocol.hpp

+ 13 - 0
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"
 	CPPFLAGS="$CPPFLAGS -DASIO_DISABLE_DEV_POLL=1"
 fi
 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],
 AC_ARG_ENABLE(man, [AC_HELP_STRING([--enable-man],
   [regenerate man pages [default=no]])], enable_man=yes, enable_man=no)
   [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/cache/tests/Makefile
                  src/lib/server_common/Makefile
                  src/lib/server_common/Makefile
                  src/lib/server_common/tests/Makefile
                  src/lib/server_common/tests/Makefile
+                 tests/Makefile
+                 tests/system/Makefile
                ])
                ])
 AC_OUTPUT([doc/version.ent
 AC_OUTPUT([doc/version.ent
            src/bin/cfgmgr/b10-cfgmgr.py
            src/bin/cfgmgr/b10-cfgmgr.py
@@ -712,6 +720,7 @@ AC_OUTPUT([doc/version.ent
            src/bin/stats/tests/stats_test
            src/bin/stats/tests/stats_test
            src/bin/bind10/bind10.py
            src/bin/bind10/bind10.py
            src/bin/bind10/tests/bind10_test
            src/bin/bind10/tests/bind10_test
+           src/bin/bind10/tests/bind10_test.py
            src/bin/bind10/run_bind10.sh
            src/bin/bind10/run_bind10.sh
            src/bin/bindctl/run_bindctl.sh
            src/bin/bindctl/run_bindctl.sh
            src/bin/bindctl/bindctl-source.py
            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/session_config.h.pre
            src/lib/cc/tests/session_unittests_config.h
            src/lib/cc/tests/session_unittests_config.h
            src/lib/log/tests/run_time_init_test.sh
            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/cmdctl/run_b10-cmdctl.sh
            chmod +x src/bin/xfrin/run_b10-xfrin.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/gen-rdatacode.py
            chmod +x src/lib/dns/tests/testdata/gen-wiredata.py
            chmod +x src/lib/dns/tests/testdata/gen-wiredata.py
            chmod +x src/lib/log/tests/run_time_init_test.sh
            chmod +x src/lib/log/tests/run_time_init_test.sh
+           chmod +x tests/system/conf.sh
           ])
           ])
 AC_OUTPUT
 AC_OUTPUT
 
 

+ 7 - 1
src/bin/auth/main.cc

@@ -122,7 +122,13 @@ main(int argc, char* argv[]) {
     ModuleCCSession* config_session = NULL;
     ModuleCCSession* config_session = NULL;
     string xfrout_socket_path;
     string xfrout_socket_path;
     if (getenv("B10_FROM_BUILD") != NULL) {
     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 {
     } else {
         xfrout_socket_path = UNIX_SOCKET_FILE;
         xfrout_socket_path = UNIX_SOCKET_FILE;
     }
     }

+ 34 - 0
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."""
     """Function that renames the process if it is requested by a option."""
     isc.util.process.rename(value)
     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():
 def main():
     global options
     global options
     global boss_of_bind
     global boss_of_bind
@@ -805,6 +834,9 @@ def main():
     parser.add_option("--pretty-name", type="string", action="callback",
     parser.add_option("--pretty-name", type="string", action="callback",
                       callback=process_rename,
                       callback=process_rename,
                       help="Set the process name (displayed in ps, top, ...)")
                       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()
     (options, args) = parser.parse_args()
     if args:
     if args:
         parser.print_help()
         parser.print_help()
@@ -865,6 +897,7 @@ def main():
         sys.stderr.write("[bind10] Error on startup: %s\n" % startup_result)
         sys.stderr.write("[bind10] Error on startup: %s\n" % startup_result)
         sys.exit(1)
         sys.exit(1)
     sys.stdout.write("[bind10] BIND 10 started\n")
     sys.stdout.write("[bind10] BIND 10 started\n")
+    dump_pid(options.pid_file)
 
 
     # send "bind10.boot_time" to b10-stats
     # send "bind10.boot_time" to b10-stats
     time.sleep(1) # wait a second
     time.sleep(1) # wait a second
@@ -918,6 +951,7 @@ def main():
     signal.signal(signal.SIGCHLD, signal.SIG_DFL)
     signal.signal(signal.SIGCHLD, signal.SIG_DFL)
     boss_of_bind.shutdown()
     boss_of_bind.shutdown()
     sys.stdout.write("[bind10] BIND 10 exiting\n");
     sys.stdout.write("[bind10] BIND 10 exiting\n");
+    unlink_pid_file(options.pid_file)
     sys.exit(0)
     sys.exit(0)
 
 
 if __name__ == "__main__":
 if __name__ == "__main__":

+ 49 - 2
src/bin/bind10/tests/bind10_test.py

@@ -1,4 +1,4 @@
-from bind10 import ProcessInfo, BoB
+from bind10 import ProcessInfo, BoB, dump_pid, unlink_pid_file
 
 
 # XXX: environment tests are currently disabled, due to the preprocessor
 # XXX: environment tests are currently disabled, due to the preprocessor
 #      setup that we have now complicating the environment
 #      setup that we have now complicating the environment
@@ -48,7 +48,7 @@ class TestProcessInfo(unittest.TestCase):
 #                                   'FOO': 'BAR' })
 #                                   'FOO': 'BAR' })
 
 
     def test_setting_null_stdout(self):
     def test_setting_null_stdout(self):
-        pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ], 
+        pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ],
                          dev_null_stdout=True)
                          dev_null_stdout=True)
         os.dup2(self.old_stdout, sys.stdout.fileno())
         os.dup2(self.old_stdout, sys.stdout.fileno())
         self.assertEqual(pi.dev_null_stdout, True)
         self.assertEqual(pi.dev_null_stdout, True)
@@ -412,5 +412,52 @@ class TestStartStopProcessesBob(unittest.TestCase):
 
 
         bob.config_handler({'start_auth': True, 'start_resolver': True})
         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__':
 if __name__ == '__main__':
     unittest.main()
     unittest.main()

+ 11 - 3
src/bin/cfgmgr/b10-cfgmgr.py.in

@@ -26,10 +26,18 @@ import os
 isc.util.process.rename()
 isc.util.process.rename()
 
 
 # If B10_FROM_SOURCE is set in the environment, we use data files
 # 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:
 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:
 else:
     PREFIX = "@prefix@"
     PREFIX = "@prefix@"
     DATA_PATH = "@localstatedir@/@PACKAGE@".replace("${prefix}", PREFIX)
     DATA_PATH = "@localstatedir@/@PACKAGE@".replace("${prefix}", PREFIX)

+ 5 - 1
src/bin/xfrout/xfrout.py.in

@@ -50,7 +50,11 @@ isc.util.process.rename()
 if "B10_FROM_BUILD" in os.environ:
 if "B10_FROM_BUILD" in os.environ:
     SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/xfrout"
     SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/xfrout"
     AUTH_SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/auth"
     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:
 else:
     PREFIX = "@prefix@"
     PREFIX = "@prefix@"
     DATAROOTDIR = "@datarootdir@"
     DATAROOTDIR = "@datarootdir@"

+ 1 - 0
src/lib/asiolink/Makefile.am

@@ -35,6 +35,7 @@ libasiolink_la_SOURCES += tcp_socket.h
 libasiolink_la_SOURCES += udp_endpoint.h
 libasiolink_la_SOURCES += udp_endpoint.h
 libasiolink_la_SOURCES += udp_server.h udp_server.cc
 libasiolink_la_SOURCES += udp_server.h udp_server.cc
 libasiolink_la_SOURCES += udp_socket.h
 libasiolink_la_SOURCES += udp_socket.h
+libasiolink_la_SOURCES += qid_gen.cc qid_gen.h
 # Note: the ordering matters: -Wno-... must follow -Wextra (defined in
 # Note: the ordering matters: -Wno-... must follow -Wextra (defined in
 # B10_CXXFLAGS)
 # B10_CXXFLAGS)
 libasiolink_la_CXXFLAGS = $(AM_CXXFLAGS)
 libasiolink_la_CXXFLAGS = $(AM_CXXFLAGS)

+ 5 - 3
src/lib/asiolink/io_fetch.cc

@@ -26,6 +26,8 @@
 #include <dns/rcode.h>
 #include <dns/rcode.h>
 #include <log/dummylog.h>
 #include <log/dummylog.h>
 
 
+#include <asiolink/qid_gen.h>
+
 #include <asio.hpp>
 #include <asio.hpp>
 #include <asiolink/io_fetch.h>
 #include <asiolink/io_fetch.h>
 
 
@@ -34,8 +36,9 @@ using namespace isc::dns;
 using namespace isc::log;
 using namespace isc::log;
 using namespace std;
 using namespace std;
 
 
-namespace asiolink {
 
 
+
+namespace asiolink {
 /// IOFetch Constructor - just initialize the private data
 /// IOFetch Constructor - just initialize the private data
 
 
 IOFetch::IOFetch(int protocol, IOService& service,
 IOFetch::IOFetch(int protocol, IOService& service,
@@ -64,8 +67,7 @@ IOFetch::operator()(error_code ec, size_t length) {
         {
         {
             Message msg(Message::RENDER);
             Message msg(Message::RENDER);
             
             
-            // TODO: replace with boost::random or some other suitable PRNG
-            msg.setQid(0);
+            msg.setQid(QidGenerator::getInstance().generateQid());
             msg.setOpcode(Opcode::QUERY());
             msg.setOpcode(Opcode::QUERY());
             msg.setRcode(Rcode::NOERROR());
             msg.setRcode(Rcode::NOERROR());
             msg.setHeaderFlag(Message::HEADERFLAG_RD);
             msg.setHeaderFlag(Message::HEADERFLAG_RD);

+ 56 - 0
src/lib/asiolink/qid_gen.cc

@@ -0,0 +1,56 @@
+// 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.
+
+// qid_gen defines a generator for query id's
+//
+// We probably want to merge this with the weighted random in the nsas
+// (and other parts where we need randomness, perhaps another thing
+// for a general libutil?)
+
+#include <asiolink/qid_gen.h>
+
+#include <sys/time.h>
+
+namespace {
+    asiolink::QidGenerator qid_generator_instance;
+}
+
+namespace asiolink {
+
+QidGenerator&
+QidGenerator::getInstance() {
+    return (qid_generator_instance);
+}
+
+QidGenerator::QidGenerator() : dist_(0, 65535),
+                               vgen_(generator_, dist_)
+{
+    seed();
+}
+
+void
+QidGenerator::seed() {
+    struct timeval tv;
+    gettimeofday(&tv, 0);
+    long int seed;
+    seed = (tv.tv_sec * 1000000) + tv.tv_usec;
+    generator_.seed(seed);
+}
+
+isc::dns::qid_t
+QidGenerator::generateQid() {
+    return (vgen_());
+}
+
+} // namespace asiolink

+ 85 - 0
src/lib/asiolink/qid_gen.h

@@ -0,0 +1,85 @@
+// 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.
+
+// qid_gen defines a generator for query id's
+//
+// We probably want to merge this with the weighted random in the nsas
+// (and other parts where we need randomness, perhaps another thing
+// for a general libutil?)
+
+#ifndef __QID_GEN_H
+#define __QID_GEN_H
+
+#include <dns/message.h>
+#include <boost/random/mersenne_twister.hpp>
+#include <boost/random/uniform_int.hpp>
+#include <boost/random/variate_generator.hpp>
+
+
+namespace asiolink {
+
+/// This class generates Qids for outgoing queries
+///
+/// It is implemented as a singleton; the public way to access it
+/// is to call getInstance()->generateQid().
+///
+/// It automatically seeds it with the current time when it is first
+/// used.
+class QidGenerator {
+public:
+    /// \brief Returns the singleton instance of the QidGenerator
+    ///
+    /// Returns a reference to the singleton instance of the generator
+    static QidGenerator& getInstance();
+
+    /// \brief Default constructor
+    ///
+    /// It is recommended that getInstance is used rather than creating
+    /// separate instances of this class.
+    ///
+    /// The constructor automatically seeds the generator with the
+    /// current time.
+    QidGenerator();
+
+    /// Generate a Qid
+    ///
+    /// \return A random Qid
+    isc::dns::qid_t generateQid();
+
+    /// \brief Seeds the QidGenerator (based on the current time)
+    ///
+    /// This is automatically called by the constructor
+    void seed();
+
+private:
+    // "Mersenne Twister: A 623-dimensionally equidistributed
+    // uniform pseudo-random number generator", Makoto Matsumoto and
+    // Takuji Nishimura, ACM Transactions on Modeling and Computer
+    // Simulation: Special Issue on Uniform Random Number Generation,
+    // Vol. 8, No. 1, January 1998, pp. 3-30.
+    //
+    // mt19937 is an implementation of one of the pseudo random
+    // generators described in this paper.
+    boost::mt19937 generator_;
+
+    // For qid's we want a uniform distribution
+    boost::uniform_int<> dist_;
+
+    boost::variate_generator<boost::mt19937&, boost::uniform_int<> > vgen_;
+};
+
+
+} // namespace asiolink
+
+#endif // __QID_GEN_H

+ 1 - 0
src/lib/asiolink/tests/Makefile.am

@@ -27,6 +27,7 @@ run_unittests_SOURCES += interval_timer_unittest.cc
 run_unittests_SOURCES += recursive_query_unittest.cc
 run_unittests_SOURCES += recursive_query_unittest.cc
 run_unittests_SOURCES += udp_endpoint_unittest.cc
 run_unittests_SOURCES += udp_endpoint_unittest.cc
 run_unittests_SOURCES += udp_socket_unittest.cc
 run_unittests_SOURCES += udp_socket_unittest.cc
+run_unittests_SOURCES += qid_gen_unittest.cc
 
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 
 

+ 59 - 0
src/lib/asiolink/tests/qid_gen_unittest.cc

@@ -0,0 +1,59 @@
+// 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.
+
+// 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.
+
+
+/// \brief Test of QidGenerator
+///
+
+#include <gtest/gtest.h>
+
+#include <asiolink/qid_gen.h>
+#include <dns/message.h>
+
+// Tests the operation of the Qid generator
+
+// Check that getInstance returns a singleton
+TEST(QidGenerator, singleton) {
+    asiolink::QidGenerator& g1 = asiolink::QidGenerator::getInstance();
+    asiolink::QidGenerator& g2 = asiolink::QidGenerator::getInstance();
+
+    EXPECT_TRUE(&g1 == &g2);
+}
+
+TEST(QidGenerator, generate) {
+    // We'll assume that boost's generator is 'good enough', and won't
+    // do full statistical checking here. Let's just call it the xkcd
+    // test (http://xkcd.com/221/), and check if three consecutive
+    // generates are not all the same.
+    isc::dns::qid_t one, two, three;
+    asiolink::QidGenerator& gen = asiolink::QidGenerator::getInstance();
+    one = gen.generateQid();
+    two = gen.generateQid();
+    three = gen.generateQid();
+    ASSERT_FALSE((one == two) && (one == three));
+}

+ 1 - 0
tests/Makefile.am

@@ -0,0 +1 @@
+SUBDIRS = system

+ 13 - 0
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

+ 62 - 0
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.

+ 33 - 0
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

+ 54 - 0
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

+ 15 - 0
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

+ 23 - 0
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

+ 19 - 0
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

+ 14 - 0
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.
+

+ 9 - 0
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"
+ }
+}

+ 31 - 0
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

+ 32 - 0
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

+ 26 - 0
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

+ 55 - 0
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.

+ 29 - 0
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

+ 19 - 0
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

+ 66 - 0
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

+ 226 - 0
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

+ 125 - 0
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

+ 44 - 0
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

+ 226 - 0
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";
+}

+ 188 - 0
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;
+}