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/>.
19 from samba
.tests
import TestCase
, check_help_consistency
23 if 'SRCDIR_ABS' in os
.environ
:
24 BASEDIR
= os
.environ
['SRCDIR_ABS']
26 BASEDIR
= os
.path
.abspath(os
.path
.join(os
.path
.dirname(__file__
),
65 'script/autobuild.py', # defaults to mount /memdisk/
66 'script/bisect-test.py',
67 'ctdb/utils/etcd/ctdb_etcd_lock',
68 'selftest/filter-subunit',
69 'selftest/format-subunit',
70 'bin/gen_output.py', # too much output!
71 'source4/scripting/bin/gen_output.py',
72 'lib/ldb/tests/python/index.py',
73 'lib/ldb/tests/python/api.py',
74 'source4/selftest/tests.py',
76 'selftest/tap2subunit',
77 'script/show_test_time',
78 'source4/scripting/bin/subunitrun',
79 'bin/samba_downgrade_db',
80 'source4/scripting/bin/samba_downgrade_db',
81 'source3/selftest/tests.py',
83 'python/samba/subunit/run.py',
84 'bin/python/samba/subunit/run.py',
85 'lib/compression/tests/scripts/three-byte-hash',
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/blackbox',
102 'bin/python/samba/tests/dcerpc',
103 'bin/python/samba/tests/krb5',
104 'bin/python/samba/tests/ndr',
105 'python/samba/tests',
106 'python/samba/tests/bin',
107 'python/samba/tests/blackbox',
108 'python/samba/tests/dcerpc',
109 'python/samba/tests/krb5',
110 'python/samba/tests/ndr',
114 def _init_git_file_finder():
115 """Generate a function that quickly answers the question:
116 'is this a git file?'
118 git_file_cache
= set()
119 p
= subprocess
.run(['git',
123 stdout
=subprocess
.PIPE
)
124 if p
.returncode
== 0:
125 for fn
in p
.stdout
.split(b
'\0'):
126 git_file_cache
.add(os
.path
.join(BASEDIR
, fn
.decode('utf-8')))
127 return git_file_cache
.__contains
__
130 is_git_file
= _init_git_file_finder()
133 def script_iterator(d
=BASEDIR
, cache
=None,
135 filename_filter
=None,
140 safename
= re
.compile(r
'\W+').sub
141 for subdir
in subdirs
:
142 sd
= os
.path
.join(d
, subdir
)
143 for root
, dirs
, files
in os
.walk(sd
, followlinks
=False):
147 if fn
.endswith('.inst'):
149 ffn
= os
.path
.join(root
, fn
)
152 except FileNotFoundError
:
154 if not s
.st_mode
& stat
.S_IXUSR
:
156 if not (subdir
== 'bin' or is_git_file(ffn
)):
159 if filename_filter
is not None:
160 if not filename_filter(ffn
):
163 if shebang_filter
is not None:
167 print("could not open %s: %s" % (ffn
, e
))
171 if not shebang_filter(line
):
174 name
= safename('_', fn
)
181 # For ELF we only look at /bin/* top level.
182 def elf_file_name(fn
):
183 fn
= fn
.partition('bin/')[2]
184 return fn
and '/' not in fn
and 'test' not in fn
and 'ldb' in fn
187 return x
[:4] == b
'\x7fELF'
191 return script_iterator(BASEDIR
, elf_cache
,
192 shebang_filter
=elf_shebang
,
193 filename_filter
=elf_file_name
,
197 perl_shebang
= re
.compile(br
'#!.+perl').match
199 perl_script_cache
= {}
200 def perl_script_iterator():
201 return script_iterator(BASEDIR
, perl_script_cache
, perl_shebang
)
204 python_shebang
= re
.compile(br
'#!.+python').match
206 python_script_cache
= {}
207 def python_script_iterator():
208 return script_iterator(BASEDIR
, python_script_cache
, python_shebang
)
211 class PerlScriptUsageTests(TestCase
):
212 """Perl scripts run without arguments should print a usage string,
213 not fail with a traceback.
218 for name
, filename
in perl_script_iterator():
219 print(name
, filename
)
222 class PythonScriptUsageTests(TestCase
):
223 """Python scripts run without arguments should print a usage string,
224 not fail with a traceback.
229 for name
, filename
in python_script_iterator():
230 # We add the actual tests after the class definition so we
231 # can give individual names to them, so we can have a
233 fn
= filename
.replace(BASEDIR
, '').lstrip('/')
235 if fn
in EXCLUDE_USAGE
:
236 print("skipping %s (EXCLUDE_USAGE)" % filename
)
239 if os
.path
.dirname(fn
) in EXCLUDE_DIRS
:
240 print("skipping %s (EXCLUDE_DIRS)" % filename
)
243 def _f(self
, filename
=filename
):
246 p
= subprocess
.Popen(['python3', filename
],
247 stderr
=subprocess
.PIPE
,
248 stdout
=subprocess
.PIPE
)
249 out
, err
= p
.communicate(timeout
=5)
251 self
.fail("Error: %s" % e
)
252 except subprocess
.SubprocessError
as e
:
253 self
.fail("Subprocess error: %s" % e
)
255 err
= err
.decode('utf-8')
256 out
= out
.decode('utf-8')
257 self
.assertNotIn('Traceback', err
)
259 self
.assertIn('usage', out
.lower() + err
.lower(),
260 'stdout:\n%s\nstderr:\n%s' % (out
, err
))
262 attr
= 'test_%s' % name
263 if hasattr(cls
, attr
):
264 raise RuntimeError(f
'Usage test ‘{attr}’ already exists!')
265 setattr(cls
, attr
, _f
)
268 class HelpTestSuper(TestCase
):
269 """Python scripts run with -h or --help should print a help string,
270 and exit with success.
272 check_return_code
= True
273 check_consistency
= True
274 check_contains_usage
= True
275 check_multiline
= True
276 check_merged_out_and_err
= False
283 raise NotImplementedError("Subclass this "
284 "and add an iterator function!")
288 for name
, filename
in cls
.iterator():
289 # We add the actual tests after the class definition so we
290 # can give individual names to them, so we can have a
292 fn
= filename
.replace(BASEDIR
, '').lstrip('/')
294 if fn
in EXCLUDE_HELP
:
295 print("skipping %s (EXCLUDE_HELP)" % filename
)
298 if os
.path
.dirname(fn
) in EXCLUDE_DIRS
:
299 print("skipping %s (EXCLUDE_DIRS)" % filename
)
302 def _f(self
, filename
=filename
):
304 for h
in ('--help', '-h'):
307 cmd
.insert(0, self
.interpreter
)
309 p
= subprocess
.Popen(cmd
,
310 stderr
=subprocess
.PIPE
,
311 stdout
=subprocess
.PIPE
)
312 out
, err
= p
.communicate(timeout
=5)
314 self
.fail("Error: %s" % e
)
315 except subprocess
.SubprocessError
as e
:
316 self
.fail("Subprocess error: %s" % e
)
318 err
= err
.decode('utf-8')
319 out
= out
.decode('utf-8')
320 if self
.check_merged_out_and_err
:
321 out
= "%s\n%s" % (out
, err
)
323 outl
= out
[:500].lower()
325 # These assertions are heuristics, not policy.
326 # If your script fails this test when it shouldn't
327 # just add it to EXCLUDE_HELP above or change the
330 # --help should produce:
331 # * multiple lines of help on stdout (not stderr),
332 # * including a "Usage:" string,
333 # * not contradict itself or repeat options,
334 # * and return success.
335 #print(out.encode('utf8'))
336 #print(err.encode('utf8'))
337 if self
.check_consistency
:
338 errors
= check_help_consistency(out
,
341 if errors
is not None:
344 if self
.check_return_code
:
345 self
.assertEqual(p
.returncode
, 0,
346 "%s %s\nreturncode should not be %d\n"
347 "err:\n%s\nout:\n%s" %
348 (filename
, h
, p
.returncode
, err
, out
))
349 if self
.check_contains_usage
:
350 self
.assertIn('usage', outl
, 'lacks "Usage:"\n')
351 if self
.check_multiline
:
352 self
.assertIn('\n', out
, 'expected multi-line output')
354 attr
= 'test_%s' % name
355 if hasattr(cls
, attr
):
356 raise RuntimeError(f
'Usage test ‘{attr}’ already exists!')
357 setattr(cls
, attr
, _f
)
360 class PythonScriptHelpTests(HelpTestSuper
):
361 """Python scripts run with -h or --help should print a help string,
362 and exit with success.
364 iterator
= python_script_iterator
365 interpreter
= 'python3'
368 class ElfHelpTests(HelpTestSuper
):
369 """ELF binaries run with -h or --help should print a help string,
370 and exit with success.
372 iterator
= elf_iterator
373 check_return_code
= False
374 check_merged_out_and_err
= True
377 PerlScriptUsageTests
.initialise()
378 PythonScriptUsageTests
.initialise()
379 PythonScriptHelpTests
.initialise()
380 ElfHelpTests
.initialise()