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."""
24 from samba
.tests
import TestSkipped
, TestCaseInTempDir
30 import xml
.etree
.ElementTree
as ET
32 class TestCase(samba
.tests
.TestCaseInTempDir
):
34 def _format_message(self
, parameters
, message
):
35 parameters
= list(parameters
)
37 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_implementation_parameters(sourcedir
):
63 # Reading entries from source code
64 f
= open(os
.path
.join(sourcedir
, "lib/param/param_table.c"), "r")
66 # burn through the preceding lines
69 if l
.startswith("struct parm_struct parm_table"):
72 for l
in f
.readlines():
73 if re
.match("^\s*\}\;\s*$", l
):
75 # pull in the param names only
76 if re
.match(".*P_SEPARATOR.*", l
):
78 m
= re
.match("\s*\.label\s*=\s*\"(.*)\".*", l
)
87 def get_documented_tuples(sourcedir
, omit_no_default
=True):
88 path
= os
.path
.join(sourcedir
, "bin", "default", "docs-xml", "smbdotconf")
89 if not os
.path
.exists(os
.path
.join(path
, "parameters.all.xml")):
90 raise Exception("Unable to find parameters.all.xml")
92 p
= open(os
.path
.join(path
, "parameters.all.xml"), 'r')
94 raise Exception("Error opening parameters file")
97 root
= ET
.fromstring(out
)
98 for parameter
in root
:
99 name
= parameter
.attrib
.get("name")
100 param_type
= parameter
.attrib
.get("type")
101 if parameter
.attrib
.get('removed') == "1":
103 values
= parameter
.findall("value")
106 if value
.attrib
.get("type") == "default":
107 defaults
.append(value
)
110 if len(defaults
) == 0:
113 elif len(defaults
) > 1:
114 raise Exception("More than one default found for parameter %s" % name
)
116 default_text
= defaults
[0].text
118 if default_text
is None:
120 context
= parameter
.attrib
.get("context")
121 yield name
, default_text
, context
, param_type
124 class SmbDotConfTests(TestCase
):
126 # defines the cases where the defaults may differ from the documentation
127 special_cases
= set(['log level', 'path', 'ldapsam:trusted', 'spoolss: architecture',
128 'share:fake_fscaps', 'ldapsam:editposix', 'rpc_daemon:DAEMON',
129 'rpc_server:SERVER', 'panic action', 'homedir map', 'NIS homedir',
130 'server string', 'netbios name', 'socket options', 'use mmap',
131 'ctdbd socket', 'printing', 'printcap name', 'queueresume command',
132 'queuepause command','lpresume command', 'lppause command',
133 'lprm command', 'lpq command', 'print command', 'template homedir',
134 'spoolss: os_major', 'spoolss: os_minor', 'spoolss: os_build'])
137 super(SmbDotConfTests
, self
).setUp()
138 # create a minimal smb.conf file for testparm
139 self
.smbconf
= os
.path
.join(self
.tempdir
, "paramtestsmb.conf")
140 f
= open(self
.smbconf
, 'w')
150 super(SmbDotConfTests
, self
).tearDown()
151 os
.unlink(self
.smbconf
)
153 def test_unknown(self
):
154 topdir
= os
.path
.abspath(samba
.source_tree_topdir())
156 documented
= set(get_documented_parameters(topdir
))
158 self
.fail("Unable to load parameters")
159 parameters
= set(get_implementation_parameters(topdir
))
160 # Filter out parametric options, since we can't find them in the parm
162 documented
= set([p
for p
in documented
if not ":" in p
])
163 unknown
= documented
.difference(parameters
)
165 self
.fail(self
._format
_message
(unknown
,
166 "Parameters that are documented but not in the implementation:"))
168 def test_undocumented(self
):
169 topdir
= os
.path
.abspath(samba
.source_tree_topdir())
171 documented
= set(get_documented_parameters(topdir
))
173 self
.fail("Unable to load parameters")
174 parameters
= set(get_implementation_parameters(topdir
))
175 undocumented
= parameters
.difference(documented
)
176 if len(undocumented
) > 0:
177 self
.fail(self
._format
_message
(undocumented
,
178 "Parameters that are in the implementation but undocumented:"))
180 def test_default_s3(self
):
181 self
._test
_default
(['bin/testparm'])
182 self
._set
_defaults
(['bin/testparm'])
184 # registry shares appears to need sudo
185 self
._set
_arbitrary
(['bin/testparm'],
186 exceptions
= ['client lanman auth',
187 'client plaintext auth',
193 def test_default_s4(self
):
194 self
._test
_default
(['bin/samba-tool', 'testparm'])
195 self
._set
_defaults
(['bin/samba-tool', 'testparm'])
196 self
._set
_arbitrary
(['bin/samba-tool', 'testparm'])
198 def _test_default(self
, program
):
199 topdir
= os
.path
.abspath(samba
.source_tree_topdir())
201 defaults
= set(get_documented_tuples(topdir
))
203 self
.fail("Unable to load parameters")
204 bindir
= os
.path
.join(topdir
, "bin")
208 for tuples
in defaults
:
209 param
, default
, context
, param_type
= tuples
210 if param
in self
.special_cases
:
218 self
.fail("%s has no valid context" % param
)
219 p
= subprocess
.Popen(program
+ ["-s", self
.smbconf
,
220 "--section-name", section
, "--parameter-name", param
],
221 stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
, cwd
=topdir
).communicate()
222 if p
[0].upper().strip() != default
.upper():
223 if not (p
[0].upper().strip() == "" and default
== '""'):
224 doc_triple
= "%s\n Expected: %s" % (param
, default
)
225 failset
.add("%s\n Got: %s" % (doc_triple
, p
[0].upper().strip()))
228 self
.fail(self
._format
_message
(failset
,
229 "Parameters that do not have matching defaults:"))
231 def _set_defaults(self
, program
):
232 topdir
= os
.path
.abspath(samba
.source_tree_topdir())
234 defaults
= set(get_documented_tuples(topdir
))
236 self
.fail("Unable to load parameters")
237 bindir
= os
.path
.join(topdir
, "bin")
241 for tuples
in defaults
:
242 param
, default
, context
, param_type
= tuples
244 if param
in ['printing']:
253 self
.fail("%s has no valid context" % param
)
254 p
= subprocess
.Popen(program
+ ["-s", self
.smbconf
,
255 "--section-name", section
, "--parameter-name", param
,
256 "--option", "%s = %s" % (param
, default
)],
257 stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
, cwd
=topdir
).communicate()
258 if p
[0].upper().strip() != default
.upper():
259 if not (p
[0].upper().strip() == "" and default
== '""'):
260 doc_triple
= "%s\n Expected: %s" % (param
, default
)
261 failset
.add("%s\n Got: %s" % (doc_triple
, p
[0].upper().strip()))
264 self
.fail(self
._format
_message
(failset
,
265 "Parameters that do not have matching defaults:"))
267 def _set_arbitrary(self
, program
, exceptions
=None):
268 arbitrary
= {'string': 'string', 'boolean': 'yes', 'integer': '5',
269 'enum':'', 'boolean-auto': '', 'char': 'a', 'list': 'a, b, c'}
271 topdir
= os
.path
.abspath(samba
.source_tree_topdir())
273 defaults
= set(get_documented_tuples(topdir
, False))
275 self
.fail("Unable to load parameters" + e
)
276 bindir
= os
.path
.join(topdir
, "bin")
280 for tuples
in defaults
:
281 param
, default
, context
, param_type
= tuples
283 if param
in ['printing', 'copy', 'include', 'log level']:
286 # currently no easy way to set an arbitrary value for these
287 if param_type
in ['enum', 'boolean-auto']:
290 if exceptions
is not None:
291 if param
in exceptions
:
300 self
.fail("%s has no valid context" % param
)
302 value_to_use
= arbitrary
.get(param_type
)
303 if value_to_use
is None:
304 self
.fail("%s has an invalid type" % param
)
306 p
= subprocess
.Popen(program
+ ["-s", self
.smbconf
,
307 "--section-name", section
, "--parameter-name", param
,
308 "--option", "%s = %s" % (param
, value_to_use
)],
309 stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
, cwd
=topdir
).communicate()
310 if p
[0].upper().strip() != value_to_use
.upper():
311 # currently no way to distinguish command lists
312 if param_type
== 'list':
313 if ", ".join(p
[0].upper().strip().split()) == value_to_use
.upper():
316 # currently no way to identify octal
317 if param_type
== 'integer':
319 if int(value_to_use
, 8) == int(p
[0].strip(), 8):
324 doc_triple
= "%s\n Expected: %s" % (param
, value_to_use
)
325 failset
.add("%s\n Got: %s" % (doc_triple
, p
[0].upper().strip()))
328 self
.fail(self
._format
_message
(failset
,
329 "Parameters that were unexpectedly not set:"))