Example #1
0
    def test_httpd(self):
        # dual stack (addresses is ipv4 and ipv6)
        if self.ipv6_enabled:
            server_addresses = (get_availaddr('::1'), get_availaddr())
            self.stats_httpd = MyStatsHttpd(*server_addresses)
            for ht in self.stats_httpd.httpd:
                self.assertTrue(isinstance(ht, stats_httpd.HttpServer))
                self.assertTrue(ht.address_family in set([socket.AF_INET,
                                                          socket.AF_INET6]))
                self.assertTrue(isinstance(ht.socket, socket.socket))
                ht.socket.close() # to silence warning about resource leak
            self.stats_httpd.close_mccs() # ditto

        # dual stack (address is ipv6)
        if self.ipv6_enabled:
            server_addresses = get_availaddr('::1')
            self.stats_httpd = MyStatsHttpd(server_addresses)
            for ht in self.stats_httpd.httpd:
                self.assertTrue(isinstance(ht, stats_httpd.HttpServer))
                self.assertEqual(ht.address_family, socket.AF_INET6)
                self.assertTrue(isinstance(ht.socket, socket.socket))
                ht.socket.close()
            self.stats_httpd.close_mccs() # ditto

        # dual/single stack (address is ipv4)
        server_addresses = get_availaddr()
        self.stats_httpd = MyStatsHttpd(server_addresses)
        for ht in self.stats_httpd.httpd:
            self.assertTrue(isinstance(ht, stats_httpd.HttpServer))
            self.assertEqual(ht.address_family, socket.AF_INET)
            self.assertTrue(isinstance(ht.socket, socket.socket))
            ht.socket.close()
        self.stats_httpd.close_mccs()
Example #2
0
 def test_open_template(self):
     self.stats_httpd = MyStatsHttpd(get_availaddr())
     # successful conditions
     tmpl = self.stats_httpd.open_template(
         stats_httpd.XML_TEMPLATE_LOCATION)
     self.assertTrue(isinstance(tmpl, string.Template))
     opts = dict(
         xml_string="<dummy></dummy>",
         xsl_url_path="/path/to/")
     lines = tmpl.substitute(opts)
     for n in opts:
         self.assertGreater(lines.find(opts[n]), 0)
     tmpl = self.stats_httpd.open_template(
         stats_httpd.XSD_TEMPLATE_LOCATION)
     self.assertTrue(isinstance(tmpl, string.Template))
     opts = dict(xsd_namespace="http://host/path/to/")
     lines = tmpl.substitute(opts)
     for n in opts:
         self.assertGreater(lines.find(opts[n]), 0)
     tmpl = self.stats_httpd.open_template(
         stats_httpd.XSL_TEMPLATE_LOCATION)
     self.assertTrue(isinstance(tmpl, string.Template))
     opts = dict(xsd_namespace="http://host/path/to/")
     lines = tmpl.substitute(opts)
     for n in opts:
         self.assertGreater(lines.find(opts[n]), 0)
     # unsuccessful condition
     self.assertRaises(
         stats_httpd.StatsHttpdDataError,
         self.stats_httpd.open_template, '/path/to/foo/bar')
Example #3
0
 def test_xsd_handler(self):
     self.stats_httpd = MyStatsHttpd(get_availaddr())
     xsd_string = self.stats_httpd.xsd_handler()
     stats_xsd = xml.etree.ElementTree.fromstring(xsd_string)
     ns = '{%s}' % XMLNS_XSD
     stats_xsd = stats_xsd[1].find('%scomplexType/%ssequence/%selement' % ((ns,)*3))
     self.assertEqual('item', stats_xsd.attrib['name'])
     stats_xsd = stats_xsd.find('%scomplexType' % ns)
     type_types = ('boolean', 'integer', 'real', 'string', 'map', \
                       'list', 'named_set', 'any')
     attribs = [('identifier', 'string', 'required'),
                ('value', 'string', 'optional'),
                ('owner', 'string', 'required'),
                ('uri', 'anyURI', 'required'),
                ('name', 'string', 'required'),
                ('type', type_types, 'required'),
                ('description', 'string', 'optional'),
                ('title', 'string', 'optional'),
                ('optional', 'boolean', 'optional'),
                ('default', 'string', 'optional'),
                ('format', 'string', 'optional')]
     for i in range(0, len(attribs)):
         self.assertEqual(attribs[i][0], stats_xsd[i].attrib['name'])
         if attribs[i][0] == 'type':
             stats_xsd_types = \
                 stats_xsd[i].find('%ssimpleType/%srestriction' % \
                                       ((ns,)*2))
             for j in range(0, len(attribs[i][1])):
                 self.assertEqual(attribs[i][1][j], \
                                      stats_xsd_types[j].attrib['value'])
         else:
             self.assertEqual(attribs[i][1], stats_xsd[i].attrib['type'])
         self.assertEqual(attribs[i][2], stats_xsd[i].attrib['use'])
Example #4
0
 def test_failure_with_a_select_error (self):
     """checks select.error is raised if the exception except
     errno.EINTR is raised while it's selecting"""
     def raise_select_except(*args):
         raise select.error('dummy error')
     select.select = raise_select_except
     self.stats_httpd = MyStatsHttpd(get_availaddr())
     self.assertRaises(select.error, self.stats_httpd.start)
