1 # Unix SMB/CIFS implementation.
2 # Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2012
4 # Tests for documentation.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 """Tests for presence of documentation."""
28 import xml.etree.ElementTree as ET
30 class TestCase(samba.tests.TestCaseInTempDir):
32 def _format_message(self, parameters, message):
33 parameters = list(parameters)
34 parameters = map(str, parameters)
36 return message + '\n\n %s' % ('\n '.join(parameters))
39 def get_documented_parameters(sourcedir):
40 path = os.path.join(sourcedir, "bin", "default", "docs-xml", "smbdotconf")
41 if not os.path.exists(os.path.join(path, "parameters.all.xml")):
42 raise Exception("Unable to find parameters.all.xml")
44 p = open(os.path.join(path, "parameters.all.xml"), 'r')
46 raise Exception("Error opening parameters file")
49 root = ET.fromstring(out)
50 for parameter in root:
51 name = parameter.attrib.get('name')
52 if parameter.attrib.get('removed') == "1":
55 syn = parameter.findall('synonym')
62 def get_documented_tuples(sourcedir, omit_no_default=True):
63 path = os.path.join(sourcedir, "bin", "default", "docs-xml", "smbdotconf")
64 if not os.path.exists(os.path.join(path, "parameters.all.xml")):
65 raise Exception("Unable to find parameters.all.xml")
67 p = open(os.path.join(path, "parameters.all.xml"), 'r')
69 raise Exception("Error opening parameters file")
72 root = ET.fromstring(out)
73 for parameter in root:
74 name = parameter.attrib.get("name")
75 param_type = parameter.attrib.get("type")
76 if parameter.attrib.get('removed') == "1":
78 values = parameter.findall("value")
81 if value.attrib.get("type") == "default":
82 defaults.append(value)
85 if len(defaults) == 0:
88 elif len(defaults) > 1:
89 raise Exception("More than one default found for parameter %s" % name)
91 default_text = defaults[0].text
93 if default_text is None:
95 context = parameter.attrib.get("context")
96 yield name, default_text, context, param_type
99 class SmbDotConfTests(TestCase):
101 # defines the cases where the defaults may differ from the documentation
102 special_cases = set(['log level', 'path', 'ldapsam:trusted', 'spoolss: architecture',
103 'share:fake_fscaps', 'ldapsam:editposix', 'rpc_daemon:DAEMON',
104 'rpc_server:SERVER', 'panic action', 'homedir map', 'NIS homedir',
105 'server string', 'netbios name', 'socket options', 'use mmap',
106 'ctdbd socket', 'printing', 'printcap name', 'queueresume command',
107 'queuepause command','lpresume command', 'lppause command',
108 'lprm command', 'lpq command', 'print command', 'template homedir',
109 'spoolss: os_major', 'spoolss: os_minor', 'spoolss: os_build',
110 'max open files', 'fss: prune stale', 'fss: sequence timeout',
111 'include system krb5 conf', 'rpc server dynamic port range'])
114 super(SmbDotConfTests, self).setUp()
115 # create a minimal smb.conf file for testparm
116 self.smbconf = os.path.join(self.tempdir, "paramtestsmb.conf")
117 f = open(self.smbconf, 'w')
126 self.blankconf = os.path.join(self.tempdir, "emptytestsmb.conf")
127 f = open(self.blankconf, 'w')
133 self.topdir = os.path.abspath(samba.source_tree_topdir())
136 self.documented = set(get_documented_parameters(self.topdir))
138 self.fail("Unable to load documented parameters")
141 self.defaults = set(get_documented_tuples(self.topdir))
143 self.fail("Unable to load parameters")
146 self.defaults_all = set(get_documented_tuples(self.topdir, False))
148 self.fail("Unable to load parameters")
152 super(SmbDotConfTests, self).tearDown()
153 os.unlink(self.smbconf)
154 os.unlink(self.blankconf)
156 def test_default_s3(self):
157 self._test_default(['bin/testparm'])
158 self._set_defaults(['bin/testparm'])
160 # registry shares appears to need sudo
161 self._set_arbitrary(['bin/testparm'],
162 exceptions = ['client lanman auth',
163 'client plaintext auth',
166 'rpc server dynamic port range'])
167 self._test_empty(['bin/testparm'])
169 def test_default_s4(self):
170 self._test_default(['bin/samba-tool', 'testparm'])
171 self._set_defaults(['bin/samba-tool', 'testparm'])
172 self._set_arbitrary(['bin/samba-tool', 'testparm'],
173 exceptions = ['smb ports',
174 'rpc server dynamic port range'])
175 self._test_empty(['bin/samba-tool', 'testparm'])
177 def _test_default(self, program):
181 for tuples in self.defaults:
182 param, default, context, param_type = tuples
184 if param in self.special_cases:
192 self.fail("%s has no valid context" % param)
193 p = subprocess.Popen(program + ["-s", self.smbconf,
194 "--section-name", section, "--parameter-name", param],
195 stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=self.topdir).communicate()
196 if p[0].upper().strip() != default.upper():
197 if not (p[0].upper().strip() == "" and default == '""'):
198 doc_triple = "%s\n Expected: %s" % (param, default)
199 failset.add("%s\n Got: %s" % (doc_triple, p[0].upper().strip()))
202 self.fail(self._format_message(failset,
203 "Parameters that do not have matching defaults:"))
205 def _set_defaults(self, program):
209 for tuples in self.defaults:
210 param, default, context, param_type = tuples
212 if param in ['printing', 'rpc server dynamic port range']:
221 self.fail("%s has no valid context" % param)
222 p = subprocess.Popen(program + ["-s", self.smbconf,
223 "--section-name", section, "--parameter-name", param,
224 "--option", "%s = %s" % (param, default)],
225 stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=self.topdir).communicate()
226 if p[0].upper().strip() != default.upper():
227 if not (p[0].upper().strip() == "" and default == '""'):
228 doc_triple = "%s\n Expected: %s" % (param, default)
229 failset.add("%s\n Got: %s" % (doc_triple, p[0].upper().strip()))
232 self.fail(self._format_message(failset,
233 "Parameters that do not have matching defaults:"))
235 def _set_arbitrary(self, program, exceptions=None):
236 arbitrary = {'string': 'string', 'boolean': 'yes', 'integer': '5',
237 'boolean-rev': 'yes',
241 'ustring': 'ustring',
242 'enum':'', 'boolean-auto': '', 'char': 'a', 'list': 'a, b, c'}
243 opposite_arbitrary = {'string': 'string2', 'boolean': 'no', 'integer': '6',
248 'ustring': 'ustring2',
249 'enum':'', 'boolean-auto': '', 'char': 'b', 'list': 'd, e, f'}
254 for tuples in self.defaults_all:
255 param, default, context, param_type = tuples
257 if param in ['printing', 'copy', 'include', 'log level']:
260 # currently no easy way to set an arbitrary value for these
261 if param_type in ['enum', 'boolean-auto']:
264 if exceptions is not None:
265 if param in exceptions:
274 self.fail("%s has no valid context" % param)
276 value_to_use = arbitrary.get(param_type)
277 if value_to_use is None:
278 self.fail("%s has an invalid type" % param)
280 p = subprocess.Popen(program + ["-s", self.smbconf,
281 "--section-name", section, "--parameter-name", param,
282 "--option", "%s = %s" % (param, value_to_use)],
283 stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=self.topdir).communicate()
284 if p[0].upper().strip() != value_to_use.upper():
285 # currently no way to distinguish command lists
286 if param_type == 'list':
287 if ", ".join(p[0].upper().strip().split()) == value_to_use.upper():
290 # currently no way to identify octal
291 if param_type == 'integer':
293 if int(value_to_use, 8) == int(p[0].strip(), 8):
298 doc_triple = "%s\n Expected: %s" % (param, value_to_use)
299 failset.add("%s\n Got: %s" % (doc_triple, p[0].upper().strip()))
301 opposite_value = opposite_arbitrary.get(param_type)
302 tempconf = os.path.join(self.tempdir, "tempsmb.conf")
303 g = open(tempconf, 'w')
305 towrite = section + "\n"
306 towrite += param + " = " + opposite_value
311 p = subprocess.Popen(program + ["-s", tempconf, "--suppress-prompt",
312 "--option", "%s = %s" % (param, value_to_use)],
313 stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=self.topdir).communicate()
317 # testparm doesn't display a value if they are equivalent
318 if (value_to_use.lower() != opposite_value.lower()):
319 for line in p[0].splitlines():
320 if not line.strip().startswith(param):
323 value_found = line.split("=")[1].upper().strip()
324 if value_found != value_to_use.upper():
325 # currently no way to distinguish command lists
326 if param_type == 'list':
327 if ", ".join(value_found.split()) == value_to_use.upper():
330 # currently no way to identify octal
331 if param_type == 'integer':
333 if int(value_to_use, 8) == int(value_found, 8):
338 doc_triple = "%s\n Expected: %s" % (param, value_to_use)
339 failset.add("%s\n Got: %s" % (doc_triple, value_found))
343 self.fail(self._format_message(failset,
344 "Parameters that were unexpectedly not set:"))
346 def _test_empty(self, program):
347 p = subprocess.Popen(program + ["-s", self.blankconf, "--suppress-prompt"],
348 stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=self.topdir).communicate()
351 for line in p[0].splitlines():
352 if line.strip().startswith('#'):
354 if line.strip().startswith("idmap config *"):
356 output += line.strip().lower() + '\n'
358 if output.strip() != '[global]' and output.strip() != '[globals]':
359 self.fail("Testparm returned unexpected output on an empty smb.conf.")