2019-03-17 04:47:40 +03:00
# Unix SMB/CIFS implementation.
# Copyright © Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import sys
import subprocess
2019-06-27 07:57:22 +03:00
from samba . tests import TestCase , check_help_consistency
2019-03-17 04:47:40 +03:00
from unittest import TestSuite
import re
import stat
if ' SRCDIR_ABS ' in os . environ :
BASEDIR = os . environ [ ' SRCDIR_ABS ' ]
else :
BASEDIR = os . path . abspath ( os . path . join ( os . path . dirname ( __file__ ) ,
' ../../.. ' ) )
TEST_DIRS = [
" bootstrap " ,
" testdata " ,
" ctdb " ,
" dfs_server " ,
" pidl " ,
" auth " ,
" packaging " ,
" python " ,
" include " ,
" nsswitch " ,
" libcli " ,
" coverity " ,
" release-scripts " ,
" testprogs " ,
" bin " ,
" source3 " ,
" docs-xml " ,
" buildtools " ,
" file_server " ,
" dynconfig " ,
" source4 " ,
" tests " ,
" libds " ,
" selftest " ,
" lib " ,
" script " ,
" traffic " ,
" testsuite " ,
" libgpo " ,
" wintest " ,
" librpc " ,
]
EXCLUDE_USAGE = {
' script/autobuild.py ' , # defaults to mount /memdisk/
' script/bisect-test.py ' ,
' ctdb/utils/etcd/ctdb_etcd_lock ' ,
' selftest/filter-subunit ' ,
' selftest/format-subunit ' ,
' bin/gen_output.py ' , # too much output!
' source4/scripting/bin/gen_output.py ' ,
' lib/ldb/tests/python/index.py ' ,
' lib/ldb/tests/python/api.py ' ,
' source4/selftest/tests.py ' ,
' buildtools/bin/waf ' ,
' selftest/tap2subunit ' ,
' script/show_test_time ' ,
' source4/scripting/bin/subunitrun ' ,
2019-07-22 04:35:21 +03:00
' bin/samba_downgrade_db ' ,
' source4/scripting/bin/samba_downgrade_db ' ,
2019-03-17 04:47:40 +03:00
' source3/selftest/tests.py ' ,
' selftest/tests.py ' ,
' python/samba/subunit/run.py ' ,
' bin/python/samba/subunit/run.py ' ,
2020-02-15 20:33:33 +03:00
' python/samba/tests/dcerpc/raw_protocol.py ' ,
2020-07-20 17:49:39 +03:00
' python/samba/tests/smb-notify.py ' ,
2020-02-15 20:33:33 +03:00
' python/samba/tests/krb5/kcrypto.py ' ,
2020-02-13 18:29:38 +03:00
' python/samba/tests/krb5/simple_tests.py ' ,
2020-05-04 19:09:53 +03:00
' python/samba/tests/krb5/s4u_tests.py ' ,
2020-05-06 16:54:55 +03:00
' python/samba/tests/krb5/xrealm_tests.py ' ,
2020-10-26 23:32:21 +03:00
' python/samba/tests/krb5/as_canonicalization_tests.py ' ,
2020-11-04 03:58:24 +03:00
' python/samba/tests/krb5/compatability_tests.py ' ,
2020-11-10 01:19:02 +03:00
' python/samba/tests/krb5/rfc4120_constants.py ' ,
2020-11-05 23:07:04 +03:00
' python/samba/tests/krb5/kdc_tests.py ' ,
2020-11-30 04:19:15 +03:00
' python/samba/tests/krb5/kdc_base_test.py ' ,
' python/samba/tests/krb5/kdc_tgs_tests.py ' ,
2021-04-28 02:06:33 +03:00
' python/samba/tests/krb5/test_ccache.py ' ,
2021-04-29 11:58:11 +03:00
' python/samba/tests/krb5/test_ldap.py ' ,
2021-04-29 12:04:25 +03:00
' python/samba/tests/krb5/test_rpc.py ' ,
2021-04-29 23:58:11 +03:00
' python/samba/tests/krb5/test_smb.py ' ,
2021-02-17 02:15:50 +03:00
' python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py ' ,
2020-04-21 12:07:45 +03:00
' python/samba/tests/krb5/as_req_tests.py ' ,
2021-06-10 00:56:58 +03:00
' python/samba/tests/krb5/fast_tests.py ' ,
2021-09-30 05:03:04 +03:00
' python/samba/tests/krb5/rodc_tests.py ' ,
2021-10-20 02:46:36 +03:00
' python/samba/tests/krb5/salt_tests.py ' ,
2021-10-21 05:45:00 +03:00
' python/samba/tests/krb5/spn_tests.py ' ,
2021-10-19 10:02:45 +03:00
' python/samba/tests/krb5/alias_tests.py ' ,
2021-10-05 17:56:06 +03:00
' python/samba/tests/krb5/test_min_domain_uid.py ' ,
2021-11-12 04:22:47 +03:00
' python/samba/tests/krb5/test_idmap_nss.py ' ,
2021-12-09 01:56:55 +03:00
' python/samba/tests/krb5/pac_align_tests.py ' ,
2022-02-01 11:00:16 +03:00
' python/samba/tests/krb5/protected_users_tests.py ' ,
2022-04-11 06:44:09 +03:00
' python/samba/tests/krb5/nt_hash_tests.py ' ,
2022-05-24 10:59:16 +03:00
' python/samba/tests/krb5/kpasswd_tests.py ' ,
2022-03-04 06:23:32 +03:00
' python/samba/tests/krb5/claims_tests.py ' ,
2022-07-04 11:48:48 +03:00
' python/samba/tests/krb5/lockout_tests.py ' ,
2022-11-03 04:49:17 +03:00
' python/samba/tests/krb5/group_tests.py ' ,
2022-11-21 22:35:14 +03:00
' lib/compression/tests/scripts/three-byte-hash ' ,
2022-10-25 09:32:27 +03:00
' python/samba/tests/krb5/etype_tests.py ' ,
2019-03-17 04:47:40 +03:00
}
2019-06-27 07:57:22 +03:00
EXCLUDE_HELP = {
' selftest/tap2subunit ' ,
' wintest/test-s3.py ' ,
' wintest/test-s4-howto.py ' ,
}
2019-03-17 04:47:40 +03:00
EXCLUDE_DIRS = {
' source3/script/tests ' ,
' python/examples ' ,
' source4/dsdb/tests/python ' ,
' bin/ab ' ,
' bin/python/samba/tests ' ,
' bin/python/samba/tests/dcerpc ' ,
2020-02-15 20:33:33 +03:00
' bin/python/samba/tests/krb5 ' ,
2021-07-02 23:44:43 +03:00
' python/samba/tests/bin ' ,
2019-03-17 04:47:40 +03:00
}
def _init_git_file_finder ( ) :
""" Generate a function that quickly answers the question:
' is this a git file? '
"""
git_file_cache = set ( )
p = subprocess . run ( [ ' git ' ,
' -C ' , BASEDIR ,
' ls-files ' ,
' -z ' ] ,
stdout = subprocess . PIPE )
if p . returncode == 0 :
for fn in p . stdout . split ( b ' \0 ' ) :
git_file_cache . add ( os . path . join ( BASEDIR , fn . decode ( ' utf-8 ' ) ) )
return git_file_cache . __contains__
is_git_file = _init_git_file_finder ( )
2019-06-27 07:57:22 +03:00
def script_iterator ( d = BASEDIR , cache = None ,
shebang_filter = None ,
filename_filter = None ,
subdirs = TEST_DIRS ) :
if not cache :
2019-03-17 04:47:40 +03:00
safename = re . compile ( r ' \ W+ ' ) . sub
2019-06-27 07:57:22 +03:00
for subdir in subdirs :
2019-03-17 04:47:40 +03:00
sd = os . path . join ( d , subdir )
for root , dirs , files in os . walk ( sd , followlinks = False ) :
for fn in files :
if fn . endswith ( ' ~ ' ) :
continue
if fn . endswith ( ' .inst ' ) :
continue
ffn = os . path . join ( root , fn )
try :
s = os . stat ( ffn )
except FileNotFoundError :
continue
if not s . st_mode & stat . S_IXUSR :
continue
2019-06-27 07:57:22 +03:00
if not ( subdir == ' bin ' or is_git_file ( ffn ) ) :
2019-03-17 04:47:40 +03:00
continue
2019-06-27 07:57:22 +03:00
if filename_filter is not None :
if not filename_filter ( ffn ) :
continue
if shebang_filter is not None :
try :
f = open ( ffn , ' rb ' )
except OSError as e :
print ( " could not open %s : %s " % ( ffn , e ) )
continue
line = f . read ( 40 )
f . close ( )
if not shebang_filter ( line ) :
continue
2019-03-17 04:47:40 +03:00
name = safename ( ' _ ' , fn )
while name in cache :
name + = ' _ '
cache [ name ] = ffn
2019-06-27 07:57:22 +03:00
return cache . items ( )
# For ELF we only look at /bin/* top level.
def elf_file_name ( fn ) :
fn = fn . partition ( ' bin/ ' ) [ 2 ]
return fn and ' / ' not in fn and ' test ' not in fn and ' ldb ' in fn
def elf_shebang ( x ) :
return x [ : 4 ] == b ' \x7f ELF '
elf_cache = { }
def elf_iterator ( ) :
return script_iterator ( BASEDIR , elf_cache ,
shebang_filter = elf_shebang ,
filename_filter = elf_file_name ,
subdirs = [ ' bin ' ] )
perl_shebang = re . compile ( br ' #!.+perl ' ) . match
perl_script_cache = { }
def perl_script_iterator ( ) :
return script_iterator ( BASEDIR , perl_script_cache , perl_shebang )
python_shebang = re . compile ( br ' #!.+python ' ) . match
python_script_cache = { }
def python_script_iterator ( ) :
return script_iterator ( BASEDIR , python_script_cache , python_shebang )
class PerlScriptUsageTests ( TestCase ) :
""" Perl scripts run without arguments should print a usage string,
not fail with a traceback .
"""
@classmethod
def initialise ( cls ) :
for name , filename in perl_script_iterator ( ) :
print ( name , filename )
2019-03-17 04:47:40 +03:00
class PythonScriptUsageTests ( TestCase ) :
""" Python scripts run without arguments should print a usage string,
not fail with a traceback .
2019-06-27 07:57:22 +03:00
"""
2019-03-17 04:47:40 +03:00
@classmethod
def initialise ( cls ) :
for name , filename in python_script_iterator ( ) :
# We add the actual tests after the class definition so we
# can give individual names to them, so we can have a
# knownfail list.
fn = filename . replace ( BASEDIR , ' ' ) . lstrip ( ' / ' )
if fn in EXCLUDE_USAGE :
print ( " skipping %s (EXCLUDE_USAGE) " % filename )
continue
if os . path . dirname ( fn ) in EXCLUDE_DIRS :
print ( " skipping %s (EXCLUDE_DIRS) " % filename )
continue
def _f ( self , filename = filename ) :
print ( filename )
try :
p = subprocess . Popen ( [ ' python3 ' , filename ] ,
stderr = subprocess . PIPE ,
stdout = subprocess . PIPE )
out , err = p . communicate ( timeout = 5 )
except OSError as e :
self . fail ( " Error: %s " % e )
except subprocess . SubprocessError as e :
self . fail ( " Subprocess error: %s " % e )
err = err . decode ( ' utf-8 ' )
out = out . decode ( ' utf-8 ' )
self . assertNotIn ( ' Traceback ' , err )
self . assertIn ( ' usage ' , out . lower ( ) + err . lower ( ) ,
' stdout: \n %s \n stderr: \n %s ' % ( out , err ) )
setattr ( cls , ' test_ %s ' % name , _f )
2019-06-27 07:57:22 +03:00
class HelpTestSuper ( TestCase ) :
2019-06-27 07:57:22 +03:00
""" Python scripts run with -h or --help should print a help string,
and exit with success .
"""
2019-06-27 07:57:22 +03:00
check_return_code = True
2019-06-27 07:57:22 +03:00
check_consistency = True
2019-06-27 07:57:22 +03:00
check_contains_usage = True
check_multiline = True
check_merged_out_and_err = False
interpreter = None
options_start = None
options_end = None
def iterator ( self ) :
raise NotImplementedError ( " Subclass this "
" and add an iterator function! " )
2019-06-27 07:57:22 +03:00
@classmethod
def initialise ( cls ) :
2019-06-27 07:57:22 +03:00
for name , filename in cls . iterator ( ) :
2019-06-27 07:57:22 +03:00
# We add the actual tests after the class definition so we
# can give individual names to them, so we can have a
# knownfail list.
fn = filename . replace ( BASEDIR , ' ' ) . lstrip ( ' / ' )
if fn in EXCLUDE_HELP :
print ( " skipping %s (EXCLUDE_HELP) " % filename )
continue
if os . path . dirname ( fn ) in EXCLUDE_DIRS :
print ( " skipping %s (EXCLUDE_DIRS) " % filename )
continue
def _f ( self , filename = filename ) :
print ( filename )
for h in ( ' --help ' , ' -h ' ) :
2019-06-27 07:57:22 +03:00
cmd = [ filename , h ]
if self . interpreter :
cmd . insert ( 0 , self . interpreter )
2019-06-27 07:57:22 +03:00
try :
2019-06-27 07:57:22 +03:00
p = subprocess . Popen ( cmd ,
2019-06-27 07:57:22 +03:00
stderr = subprocess . PIPE ,
stdout = subprocess . PIPE )
out , err = p . communicate ( timeout = 5 )
except OSError as e :
self . fail ( " Error: %s " % e )
except subprocess . SubprocessError as e :
self . fail ( " Subprocess error: %s " % e )
err = err . decode ( ' utf-8 ' )
2019-06-27 07:57:22 +03:00
out = out . decode ( ' utf-8 ' )
if self . check_merged_out_and_err :
out = " %s \n %s " % ( out , err )
2019-06-27 07:57:22 +03:00
2019-06-27 07:57:22 +03:00
outl = out [ : 500 ] . lower ( )
2019-06-27 07:57:22 +03:00
# NOTE:
# These assertions are heuristics, not policy.
# If your script fails this test when it shouldn't
# just add it to EXCLUDE_HELP above or change the
# heuristic.
# --help should produce:
# * multiple lines of help on stdout (not stderr),
# * including a "Usage:" string,
2019-06-27 07:57:22 +03:00
# * not contradict itself or repeat options,
2019-06-27 07:57:22 +03:00
# * and return success.
2019-06-27 07:57:22 +03:00
#print(out.encode('utf8'))
#print(err.encode('utf8'))
2019-06-27 07:57:22 +03:00
if self . check_consistency :
errors = check_help_consistency ( out ,
self . options_start ,
self . options_end )
if errors is not None :
self . fail ( errors )
2019-06-27 07:57:22 +03:00
if self . check_return_code :
self . assertEqual ( p . returncode , 0 ,
2020-03-24 16:02:58 +03:00
" %s %s \n returncode should not be %d \n "
" err: \n %s \n out: \n %s " %
( filename , h , p . returncode , err , out ) )
2019-06-27 07:57:22 +03:00
if self . check_contains_usage :
self . assertIn ( ' usage ' , outl , ' lacks " Usage: " \n ' )
if self . check_multiline :
self . assertIn ( ' \n ' , out , ' expected multi-line output ' )
2019-06-27 07:57:22 +03:00
setattr ( cls , ' test_ %s ' % name , _f )
2019-06-27 07:57:22 +03:00
class PythonScriptHelpTests ( HelpTestSuper ) :
""" Python scripts run with -h or --help should print a help string,
and exit with success .
"""
iterator = python_script_iterator
interpreter = ' python3 '
class ElfHelpTests ( HelpTestSuper ) :
""" ELF binaries run with -h or --help should print a help string,
and exit with success .
"""
iterator = elf_iterator
check_return_code = False
check_merged_out_and_err = True
PerlScriptUsageTests . initialise ( )
2019-03-17 04:47:40 +03:00
PythonScriptUsageTests . initialise ( )
2019-06-27 07:57:22 +03:00
PythonScriptHelpTests . initialise ( )
2019-06-27 07:57:22 +03:00
ElfHelpTests . initialise ( )