Example #5
0
 def test_httpd_anyIPv4(self):
     # any address (IPv4)
     server_addresses = get_availaddr(address='0.0.0.0')
     self.stats_httpd = MyStatsHttpd(server_addresses)
     for ht in self.stats_httpd.httpd:
         self.assertTrue(isinstance(ht, stats_httpd.HttpServer))
         self.assertEqual(ht.address_family,socket.AF_INET)
         self.assertTrue(isinstance(ht.socket, socket.socket))
Example #6
0
 def test_nofailure_with_errno_EINTR(self):
     """checks no exception is raised if errno.EINTR is raised
     while it's selecting"""
     self.__call_count = 0
     select.select = lambda r, w, x, t: self.__faked_select(
         select.error(errno.EINTR))
     self.stats_httpd = MyStatsHttpd(get_availaddr())
     self.stats_httpd.start() # shouldn't leak the exception
     self.assertFalse(self.stats_httpd.running)
     self.assertIsNone(self.stats_httpd.mccs)
Example #7
0
 def test_commands(self):
     self.stats_httpd = MyStatsHttpd(get_availaddr())
     self.assertEqual(self.stats_httpd.command_handler("status", None),
                      isc.config.ccsession.create_answer(
             0, "Stats Httpd is up. (PID " + str(os.getpid()) + ")"))
     self.stats_httpd.running = True
     self.assertEqual(self.stats_httpd.command_handler("shutdown", None),
                      isc.config.ccsession.create_answer(0))
     self.assertFalse(self.stats_httpd.running)
     self.assertEqual(
         self.stats_httpd.command_handler("__UNKNOWN_COMMAND__", None),
         isc.config.ccsession.create_answer(
             1, "Unknown command: __UNKNOWN_COMMAND__"))
Example #8
0
 def test_openclose_mccs(self):
     self.stats_httpd = MyStatsHttpd(get_availaddr())
     mccs = self.stats_httpd.mccs
     self.assertFalse(self.stats_httpd.mccs.stopped)
     self.assertFalse(self.stats_httpd.mccs.closed)
     self.stats_httpd.close_mccs()
     self.assertTrue(mccs.stopped)
     self.assertTrue(mccs.closed)
     self.assertIsNone(self.stats_httpd.mccs)
     self.stats_httpd.open_mccs()
     self.assertIsNotNone(self.stats_httpd.mccs)
     self.stats_httpd.mccs = None
     self.assertIsNone(self.stats_httpd.mccs)
     self.assertIsNone(self.stats_httpd.close_mccs())
Example #9
0
 def test_mccs(self):
     self.stats_httpd = MyStatsHttpd(get_availaddr())
     self.assertIsNotNone(self.stats_httpd.mccs.get_socket())
     self.assertTrue(
         isinstance(self.stats_httpd.mccs.get_socket(), socket.socket))
     self.assertIsNotNone(self.stats_httpd.cc_session)
     statistics_spec = self.stats_httpd.get_stats_spec()
     for mod in DUMMY_DATA:
         self.assertTrue(mod in statistics_spec)
         for cfg in statistics_spec[mod]:
             self.assertTrue('item_name' in cfg)
             self.assertTrue(cfg['item_name'] in DUMMY_DATA[mod])
         self.assertTrue(len(statistics_spec[mod]), len(DUMMY_DATA[mod]))
     self.stats_httpd.close_mccs()
     self.assertIsNone(self.stats_httpd.mccs)
Example #10
0
    def test_config(self):
        self.stats_httpd = MyStatsHttpd(get_availaddr())
        self.assertEqual(
            self.stats_httpd.config_handler(dict(_UNKNOWN_KEY_=None)),
            isc.config.ccsession.create_answer(
                1, "unknown item _UNKNOWN_KEY_"))

        addresses = get_availaddr()
        self.assertEqual(
            self.stats_httpd.config_handler(
                dict(listen_on=[dict(address=addresses[0],port=addresses[1])])),
            isc.config.ccsession.create_answer(0))
        self.assertTrue("listen_on" in self.stats_httpd.config)
        for addr in self.stats_httpd.config["listen_on"]:
            self.assertTrue("address" in addr)
            self.assertTrue("port" in addr)
            self.assertTrue(addr["address"] == addresses[0])
            self.assertTrue(addr["port"] == addresses[1])

        if self.ipv6_enabled:
            addresses = get_availaddr("::1")
            self.assertEqual(
                self.stats_httpd.config_handler(
                dict(listen_on=[dict(address=addresses[0],port=addresses[1])])),
                isc.config.ccsession.create_answer(0))
            self.assertTrue("listen_on" in self.stats_httpd.config)
            for addr in self.stats_httpd.config["listen_on"]:
                self.assertTrue("address" in addr)
                self.assertTrue("port" in addr)
                self.assertTrue(addr["address"] == addresses[0])
                self.assertTrue(addr["port"] == addresses[1])

        addresses = get_availaddr()
        self.assertEqual(
            self.stats_httpd.config_handler(
                dict(listen_on=[dict(address=addresses[0],port=addresses[1])])),
            isc.config.ccsession.create_answer(0))
        self.assertTrue("listen_on" in self.stats_httpd.config)
        for addr in self.stats_httpd.config["listen_on"]:
            self.assertTrue("address" in addr)
            self.assertTrue("port" in addr)
            self.assertTrue(addr["address"] == addresses[0])
            self.assertTrue(addr["port"] == addresses[1])
        (ret, arg) = isc.config.ccsession.parse_answer(
            self.stats_httpd.config_handler(
                dict(listen_on=[dict(address="1.2.3.4",port=543210)]))
            )
        self.assertEqual(ret, 1)
