From fca80dccf86d00b3dfe42f35b78b0538e3cd1c0e Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Tue, 24 Dec 2013 15:33:42 +1300 Subject: [PATCH] selftest: updated docs.py script The script now checks the parameter defaults against the documentation by using the output of testparm and samba-tool testparm. It now also uses the ElementTree xml library. Change-Id: I2657c8c56a8c8383735e659dc9f636b4c5ab460b Signed-off-by: Garming Sam Signed-off-by: Andrew Bartlett Reviewed-by: Michael Adam Autobuild-User(master): Michael Adam Autobuild-Date(master): Fri Jan 31 23:22:09 CET 2014 on sn-devel-104 --- python/samba/tests/docs.py | 155 ++++++++++++++++++++++++++++--------- 1 file changed, 118 insertions(+), 37 deletions(-) diff --git a/python/samba/tests/docs.py b/python/samba/tests/docs.py index c1b371680d7..afa9fdd2246 100644 --- a/python/samba/tests/docs.py +++ b/python/samba/tests/docs.py @@ -21,54 +21,42 @@ import samba import samba.tests -from samba.tests import TestSkipped +from samba.tests import TestSkipped, TestCaseInTempDir import errno import os import re import subprocess +import xml.etree.ElementTree as ET - -class TestCase(samba.tests.TestCase): +class TestCase(samba.tests.TestCaseInTempDir): def _format_message(self, parameters, message): parameters = list(parameters) parameters.sort() return message + '\n\n %s' % ('\n '.join(parameters)) - -class NoXsltProc(Exception): - - def __init__(self): - Exception.__init__(self, "'xsltproc' is not installed") - - def get_documented_parameters(sourcedir): path = os.path.join(sourcedir, "bin", "default", "docs-xml", "smbdotconf") if not os.path.exists(os.path.join(path, "parameters.all.xml")): raise Exception("Unable to find parameters.all.xml") try: - p = subprocess.Popen( - ["xsltproc", "--xinclude", "--param", "smb.context", "ALL", os.path.join(sourcedir, "docs-xml", "smbdotconf", "generate-context.xsl"), "parameters.all.xml"], - stderr=subprocess.STDOUT, stdout=subprocess.PIPE, - cwd=path) - except OSError, e: - if e.errno == errno.ENOENT: - raise NoXsltProc() - raise - out, err = p.communicate() - assert p.returncode == 0, "returncode was %r" % p.returncode - for l in out.splitlines(): - m = re.match('(.*).*', l) - if m: - name = m.group(1) - yield name + p = open(os.path.join(path, "parameters.all.xml"), 'r') + except IOError, e: + raise Exception("Error opening parameters file") + out = p.read() + + root = ET.fromstring(out) + for parameter in root: + name = parameter.attrib.get('name') + if parameter.attrib.get('removed') == "1": + continue + yield name + syn = parameter.findall('synonym') + if syn is not None: + for sy in syn: + yield sy.text + p.close() def get_implementation_parameters(sourcedir): @@ -96,15 +84,69 @@ def get_implementation_parameters(sourcedir): finally: f.close() +def get_default_triples(sourcedir): + path = os.path.join(sourcedir, "bin", "default", "docs-xml", "smbdotconf") + if not os.path.exists(os.path.join(path, "parameters.all.xml")): + raise Exception("Unable to find parameters.all.xml") + try: + p = open(os.path.join(path, "parameters.all.xml"), 'r') + except IOError, e: + raise Exception("Error opening parameters file") + out = p.read() + + root = ET.fromstring(out) + for parameter in root: + name = parameter.attrib.get("name") + values = parameter.findall("value") + defaults = [] + for value in values: + if value.attrib.get("type") == "default": + defaults.append(value) + if len(defaults) == 0: + continue + elif len(defaults) > 1: + raise Exception("More than one default found for parameter %s" % name) + default_text = defaults[0].text + if default_text is None: + default_text = "" + context = parameter.attrib.get("context") + yield name, default_text, context + p.close() class SmbDotConfTests(TestCase): + # defines the cases where the defaults may differ from the documentation + special_cases = set(['log level', 'path', 'ldapsam:trusted', 'spoolss: architecture', + 'share:fake_fscaps', 'ldapsam:editposix', 'rpc_daemon:DAEMON', + 'rpc_server:SERVER', 'panic action', 'homedir map', 'NIS homedir', + 'server string', 'netbios name', 'socket options', 'use mmap', + 'ctdbd socket', 'printing', 'printcap name', 'queueresume command', + 'queuepause command','lpresume command', 'lppause command', + 'lprm command', 'lpq command', 'print command', 'template homedir']) + + def setUp(self): + super(SmbDotConfTests, self).setUp() + # create a minimal smb.conf file for testparm + self.smbconf = os.path.join(self.tempdir, "paramtestsmb.conf") + f = open(self.smbconf, 'w') + try: + f.write(""" +[test] + path = / +""") + finally: + f.close() + + def tearDown(self): + super(SmbDotConfTests, self).tearDown() + os.unlink(self.smbconf) + def test_unknown(self): - topdir = samba.source_tree_topdir() + topdir = os.path.abspath(samba.source_tree_topdir()) try: documented = set(get_documented_parameters(topdir)) - except NoXsltProc: - raise TestSkipped("'xsltproc' is missing, unable to load parameters") + except e: + self.fail("Unable to load parameters") parameters = set(get_implementation_parameters(topdir)) # Filter out parametric options, since we can't find them in the parm # table @@ -115,13 +157,52 @@ class SmbDotConfTests(TestCase): "Parameters that are documented but not in the implementation:")) def test_undocumented(self): - topdir = samba.source_tree_topdir() + topdir = os.path.abspath(samba.source_tree_topdir()) try: documented = set(get_documented_parameters(topdir)) - except NoXsltProc: - raise TestSkipped("'xsltproc' is missing, unable to load parameters") + except: + self.fail("Unable to load parameters") parameters = set(get_implementation_parameters(topdir)) undocumented = parameters.difference(documented) if len(undocumented) > 0: self.fail(self._format_message(undocumented, "Parameters that are in the implementation but undocumented:")) + + def test_default_s3(self): + self._test_default(['bin/testparm']) + + def test_default_s4(self): + self._test_default(['bin/samba-tool', 'testparm']) + + def _test_default(self, program): + topdir = os.path.abspath(samba.source_tree_topdir()) + try: + defaults = set(get_default_triples(topdir)) + except: + self.fail("Unable to load parameters") + bindir = os.path.join(topdir, "bin") + failset = set() + count = 0 + + for triple in defaults: + param, default, context = triple + if param in self.special_cases: + continue + section = None + if context == "G": + section = "global" + elif context == "S": + section = "test" + else: + self.fail("%s has no valid context" % param) + p = subprocess.Popen(program + ["-s", self.smbconf, + "--section-name", section, "--parameter-name", param], + stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=topdir).communicate() + if p[0].upper().strip() != default.upper(): + if not (p[0].upper().strip() == "" and default == '""'): + doc_triple = "%s\n Expected: %s" % (param, default) + failset.add("%s\n Got: %s" % (doc_triple, p[0].upper().strip())) + + if len(failset) > 0: + self.fail(self._format_message(failset, + "Parameters that do not have matching defaults:"))