1 # Unix SMB/CIFS implementation.
2 # Copyright © Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 3 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 from samba.tests import TestCase
21 from unittest import TestSuite
25 if 'SRCDIR_ABS' in os.environ:
26 BASEDIR = os.environ['SRCDIR_ABS']
28 BASEDIR = os.path.abspath(os.path.join(os.path.dirname(__file__),
67 'script/autobuild.py', # defaults to mount /memdisk/
68 'script/bisect-test.py',
69 'ctdb/utils/etcd/ctdb_etcd_lock',
70 'selftest/filter-subunit',
71 'selftest/format-subunit',
72 'bin/gen_output.py', # too much output!
73 'source4/scripting/bin/gen_output.py',
74 'lib/ldb/tests/python/index.py',
75 'lib/ldb/tests/python/api.py',
76 'source4/selftest/tests.py',
78 'selftest/tap2subunit',
79 'script/show_test_time',
80 'source4/scripting/bin/subunitrun',
81 'source3/selftest/tests.py',
83 'python/samba/subunit/run.py',
84 'bin/python/samba/subunit/run.py',
85 'python/samba/tests/dcerpc/raw_protocol.py'
89 'selftest/tap2subunit',
91 'wintest/test-s4-howto.py',
96 'source3/script/tests',
98 'source4/dsdb/tests/python',
100 'bin/python/samba/tests',
101 'bin/python/samba/tests/dcerpc',
105 def _init_git_file_finder():
106 """Generate a function that quickly answers the question:
107 'is this a git file?'
109 git_file_cache = set()
110 p = subprocess.run(['git',
114 stdout=subprocess.PIPE)
115 if p.returncode == 0:
116 for fn in p.stdout.split(b'\0'):
117 git_file_cache.add(os.path.join(BASEDIR, fn.decode('utf-8')))
118 return git_file_cache.__contains__
121 is_git_file = _init_git_file_finder()
124 def script_iterator(d=BASEDIR, cache=None,
126 filename_filter=None,
129 safename = re.compile(r'\W+').sub
130 for subdir in subdirs:
131 sd = os.path.join(d, subdir)
132 for root, dirs, files in os.walk(sd, followlinks=False):
136 if fn.endswith('.inst'):
138 ffn = os.path.join(root, fn)
141 except FileNotFoundError:
143 if not s.st_mode & stat.S_IXUSR:
145 if not (subdir == 'bin' or is_git_file(ffn)):
148 if filename_filter is not None:
149 if not filename_filter(ffn):
152 if shebang_filter is not None:
156 print("could not open %s: %s" % (ffn, e))
160 if not shebang_filter(line):
163 name = safename('_', fn)
170 # For ELF we only look at /bin/* top level.
171 def elf_file_name(fn):
172 fn = fn.partition('bin/')[2]
173 return fn and '/' not in fn and 'test' not in fn and 'ldb' in fn
176 return x[:4] == b'\x7fELF'
180 return script_iterator(BASEDIR, elf_cache,
181 shebang_filter=elf_shebang,
182 filename_filter=elf_file_name,
186 perl_shebang = re.compile(br'#!.+perl').match
188 perl_script_cache = {}
189 def perl_script_iterator():
190 return script_iterator(BASEDIR, perl_script_cache, perl_shebang)
193 python_shebang = re.compile(br'#!.+python').match
195 python_script_cache = {}
196 def python_script_iterator():
197 return script_iterator(BASEDIR, python_script_cache, python_shebang)
200 class PerlScriptUsageTests(TestCase):
201 """Perl scripts run without arguments should print a usage string,
202 not fail with a traceback.
207 for name, filename in perl_script_iterator():
208 print(name, filename)
211 class PythonScriptUsageTests(TestCase):
212 """Python scripts run without arguments should print a usage string,
213 not fail with a traceback.
218 for name, filename in python_script_iterator():
219 # We add the actual tests after the class definition so we
220 # can give individual names to them, so we can have a
222 fn = filename.replace(BASEDIR, '').lstrip('/')
224 if fn in EXCLUDE_USAGE:
225 print("skipping %s (EXCLUDE_USAGE)" % filename)
228 if os.path.dirname(fn) in EXCLUDE_DIRS:
229 print("skipping %s (EXCLUDE_DIRS)" % filename)
232 def _f(self, filename=filename):
235 p = subprocess.Popen(['python3', filename],
236 stderr=subprocess.PIPE,
237 stdout=subprocess.PIPE)
238 out, err = p.communicate(timeout=5)
240 self.fail("Error: %s" % e)
241 except subprocess.SubprocessError as e:
242 self.fail("Subprocess error: %s" % e)
244 err = err.decode('utf-8')
245 out = out.decode('utf-8')
246 self.assertNotIn('Traceback', err)
248 self.assertIn('usage', out.lower() + err.lower(),
249 'stdout:\n%s\nstderr:\n%s' % (out, err))
251 setattr(cls, 'test_%s' % name, _f)
254 class HelpTestSuper(TestCase):
255 """Python scripts run with -h or --help should print a help string,
256 and exit with success.
258 check_return_code = True
259 check_contains_usage = True
260 check_multiline = True
261 check_merged_out_and_err = False
268 raise NotImplementedError("Subclass this "
269 "and add an iterator function!")
273 for name, filename in cls.iterator():
274 # We add the actual tests after the class definition so we
275 # can give individual names to them, so we can have a
277 fn = filename.replace(BASEDIR, '').lstrip('/')
279 if fn in EXCLUDE_HELP:
280 print("skipping %s (EXCLUDE_HELP)" % filename)
283 if os.path.dirname(fn) in EXCLUDE_DIRS:
284 print("skipping %s (EXCLUDE_DIRS)" % filename)
287 def _f(self, filename=filename):
289 for h in ('--help', '-h'):
292 cmd.insert(0, self.interpreter)
294 p = subprocess.Popen(cmd,
295 stderr=subprocess.PIPE,
296 stdout=subprocess.PIPE)
297 out, err = p.communicate(timeout=5)
299 self.fail("Error: %s" % e)
300 except subprocess.SubprocessError as e:
301 self.fail("Subprocess error: %s" % e)
303 err = err.decode('utf-8')
304 out = out.decode('utf-8')
305 if self.check_merged_out_and_err:
306 out = "%s\n%s" % (out, err)
308 outl = out[:500].lower()
310 # These assertions are heuristics, not policy.
311 # If your script fails this test when it shouldn't
312 # just add it to EXCLUDE_HELP above or change the
315 # --help should produce:
316 # * multiple lines of help on stdout (not stderr),
317 # * including a "Usage:" string,
318 # * not contradict itself or repeat options,
319 # * and return success.
320 #print(out.encode('utf8'))
321 #print(err.encode('utf8'))
323 if self.check_return_code:
324 self.assertEqual(p.returncode, 0,
325 "%s %s\nreturncode should not be %d" %
326 (filename, h, p.returncode))
327 if self.check_contains_usage:
328 self.assertIn('usage', outl, 'lacks "Usage:"\n')
329 if self.check_multiline:
330 self.assertIn('\n', out, 'expected multi-line output')
332 setattr(cls, 'test_%s' % name, _f)
335 class PythonScriptHelpTests(HelpTestSuper):
336 """Python scripts run with -h or --help should print a help string,
337 and exit with success.
339 iterator = python_script_iterator
340 interpreter = 'python3'
343 class ElfHelpTests(HelpTestSuper):
344 """ELF binaries run with -h or --help should print a help string,
345 and exit with success.
347 iterator = elf_iterator
348 check_return_code = False
349 check_merged_out_and_err = True
352 PerlScriptUsageTests.initialise()
353 PythonScriptUsageTests.initialise()
354 PythonScriptHelpTests.initialise()
355 ElfHelpTests.initialise()