Example #11
0
 def test_init(self):
     server_address = get_availaddr()
     self.stats_httpd = MyStatsHttpd(server_address)
     self.assertEqual(self.stats_httpd.running, False)
     self.assertEqual(self.stats_httpd.poll_intval, 0.5)
     self.assertNotEqual(len(self.stats_httpd.httpd), 0)
     self.assertIsNotNone(self.stats_httpd.mccs)
     self.assertIsNotNone(self.stats_httpd.cc_session)
     # The real CfgMgr would return 'version', but our test mock omits it,
     # so the len(config) should be 1
     self.assertEqual(len(self.stats_httpd.config), 1)
     self.assertTrue('listen_on' in self.stats_httpd.config)
     self.assertEqual(len(self.stats_httpd.config['listen_on']), 1)
     self.assertTrue('address' in self.stats_httpd.config['listen_on'][0])
     self.assertTrue('port' in self.stats_httpd.config['listen_on'][0])
     self.assertTrue(server_address in set(self.stats_httpd.http_addrs))
     self.assertEqual('StatsHttpd', self.stats_httpd.mccs.\
                          get_module_spec().get_module_name())
Example #12
0
 def test_xsl_handler(self):
     self.stats_httpd = MyStatsHttpd(get_availaddr())
     xsl_string = self.stats_httpd.xsl_handler()
     stats_xsl = xml.etree.ElementTree.fromstring(xsl_string)
     nst = '{%s}' % XMLNS_XSL
     nsx = '{%s}' % XMLNS_XHTML
     self.assertEqual("bind10:statistics", stats_xsl[2].attrib['match'])
     stats_xsl = stats_xsl[2].find('%stable' % nsx)
     self.assertEqual('item', stats_xsl[1].attrib['select'])
     stats_xsl = stats_xsl[1].find('%str' % nsx)
     self.assertEqual('@uri', stats_xsl[0].find(
             '%selement/%sattribute/%svalue-of' % ((nst,)*3)).attrib['select'])
     self.assertEqual('@identifier', stats_xsl[0].find(
             '%selement/%svalue-of' % ((nst,)*2)).attrib['select'])
     self.assertEqual('@value', stats_xsl[1].find('%sif' % nst).attrib['test'])
     self.assertEqual('@value', stats_xsl[1].find('%sif/%svalue-of' % ((nst,)*2)).attrib['select'])
     self.assertEqual('@description', stats_xsl[2].find('%sif' % nst).attrib['test'])
     self.assertEqual('@description', stats_xsl[2].find('%sif/%svalue-of' % ((nst,)*2)).attrib['select'])
Example #13
0
    def test_running(self):
        # Previous version of this test checks the result of "status" and
        # "shutdown" commands; however, they are more explicitly tested
        # in specific tests.  In this test we only have to check:
        # - start() will set 'running' to True
        # - as long as 'running' is True, it keeps calling select.select
        # - when running becomes False, it exists from the loop and calls
        #   stop()
        self.stats_httpd = MyStatsHttpd(get_availaddr())
        self.assertFalse(self.stats_httpd.running)

        # In this test we'll call select.select() 2 times: on the first call
        # stats_httpd.running should be True; on the second call the faked
        # select() will set it to False.
        self.__call_count = 0
        select.select = lambda r, w, x, t: self.__faked_select()
        self.stats_httpd.start()
        self.assertFalse(self.stats_httpd.running)
        self.assertIsNone(self.stats_httpd.mccs) # stop() clears .mccs
