Commit 8f5429e4 authored by Jeremy C. Reed's avatar Jeremy C. Reed
Browse files

Merge branch 'master' into trac1341

parents 52fa244c 24c2111e
320. [func]* vorner
The --brittle switch was removed from the bind10 executable. It didn't
work after the #213 change and the same effect can be accomplished by
declaring all components as core.
(Trac #1340, git f9224368908dd7ba16875b0d36329cf1161193f0)
319. [func] naokikambe
b10-stats-httpd was updated. In addition of the access to all
statistics items of all modules, the specified item or the items of the
specified module name can be accessed. For example, the URI requested
by using the feature is showed as "/bind10/statistics/xml/Auth" or
"/bind10/statistics/xml/Auth/queries.tcp". The list of all possible
module names and all possible item names can be showed in the root
document, whose URI is "/bind10/statistics/xml". This change is not
only for the XML documents but also is for the XSD and XSL documents.
(Trac #917, git b34bf286c064d44746ec0b79e38a6177d01e6956)
318. [func] stephen
Add C++ API for accessing zone difference information in database-based
data sources.
(Trac #1330, git 78770f52c7f1e7268d99e8bfa8c61e889813bb33)
317. [func] vorner
datasrc: the getUpdater method of DataSourceClient supports an optional
'journaling' parameter to indicate the generated updater to store diffs.
The database based derived class implements this extension.
(Trac #1331, git 713160c9bed3d991a00b2ea5e7e3e7714d79625d)
316. [func]* vorner
The configuration of what parts of the system run is more flexible now.
Everything that should run must have an entry in Boss/components.
......@@ -484,7 +512,7 @@ bind10-devel-20110705 released on July 05, 2011
(Trac #542, git 1aa773d84cd6431aa1483eb34a7f4204949a610f)
243. [func]* feng
Add optional hmac algorithm SHA224/384/812.
Add optional hmac algorithm SHA224/384/512.
(Trac #782, git 77d792c9d7c1a3f95d3e6a8b721ac79002cd7db1)
bind10-devel-20110519 released on May 19, 2011
......
......@@ -51,7 +51,6 @@
<arg><option>-u <replaceable>user</replaceable></option></arg>
<arg><option>-v</option></arg>
<arg><option>-w <replaceable>wait_time</replaceable></option></arg>
<arg><option>--brittle</option></arg>
<arg><option>--cmdctl-port</option> <replaceable>port</replaceable></arg>
<arg><option>--config-file</option> <replaceable>config-filename</replaceable></arg>
<arg><option>--data-path</option> <replaceable>directory</replaceable></arg>
......@@ -90,20 +89,6 @@
<variablelist>
<varlistentry>
<term>
<option>--brittle</option>
</term>
<listitem>
<para>
Shutdown if any of the child processes of
<command>bind10</command> exit. This is intended to
help developers debug the server, and should not be
used in production.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-c</option> <replaceable>config-filename</replaceable>,
......
......@@ -219,7 +219,7 @@ class BoB:
def __init__(self, msgq_socket_file=None, data_path=None,
config_filename=None, nocache=False, verbose=False, setuid=None,
username=None, cmdctl_port=None, brittle=False, wait_time=10):
username=None, cmdctl_port=None, wait_time=10):
"""
Initialize the Boss of BIND. This is a singleton (only one can run).
......@@ -233,9 +233,6 @@ class BoB:
The cmdctl_port is passed to cmdctl and specify on which port it
should listen.
brittle is a debug option that controls whether the Boss shuts down
after any process dies.
wait_time controls the amount of time (in seconds) that Boss waits
for selected processes to initialize before continuing with the
initialization. Currently this is only the configuration manager.
......@@ -264,7 +261,6 @@ class BoB:
self.data_path = data_path
self.config_filename = config_filename
self.cmdctl_port = cmdctl_port
self.brittle = brittle
self.wait_time = wait_time
self._component_configurator = isc.bind10.component.Configurator(self,
isc.bind10.special_component.get_specials())
......@@ -628,21 +624,10 @@ class BoB:
# ... and start
return self.start_process("b10-resolver", resargs, self.c_channel_env)
def start_cmdctl(self):
"""
Starts the command control process
"""
args = ["b10-cmdctl"]
if self.cmdctl_port is not None:
args.append("--port=" + str(self.cmdctl_port))
if self.verbose:
args.append("-v")
return self.start_process("b10-cmdctl", args, self.c_channel_env,
self.cmdctl_port)
def start_xfrin(self):
# XXX: a quick-hack workaround. xfrin will implicitly use dynamically
# loadable data source modules, which will be installed in $(libdir).
def __ld_path_hack(self):
# XXX: a quick-hack workaround. xfrin/out will implicitly use
# dynamically loadable data source modules, which will be installed in
# $(libdir).
# On some OSes (including MacOS X and *BSDs) the main process (python)
# cannot find the modules unless they are located in a common shared
# object path or a path in the (DY)LD_LIBRARY_PATH. We should seek
......@@ -655,21 +640,44 @@ class BoB:
# the same as for the libexec path addition
# TODO: Once #1292 is finished, remove this method and the special
# component, use it as normal component.
c_channel_env = dict(self.c_channel_env)
env = dict(self.c_channel_env)
if ADD_LIBEXEC_PATH:
cur_path = os.getenv('DYLD_LIBRARY_PATH')
cur_path = '' if cur_path is None else ':' + cur_path
c_channel_env['DYLD_LIBRARY_PATH'] = "@@LIBDIR@@" + cur_path
env['DYLD_LIBRARY_PATH'] = "@@LIBDIR@@" + cur_path
cur_path = os.getenv('LD_LIBRARY_PATH')
cur_path = '' if cur_path is None else ':' + cur_path
c_channel_env['LD_LIBRARY_PATH'] = "@@LIBDIR@@" + cur_path
env['LD_LIBRARY_PATH'] = "@@LIBDIR@@" + cur_path
return env
def start_cmdctl(self):
"""
Starts the command control process
"""
args = ["b10-cmdctl"]
if self.cmdctl_port is not None:
args.append("--port=" + str(self.cmdctl_port))
if self.verbose:
args.append("-v")
return self.start_process("b10-cmdctl", args, self.c_channel_env,
self.cmdctl_port)
def start_xfrin(self):
# Set up the command arguments.
args = ['b10-xfrin']
if self.verbose:
args += ['-v']
return self.start_process("b10-xfrin", args, c_channel_env)
return self.start_process("b10-xfrin", args, self.__ld_path_hack())
def start_xfrout(self):
# Set up the command arguments.
args = ['b10-xfrout']
if self.verbose:
args += ['-v']
return self.start_process("b10-xfrout", args, self.__ld_path_hack())
def start_all_components(self):
"""
......@@ -928,8 +936,6 @@ def parse_args(args=sys.argv[1:], Parser=OptionParser):
parser.add_option("--pid-file", dest="pid_file", type="string",
default=None,
help="file to dump the PID of the BIND 10 process")
parser.add_option("--brittle", dest="brittle", action="store_true",
help="debugging flag: exit if any component dies")
parser.add_option("-w", "--wait", dest="wait_time", type="int",
default=10, help="Time (in seconds) to wait for config manager to start up")
......@@ -1034,7 +1040,7 @@ def main():
# Go bob!
boss_of_bind = BoB(options.msgq_socket_file, options.data_path,
options.config_file, options.nocache, options.verbose,
setuid, username, options.cmdctl_port, options.brittle,
setuid, username, options.cmdctl_port,
options.wait_time)
startup_result = boss_of_bind.startup()
if startup_result:
......
......@@ -15,7 +15,7 @@
"kind": "dispensable"
},
"b10-xfrin": { "special": "xfrin", "kind": "dispensable" },
"b10-xfrout": { "address": "Xfrout", "kind": "dispensable" },
"b10-xfrout": { "special": "xfrout", "kind": "dispensable" },
"b10-zonemgr": { "address": "Zonemgr", "kind": "dispensable" },
"b10-stats": { "address": "Stats", "kind": "dispensable" },
"b10-stats-httpd": {
......
......@@ -274,8 +274,7 @@ class MockBob(BoB):
return procinfo
def start_simple(self, name):
procmap = { 'b10-xfrout': self.start_xfrout,
'b10-zonemgr': self.start_zonemgr,
procmap = { 'b10-zonemgr': self.start_zonemgr,
'b10-stats': self.start_stats,
'b10-stats-httpd': self.start_stats_httpd,
'b10-cmdctl': self.start_cmdctl,
......@@ -475,7 +474,7 @@ class TestStartStopProcessesBob(unittest.TestCase):
if start_auth:
config['b10-auth'] = { 'kind': 'needed', 'special': 'auth' }
config['b10-xfrout'] = { 'kind': 'dispensable',
'address': 'Xfrout' }
'special': 'xfrout' }
config['b10-xfrin'] = { 'kind': 'dispensable', 'special': 'xfrin' }
config['b10-zonemgr'] = { 'kind': 'dispensable',
'address': 'Zonemgr' }
......@@ -741,15 +740,6 @@ class TestParseArgs(unittest.TestCase):
options = parse_args(['--cmdctl-port=1234'], TestOptParser)
self.assertEqual(1234, options.cmdctl_port)
def test_brittle(self):
"""
Test we can use the "brittle" flag.
"""
options = parse_args([], TestOptParser)
self.assertFalse(options.brittle)
options = parse_args(['--brittle'], TestOptParser)
self.assertTrue(options.brittle)
class TestPIDFile(unittest.TestCase):
def setUp(self):
self.pid_file = '@builddir@' + os.sep + 'bind10.pid'
......@@ -797,37 +787,6 @@ class TestPIDFile(unittest.TestCase):
self.assertRaises(IOError, dump_pid,
'nonexistent_dir' + os.sep + 'bind10.pid')
# TODO: Do we want brittle mode? Probably yes. So we need to re-enable to after that.
@unittest.skip("Brittle mode temporarily broken")
class TestBrittle(unittest.TestCase):
def test_brittle_disabled(self):
bob = MockBob()
bob.start_all_components()
bob.runnable = True
bob.reap_children()
self.assertTrue(bob.runnable)
def simulated_exit(self):
ret_val = self.exit_info
self.exit_info = (0, 0)
return ret_val
def test_brittle_enabled(self):
bob = MockBob()
bob.start_all_components()
bob.runnable = True
bob.brittle = True
self.exit_info = (5, 0)
bob._get_process_exit_status = self.simulated_exit
old_stdout = sys.stdout
sys.stdout = open("/dev/null", "w")
bob.reap_children()
sys.stdout = old_stdout
self.assertFalse(bob.runnable)
class TestBossComponents(unittest.TestCase):
"""
Test the boss propagates component configuration properly to the
......
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="$xsl_url_path"?>
<!--
- Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- PERFORMANCE OF THIS SOFTWARE.
-->
<stats:stats_data version="1.0"
xmlns:stats="$xsd_namespace"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="$xsd_namespace $xsd_url_path">
$xml_string
</stats:stats_data>
$xml_string
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- PERFORMANCE OF THIS SOFTWARE.
-->
<schema targetNamespace="$xsd_namespace"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:stats="$xsd_namespace">
<annotation>
<documentation xml:lang="en">XML schema of the statistics
data in BIND 10</documentation>
</annotation>
<element name="stats_data">
<annotation>
<documentation>A set of statistics data</documentation>
</annotation>
<complexType>
$xsd_string
<attribute name="version" type="token" use="optional" default="1.0">
<annotation>
<documentation>Version number of syntax</documentation>
</annotation>
</attribute>
</complexType>
</element>
</schema>
$xsd_string
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- PERFORMANCE OF THIS SOFTWARE.
-->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml"
xmlns:stats="$xsd_namespace">
xmlns:bind10="$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 " />
......@@ -42,14 +26,7 @@ td.title {
</head>
<body>
<h1>BIND 10 Statistics</h1>
<table>
<tr>
<th>Owner</th>
<th>Title</th>
<th>Value</th>
</tr>
<xsl:apply-templates />
</table>
<xsl:apply-templates />
</body>
</html>
</xsl:template>
......
......@@ -246,12 +246,12 @@ class Stats:
self.update_statistics_data()
if owner and name:
try:
return self.statistics_data[owner][name]
return {owner:{name:self.statistics_data[owner][name]}}
except KeyError:
pass
elif owner:
try:
return self.statistics_data[owner]
return {owner: self.statistics_data[owner]}
except KeyError:
pass
elif name:
......@@ -360,9 +360,9 @@ class Stats:
if owner:
try:
if name:
return isc.config.create_answer(0, schema_byname[owner][name])
return isc.config.create_answer(0, {owner:[schema_byname[owner][name]]})
else:
return isc.config.create_answer(0, schema[owner])
return isc.config.create_answer(0, {owner:schema[owner]})
except KeyError:
pass
else:
......
This diff is collapsed.
......@@ -55,6 +55,12 @@ response will be sent back, and the specific error is printed. This
is an error condition that likely points to a module that is not
responding correctly to statistic requests.
% STATHTTPD_SERVER_DATAERROR HTTP server data error: %1
An internal error occurred while handling an HTTP request. An HTTP 404
response will be sent back, and the specific error is printed. This
is an error condition that likely points the specified data
corresponding to the requested URI is incorrect.
% STATHTTPD_SERVER_INIT_ERROR HTTP server initialization error: %1
There was a problem initializing the HTTP server in the stats-httpd
module upon receiving its configuration data. The most likely cause
......
PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
PYTESTS = b10-stats_test.py b10-stats-httpd_test.py
EXTRA_DIST = $(PYTESTS) test_utils.py
CLEANFILES = test_utils.pyc msgq_socket_test
CLEANFILES = test_utils.pyc
# If necessary (rare cases), explicitly specify paths to dynamic libraries
# required by loadable python modules.
......
This diff is collapsed.
......@@ -226,7 +226,7 @@ class TestStats(unittest.TestCase):
'show', 'Stats',
params={ 'owner' : 'Boss',
'name' : 'boot_time' }),
(0, self.const_datetime))
(0, {'Boss': {'boot_time': self.const_datetime}}))
self.assertEqual(
send_command(
'set', 'Stats',
......@@ -238,7 +238,7 @@ class TestStats(unittest.TestCase):
'show', 'Stats',
params={ 'owner' : 'Boss',
'name' : 'boot_time' }),
(0, self.const_datetime))
(0, {'Boss': {'boot_time': self.const_datetime}}))
self.assertEqual(
send_command('status', 'Stats'),
(0, "Stats is up. (PID " + str(os.getpid()) + ")"))
......@@ -321,25 +321,25 @@ class TestStats(unittest.TestCase):
my_statistics_data = self.stats.get_statistics_data()
self.assertTrue('Stats' in my_statistics_data)
self.assertTrue('Boss' in my_statistics_data)
self.assertTrue('boot_time' in my_statistics_data['Boss'])
my_statistics_data = self.stats.get_statistics_data(owner='Stats')
self.assertTrue('report_time' in my_statistics_data)
self.assertTrue('boot_time' in my_statistics_data)
self.assertTrue('last_update_time' in my_statistics_data)
self.assertTrue('timestamp' in my_statistics_data)
self.assertTrue('lname' in my_statistics_data)
self.assertTrue('Stats' in my_statistics_data)
self.assertTrue('report_time' in my_statistics_data['Stats'])
self.assertTrue('boot_time' in my_statistics_data['Stats'])
self.assertTrue('last_update_time' in my_statistics_data['Stats'])
self.assertTrue('timestamp' in my_statistics_data['Stats'])
self.assertTrue('lname' in my_statistics_data['Stats'])
self.assertRaises(stats.StatsError, self.stats.get_statistics_data, owner='Foo')
my_statistics_data = self.stats.get_statistics_data(owner='Stats')
self.assertTrue('boot_time' in my_statistics_data)
my_statistics_data = self.stats.get_statistics_data(owner='Stats', name='report_time')
self.assertEqual(my_statistics_data, self.const_default_datetime)
self.assertEqual(my_statistics_data['Stats']['report_time'], self.const_default_datetime)
my_statistics_data = self.stats.get_statistics_data(owner='Stats', name='boot_time')
self.assertEqual(my_statistics_data, self.const_default_datetime)
self.assertEqual(my_statistics_data['Stats']['boot_time'], self.const_default_datetime)
my_statistics_data = self.stats.get_statistics_data(owner='Stats', name='last_update_time')
self.assertEqual(my_statistics_data, self.const_default_datetime)
self.assertEqual(my_statistics_data['Stats']['last_update_time'], self.const_default_datetime)
my_statistics_data = self.stats.get_statistics_data(owner='Stats', name='timestamp')
self.assertEqual(my_statistics_data, 0.0)
self.assertEqual(my_statistics_data['Stats']['timestamp'], 0.0)
my_statistics_data = self.stats.get_statistics_data(owner='Stats', name='lname')
self.assertEqual(my_statistics_data, '')
self.assertEqual(my_statistics_data, {'Stats': {'lname':''}})
self.assertRaises(stats.StatsError, self.stats.get_statistics_data,
owner='Stats', name='Bar')
self.assertRaises(stats.StatsError, self.stats.get_statistics_data,
......@@ -385,10 +385,25 @@ class TestStats(unittest.TestCase):
1, "specified arguments are incorrect: owner: Foo, name: bar"))
self.assertEqual(self.stats.command_show(owner='Auth'),
isc.config.create_answer(
0, {'queries.tcp': 0, 'queries.udp': 0}))
0, {'Auth':{ 'queries.udp': 0,
'queries.tcp': 0,
'queries.perzone': [{ 'zonename': 'test1.example',
'queries.udp': 1,
'queries.tcp': 2 },
{ 'zonename': 'test2.example',
'queries.udp': 3,
'queries.tcp': 4 }] }}))
self.assertEqual(self.stats.command_show(owner='Auth', name='queries.udp'),
isc.config.create_answer(
0, 0))
0, {'Auth': {'queries.udp':0}}))
self.assertEqual(self.stats.command_show(owner='Auth', name='queries.perzone'),
isc.config.create_answer(
0, {'Auth': {'queries.perzone': [{ 'zonename': 'test1.example',
'queries.udp': 1,
'queries.tcp': 2 },
{ 'zonename': 'test2.example',
'queries.udp': 3,
'queries.tcp': 4 }]}}))
orig_get_timestamp = stats.get_timestamp
orig_get_datetime = stats.get_datetime
stats.get_timestamp = lambda : self.const_timestamp
......@@ -396,7 +411,7 @@ class TestStats(unittest.TestCase):
self.assertEqual(stats.get_timestamp(), self.const_timestamp)
self.assertEqual(stats.get_datetime(), self.const_datetime)
self.assertEqual(self.stats.command_show(owner='Stats', name='report_time'), \
isc.config.create_answer(0, self.const_datetime))
isc.config.create_answer(0, {'Stats': {'report_time':self.const_datetime}}))
self.assertEqual(self.stats.statistics_data['Stats']['timestamp'], self.const_timestamp)
self.assertEqual(self.stats.statistics_data['Stats']['boot_time'], self.const_default_datetime)
stats.get_timestamp = orig_get_timestamp
......@@ -442,9 +457,12 @@ class TestStats(unittest.TestCase):
self.assertTrue('item_format' in item)
schema = value['Auth']
self.assertEqual(len(schema), 2)
self.assertEqual(len(schema), 3)
for item in schema:
self.assertTrue(len(item) == 6)
if item['item_type'] == 'list':
self.assertEqual(len(item), 7)
else:
self.assertEqual(len(item), 6)
self.assertTrue('item_name' in item)
self.assertTrue('item_type' in item)
self.assertTrue('item_optional' in item)
......@@ -455,10 +473,10 @@ class TestStats(unittest.TestCase):
(rcode, value) = isc.config.ccsession.parse_answer(
self.stats.command_showschema(owner='Stats'))
self.assertEqual(rcode, 0)
self.assertFalse('Stats' in value)
self.assertTrue('Stats' in value)
self.assertFalse('Boss' in value)
self.assertFalse('Auth' in value)
for item in value:
for item in value['Stats']:
self.assertTrue(len(item) == 6 or len(item) == 7)
self.assertTrue('item_name' in item)
self.assertTrue('item_type' in item)
......@@ -472,19 +490,19 @@ class TestStats(unittest.TestCase):
(rcode, value) = isc.config.ccsession.parse_answer(
self.stats.command_showschema(owner='Stats', name='report_time'))
self.assertEqual(rcode, 0)
self.assertFalse('Stats' in value)
self.assertTrue('Stats' in value)
self.assertFalse('Boss' in value)
self.assertFalse('Auth' in value)
self.assertTrue(len(value) == 7)
self.assertTrue('item_name' in value)
self.assertTrue('item_type' in value)
self.assertTrue('item_optional' in value)
self.assertTrue('item_default' in value)
self.assertTrue('item_title' in value)
self.assertTrue('item_description' in value)
self.assertTrue('item_format' in value)
self.assertEqual(value['item_name'], 'report_time')
self.assertEqual(value['item_format'], 'date-time')
self.assertEqual(len(value['Stats'][0]), 7)
self.assertTrue('item_name' in value['Stats'][0])
self.assertTrue('item_type' in value['Stats'][0])
self.assertTrue('item_optional' in value['Stats'][0])
self.assertTrue('item_default' in value['Stats'][0])
self.assertTrue('item_title' in value['Stats'][0])
self.assertTrue('item_description' in value['Stats'][0])
self.assertTrue('item_format' in value['Stats'][0])
self.assertEqual(value['Stats'][0]['item_name'], 'report_time')
self.assertEqual(value['Stats'][0]['item_format'], 'date-time')
self.assertEqual(self.stats.command_showschema(owner='Foo'),
isc.config.create_answer(
......@@ -494,7 +512,7 @@ class TestStats(unittest.TestCase):
1, "specified arguments are incorrect: owner: Foo, name: bar"))
self.assertEqual(self.stats.command_showschema(owner='Auth'),
isc.config.create_answer(
0, [{
0, {'Auth': [{
"item_default": 0,
"item_description": "A number of total query counts which all auth servers receive over TCP since they started initially",
"item_name": "queries.tcp",
......@@ -509,17 +527,121 @@ class TestStats(unittest.TestCase):
"item_optional": False,
"item_title": "Queries UDP",
"item_type": "integer"
}]))
},
{
"item_name": "queries.perzone",
"item_type": "list",
"item_optional": False,
"item_default": [
{
"zonename" : "test1.example",
"queries.udp" : 1,
"queries.tcp" : 2
},
{
"zonename" : "test2.example",
"queries.udp" : 3,
"queries.tcp" : 4
}
],
"item_title": "Queries per zone",
"item_description": "Queries per zone",
"list_item_spec": {
"item_name": "zones",