BIND 10 bind10-1.0.0-rc-release, updated. fe5478b124614d5d6b6abc8bb4815288e53fc9c7 [bind10-1.0.0-rc-release][2145-revert] Revert "[master] Merge branch 'trac2145'"

BIND 10 source code commits bind10-changes at lists.isc.org
Thu Feb 14 21:45:29 UTC 2013


The branch, bind10-1.0.0-rc-release has been updated
       via  fe5478b124614d5d6b6abc8bb4815288e53fc9c7 (commit)
      from  62cb314a492feb5f367953dce2f39326858abc73 (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 fe5478b124614d5d6b6abc8bb4815288e53fc9c7
Author: JINMEI Tatuya <jinmei at isc.org>
Date:   Thu Feb 14 10:52:47 2013 -0800

    [bind10-1.0.0-rc-release][2145-revert] Revert "[master] Merge branch 'trac2145'"
    
    This reverts commit 530f569e47b06f49402611bda07e1956cdf04a24, reversing
    changes made to da67c0642c9403f08e278e2424bc7bfde74e034a.
    
    and fix conflict

-----------------------------------------------------------------------

Summary of changes:
 configure.ac                                       |    2 +-
 src/bin/bind10/bind10.in                           |    2 --
 src/bin/bind10/init.py.in                          |    1 -
 src/bin/bind10/tests/Makefile.am                   |    2 +-
 .../tests/{init_test.py.in => bind10_test.py.in}   |    2 +-
 src/bin/bindctl/bindcmd.py                         |    2 +-
 src/bin/bindctl/run_bindctl.sh.in                  |    2 +-
 src/bin/stats/stats.py.in                          |    3 +--
 src/bin/sysinfo/run_sysinfo.sh.in                  |   14 +++++++++++++-
 src/lib/python/isc/__init__.py                     |   10 +++++++---
 .../python/isc/datasrc/tests/zone_loader_test.py   |    1 -
 11 files changed, 26 insertions(+), 15 deletions(-)
 rename src/bin/bind10/tests/{init_test.py.in => bind10_test.py.in} (99%)

-----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index f843132..5683b65 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1342,7 +1342,7 @@ AC_OUTPUT([doc/version.ent
            src/bin/stats/stats_httpd.py
            src/bin/bind10/init.py
            src/bin/bind10/run_bind10.sh
-           src/bin/bind10/tests/init_test.py
+           src/bin/bind10/tests/bind10_test.py
            src/bin/bindctl/run_bindctl.sh
            src/bin/bindctl/bindctl_main.py
            src/bin/bindctl/tests/bindctl_test
diff --git a/src/bin/bind10/bind10.in b/src/bin/bind10/bind10.in
index 88c45c9..6421bab 100755
--- a/src/bin/bind10/bind10.in
+++ b/src/bin/bind10/bind10.in
@@ -1,7 +1,5 @@
 #!/bin/sh
 
-# We use this wrapper script both for production and in-source tests; in
-# the latter case B10_FROM_BUILD environment is expected to be defined.
 if test -n "${B10_FROM_BUILD}"; then
 	exec ${B10_FROM_BUILD}/src/bin/bind10/b10-init $*
 else
diff --git a/src/bin/bind10/init.py.in b/src/bin/bind10/init.py.in
index f47de31..874fb34 100755
--- a/src/bin/bind10/init.py.in
+++ b/src/bin/bind10/init.py.in
@@ -72,7 +72,6 @@ import isc.cc
 import isc.util.process
 import isc.net.parse
 import isc.log
-import isc.config
 from isc.log_messages.init_messages import *
 import isc.bind10.component
 import isc.bind10.special_component
diff --git a/src/bin/bind10/tests/Makefile.am b/src/bin/bind10/tests/Makefile.am
index 6d59dbd..a5e3fab 100644
--- a/src/bin/bind10/tests/Makefile.am
+++ b/src/bin/bind10/tests/Makefile.am
@@ -1,7 +1,7 @@
 PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
 #PYTESTS = args_test.py bind10_test.py
 # NOTE: this has a generated test found in the builddir
-PYTESTS = init_test.py
+PYTESTS = bind10_test.py
 noinst_SCRIPTS = $(PYTESTS)
 
 # If necessary (rare cases), explicitly specify paths to dynamic libraries
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..36b98fe
--- /dev/null
+++ b/src/bin/bind10/tests/bind10_test.py.in
@@ -0,0 +1,2426 @@
+# Copyright (C) 2011  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and 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 INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM 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.
+
+# Most of the time, we omit the "init" for brevity. Sometimes,
+# we want to be explicit about what we do, like when hijacking a library
+# call used by the b10-init.
+from init import Init, ProcessInfo, parse_args, dump_pid, unlink_pid_file, _BASETIME
+import init
+
+# 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 os.path
+import copy
+import signal
+import socket
+from isc.net.addr import IPAddr
+import time
+import isc
+import isc.log
+import isc.bind10.socket_cache
+import errno
+import random
+
+from isc.testutils.parse_args import TestOptParser, OptsError
+from isc.testutils.ccsession_mock import MockModuleCCSession
+
+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' ])
+        pi.spawn()
+        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)
+        pi.spawn()
+        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' ])
+        pi.spawn()
+        # 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 TestCacheCommands(unittest.TestCase):
+    """
+    Test methods of b10-init related to the socket cache and socket handling.
+    """
+    def setUp(self):
+        """
+        Prepare b10-init for some tests.
+
+        Also prepare some variables we need.
+        """
+        self.__b10_init = Init()
+        # Fake the cache here so we can pretend it is us and hijack the
+        # calls to its methods.
+        self.__b10_init._socket_cache = self
+        self.__b10_init._socket_path = '/socket/path'
+        self.__raise_exception = None
+        self.__socket_args = {
+            "port": 53,
+            "address": "::",
+            "protocol": "UDP",
+            "share_mode": "ANY",
+            "share_name": "app"
+        }
+        # What was and wasn't called.
+        self.__drop_app_called = None
+        self.__get_socket_called = None
+        self.__send_fd_called = None
+        self.__get_token_called = None
+        self.__drop_socket_called = None
+        init.libutil_io_python.send_fd = self.__send_fd
+
+    def __send_fd(self, to, socket):
+        """
+        A function to hook the send_fd in the b10-init.
+        """
+        self.__send_fd_called = (to, socket)
+
+    class FalseSocket:
+        """
+        A socket where we can fake methods we need instead of having a real
+        socket.
+        """
+        def __init__(self):
+            self.send = b""
+        def fileno(self):
+            """
+            The file number. Used for identifying the remote application.
+            """
+            return 42
+
+        def sendall(self, data):
+            """
+            Adds data to the self.send.
+            """
+            self.send += data
+
+    def drop_application(self, application):
+        """
+        Part of pretending to be the cache. Logs the parameter to
+        self.__drop_app_called.
+
+        In the case self.__raise_exception is set, the exception there
+        is raised instead.
+        """
+        if self.__raise_exception is not None:
+            raise self.__raise_exception
+        self.__drop_app_called = application
+
+    def test_consumer_dead(self):
+        """
+        Test that it calls the drop_application method of the cache.
+        """
+        self.__b10_init.socket_consumer_dead(self.FalseSocket())
+        self.assertEqual(42, self.__drop_app_called)
+
+    def test_consumer_dead_invalid(self):
+        """
+        Test that it doesn't crash in case the application is not known to
+        the cache, the b10_init doesn't crash, as this actually can happen in
+        practice.
+        """
+        self.__raise_exception = ValueError("This application is unknown")
+        # This doesn't crash
+        self.__b10_init.socket_consumer_dead(self.FalseSocket())
+
+    def get_socket(self, token, application):
+        """
+        Part of pretending to be the cache. If there's anything in
+        __raise_exception, it is raised. Otherwise, the call is logged
+        into __get_socket_called and a number is returned.
+        """
+        if self.__raise_exception is not None:
+            raise self.__raise_exception
+        self.__get_socket_called = (token, application)
+        return 13
+
+    def test_request_handler(self):
+        """
+        Test that a request for socket is forwarded and the socket is sent
+        back, if it returns a socket.
+        """
+        socket = self.FalseSocket()
+        # An exception from the cache
+        self.__raise_exception = ValueError("Test value error")
+        self.__b10_init.socket_request_handler(b"token", socket)
+        # It was called, but it threw, so it is not noted here
+        self.assertIsNone(self.__get_socket_called)
+        self.assertEqual(b"0\n", socket.send)
+        # It should not have sent any socket.
+        self.assertIsNone(self.__send_fd_called)
+        # Now prepare a valid scenario
+        self.__raise_exception = None
+        socket.send = b""
+        self.__b10_init.socket_request_handler(b"token", socket)
+        self.assertEqual(b"1\n", socket.send)
+        self.assertEqual((42, 13), self.__send_fd_called)
+        self.assertEqual(("token", 42), self.__get_socket_called)
+
+    def get_token(self, protocol, address, port, share_mode, share_name):
+        """
+        Part of pretending to be the cache. If there's anything in
+        __raise_exception, it is raised. Otherwise, the parameters are
+        logged into __get_token_called and a token is returned.
+        """
+        if self.__raise_exception is not None:
+            raise self.__raise_exception
+        self.__get_token_called = (protocol, address, port, share_mode,
+                                   share_name)
+        return "token"
+
+    def test_get_socket_ok(self):
+        """
+        Test the successful scenario of getting a socket.
+        """
+        result = self.__b10_init._get_socket(self.__socket_args)
+        [code, answer] = result['result']
+        self.assertEqual(0, code)
+        self.assertEqual({
+            'token': 'token',
+            'path': '/socket/path'
+        }, answer)
+        addr = self.__get_token_called[1]
+        self.assertTrue(isinstance(addr, IPAddr))
+        self.assertEqual("::", str(addr))
+        self.assertEqual(("UDP", addr, 53, "ANY", "app"),
+                         self.__get_token_called)
+
+    def test_get_socket_error(self):
+        """
+        Test that bad inputs are handled correctly, etc.
+        """
+        def check_code(code, args):
+            """
+            Pass the args there and check if it returns success or not.
+
+            The rest is not tested, as it is already checked in the
+            test_get_socket_ok.
+            """
+            [rcode, ranswer] = self.__b10_init._get_socket(args)['result']
+            self.assertEqual(code, rcode)
+            if code != 0:
+                # This should be an error message. The exact formatting
+                # is unknown, but we check it is string at least
+                self.assertTrue(isinstance(ranswer, str))
+
+        def mod_args(name, value):
+            """
+            Override a parameter in the args.
+            """
+            result = dict(self.__socket_args)
+            result[name] = value
+            return result
+
+        # Port too large
+        check_code(1, mod_args('port', 65536))
+        # Not numeric address
+        check_code(1, mod_args('address', 'example.org.'))
+        # Some bad values of enum-like params
+        check_code(1, mod_args('protocol', 'BAD PROTO'))
+        check_code(1, mod_args('share_mode', 'BAD SHARE'))
+        # Check missing parameters
+        for param in self.__socket_args.keys():
+            args = dict(self.__socket_args)
+            del args[param]
+            check_code(1, args)
+        # These are OK values for the enum-like parameters
+        # The ones from test_get_socket_ok are not tested here
+        check_code(0, mod_args('protocol', 'TCP'))
+        check_code(0, mod_args('share_mode', 'SAMEAPP'))
+        check_code(0, mod_args('share_mode', 'NO'))
+        # If an exception is raised from within the cache, it is converted
+        # to an error, not propagated
+        self.__raise_exception = Exception("Test exception")
+        check_code(1, self.__socket_args)
+        # The special "expected" exceptions
+        self.__raise_exception = \
+            isc.bind10.socket_cache.ShareError("Not shared")
+        check_code(3, self.__socket_args)
+        self.__raise_exception = \
+            isc.bind10.socket_cache.SocketError("Not shared", 13)
+        check_code(2, self.__socket_args)
+
+    def drop_socket(self, token):
+        """
+        Part of pretending to be the cache. If there's anything in
+        __raise_exception, it is raised. Otherwise, the parameter is stored
+        in __drop_socket_called.
+        """
+        if self.__raise_exception is not None:
+            raise self.__raise_exception
+        self.__drop_socket_called = token
+
+    def test_drop_socket(self):
+        """
+        Check the drop_socket command. It should directly call the method
+        on the cache. Exceptions should be translated to error messages.
+        """
+        # This should be OK and just propagated to the call.
+        self.assertEqual({"result": [0]},
+                         self.__b10_init.command_handler("drop_socket",
+                                                         {"token": "token"}))
+        self.assertEqual("token", self.__drop_socket_called)
+        self.__drop_socket_called = None
+        # Missing parameter
+        self.assertEqual({"result": [1, "Missing token parameter"]},
+                         self.__b10_init.command_handler("drop_socket", {}))
+        self.assertIsNone(self.__drop_socket_called)
+        # An exception is raised from within the cache
+        self.__raise_exception = ValueError("Test error")
+        self.assertEqual({"result": [1, "Test error"]},
+                         self.__b10_init.command_handler("drop_socket",
+                         {"token": "token"}))
+
+
+class TestInit(unittest.TestCase):
+    def setUp(self):
+        # Save original values that may be tweaked in some tests
+        self.__orig_setgid = init.posix.setgid
+        self.__orig_setuid = init.posix.setuid
+        self.__orig_logger_class = isc.log.Logger
+
+    def tearDown(self):
+        # Restore original values saved in setUp()
+        init.posix.setgid = self.__orig_setgid
+        init.posix.setuid = self.__orig_setuid
+        isc.log.Logger = self.__orig_logger_class
+
+    def test_init(self):
+        b10_init = Init()
+        self.assertEqual(b10_init.verbose, False)
+        self.assertEqual(b10_init.msgq_socket_file, None)
+        self.assertEqual(b10_init.cc_session, None)
+        self.assertEqual(b10_init.ccs, None)
+        self.assertEqual(b10_init.components, {})
+        self.assertEqual(b10_init.runnable, False)
+        self.assertEqual(b10_init.username, None)
+        self.assertIsNone(b10_init._socket_cache)
+
+    def __setgid(self, gid):
+        self.__gid_set = gid
+
+    def __setuid(self, uid):
+        self.__uid_set = uid
+
+    def test_change_user(self):
+        init.posix.setgid = self.__setgid
+        init.posix.setuid = self.__setuid
+
+        self.__gid_set = None
+        self.__uid_set = None
+        b10_init = Init()
+        b10_init.change_user()
+        # No gid/uid set in init, nothing called.
+        self.assertIsNone(self.__gid_set)
+        self.assertIsNone(self.__uid_set)
+
+        Init(setuid=42, setgid=4200).change_user()
+        # This time, it get's called
+        self.assertEqual(4200, self.__gid_set)
+        self.assertEqual(42, self.__uid_set)
+
+        def raising_set_xid(gid_or_uid):
+            ex = OSError()
+            ex.errno, ex.strerror = errno.EPERM, 'Operation not permitted'
+            raise ex
+
+        # Let setgid raise an exception
+        init.posix.setgid = raising_set_xid
+        init.posix.setuid = self.__setuid
+        self.assertRaises(init.ChangeUserError,
+                          Init(setuid=42, setgid=4200).change_user)
+
+        # Let setuid raise an exception
+        init.posix.setgid = self.__setgid
+        init.posix.setuid = raising_set_xid
+        self.assertRaises(init.ChangeUserError,
+                          Init(setuid=42, setgid=4200).change_user)
+
+        # Let initial log output after setuid raise an exception
+        init.posix.setgid = self.__setgid
+        init.posix.setuid = self.__setuid
+        isc.log.Logger = raising_set_xid
+        self.assertRaises(init.ChangeUserError,
+                          Init(setuid=42, setgid=4200).change_user)
+
+    def test_set_creator(self):
+        """
+        Test the call to set_creator. First time, the cache is created
+        with the passed creator. The next time, it throws an exception.
+        """
+        init = Init()
+        # The cache doesn't use it at start, so just create an empty class
+        class Creator: pass
+        creator = Creator()
+        init.set_creator(creator)
+        self.assertTrue(isinstance(init._socket_cache,
+                        isc.bind10.socket_cache.Cache))
+        self.assertEqual(creator, init._socket_cache._creator)
+        self.assertRaises(ValueError, init.set_creator, creator)
+
+    def test_socket_srv(self):
+        """Tests init_socket_srv() and remove_socket_srv() work as expected."""
+        init = Init()
+
+        self.assertIsNone(init._srv_socket)
+        self.assertIsNone(init._tmpdir)
+        self.assertIsNone(init._socket_path)
+
+        init.init_socket_srv()
+
+        self.assertIsNotNone(init._srv_socket)
+        self.assertNotEqual(-1, init._srv_socket.fileno())
+        self.assertEqual(os.path.join(init._tmpdir, 'sockcreator'),
+                         init._srv_socket.getsockname())
+
+        self.assertIsNotNone(init._tmpdir)
+        self.assertTrue(os.path.isdir(init._tmpdir))
+        self.assertIsNotNone(init._socket_path)
+        self.assertTrue(os.path.exists(init._socket_path))
+
+        # Check that it's possible to connect to the socket file (this
+        # only works if the socket file exists and the server listens on
+        # it).
+        s = socket.socket(socket.AF_UNIX)
+        try:
+            s.connect(init._socket_path)
+            can_connect = True
+            s.close()
+        except socket.error as e:
+            can_connect = False
+
+        self.assertTrue(can_connect)
+
+        init.remove_socket_srv()
+
+        self.assertEqual(-1, init._srv_socket.fileno())
+        self.assertFalse(os.path.exists(init._socket_path))
+        self.assertFalse(os.path.isdir(init._tmpdir))
+
+        # These should not fail either:
+
+        # second call
+        init.remove_socket_srv()
+
+        init._srv_socket = None
+        init.remove_socket_srv()
+
+    def test_init_alternate_socket(self):
+        init = Init("alt_socket_file")
+        self.assertEqual(init.verbose, False)
+        self.assertEqual(init.msgq_socket_file, "alt_socket_file")
+        self.assertEqual(init.cc_session, None)
+        self.assertEqual(init.ccs, None)
+        self.assertEqual(init.components, {})
+        self.assertEqual(init.runnable, False)
+        self.assertEqual(init.username, None)
+
+    def test_command_handler(self):
+        class DummySession():
+            def group_sendmsg(self, msg, group):
+                (self.msg, self.group) = (msg, group)
+            def group_recvmsg(self, nonblock, seq): pass
+        class DummyModuleCCSession():
+            module_spec = isc.config.module_spec.ModuleSpec({
+                    "module_name": "Init",
+                    "statistics": [
+                        {
+                            "item_name": "boot_time",
+                            "item_type": "string",
+                            "item_optional": False,
+                            "item_default": "1970-01-01T00:00:00Z",
+                            "item_title": "Boot time",
+                            "item_description": "A date time when bind10 process starts initially",
+                            "item_format": "date-time"
+                            }
+                        ]
+                    })
+            def get_module_spec(self):
+                return self.module_spec
+        init = Init()
+        init.verbose = True
+        init.cc_session = DummySession()
+        init.ccs = DummyModuleCCSession()
+        # a bad command
+        self.assertEqual(init.command_handler(-1, None),
+                         isc.config.ccsession.create_answer(1, "bad command"))
+        # "shutdown" command
+        self.assertEqual(init.command_handler("shutdown", None),
+                         isc.config.ccsession.create_answer(0))
+        self.assertFalse(init.runnable)
+        # "getstats" command
+        self.assertEqual(init.command_handler("getstats", None),
+                         isc.config.ccsession.create_answer(0,
+                            { 'boot_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', _BASETIME) }))
+        # "ping" command
+        self.assertEqual(init.command_handler("ping", None),
+                         isc.config.ccsession.create_answer(0, "pong"))
+        # "show_processes" command
+        self.assertEqual(init.command_handler("show_processes", None),
+                         isc.config.ccsession.create_answer(0,
+                                                            init.get_processes()))
+        # an unknown command
+        self.assertEqual(init.command_handler("__UNKNOWN__", None),
+                         isc.config.ccsession.create_answer(1, "Unknown command"))
+
+        # Fake the get_token of cache and test the command works
+        init._socket_path = '/socket/path'
+        class cache:
+            def get_token(self, protocol, addr, port, share_mode, share_name):
+                return str(addr) + ':' + str(port)
+        init._socket_cache = cache()
+        args = {
+            "port": 53,
+            "address": "0.0.0.0",
+            "protocol": "UDP",
+            "share_mode": "ANY",
+            "share_name": "app"
+        }
+        # at all and this is the easiest way to check.
+        self.assertEqual({'result': [0, {'token': '0.0.0.0:53',
+                                         'path': '/socket/path'}]},
+                         init.command_handler("get_socket", args))
+        # The drop_socket is not tested here, but in TestCacheCommands.
+        # It needs the cache mocks to be in place and they are there.
+
+    def test_stop_process(self):
+        """
+        Test checking the stop_process method sends the right message over
+        the message bus.
+        """
+        class DummySession():
+            def group_sendmsg(self, msg, group, instance="*"):
+                (self.msg, self.group, self.instance) = (msg, group, instance)
+        init = Init()
+        init.cc_session = DummySession()
+        init.stop_process('process', 'address', 42)
+        self.assertEqual('address', init.cc_session.group)
+        self.assertEqual('address', init.cc_session.instance)
+        self.assertEqual({'command': ['shutdown', {'pid': 42}]},
+                         init.cc_session.msg)
+
+# Mock class for testing Init's usage of ProcessInfo
+class MockProcessInfo:
+    def __init__(self, name, args, env={}, dev_null_stdout=False,
+                 dev_null_stderr=False):
+        self.name = name
+        self.args = args
+        self.env = env
+        self.dev_null_stdout = dev_null_stdout
+        self.dev_null_stderr = dev_null_stderr
+        self.process = None
+        self.pid = None
+
+    def spawn(self):
+        # set some pid (only used for testing that it is not None anymore)
+        self.pid = 42147
+
+# Class for testing the Init without actually starting processes.
+# This is used for testing the start/stop components routines and
+# the Init commands.
+#
+# 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 MockInit(Init):
+    def __init__(self):
+        Init.__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.stats_httpd = False
+        self.cmdctl = False
+        self.dhcp6 = False
+        self.dhcp4 = False
+        self.c_channel_env = {}
+        self.components = { }
+        self.creator = False
+        self.get_process_exit_status_called = False
+
+        class MockSockCreator(isc.bind10.component.Component):
+            def __init__(self, process, b10_init, kind, address=None,
+                         params=None):
+                isc.bind10.component.Component.__init__(self, process,
+                                                        b10_init, kind,
+                                                        'SockCreator')
+                self._start_func = b10_init.start_creator
+
+        specials = isc.bind10.special_component.get_specials()
+        specials['sockcreator'] = MockSockCreator
+        self._component_configurator = \
+            isc.bind10.component.Configurator(self, specials)
+
+    def start_creator(self):
+        self.creator = True
+        procinfo = ProcessInfo('b10-sockcreator', ['/bin/false'])
+        procinfo.pid = 1
+        return procinfo
+
+    def _read_bind10_config(self):
+        # Configuration options are set directly
+        pass
+
+    def start_msgq(self):
+        self.msgq = True
+        procinfo = ProcessInfo('b10-msgq', ['/bin/false'])
+        procinfo.pid = 2
+        return procinfo
+
+    def start_ccsession(self, c_channel_env):
+        # this is not a process, don't have to do anything with procinfo
+        self.ccsession = True
+
+    def start_cfgmgr(self):
+        self.cfgmgr = True
+        procinfo = ProcessInfo('b10-cfgmgr', ['/bin/false'])
+        procinfo.pid = 3
+        return procinfo
+
+    def start_auth(self):
+        self.auth = True
+        procinfo = ProcessInfo('b10-auth', ['/bin/false'])
+        procinfo.pid = 5
+        return procinfo
+
+    def start_resolver(self):
+        self.resolver = True
+        procinfo = ProcessInfo('b10-resolver', ['/bin/false'])
+        procinfo.pid = 6
+        return procinfo
+
+    def start_simple(self, name):
+        procmap = { 'b10-zonemgr': self.start_zonemgr,
+                    'b10-stats': self.start_stats,
+                    'b10-stats-httpd': self.start_stats_httpd,
+                    'b10-cmdctl': self.start_cmdctl,
+                    'b10-dhcp6': self.start_dhcp6,
+                    'b10-dhcp4': self.start_dhcp4,
+                    'b10-xfrin': self.start_xfrin,
+                    'b10-xfrout': self.start_xfrout }
+        return procmap[name]()
+
+    def start_xfrout(self):
+        self.xfrout = True
+        procinfo = ProcessInfo('b10-xfrout', ['/bin/false'])
+        procinfo.pid = 7
+        return procinfo
+
+    def start_xfrin(self):
+        self.xfrin = True
+        procinfo = ProcessInfo('b10-xfrin', ['/bin/false'])
+        procinfo.pid = 8
+        return procinfo
+
+    def start_zonemgr(self):
+        self.zonemgr = True
+        procinfo = ProcessInfo('b10-zonemgr', ['/bin/false'])
+        procinfo.pid = 9
+        return procinfo
+
+    def start_stats(self):
+        self.stats = True
+        procinfo = ProcessInfo('b10-stats', ['/bin/false'])
+        procinfo.pid = 10
+        return procinfo
+
+    def start_stats_httpd(self):
+        self.stats_httpd = True
+        procinfo = ProcessInfo('b10-stats-httpd', ['/bin/false'])
+        procinfo.pid = 11
+        return procinfo
+
+    def start_cmdctl(self):
+        self.cmdctl = True
+        procinfo = ProcessInfo('b10-cmdctl', ['/bin/false'])
+        procinfo.pid = 12
+        return procinfo
+
+    def start_dhcp6(self):
+        self.dhcp6 = True
+        procinfo = ProcessInfo('b10-dhcp6', ['/bin/false'])
+        procinfo.pid = 13
+        return procinfo
+
+    def start_dhcp4(self):
+        self.dhcp4 = True
+        procinfo = ProcessInfo('b10-dhcp4', ['/bin/false'])
+        procinfo.pid = 14
+        return procinfo
+
+    def stop_process(self, process, recipient, pid):
+        procmap = { 'b10-auth': self.stop_auth,
+                    'b10-resolver': self.stop_resolver,
+                    'b10-xfrout': self.stop_xfrout,
+                    'b10-xfrin': self.stop_xfrin,
+                    'b10-zonemgr': self.stop_zonemgr,
+                    'b10-stats': self.stop_stats,
+                    'b10-stats-httpd': self.stop_stats_httpd,
+                    'b10-cmdctl': self.stop_cmdctl }
+        procmap[process]()
+
+    # Some functions to pretend we stop processes, use by stop_process
+    def stop_msgq(self):
+        if self.msgq:
+            del self.components[2]
+        self.msgq = False
+
+    def stop_cfgmgr(self):
+        if self.cfgmgr:
+            del self.components[3]
+        self.cfgmgr = False
+
+    def stop_auth(self):
+        if self.auth:
+            del self.components[5]
+        self.auth = False
+
+    def stop_resolver(self):
+        if self.resolver:
+            del self.components[6]
+        self.resolver = False
+
+    def stop_xfrout(self):
+        if self.xfrout:
+            del self.components[7]
+        self.xfrout = False
+
+    def stop_xfrin(self):
+        if self.xfrin:
+            del self.components[8]
+        self.xfrin = False
+
+    def stop_zonemgr(self):
+        if self.zonemgr:
+            del self.components[9]
+        self.zonemgr = False
+
+    def stop_stats(self):
+        if self.stats:
+            del self.components[10]
+        self.stats = False
+
+    def stop_stats_httpd(self):
+        if self.stats_httpd:
+            del self.components[11]
+        self.stats_httpd = False
+
+    def stop_cmdctl(self):
+        if self.cmdctl:
+            del self.components[12]
+        self.cmdctl = False
+
+    def _get_process_exit_status(self):
+        if self.get_process_exit_status_called:
+            return (0, 0)
+        self.get_process_exit_status_called = True
+        return (53, 0)
+
+    def _get_process_exit_status_unknown_pid(self):
+        if self.get_process_exit_status_called:
+            return (0, 0)
+        self.get_process_exit_status_called = True
+        return (42, 0)
+
+    def _get_process_exit_status_raises_oserror_echild(self):
+        raise OSError(errno.ECHILD, 'Mock error')
+
+    def _get_process_exit_status_raises_oserror_other(self):
+        raise OSError(0, 'Mock error')
+
+    def _get_process_exit_status_raises_other(self):
+        raise Exception('Mock error')
+
+    def _make_mock_process_info(self, name, args, c_channel_env,
+                                dev_null_stdout=False, dev_null_stderr=False):
+        return MockProcessInfo(name, args, c_channel_env,
+                               dev_null_stdout, dev_null_stderr)
+
+class MockInitSimple(Init):
+    def __init__(self):
+        Init.__init__(self)
+        # Set which process has been started
+        self.started_process_name = None
+        self.started_process_args = None
+        self.started_process_env = None
+
+    def _make_mock_process_info(self, name, args, c_channel_env,
+                                dev_null_stdout=False, dev_null_stderr=False):
+        return MockProcessInfo(name, args, c_channel_env,
+                               dev_null_stdout, dev_null_stderr)
+
+    def start_process(self, name, args, c_channel_env, port=None,
+                      address=None):
+        self.started_process_name = name
+        self.started_process_args = args
+        self.started_process_env = c_channel_env
+        return None
+
+class TestStartStopProcessesInit(unittest.TestCase):
+    """
+    Check that the start_all_components method starts the right combination
+    of components and that the right components are started and stopped
+    according to changes in configuration.
+    """
+    def check_environment_unchanged(self):
+        # Check whether the environment has not been changed
+        self.assertEqual(original_os_environ, os.environ)
+
+    def check_started(self, init, 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(init.msgq, core)
+        self.assertEqual(init.cfgmgr, core)
+        self.assertEqual(init.ccsession, core)
+        self.assertEqual(init.creator, core)
+        self.assertEqual(init.auth, auth)
+        self.assertEqual(init.resolver, resolver)
+        self.assertEqual(init.xfrout, auth)
+        self.assertEqual(init.xfrin, auth)
+        self.assertEqual(init.zonemgr, auth)
+        self.assertEqual(init.stats, core)
+        self.assertEqual(init.stats_httpd, core)
+        self.assertEqual(init.cmdctl, core)
+        self.check_environment_unchanged()
+
+    def check_preconditions(self, init):
+        self.check_started(init, False, False, False)
+
+    def check_started_none(self, init):
+        """
+        Check that the situation is according to configuration where no servers
+        should be started. Some components still need to be running.
+        """
+        self.check_started(init, True, False, False)
+        self.check_environment_unchanged()
+
+    def check_started_both(self, init):
+        """
+        Check the situation is according to configuration where both servers
+        (auth and resolver) are enabled.
+        """
+        self.check_started(init, True, True, True)
+        self.check_environment_unchanged()
+
+    def check_started_auth(self, init):
+        """
+        Check the set of components needed to run auth only is started.
+        """
+        self.check_started(init, True, True, False)
+        self.check_environment_unchanged()
+
+    def check_started_resolver(self, init):
+        """
+        Check the set of components needed to run resolver only is started.
+        """
+        self.check_started(init, True, False, True)
+        self.check_environment_unchanged()
+
+    def check_started_dhcp(self, init, v4, v6):
+        """
+        Check if proper combinations of DHCPv4 and DHCpv6 can be started
+        """
+        self.assertEqual(v4, init.dhcp4)
+        self.assertEqual(v6, init.dhcp6)
+        self.check_environment_unchanged()
+
+    def construct_config(self, start_auth, start_resolver):
+        # The things that are common, not turned on an off
+        config = {}
+        config['b10-stats'] = { 'kind': 'dispensable', 'address': 'Stats' }
+        config['b10-stats-httpd'] = { 'kind': 'dispensable',
+                                      'address': 'StatsHttpd' }
+        config['b10-cmdctl'] = { 'kind': 'needed', 'special': 'cmdctl' }
+        if start_auth:
+            config['b10-auth'] = { 'kind': 'needed', 'special': 'auth' }
+            config['b10-xfrout'] = { 'kind': 'dispensable',
+                                     'address': 'Xfrout' }
+            config['b10-xfrin'] = { 'kind': 'dispensable',
+                                    'address': 'Xfrin' }
+            config['b10-zonemgr'] = { 'kind': 'dispensable',
+                                      'address': 'Zonemgr' }
+        if start_resolver:
+            config['b10-resolver'] = { 'kind': 'needed',
+                                       'special': 'resolver' }
+        return {'components': config}
+
+    def config_start_init(self, start_auth, start_resolver):
+        """
+        Test the configuration is loaded at the startup.
+        """
+        init = MockInit()
+        config = self.construct_config(start_auth, start_resolver)
+        class CC:
+            def get_full_config(self):
+                return config
+        # Provide the fake CC with data
+        init.ccs = CC()
+        # And make sure it's not overwritten
+        def start_ccsession():
+            init.ccsession = True
+        init.start_ccsession = lambda _: start_ccsession()
+        # We need to return the original _read_bind10_config
+        init._read_bind10_config = lambda: Init._read_bind10_config(init)
+        init.start_all_components()
+        self.check_started(init, True, start_auth, start_resolver)
+        self.check_environment_unchanged()
+
+    def test_start_none(self):
+        self.config_start_init(False, False)
+
+    def test_start_resolver(self):
+        self.config_start_init(False, True)
+
+    def test_start_auth(self):
+        self.config_start_init(True, False)
+
+    def test_start_both(self):
+        self.config_start_init(True, True)
+
+    def test_config_start(self):
+        """
+        Test that the configuration starts and stops components according
+        to configuration changes.
+        """
+
+        # Create Init and ensure correct initialization
+        init = MockInit()
+        self.check_preconditions(init)
+
+        init.start_all_components()
+        init.runnable = True
+        init.config_handler(self.construct_config(False, False))
+        self.check_started_none(init)
+
+        # Enable both at once
+        init.config_handler(self.construct_config(True, True))
+        self.check_started_both(init)
+
+        # Not touched by empty change
+        init.config_handler({})
+        self.check_started_both(init)
+
+        # Not touched by change to the same configuration
+        init.config_handler(self.construct_config(True, True))
+        self.check_started_both(init)
+
+        # Turn them both off again
+        init.config_handler(self.construct_config(False, False))
+        self.check_started_none(init)
+
+        # Not touched by empty change
+        init.config_handler({})
+        self.check_started_none(init)
+
+        # Not touched by change to the same configuration
+        init.config_handler(self.construct_config(False, False))
+        self.check_started_none(init)
+
+        # Start and stop auth separately
+        init.config_handler(self.construct_config(True, False))
+        self.check_started_auth(init)
+
+        init.config_handler(self.construct_config(False, False))
+        self.check_started_none(init)
+
+        # Start and stop resolver separately
+        init.config_handler(self.construct_config(False, True))
+        self.check_started_resolver(init)
+
+        init.config_handler(self.construct_config(False, False))
+        self.check_started_none(init)
+
+        # Alternate
+        init.config_handler(self.construct_config(True, False))
+        self.check_started_auth(init)
+
+        init.config_handler(self.construct_config(False, True))
+        self.check_started_resolver(init)
+
+        init.config_handler(self.construct_config(True, False))
+        self.check_started_auth(init)
+
+    def test_config_start_once(self):
+        """
+        Tests that a component is started only once.
+        """
+        # Create Init and ensure correct initialization
+        init = MockInit()
+        self.check_preconditions(init)
+
+        init.start_all_components()
+
+        init.runnable = True
+        init.config_handler(self.construct_config(True, True))
+        self.check_started_both(init)
+
+        init.start_auth = lambda: self.fail("Started auth again")
+        init.start_xfrout = lambda: self.fail("Started xfrout again")
+        init.start_xfrin = lambda: self.fail("Started xfrin again")
+        init.start_zonemgr = lambda: self.fail("Started zonemgr again")
+        init.start_resolver = lambda: self.fail("Started resolver again")
+
+        # Send again we want to start them. Should not do it, as they are.
+        init.config_handler(self.construct_config(True, True))
+
+    def test_config_not_started_early(self):
+        """
+        Test that components are not started by the config handler before
+        startup.
+        """
+        init = MockInit()
+        self.check_preconditions(init)
+
+        init.start_auth = lambda: self.fail("Started auth again")
+        init.start_xfrout = lambda: self.fail("Started xfrout again")
+        init.start_xfrin = lambda: self.fail("Started xfrin again")
+        init.start_zonemgr = lambda: self.fail("Started zonemgr again")
+        init.start_resolver = lambda: self.fail("Started resolver again")
+
+        init.config_handler({'start_auth': True, 'start_resolver': True})
+
+    # Checks that DHCP (v4 and v6) components are started when expected
+    def test_start_dhcp(self):
+
+        # Create Init and ensure correct initialization
+        init = MockInit()
+        self.check_preconditions(init)
+
+        init.start_all_components()
+        init.config_handler(self.construct_config(False, False))
+        self.check_started_dhcp(init, False, False)
+
+    def test_start_dhcp_v6only(self):
+        # Create Init and ensure correct initialization
+        init = MockInit()
+        self.check_preconditions(init)
+        # v6 only enabled
+        init.start_all_components()
+        init.runnable = True
+        init._Init_started = True
+        config = self.construct_config(False, False)
+        config['components']['b10-dhcp6'] = { 'kind': 'needed',
+                                              'address': 'Dhcp6' }
+        init.config_handler(config)
+        self.check_started_dhcp(init, False, True)
+
+        # uncomment when dhcpv4 becomes implemented
+        # v4 only enabled
+        #init.cfg_start_dhcp6 = False
+        #init.cfg_start_dhcp4 = True
+        #self.check_started_dhcp(init, True, False)
+
+        # both v4 and v6 enabled
+        #init.cfg_start_dhcp6 = True
+        #init.cfg_start_dhcp4 = True
+        #self.check_started_dhcp(init, True, True)
+
+class MockComponent:
+    def __init__(self, name, pid, address=None):
+        self.name = lambda: name
+        self.pid = lambda: pid
+        self.address = lambda: address
+        self.restarted = False
+        self.forceful = False
+        self.running = True
+        self.has_failed = False
+
+    def get_restart_time(self):
+        return 0                # arbitrary dummy value
+
+    def restart(self, now):
+        self.restarted = True
+        return True
+
+    def is_running(self):
+        return self.running
+
+    def failed(self, status):
+        return self.has_failed
+
+    def kill(self, forceful):
+        self.forceful = forceful
+
+class TestInitCmd(unittest.TestCase):
+    def test_ping(self):
+        """
+        Confirm simple ping command works.
+        """
+        init = MockInit()
+        answer = init.command_handler("ping", None)
+        self.assertEqual(answer, {'result': [0, 'pong']})
+
+    def test_show_processes_empty(self):
+        """
+        Confirm getting a list of processes works.
+        """
+        init = MockInit()
+        answer = init.command_handler("show_processes", None)
+        self.assertEqual(answer, {'result': [0, []]})
+
+    def test_show_processes(self):
+        """
+        Confirm getting a list of processes works.
+        """
+        init = MockInit()
+        init.register_process(1, MockComponent('first', 1))
+        init.register_process(2, MockComponent('second', 2, 'Second'))
+        answer = init.command_handler("show_processes", None)
+        processes = [[1, 'first', None],
+                     [2, 'second', 'Second']]
+        self.assertEqual(answer, {'result': [0, processes]})
+
+class TestParseArgs(unittest.TestCase):
+    """
+    This tests parsing of arguments of the bind10 master process.
+    """
+    #TODO: Write tests for the original parsing, bad options, etc.
+    def test_no_opts(self):
+        """
+        Test correct default values when no options are passed.
+        """
+        options = parse_args([], TestOptParser)
+        self.assertEqual(None, options.data_path)
+        self.assertEqual(None, options.config_file)
+        self.assertEqual(None, options.cmdctl_port)
+
+    def test_data_path(self):
+        """
+        Test it can parse the data path.
+        """
+        self.assertRaises(OptsError, parse_args, ['-p'], TestOptParser)
+        self.assertRaises(OptsError, parse_args, ['--data-path'],
+                          TestOptParser)
+        options = parse_args(['-p', '/data/path'], TestOptParser)
+        self.assertEqual('/data/path', options.data_path)
+        options = parse_args(['--data-path=/data/path'], TestOptParser)
+        self.assertEqual('/data/path', options.data_path)
+
+    def test_config_filename(self):
+        """
+        Test it can parse the config switch.
+        """
+        self.assertRaises(OptsError, parse_args, ['-c'], TestOptParser)
+        self.assertRaises(OptsError, parse_args, ['--config-file'],
+                          TestOptParser)
+        options = parse_args(['-c', 'config-file'], TestOptParser)
+        self.assertEqual('config-file', options.config_file)
+        options = parse_args(['--config-file=config-file'], TestOptParser)
+        self.assertEqual('config-file', options.config_file)
+
+    def test_clear_config(self):
+        options = parse_args([], TestOptParser)
+        self.assertEqual(False, options.clear_config)
+        options = parse_args(['--clear-config'], TestOptParser)
+        self.assertEqual(True, options.clear_config)
+
+    def test_nokill(self):
+        options = parse_args([], TestOptParser)
+        self.assertEqual(False, options.nokill)
+        options = parse_args(['--no-kill'], TestOptParser)
+        self.assertEqual(True, options.nokill)
+        options = parse_args([], TestOptParser)
+        self.assertEqual(False, options.nokill)
+        options = parse_args(['-i'], TestOptParser)
+        self.assertEqual(True, options.nokill)
+
+    def test_cmdctl_port(self):
+        """
+        Test it can parse the command control port.
+        """
+        self.assertRaises(OptsError, parse_args, ['--cmdctl-port=abc'],
+                                                TestOptParser)
+        self.assertRaises(OptsError, parse_args, ['--cmdctl-port=100000000'],
+                                                TestOptParser)
+        self.assertRaises(OptsError, parse_args, ['--cmdctl-port'],
+                          TestOptParser)
+        options = parse_args(['--cmdctl-port=1234'], TestOptParser)
+        self.assertEqual(1234, options.cmdctl_port)
+
+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()
+        with open(self.pid_file, "r") as f:
+            self.assertEqual(my_pid, int(f.read()))
+
+    def test_dump_pid(self):
+        self.check_pid_file()
+
+        # make sure any existing content will be removed
+        with open(self.pid_file, "w") as f:
+            f.write('dummy data\n')
+        self.check_pid_file()
+
+    def test_unlink_pid_file_notexist(self):
+        dummy_data = 'dummy_data\n'
+
+        with open(self.pid_file, "w") as f:
+            f.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.
+        with open(self.pid_file, "r") as f:
+            self.assertEqual(dummy_data, f.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'
+
+        with open(self.pid_file, "w") as f:
+            f.write(dummy_data)
+
+        unlink_pid_file(None)
+
+        with open(self.pid_file, "r") as f:
+            self.assertEqual(dummy_data, f.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')
+
+class TestInitComponents(unittest.TestCase):
+    """
+    Test b10-init propagates component configuration properly to the
+    component configurator and acts sane.
+    """
+    def setUp(self):
+        self.__param = None
+        self.__called = False
+        self.__compconfig = {
+            'comp': {
+                'kind': 'needed',
+                'process': 'cat'
+            }
+        }
+        self._tmp_time = None
+        self._tmp_sleep = None
+        self._tmp_module_cc_session = None
+        self._tmp_cc_session = None
+
+    def tearDown(self):
+        if self._tmp_time is not None:
+            time.time = self._tmp_time
+        if self._tmp_sleep is not None:
+            time.sleep = self._tmp_sleep
+        if self._tmp_module_cc_session is not None:
+            isc.config.ModuleCCSession = self._tmp_module_cc_session
+        if self._tmp_cc_session is not None:
+            isc.cc.Session = self._tmp_cc_session
+
+    def __unary_hook(self, param):
+        """
+        A hook function that stores the parameter for later examination.
+        """
+        self.__param = param
+
+    def __nullary_hook(self):
+        """
+        A hook function that notes down it was called.
+        """
+        self.__called = True
+
+    def __check_core(self, config):
+        """
+        A function checking that the config contains parts for the valid
+        core component configuration.
+        """
+        self.assertIsNotNone(config)
+        for component in ['sockcreator', 'msgq', 'cfgmgr']:
+            self.assertTrue(component in config)
+            self.assertEqual(component, config[component]['special'])
+            self.assertEqual('core', config[component]['kind'])
+
+    def __check_extended(self, config):
+        """
+        This checks that the config contains the core and one more component.
+        """
+        self.__check_core(config)
+        self.assertTrue('comp' in config)
+        self.assertEqual('cat', config['comp']['process'])
+        self.assertEqual('needed', config['comp']['kind'])
+        self.assertEqual(4, len(config))
+
+    def test_correct_run(self):
+        """
+        Test the situation when we run in usual scenario, nothing fails,
+        we just start, reconfigure and then stop peacefully.
+        """
+        init = MockInit()
+        # Start it
+        orig = init._component_configurator.startup
+        init._component_configurator.startup = self.__unary_hook
+        init.start_all_components()
+        init._component_configurator.startup = orig
+        self.__check_core(self.__param)
+        self.assertEqual(3, len(self.__param))
+
+        # Reconfigure it
+        self.__param = None
+        orig = init._component_configurator.reconfigure
+        init._component_configurator.reconfigure = self.__unary_hook
+        # Otherwise it does not work
+        init.runnable = True
+        init.config_handler({'components': self.__compconfig})
+        self.__check_extended(self.__param)
+        currconfig = self.__param
+        # If we reconfigure it, but it does not contain the components part,
+        # nothing is called
+        init.config_handler({})
+        self.assertEqual(self.__param, currconfig)
+        self.__param = None
+        init._component_configurator.reconfigure = orig
+        # Check a configuration that messes up the core components is rejected.
+        compconf = dict(self.__compconfig)
+        compconf['msgq'] = { 'process': 'echo' }
+        result = init.config_handler({'components': compconf})
+        # Check it rejected it
+        self.assertEqual(1, result['result'][0])
+
+        # We can't call shutdown, that one relies on the stuff in main
+        # We check somewhere else that the shutdown is actually called
+        # from there (the test_kills).
+
+    def __real_test_kill(self, nokill=False, ex_on_kill=None):
+        """
+        Helper function that does the actual kill functionality testing.
+        """
+        init = MockInit()
+        init.nokill = nokill
+
+        killed = []
+        class ImmortalComponent:
+            """
+            An immortal component. It does not stop when it is told so
+            (anyway it is not told so). It does not die if it is killed
+            the first time. It dies only when killed forcefully.
+            """
+            def __init__(self):
+                # number of kill() calls, preventing infinite loop.
+                self.__call_count = 0
+
+            def kill(self, forceful=False):
+                self.__call_count += 1
+                if self.__call_count > 2:
+                    raise Exception('Too many calls to ImmortalComponent.kill')
+
+                killed.append(forceful)
+                if ex_on_kill is not None:
+                    # If exception is given by the test, raise it here.
+                    # In the case of ESRCH, the process should have gone
+                    # somehow, so we clear the components.
+                    if ex_on_kill.errno == errno.ESRCH:
+                        init.components = {}
+                    raise ex_on_kill
+                if forceful:
+                    init.components = {}
+            def pid(self):
+                return 1
+            def name(self):
+                return "Immortal"
+        init.components = {}
+        init.register_process(1, ImmortalComponent())
+
+        # While at it, we check the configurator shutdown is actually called
+        orig = init._component_configurator.shutdown
+        init._component_configurator.shutdown = self.__nullary_hook
+        self.__called = False
+
+        init.ccs = MockModuleCCSession()
+        self.assertFalse(init.ccs.stopped)
+
+        init.shutdown()
+
+        self.assertTrue(init.ccs.stopped)
+
+        # Here, killed is an array where False is added if SIGTERM
+        # should be sent, or True if SIGKILL should be sent, in order in
+        # which they're sent.
+        if nokill:
+            self.assertEqual([], killed)
+        else:
+            if ex_on_kill is not None:
+                self.assertEqual([False], killed)
+            else:
+                self.assertEqual([False, True], killed)
+
+        self.assertTrue(self.__called)
+
+        init._component_configurator.shutdown = orig
+
+    def test_kills(self):
+        """
+        Test that b10-init kills components which don't want to stop.
+        """
+        self.__real_test_kill()
+
+    def test_kill_fail(self):
+        """Test cases where kill() results in an exception due to OS error.
+
+        The behavior should be different for EPERM, so we test two cases.
+
+        """
+
+        ex = OSError()
+        ex.errno, ex.strerror = errno.ESRCH, 'No such process'
+        self.__real_test_kill(ex_on_kill=ex)
+
+        ex.errno, ex.strerror = errno.EPERM, 'Operation not permitted'
+        self.__real_test_kill(ex_on_kill=ex)
+
+    def test_nokill(self):
+        """
+        Test that b10-init *doesn't* kill components which don't want to
+        stop, when asked not to (by passing the --no-kill option which
+        sets init.nokill to True).
+        """
+        self.__real_test_kill(True)
+
+    def test_component_shutdown(self):
+        """
+        Test the component_shutdown sets all variables accordingly.
+        """
+        init = MockInit()
+        self.assertRaises(Exception, init.component_shutdown, 1)
+        self.assertEqual(1, init.exitcode)
+        init._Init__started = True
+        init.component_shutdown(2)
+        self.assertEqual(2, init.exitcode)
+        self.assertFalse(init.runnable)
+
+    def test_init_config(self):
+        """
+        Test initial configuration is loaded.
+        """
+        init = MockInit()
+        # Start it
+        init._component_configurator.reconfigure = self.__unary_hook
+        # We need to return the original read_bind10_config
+        init._read_bind10_config = lambda: Init._read_bind10_config(init)
+        # And provide a session to read the data from
+        class CC:
+            pass
+        init.ccs = CC()
+        init.ccs.get_full_config = lambda: {'components': self.__compconfig}
+        init.start_all_components()
+        self.__check_extended(self.__param)
+
+    def __setup_restart(self, init, component):
+        '''Common procedure for restarting a component used below.'''
+        init.components_to_restart = { component }
+        component.restarted = False
+        init.restart_processes()
+
+    def test_restart_processes(self):
+        '''Check some behavior on restarting processes.'''
+        init = MockInit()
+        init.runnable = True
+        component = MockComponent('test', 53)
+
+        # A component to be restarted will actually be restarted iff it's
+        # in the configurator's configuration.
+        # We bruteforce the configurator internal below; ugly, but the easiest
+        # way for the test.
+        init._component_configurator._components['test'] = (None, component)
+        self.__setup_restart(init, component)
+        self.assertTrue(component.restarted)
+        self.assertNotIn(component, init.components_to_restart)
+
+        # Remove the component from the configuration.  It won't be restarted
+        # even if scheduled, nor will remain in the to-be-restarted list.
+        del init._component_configurator._components['test']
+        self.__setup_restart(init, component)
+        self.assertFalse(component.restarted)
+        self.assertNotIn(component, init.components_to_restart)
+
+    def test_get_processes(self):
+        '''Test that procsses are returned correctly, sorted by pid.'''
+        init = MockInit()
+
+        pids = list(range(0, 20))
+        random.shuffle(pids)
+
+        for i in range(0, 20):
+            pid = pids[i]
+            component = MockComponent('test' + str(pid), pid,
+                                      'Test' + str(pid))
+            init.components[pid] = component
+
+        process_list = init.get_processes()
+        self.assertEqual(20, len(process_list))
+
+        last_pid = -1
+        for process in process_list:
+            pid = process[0]
+            self.assertLessEqual(last_pid, pid)
+            last_pid = pid
+            self.assertEqual([pid, 'test' + str(pid), 'Test' + str(pid)],
+                             process)
+
+    def _test_reap_children_helper(self, runnable, is_running, failed):
+        '''Construct a Init instance, set various data in it according to
+        passed args and check if the component was added to the list of
+        components to restart.'''
+        init = MockInit()
+        init.runnable = runnable
+
+        component = MockComponent('test', 53)
+        component.running = is_running
+        component.has_failed = failed
+        init.components[53] = component
+
+        self.assertNotIn(component, init.components_to_restart)
+
+        init.reap_children()
+
+        if runnable and is_running and not failed:
+            self.assertIn(component, init.components_to_restart)
+        else:
+            self.assertEqual([], init.components_to_restart)
+
+    def test_reap_children(self):
+        '''Test that children are queued to be restarted when they ask for it.'''
+        # test various combinations of 3 booleans
+        # (Init.runnable, component.is_running(), component.failed())
+        self._test_reap_children_helper(False, False, False)
+        self._test_reap_children_helper(False, False, True)
+        self._test_reap_children_helper(False, True,  False)
+        self._test_reap_children_helper(False, True,  True)
+        self._test_reap_children_helper(True,  False, False)
+        self._test_reap_children_helper(True,  False, True)
+        self._test_reap_children_helper(True,  True,  False)
+        self._test_reap_children_helper(True,  True,  True)
+
+        # setup for more tests below
+        init = MockInit()
+        init.runnable = True
+        component = MockComponent('test', 53)
+        init.components[53] = component
+
+        # case where the returned pid is unknown to us. nothing should
+        # happpen then.
+        init.get_process_exit_status_called = False
+        init._get_process_exit_status = init._get_process_exit_status_unknown_pid
+        init.components_to_restart = []
+        # this should do nothing as the pid is unknown
+        init.reap_children()
+        self.assertEqual([], init.components_to_restart)
+
+        # case where init._get_process_exit_status() raises OSError with
+        # errno.ECHILD
+        init._get_process_exit_status = \
+            init._get_process_exit_status_raises_oserror_echild
+        init.components_to_restart = []
+        # this should catch and handle the OSError
+        init.reap_children()
+        self.assertEqual([], init.components_to_restart)
+
+        # case where init._get_process_exit_status() raises OSError with
+        # errno other than ECHILD
+        init._get_process_exit_status = \
+            init._get_process_exit_status_raises_oserror_other
+        with self.assertRaises(OSError):
+            init.reap_children()
+
+        # case where init._get_process_exit_status() raises something
+        # other than OSError
+        init._get_process_exit_status = \
+            init._get_process_exit_status_raises_other
+        with self.assertRaises(Exception):
+            init.reap_children()
+
+    def test_kill_started_components(self):
+        '''Test that started components are killed.'''
+        init = MockInit()
+
+        component = MockComponent('test', 53, 'Test')
+        init.components[53] = component
+
+        self.assertEqual([[53, 'test', 'Test']], init.get_processes())
+        init.kill_started_components()
+        self.assertEqual([], init.get_processes())
+        self.assertTrue(component.forceful)
+
+    def _start_msgq_helper(self, init, verbose):
+        init.verbose = verbose
+        pi = init.start_msgq()
+        self.assertEqual('b10-msgq', pi.name)
+        self.assertEqual(['b10-msgq'], pi.args)
+        self.assertTrue(pi.dev_null_stdout)
+        self.assertEqual(pi.dev_null_stderr, not verbose)
+        self.assertEqual({'FOO': 'an env string'}, pi.env)
+
+        # this is set by ProcessInfo.spawn()
+        self.assertEqual(42147, pi.pid)
+
+    def test_start_msgq(self):
+        '''Test that b10-msgq is started.'''
+        init = MockInitSimple()
+        init.c_channel_env = {'FOO': 'an env string'}
+        init._run_under_unittests = True
+
+        # use the MockProcessInfo creator
+        init._make_process_info = init._make_mock_process_info
+
+        # non-verbose case
+        self._start_msgq_helper(init, False)
+
+        # verbose case
+        self._start_msgq_helper(init, True)
+
+    def test_start_msgq_timeout(self):
+        '''Test that b10-msgq startup attempts connections several times
+        and times out eventually.'''
+        b10_init = MockInitSimple()
+        b10_init.c_channel_env = {}
+        # set the timeout to an arbitrary pre-determined value (which
+        # code below depends on)
+        b10_init.msgq_timeout = 1
+        b10_init._run_under_unittests = False
+
+        # use the MockProcessInfo creator
+        b10_init._make_process_info = b10_init._make_mock_process_info
+
+        global attempts
+        global tsec
+        attempts = 0
+        tsec = 0
+        self._tmp_time = time.time
+        self._tmp_sleep = time.sleep
+        def _my_time():
+            global attempts
+            global tsec
+            attempts += 1
+            return tsec
+        def _my_sleep(nsec):
+            global tsec
+            tsec += nsec
+        time.time = _my_time
+        time.sleep = _my_sleep
+
+        global cc_sub
+        cc_sub = None
+        class DummySessionAlwaysFails():
+            def __init__(self, socket_file):
+                raise isc.cc.session.SessionError('Connection fails')
+            def group_subscribe(self, s):
+                global cc_sub
+                cc_sub = s
+
+        isc.cc.Session = DummySessionAlwaysFails
+
+        with self.assertRaises(init.CChannelConnectError):
+            # An exception will be thrown here when it eventually times
+            # out.
+            pi = b10_init.start_msgq()
+
+        # time.time() should be called 12 times within the while loop:
+        # starting from 0, and 11 more times from 0.1 to 1.1. There's
+        # another call to time.time() outside the loop, which makes it
+        # 13.
+        self.assertEqual(attempts, 13)
+
+        # group_subscribe() should not have been called here.
+        self.assertIsNone(cc_sub)
+
+        global cc_socket_file
+        cc_socket_file = None
+        cc_sub = None
+        class DummySession():
+            def __init__(self, socket_file):
+                global cc_socket_file
+                cc_socket_file = socket_file
+            def group_subscribe(self, s):
+                global cc_sub
+                cc_sub = s
+
+        isc.cc.Session = DummySession
+
+        # reset values
+        attempts = 0
+        tsec = 0
+
+        pi = b10_init.start_msgq()
+
+        # just one attempt, but 2 calls to time.time()
+        self.assertEqual(attempts, 2)
+
+        self.assertEqual(cc_socket_file, b10_init.msgq_socket_file)
+        self.assertEqual(cc_sub, 'Init')
+
+        # isc.cc.Session, time.time() and time.sleep() are restored
+        # during tearDown().
+
+    def _start_cfgmgr_helper(self, init, data_path, filename, clear_config):
+        expect_args = ['b10-cfgmgr']
+        if data_path is not None:
+            init.data_path = data_path
+            expect_args.append('--data-path=' + data_path)
+        if filename is not None:
+            init.config_filename = filename
+            expect_args.append('--config-filename=' + filename)
+        if clear_config:
+            init.clear_config = clear_config
+            expect_args.append('--clear-config')
+
+        pi = init.start_cfgmgr()
+        self.assertEqual('b10-cfgmgr', pi.name)
+        self.assertEqual(expect_args, pi.args)
+        self.assertEqual({'TESTENV': 'A test string'}, pi.env)
+
+        # this is set by ProcessInfo.spawn()
+        self.assertEqual(42147, pi.pid)
+
+    def test_start_cfgmgr(self):
+        '''Test that b10-cfgmgr is started.'''
+        class DummySession():
+            def __init__(self):
+                self._tries = 0
+            def group_recvmsg(self):
+                self._tries += 1
+                # return running on the 3rd try onwards
+                if self._tries >= 3:
+                    return ({'running': 'ConfigManager'}, None)
+                else:
+                    return ({}, None)
+
+        init = MockInitSimple()
+        init.c_channel_env = {'TESTENV': 'A test string'}
+        init.cc_session = DummySession()
+        init.wait_time = 5
+
+        # use the MockProcessInfo creator
+        init._make_process_info = init._make_mock_process_info
+
+        global attempts
+        attempts = 0
+        self._tmp_sleep = time.sleep
+        def _my_sleep(nsec):
+            global attempts
+            attempts += 1
+        time.sleep = _my_sleep
+
+        # defaults
+        self._start_cfgmgr_helper(init, None, None, False)
+
+        # check that 2 attempts were made. on the 3rd attempt,
+        # process_running() returns that ConfigManager is running.
+        self.assertEqual(attempts, 2)
+
+        # data_path is specified
+        self._start_cfgmgr_helper(init, '/var/lib/test', None, False)
+
+        # config_filename is specified. Because `init` is not
+        # reconstructed, data_path is retained from the last call to
+        # _start_cfgmgr_helper().
+        self._start_cfgmgr_helper(init, '/var/lib/test', 'foo.cfg', False)
+
+        # clear_config is specified. Because `init` is not reconstructed,
+        # data_path and config_filename are retained from the last call
+        # to _start_cfgmgr_helper().
+        self._start_cfgmgr_helper(init, '/var/lib/test', 'foo.cfg', True)
+
+    def test_start_cfgmgr_timeout(self):
+        '''Test that b10-cfgmgr startup attempts connections several times
+        and times out eventually.'''
+        class DummySession():
+            def group_recvmsg(self):
+                return (None, None)
+        b10_init = MockInitSimple()
+        b10_init.c_channel_env = {}
+        b10_init.cc_session = DummySession()
+        # set wait_time to an arbitrary pre-determined value (which code
+        # below depends on)
+        b10_init.wait_time = 2
+
+        # use the MockProcessInfo creator
+        b10_init._make_process_info = b10_init._make_mock_process_info
+
+        global attempts
+        attempts = 0
+        self._tmp_sleep = time.sleep
+        def _my_sleep(nsec):
+            global attempts
+            attempts += 1
+        time.sleep = _my_sleep
+
+        # We just check that an exception was thrown, and that several
+        # attempts were made to connect.
+        with self.assertRaises(init.ProcessStartError):
+            pi = b10_init.start_cfgmgr()
+
+        # 2 seconds of attempts every 1 second should result in 2 attempts
+        self.assertEqual(attempts, 2)
+
+        # time.sleep() is restored during tearDown().
+
+    def test_start_ccsession(self):
+        '''Test that CC session is started.'''
+        class DummySession():
+            def __init__(self, specfile, config_handler, command_handler,
+                         socket_file):
+                self.specfile = specfile
+                self.config_handler = config_handler
+                self.command_handler = command_handler
+                self.socket_file = socket_file
+                self.started = False
+            def start(self):
+                self.started = True
+        b10_init = MockInitSimple()
+        self._tmp_module_cc_session = isc.config.ModuleCCSession
+        isc.config.ModuleCCSession = DummySession
+
+        b10_init.start_ccsession({})
+        self.assertEqual(init.SPECFILE_LOCATION, b10_init.ccs.specfile)
+        self.assertEqual(b10_init.config_handler, b10_init.ccs.config_handler)
+        self.assertEqual(b10_init.command_handler,
+                         b10_init.ccs.command_handler)
+        self.assertEqual(b10_init.msgq_socket_file, b10_init.ccs.socket_file)
+        self.assertTrue(b10_init.ccs.started)
+
+        # isc.config.ModuleCCSession is restored during tearDown().
+
+    def test_start_process(self):
+        '''Test that processes can be started.'''
+        init = MockInit()
+
+        # use the MockProcessInfo creator
+        init._make_process_info = init._make_mock_process_info
+
+        pi = init.start_process('Test Process', ['/bin/true'], {})
+        self.assertEqual('Test Process', pi.name)
+        self.assertEqual(['/bin/true'], pi.args)
+        self.assertEqual({}, pi.env)
+
+        # this is set by ProcessInfo.spawn()
+        self.assertEqual(42147, pi.pid)
+
+    def test_register_process(self):
+        '''Test that processes can be registered with Init.'''
+        init = MockInit()
+        component = MockComponent('test', 53, 'Test')
+
+        self.assertFalse(53 in init.components)
+        init.register_process(53, component)
+        self.assertTrue(53 in init.components)
+        self.assertEqual(init.components[53].name(), 'test')
+        self.assertEqual(init.components[53].pid(), 53)
+        self.assertEqual(init.components[53].address(), 'Test')
+
+    def _start_simple_helper(self, init, verbose):
+        init.verbose = verbose
+
+        args = ['/bin/true']
+        if verbose:
+            args.append('-v')
+
+        init.start_simple('/bin/true')
+        self.assertEqual('/bin/true', init.started_process_name)
+        self.assertEqual(args, init.started_process_args)
+        self.assertEqual({'TESTENV': 'A test string'}, init.started_process_env)
+
+    def test_start_simple(self):
+        '''Test simple process startup.'''
+        init = MockInitSimple()
+        init.c_channel_env = {'TESTENV': 'A test string'}
+
+        # non-verbose case
+        self._start_simple_helper(init, False)
+
+        # verbose case
+        self._start_simple_helper(init, True)
+
+    def _start_auth_helper(self, init, verbose):
+        init.verbose = verbose
+
+        args = ['b10-auth']
+        if verbose:
+            args.append('-v')
+
+        init.start_auth()
+        self.assertEqual('b10-auth', init.started_process_name)
+        self.assertEqual(args, init.started_process_args)
+        self.assertEqual({'FOO': 'an env string'}, init.started_process_env)
+
+    def test_start_auth(self):
+        '''Test that b10-auth is started.'''
+        init = MockInitSimple()
+        init.c_channel_env = {'FOO': 'an env string'}
+
+        # non-verbose case
+        self._start_auth_helper(init, False)
+
+        # verbose case
+        self._start_auth_helper(init, True)
+
+    def _start_resolver_helper(self, init, verbose):
+        init.verbose = verbose
+
+        args = ['b10-resolver']
+        if verbose:
+            args.append('-v')
+
+        init.start_resolver()
+        self.assertEqual('b10-resolver', init.started_process_name)
+        self.assertEqual(args, init.started_process_args)
+        self.assertEqual({'BAR': 'an env string'}, init.started_process_env)
+
+    def test_start_resolver(self):
+        '''Test that b10-resolver is started.'''
+        init = MockInitSimple()
+        init.c_channel_env = {'BAR': 'an env string'}
+
+        # non-verbose case
+        self._start_resolver_helper(init, False)
+
+        # verbose case
+        self._start_resolver_helper(init, True)
+
+    def _start_cmdctl_helper(self, init, verbose, port = None):
+        init.verbose = verbose
+
+        args = ['b10-cmdctl']
+
+        if port is not None:
+            init.cmdctl_port = port
+            args.append('--port=9353')
+
+        if verbose:
+            args.append('-v')
+
+        init.start_cmdctl()
+        self.assertEqual('b10-cmdctl', init.started_process_name)
+        self.assertEqual(args, init.started_process_args)
+        self.assertEqual({'BAZ': 'an env string'}, init.started_process_env)
+
+    def test_start_cmdctl(self):
+        '''Test that b10-cmdctl is started.'''
+        init = MockInitSimple()
+        init.c_channel_env = {'BAZ': 'an env string'}
+
+        # non-verbose case
+        self._start_cmdctl_helper(init, False)
+
+        # verbose case
+        self._start_cmdctl_helper(init, True)
+
+        # with port, non-verbose case
+        self._start_cmdctl_helper(init, False, 9353)
+
+        # with port, verbose case
+        self._start_cmdctl_helper(init, True, 9353)
+
+    def test_socket_data(self):
+        '''Test that Init._socket_data works as expected.'''
+        class MockSock:
+            def __init__(self, fd, throw):
+                self.fd = fd
+                self.throw = throw
+                self.buf = b'Hello World.\nYou are so nice today.\nXX'
+                self.i = 0
+
+            def recv(self, bufsize, flags = 0):
+                if bufsize != 1:
+                    raise Exception('bufsize != 1')
+                if flags != socket.MSG_DONTWAIT:
+                    raise Exception('flags != socket.MSG_DONTWAIT')
+                # after 15 recv()s, throw a socket.error with EAGAIN to
+                # get _socket_data() to save back what's been read. The
+                # number 15 is arbitrarily chosen, but the checks then
+                # depend on this being 15, i.e., if you adjust this
+                # number, you may have to adjust the checks below too.
+                if self.throw and self.i > 15:
+                    raise socket.error(errno.EAGAIN, 'Try again')
+                if self.i >= len(self.buf):
+                    return b'';
+                t = self.i
+                self.i += 1
+                return self.buf[t:t+1]
+
+            def close(self):
+                return
+
+        class MockInitSocketData(Init):
+            def __init__(self, throw):
+                self._unix_sockets = {42: (MockSock(42, throw), b'')}
+                self.requests = []
+                self.dead = []
+
+            def socket_request_handler(self, previous, sock):
+                self.requests.append({sock.fd: previous})
+
+            def socket_consumer_dead(self, sock):
+                self.dead.append(sock.fd)
+
+        # Case where we get data every time we call recv()
+        init = MockInitSocketData(False)
+        init._socket_data(42)
+        self.assertEqual(init.requests,
+                         [{42: b'Hello World.'},
+                          {42: b'You are so nice today.'}])
+        self.assertEqual(init.dead, [42])
+        self.assertEqual({}, init._unix_sockets)
+
+        # Case where socket.recv() raises EAGAIN. In this case, the
+        # routine is supposed to save what it has back to
+        # Init._unix_sockets.
+        init = MockInitSocketData(True)
+        init._socket_data(42)
+        self.assertEqual(init.requests, [{42: b'Hello World.'}])
+        self.assertFalse(init.dead)
+        self.assertEqual(len(init._unix_sockets), 1)
+        self.assertEqual(init._unix_sockets[42][1], b'You')
+
+    def test_startup(self):
+        '''Test that Init.startup() handles failures properly.'''
+        class MockInitStartup(Init):
+            def __init__(self, throw):
+                self.throw = throw
+                self.started = False
+                self.killed = False
+                self.msgq_socket_file = None
+                self.curproc = 'myproc'
+                self.runnable = False
+
+            def start_all_components(self):
+                self.started = True
+                if self.throw is True:
+                    raise Exception('Assume starting components has failed.')
+                elif self.throw:
+                    raise self.throw
+
+            def kill_started_components(self):
+                self.killed = True
+
+        class DummySession():
+            def __init__(self, socket_file):
+                raise isc.cc.session.SessionError('This is the expected case.')
+
+        class DummySessionSocketExists():
+            def __init__(self, socket_file):
+                # simulate that connect passes
+                return
+
+        isc.cc.Session = DummySession
+
+        # All is well case, where all components are started
+        # successfully. We check that the actual call to
+        # start_all_components() is made, and Init.runnable is true.
+        b10_init = MockInitStartup(False)
+        r = b10_init.startup()
+        self.assertIsNone(r)
+        self.assertTrue(b10_init.started)
+        self.assertFalse(b10_init.killed)
+        self.assertTrue(b10_init.runnable)
+        self.assertEqual({}, b10_init.c_channel_env)
+
+        # Case where starting components fails. We check that
+        # kill_started_components() is called right after, and
+        # Init.runnable is not modified.
+        b10_init = MockInitStartup(True)
+        r = b10_init.startup()
+        # r contains an error message
+        self.assertEqual(r, 'Unable to start myproc: Assume starting components has failed.')
+        self.assertTrue(b10_init.started)
+        self.assertTrue(b10_init.killed)
+        self.assertFalse(b10_init.runnable)
+        self.assertEqual({}, b10_init.c_channel_env)
+
+        # Check if msgq_socket_file is carried over
+        b10_init = MockInitStartup(False)
+        b10_init.msgq_socket_file = 'foo'
+        r = b10_init.startup()
+        self.assertEqual({'BIND10_MSGQ_SOCKET_FILE': 'foo'},
+                         b10_init.c_channel_env)
+
+        # Check failure of changing user results in a different message
+        b10_init = MockInitStartup(init.ChangeUserError('failed to chusr'))
+        r = b10_init.startup()
+        self.assertIn('failed to chusr', r)
+        self.assertTrue(b10_init.killed)
+
+        # Check the case when socket file already exists
+        isc.cc.Session = DummySessionSocketExists
+        b10_init = MockInitStartup(False)
+        r = b10_init.startup()
+        self.assertIn('already running', r)
+
+        # isc.cc.Session is restored during tearDown().
+
+class SocketSrvTest(unittest.TestCase):
+    """
+    This tests some methods of b10-init related to the unix domain sockets
+    used to transfer other sockets to applications.
+    """
+    def setUp(self):
+        """
+        Create the b10-init to test, testdata and backup some functions.
+        """
+        self.__b10_init = Init()
+        self.__select_backup = init.select.select
+        self.__select_called = None
+        self.__socket_data_called = None
+        self.__consumer_dead_called = None
+        self.__socket_request_handler_called = None
+
+    def tearDown(self):
+        """
+        Restore functions.
+        """
+        init.select.select = self.__select_backup
+
+    class __FalseSocket:
+        """
+        A mock socket for the select and accept and stuff like that.
+        """
+        def __init__(self, owner, fileno=42):
+            self.__owner = owner
+            self.__fileno = fileno
+            self.data = None
+            self.closed = False
+
+        def fileno(self):
+            return self.__fileno
+
+        def accept(self):
+            return (self.__class__(self.__owner, 13), "/path/to/socket")
+
+        def recv(self, bufsize, flags=0):
+            self.__owner.assertEqual(1, bufsize)
+            self.__owner.assertEqual(socket.MSG_DONTWAIT, flags)
+            if isinstance(self.data, socket.error):
+                raise self.data
+            elif self.data is not None:
+                if len(self.data):
+                    result = self.data[0:1]
+                    self.data = self.data[1:]
+                    return result
+                else:
+                    raise socket.error(errno.EAGAIN, "Would block")
+            else:
+                return b''
+
+        def close(self):
+            self.closed = True
+
+    class __CCS:
+        """
+        A mock CCS, just to provide the socket file number.
+        """
+        class __Socket:
+            def fileno(self):
+                return 1
+        def get_socket(self):
+            return self.__Socket()
+
+    def __select_accept(self, r, w, x, t):
+        self.__select_called = (r, w, x, t)
+        return ([42], [], [])
+
+    def __select_data(self, r, w, x, t):
+        self.__select_called = (r, w, x, t)
+        return ([13], [], [])
+
+    def __accept(self):
+        """
+        Hijack the accept method of the b10-init.
+
+        Notes down it was called and stops b10-init.
+        """
+        self.__accept_called = True
+        self.__b10_init.runnable = False
+
+    def test_srv_accept_called(self):
+        """
+        Test that the _srv_accept method of b10-init is called when the
+        listening socket is readable.
+        """
+        self.__b10_init.runnable = True
+        self.__b10_init._srv_socket = self.__FalseSocket(self)
+        self.__b10_init._srv_accept = self.__accept
+        self.__b10_init.ccs = self.__CCS()
+        init.select.select = self.__select_accept
+        self.__b10_init.run(2)
+        # It called the accept
+        self.assertTrue(self.__accept_called)
+        # And the select had the right parameters
+        self.assertEqual(([2, 1, 42], [], [], None), self.__select_called)
+
+    def test_srv_accept(self):
+        """
+        Test how the _srv_accept method works.
+        """
+        self.__b10_init._srv_socket = self.__FalseSocket(self)
+        self.__b10_init._srv_accept()
+        # After we accepted, a new socket is added there
+        socket = self.__b10_init._unix_sockets[13][0]
+        # The socket is properly stored there
+        self.assertTrue(isinstance(socket, self.__FalseSocket))
+        # And the buffer (yet empty) is there
+        self.assertEqual({13: (socket, b'')}, self.__b10_init._unix_sockets)
+
+    def __socket_data(self, socket):
+        self.__b10_init.runnable = False
+        self.__socket_data_called = socket
+
+    def test_socket_data(self):
+        """
+        Test that a socket that wants attention gets it.
+        """
+        self.__b10_init._srv_socket = self.__FalseSocket(self)
+        self.__b10_init._socket_data = self.__socket_data
+        self.__b10_init.ccs = self.__CCS()
+        self.__b10_init._unix_sockets = {13: (self.__FalseSocket(self, 13), b'')}
+        self.__b10_init.runnable = True
+        init.select.select = self.__select_data
+        self.__b10_init.run(2)
+        self.assertEqual(13, self.__socket_data_called)
+        self.assertEqual(([2, 1, 42, 13], [], [], None), self.__select_called)
+
+    def __prepare_data(self, data):
+        socket = self.__FalseSocket(self, 13)
+        self.__b10_init._unix_sockets = {13: (socket, b'')}
+        socket.data = data
+        self.__b10_init.socket_consumer_dead = self.__consumer_dead
+        self.__b10_init.socket_request_handler = self.__socket_request_handler
+        return socket
+
+    def __consumer_dead(self, socket):
+        self.__consumer_dead_called = socket
+
+    def __socket_request_handler(self, token, socket):
+        self.__socket_request_handler_called = (token, socket)
+
+    def test_socket_closed(self):
+        """
+        Test that a socket is removed and the socket_consumer_dead is called
+        when it is closed.
+        """
+        socket = self.__prepare_data(None)
+        self.__b10_init._socket_data(13)
+        self.assertEqual(socket, self.__consumer_dead_called)
+        self.assertEqual({}, self.__b10_init._unix_sockets)
+        self.assertTrue(socket.closed)
+
+    def test_socket_short(self):
+        """
+        Test that if there's not enough data to get the whole socket, it is
+        kept there, but nothing is called.
+        """
+        socket = self.__prepare_data(b'tok')
+        self.__b10_init._socket_data(13)
+        self.assertEqual({13: (socket, b'tok')}, self.__b10_init._unix_sockets)
+        self.assertFalse(socket.closed)
+        self.assertIsNone(self.__consumer_dead_called)
+        self.assertIsNone(self.__socket_request_handler_called)
+
+    def test_socket_continue(self):
+        """
+        Test that we call the token handling function when the whole token
+        comes. This test pretends to continue reading where the previous one
+        stopped.
+        """
+        socket = self.__prepare_data(b"en\nanothe")
+        # The data to finish
+        self.__b10_init._unix_sockets[13] = (socket, b'tok')
+        self.__b10_init._socket_data(13)
+        self.assertEqual({13: (socket, b'anothe')}, self.__b10_init._unix_sockets)
+        self.assertFalse(socket.closed)
+        self.assertIsNone(self.__consumer_dead_called)
+        self.assertEqual((b'token', socket),
+                         self.__socket_request_handler_called)
+
+    def test_broken_socket(self):
+        """
+        If the socket raises an exception during the read other than EAGAIN,
+        it is broken and we remove it.
+        """
+        sock = self.__prepare_data(socket.error(errno.ENOMEM,
+            "There's more memory available, but not for you"))
+        self.__b10_init._socket_data(13)
+        self.assertEqual(sock, self.__consumer_dead_called)
+        self.assertEqual({}, self.__b10_init._unix_sockets)
+        self.assertTrue(sock.closed)
+
+class TestFunctions(unittest.TestCase):
+    def setUp(self):
+        self.lockfile_testpath = \
+            "@abs_top_builddir@/src/bin/bind10/tests/lockfile_test"
+        self.assertFalse(os.path.exists(self.lockfile_testpath))
+        os.mkdir(self.lockfile_testpath)
+        self.assertTrue(os.path.isdir(self.lockfile_testpath))
+        self.__isfile_orig = init.os.path.isfile
+        self.__unlink_orig = init.os.unlink
+
+    def tearDown(self):
+        os.rmdir(self.lockfile_testpath)
+        self.assertFalse(os.path.isdir(self.lockfile_testpath))
+        os.environ["B10_LOCKFILE_DIR_FROM_BUILD"] = "@abs_top_builddir@"
+        init.os.path.isfile = self.__isfile_orig
+        init.os.unlink = self.__unlink_orig
+
+    def test_remove_lock_files(self):
+        os.environ["B10_LOCKFILE_DIR_FROM_BUILD"] = self.lockfile_testpath
+
+        # create lockfiles for the testcase
+        lockfiles = ["logger_lockfile"]
+        for f in lockfiles:
+            fname = os.environ["B10_LOCKFILE_DIR_FROM_BUILD"] + '/' + f
+            self.assertFalse(os.path.exists(fname))
+            open(fname, "w").close()
+            self.assertTrue(os.path.isfile(fname))
+
+        # first call should clear up all the lockfiles
+        init.remove_lock_files()
+
+        # check if the lockfiles exist
+        for f in lockfiles:
+            fname = os.environ["B10_LOCKFILE_DIR_FROM_BUILD"] + '/' + f
+            self.assertFalse(os.path.isfile(fname))
+
+        # second call should not assert anyway
+        init.remove_lock_files()
+
+    def test_remove_lock_files_fail(self):
+        # Permission error on unlink is ignored; other exceptions are really
+        # unexpected and propagated.
+        def __raising_unlink(unused, ex):
+            raise ex
+
+        init.os.path.isfile = lambda _: True
+        os_error = OSError()
+        init.os.unlink = lambda f: __raising_unlink(f, os_error)
+
+        os_error.errno = errno.EPERM
+        init.remove_lock_files() # no disruption
+
+        os_error.errno = errno.EACCES
+        init.remove_lock_files() # no disruption
+
+        os_error.errno = errno.ENOENT
+        self.assertRaises(OSError, init.remove_lock_files)
+
+        init.os.unlink = lambda f: __raising_unlink(f, Exception('bad'))
+        self.assertRaises(Exception, init.remove_lock_files)
+
+    def test_get_signame(self):
+        # just test with some samples
+        signame = init.get_signame(signal.SIGTERM)
+        self.assertEqual('SIGTERM', signame)
+        signame = init.get_signame(signal.SIGKILL)
+        self.assertEqual('SIGKILL', signame)
+        # 59426 is hopefully an unused signal on most platforms
+        signame = init.get_signame(59426)
+        self.assertEqual('Unknown signal 59426', signame)
+
+    def test_fatal_signal(self):
+        self.assertIsNone(init.b10_init)
+        init.b10_init = Init()
+        init.b10_init.runnable = True
+        init.fatal_signal(signal.SIGTERM, None)
+        # Now, runnable must be False
+        self.assertFalse(init.b10_init.runnable)
+        init.b10_init = None
+
+if __name__ == '__main__':
+    # store os.environ for test_unchanged_environment
+    original_os_environ = copy.deepcopy(os.environ)
+    isc.log.resetUnitTestRootLogger()
+    unittest.main()
diff --git a/src/bin/bind10/tests/init_test.py.in b/src/bin/bind10/tests/init_test.py.in
deleted file mode 100644
index 9a591ef..0000000
--- a/src/bin/bind10/tests/init_test.py.in
+++ /dev/null
@@ -1,2426 +0,0 @@
-# Copyright (C) 2011  Internet Systems Consortium.
-#
-# Permission to use, copy, modify, and 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 INTERNET SYSTEMS CONSORTIUM
-# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
-# INTERNET SYSTEMS CONSORTIUM 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.
-
-# Most of the time, we omit the "init" for brevity. Sometimes,
-# we want to be explicit about what we do, like when hijacking a library
-# call used by the b10-init.
-from init import Init, ProcessInfo, parse_args, dump_pid, unlink_pid_file, _BASETIME
-import init
-
-# 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 os.path
-import copy
-import signal
-import socket
-from isc.net.addr import IPAddr
-import time
-import isc.log
-import isc.config
-import isc.bind10.socket_cache
-import errno
-import random
-
-from isc.testutils.parse_args import TestOptParser, OptsError
-from isc.testutils.ccsession_mock import MockModuleCCSession
-
-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' ])
-        pi.spawn()
-        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)
-        pi.spawn()
-        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' ])
-        pi.spawn()
-        # 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 TestCacheCommands(unittest.TestCase):
-    """
-    Test methods of b10-init related to the socket cache and socket handling.
-    """
-    def setUp(self):
-        """
-        Prepare b10-init for some tests.
-
-        Also prepare some variables we need.
-        """
-        self.__b10_init = Init()
-        # Fake the cache here so we can pretend it is us and hijack the
-        # calls to its methods.
-        self.__b10_init._socket_cache = self
-        self.__b10_init._socket_path = '/socket/path'
-        self.__raise_exception = None
-        self.__socket_args = {
-            "port": 53,
-            "address": "::",
-            "protocol": "UDP",
-            "share_mode": "ANY",
-            "share_name": "app"
-        }
-        # What was and wasn't called.
-        self.__drop_app_called = None
-        self.__get_socket_called = None
-        self.__send_fd_called = None
-        self.__get_token_called = None
-        self.__drop_socket_called = None
-        init.libutil_io_python.send_fd = self.__send_fd
-
-    def __send_fd(self, to, socket):
-        """
-        A function to hook the send_fd in the b10-init.
-        """
-        self.__send_fd_called = (to, socket)
-
-    class FalseSocket:
-        """
-        A socket where we can fake methods we need instead of having a real
-        socket.
-        """
-        def __init__(self):
-            self.send = b""
-        def fileno(self):
-            """
-            The file number. Used for identifying the remote application.
-            """
-            return 42
-
-        def sendall(self, data):
-            """
-            Adds data to the self.send.
-            """
-            self.send += data
-
-    def drop_application(self, application):
-        """
-        Part of pretending to be the cache. Logs the parameter to
-        self.__drop_app_called.
-
-        In the case self.__raise_exception is set, the exception there
-        is raised instead.
-        """
-        if self.__raise_exception is not None:
-            raise self.__raise_exception
-        self.__drop_app_called = application
-
-    def test_consumer_dead(self):
-        """
-        Test that it calls the drop_application method of the cache.
-        """
-        self.__b10_init.socket_consumer_dead(self.FalseSocket())
-        self.assertEqual(42, self.__drop_app_called)
-
-    def test_consumer_dead_invalid(self):
-        """
-        Test that it doesn't crash in case the application is not known to
-        the cache, the b10_init doesn't crash, as this actually can happen in
-        practice.
-        """
-        self.__raise_exception = ValueError("This application is unknown")
-        # This doesn't crash
-        self.__b10_init.socket_consumer_dead(self.FalseSocket())
-
-    def get_socket(self, token, application):
-        """
-        Part of pretending to be the cache. If there's anything in
-        __raise_exception, it is raised. Otherwise, the call is logged
-        into __get_socket_called and a number is returned.
-        """
-        if self.__raise_exception is not None:
-            raise self.__raise_exception
-        self.__get_socket_called = (token, application)
-        return 13
-
-    def test_request_handler(self):
-        """
-        Test that a request for socket is forwarded and the socket is sent
-        back, if it returns a socket.
-        """
-        socket = self.FalseSocket()
-        # An exception from the cache
-        self.__raise_exception = ValueError("Test value error")
-        self.__b10_init.socket_request_handler(b"token", socket)
-        # It was called, but it threw, so it is not noted here
-        self.assertIsNone(self.__get_socket_called)
-        self.assertEqual(b"0\n", socket.send)
-        # It should not have sent any socket.
-        self.assertIsNone(self.__send_fd_called)
-        # Now prepare a valid scenario
-        self.__raise_exception = None
-        socket.send = b""
-        self.__b10_init.socket_request_handler(b"token", socket)
-        self.assertEqual(b"1\n", socket.send)
-        self.assertEqual((42, 13), self.__send_fd_called)
-        self.assertEqual(("token", 42), self.__get_socket_called)
-
-    def get_token(self, protocol, address, port, share_mode, share_name):
-        """
-        Part of pretending to be the cache. If there's anything in
-        __raise_exception, it is raised. Otherwise, the parameters are
-        logged into __get_token_called and a token is returned.
-        """
-        if self.__raise_exception is not None:
-            raise self.__raise_exception
-        self.__get_token_called = (protocol, address, port, share_mode,
-                                   share_name)
-        return "token"
-
-    def test_get_socket_ok(self):
-        """
-        Test the successful scenario of getting a socket.
-        """
-        result = self.__b10_init._get_socket(self.__socket_args)
-        [code, answer] = result['result']
-        self.assertEqual(0, code)
-        self.assertEqual({
-            'token': 'token',
-            'path': '/socket/path'
-        }, answer)
-        addr = self.__get_token_called[1]
-        self.assertTrue(isinstance(addr, IPAddr))
-        self.assertEqual("::", str(addr))
-        self.assertEqual(("UDP", addr, 53, "ANY", "app"),
-                         self.__get_token_called)
-
-    def test_get_socket_error(self):
-        """
-        Test that bad inputs are handled correctly, etc.
-        """
-        def check_code(code, args):
-            """
-            Pass the args there and check if it returns success or not.
-
-            The rest is not tested, as it is already checked in the
-            test_get_socket_ok.
-            """
-            [rcode, ranswer] = self.__b10_init._get_socket(args)['result']
-            self.assertEqual(code, rcode)
-            if code != 0:
-                # This should be an error message. The exact formatting
-                # is unknown, but we check it is string at least
-                self.assertTrue(isinstance(ranswer, str))
-
-        def mod_args(name, value):
-            """
-            Override a parameter in the args.
-            """
-            result = dict(self.__socket_args)
-            result[name] = value
-            return result
-
-        # Port too large
-        check_code(1, mod_args('port', 65536))
-        # Not numeric address
-        check_code(1, mod_args('address', 'example.org.'))
-        # Some bad values of enum-like params
-        check_code(1, mod_args('protocol', 'BAD PROTO'))
-        check_code(1, mod_args('share_mode', 'BAD SHARE'))
-        # Check missing parameters
-        for param in self.__socket_args.keys():
-            args = dict(self.__socket_args)
-            del args[param]
-            check_code(1, args)
-        # These are OK values for the enum-like parameters
-        # The ones from test_get_socket_ok are not tested here
-        check_code(0, mod_args('protocol', 'TCP'))
-        check_code(0, mod_args('share_mode', 'SAMEAPP'))
-        check_code(0, mod_args('share_mode', 'NO'))
-        # If an exception is raised from within the cache, it is converted
-        # to an error, not propagated
-        self.__raise_exception = Exception("Test exception")
-        check_code(1, self.__socket_args)
-        # The special "expected" exceptions
-        self.__raise_exception = \
-            isc.bind10.socket_cache.ShareError("Not shared")
-        check_code(3, self.__socket_args)
-        self.__raise_exception = \
-            isc.bind10.socket_cache.SocketError("Not shared", 13)
-        check_code(2, self.__socket_args)
-
-    def drop_socket(self, token):
-        """
-        Part of pretending to be the cache. If there's anything in
-        __raise_exception, it is raised. Otherwise, the parameter is stored
-        in __drop_socket_called.
-        """
-        if self.__raise_exception is not None:
-            raise self.__raise_exception
-        self.__drop_socket_called = token
-
-    def test_drop_socket(self):
-        """
-        Check the drop_socket command. It should directly call the method
-        on the cache. Exceptions should be translated to error messages.
-        """
-        # This should be OK and just propagated to the call.
-        self.assertEqual({"result": [0]},
-                         self.__b10_init.command_handler("drop_socket",
-                                                         {"token": "token"}))
-        self.assertEqual("token", self.__drop_socket_called)
-        self.__drop_socket_called = None
-        # Missing parameter
-        self.assertEqual({"result": [1, "Missing token parameter"]},
-                         self.__b10_init.command_handler("drop_socket", {}))
-        self.assertIsNone(self.__drop_socket_called)
-        # An exception is raised from within the cache
-        self.__raise_exception = ValueError("Test error")
-        self.assertEqual({"result": [1, "Test error"]},
-                         self.__b10_init.command_handler("drop_socket",
-                         {"token": "token"}))
-
-
-class TestInit(unittest.TestCase):
-    def setUp(self):
-        # Save original values that may be tweaked in some tests
-        self.__orig_setgid = init.posix.setgid
-        self.__orig_setuid = init.posix.setuid
-        self.__orig_logger_class = isc.log.Logger
-
-    def tearDown(self):
-        # Restore original values saved in setUp()
-        init.posix.setgid = self.__orig_setgid
-        init.posix.setuid = self.__orig_setuid
-        isc.log.Logger = self.__orig_logger_class
-
-    def test_init(self):
-        b10_init = Init()
-        self.assertEqual(b10_init.verbose, False)
-        self.assertEqual(b10_init.msgq_socket_file, None)
-        self.assertEqual(b10_init.cc_session, None)
-        self.assertEqual(b10_init.ccs, None)
-        self.assertEqual(b10_init.components, {})
-        self.assertEqual(b10_init.runnable, False)
-        self.assertEqual(b10_init.username, None)
-        self.assertIsNone(b10_init._socket_cache)
-
-    def __setgid(self, gid):
-        self.__gid_set = gid
-
-    def __setuid(self, uid):
-        self.__uid_set = uid
-
-    def test_change_user(self):
-        init.posix.setgid = self.__setgid
-        init.posix.setuid = self.__setuid
-
-        self.__gid_set = None
-        self.__uid_set = None
-        b10_init = Init()
-        b10_init.change_user()
-        # No gid/uid set in init, nothing called.
-        self.assertIsNone(self.__gid_set)
-        self.assertIsNone(self.__uid_set)
-
-        Init(setuid=42, setgid=4200).change_user()
-        # This time, it get's called
-        self.assertEqual(4200, self.__gid_set)
-        self.assertEqual(42, self.__uid_set)
-
-        def raising_set_xid(gid_or_uid):
-            ex = OSError()
-            ex.errno, ex.strerror = errno.EPERM, 'Operation not permitted'
-            raise ex
-
-        # Let setgid raise an exception
-        init.posix.setgid = raising_set_xid
-        init.posix.setuid = self.__setuid
-        self.assertRaises(init.ChangeUserError,
-                          Init(setuid=42, setgid=4200).change_user)
-
-        # Let setuid raise an exception
-        init.posix.setgid = self.__setgid
-        init.posix.setuid = raising_set_xid
-        self.assertRaises(init.ChangeUserError,
-                          Init(setuid=42, setgid=4200).change_user)
-
-        # Let initial log output after setuid raise an exception
-        init.posix.setgid = self.__setgid
-        init.posix.setuid = self.__setuid
-        isc.log.Logger = raising_set_xid
-        self.assertRaises(init.ChangeUserError,
-                          Init(setuid=42, setgid=4200).change_user)
-
-    def test_set_creator(self):
-        """
-        Test the call to set_creator. First time, the cache is created
-        with the passed creator. The next time, it throws an exception.
-        """
-        init = Init()
-        # The cache doesn't use it at start, so just create an empty class
-        class Creator: pass
-        creator = Creator()
-        init.set_creator(creator)
-        self.assertTrue(isinstance(init._socket_cache,
-                        isc.bind10.socket_cache.Cache))
-        self.assertEqual(creator, init._socket_cache._creator)
-        self.assertRaises(ValueError, init.set_creator, creator)
-
-    def test_socket_srv(self):
-        """Tests init_socket_srv() and remove_socket_srv() work as expected."""
-        init = Init()
-
-        self.assertIsNone(init._srv_socket)
-        self.assertIsNone(init._tmpdir)
-        self.assertIsNone(init._socket_path)
-
-        init.init_socket_srv()
-
-        self.assertIsNotNone(init._srv_socket)
-        self.assertNotEqual(-1, init._srv_socket.fileno())
-        self.assertEqual(os.path.join(init._tmpdir, 'sockcreator'),
-                         init._srv_socket.getsockname())
-
-        self.assertIsNotNone(init._tmpdir)
-        self.assertTrue(os.path.isdir(init._tmpdir))
-        self.assertIsNotNone(init._socket_path)
-        self.assertTrue(os.path.exists(init._socket_path))
-
-        # Check that it's possible to connect to the socket file (this
-        # only works if the socket file exists and the server listens on
-        # it).
-        s = socket.socket(socket.AF_UNIX)
-        try:
-            s.connect(init._socket_path)
-            can_connect = True
-            s.close()
-        except socket.error as e:
-            can_connect = False
-
-        self.assertTrue(can_connect)
-
-        init.remove_socket_srv()
-
-        self.assertEqual(-1, init._srv_socket.fileno())
-        self.assertFalse(os.path.exists(init._socket_path))
-        self.assertFalse(os.path.isdir(init._tmpdir))
-
-        # These should not fail either:
-
-        # second call
-        init.remove_socket_srv()
-
-        init._srv_socket = None
-        init.remove_socket_srv()
-
-    def test_init_alternate_socket(self):
-        init = Init("alt_socket_file")
-        self.assertEqual(init.verbose, False)
-        self.assertEqual(init.msgq_socket_file, "alt_socket_file")
-        self.assertEqual(init.cc_session, None)
-        self.assertEqual(init.ccs, None)
-        self.assertEqual(init.components, {})
-        self.assertEqual(init.runnable, False)
-        self.assertEqual(init.username, None)
-
-    def test_command_handler(self):
-        class DummySession():
-            def group_sendmsg(self, msg, group):
-                (self.msg, self.group) = (msg, group)
-            def group_recvmsg(self, nonblock, seq): pass
-        class DummyModuleCCSession():
-            module_spec = isc.config.module_spec.ModuleSpec({
-                    "module_name": "Init",
-                    "statistics": [
-                        {
-                            "item_name": "boot_time",
-                            "item_type": "string",
-                            "item_optional": False,
-                            "item_default": "1970-01-01T00:00:00Z",
-                            "item_title": "Boot time",
-                            "item_description": "A date time when bind10 process starts initially",
-                            "item_format": "date-time"
-                            }
-                        ]
-                    })
-            def get_module_spec(self):
-                return self.module_spec
-        init = Init()
-        init.verbose = True
-        init.cc_session = DummySession()
-        init.ccs = DummyModuleCCSession()
-        # a bad command
-        self.assertEqual(init.command_handler(-1, None),
-                         isc.config.ccsession.create_answer(1, "bad command"))
-        # "shutdown" command
-        self.assertEqual(init.command_handler("shutdown", None),
-                         isc.config.ccsession.create_answer(0))
-        self.assertFalse(init.runnable)
-        # "getstats" command
-        self.assertEqual(init.command_handler("getstats", None),
-                         isc.config.ccsession.create_answer(0,
-                            { 'boot_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', _BASETIME) }))
-        # "ping" command
-        self.assertEqual(init.command_handler("ping", None),
-                         isc.config.ccsession.create_answer(0, "pong"))
-        # "show_processes" command
-        self.assertEqual(init.command_handler("show_processes", None),
-                         isc.config.ccsession.create_answer(0,
-                                                            init.get_processes()))
-        # an unknown command
-        self.assertEqual(init.command_handler("__UNKNOWN__", None),
-                         isc.config.ccsession.create_answer(1, "Unknown command"))
-
-        # Fake the get_token of cache and test the command works
-        init._socket_path = '/socket/path'
-        class cache:
-            def get_token(self, protocol, addr, port, share_mode, share_name):
-                return str(addr) + ':' + str(port)
-        init._socket_cache = cache()
-        args = {
-            "port": 53,
-            "address": "0.0.0.0",
-            "protocol": "UDP",
-            "share_mode": "ANY",
-            "share_name": "app"
-        }
-        # at all and this is the easiest way to check.
-        self.assertEqual({'result': [0, {'token': '0.0.0.0:53',
-                                         'path': '/socket/path'}]},
-                         init.command_handler("get_socket", args))
-        # The drop_socket is not tested here, but in TestCacheCommands.
-        # It needs the cache mocks to be in place and they are there.
-
-    def test_stop_process(self):
-        """
-        Test checking the stop_process method sends the right message over
-        the message bus.
-        """
-        class DummySession():
-            def group_sendmsg(self, msg, group, instance="*"):
-                (self.msg, self.group, self.instance) = (msg, group, instance)
-        init = Init()
-        init.cc_session = DummySession()
-        init.stop_process('process', 'address', 42)
-        self.assertEqual('address', init.cc_session.group)
-        self.assertEqual('address', init.cc_session.instance)
-        self.assertEqual({'command': ['shutdown', {'pid': 42}]},
-                         init.cc_session.msg)
-
-# Mock class for testing Init's usage of ProcessInfo
-class MockProcessInfo:
-    def __init__(self, name, args, env={}, dev_null_stdout=False,
-                 dev_null_stderr=False):
-        self.name = name
-        self.args = args
-        self.env = env
-        self.dev_null_stdout = dev_null_stdout
-        self.dev_null_stderr = dev_null_stderr
-        self.process = None
-        self.pid = None
-
-    def spawn(self):
-        # set some pid (only used for testing that it is not None anymore)
-        self.pid = 42147
-
-# Class for testing the Init without actually starting processes.
-# This is used for testing the start/stop components routines and
-# the Init commands.
-#
-# 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 MockInit(Init):
-    def __init__(self):
-        Init.__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.stats_httpd = False
-        self.cmdctl = False
-        self.dhcp6 = False
-        self.dhcp4 = False
-        self.c_channel_env = {}
-        self.components = { }
-        self.creator = False
-        self.get_process_exit_status_called = False
-
-        class MockSockCreator(isc.bind10.component.Component):
-            def __init__(self, process, b10_init, kind, address=None,
-                         params=None):
-                isc.bind10.component.Component.__init__(self, process,
-                                                        b10_init, kind,
-                                                        'SockCreator')
-                self._start_func = b10_init.start_creator
-
-        specials = isc.bind10.special_component.get_specials()
-        specials['sockcreator'] = MockSockCreator
-        self._component_configurator = \
-            isc.bind10.component.Configurator(self, specials)
-
-    def start_creator(self):
-        self.creator = True
-        procinfo = ProcessInfo('b10-sockcreator', ['/bin/false'])
-        procinfo.pid = 1
-        return procinfo
-
-    def _read_bind10_config(self):
-        # Configuration options are set directly
-        pass
-
-    def start_msgq(self):
-        self.msgq = True
-        procinfo = ProcessInfo('b10-msgq', ['/bin/false'])
-        procinfo.pid = 2
-        return procinfo
-
-    def start_ccsession(self, c_channel_env):
-        # this is not a process, don't have to do anything with procinfo
-        self.ccsession = True
-
-    def start_cfgmgr(self):
-        self.cfgmgr = True
-        procinfo = ProcessInfo('b10-cfgmgr', ['/bin/false'])
-        procinfo.pid = 3
-        return procinfo
-
-    def start_auth(self):
-        self.auth = True
-        procinfo = ProcessInfo('b10-auth', ['/bin/false'])
-        procinfo.pid = 5
-        return procinfo
-
-    def start_resolver(self):
-        self.resolver = True
-        procinfo = ProcessInfo('b10-resolver', ['/bin/false'])
-        procinfo.pid = 6
-        return procinfo
-
-    def start_simple(self, name):
-        procmap = { 'b10-zonemgr': self.start_zonemgr,
-                    'b10-stats': self.start_stats,
-                    'b10-stats-httpd': self.start_stats_httpd,
-                    'b10-cmdctl': self.start_cmdctl,
-                    'b10-dhcp6': self.start_dhcp6,
-                    'b10-dhcp4': self.start_dhcp4,
-                    'b10-xfrin': self.start_xfrin,
-                    'b10-xfrout': self.start_xfrout }
-        return procmap[name]()
-
-    def start_xfrout(self):
-        self.xfrout = True
-        procinfo = ProcessInfo('b10-xfrout', ['/bin/false'])
-        procinfo.pid = 7
-        return procinfo
-
-    def start_xfrin(self):
-        self.xfrin = True
-        procinfo = ProcessInfo('b10-xfrin', ['/bin/false'])
-        procinfo.pid = 8
-        return procinfo
-
-    def start_zonemgr(self):
-        self.zonemgr = True
-        procinfo = ProcessInfo('b10-zonemgr', ['/bin/false'])
-        procinfo.pid = 9
-        return procinfo
-
-    def start_stats(self):
-        self.stats = True
-        procinfo = ProcessInfo('b10-stats', ['/bin/false'])
-        procinfo.pid = 10
-        return procinfo
-
-    def start_stats_httpd(self):
-        self.stats_httpd = True
-        procinfo = ProcessInfo('b10-stats-httpd', ['/bin/false'])
-        procinfo.pid = 11
-        return procinfo
-
-    def start_cmdctl(self):
-        self.cmdctl = True
-        procinfo = ProcessInfo('b10-cmdctl', ['/bin/false'])
-        procinfo.pid = 12
-        return procinfo
-
-    def start_dhcp6(self):
-        self.dhcp6 = True
-        procinfo = ProcessInfo('b10-dhcp6', ['/bin/false'])
-        procinfo.pid = 13
-        return procinfo
-
-    def start_dhcp4(self):
-        self.dhcp4 = True
-        procinfo = ProcessInfo('b10-dhcp4', ['/bin/false'])
-        procinfo.pid = 14
-        return procinfo
-
-    def stop_process(self, process, recipient, pid):
-        procmap = { 'b10-auth': self.stop_auth,
-                    'b10-resolver': self.stop_resolver,
-                    'b10-xfrout': self.stop_xfrout,
-                    'b10-xfrin': self.stop_xfrin,
-                    'b10-zonemgr': self.stop_zonemgr,
-                    'b10-stats': self.stop_stats,
-                    'b10-stats-httpd': self.stop_stats_httpd,
-                    'b10-cmdctl': self.stop_cmdctl }
-        procmap[process]()
-
-    # Some functions to pretend we stop processes, use by stop_process
-    def stop_msgq(self):
-        if self.msgq:
-            del self.components[2]
-        self.msgq = False
-
-    def stop_cfgmgr(self):
-        if self.cfgmgr:
-            del self.components[3]
-        self.cfgmgr = False
-
-    def stop_auth(self):
-        if self.auth:
-            del self.components[5]
-        self.auth = False
-
-    def stop_resolver(self):
-        if self.resolver:
-            del self.components[6]
-        self.resolver = False
-
-    def stop_xfrout(self):
-        if self.xfrout:
-            del self.components[7]
-        self.xfrout = False
-
-    def stop_xfrin(self):
-        if self.xfrin:
-            del self.components[8]
-        self.xfrin = False
-
-    def stop_zonemgr(self):
-        if self.zonemgr:
-            del self.components[9]
-        self.zonemgr = False
-
-    def stop_stats(self):
-        if self.stats:
-            del self.components[10]
-        self.stats = False
-
-    def stop_stats_httpd(self):
-        if self.stats_httpd:
-            del self.components[11]
-        self.stats_httpd = False
-
-    def stop_cmdctl(self):
-        if self.cmdctl:
-            del self.components[12]
-        self.cmdctl = False
-
-    def _get_process_exit_status(self):
-        if self.get_process_exit_status_called:
-            return (0, 0)
-        self.get_process_exit_status_called = True
-        return (53, 0)
-
-    def _get_process_exit_status_unknown_pid(self):
-        if self.get_process_exit_status_called:
-            return (0, 0)
-        self.get_process_exit_status_called = True
-        return (42, 0)
-
-    def _get_process_exit_status_raises_oserror_echild(self):
-        raise OSError(errno.ECHILD, 'Mock error')
-
-    def _get_process_exit_status_raises_oserror_other(self):
-        raise OSError(0, 'Mock error')
-
-    def _get_process_exit_status_raises_other(self):
-        raise Exception('Mock error')
-
-    def _make_mock_process_info(self, name, args, c_channel_env,
-                                dev_null_stdout=False, dev_null_stderr=False):
-        return MockProcessInfo(name, args, c_channel_env,
-                               dev_null_stdout, dev_null_stderr)
-
-class MockInitSimple(Init):
-    def __init__(self):
-        Init.__init__(self)
-        # Set which process has been started
-        self.started_process_name = None
-        self.started_process_args = None
-        self.started_process_env = None
-
-    def _make_mock_process_info(self, name, args, c_channel_env,
-                                dev_null_stdout=False, dev_null_stderr=False):
-        return MockProcessInfo(name, args, c_channel_env,
-                               dev_null_stdout, dev_null_stderr)
-
-    def start_process(self, name, args, c_channel_env, port=None,
-                      address=None):
-        self.started_process_name = name
-        self.started_process_args = args
-        self.started_process_env = c_channel_env
-        return None
-
-class TestStartStopProcessesInit(unittest.TestCase):
-    """
-    Check that the start_all_components method starts the right combination
-    of components and that the right components are started and stopped
-    according to changes in configuration.
-    """
-    def check_environment_unchanged(self):
-        # Check whether the environment has not been changed
-        self.assertEqual(original_os_environ, os.environ)
-
-    def check_started(self, init, 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(init.msgq, core)
-        self.assertEqual(init.cfgmgr, core)
-        self.assertEqual(init.ccsession, core)
-        self.assertEqual(init.creator, core)
-        self.assertEqual(init.auth, auth)
-        self.assertEqual(init.resolver, resolver)
-        self.assertEqual(init.xfrout, auth)
-        self.assertEqual(init.xfrin, auth)
-        self.assertEqual(init.zonemgr, auth)
-        self.assertEqual(init.stats, core)
-        self.assertEqual(init.stats_httpd, core)
-        self.assertEqual(init.cmdctl, core)
-        self.check_environment_unchanged()
-
-    def check_preconditions(self, init):
-        self.check_started(init, False, False, False)
-
-    def check_started_none(self, init):
-        """
-        Check that the situation is according to configuration where no servers
-        should be started. Some components still need to be running.
-        """
-        self.check_started(init, True, False, False)
-        self.check_environment_unchanged()
-
-    def check_started_both(self, init):
-        """
-        Check the situation is according to configuration where both servers
-        (auth and resolver) are enabled.
-        """
-        self.check_started(init, True, True, True)
-        self.check_environment_unchanged()
-
-    def check_started_auth(self, init):
-        """
-        Check the set of components needed to run auth only is started.
-        """
-        self.check_started(init, True, True, False)
-        self.check_environment_unchanged()
-
-    def check_started_resolver(self, init):
-        """
-        Check the set of components needed to run resolver only is started.
-        """
-        self.check_started(init, True, False, True)
-        self.check_environment_unchanged()
-
-    def check_started_dhcp(self, init, v4, v6):
-        """
-        Check if proper combinations of DHCPv4 and DHCpv6 can be started
-        """
-        self.assertEqual(v4, init.dhcp4)
-        self.assertEqual(v6, init.dhcp6)
-        self.check_environment_unchanged()
-
-    def construct_config(self, start_auth, start_resolver):
-        # The things that are common, not turned on an off
-        config = {}
-        config['b10-stats'] = { 'kind': 'dispensable', 'address': 'Stats' }
-        config['b10-stats-httpd'] = { 'kind': 'dispensable',
-                                      'address': 'StatsHttpd' }
-        config['b10-cmdctl'] = { 'kind': 'needed', 'special': 'cmdctl' }
-        if start_auth:
-            config['b10-auth'] = { 'kind': 'needed', 'special': 'auth' }
-            config['b10-xfrout'] = { 'kind': 'dispensable',
-                                     'address': 'Xfrout' }
-            config['b10-xfrin'] = { 'kind': 'dispensable',
-                                    'address': 'Xfrin' }
-            config['b10-zonemgr'] = { 'kind': 'dispensable',
-                                      'address': 'Zonemgr' }
-        if start_resolver:
-            config['b10-resolver'] = { 'kind': 'needed',
-                                       'special': 'resolver' }
-        return {'components': config}
-
-    def config_start_init(self, start_auth, start_resolver):
-        """
-        Test the configuration is loaded at the startup.
-        """
-        init = MockInit()
-        config = self.construct_config(start_auth, start_resolver)
-        class CC:
-            def get_full_config(self):
-                return config
-        # Provide the fake CC with data
-        init.ccs = CC()
-        # And make sure it's not overwritten
-        def start_ccsession():
-            init.ccsession = True
-        init.start_ccsession = lambda _: start_ccsession()
-        # We need to return the original _read_bind10_config
-        init._read_bind10_config = lambda: Init._read_bind10_config(init)
-        init.start_all_components()
-        self.check_started(init, True, start_auth, start_resolver)
-        self.check_environment_unchanged()
-
-    def test_start_none(self):
-        self.config_start_init(False, False)
-
-    def test_start_resolver(self):
-        self.config_start_init(False, True)
-
-    def test_start_auth(self):
-        self.config_start_init(True, False)
-
-    def test_start_both(self):
-        self.config_start_init(True, True)
-
-    def test_config_start(self):
-        """
-        Test that the configuration starts and stops components according
-        to configuration changes.
-        """
-
-        # Create Init and ensure correct initialization
-        init = MockInit()
-        self.check_preconditions(init)
-
-        init.start_all_components()
-        init.runnable = True
-        init.config_handler(self.construct_config(False, False))
-        self.check_started_none(init)
-
-        # Enable both at once
-        init.config_handler(self.construct_config(True, True))
-        self.check_started_both(init)
-
-        # Not touched by empty change
-        init.config_handler({})
-        self.check_started_both(init)
-
-        # Not touched by change to the same configuration
-        init.config_handler(self.construct_config(True, True))
-        self.check_started_both(init)
-
-        # Turn them both off again
-        init.config_handler(self.construct_config(False, False))
-        self.check_started_none(init)
-
-        # Not touched by empty change
-        init.config_handler({})
-        self.check_started_none(init)
-
-        # Not touched by change to the same configuration
-        init.config_handler(self.construct_config(False, False))
-        self.check_started_none(init)
-
-        # Start and stop auth separately
-        init.config_handler(self.construct_config(True, False))
-        self.check_started_auth(init)
-
-        init.config_handler(self.construct_config(False, False))
-        self.check_started_none(init)
-
-        # Start and stop resolver separately
-        init.config_handler(self.construct_config(False, True))
-        self.check_started_resolver(init)
-
-        init.config_handler(self.construct_config(False, False))
-        self.check_started_none(init)
-
-        # Alternate
-        init.config_handler(self.construct_config(True, False))
-        self.check_started_auth(init)
-
-        init.config_handler(self.construct_config(False, True))
-        self.check_started_resolver(init)
-
-        init.config_handler(self.construct_config(True, False))
-        self.check_started_auth(init)
-
-    def test_config_start_once(self):
-        """
-        Tests that a component is started only once.
-        """
-        # Create Init and ensure correct initialization
-        init = MockInit()
-        self.check_preconditions(init)
-
-        init.start_all_components()
-
-        init.runnable = True
-        init.config_handler(self.construct_config(True, True))
-        self.check_started_both(init)
-
-        init.start_auth = lambda: self.fail("Started auth again")
-        init.start_xfrout = lambda: self.fail("Started xfrout again")
-        init.start_xfrin = lambda: self.fail("Started xfrin again")
-        init.start_zonemgr = lambda: self.fail("Started zonemgr again")
-        init.start_resolver = lambda: self.fail("Started resolver again")
-
-        # Send again we want to start them. Should not do it, as they are.
-        init.config_handler(self.construct_config(True, True))
-
-    def test_config_not_started_early(self):
-        """
-        Test that components are not started by the config handler before
-        startup.
-        """
-        init = MockInit()
-        self.check_preconditions(init)
-
-        init.start_auth = lambda: self.fail("Started auth again")
-        init.start_xfrout = lambda: self.fail("Started xfrout again")
-        init.start_xfrin = lambda: self.fail("Started xfrin again")
-        init.start_zonemgr = lambda: self.fail("Started zonemgr again")
-        init.start_resolver = lambda: self.fail("Started resolver again")
-
-        init.config_handler({'start_auth': True, 'start_resolver': True})
-
-    # Checks that DHCP (v4 and v6) components are started when expected
-    def test_start_dhcp(self):
-
-        # Create Init and ensure correct initialization
-        init = MockInit()
-        self.check_preconditions(init)
-
-        init.start_all_components()
-        init.config_handler(self.construct_config(False, False))
-        self.check_started_dhcp(init, False, False)
-
-    def test_start_dhcp_v6only(self):
-        # Create Init and ensure correct initialization
-        init = MockInit()
-        self.check_preconditions(init)
-        # v6 only enabled
-        init.start_all_components()
-        init.runnable = True
-        init._Init_started = True
-        config = self.construct_config(False, False)
-        config['components']['b10-dhcp6'] = { 'kind': 'needed',
-                                              'address': 'Dhcp6' }
-        init.config_handler(config)
-        self.check_started_dhcp(init, False, True)
-
-        # uncomment when dhcpv4 becomes implemented
-        # v4 only enabled
-        #init.cfg_start_dhcp6 = False
-        #init.cfg_start_dhcp4 = True
-        #self.check_started_dhcp(init, True, False)
-
-        # both v4 and v6 enabled
-        #init.cfg_start_dhcp6 = True
-        #init.cfg_start_dhcp4 = True
-        #self.check_started_dhcp(init, True, True)
-
-class MockComponent:
-    def __init__(self, name, pid, address=None):
-        self.name = lambda: name
-        self.pid = lambda: pid
-        self.address = lambda: address
-        self.restarted = False
-        self.forceful = False
-        self.running = True
-        self.has_failed = False
-
-    def get_restart_time(self):
-        return 0                # arbitrary dummy value
-
-    def restart(self, now):
-        self.restarted = True
-        return True
-
-    def is_running(self):
-        return self.running
-
-    def failed(self, status):
-        return self.has_failed
-
-    def kill(self, forceful):
-        self.forceful = forceful
-
-class TestInitCmd(unittest.TestCase):
-    def test_ping(self):
-        """
-        Confirm simple ping command works.
-        """
-        init = MockInit()
-        answer = init.command_handler("ping", None)
-        self.assertEqual(answer, {'result': [0, 'pong']})
-
-    def test_show_processes_empty(self):
-        """
-        Confirm getting a list of processes works.
-        """
-        init = MockInit()
-        answer = init.command_handler("show_processes", None)
-        self.assertEqual(answer, {'result': [0, []]})
-
-    def test_show_processes(self):
-        """
-        Confirm getting a list of processes works.
-        """
-        init = MockInit()
-        init.register_process(1, MockComponent('first', 1))
-        init.register_process(2, MockComponent('second', 2, 'Second'))
-        answer = init.command_handler("show_processes", None)
-        processes = [[1, 'first', None],
-                     [2, 'second', 'Second']]
-        self.assertEqual(answer, {'result': [0, processes]})
-
-class TestParseArgs(unittest.TestCase):
-    """
-    This tests parsing of arguments of the bind10 master process.
-    """
-    #TODO: Write tests for the original parsing, bad options, etc.
-    def test_no_opts(self):
-        """
-        Test correct default values when no options are passed.
-        """
-        options = parse_args([], TestOptParser)
-        self.assertEqual(None, options.data_path)
-        self.assertEqual(None, options.config_file)
-        self.assertEqual(None, options.cmdctl_port)
-
-    def test_data_path(self):
-        """
-        Test it can parse the data path.
-        """
-        self.assertRaises(OptsError, parse_args, ['-p'], TestOptParser)
-        self.assertRaises(OptsError, parse_args, ['--data-path'],
-                          TestOptParser)
-        options = parse_args(['-p', '/data/path'], TestOptParser)
-        self.assertEqual('/data/path', options.data_path)
-        options = parse_args(['--data-path=/data/path'], TestOptParser)
-        self.assertEqual('/data/path', options.data_path)
-
-    def test_config_filename(self):
-        """
-        Test it can parse the config switch.
-        """
-        self.assertRaises(OptsError, parse_args, ['-c'], TestOptParser)
-        self.assertRaises(OptsError, parse_args, ['--config-file'],
-                          TestOptParser)
-        options = parse_args(['-c', 'config-file'], TestOptParser)
-        self.assertEqual('config-file', options.config_file)
-        options = parse_args(['--config-file=config-file'], TestOptParser)
-        self.assertEqual('config-file', options.config_file)
-
-    def test_clear_config(self):
-        options = parse_args([], TestOptParser)
-        self.assertEqual(False, options.clear_config)
-        options = parse_args(['--clear-config'], TestOptParser)
-        self.assertEqual(True, options.clear_config)
-
-    def test_nokill(self):
-        options = parse_args([], TestOptParser)
-        self.assertEqual(False, options.nokill)
-        options = parse_args(['--no-kill'], TestOptParser)
-        self.assertEqual(True, options.nokill)
-        options = parse_args([], TestOptParser)
-        self.assertEqual(False, options.nokill)
-        options = parse_args(['-i'], TestOptParser)
-        self.assertEqual(True, options.nokill)
-
-    def test_cmdctl_port(self):
-        """
-        Test it can parse the command control port.
-        """
-        self.assertRaises(OptsError, parse_args, ['--cmdctl-port=abc'],
-                                                TestOptParser)
-        self.assertRaises(OptsError, parse_args, ['--cmdctl-port=100000000'],
-                                                TestOptParser)
-        self.assertRaises(OptsError, parse_args, ['--cmdctl-port'],
-                          TestOptParser)
-        options = parse_args(['--cmdctl-port=1234'], TestOptParser)
-        self.assertEqual(1234, options.cmdctl_port)
-
-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()
-        with open(self.pid_file, "r") as f:
-            self.assertEqual(my_pid, int(f.read()))
-
-    def test_dump_pid(self):
-        self.check_pid_file()
-
-        # make sure any existing content will be removed
-        with open(self.pid_file, "w") as f:
-            f.write('dummy data\n')
-        self.check_pid_file()
-
-    def test_unlink_pid_file_notexist(self):
-        dummy_data = 'dummy_data\n'
-
-        with open(self.pid_file, "w") as f:
-            f.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.
-        with open(self.pid_file, "r") as f:
-            self.assertEqual(dummy_data, f.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'
-
-        with open(self.pid_file, "w") as f:
-            f.write(dummy_data)
-
-        unlink_pid_file(None)
-
-        with open(self.pid_file, "r") as f:
-            self.assertEqual(dummy_data, f.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')
-
-class TestInitComponents(unittest.TestCase):
-    """
-    Test b10-init propagates component configuration properly to the
-    component configurator and acts sane.
-    """
-    def setUp(self):
-        self.__param = None
-        self.__called = False
-        self.__compconfig = {
-            'comp': {
-                'kind': 'needed',
-                'process': 'cat'
-            }
-        }
-        self._tmp_time = None
-        self._tmp_sleep = None
-        self._tmp_module_cc_session = None
-        self._tmp_cc_session = None
-
-    def tearDown(self):
-        if self._tmp_time is not None:
-            time.time = self._tmp_time
-        if self._tmp_sleep is not None:
-            time.sleep = self._tmp_sleep
-        if self._tmp_module_cc_session is not None:
-            isc.config.ModuleCCSession = self._tmp_module_cc_session
-        if self._tmp_cc_session is not None:
-            isc.cc.Session = self._tmp_cc_session
-
-    def __unary_hook(self, param):
-        """
-        A hook function that stores the parameter for later examination.
-        """
-        self.__param = param
-
-    def __nullary_hook(self):
-        """
-        A hook function that notes down it was called.
-        """
-        self.__called = True
-
-    def __check_core(self, config):
-        """
-        A function checking that the config contains parts for the valid
-        core component configuration.
-        """
-        self.assertIsNotNone(config)
-        for component in ['sockcreator', 'msgq', 'cfgmgr']:
-            self.assertTrue(component in config)
-            self.assertEqual(component, config[component]['special'])
-            self.assertEqual('core', config[component]['kind'])
-
-    def __check_extended(self, config):
-        """
-        This checks that the config contains the core and one more component.
-        """
-        self.__check_core(config)
-        self.assertTrue('comp' in config)
-        self.assertEqual('cat', config['comp']['process'])
-        self.assertEqual('needed', config['comp']['kind'])
-        self.assertEqual(4, len(config))
-
-    def test_correct_run(self):
-        """
-        Test the situation when we run in usual scenario, nothing fails,
-        we just start, reconfigure and then stop peacefully.
-        """
-        init = MockInit()
-        # Start it
-        orig = init._component_configurator.startup
-        init._component_configurator.startup = self.__unary_hook
-        init.start_all_components()
-        init._component_configurator.startup = orig
-        self.__check_core(self.__param)
-        self.assertEqual(3, len(self.__param))
-
-        # Reconfigure it
-        self.__param = None
-        orig = init._component_configurator.reconfigure
-        init._component_configurator.reconfigure = self.__unary_hook
-        # Otherwise it does not work
-        init.runnable = True
-        init.config_handler({'components': self.__compconfig})
-        self.__check_extended(self.__param)
-        currconfig = self.__param
-        # If we reconfigure it, but it does not contain the components part,
-        # nothing is called
-        init.config_handler({})
-        self.assertEqual(self.__param, currconfig)
-        self.__param = None
-        init._component_configurator.reconfigure = orig
-        # Check a configuration that messes up the core components is rejected.
-        compconf = dict(self.__compconfig)
-        compconf['msgq'] = { 'process': 'echo' }
-        result = init.config_handler({'components': compconf})
-        # Check it rejected it
-        self.assertEqual(1, result['result'][0])
-
-        # We can't call shutdown, that one relies on the stuff in main
-        # We check somewhere else that the shutdown is actually called
-        # from there (the test_kills).
-
-    def __real_test_kill(self, nokill=False, ex_on_kill=None):
-        """
-        Helper function that does the actual kill functionality testing.
-        """
-        init = MockInit()
-        init.nokill = nokill
-
-        killed = []
-        class ImmortalComponent:
-            """
-            An immortal component. It does not stop when it is told so
-            (anyway it is not told so). It does not die if it is killed
-            the first time. It dies only when killed forcefully.
-            """
-            def __init__(self):
-                # number of kill() calls, preventing infinite loop.
-                self.__call_count = 0
-
-            def kill(self, forceful=False):
-                self.__call_count += 1
-                if self.__call_count > 2:
-                    raise Exception('Too many calls to ImmortalComponent.kill')
-
-                killed.append(forceful)
-                if ex_on_kill is not None:
-                    # If exception is given by the test, raise it here.
-                    # In the case of ESRCH, the process should have gone
-                    # somehow, so we clear the components.
-                    if ex_on_kill.errno == errno.ESRCH:
-                        init.components = {}
-                    raise ex_on_kill
-                if forceful:
-                    init.components = {}
-            def pid(self):
-                return 1
-            def name(self):
-                return "Immortal"
-        init.components = {}
-        init.register_process(1, ImmortalComponent())
-
-        # While at it, we check the configurator shutdown is actually called
-        orig = init._component_configurator.shutdown
-        init._component_configurator.shutdown = self.__nullary_hook
-        self.__called = False
-
-        init.ccs = MockModuleCCSession()
-        self.assertFalse(init.ccs.stopped)
-
-        init.shutdown()
-
-        self.assertTrue(init.ccs.stopped)
-
-        # Here, killed is an array where False is added if SIGTERM
-        # should be sent, or True if SIGKILL should be sent, in order in
-        # which they're sent.
-        if nokill:
-            self.assertEqual([], killed)
-        else:
-            if ex_on_kill is not None:
-                self.assertEqual([False], killed)
-            else:
-                self.assertEqual([False, True], killed)
-
-        self.assertTrue(self.__called)
-
-        init._component_configurator.shutdown = orig
-
-    def test_kills(self):
-        """
-        Test that b10-init kills components which don't want to stop.
-        """
-        self.__real_test_kill()
-
-    def test_kill_fail(self):
-        """Test cases where kill() results in an exception due to OS error.
-
-        The behavior should be different for EPERM, so we test two cases.
-
-        """
-
-        ex = OSError()
-        ex.errno, ex.strerror = errno.ESRCH, 'No such process'
-        self.__real_test_kill(ex_on_kill=ex)
-
-        ex.errno, ex.strerror = errno.EPERM, 'Operation not permitted'
-        self.__real_test_kill(ex_on_kill=ex)
-
-    def test_nokill(self):
-        """
-        Test that b10-init *doesn't* kill components which don't want to
-        stop, when asked not to (by passing the --no-kill option which
-        sets init.nokill to True).
-        """
-        self.__real_test_kill(True)
-
-    def test_component_shutdown(self):
-        """
-        Test the component_shutdown sets all variables accordingly.
-        """
-        init = MockInit()
-        self.assertRaises(Exception, init.component_shutdown, 1)
-        self.assertEqual(1, init.exitcode)
-        init._Init__started = True
-        init.component_shutdown(2)
-        self.assertEqual(2, init.exitcode)
-        self.assertFalse(init.runnable)
-
-    def test_init_config(self):
-        """
-        Test initial configuration is loaded.
-        """
-        init = MockInit()
-        # Start it
-        init._component_configurator.reconfigure = self.__unary_hook
-        # We need to return the original read_bind10_config
-        init._read_bind10_config = lambda: Init._read_bind10_config(init)
-        # And provide a session to read the data from
-        class CC:
-            pass
-        init.ccs = CC()
-        init.ccs.get_full_config = lambda: {'components': self.__compconfig}
-        init.start_all_components()
-        self.__check_extended(self.__param)
-
-    def __setup_restart(self, init, component):
-        '''Common procedure for restarting a component used below.'''
-        init.components_to_restart = { component }
-        component.restarted = False
-        init.restart_processes()
-
-    def test_restart_processes(self):
-        '''Check some behavior on restarting processes.'''
-        init = MockInit()
-        init.runnable = True
-        component = MockComponent('test', 53)
-
-        # A component to be restarted will actually be restarted iff it's
-        # in the configurator's configuration.
-        # We bruteforce the configurator internal below; ugly, but the easiest
-        # way for the test.
-        init._component_configurator._components['test'] = (None, component)
-        self.__setup_restart(init, component)
-        self.assertTrue(component.restarted)
-        self.assertNotIn(component, init.components_to_restart)
-
-        # Remove the component from the configuration.  It won't be restarted
-        # even if scheduled, nor will remain in the to-be-restarted list.
-        del init._component_configurator._components['test']
-        self.__setup_restart(init, component)
-        self.assertFalse(component.restarted)
-        self.assertNotIn(component, init.components_to_restart)
-
-    def test_get_processes(self):
-        '''Test that procsses are returned correctly, sorted by pid.'''
-        init = MockInit()
-
-        pids = list(range(0, 20))
-        random.shuffle(pids)
-
-        for i in range(0, 20):
-            pid = pids[i]
-            component = MockComponent('test' + str(pid), pid,
-                                      'Test' + str(pid))
-            init.components[pid] = component
-
-        process_list = init.get_processes()
-        self.assertEqual(20, len(process_list))
-
-        last_pid = -1
-        for process in process_list:
-            pid = process[0]
-            self.assertLessEqual(last_pid, pid)
-            last_pid = pid
-            self.assertEqual([pid, 'test' + str(pid), 'Test' + str(pid)],
-                             process)
-
-    def _test_reap_children_helper(self, runnable, is_running, failed):
-        '''Construct a Init instance, set various data in it according to
-        passed args and check if the component was added to the list of
-        components to restart.'''
-        init = MockInit()
-        init.runnable = runnable
-
-        component = MockComponent('test', 53)
-        component.running = is_running
-        component.has_failed = failed
-        init.components[53] = component
-
-        self.assertNotIn(component, init.components_to_restart)
-
-        init.reap_children()
-
-        if runnable and is_running and not failed:
-            self.assertIn(component, init.components_to_restart)
-        else:
-            self.assertEqual([], init.components_to_restart)
-
-    def test_reap_children(self):
-        '''Test that children are queued to be restarted when they ask for it.'''
-        # test various combinations of 3 booleans
-        # (Init.runnable, component.is_running(), component.failed())
-        self._test_reap_children_helper(False, False, False)
-        self._test_reap_children_helper(False, False, True)
-        self._test_reap_children_helper(False, True,  False)
-        self._test_reap_children_helper(False, True,  True)
-        self._test_reap_children_helper(True,  False, False)
-        self._test_reap_children_helper(True,  False, True)
-        self._test_reap_children_helper(True,  True,  False)
-        self._test_reap_children_helper(True,  True,  True)
-
-        # setup for more tests below
-        init = MockInit()
-        init.runnable = True
-        component = MockComponent('test', 53)
-        init.components[53] = component
-
-        # case where the returned pid is unknown to us. nothing should
-        # happpen then.
-        init.get_process_exit_status_called = False
-        init._get_process_exit_status = init._get_process_exit_status_unknown_pid
-        init.components_to_restart = []
-        # this should do nothing as the pid is unknown
-        init.reap_children()
-        self.assertEqual([], init.components_to_restart)
-
-        # case where init._get_process_exit_status() raises OSError with
-        # errno.ECHILD
-        init._get_process_exit_status = \
-            init._get_process_exit_status_raises_oserror_echild
-        init.components_to_restart = []
-        # this should catch and handle the OSError
-        init.reap_children()
-        self.assertEqual([], init.components_to_restart)
-
-        # case where init._get_process_exit_status() raises OSError with
-        # errno other than ECHILD
-        init._get_process_exit_status = \
-            init._get_process_exit_status_raises_oserror_other
-        with self.assertRaises(OSError):
-            init.reap_children()
-
-        # case where init._get_process_exit_status() raises something
-        # other than OSError
-        init._get_process_exit_status = \
-            init._get_process_exit_status_raises_other
-        with self.assertRaises(Exception):
-            init.reap_children()
-
-    def test_kill_started_components(self):
-        '''Test that started components are killed.'''
-        init = MockInit()
-
-        component = MockComponent('test', 53, 'Test')
-        init.components[53] = component
-
-        self.assertEqual([[53, 'test', 'Test']], init.get_processes())
-        init.kill_started_components()
-        self.assertEqual([], init.get_processes())
-        self.assertTrue(component.forceful)
-
-    def _start_msgq_helper(self, init, verbose):
-        init.verbose = verbose
-        pi = init.start_msgq()
-        self.assertEqual('b10-msgq', pi.name)
-        self.assertEqual(['b10-msgq'], pi.args)
-        self.assertTrue(pi.dev_null_stdout)
-        self.assertEqual(pi.dev_null_stderr, not verbose)
-        self.assertEqual({'FOO': 'an env string'}, pi.env)
-
-        # this is set by ProcessInfo.spawn()
-        self.assertEqual(42147, pi.pid)
-
-    def test_start_msgq(self):
-        '''Test that b10-msgq is started.'''
-        init = MockInitSimple()
-        init.c_channel_env = {'FOO': 'an env string'}
-        init._run_under_unittests = True
-
-        # use the MockProcessInfo creator
-        init._make_process_info = init._make_mock_process_info
-
-        # non-verbose case
-        self._start_msgq_helper(init, False)
-
-        # verbose case
-        self._start_msgq_helper(init, True)
-
-    def test_start_msgq_timeout(self):
-        '''Test that b10-msgq startup attempts connections several times
-        and times out eventually.'''
-        b10_init = MockInitSimple()
-        b10_init.c_channel_env = {}
-        # set the timeout to an arbitrary pre-determined value (which
-        # code below depends on)
-        b10_init.msgq_timeout = 1
-        b10_init._run_under_unittests = False
-
-        # use the MockProcessInfo creator
-        b10_init._make_process_info = b10_init._make_mock_process_info
-
-        global attempts
-        global tsec
-        attempts = 0
-        tsec = 0
-        self._tmp_time = time.time
-        self._tmp_sleep = time.sleep
-        def _my_time():
-            global attempts
-            global tsec
-            attempts += 1
-            return tsec
-        def _my_sleep(nsec):
-            global tsec
-            tsec += nsec
-        time.time = _my_time
-        time.sleep = _my_sleep
-
-        global cc_sub
-        cc_sub = None
-        class DummySessionAlwaysFails():
-            def __init__(self, socket_file):
-                raise isc.cc.session.SessionError('Connection fails')
-            def group_subscribe(self, s):
-                global cc_sub
-                cc_sub = s
-
-        isc.cc.Session = DummySessionAlwaysFails
-
-        with self.assertRaises(init.CChannelConnectError):
-            # An exception will be thrown here when it eventually times
-            # out.
-            pi = b10_init.start_msgq()
-
-        # time.time() should be called 12 times within the while loop:
-        # starting from 0, and 11 more times from 0.1 to 1.1. There's
-        # another call to time.time() outside the loop, which makes it
-        # 13.
-        self.assertEqual(attempts, 13)
-
-        # group_subscribe() should not have been called here.
-        self.assertIsNone(cc_sub)
-
-        global cc_socket_file
-        cc_socket_file = None
-        cc_sub = None
-        class DummySession():
-            def __init__(self, socket_file):
-                global cc_socket_file
-                cc_socket_file = socket_file
-            def group_subscribe(self, s):
-                global cc_sub
-                cc_sub = s
-
-        isc.cc.Session = DummySession
-
-        # reset values
-        attempts = 0
-        tsec = 0
-
-        pi = b10_init.start_msgq()
-
-        # just one attempt, but 2 calls to time.time()
-        self.assertEqual(attempts, 2)
-
-        self.assertEqual(cc_socket_file, b10_init.msgq_socket_file)
-        self.assertEqual(cc_sub, 'Init')
-
-        # isc.cc.Session, time.time() and time.sleep() are restored
-        # during tearDown().
-
-    def _start_cfgmgr_helper(self, init, data_path, filename, clear_config):
-        expect_args = ['b10-cfgmgr']
-        if data_path is not None:
-            init.data_path = data_path
-            expect_args.append('--data-path=' + data_path)
-        if filename is not None:
-            init.config_filename = filename
-            expect_args.append('--config-filename=' + filename)
-        if clear_config:
-            init.clear_config = clear_config
-            expect_args.append('--clear-config')
-
-        pi = init.start_cfgmgr()
-        self.assertEqual('b10-cfgmgr', pi.name)
-        self.assertEqual(expect_args, pi.args)
-        self.assertEqual({'TESTENV': 'A test string'}, pi.env)
-
-        # this is set by ProcessInfo.spawn()
-        self.assertEqual(42147, pi.pid)
-
-    def test_start_cfgmgr(self):
-        '''Test that b10-cfgmgr is started.'''
-        class DummySession():
-            def __init__(self):
-                self._tries = 0
-            def group_recvmsg(self):
-                self._tries += 1
-                # return running on the 3rd try onwards
-                if self._tries >= 3:
-                    return ({'running': 'ConfigManager'}, None)
-                else:
-                    return ({}, None)
-
-        init = MockInitSimple()
-        init.c_channel_env = {'TESTENV': 'A test string'}
-        init.cc_session = DummySession()
-        init.wait_time = 5
-
-        # use the MockProcessInfo creator
-        init._make_process_info = init._make_mock_process_info
-
-        global attempts
-        attempts = 0
-        self._tmp_sleep = time.sleep
-        def _my_sleep(nsec):
-            global attempts
-            attempts += 1
-        time.sleep = _my_sleep
-
-        # defaults
-        self._start_cfgmgr_helper(init, None, None, False)
-
-        # check that 2 attempts were made. on the 3rd attempt,
-        # process_running() returns that ConfigManager is running.
-        self.assertEqual(attempts, 2)
-
-        # data_path is specified
-        self._start_cfgmgr_helper(init, '/var/lib/test', None, False)
-
-        # config_filename is specified. Because `init` is not
-        # reconstructed, data_path is retained from the last call to
-        # _start_cfgmgr_helper().
-        self._start_cfgmgr_helper(init, '/var/lib/test', 'foo.cfg', False)
-
-        # clear_config is specified. Because `init` is not reconstructed,
-        # data_path and config_filename are retained from the last call
-        # to _start_cfgmgr_helper().
-        self._start_cfgmgr_helper(init, '/var/lib/test', 'foo.cfg', True)
-
-    def test_start_cfgmgr_timeout(self):
-        '''Test that b10-cfgmgr startup attempts connections several times
-        and times out eventually.'''
-        class DummySession():
-            def group_recvmsg(self):
-                return (None, None)
-        b10_init = MockInitSimple()
-        b10_init.c_channel_env = {}
-        b10_init.cc_session = DummySession()
-        # set wait_time to an arbitrary pre-determined value (which code
-        # below depends on)
-        b10_init.wait_time = 2
-
-        # use the MockProcessInfo creator
-        b10_init._make_process_info = b10_init._make_mock_process_info
-
-        global attempts
-        attempts = 0
-        self._tmp_sleep = time.sleep
-        def _my_sleep(nsec):
-            global attempts
-            attempts += 1
-        time.sleep = _my_sleep
-
-        # We just check that an exception was thrown, and that several
-        # attempts were made to connect.
-        with self.assertRaises(init.ProcessStartError):
-            pi = b10_init.start_cfgmgr()
-
-        # 2 seconds of attempts every 1 second should result in 2 attempts
-        self.assertEqual(attempts, 2)
-
-        # time.sleep() is restored during tearDown().
-
-    def test_start_ccsession(self):
-        '''Test that CC session is started.'''
-        class DummySession():
-            def __init__(self, specfile, config_handler, command_handler,
-                         socket_file):
-                self.specfile = specfile
-                self.config_handler = config_handler
-                self.command_handler = command_handler
-                self.socket_file = socket_file
-                self.started = False
-            def start(self):
-                self.started = True
-        b10_init = MockInitSimple()
-        self._tmp_module_cc_session = isc.config.ModuleCCSession
-        isc.config.ModuleCCSession = DummySession
-
-        b10_init.start_ccsession({})
-        self.assertEqual(init.SPECFILE_LOCATION, b10_init.ccs.specfile)
-        self.assertEqual(b10_init.config_handler, b10_init.ccs.config_handler)
-        self.assertEqual(b10_init.command_handler,
-                         b10_init.ccs.command_handler)
-        self.assertEqual(b10_init.msgq_socket_file, b10_init.ccs.socket_file)
-        self.assertTrue(b10_init.ccs.started)
-
-        # isc.config.ModuleCCSession is restored during tearDown().
-
-    def test_start_process(self):
-        '''Test that processes can be started.'''
-        init = MockInit()
-
-        # use the MockProcessInfo creator
-        init._make_process_info = init._make_mock_process_info
-
-        pi = init.start_process('Test Process', ['/bin/true'], {})
-        self.assertEqual('Test Process', pi.name)
-        self.assertEqual(['/bin/true'], pi.args)
-        self.assertEqual({}, pi.env)
-
-        # this is set by ProcessInfo.spawn()
-        self.assertEqual(42147, pi.pid)
-
-    def test_register_process(self):
-        '''Test that processes can be registered with Init.'''
-        init = MockInit()
-        component = MockComponent('test', 53, 'Test')
-
-        self.assertFalse(53 in init.components)
-        init.register_process(53, component)
-        self.assertTrue(53 in init.components)
-        self.assertEqual(init.components[53].name(), 'test')
-        self.assertEqual(init.components[53].pid(), 53)
-        self.assertEqual(init.components[53].address(), 'Test')
-
-    def _start_simple_helper(self, init, verbose):
-        init.verbose = verbose
-
-        args = ['/bin/true']
-        if verbose:
-            args.append('-v')
-
-        init.start_simple('/bin/true')
-        self.assertEqual('/bin/true', init.started_process_name)
-        self.assertEqual(args, init.started_process_args)
-        self.assertEqual({'TESTENV': 'A test string'}, init.started_process_env)
-
-    def test_start_simple(self):
-        '''Test simple process startup.'''
-        init = MockInitSimple()
-        init.c_channel_env = {'TESTENV': 'A test string'}
-
-        # non-verbose case
-        self._start_simple_helper(init, False)
-
-        # verbose case
-        self._start_simple_helper(init, True)
-
-    def _start_auth_helper(self, init, verbose):
-        init.verbose = verbose
-
-        args = ['b10-auth']
-        if verbose:
-            args.append('-v')
-
-        init.start_auth()
-        self.assertEqual('b10-auth', init.started_process_name)
-        self.assertEqual(args, init.started_process_args)
-        self.assertEqual({'FOO': 'an env string'}, init.started_process_env)
-
-    def test_start_auth(self):
-        '''Test that b10-auth is started.'''
-        init = MockInitSimple()
-        init.c_channel_env = {'FOO': 'an env string'}
-
-        # non-verbose case
-        self._start_auth_helper(init, False)
-
-        # verbose case
-        self._start_auth_helper(init, True)
-
-    def _start_resolver_helper(self, init, verbose):
-        init.verbose = verbose
-
-        args = ['b10-resolver']
-        if verbose:
-            args.append('-v')
-
-        init.start_resolver()
-        self.assertEqual('b10-resolver', init.started_process_name)
-        self.assertEqual(args, init.started_process_args)
-        self.assertEqual({'BAR': 'an env string'}, init.started_process_env)
-
-    def test_start_resolver(self):
-        '''Test that b10-resolver is started.'''
-        init = MockInitSimple()
-        init.c_channel_env = {'BAR': 'an env string'}
-
-        # non-verbose case
-        self._start_resolver_helper(init, False)
-
-        # verbose case
-        self._start_resolver_helper(init, True)
-
-    def _start_cmdctl_helper(self, init, verbose, port = None):
-        init.verbose = verbose
-
-        args = ['b10-cmdctl']
-
-        if port is not None:
-            init.cmdctl_port = port
-            args.append('--port=9353')
-
-        if verbose:
-            args.append('-v')
-
-        init.start_cmdctl()
-        self.assertEqual('b10-cmdctl', init.started_process_name)
-        self.assertEqual(args, init.started_process_args)
-        self.assertEqual({'BAZ': 'an env string'}, init.started_process_env)
-
-    def test_start_cmdctl(self):
-        '''Test that b10-cmdctl is started.'''
-        init = MockInitSimple()
-        init.c_channel_env = {'BAZ': 'an env string'}
-
-        # non-verbose case
-        self._start_cmdctl_helper(init, False)
-
-        # verbose case
-        self._start_cmdctl_helper(init, True)
-
-        # with port, non-verbose case
-        self._start_cmdctl_helper(init, False, 9353)
-
-        # with port, verbose case
-        self._start_cmdctl_helper(init, True, 9353)
-
-    def test_socket_data(self):
-        '''Test that Init._socket_data works as expected.'''
-        class MockSock:
-            def __init__(self, fd, throw):
-                self.fd = fd
-                self.throw = throw
-                self.buf = b'Hello World.\nYou are so nice today.\nXX'
-                self.i = 0
-
-            def recv(self, bufsize, flags = 0):
-                if bufsize != 1:
-                    raise Exception('bufsize != 1')
-                if flags != socket.MSG_DONTWAIT:
-                    raise Exception('flags != socket.MSG_DONTWAIT')
-                # after 15 recv()s, throw a socket.error with EAGAIN to
-                # get _socket_data() to save back what's been read. The
-                # number 15 is arbitrarily chosen, but the checks then
-                # depend on this being 15, i.e., if you adjust this
-                # number, you may have to adjust the checks below too.
-                if self.throw and self.i > 15:
-                    raise socket.error(errno.EAGAIN, 'Try again')
-                if self.i >= len(self.buf):
-                    return b'';
-                t = self.i
-                self.i += 1
-                return self.buf[t:t+1]
-
-            def close(self):
-                return
-
-        class MockInitSocketData(Init):
-            def __init__(self, throw):
-                self._unix_sockets = {42: (MockSock(42, throw), b'')}
-                self.requests = []
-                self.dead = []
-
-            def socket_request_handler(self, previous, sock):
-                self.requests.append({sock.fd: previous})
-
-            def socket_consumer_dead(self, sock):
-                self.dead.append(sock.fd)
-
-        # Case where we get data every time we call recv()
-        init = MockInitSocketData(False)
-        init._socket_data(42)
-        self.assertEqual(init.requests,
-                         [{42: b'Hello World.'},
-                          {42: b'You are so nice today.'}])
-        self.assertEqual(init.dead, [42])
-        self.assertEqual({}, init._unix_sockets)
-
-        # Case where socket.recv() raises EAGAIN. In this case, the
-        # routine is supposed to save what it has back to
-        # Init._unix_sockets.
-        init = MockInitSocketData(True)
-        init._socket_data(42)
-        self.assertEqual(init.requests, [{42: b'Hello World.'}])
-        self.assertFalse(init.dead)
-        self.assertEqual(len(init._unix_sockets), 1)
-        self.assertEqual(init._unix_sockets[42][1], b'You')
-
-    def test_startup(self):
-        '''Test that Init.startup() handles failures properly.'''
-        class MockInitStartup(Init):
-            def __init__(self, throw):
-                self.throw = throw
-                self.started = False
-                self.killed = False
-                self.msgq_socket_file = None
-                self.curproc = 'myproc'
-                self.runnable = False
-
-            def start_all_components(self):
-                self.started = True
-                if self.throw is True:
-                    raise Exception('Assume starting components has failed.')
-                elif self.throw:
-                    raise self.throw
-
-            def kill_started_components(self):
-                self.killed = True
-
-        class DummySession():
-            def __init__(self, socket_file):
-                raise isc.cc.session.SessionError('This is the expected case.')
-
-        class DummySessionSocketExists():
-            def __init__(self, socket_file):
-                # simulate that connect passes
-                return
-
-        isc.cc.Session = DummySession
-
-        # All is well case, where all components are started
-        # successfully. We check that the actual call to
-        # start_all_components() is made, and Init.runnable is true.
-        b10_init = MockInitStartup(False)
-        r = b10_init.startup()
-        self.assertIsNone(r)
-        self.assertTrue(b10_init.started)
-        self.assertFalse(b10_init.killed)
-        self.assertTrue(b10_init.runnable)
-        self.assertEqual({}, b10_init.c_channel_env)
-
-        # Case where starting components fails. We check that
-        # kill_started_components() is called right after, and
-        # Init.runnable is not modified.
-        b10_init = MockInitStartup(True)
-        r = b10_init.startup()
-        # r contains an error message
-        self.assertEqual(r, 'Unable to start myproc: Assume starting components has failed.')
-        self.assertTrue(b10_init.started)
-        self.assertTrue(b10_init.killed)
-        self.assertFalse(b10_init.runnable)
-        self.assertEqual({}, b10_init.c_channel_env)
-
-        # Check if msgq_socket_file is carried over
-        b10_init = MockInitStartup(False)
-        b10_init.msgq_socket_file = 'foo'
-        r = b10_init.startup()
-        self.assertEqual({'BIND10_MSGQ_SOCKET_FILE': 'foo'},
-                         b10_init.c_channel_env)
-
-        # Check failure of changing user results in a different message
-        b10_init = MockInitStartup(init.ChangeUserError('failed to chusr'))
-        r = b10_init.startup()
-        self.assertIn('failed to chusr', r)
-        self.assertTrue(b10_init.killed)
-
-        # Check the case when socket file already exists
-        isc.cc.Session = DummySessionSocketExists
-        b10_init = MockInitStartup(False)
-        r = b10_init.startup()
-        self.assertIn('already running', r)
-
-        # isc.cc.Session is restored during tearDown().
-
-class SocketSrvTest(unittest.TestCase):
-    """
-    This tests some methods of b10-init related to the unix domain sockets
-    used to transfer other sockets to applications.
-    """
-    def setUp(self):
-        """
-        Create the b10-init to test, testdata and backup some functions.
-        """
-        self.__b10_init = Init()
-        self.__select_backup = init.select.select
-        self.__select_called = None
-        self.__socket_data_called = None
-        self.__consumer_dead_called = None
-        self.__socket_request_handler_called = None
-
-    def tearDown(self):
-        """
-        Restore functions.
-        """
-        init.select.select = self.__select_backup
-
-    class __FalseSocket:
-        """
-        A mock socket for the select and accept and stuff like that.
-        """
-        def __init__(self, owner, fileno=42):
-            self.__owner = owner
-            self.__fileno = fileno
-            self.data = None
-            self.closed = False
-
-        def fileno(self):
-            return self.__fileno
-
-        def accept(self):
-            return (self.__class__(self.__owner, 13), "/path/to/socket")
-
-        def recv(self, bufsize, flags=0):
-            self.__owner.assertEqual(1, bufsize)
-            self.__owner.assertEqual(socket.MSG_DONTWAIT, flags)
-            if isinstance(self.data, socket.error):
-                raise self.data
-            elif self.data is not None:
-                if len(self.data):
-                    result = self.data[0:1]
-                    self.data = self.data[1:]
-                    return result
-                else:
-                    raise socket.error(errno.EAGAIN, "Would block")
-            else:
-                return b''
-
-        def close(self):
-            self.closed = True
-
-    class __CCS:
-        """
-        A mock CCS, just to provide the socket file number.
-        """
-        class __Socket:
-            def fileno(self):
-                return 1
-        def get_socket(self):
-            return self.__Socket()
-
-    def __select_accept(self, r, w, x, t):
-        self.__select_called = (r, w, x, t)
-        return ([42], [], [])
-
-    def __select_data(self, r, w, x, t):
-        self.__select_called = (r, w, x, t)
-        return ([13], [], [])
-
-    def __accept(self):
-        """
-        Hijack the accept method of the b10-init.
-
-        Notes down it was called and stops b10-init.
-        """
-        self.__accept_called = True
-        self.__b10_init.runnable = False
-
-    def test_srv_accept_called(self):
-        """
-        Test that the _srv_accept method of b10-init is called when the
-        listening socket is readable.
-        """
-        self.__b10_init.runnable = True
-        self.__b10_init._srv_socket = self.__FalseSocket(self)
-        self.__b10_init._srv_accept = self.__accept
-        self.__b10_init.ccs = self.__CCS()
-        init.select.select = self.__select_accept
-        self.__b10_init.run(2)
-        # It called the accept
-        self.assertTrue(self.__accept_called)
-        # And the select had the right parameters
-        self.assertEqual(([2, 1, 42], [], [], None), self.__select_called)
-
-    def test_srv_accept(self):
-        """
-        Test how the _srv_accept method works.
-        """
-        self.__b10_init._srv_socket = self.__FalseSocket(self)
-        self.__b10_init._srv_accept()
-        # After we accepted, a new socket is added there
-        socket = self.__b10_init._unix_sockets[13][0]
-        # The socket is properly stored there
-        self.assertTrue(isinstance(socket, self.__FalseSocket))
-        # And the buffer (yet empty) is there
-        self.assertEqual({13: (socket, b'')}, self.__b10_init._unix_sockets)
-
-    def __socket_data(self, socket):
-        self.__b10_init.runnable = False
-        self.__socket_data_called = socket
-
-    def test_socket_data(self):
-        """
-        Test that a socket that wants attention gets it.
-        """
-        self.__b10_init._srv_socket = self.__FalseSocket(self)
-        self.__b10_init._socket_data = self.__socket_data
-        self.__b10_init.ccs = self.__CCS()
-        self.__b10_init._unix_sockets = {13: (self.__FalseSocket(self, 13), b'')}
-        self.__b10_init.runnable = True
-        init.select.select = self.__select_data
-        self.__b10_init.run(2)
-        self.assertEqual(13, self.__socket_data_called)
-        self.assertEqual(([2, 1, 42, 13], [], [], None), self.__select_called)
-
-    def __prepare_data(self, data):
-        socket = self.__FalseSocket(self, 13)
-        self.__b10_init._unix_sockets = {13: (socket, b'')}
-        socket.data = data
-        self.__b10_init.socket_consumer_dead = self.__consumer_dead
-        self.__b10_init.socket_request_handler = self.__socket_request_handler
-        return socket
-
-    def __consumer_dead(self, socket):
-        self.__consumer_dead_called = socket
-
-    def __socket_request_handler(self, token, socket):
-        self.__socket_request_handler_called = (token, socket)
-
-    def test_socket_closed(self):
-        """
-        Test that a socket is removed and the socket_consumer_dead is called
-        when it is closed.
-        """
-        socket = self.__prepare_data(None)
-        self.__b10_init._socket_data(13)
-        self.assertEqual(socket, self.__consumer_dead_called)
-        self.assertEqual({}, self.__b10_init._unix_sockets)
-        self.assertTrue(socket.closed)
-
-    def test_socket_short(self):
-        """
-        Test that if there's not enough data to get the whole socket, it is
-        kept there, but nothing is called.
-        """
-        socket = self.__prepare_data(b'tok')
-        self.__b10_init._socket_data(13)
-        self.assertEqual({13: (socket, b'tok')}, self.__b10_init._unix_sockets)
-        self.assertFalse(socket.closed)
-        self.assertIsNone(self.__consumer_dead_called)
-        self.assertIsNone(self.__socket_request_handler_called)
-
-    def test_socket_continue(self):
-        """
-        Test that we call the token handling function when the whole token
-        comes. This test pretends to continue reading where the previous one
-        stopped.
-        """
-        socket = self.__prepare_data(b"en\nanothe")
-        # The data to finish
-        self.__b10_init._unix_sockets[13] = (socket, b'tok')
-        self.__b10_init._socket_data(13)
-        self.assertEqual({13: (socket, b'anothe')}, self.__b10_init._unix_sockets)
-        self.assertFalse(socket.closed)
-        self.assertIsNone(self.__consumer_dead_called)
-        self.assertEqual((b'token', socket),
-                         self.__socket_request_handler_called)
-
-    def test_broken_socket(self):
-        """
-        If the socket raises an exception during the read other than EAGAIN,
-        it is broken and we remove it.
-        """
-        sock = self.__prepare_data(socket.error(errno.ENOMEM,
-            "There's more memory available, but not for you"))
-        self.__b10_init._socket_data(13)
-        self.assertEqual(sock, self.__consumer_dead_called)
-        self.assertEqual({}, self.__b10_init._unix_sockets)
-        self.assertTrue(sock.closed)
-
-class TestFunctions(unittest.TestCase):
-    def setUp(self):
-        self.lockfile_testpath = \
-            "@abs_top_builddir@/src/bin/bind10/tests/lockfile_test"
-        self.assertFalse(os.path.exists(self.lockfile_testpath))
-        os.mkdir(self.lockfile_testpath)
-        self.assertTrue(os.path.isdir(self.lockfile_testpath))
-        self.__isfile_orig = init.os.path.isfile
-        self.__unlink_orig = init.os.unlink
-
-    def tearDown(self):
-        os.rmdir(self.lockfile_testpath)
-        self.assertFalse(os.path.isdir(self.lockfile_testpath))
-        os.environ["B10_LOCKFILE_DIR_FROM_BUILD"] = "@abs_top_builddir@"
-        init.os.path.isfile = self.__isfile_orig
-        init.os.unlink = self.__unlink_orig
-
-    def test_remove_lock_files(self):
-        os.environ["B10_LOCKFILE_DIR_FROM_BUILD"] = self.lockfile_testpath
-
-        # create lockfiles for the testcase
-        lockfiles = ["logger_lockfile"]
-        for f in lockfiles:
-            fname = os.environ["B10_LOCKFILE_DIR_FROM_BUILD"] + '/' + f
-            self.assertFalse(os.path.exists(fname))
-            open(fname, "w").close()
-            self.assertTrue(os.path.isfile(fname))
-
-        # first call should clear up all the lockfiles
-        init.remove_lock_files()
-
-        # check if the lockfiles exist
-        for f in lockfiles:
-            fname = os.environ["B10_LOCKFILE_DIR_FROM_BUILD"] + '/' + f
-            self.assertFalse(os.path.isfile(fname))
-
-        # second call should not assert anyway
-        init.remove_lock_files()
-
-    def test_remove_lock_files_fail(self):
-        # Permission error on unlink is ignored; other exceptions are really
-        # unexpected and propagated.
-        def __raising_unlink(unused, ex):
-            raise ex
-
-        init.os.path.isfile = lambda _: True
-        os_error = OSError()
-        init.os.unlink = lambda f: __raising_unlink(f, os_error)
-
-        os_error.errno = errno.EPERM
-        init.remove_lock_files() # no disruption
-
-        os_error.errno = errno.EACCES
-        init.remove_lock_files() # no disruption
-
-        os_error.errno = errno.ENOENT
-        self.assertRaises(OSError, init.remove_lock_files)
-
-        init.os.unlink = lambda f: __raising_unlink(f, Exception('bad'))
-        self.assertRaises(Exception, init.remove_lock_files)
-
-    def test_get_signame(self):
-        # just test with some samples
-        signame = init.get_signame(signal.SIGTERM)
-        self.assertEqual('SIGTERM', signame)
-        signame = init.get_signame(signal.SIGKILL)
-        self.assertEqual('SIGKILL', signame)
-        # 59426 is hopefully an unused signal on most platforms
-        signame = init.get_signame(59426)
-        self.assertEqual('Unknown signal 59426', signame)
-
-    def test_fatal_signal(self):
-        self.assertIsNone(init.b10_init)
-        init.b10_init = Init()
-        init.b10_init.runnable = True
-        init.fatal_signal(signal.SIGTERM, None)
-        # Now, runnable must be False
-        self.assertFalse(init.b10_init.runnable)
-        init.b10_init = None
-
-if __name__ == '__main__':
-    # store os.environ for test_unchanged_environment
-    original_os_environ = copy.deepcopy(os.environ)
-    isc.log.resetUnitTestRootLogger()
-    unittest.main()
diff --git a/src/bin/bindctl/bindcmd.py b/src/bin/bindctl/bindcmd.py
index f382e2a..af599a4 100644
--- a/src/bin/bindctl/bindcmd.py
+++ b/src/bin/bindctl/bindcmd.py
@@ -25,7 +25,7 @@ from bindctl.moduleinfo import *
 from bindctl.cmdparse import BindCmdParser
 from bindctl import command_sets
 from xml.dom import minidom
-import isc.config
+import isc
 import isc.cc.data
 import http.client
 import json
diff --git a/src/bin/bindctl/run_bindctl.sh.in b/src/bin/bindctl/run_bindctl.sh.in
index 8a5d00b..999d7ee 100755
--- a/src/bin/bindctl/run_bindctl.sh.in
+++ b/src/bin/bindctl/run_bindctl.sh.in
@@ -23,7 +23,7 @@ BINDCTL_PATH=@abs_top_builddir@/src/bin/bindctl
 # Note: lib/dns/python/.libs is necessary because __init__.py of isc package
 # automatically imports isc.datasrc, which then requires the DNS loadable
 # module.  #2145 should eliminate the need for it.
-PYTHONPATH=@abs_top_srcdir@/src/bin:@abs_top_builddir@/src/lib/python/isc/log_messages:@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/bin:@abs_top_srcdir@/src/lib/python
+PYTHONPATH=@abs_top_srcdir@/src/bin:@abs_top_builddir@/src/lib/python/isc/log_messages:@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/bin:@abs_top_srcdir@/src/lib/python:@abs_top_builddir@/src/lib/dns/python/.libs
 export PYTHONPATH
 
 # If necessary (rare cases), explicitly specify paths to dynamic libraries
diff --git a/src/bin/stats/stats.py.in b/src/bin/stats/stats.py.in
index 0af0933..17d2f74 100755
--- a/src/bin/stats/stats.py.in
+++ b/src/bin/stats/stats.py.in
@@ -26,8 +26,7 @@ from optparse import OptionParser, OptionValueError
 import errno
 import select
 
-import isc.cc
-import isc.config
+import isc
 import isc.util.process
 import isc.log
 from isc.log_messages.stats_messages import *
diff --git a/src/bin/sysinfo/run_sysinfo.sh.in b/src/bin/sysinfo/run_sysinfo.sh.in
index b5593b9..6459c2d 100755
--- a/src/bin/sysinfo/run_sysinfo.sh.in
+++ b/src/bin/sysinfo/run_sysinfo.sh.in
@@ -20,8 +20,20 @@ export PYTHON_EXEC
 
 SYSINFO_PATH=@abs_top_builddir@/src/bin/sysinfo
 
-PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_srcdir@/src/lib/python
+# Note: we shouldn't need log_messages and lib/dns except for the seemingly
+# necessary dependency due to the automatic import in the isc package (its
+# __init__.py imports some other modules)
+# #2145 should eliminate the need for them.
+PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_srcdir@/src/lib/python:@abs_top_builddir@/src/lib/python/isc/log_messages:@abs_top_builddir@/src/lib/dns/python/.libs
 export PYTHONPATH
 
+# Likewise, we need only because isc.log requires some loadable modules.
+# sysinfo itself shouldn't need any of them.
+SET_ENV_LIBRARY_PATH=@SET_ENV_LIBRARY_PATH@
+if test $SET_ENV_LIBRARY_PATH = yes; then
+	@ENV_LIBRARY_PATH@=@abs_top_builddir@/src/lib/dns/.libs:@abs_top_builddir@/src/lib/dns/python/.libs:@abs_top_builddir@/src/lib/cryptolink/.libs:@abs_top_builddir@/src/lib/cc/.libs:@abs_top_builddir@/src/lib/config/.libs:@abs_top_builddir@/src/lib/log/.libs:@abs_top_builddir@/src/lib/acl/.libs:@abs_top_builddir@/src/lib/util/.libs:@abs_top_builddir@/src/lib/util/io/.libs:@abs_top_builddir@/src/lib/exceptions/.libs:@abs_top_builddir@/src/lib/datasrc/.libs:$@ENV_LIBRARY_PATH@
+	export @ENV_LIBRARY_PATH@
+fi
+
 cd ${SYSINFO_PATH}
 exec ${PYTHON_EXEC} -O sysinfo.py "$@"
diff --git a/src/lib/python/isc/__init__.py b/src/lib/python/isc/__init__.py
index 37138a2..029f110 100644
--- a/src/lib/python/isc/__init__.py
+++ b/src/lib/python/isc/__init__.py
@@ -1,3 +1,7 @@
-"""
-This is the top directory for common BIND 10 Python modules and packages.
-"""
+# On some systems, it appears the dynamic linker gets
+# confused if the order is not right here
+# There is probably a solution for this, but for now:
+# order is important here!
+import isc.cc
+import isc.config
+import isc.datasrc
diff --git a/src/lib/python/isc/datasrc/tests/zone_loader_test.py b/src/lib/python/isc/datasrc/tests/zone_loader_test.py
index 4cd4879..759afd7 100644
--- a/src/lib/python/isc/datasrc/tests/zone_loader_test.py
+++ b/src/lib/python/isc/datasrc/tests/zone_loader_test.py
@@ -13,7 +13,6 @@
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-import isc.log
 import isc.datasrc
 import isc.dns
 



More information about the bind10-changes mailing list