Example #14
0
 def test_xml_handler(self):
     self.stats_httpd = MyStatsHttpd(get_availaddr())
     module_name = 'Dummy'
     stats_spec = \
         { module_name :
               [{
                     "item_name": "foo",
                     "item_type": "string",
                     "item_optional": False,
                     "item_default": "bar",
                     "item_description": "foo is bar",
                     "item_title": "Foo"
                     },
                {
                     "item_name": "foo2",
                     "item_type": "list",
                     "item_optional": False,
                     "item_default": [
                         {
                             "zonename" : "test1",
                             "queries.udp" : 1,
                             "queries.tcp" : 2
                             },
                         {
                             "zonename" : "test2",
                             "queries.udp" : 3,
                             "queries.tcp" : 4
                             }
                     ],
                     "item_title": "Foo bar",
                     "item_description": "Foo bar",
                     "list_item_spec": {
                         "item_name": "foo2-1",
                         "item_type": "map",
                         "item_optional": False,
                         "item_default": {},
                         "map_item_spec": [
                             {
                                 "item_name": "foo2-1-1",
                                 "item_type": "string",
                                 "item_optional": False,
                                 "item_default": "",
                                 "item_title": "Foo2 1 1",
                                 "item_description": "Foo bar"
                                 },
                             {
                                 "item_name": "foo2-1-2",
                                 "item_type": "integer",
                                 "item_optional": False,
                                 "item_default": 0,
                                 "item_title": "Foo2 1 2",
                                 "item_description": "Foo bar"
                                 },
                             {
                                 "item_name": "foo2-1-3",
                                 "item_type": "integer",
                                 "item_optional": False,
                                 "item_default": 0,
                                 "item_title": "Foo2 1 3",
                                 "item_description": "Foo bar"
                                 }
                             ]
                         }
                     }]
           }
     stats_data = \
         { module_name : { 'foo':'bar',
                       'foo2': [
                         {
                             "foo2-1-1" : "bar1",
                             "foo2-1-2" : 10,
                             "foo2-1-3" : 9
                             },
                         {
                             "foo2-1-1" : "bar2",
                             "foo2-1-2" : 8,
                             "foo2-1-3" : 7
                             }
                         ] } }
     self.stats_httpd.get_stats_spec = lambda x,y: stats_spec
     self.stats_httpd.get_stats_data = lambda x,y: stats_data
     xml_string = self.stats_httpd.xml_handler()
     stats_xml = xml.etree.ElementTree.fromstring(xml_string)
     schema_loc = '{%s}schemaLocation' % XMLNS_XSI
     self.assertEqual(stats_xml.attrib[schema_loc],
                      stats_httpd.XML_ROOT_ATTRIB['xsi:schemaLocation'])
     stats_data = stats_data[module_name]
     stats_spec = stats_spec[module_name]
     names = stats_httpd.item_name_list(stats_data, '')
     for i in range(0, len(names)):
         self.assertEqual('%s/%s' % (module_name, names[i]), stats_xml[i].attrib['identifier'])
         value = isc.cc.data.find(stats_data, names[i])
         if type(value) is int:
             value = str(value)
         if type(value) is dict or type(value) is list:
             self.assertFalse('value' in stats_xml[i].attrib)
         else:
             self.assertEqual(value, stats_xml[i].attrib['value'])
         self.assertEqual(module_name, stats_xml[i].attrib['owner'])
         self.assertEqual(urllib.parse.quote('%s/%s/%s' % (stats_httpd.XML_URL_PATH,
                                                           module_name, names[i])),
                          stats_xml[i].attrib['uri'])
         spec = isc.config.find_spec_part(stats_spec, names[i])
         self.assertEqual(spec['item_name'], stats_xml[i].attrib['name'])
         self.assertEqual(spec['item_type'], stats_xml[i].attrib['type'])
         self.assertEqual(spec['item_description'], stats_xml[i].attrib['description'])
         self.assertEqual(spec['item_title'], stats_xml[i].attrib['title'])
         self.assertEqual(str(spec['item_optional']).lower(), stats_xml[i].attrib['optional'])
         default = spec['item_default']
         if type(default) is int:
             default = str(default)
         if type(default) is dict or type(default) is list:
             self.assertFalse('default' in stats_xml[i].attrib)
         else:
             self.assertEqual(default, stats_xml[i].attrib['default'])
         self.assertFalse('item_format' in spec)
         self.assertFalse('format' in stats_xml[i].attrib)
Example #15
0
 def test_running_fail(self):
     # A failure case of start(): we close the (real but dummy) socket for
     # the CC session.  This breaks the select-loop due to exception
     self.stats_httpd = MyStatsHttpd(get_availaddr())
     self.stats_httpd.mccs.get_socket().close()
     self.assertRaises(ValueError, self.stats_httpd.start)
