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."""
27 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 = list(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
100 class SmbDotConfTests(TestCase):
102 # defines the cases where the defaults may differ from the documentation
103 special_cases = set([
116 'queueresume command',
117 'queuepause command',
125 'include system krb5 conf',
126 'rpc server dynamic port range',
131 super(SmbDotConfTests, self).setUp()
132 # create a minimal smb.conf file for testparm
133 self.smbconf = os.path.join(self.tempdir, "paramtestsmb.conf")
134 f = open(self.smbconf, 'w')
143 self.blankconf = os.path.join(self.tempdir, "emptytestsmb.conf")
144 f = open(self.blankconf, 'w')
150 self.topdir = os.path.abspath(samba.source_tree_topdir())
153 self.documented = set(get_documented_parameters(self.topdir))
155 self.fail("Unable to load documented parameters")
158 self.defaults = set(get_documented_tuples(self.topdir))
160 self.fail("Unable to load parameters")
163 self.defaults_all = set(get_documented_tuples(self.topdir, False))
165 self.fail("Unable to load parameters")
168 super(SmbDotConfTests, self).tearDown()
169 os.unlink(self.smbconf)
170 os.unlink(self.blankconf)
172 def test_default_s3(self):
173 self._test_default(['bin/testparm'])
174 self._set_defaults(['bin/testparm'])
176 # registry shares appears to need sudo
177 self._set_arbitrary(['bin/testparm'],
178 exceptions = ['client lanman auth',
179 'client plaintext auth',
182 'rpc server dynamic port range',
183 'name resolve order',
185 self._test_empty(['bin/testparm'])
187 def test_default_s4(self):
188 self._test_default(['bin/samba-tool', 'testparm'])
189 self._set_defaults(['bin/samba-tool', 'testparm'])
190 self._set_arbitrary(['bin/samba-tool', 'testparm'],
191 exceptions=['smb ports',
192 'rpc server dynamic port range',
193 'name resolve order'])
194 self._test_empty(['bin/samba-tool', 'testparm'])
196 def _test_default(self, program):
198 if program[0] == 'bin/samba-tool' and os.getenv("PYTHON", None):
199 program = [os.environ["PYTHON"]] + program
203 for tuples in self.defaults:
204 param, default, context, param_type = tuples
206 if param in self.special_cases:
208 # bad, bad parametric options - we don't have their default values
217 self.fail("%s has no valid context" % param)
218 p = subprocess.Popen(program + ["-s",
224 stdout=subprocess.PIPE,
225 stderr=subprocess.PIPE,
226 cwd=self.topdir).communicate()
227 result = p[0].decode().upper().strip()
228 if result != default.upper():
229 if not (result == "" and default == '""'):
230 doc_triple = "%s\n Expected: %s" % (param, default)
231 failset.add("%s\n Got: %s" % (doc_triple, result))
234 self.fail(self._format_message(failset,
235 "Parameters that do not have matching defaults:"))
237 def _set_defaults(self, program):
239 if program[0] == 'bin/samba-tool' and os.getenv("PYTHON", None):
240 program = [os.environ["PYTHON"]] + program
244 for tuples in self.defaults:
245 param, default, context, param_type = tuples
247 if param in ['printing', 'rpc server dynamic port range']:
256 self.fail("%s has no valid context" % param)
257 p = subprocess.Popen(program + ["-s",
264 "%s = %s" % (param, default)],
265 stdout=subprocess.PIPE,
266 stderr=subprocess.PIPE,
267 cwd=self.topdir).communicate()
268 result = p[0].decode().upper().strip()
269 if result != default.upper():
270 if not (result == "" and default == '""'):
271 doc_triple = "%s\n Expected: %s" % (param, default)
272 failset.add("%s\n Got: %s" % (doc_triple, result))
275 self.fail(self._format_message(failset,
276 "Parameters that do not have matching defaults:"))
278 def _set_arbitrary(self, program, exceptions=None):
280 if program[0] == 'bin/samba-tool' and os.getenv("PYTHON", None):
281 program = [os.environ["PYTHON"]] + program
283 arbitrary = {'string': 'string', 'boolean': 'yes', 'integer': '5',
284 'boolean-rev': 'yes',
288 'ustring': 'ustring',
289 'enum': '', 'boolean-auto': '', 'char': 'a', 'list': 'a, b, c'}
290 opposite_arbitrary = {'string': 'string2', 'boolean': 'no', 'integer': '6',
295 'ustring': 'ustring2',
296 'enum': '', 'boolean-auto': '', 'char': 'b', 'list': 'd, e, f'}
300 for tuples in self.defaults_all:
301 param, default, context, param_type = tuples
303 if param in ['printing', 'copy', 'include', 'log level']:
306 # currently no easy way to set an arbitrary value for these
307 if param_type in ['enum', 'boolean-auto']:
310 if exceptions is not None:
311 if param in exceptions:
320 self.fail("%s has no valid context" % param)
322 value_to_use = arbitrary.get(param_type)
323 if value_to_use is None:
324 self.fail("%s has an invalid type" % param)
326 p = subprocess.Popen(program + ["-s",
333 "%s = %s" % (param, value_to_use)],
334 stdout=subprocess.PIPE,
335 stderr=subprocess.PIPE,
336 cwd=self.topdir).communicate()
337 result = p[0].decode().upper().strip()
338 if result != value_to_use.upper():
339 # currently no way to distinguish command lists
340 if param_type == 'list':
341 if ", ".join(result.split()) == value_to_use.upper():
344 # currently no way to identify octal
345 if param_type == 'integer':
347 if int(value_to_use, 8) == int(p[0].strip(), 8):
352 doc_triple = "%s\n Expected: %s" % (param, value_to_use)
353 failset.add("%s\n Got: %s" % (doc_triple, p[0].upper().strip()))
355 opposite_value = opposite_arbitrary.get(param_type)
356 tempconf = os.path.join(self.tempdir, "tempsmb.conf")
357 g = open(tempconf, 'w')
359 towrite = section + "\n"
360 towrite += param + " = " + opposite_value
365 p = subprocess.Popen(program + ["-s",
369 "%s = %s" % (param, value_to_use)],
370 stdout=subprocess.PIPE,
371 stderr=subprocess.PIPE,
372 cwd=self.topdir).communicate()
376 # testparm doesn't display a value if they are equivalent
377 if (value_to_use.lower() != opposite_value.lower()):
378 for line in p[0].decode().splitlines():
379 if not line.strip().startswith(param):
382 value_found = line.split("=")[1].upper().strip()
383 if value_found != value_to_use.upper():
384 # currently no way to distinguish command lists
385 if param_type == 'list':
386 if ", ".join(value_found.split()) == value_to_use.upper():
389 # currently no way to identify octal
390 if param_type == 'integer':
392 if int(value_to_use, 8) == int(value_found, 8):
397 doc_triple = "%s\n Expected: %s" % (param, value_to_use)
398 failset.add("%s\n Got: %s" % (doc_triple, value_found))
401 self.fail(self._format_message(failset,
402 "Parameters that were unexpectedly not set:"))
404 def _test_empty(self, program):
406 if program[0] == 'bin/samba-tool' and os.getenv("PYTHON", None):
407 program = [os.environ["PYTHON"]] + program
409 p = subprocess.Popen(program + ["-s",
411 "--suppress-prompt"],
412 stdout=subprocess.PIPE,
413 stderr=subprocess.PIPE,
414 cwd=self.topdir).communicate()
417 for line in p[0].decode().splitlines():
418 if line.strip().startswith('#'):
420 if line.strip().startswith("idmap config *"):
422 output += line.strip().lower() + '\n'
424 if output.strip() != '[global]' and output.strip() != '[globals]':
425 self.fail("Testparm returned unexpected output on an empty smb.conf.")