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',
115 super(SmbDotConfTests, self).setUp()
116 # create a minimal smb.conf file for testparm
117 self.smbconf = os.path.join(self.tempdir, "paramtestsmb.conf")
118 f = open(self.smbconf, 'w')
127 self.blankconf = os.path.join(self.tempdir, "emptytestsmb.conf")
128 f = open(self.blankconf, 'w')
134 self.topdir = os.path.abspath(samba.source_tree_topdir())
137 self.documented = set(get_documented_parameters(self.topdir))
139 self.fail("Unable to load documented parameters")
142 self.defaults = set(get_documented_tuples(self.topdir))
144 self.fail("Unable to load parameters")
147 self.defaults_all = set(get_documented_tuples(self.topdir, False))
149 self.fail("Unable to load parameters")
153 super(SmbDotConfTests, self).tearDown()
154 os.unlink(self.smbconf)
155 os.unlink(self.blankconf)
157 def test_default_s3(self):
158 self._test_default(['bin/testparm'])
159 self._set_defaults(['bin/testparm'])
161 # registry shares appears to need sudo
162 self._set_arbitrary(['bin/testparm'],
163 exceptions = ['client lanman auth',
164 'client plaintext auth',
167 'rpc server dynamic port range',
168 'name resolve order'])
169 self._test_empty(['bin/testparm'])
171 def test_default_s4(self):
172 self._test_default(['bin/samba-tool', 'testparm'])
173 self._set_defaults(['bin/samba-tool', 'testparm'])
174 self._set_arbitrary(['bin/samba-tool', 'testparm'],
175 exceptions = ['smb ports',
176 'rpc server dynamic port range',
177 'name resolve order'])
178 self._test_empty(['bin/samba-tool', 'testparm'])
180 def _test_default(self, program):
184 for tuples in self.defaults:
185 param, default, context, param_type = tuples
187 if param in self.special_cases:
189 # bad, bad parametric options - we don't have their default values
198 self.fail("%s has no valid context" % param)
199 p = subprocess.Popen(program + ["-s", self.smbconf,
200 "--section-name", section, "--parameter-name", param],
201 stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=self.topdir).communicate()
202 if p[0].upper().strip() != default.upper():
203 if not (p[0].upper().strip() == "" and default == '""'):
204 doc_triple = "%s\n Expected: %s" % (param, default)
205 failset.add("%s\n Got: %s" % (doc_triple, p[0].upper().strip()))
208 self.fail(self._format_message(failset,
209 "Parameters that do not have matching defaults:"))
211 def _set_defaults(self, program):
215 for tuples in self.defaults:
216 param, default, context, param_type = tuples
218 if param in ['printing', 'rpc server dynamic port range']:
227 self.fail("%s has no valid context" % param)
228 p = subprocess.Popen(program + ["-s", self.smbconf,
229 "--section-name", section, "--parameter-name", param,
230 "--option", "%s = %s" % (param, default)],
231 stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=self.topdir).communicate()
232 if p[0].upper().strip() != default.upper():
233 if not (p[0].upper().strip() == "" and default == '""'):
234 doc_triple = "%s\n Expected: %s" % (param, default)
235 failset.add("%s\n Got: %s" % (doc_triple, p[0].upper().strip()))
238 self.fail(self._format_message(failset,
239 "Parameters that do not have matching defaults:"))
241 def _set_arbitrary(self, program, exceptions=None):
242 arbitrary = {'string': 'string', 'boolean': 'yes', 'integer': '5',
243 'boolean-rev': 'yes',
247 'ustring': 'ustring',
248 'enum':'', 'boolean-auto': '', 'char': 'a', 'list': 'a, b, c'}
249 opposite_arbitrary = {'string': 'string2', 'boolean': 'no', 'integer': '6',
254 'ustring': 'ustring2',
255 'enum':'', 'boolean-auto': '', 'char': 'b', 'list': 'd, e, f'}
260 for tuples in self.defaults_all:
261 param, default, context, param_type = tuples
263 if param in ['printing', 'copy', 'include', 'log level']:
266 # currently no easy way to set an arbitrary value for these
267 if param_type in ['enum', 'boolean-auto']:
270 if exceptions is not None:
271 if param in exceptions:
280 self.fail("%s has no valid context" % param)
282 value_to_use = arbitrary.get(param_type)
283 if value_to_use is None:
284 self.fail("%s has an invalid type" % param)
286 p = subprocess.Popen(program + ["-s", self.smbconf,
287 "--section-name", section, "--parameter-name", param,
288 "--option", "%s = %s" % (param, value_to_use)],
289 stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=self.topdir).communicate()
290 if p[0].upper().strip() != value_to_use.upper():
291 # currently no way to distinguish command lists
292 if param_type == 'list':
293 if ", ".join(p[0].upper().strip().split()) == value_to_use.upper():
296 # currently no way to identify octal
297 if param_type == 'integer':
299 if int(value_to_use, 8) == int(p[0].strip(), 8):
304 doc_triple = "%s\n Expected: %s" % (param, value_to_use)
305 failset.add("%s\n Got: %s" % (doc_triple, p[0].upper().strip()))
307 opposite_value = opposite_arbitrary.get(param_type)
308 tempconf = os.path.join(self.tempdir, "tempsmb.conf")
309 g = open(tempconf, 'w')
311 towrite = section + "\n"
312 towrite += param + " = " + opposite_value
317 p = subprocess.Popen(program + ["-s", tempconf, "--suppress-prompt",
318 "--option", "%s = %s" % (param, value_to_use)],
319 stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=self.topdir).communicate()
323 # testparm doesn't display a value if they are equivalent
324 if (value_to_use.lower() != opposite_value.lower()):
325 for line in p[0].splitlines():
326 if not line.strip().startswith(param):
329 value_found = line.split("=")[1].upper().strip()
330 if value_found != value_to_use.upper():
331 # currently no way to distinguish command lists
332 if param_type == 'list':
333 if ", ".join(value_found.split()) == value_to_use.upper():
336 # currently no way to identify octal
337 if param_type == 'integer':
339 if int(value_to_use, 8) == int(value_found, 8):
344 doc_triple = "%s\n Expected: %s" % (param, value_to_use)
345 failset.add("%s\n Got: %s" % (doc_triple, value_found))
349 self.fail(self._format_message(failset,
350 "Parameters that were unexpectedly not set:"))
352 def _test_empty(self, program):
353 p = subprocess.Popen(program + ["-s", self.blankconf, "--suppress-prompt"],
354 stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=self.topdir).communicate()
357 for line in p[0].splitlines():
358 if line.strip().startswith('#'):
360 if line.strip().startswith("idmap config *"):
362 output += line.strip().lower() + '\n'
364 if output.strip() != '[global]' and output.strip() != '[globals]':
365 self.fail("Testparm returned unexpected output on an empty smb.conf.")