Example #16
0
class TestStatsHttpd(unittest.TestCase):
    """Tests for StatsHttpd class"""

    def setUp(self):
        # set the signal handler for deadlock
        self.sig_handler = SignalHandler(self.fail)
        # checking IPv6 enabled on this platform
        self.ipv6_enabled = is_ipv6_enabled()
        # instantiation of StatsHttpd indirectly calls gethostbyaddr(), which
        # can block for an uncontrollable period, leading many undesirable
        # results.  We should rather eliminate the reliance, but until we
        # can make such fundamental cleanup we replace it with a faked method;
        # in our test scenario the return value doesn't matter.
        self.__gethostbyaddr_orig = socket.gethostbyaddr
        socket.gethostbyaddr = lambda x: ('test.example.', [], None)

        # Some tests replace this library function.  Keep the original for
        # restor
        self.__orig_select_select = select.select

    def tearDown(self):
        socket.gethostbyaddr = self.__gethostbyaddr_orig
        if hasattr(self, "stats_httpd"):
            self.stats_httpd.stop()
        # reset the signal handler
        self.sig_handler.reset()

        # restore original of replaced library
        select.select = self.__orig_select_select

    def test_init(self):
        server_address = get_availaddr()
        self.stats_httpd = MyStatsHttpd(server_address)
        self.assertEqual(self.stats_httpd.running, False)
        self.assertEqual(self.stats_httpd.poll_intval, 0.5)
        self.assertNotEqual(len(self.stats_httpd.httpd), 0)
        self.assertIsNotNone(self.stats_httpd.mccs)
        self.assertIsNotNone(self.stats_httpd.cc_session)
        # The real CfgMgr would return 'version', but our test mock omits it,
        # so the len(config) should be 1
        self.assertEqual(len(self.stats_httpd.config), 1)
        self.assertTrue('listen_on' in self.stats_httpd.config)
        self.assertEqual(len(self.stats_httpd.config['listen_on']), 1)
        self.assertTrue('address' in self.stats_httpd.config['listen_on'][0])
        self.assertTrue('port' in self.stats_httpd.config['listen_on'][0])
        self.assertTrue(server_address in set(self.stats_httpd.http_addrs))
        self.assertEqual('StatsHttpd', self.stats_httpd.mccs.\
                             get_module_spec().get_module_name())

    def test_init_hterr(self):
        """Test the behavior of StatsHttpd constructor when open_httpd fails.

        We specifically check the following two:
        - close_mccs() is called (so stats-httpd tells ConfigMgr it's shutting
          down)
        - the constructor results in HttpServerError exception.

        """
        self.__mccs_closed = False
        def call_checker():
            self.__mccs_closed = True
        class FailingStatsHttpd(MyStatsHttpd):
            def open_httpd(self):
                raise stats_httpd.HttpServerError
            def close_mccs(self):
                call_checker()
        self.assertRaises(stats_httpd.HttpServerError, FailingStatsHttpd)
        self.assertTrue(self.__mccs_closed)

    def test_openclose_mccs(self):
        self.stats_httpd = MyStatsHttpd(get_availaddr())
        mccs = self.stats_httpd.mccs
        self.assertFalse(self.stats_httpd.mccs.stopped)
        self.assertFalse(self.stats_httpd.mccs.closed)
        self.stats_httpd.close_mccs()
        self.assertTrue(mccs.stopped)
        self.assertTrue(mccs.closed)
        self.assertIsNone(self.stats_httpd.mccs)
        self.stats_httpd.open_mccs()
        self.assertIsNotNone(self.stats_httpd.mccs)
        self.stats_httpd.mccs = None
        self.assertIsNone(self.stats_httpd.mccs)
        self.assertIsNone(self.stats_httpd.close_mccs())

    def test_mccs(self):
        self.stats_httpd = MyStatsHttpd(get_availaddr())
        self.assertIsNotNone(self.stats_httpd.mccs.get_socket())
        self.assertTrue(
            isinstance(self.stats_httpd.mccs.get_socket(), socket.socket))
        self.assertIsNotNone(self.stats_httpd.cc_session)
        statistics_spec = self.stats_httpd.get_stats_spec()
        for mod in DUMMY_DATA:
            self.assertTrue(mod in statistics_spec)
            for cfg in statistics_spec[mod]:
                self.assertTrue('item_name' in cfg)
                self.assertTrue(cfg['item_name'] in DUMMY_DATA[mod])
            self.assertTrue(len(statistics_spec[mod]), len(DUMMY_DATA[mod]))
        self.stats_httpd.close_mccs()
        self.assertIsNone(self.stats_httpd.mccs)

    def test_httpd(self):
        # dual stack (addresses is ipv4 and ipv6)
        if self.ipv6_enabled:
            server_addresses = (get_availaddr('::1'), get_availaddr())
            self.stats_httpd = MyStatsHttpd(*server_addresses)
            for ht in self.stats_httpd.httpd:
                self.assertTrue(isinstance(ht, stats_httpd.HttpServer))
                self.assertTrue(ht.address_family in set([socket.AF_INET,
                                                          socket.AF_INET6]))
                self.assertTrue(isinstance(ht.socket, socket.socket))
                ht.socket.close() # to silence warning about resource leak
            self.stats_httpd.close_mccs() # ditto

        # dual stack (address is ipv6)
        if self.ipv6_enabled:
            server_addresses = get_availaddr('::1')
            self.stats_httpd = MyStatsHttpd(server_addresses)
            for ht in self.stats_httpd.httpd:
                self.assertTrue(isinstance(ht, stats_httpd.HttpServer))
                self.assertEqual(ht.address_family, socket.AF_INET6)
                self.assertTrue(isinstance(ht.socket, socket.socket))
                ht.socket.close()
            self.stats_httpd.close_mccs() # ditto

        # dual/single stack (address is ipv4)
        server_addresses = get_availaddr()
        self.stats_httpd = MyStatsHttpd(server_addresses)
        for ht in self.stats_httpd.httpd:
            self.assertTrue(isinstance(ht, stats_httpd.HttpServer))
            self.assertEqual(ht.address_family, socket.AF_INET)
            self.assertTrue(isinstance(ht.socket, socket.socket))
            ht.socket.close()
        self.stats_httpd.close_mccs()

    def test_httpd_anyIPv4(self):
        # any address (IPv4)
        server_addresses = get_availaddr(address='0.0.0.0')
        self.stats_httpd = MyStatsHttpd(server_addresses)
        for ht in self.stats_httpd.httpd:
            self.assertTrue(isinstance(ht, stats_httpd.HttpServer))
            self.assertEqual(ht.address_family,socket.AF_INET)
            self.assertTrue(isinstance(ht.socket, socket.socket))

    def test_httpd_anyIPv6(self):
        # any address (IPv6)
        if self.ipv6_enabled:
            server_addresses = get_availaddr(address='::')
            self.stats_httpd = MyStatsHttpd(server_addresses)
            for ht in self.stats_httpd.httpd:
                self.assertTrue(isinstance(ht, stats_httpd.HttpServer))
                self.assertEqual(ht.address_family,socket.AF_INET6)
                self.assertTrue(isinstance(ht.socket, socket.socket))

    def test_httpd_failed(self):
        # existent hostname
        self.assertRaises(stats_httpd.HttpServerError, MyStatsHttpd,
                          get_availaddr(address='localhost'))

        # nonexistent hostname
        self.assertRaises(stats_httpd.HttpServerError, MyStatsHttpd,
                          ('my.host.domain', 8000))

        # over flow of port number
        self.assertRaises(stats_httpd.HttpServerError, MyStatsHttpd,
                          ('127.0.0.1', 80000))

        # negative
        self.assertRaises(stats_httpd.HttpServerError, MyStatsHttpd,
                          ('127.0.0.1', -8000))

        # alphabet
        self.assertRaises(stats_httpd.HttpServerError, MyStatsHttpd,
                          ('127.0.0.1', 'ABCDE'))

        # Address already in use
        server_addresses = get_availaddr()
        server = MyStatsHttpd(server_addresses)
        self.assertRaises(stats_httpd.HttpServerError, MyStatsHttpd,
                          server_addresses)

    def __faked_select(self, ex=None):
        """A helper subroutine for tests using faked select.select.

        See test_running() for basic features.  If ex is not None,
        it's assumed to be an exception object and will be raised on the
        first call.

        """
        self.assertTrue(self.stats_httpd.running)
        self.__call_count += 1
        if ex is not None and self.__call_count == 1:
            raise ex
        if self.__call_count == 2:
            self.stats_httpd.running  = False
        assert self.__call_count <= 2 # safety net to avoid infinite loop
        return ([], [], [])

    def test_running(self):
        # Previous version of this test checks the result of "status" and
        # "shutdown" commands; however, they are more explicitly tested
        # in specific tests.  In this test we only have to check:
        # - start() will set 'running' to True
        # - as long as 'running' is True, it keeps calling select.select
        # - when running becomes False, it exists from the loop and calls
        #   stop()
        self.stats_httpd = MyStatsHttpd(get_availaddr())
        self.assertFalse(self.stats_httpd.running)

        # In this test we'll call select.select() 2 times: on the first call
        # stats_httpd.running should be True; on the second call the faked
        # select() will set it to False.
        self.__call_count = 0
        select.select = lambda r, w, x, t: self.__faked_select()
        self.stats_httpd.start()
        self.assertFalse(self.stats_httpd.running)
        self.assertIsNone(self.stats_httpd.mccs) # stop() clears .mccs

    def test_running_fail(self):
        # A failure case of start(): we close the (real but dummy) socket for
        # the CC session.  This breaks the select-loop due to exception
        self.stats_httpd = MyStatsHttpd(get_availaddr())
        self.stats_httpd.mccs.get_socket().close()
        self.assertRaises(ValueError, self.stats_httpd.start)

    def test_failure_with_a_select_error (self):
        """checks select.error is raised if the exception except
        errno.EINTR is raised while it's selecting"""
        def raise_select_except(*args):
            raise select.error('dummy error')
        select.select = raise_select_except
        self.stats_httpd = MyStatsHttpd(get_availaddr())
        self.assertRaises(select.error, self.stats_httpd.start)

    def test_nofailure_with_errno_EINTR(self):
        """checks no exception is raised if errno.EINTR is raised
        while it's selecting"""
        self.__call_count = 0
        select.select = lambda r, w, x, t: self.__faked_select(
            select.error(errno.EINTR))
        self.stats_httpd = MyStatsHttpd(get_availaddr())
        self.stats_httpd.start() # shouldn't leak the exception
        self.assertFalse(self.stats_httpd.running)
        self.assertIsNone(self.stats_httpd.mccs)

    def test_open_template(self):
        self.stats_httpd = MyStatsHttpd(get_availaddr())
        # successful conditions
        tmpl = self.stats_httpd.open_template(
            stats_httpd.XML_TEMPLATE_LOCATION)
        self.assertTrue(isinstance(tmpl, string.Template))
        opts = dict(
            xml_string="<dummy></dummy>",
            xsl_url_path="/path/to/")
        lines = tmpl.substitute(opts)
        for n in opts:
            self.assertGreater(lines.find(opts[n]), 0)
        tmpl = self.stats_httpd.open_template(
            stats_httpd.XSD_TEMPLATE_LOCATION)
        self.assertTrue(isinstance(tmpl, string.Template))
        opts = dict(xsd_namespace="http://host/path/to/")
        lines = tmpl.substitute(opts)
        for n in opts:
            self.assertGreater(lines.find(opts[n]), 0)
        tmpl = self.stats_httpd.open_template(
            stats_httpd.XSL_TEMPLATE_LOCATION)
        self.assertTrue(isinstance(tmpl, string.Template))
        opts = dict(xsd_namespace="http://host/path/to/")
        lines = tmpl.substitute(opts)
        for n in opts:
            self.assertGreater(lines.find(opts[n]), 0)
        # unsuccessful condition
        self.assertRaises(
            stats_httpd.StatsHttpdDataError,
            self.stats_httpd.open_template, '/path/to/foo/bar')

    def test_commands(self):
        self.stats_httpd = MyStatsHttpd(get_availaddr())
        self.assertEqual(self.stats_httpd.command_handler("status", None),
                         isc.config.ccsession.create_answer(
                0, "Stats Httpd is up. (PID " + str(os.getpid()) + ")"))
        self.stats_httpd.running = True
        self.assertEqual(self.stats_httpd.command_handler("shutdown", None),
                         isc.config.ccsession.create_answer(0))
        self.assertFalse(self.stats_httpd.running)
        self.assertEqual(
            self.stats_httpd.command_handler("__UNKNOWN_COMMAND__", None),
            isc.config.ccsession.create_answer(
                1, "Unknown command: __UNKNOWN_COMMAND__"))

    def test_config(self):
        self.stats_httpd = MyStatsHttpd(get_availaddr())
        self.assertEqual(
            self.stats_httpd.config_handler(dict(_UNKNOWN_KEY_=None)),
            isc.config.ccsession.create_answer(
                1, "unknown item _UNKNOWN_KEY_"))

        addresses = get_availaddr()
        self.assertEqual(
            self.stats_httpd.config_handler(
                dict(listen_on=[dict(address=addresses[0],port=addresses[1])])),
            isc.config.ccsession.create_answer(0))
        self.assertTrue("listen_on" in self.stats_httpd.config)
        for addr in self.stats_httpd.config["listen_on"]:
            self.assertTrue("address" in addr)
            self.assertTrue("port" in addr)
            self.assertTrue(addr["address"] == addresses[0])
            self.assertTrue(addr["port"] == addresses[1])

        if self.ipv6_enabled:
            addresses = get_availaddr("::1")
            self.assertEqual(
                self.stats_httpd.config_handler(
                dict(listen_on=[dict(address=addresses[0],port=addresses[1])])),
                isc.config.ccsession.create_answer(0))
            self.assertTrue("listen_on" in self.stats_httpd.config)
            for addr in self.stats_httpd.config["listen_on"]:
                self.assertTrue("address" in addr)
                self.assertTrue("port" in addr)
                self.assertTrue(addr["address"] == addresses[0])
                self.assertTrue(addr["port"] == addresses[1])

        addresses = get_availaddr()
        self.assertEqual(
            self.stats_httpd.config_handler(
                dict(listen_on=[dict(address=addresses[0],port=addresses[1])])),
            isc.config.ccsession.create_answer(0))
        self.assertTrue("listen_on" in self.stats_httpd.config)
        for addr in self.stats_httpd.config["listen_on"]:
            self.assertTrue("address" in addr)
            self.assertTrue("port" in addr)
            self.assertTrue(addr["address"] == addresses[0])
            self.assertTrue(addr["port"] == addresses[1])
        (ret, arg) = isc.config.ccsession.parse_answer(
            self.stats_httpd.config_handler(
                dict(listen_on=[dict(address="1.2.3.4",port=543210)]))
            )
        self.assertEqual(ret, 1)

    @unittest.skipUnless(xml_parser, "skipping the test using XMLParser")
    def test_xml_handler(self):
        self.stats_httpd = MyStatsHttpd(get_availaddr())
        module_name = 'Dummy'
        stats_spec = \
            { module_name :
                  [{
                        "item_name": "foo",
                        "item_type": "string",
                        "item_optional": False,
                        "item_default": "bar",
                        "item_description": "foo is bar",
                        "item_title": "Foo"
                        },
                   {
                        "item_name": "foo2",
                        "item_type": "list",
                        "item_optional": False,
                        "item_default": [
                            {
                                "zonename" : "test1",
                                "queries.udp" : 1,
                                "queries.tcp" : 2
                                },
                            {
                                "zonename" : "test2",
                                "queries.udp" : 3,
                                "queries.tcp" : 4
                                }
                        ],
                        "item_title": "Foo bar",
                        "item_description": "Foo bar",
                        "list_item_spec": {
                            "item_name": "foo2-1",
                            "item_type": "map",
                            "item_optional": False,
                            "item_default": {},
                            "map_item_spec": [
                                {
                                    "item_name": "foo2-1-1",
                                    "item_type": "string",
                                    "item_optional": False,
                                    "item_default": "",
                                    "item_title": "Foo2 1 1",
                                    "item_description": "Foo bar"
                                    },
                                {
                                    "item_name": "foo2-1-2",
                                    "item_type": "integer",
                                    "item_optional": False,
                                    "item_default": 0,
                                    "item_title": "Foo2 1 2",
                                    "item_description": "Foo bar"
                                    },
                                {
                                    "item_name": "foo2-1-3",
                                    "item_type": "integer",
                                    "item_optional": False,
                                    "item_default": 0,
                                    "item_title": "Foo2 1 3",
                                    "item_description": "Foo bar"
                                    }
                                ]
                            }
                        }]
              }
        stats_data = \
            { module_name : { 'foo':'bar',
                          'foo2': [
                            {
                                "foo2-1-1" : "bar1",
                                "foo2-1-2" : 10,
                                "foo2-1-3" : 9
                                },
                            {
                                "foo2-1-1" : "bar2",
                                "foo2-1-2" : 8,
                                "foo2-1-3" : 7
                                }
                            ] } }
        self.stats_httpd.get_stats_spec = lambda x,y: stats_spec
        self.stats_httpd.get_stats_data = lambda x,y: stats_data
        xml_string = self.stats_httpd.xml_handler()
        stats_xml = xml.etree.ElementTree.fromstring(xml_string)
        schema_loc = '{%s}schemaLocation' % XMLNS_XSI
        self.assertEqual(stats_xml.attrib[schema_loc],
                         stats_httpd.XML_ROOT_ATTRIB['xsi:schemaLocation'])
        stats_data = stats_data[module_name]
        stats_spec = stats_spec[module_name]
        names = stats_httpd.item_name_list(stats_data, '')
        for i in range(0, len(names)):
            self.assertEqual('%s/%s' % (module_name, names[i]), stats_xml[i].attrib['identifier'])
            value = isc.cc.data.find(stats_data, names[i])
            if type(value) is int:
                value = str(value)
            if type(value) is dict or type(value) is list:
                self.assertFalse('value' in stats_xml[i].attrib)
            else:
                self.assertEqual(value, stats_xml[i].attrib['value'])
            self.assertEqual(module_name, stats_xml[i].attrib['owner'])
            self.assertEqual(urllib.parse.quote('%s/%s/%s' % (stats_httpd.XML_URL_PATH,
                                                              module_name, names[i])),
                             stats_xml[i].attrib['uri'])
            spec = isc.config.find_spec_part(stats_spec, names[i])
            self.assertEqual(spec['item_name'], stats_xml[i].attrib['name'])
            self.assertEqual(spec['item_type'], stats_xml[i].attrib['type'])
            self.assertEqual(spec['item_description'], stats_xml[i].attrib['description'])
            self.assertEqual(spec['item_title'], stats_xml[i].attrib['title'])
            self.assertEqual(str(spec['item_optional']).lower(), stats_xml[i].attrib['optional'])
            default = spec['item_default']
            if type(default) is int:
                default = str(default)
            if type(default) is dict or type(default) is list:
                self.assertFalse('default' in stats_xml[i].attrib)
            else:
                self.assertEqual(default, stats_xml[i].attrib['default'])
            self.assertFalse('item_format' in spec)
            self.assertFalse('format' in stats_xml[i].attrib)

    @unittest.skipUnless(xml_parser, "skipping the test using XMLParser")
    def test_xsd_handler(self):
        self.stats_httpd = MyStatsHttpd(get_availaddr())
        xsd_string = self.stats_httpd.xsd_handler()
        stats_xsd = xml.etree.ElementTree.fromstring(xsd_string)
        ns = '{%s}' % XMLNS_XSD
        stats_xsd = stats_xsd[1].find('%scomplexType/%ssequence/%selement' % ((ns,)*3))
        self.assertEqual('item', stats_xsd.attrib['name'])
        stats_xsd = stats_xsd.find('%scomplexType' % ns)
        type_types = ('boolean', 'integer', 'real', 'string', 'map', \
                          'list', 'named_set', 'any')
        attribs = [('identifier', 'string', 'required'),
                   ('value', 'string', 'optional'),
                   ('owner', 'string', 'required'),
                   ('uri', 'anyURI', 'required'),
                   ('name', 'string', 'required'),
                   ('type', type_types, 'required'),
                   ('description', 'string', 'optional'),
                   ('title', 'string', 'optional'),
                   ('optional', 'boolean', 'optional'),
                   ('default', 'string', 'optional'),
                   ('format', 'string', 'optional')]
        for i in range(0, len(attribs)):
            self.assertEqual(attribs[i][0], stats_xsd[i].attrib['name'])
            if attribs[i][0] == 'type':
                stats_xsd_types = \
                    stats_xsd[i].find('%ssimpleType/%srestriction' % \
                                          ((ns,)*2))
                for j in range(0, len(attribs[i][1])):
                    self.assertEqual(attribs[i][1][j], \
                                         stats_xsd_types[j].attrib['value'])
            else:
                self.assertEqual(attribs[i][1], stats_xsd[i].attrib['type'])
            self.assertEqual(attribs[i][2], stats_xsd[i].attrib['use'])

    @unittest.skipUnless(xml_parser, "skipping the test using XMLParser")
    def test_xsl_handler(self):
        self.stats_httpd = MyStatsHttpd(get_availaddr())
        xsl_string = self.stats_httpd.xsl_handler()
        stats_xsl = xml.etree.ElementTree.fromstring(xsl_string)
        nst = '{%s}' % XMLNS_XSL
        nsx = '{%s}' % XMLNS_XHTML
        self.assertEqual("bind10:statistics", stats_xsl[2].attrib['match'])
        stats_xsl = stats_xsl[2].find('%stable' % nsx)
        self.assertEqual('item', stats_xsl[1].attrib['select'])
        stats_xsl = stats_xsl[1].find('%str' % nsx)
        self.assertEqual('@uri', stats_xsl[0].find(
                '%selement/%sattribute/%svalue-of' % ((nst,)*3)).attrib['select'])
        self.assertEqual('@identifier', stats_xsl[0].find(
                '%selement/%svalue-of' % ((nst,)*2)).attrib['select'])
        self.assertEqual('@value', stats_xsl[1].find('%sif' % nst).attrib['test'])
        self.assertEqual('@value', stats_xsl[1].find('%sif/%svalue-of' % ((nst,)*2)).attrib['select'])
        self.assertEqual('@description', stats_xsl[2].find('%sif' % nst).attrib['test'])
        self.assertEqual('@description', stats_xsl[2].find('%sif/%svalue-of' % ((nst,)*2)).attrib['select'])