BIND 10 trac547, updated. ae170ab6674e889369bf4d97c01294222f2a4edd [trac547] add more tests - stats module returns error - "shutdown" command is invoked
BIND 10 source code commits
bind10-changes at lists.isc.org
Mon Mar 7 12:45:38 UTC 2011
The branch, trac547 has been updated
via ae170ab6674e889369bf4d97c01294222f2a4edd (commit)
via 4d04514e9ea4b5261c2d8e4f04776d391a00688e (commit)
via 04a63faa1b803ed862af655e38c9989a48e286b7 (commit)
via ce2bc7f565535cfedf1958157d539e0fd02c3354 (commit)
via de46ddd9ba5e884e2164c0a6ff66a30d641826b1 (commit)
via 4e96a5b01f0f11ab92dd2b8d17371da3fb970dff (commit)
via c6c2a5e9e9c353f0c7103f269270b0a9a66a8791 (commit)
via d050a27bba812802f96524cd8f660dbdcb5c77cc (commit)
via c0b77c41f7dc0daa763ee53566fe9ca18d81a7a2 (commit)
from bf7bda2a551b71f131bf8d95ca45ef532b1e181e (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 ae170ab6674e889369bf4d97c01294222f2a4edd
Author: Naoki Kambe <kambe at jprs.co.jp>
Date: Mon Mar 7 21:39:38 2011 +0900
[trac547] add more tests
- stats module returns error
- "shutdown" command is invoked
commit 4d04514e9ea4b5261c2d8e4f04776d391a00688e
Author: Naoki Kambe <kambe at jprs.co.jp>
Date: Mon Mar 7 19:36:58 2011 +0900
[trac547] add more test
commit 04a63faa1b803ed862af655e38c9989a48e286b7
Author: Naoki Kambe <kambe at jprs.co.jp>
Date: Mon Mar 7 18:03:56 2011 +0900
[trac547]
- add restoring old config data if failed restarting httpd
- add to a new methods "get_sockets" to return socket list
- add more verbose messages
- remove destructor of stats_httpd module and add catching SessionError when stats_httpd object is exiting
commit ce2bc7f565535cfedf1958157d539e0fd02c3354
Author: Naoki Kambe <kambe at jprs.co.jp>
Date: Mon Mar 7 12:27:31 2011 +0900
[trac547]
- change URL of XML, XSD and XSL documents
- add parameter of XSD namespace
- add default configure
- add some assertion
- rename some methods which return XML, XSD and XSL document
- implement HTTP redirection because of no found document requested
- remove catching some exceptions because it didn't be needed to be so much strict
- add error handling when received incorrect configure
- configurable of multiple IP addresses and ports for HTTP listen (it can hold multiple sockets for HTTP listen)
- add http closing message for verbose
- fix some try/except statements
- add some minor changes and minor refactoring
commit de46ddd9ba5e884e2164c0a6ff66a30d641826b1
Author: Naoki Kambe <kambe at jprs.co.jp>
Date: Mon Mar 7 12:03:12 2011 +0900
[trac547]
- add changes according to changes of the target source code
- change values of dummy data
- add more tests
commit 4e96a5b01f0f11ab92dd2b8d17371da3fb970dff
Author: Naoki Kambe <kambe at jprs.co.jp>
Date: Mon Mar 7 12:01:24 2011 +0900
[trac547]
- change values of constant parameters for testing
- add more information in error massages
commit c6c2a5e9e9c353f0c7103f269270b0a9a66a8791
Author: Naoki Kambe <kambe at jprs.co.jp>
Date: Mon Mar 7 11:59:35 2011 +0900
[trac547] add some minor changes for testing
- add/rename some minor parameter
- remove some minor getter methods
commit d050a27bba812802f96524cd8f660dbdcb5c77cc
Author: Naoki Kambe <kambe at jprs.co.jp>
Date: Mon Mar 7 11:57:40 2011 +0900
[trac547] configurable of multiple IP addresses and ports for HTTP listen
commit c0b77c41f7dc0daa763ee53566fe9ca18d81a7a2
Author: Naoki Kambe <kambe at jprs.co.jp>
Date: Mon Mar 7 11:53:05 2011 +0900
[trac547]
- replaced with substitution strings for namespace and url
- add text decoration of CSS to XSL document
-----------------------------------------------------------------------
Summary of changes:
src/bin/stats/stats-httpd-xml.tpl.in | 6 +-
src/bin/stats/stats-httpd-xsd.tpl.in | 4 +-
src/bin/stats/stats-httpd-xsl.tpl.in | 5 +-
src/bin/stats/stats-httpd.spec.in | 46 +++-
src/bin/stats/stats_httpd.py.in | 349 +++++++++++++++-----------
src/bin/stats/tests/b10-stats-httpd_test.py | 311 +++++++++++++++---------
src/bin/stats/tests/http/server.py | 14 +-
src/bin/stats/tests/socket.py | 8 +-
8 files changed, 451 insertions(+), 292 deletions(-)
-----------------------------------------------------------------------
diff --git a/src/bin/stats/stats-httpd-xml.tpl.in b/src/bin/stats/stats-httpd-xml.tpl.in
index 7f2cb68..d5846ad 100644
--- a/src/bin/stats/stats-httpd-xml.tpl.in
+++ b/src/bin/stats/stats-httpd-xml.tpl.in
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet type="text/xsl" href="bind10-statistics.xsl"?>
+<?xml-stylesheet type="text/xsl" href="$xsl_url_path"?>
<!--
- Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
-
@@ -17,8 +17,8 @@
-->
<stats:stats_data version="1.0"
- xmlns:stats="http://bind10.isc.org/xsd/bind10-statistics"
+ xmlns:stats="$xsd_namespace"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://bind10.isc.org/xsd/bind10-statistics bind10-statistics.xsd">
+ xsi:schemaLocation="$xsd_namespace $xsd_url_path">
$xml_string
</stats:stats_data>
diff --git a/src/bin/stats/stats-httpd-xsd.tpl.in b/src/bin/stats/stats-httpd-xsd.tpl.in
index 469140f..6ad1280 100644
--- a/src/bin/stats/stats-httpd-xsd.tpl.in
+++ b/src/bin/stats/stats-httpd-xsd.tpl.in
@@ -15,9 +15,9 @@
- PERFORMANCE OF THIS SOFTWARE.
-->
-<schema targetNamespace="http://bind10.isc.org/xsd/bind10-statistics"
+<schema targetNamespace="$xsd_namespace"
xmlns="http://www.w3.org/2001/XMLSchema"
- xmlns:stats="http://bind10.isc.org/xsd/bind10-statistics">
+ xmlns:stats="$xsd_namespace">
<annotation>
<documentation xml:lang="en">XML schema of the statistics
data in BIND 10</documentation>
diff --git a/src/bin/stats/stats-httpd-xsl.tpl.in b/src/bin/stats/stats-httpd-xsl.tpl.in
index 9354c78..01ffdc6 100644
--- a/src/bin/stats/stats-httpd-xsl.tpl.in
+++ b/src/bin/stats/stats-httpd-xsl.tpl.in
@@ -17,7 +17,7 @@
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml"
- xmlns:stats="http://bind10.isc.org/xsd/bind10-statistics">
+ xmlns:stats="$xsd_namespace">
<xsl:output method="html" encoding="UTF-8"
doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"
doctype-system=" http://www.w3.org/TR/html4/loose.dtd " />
@@ -34,6 +34,9 @@ td, th {
padding: 3px 20px;
border: 1px #000000 solid;
}
+td.title {
+ text-decoration:underline;
+}
]]>
</style>
</head>
diff --git a/src/bin/stats/stats-httpd.spec.in b/src/bin/stats/stats-httpd.spec.in
index d769752..f4d7a52 100644
--- a/src/bin/stats/stats-httpd.spec.in
+++ b/src/bin/stats/stats-httpd.spec.in
@@ -4,18 +4,42 @@
"module_description": "Stats HTTP daemon",
"config_data": [
{
- "item_name": "listen_on_address",
- "item_type": "string",
- "item_optional": true,
- "item_default": "127.0.0.1",
- "item_description": "http listen-on address"
- },
- {
- "item_name": "listen_on_port",
- "item_type": "integer",
+ "item_name": "listen_on",
+ "item_type": "list",
"item_optional": false,
- "item_default": 8000,
- "item_description": "http listen-on port"
+ "item_default": [
+ {
+ "address": "::1",
+ "port": 8000
+ },
+ {
+ "address": "127.0.0.1",
+ "port": 8000
+ }
+ ],
+ "list_item_spec": {
+ "item_name": "address",
+ "item_type": "map",
+ "item_optional": false,
+ "item_default": {},
+ "map_item_spec": [
+ {
+ "item_name": "address",
+ "item_type": "string",
+ "item_optional": true,
+ "item_default": "127.0.0.1",
+ "item_description": "http listen-on address"
+ },
+ {
+ "item_name": "port",
+ "item_type": "integer",
+ "item_optional": true,
+ "item_default": 8000,
+ "item_description": "http listen-on port"
+ }
+ ]
+ },
+ "item_description": "http listen-on address and port"
}
],
"commands": [
diff --git a/src/bin/stats/stats_httpd.py.in b/src/bin/stats/stats_httpd.py.in
index 29a526d..ab0a291 100644
--- a/src/bin/stats/stats_httpd.py.in
+++ b/src/bin/stats/stats_httpd.py.in
@@ -45,9 +45,12 @@ STATS_SPECFILE_LOCATION = BASE_LOCATION + os.sep + "stats.spec"
XML_TEMPLATE_LOCATION = BASE_LOCATION + os.sep + "stats-httpd-xml.tpl"
XSD_TEMPLATE_LOCATION = BASE_LOCATION + os.sep + "stats-httpd-xsd.tpl"
XSL_TEMPLATE_LOCATION = BASE_LOCATION + os.sep + "stats-httpd-xsl.tpl"
-XML_URL_PATH = '/'
-XSD_URL_PATH = '/bind10-statistics.xsd'
-XSL_URL_PATH = '/bind10-statistics.xsl'
+
+XML_URL_PATH = '/bind10/statistics/xml'
+XSD_URL_PATH = '/bind10/statistics/xsd'
+XSL_URL_PATH = '/bind10/statistics/xsl'
+XSD_NAMESPACE = 'http://bind10.isc.org' + XSD_URL_PATH # TODO: should be considered later
+DEFAULT_CONFIG = dict(listen_on=[('127.0.0.1', 8000)])
MAX_SIZE_OF_TEMPLATE = 102400 # under 100k
@@ -55,62 +58,78 @@ MAX_SIZE_OF_TEMPLATE = 102400 # under 100k
isc.util.process.rename()
class HttpHandler(http.server.BaseHTTPRequestHandler):
- """
- HTTP handler class
- """
+ """HTTP handler class"""
def do_GET(self):
body = self.send_head()
- if type(body) is str:
+ if body is not None:
self.wfile.write(body.encode())
def do_HEAD(self):
self.send_head()
def send_head(self):
+ assert isinstance(self.server, HttpServer)
try:
if self.path == XML_URL_PATH:
- contents = self.server.stats_httpd.get_stats_xml()
+ body = self.server.xml_handler()
elif self.path == XSD_URL_PATH:
- contents = self.server.stats_httpd.get_stats_xsd()
+ body = self.server.xsd_handler()
elif self.path == XSL_URL_PATH:
- contents = self.server.stats_httpd.get_stats_xsl()
+ body = self.server.xsl_handler()
else:
- self.send_error(404)
- return None
+ if 'Host' in self.headers.keys():
+ # redirect to XML URL
+ self.send_response(302)
+ self.send_header(
+ "Location",
+ "http://" + self.headers.get('Host') + XML_URL_PATH)
+ self.end_headers()
+ return None
+ else:
+ # Couldn't find HOST
+ self.send_error(404)
+ return None
except StatsHttpdError as err:
self.send_error(500)
- raise StatsHttpdError(err)
+ if self.server.verbose:
+ self.server.log_writer(
+ "[b10-stats-httpd] %s\n" % err)
+ return None
else:
self.send_response(200)
self.send_header("Content-type", "text/xml")
- self.send_header("Content-Length", len(contents))
+ self.send_header("Content-Length", len(body))
self.end_headers()
- return contents
+ return body
def log_message(self, format, *args):
- """
- Change the default log format
- """
+ """Change the default log format"""
+ assert isinstance(self.server, HttpServer)
if self.server.verbose:
- self.server.stats_httpd.write_log(
+ self.server.log_writer(
"[b10-stats-httpd] %s - - [%s] %s\n" %
(self.address_string(),
self.log_date_time_string(),
format%args))
+class HttpServerError(Exception):
+ """To be passed from the HttpServer object to the StatsHttpd object"""
+ pass
+
class HttpServer(http.server.HTTPServer):
- """
- HTTP Server class
- """
- def __init__(self, handler, stats_httpd, verbose=False):
+ """HTTP Server class"""
+ def __init__(self, server_address, handler,
+ xml_handler, xsd_handler, xsl_handler, log_writer, verbose=False):
+ self.server_address = server_address
+ self.xml_handler = xml_handler
+ self.xsd_handler = xsd_handler
+ self.xsl_handler = xsl_handler
+ self.log_writer = log_writer
self.verbose = verbose
- self.stats_httpd = stats_httpd
- http.server.HTTPServer.__init__(
- self,
- (self.stats_httpd.http_addr, self.stats_httpd.http_port),
- handler)
+ http.server.HTTPServer.__init__(self, server_address, handler)
class StatsHttpdError(Exception):
+ """To be passed from the StatsHttpd object to the HttpHandler object"""
pass
class StatsHttpd:
@@ -118,139 +137,176 @@ class StatsHttpd:
"""
def __init__(self, verbose=False):
self.verbose = verbose
- self.running = True
+ self.running = False
self.poll_intval = 0.5
self.write_log = sys.stderr.write
self.mccs = None
- self.httpd = None
- try:
- self.open_mccs()
- self.load_config()
- self.load_templates()
- self.open_httpd()
- except StatsHttpdError as err:
- raise StatsHttpdError(
- "error with initializing StatsHttpd: %s" % err)
+ self.httpd = []
+ self.open_mccs()
+ self.load_config()
+ self.load_templates()
+ self.open_httpd()
def open_mccs(self):
# create ModuleCCSession
+ if self.verbose:
+ self.write_log("[b10-stats-httpd] Starting CC Session\n")
self.mccs = isc.config.ModuleCCSession(
SPECFILE_LOCATION, self.config_handler, self.command_handler)
- self.mccs_fd = self.mccs.get_socket()
self.cc_session = self.mccs._session
+ # read spec file of stats module and subscribe 'Stats'
self.stats_module_spec = isc.config.module_spec_from_file(STATS_SPECFILE_LOCATION)
self.stats_config_spec = self.stats_module_spec.get_config_spec()
self.stats_module_name = self.stats_module_spec.get_module_name()
+ if self.verbose:
+ self.write_log("[b10-stats-httpd] Starts to subscribe stats module\n")
+ self.cc_session.group_subscribe(self.stats_module_name, "*")
def close_mccs(self):
if self.mccs is None:
return
+ if self.verbose:
+ self.write_log("[b10-stats-httpd] Closing CC Session\n")
try:
self.cc_session.group_unsubscribe(self.stats_module_name, "*")
- except isc.cc.session.SessionError as err:
- raise StatsHttpdError("error in CCSession: %s\n" % err)
+ except isc.cc.session.SessionError as se:
+ if self.verbose:
+ self.write_log("[b10-stats-httpd] Failed to unsubscribe stats module\n")
self.mccs.close()
self.mccs = None
- def load_config(self, new_config=None):
+ def load_config(self, new_config={}):
# load config
- if new_config is not None:
+ if len(new_config) > 0:
+ assert type(self.config) is dict
assert type(new_config) is dict
- assert self.config is not None
self.config.update(new_config)
else:
- self.config = dict([
- (i['item_name'], self.mccs.get_value(i['item_name'])[0])
- for i in self.mccs.get_module_spec().get_config_spec()
- ])
- assert self.config is not None and len(self.config) > 0 and type(self.config) is dict
- assert 'listen_on_address' in self.config
- assert 'listen_on_port' in self.config
- self.http_addr = self.config['listen_on_address']
- self.http_port = self.config['listen_on_port']
-
- def open_httpd(self, address_family=None):
+ self.config = DEFAULT_CONFIG
+ self.config.update(
+ dict([
+ (itm['item_name'], self.mccs.get_value(itm['item_name'])[0])
+ for itm in self.mccs.get_module_spec().get_config_spec()
+ ])
+ )
+ assert 'listen_on' in self.config
+ assert type(self.config['listen_on']) is list
+ # remove duplicated element
+ self.http_addrs = list(
+ set([ (cf['address'], cf['port']) for cf in self.config['listen_on'] ])
+ )
+
+ def open_httpd(self):
+ assert type(self.http_addrs) is list
+ for addr in self.http_addrs:
+ self.httpd.append(self._open_httpd(addr))
+
+ def _open_httpd(self, server_address, address_family=None):
+ assert type(server_address) is tuple
try:
- # try IPv6 as default
- if address_family is None and socket.has_ipv6:
- HttpServer.address_family = socket.AF_INET6
- elif address_family is not None:
+ # try IPv6 at first
+ if address_family is not None:
HttpServer.address_family = address_family
- self.httpd = HttpServer(HttpHandler, self, self.verbose)
+ elif socket.has_ipv6:
+ HttpServer.address_family = socket.AF_INET6
+ httpd = HttpServer(
+ server_address, HttpHandler,
+ self.xml_handler, self.xsd_handler, self.xsl_handler,
+ self.write_log, self.verbose)
except (socket.gaierror, socket.error,
OverflowError, TypeError) as err:
+ # try IPv4 next
if HttpServer.address_family == socket.AF_INET6:
- # try IPv4
- self.open_httpd(address_family=socket.AF_INET)
+ httpd = self._open_httpd(server_address, socket.AF_INET)
else:
- raise StatsHttpdError(
- "Invalid address %s: %s: %s\n" %
- (self.http_addr, self.http_port, err))
+ raise HttpServerError(
+ "Invalid address %s, port %s: %s: %s" %
+ (server_address[0], server_address[1],
+ err.__class__.__name__, err))
else:
- self.http_fd = self.httpd.socket
- if self.verbose and self.running:
+ if self.verbose:
self.write_log(
"[b10-stats-httpd] Started on address %s, port %s\n" %
- (self.http_addr, self.http_port))
+ server_address)
+ assert isinstance(httpd, HttpServer)
+ return httpd
def close_httpd(self):
- if self.httpd is None:
+ if len(self.httpd) == 0:
return
- self.http_fd.close()
- self.httpd = None
+ for ht in self.httpd:
+ assert type(ht.server_address) is tuple
+ if self.verbose:
+ self.write_log(
+ "[b10-stats-httpd] Closing address %s, port %s\n" %
+ (ht.server_address[0], ht.server_address[1])
+ )
+ ht.server_close()
+ self.httpd = []
def start(self):
- try:
- self.mccs.start()
- self.cc_session.group_subscribe(self.stats_module_name, "*")
- while self.running:
- try:
- (rfd, wfd, xfd) = select.select(
- [self.mccs_fd, self.http_fd], [], [], self.poll_intval)
- except select.error as err:
- if err.args[0] == errno.EINTR:
- (rfd, wfd, xfd) = ([], [], [])
- else:
- raise StatsHttpdError(err)
- for fd in rfd + xfd:
- if fd == self.mccs_fd:
- self.mccs.check_command(nonblock=False)
- elif fd == self.http_fd:
- self.httpd.handle_request()
- except (isc.cc.session.SessionError,
- isc.config.ccsession.ModuleCCSessionError) as err:
- raise StatsHttpdError("error in CCSession: %s\n" % err)
- except StatsHttpdError as err:
- raise StatsHttpdError("error with selecting; %s\n" % err)
- finally:
- self.stop()
+ self.mccs.start()
+ self.running = True
+ while self.running:
+ try:
+ (rfd, wfd, xfd) = select.select(
+ self.get_sockets(), [], [], self.poll_intval)
+ except select.error as err:
+ if err.args[0] == errno.EINTR:
+ (rfd, wfd, xfd) = ([], [], [])
+ else:
+ raise select.error(err)
+ for fd in rfd + xfd:
+ if fd == self.mccs.get_socket():
+ self.mccs.check_command(nonblock=False)
+ continue
+ for ht in self.httpd:
+ if fd == ht.socket:
+ ht.handle_request()
+ break
+ self.stop()
def stop(self):
if self.verbose:
self.write_log("[b10-stats-httpd] Shutting down\n")
- self.running = False
self.close_httpd()
self.close_mccs()
- def __del__(self):
- self.stop()
+ def get_sockets(self):
+ sockets = []
+ if self.mccs is not None:
+ sockets.append(self.mccs.get_socket())
+ if len(self.httpd) > 0:
+ for ht in self.httpd:
+ sockets.append(ht.socket)
+ return sockets
def config_handler(self, new_config):
- """
- config handler
- """
+ """config handler for ModuleCCSession object"""
+ assert type(new_config) is dict
if self.verbose:
self.write_log("[b10-stats-httpd] Loading new config : %s\n" % str(new_config))
+ for key in new_config.keys():
+ if key not in DEFAULT_CONFIG:
+ if self.verbose:
+ self.write_log(
+ "[b10-stats-httpd] Unknown known config: %s" % key)
+ return isc.config.ccsession.create_answer(
+ 1, "Unknown known config: %s" % key)
+ # backup old config
+ old_config = self.config.copy()
self.close_httpd()
+ self.load_config(new_config)
try:
- self.load_config(new_config)
self.open_httpd()
- except StatsHttpdError as err:
+ except HttpServerError as err:
if self.verbose:
- self.write_log(
- "[b10-stats-httpd] Unexpected error with reloading new config: %s" % err)
+ self.write_log("[b10-stats-httpd] %s\n" % err)
+ self.write_log("[b10-stats-httpd] Restoring old config\n")
+ # restore old config
+ self.config_handler(old_config)
return isc.config.ccsession.create_answer(
- 1, "Unexpected error with reloading new config: %s" % err)
+ 1, "[b10-stats-httpd] %s" % err)
else:
return isc.config.ccsession.create_answer(0)
@@ -280,35 +336,27 @@ class StatsHttpd:
seq = self.cc_session.group_sendmsg(
isc.config.ccsession.create_command('show'),
self.stats_module_name)
- answer, env = self.cc_session.group_recvmsg(False, seq)
+ (answer, env) = self.cc_session.group_recvmsg(False, seq)
if answer:
(rcode, value) = isc.config.ccsession.parse_answer(answer)
self.cc_session.group_reply(
env, isc.config.ccsession.create_answer(0))
- except (isc.cc.SessionTimeout,
+ except (isc.cc.session.SessionTimeout,
isc.cc.session.SessionError) as err:
- raise StatsHttpdError(err)
+ raise StatsHttpdError("%s: %s" %
+ (err.__class__.__name__, err))
else:
if rcode == 0:
return value
else:
- raise StatsHttpdError("can't the stats data")
+ raise StatsHttpdError("Stats module: %s" % str(value))
def get_stats_spec(self):
- """
- return spec data
- """
+ """return spec data"""
return self.stats_config_spec
def load_templates(self):
- # open templates
- self.xml_content = ""
- self.xsd_content = ""
- self.xsl_content = ""
- self.xml_template = self.open_template(XML_TEMPLATE_LOCATION)
- self.xsd_template = self.open_template(XSD_TEMPLATE_LOCATION)
- self.xsl_template = self.open_template(XSL_TEMPLATE_LOCATION)
-
+ """open templates of XSD and XSL and create their string"""
# for XSD
xsd_root = xml.etree.ElementTree.Element("all") # started with "all" tag
for item in self.get_stats_spec():
@@ -329,9 +377,11 @@ class StatsHttpd:
element.append(annotation)
xsd_root.append(element)
xsd_string = xml.etree.ElementTree.tostring(xsd_root)
- assert self.xsd_template is not None
- self.xsd_content = self.xsd_template.substitute(
- xsd_string=xsd_string)
+ self.xsd_body = self.open_template(XSD_TEMPLATE_LOCATION).substitute(
+ xsd_string=xsd_string,
+ xsd_namespace=XSD_NAMESPACE
+ )
+ assert self.xsd_body is not None
# for XSL
xsd_root = xml.etree.ElementTree.Element(
@@ -340,7 +390,8 @@ class StatsHttpd:
for item in self.get_stats_spec():
tr = xml.etree.ElementTree.Element("tr")
td1 = xml.etree.ElementTree.Element(
- "td", dict(title=item["item_description"]))
+ "td", { "class" : "title",
+ "title" : item["item_description"] })
td1.text = item["item_title"]
td2 = xml.etree.ElementTree.Element("td")
xsl_valueof = xml.etree.ElementTree.Element(
@@ -351,40 +402,40 @@ class StatsHttpd:
tr.append(td2)
xsd_root.append(tr)
xsl_string = xml.etree.ElementTree.tostring(xsd_root)
- assert self.xsl_template is not None
- self.xsl_content = self.xsl_template.substitute(
- xsl_string=xsl_string)
+ self.xsl_body = self.open_template(XSL_TEMPLATE_LOCATION).substitute(
+ xsl_string=xsl_string,
+ xsd_namespace=XSD_NAMESPACE)
+ assert self.xsl_body is not None
- def get_stats_xml(self):
+ def xml_handler(self):
xml_list=[]
for (k, v) in self.get_stats_data().items():
(k, v) = (str(k), str(v))
- assert type(k) is str and type(v) is str
- x = xml.etree.ElementTree.Element(k)
- x.text = v
+ elem = xml.etree.ElementTree.Element(k)
+ elem.text = v
xml_list.append(
- xml.etree.ElementTree.tostring(x))
+ xml.etree.ElementTree.tostring(elem))
assert len(xml_list) > 0
xml_string = "".join(xml_list)
- assert self.xml_template is not None
- self.xml_content = self.xml_template.substitute(
- xml_string=xml_string)
- return self.xml_content
+ self.xml_body = self.open_template(XML_TEMPLATE_LOCATION).substitute(
+ xml_string=xml_string,
+ xsd_namespace=XSD_NAMESPACE,
+ xsd_url_path=XSD_URL_PATH,
+ xsl_url_path=XSL_URL_PATH)
+ assert self.xml_body is not None
+ return self.xml_body
- def get_stats_xsd(self):
- return self.xsd_content
+ def xsd_handler(self):
+ return self.xsd_body
- def get_stats_xsl(self):
- return self.xsl_content
+ def xsl_handler(self):
+ return self.xsl_body
def open_template(self, file_name):
- try:
- contents = "".join(
- open(file_name, 'r').readlines(MAX_SIZE_OF_TEMPLATE))
- except IOError as err:
- raise StatsHttpdError("error in opening file; %s" % err)
- else:
- return string.Template(contents)
+ lines = "".join(
+ open(file_name, 'r').readlines(MAX_SIZE_OF_TEMPLATE))
+ assert lines is not None
+ return string.Template(lines)
if __name__ == "__main__":
try:
@@ -400,5 +451,7 @@ if __name__ == "__main__":
except isc.cc.session.SessionError as se:
sys.stderr.write("[b10-stats-httpd] Error creating module, "
+ "is the command channel daemon running?\n")
+ except HttpServerError as hse:
+ sys.stderr.write("[b10-stats-httpd] %s\n" % hse)
except KeyboardInterrupt as kie:
sys.stderr.write("[b10-stats-httpd] Interrupted, exiting\n")
diff --git a/src/bin/stats/tests/b10-stats-httpd_test.py b/src/bin/stats/tests/b10-stats-httpd_test.py
index 082f603..20168b0 100644
--- a/src/bin/stats/tests/b10-stats-httpd_test.py
+++ b/src/bin/stats/tests/b10-stats-httpd_test.py
@@ -27,15 +27,15 @@ import isc.cc
import stats_httpd
DUMMY_DATA = {
- "auth.queries.tcp": 0,
- "auth.queries.udp": 0,
- "bind10.boot_time": "1970-01-01T00:00:00Z",
- "report_time": "2011-02-24T09:08:32Z",
- "stats.boot_time": "2011-02-24T09:08:21Z",
- "stats.last_update_time": "2011-02-24T09:08:21Z",
- "stats.lname": "4d662005_a at fdvm",
- "stats.start_time": "2011-02-24T09:08:21Z",
- "stats.timestamp": 1298538512.87378
+ "auth.queries.tcp": 10000,
+ "auth.queries.udp": 12000,
+ "bind10.boot_time": "2011-03-04T11:59:05Z",
+ "report_time": "2011-03-04T11:59:19Z",
+ "stats.boot_time": "2011-03-04T11:59:06Z",
+ "stats.last_update_time": "2011-03-04T11:59:07Z",
+ "stats.lname": "4d70d40a_c at host",
+ "stats.start_time": "2011-03-04T11:59:06Z",
+ "stats.timestamp": 1299239959.560846
}
def push_answer(stats_httpd):
@@ -56,16 +56,22 @@ class TestHttpHandler(unittest.TestCase):
def setUp(self):
self.verbose = True
self.stats_httpd = stats_httpd.StatsHttpd(self.verbose)
- self.handler = stats_httpd.HttpHandler(None, None, self.stats_httpd.httpd)
- self.assertTrue(self.stats_httpd.httpd.verbose)
+ self.assertTrue(type(self.stats_httpd.httpd) is list)
+ self.httpd = self.stats_httpd.httpd
+ for ht in self.httpd:
+ self.assertTrue(ht.verbose)
self.stats_httpd.cc_session.verbose = False
def test_do_GET(self):
+ for ht in self.httpd:
+ self._test_do_GET(ht._handler)
- # URL is '/'
- self.handler.path = stats_httpd.XML_URL_PATH
+ def _test_do_GET(self, handler):
+
+ # URL is '/bind10/statistics/xml'
+ handler.path = stats_httpd.XML_URL_PATH
push_answer(self.stats_httpd)
- self.handler.do_GET()
+ handler.do_GET()
(ret, arg, env) = pull_query(self.stats_httpd)
self.assertEqual(ret, "show")
self.assertIsNone(arg)
@@ -76,74 +82,117 @@ class TestHttpHandler(unittest.TestCase):
self.assertIsNone(arg)
self.assertTrue('group' in env)
self.assertEqual(env['group'], 'Stats')
- self.assertEqual(self.handler.response.code, 200)
- self.assertEqual(self.handler.response.headers["Content-type"], "text/xml")
- self.assertTrue(self.handler.response.headers["Content-Length"] > 0)
- self.assertTrue(self.handler.response.wrote_headers)
+ self.assertEqual(handler.response.code, 200)
+ self.assertEqual(handler.response.headers["Content-type"], "text/xml")
+ self.assertTrue(handler.response.headers["Content-Length"] > 0)
+ self.assertTrue(handler.response.wrote_headers)
+ self.assertRegexpMatches(handler.response.body, stats_httpd.XSD_NAMESPACE)
+ self.assertRegexpMatches(handler.response.body, stats_httpd.XSD_URL_PATH)
for (k, v) in DUMMY_DATA.items():
- self.assertRegexpMatches(self.handler.response.body, str(k))
- self.assertRegexpMatches(self.handler.response.body, str(v))
-
- # URL is '/bind10-statitics.xsd'
- self.handler.path = stats_httpd.XSD_URL_PATH
- self.handler.do_GET()
- self.assertEqual(self.handler.response.code, 200)
- self.assertEqual(self.handler.response.headers["Content-type"], "text/xml")
- self.assertTrue(self.handler.response.headers["Content-Length"] > 0)
- self.assertTrue(self.handler.response.wrote_headers)
+ self.assertRegexpMatches(handler.response.body, str(k))
+ self.assertRegexpMatches(handler.response.body, str(v))
+
+ # URL is '/bind10/statitics/xsd'
+ handler.path = stats_httpd.XSD_URL_PATH
+ handler.do_GET()
+ self.assertEqual(handler.response.code, 200)
+ self.assertEqual(handler.response.headers["Content-type"], "text/xml")
+ self.assertTrue(handler.response.headers["Content-Length"] > 0)
+ self.assertTrue(handler.response.wrote_headers)
+ self.assertRegexpMatches(handler.response.body, stats_httpd.XSD_NAMESPACE)
for (k, v) in DUMMY_DATA.items():
- self.assertRegexpMatches(self.handler.response.body, str(k))
-
- # URL is '/bind10-statitics.xsl'
- self.handler.path = stats_httpd.XSL_URL_PATH
- self.handler.do_GET()
- self.assertEqual(self.handler.response.code, 200)
- self.assertEqual(self.handler.response.headers["Content-type"], "text/xml")
- self.assertTrue(self.handler.response.headers["Content-Length"] > 0)
- self.assertTrue(self.handler.response.wrote_headers)
+ self.assertRegexpMatches(handler.response.body, str(k))
+
+ # URL is '/bind10/statitics/xsl'
+ handler.path = stats_httpd.XSL_URL_PATH
+ handler.do_GET()
+ self.assertEqual(handler.response.code, 200)
+ self.assertEqual(handler.response.headers["Content-type"], "text/xml")
+ self.assertTrue(handler.response.headers["Content-Length"] > 0)
+ self.assertTrue(handler.response.wrote_headers)
+ self.assertRegexpMatches(handler.response.body, stats_httpd.XSD_NAMESPACE)
for (k, v) in DUMMY_DATA.items():
- self.assertRegexpMatches(self.handler.response.body, str(k))
-
- # NotFound URL
- self.handler.path = '/path/to/foo/bar'
- self.handler.do_GET()
- self.assertEqual(self.handler.response.code, 404)
-
- # failure case(network problem)
- self.handler.path = stats_httpd.XML_URL_PATH
+ self.assertRegexpMatches(handler.response.body, str(k))
+
+ # 302 redirect
+ handler.path = '/'
+ handler.headers = {'Host': 'my.host.domain'}
+ handler.do_GET()
+ self.assertEqual(handler.response.code, 302)
+ self.assertEqual(handler.response.headers["Location"],
+ "http://my.host.domain%s" % stats_httpd.XML_URL_PATH)
+
+ # 404 NotFound
+ handler.path = '/path/to/foo/bar'
+ handler.headers = {}
+ handler.do_GET()
+ self.assertEqual(handler.response.code, 404)
+
+ # failure case(connection with Stats is down)
+ handler.path = stats_httpd.XML_URL_PATH
push_answer(self.stats_httpd)
self.assertFalse(self.stats_httpd.cc_session._socket._closed)
self.stats_httpd.cc_session._socket._closed = True
- self.assertRaises(stats_httpd.StatsHttpdError, self.handler.do_GET)
- self.assertEqual(self.handler.response.code, 500)
+ handler.do_GET()
+ self.stats_httpd.cc_session._socket._closed = False
+ self.assertEqual(handler.response.code, 500)
+ self.stats_httpd.cc_session._clear_ques()
+
+ # failure case(Stats module returns err)
+ handler.path = stats_httpd.XML_URL_PATH
+ self.stats_httpd.cc_session.group_sendmsg(
+ { 'result': [ 1, "I have an error." ] }, "Stats")
+ self.assertFalse(self.stats_httpd.cc_session._socket._closed)
+ self.stats_httpd.cc_session._socket._closed = False
+ handler.do_GET()
+ self.assertEqual(handler.response.code, 500)
+ self.stats_httpd.cc_session._clear_ques()
def test_do_HEAD(self):
- # other url
- self.handler.path = '/path/to/foo/bar'
- self.handler.do_HEAD()
- self.assertEqual(self.handler.response.code, 404)
+ for ht in self.httpd:
+ self._test_do_HEAD(ht._handler)
+
+ def _test_do_HEAD(self, handler):
+ handler.path = '/path/to/foo/bar'
+ handler.do_HEAD()
+ self.assertEqual(handler.response.code, 404)
def test_log_message(self):
+ for ht in self.httpd:
+ self._test_log_message(ht._handler)
+
+ def _test_log_message(self, handler):
# switch write_log function
- self.stats_httpd.write_log = self.handler.response._write_log
+ handler.server.log_writer = handler.response._write_log
log_message = 'ABCDEFG'
- self.handler.log_message("%s", log_message)
- self.assertEqual(self.handler.response.log,
+ handler.log_message("%s", log_message)
+ self.assertEqual(handler.response.log,
"[b10-stats-httpd] %s - - [%s] %s\n" %
- (self.handler.address_string(),
- self.handler.log_date_time_string(),
+ (handler.address_string(),
+ handler.log_date_time_string(),
log_message))
+class TestHttpServerError(unittest.TestCase):
+ def test_raises(self):
+ try:
+ raise stats_httpd.HttpServerError('Nothing')
+ except stats_httpd.HttpServerError as err:
+ self.assertEqual(str(err), 'Nothing')
+
class TestHttpServer(unittest.TestCase):
def setUp(self):
self.verbose = True
self.stats_httpd = stats_httpd.StatsHttpd(self.verbose)
- self.httpd = stats_httpd.HttpServer(stats_httpd.HttpHandler, self.stats_httpd, self.verbose)
- self.assertEqual(self.httpd.verbose, self.verbose)
- self.assertEqual(self.httpd.stats_httpd, self.stats_httpd)
- self.assertEqual(type(self.httpd._get_handler), stats_httpd.HttpHandler)
- self.assertEqual(self.httpd._get_server_class,
- (self.stats_httpd.http_addr, self.stats_httpd.http_port))
+ self.stats_httpd.cc_session.verbose = False
+ for ht in self.stats_httpd.httpd:
+ self.assertTrue(ht.server_address in self.stats_httpd.http_addrs)
+ self.assertEqual(self.ht.verbose, self.verbose)
+ self.assertEqual(self.ht.xml_handler, self.stats_httpd.xml_handler)
+ self.assertEqual(self.ht.xsd_handler, self.stats_httpd.xsd_handler)
+ self.assertEqual(self.ht.xsl_handler, self.stats_httpd.xsl_handler)
+ self.assertEqual(self.ht.log_writer, self.stats_httpd.write_log)
+ self.assertTrue(isinstance(self.ht._handler, stats_httpd.HttpHandler))
+ self.assertTrue(isinstance(self.ht.socket, socket.socket))
class TestStatsHttpdError(unittest.TestCase):
def test_raises(self):
@@ -157,18 +206,21 @@ class TestStatsHttpd(unittest.TestCase):
def setUp(self):
self.verbose = True
socket._CLOSED = False
+ socket.has_ipv6 = True
self.stats_httpd = stats_httpd.StatsHttpd(self.verbose)
+ self.stats_httpd.cc_session.verbose = False
def tearDown(self):
self.stats_httpd.stop()
def test_init(self):
self.assertTrue(self.stats_httpd.verbose)
- self.assertTrue(self.stats_httpd.running)
- self.assertFalse(self.stats_httpd.mccs_fd._closed)
- self.assertFalse(self.stats_httpd.http_fd._closed)
- self.assertEqual(self.stats_httpd.mccs_fd.fileno(), id(self.stats_httpd.mccs_fd))
- self.assertEqual(self.stats_httpd.http_fd.fileno(), id(self.stats_httpd.http_fd))
+ self.assertFalse(self.stats_httpd.mccs.get_socket()._closed)
+ self.assertEqual(self.stats_httpd.mccs.get_socket().fileno(),
+ id(self.stats_httpd.mccs.get_socket()))
+ for ht in self.stats_httpd.httpd:
+ self.assertFalse(ht.socket._closed)
+ self.assertEqual(ht.socket.fileno(), id(ht.socket))
socket._CLOSED = True
self.assertRaises(isc.cc.session.SessionError,
stats_httpd.StatsHttpd)
@@ -176,9 +228,12 @@ class TestStatsHttpd(unittest.TestCase):
def test_mccs(self):
self.stats_httpd.open_mccs()
- self.assertTrue(isinstance(self.stats_httpd.mccs_fd, socket.socket))
- self.assertTrue(isinstance(self.stats_httpd.cc_session, isc.cc.session.Session))
- self.assertTrue(isinstance(self.stats_httpd.stats_module_spec, isc.config.ModuleSpec))
+ self.assertTrue(
+ isinstance(self.stats_httpd.mccs.get_socket(), socket.socket))
+ self.assertTrue(
+ isinstance(self.stats_httpd.cc_session, isc.cc.session.Session))
+ self.assertTrue(
+ isinstance(self.stats_httpd.stats_module_spec, isc.config.ModuleSpec))
for cfg in self.stats_httpd.stats_config_spec:
self.assertTrue('item_name' in cfg)
self.assertTrue(cfg['item_name'] in DUMMY_DATA)
@@ -186,90 +241,108 @@ class TestStatsHttpd(unittest.TestCase):
def test_load_config(self):
self.stats_httpd.load_config()
- self.assertEqual(self.stats_httpd.http_addr, '127.0.0.1')
- self.assertEqual(self.stats_httpd.http_port, 8000)
+ self.assertTrue(('127.0.0.1', 8000) in set(self.stats_httpd.http_addrs))
+ self.assertTrue(('::1', 8000) in set(self.stats_httpd.http_addrs))
def test_httpd(self):
- # dual stack (address is ipv4)
+ # dual stack (addresses is ipv4 and ipv6)
socket.has_ipv6 = True
- (self.stats_httpd.http_addr, self.stats_httpd.http_port) = ('127.0.0.1', 8000)
- assert stats_httpd.HttpServer.address_family is socket.AF_INET
+ self.assertTrue(('127.0.0.1', 8000) in set(self.stats_httpd.http_addrs))
+ self.assertTrue(('::1', 8000) in set(self.stats_httpd.http_addrs))
+ self.assertTrue(
+ stats_httpd.HttpServer.address_family in set([socket.AF_INET, socket.AF_INET6]))
self.stats_httpd.open_httpd()
- self.assertTrue(isinstance(self.stats_httpd.http_fd, socket.socket))
+ for ht in self.stats_httpd.httpd:
+ self.assertTrue(isinstance(ht.socket, socket.socket))
self.stats_httpd.close_httpd()
+
# dual stack (address is ipv6)
socket.has_ipv6 = True
- (self.stats_httpd.http_addr, self.stats_httpd.http_port) = ('::1', 8000)
+ self.stats_httpd.http_addrs = [ ('::1', 8000) ]
self.stats_httpd.open_httpd()
- self.assertTrue(isinstance(self.stats_httpd.http_fd, socket.socket))
+ for ht in self.stats_httpd.httpd:
+ self.assertTrue(isinstance(ht.socket, socket.socket))
+ self.stats_httpd.close_httpd()
+
+ # dual stack (address is ipv4)
+ socket.has_ipv6 = True
+ self.stats_httpd.http_addrs = [ ('127.0.0.1', 8000) ]
+ self.stats_httpd.open_httpd()
+ for ht in self.stats_httpd.httpd:
+ self.assertTrue(isinstance(ht.socket, socket.socket))
self.stats_httpd.close_httpd()
# only-ipv4 single stack
socket.has_ipv6 = False
- (self.stats_httpd.http_addr, self.stats_httpd.http_port) = ('127.0.0.1', 8000)
+ self.stats_httpd.http_addrs = [ ('127.0.0.1', 8000) ]
self.stats_httpd.open_httpd()
- self.assertTrue(isinstance(self.stats_httpd.http_fd, socket.socket))
- self.stats_httpd.close_httpd()
- (self.stats_httpd.http_addr, self.stats_httpd.http_port) = ('::1', 8000)
- self.assertRaises(stats_httpd.StatsHttpdError, self.stats_httpd.open_httpd)
- self.assertTrue(isinstance(self.stats_httpd.http_fd, socket.socket))
+ for ht in self.stats_httpd.httpd:
+ self.assertTrue(isinstance(ht.socket, socket.socket))
self.stats_httpd.close_httpd()
+ # only-ipv4 single stack (force set ipv6 )
+ socket.has_ipv6 = False
+ self.stats_httpd.http_addrs = [ ('::1', 8000) ]
+ self.assertRaises(stats_httpd.HttpServerError,
+ self.stats_httpd.open_httpd)
+
# hostname
- (self.stats_httpd.http_addr, self.stats_httpd.http_port) = ('localhost', 8000)
+ self.stats_httpd.http_addrs = [ ('localhost', 8000) ]
self.stats_httpd.open_httpd()
- self.assertTrue(isinstance(self.stats_httpd.http_fd, socket.socket))
+ for ht in self.stats_httpd.httpd:
+ self.assertTrue(isinstance(ht.socket, socket.socket))
self.stats_httpd.close_httpd()
- (self.stats_httpd.http_addr, self.stats_httpd.http_port) = ('my.host.domain', 8000)
+
+ self.stats_httpd.http_addrs = [ ('my.host.domain', 8000) ]
self.stats_httpd.open_httpd()
- self.assertTrue(isinstance(self.stats_httpd.http_fd, socket.socket))
+ for ht in self.stats_httpd.httpd:
+ self.assertTrue(isinstance(ht.socket, socket.socket))
self.stats_httpd.close_httpd()
- # port is over flow
- (self.stats_httpd.http_addr, self.stats_httpd.http_port) = ('', 80000)
- self.assertRaises(stats_httpd.StatsHttpdError, self.stats_httpd.open_httpd)
- (self.stats_httpd.http_addr, self.stats_httpd.http_port) = ('', -8000)
- self.assertRaises(stats_httpd.StatsHttpdError, self.stats_httpd.open_httpd)
- (self.stats_httpd.http_addr, self.stats_httpd.http_port) = ('', 'ABCDE')
- self.assertRaises(stats_httpd.StatsHttpdError, self.stats_httpd.open_httpd)
+ # over flow of port number
+ self.stats_httpd.http_addrs = [ ('', 80000) ]
+ self.assertRaises(stats_httpd.HttpServerError, self.stats_httpd.open_httpd)
+ # negative
+ self.stats_httpd.http_addrs = [ ('', -8000) ]
+ self.assertRaises(stats_httpd.HttpServerError, self.stats_httpd.open_httpd)
+ # alphabet
+ self.stats_httpd.http_addrs = [ ('', 'ABCDE') ]
+ self.assertRaises(stats_httpd.HttpServerError, self.stats_httpd.open_httpd)
def test_start(self):
- self.assertTrue(self.stats_httpd.running)
+ self.stats_httpd.cc_session.group_sendmsg(
+ { 'command': [ "shutdown" ] }, "StatsHttpd")
+ self.stats_httpd.start()
+ self.stats_httpd = stats_httpd.StatsHttpd(self.verbose)
+ self.stats_httpd.cc_session.verbose = False
self.assertRaises(
- stats_httpd.StatsHttpdError,
- self.stats_httpd.start)
- self.assertFalse(self.stats_httpd.running)
+ select.error, self.stats_httpd.start)
def test_stop(self):
# success case
socket._CLOSED = False
- self.assertTrue(self.stats_httpd.running)
self.stats_httpd.stop()
self.assertFalse(self.stats_httpd.running)
- self.assertTrue(self.stats_httpd.mccs_fd._closed)
- self.assertTrue(self.stats_httpd.http_fd._closed)
+ self.assertIsNone(self.stats_httpd.mccs)
+ for ht in self.stats_httpd.httpd:
+ self.assertTrue(ht.socket._closed)
self.assertTrue(self.stats_httpd.cc_session._socket._closed)
# failure case
self.stats_httpd.cc_session._socket._closed = False
self.stats_httpd.open_mccs()
self.stats_httpd.cc_session._socket._closed = True
- self.assertRaises(stats_httpd.StatsHttpdError, self.stats_httpd.stop)
+ self.stats_httpd.stop() # No excetion raises
self.stats_httpd.cc_session._socket._closed = False
def test_open_template(self):
self.assertRaises(
- stats_httpd.StatsHttpdError,
+ IOError,
self.stats_httpd.open_template, '/path/to/foo/bar')
def test_commands(self):
- self.assertEqual(
- self.stats_httpd.config_handler(None),
- isc.config.ccsession.create_answer(0))
- self.assertTrue(self.stats_httpd.running)
self.assertEqual(self.stats_httpd.command_handler("status", None),
isc.config.ccsession.create_answer(
0, "Stats Httpd is up. (PID " + str(os.getpid()) + ")"))
- self.assertTrue(self.stats_httpd.running)
self.stats_httpd.running = True
self.assertEqual(self.stats_httpd.command_handler("shutdown", None),
isc.config.ccsession.create_answer(
@@ -281,19 +354,29 @@ class TestStatsHttpd(unittest.TestCase):
1, "Unknown command: __UNKNOWN_COMMAND__"))
def test_config(self):
+ d = dict(_UNKNOWN_KEY_=None)
+ assert type(d) is dict
+ self.assertEqual(
+ self.stats_httpd.config_handler(d),
+ isc.config.ccsession.create_answer(
+ 1, "Unknown known config: _UNKNOWN_KEY_"))
self.assertEqual(
self.stats_httpd.config_handler(
- { 'listen_on_address' : '::1' }),
+ dict(listen_on=[dict(address="::2",port=8000)])),
isc.config.ccsession.create_answer(0))
self.assertEqual(
self.stats_httpd.config_handler(
- { 'listen_on_port' : 80 }),
+ dict(listen_on=[dict(address="::1",port=80)])),
isc.config.ccsession.create_answer(0))
self.assertEqual(
self.stats_httpd.config_handler(
- { 'listen_on_address' : "1.2.3.4",
- 'listen_on_port' : 54321 }),
+ dict(listen_on=[dict(address="1.2.3.4",port=54321)])),
isc.config.ccsession.create_answer(0))
+ (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)
def test_no_buildpath(self):
"""
diff --git a/src/bin/stats/tests/http/server.py b/src/bin/stats/tests/http/server.py
index 4d4621e..8bdad98 100644
--- a/src/bin/stats/tests/http/server.py
+++ b/src/bin/stats/tests/http/server.py
@@ -19,10 +19,11 @@ class DummyHttpResponse:
def __init__(self, path):
self.path = path
self.headers={}
+ self.log = ""
def _write_log(self, msg):
assert type(msg) is str
- self.log = msg
+ self.log = self.log + msg
class HTTPServer:
"""
@@ -33,20 +34,14 @@ class HTTPServer:
self.socket = socket.socket(self.address_family)
self.server_class = server_class
self.socket.bind(self.server_class)
- self.handler = handler_class(None, None, self)
+ self._handler = handler_class(None, None, self)
def handle_request(self):
pass
- def close(self):
+ def server_close(self):
self.socket.close()
- def _get_handler(self):
- return self.handler
-
- def _get_server_class(self):
- return self.server_class
-
class BaseHTTPRequestHandler:
"""
This module is a mock-up class of http.server.BaseHTTPRequestHandler
@@ -54,6 +49,7 @@ class BaseHTTPRequestHandler:
def __init__(self, request, client_address, server):
self.path = "/path/to"
+ self.headers = {}
self.server = server
self.response = DummyHttpResponse(path=self.path)
self.response.write = self._write
diff --git a/src/bin/stats/tests/socket.py b/src/bin/stats/tests/socket.py
index 8a82955..e6a4dd7 100644
--- a/src/bin/stats/tests/socket.py
+++ b/src/bin/stats/tests/socket.py
@@ -19,8 +19,8 @@ This module is a mock-up classes of socket module
import re
-AF_INET = 'IPV4_OK'
-AF_INET6 = 'IPV6_OK'
+AF_INET = 'AF_INET'
+AF_INET6 = 'AF_INET6'
_ADDRFAMILY = AF_INET
has_ipv6 = True
_CLOSED = False
@@ -54,10 +54,10 @@ class socket:
if self.address_family not in set([AF_INET, AF_INET6]):
raise error("Address family not supported by protocol: %s" % self.address_family)
if self.address_family == AF_INET6 and not has_ipv6:
- raise error("Address family not supported in this machine: %s ipv6: %s"
+ raise error("Address family not supported in this machine: %s has_ipv6: %s"
% (self.address_family, str(has_ipv6)))
if self.address_family == AF_INET and re.search(':', self.server_address) is not None:
- raise gaierror("Address family for hostname not supported : %s" % str(self.server_address))
+ raise gaierror("Address family for hostname not supported : %s %s" % (self.server_address, self.address_family))
if self.address_family == AF_INET6 and re.search(':', self.server_address) is None:
raise error("Cannot assign requested address : %s" % str(self.server_address))
if type(self.server_port) is not int:
More information about the bind10-changes
mailing list