2 # Bootstrap Samba and run a number of tests against it.
3 # Copyright (C) 2005-2012 Jelmer Vernooij <jelmer@samba.org>
4 # Copyright (C) 2007-2009 Stefan Metzmacher <metze@samba.org>
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 from cStringIO
import StringIO
35 sys
.path
.insert(0, os
.path
.dirname(os
.path
.dirname(__file__
)))
37 from selftest
import (
42 from selftest
.target
import (
45 UnsupportedEnvironment
,
52 return datetime
.datetime
.utcnow().replace(tzinfo
=iso8601
.iso8601
.Utc())
54 def read_excludes(fn
):
55 excludes
.extend(testlist
.read_test_regexes(fn
))
57 def read_includes(fn
):
58 includes
.extend(testlist
.read_test_regexes(fn
))
60 parser
= optparse
.OptionParser("TEST-REGEXES")
61 parser
.add_option("--target", type="choice", choices
=["samba", "samba3", "none"], default
="samba", help="Samba version to target")
62 parser
.add_option("--quick", help="run quick overall test", action
="store_true", default
=False)
63 parser
.add_option("--list", help="list available tests", action
="store_true", default
=False)
64 parser
.add_option("--socket-wrapper", help="enable socket wrapper", action
="store_true", default
=False)
65 parser
.add_option("--socket-wrapper-pcap", help="save traffic to pcap directories", type="str")
66 parser
.add_option("--socket-wrapper-keep-pcap", help="keep all pcap files, not just those for tests that failed", action
="store_true", default
=False)
67 parser
.add_option("--one", help="abort when the first test fails", action
="store_true", default
=False)
68 parser
.add_option("--exclude", action
="callback", help="Add file to exclude files", callback
=read_excludes
)
69 parser
.add_option("--include", action
="callback", help="Add file to include files", callback
=read_includes
)
70 parser
.add_option("--testenv", help="run a shell in the requested test environment", action
="store_true", default
=False)
71 parser
.add_option("--resetup-environment", help="Re-setup environment", action
="store_true", default
=False)
72 parser
.add_option("--binary-mapping", help="Map binaries to use", type=str)
73 parser
.add_option("--load-list", help="Load list of tests to load from a file", type=str)
74 parser
.add_option("--prefix", help="prefix to run tests in", type=str, default
="./st")
75 parser
.add_option("--srcdir", type=str, default
=".", help="source directory")
76 parser
.add_option("--bindir", type=str, default
="./bin", help="binaries directory")
77 parser
.add_option("--testlist", type=str, action
="append", help="file to read available tests from")
78 parser
.add_option("--ldap", help="back samba onto specified ldap server", choices
=["openldap", "fedora-ds"], type="choice")
80 opts
, args
= parser
.parse_args()
82 subunit_ops
= subunithelper
.SubunitOps(sys
.stdout
)
84 def handle_signal(sig
, frame
):
85 sys
.stderr
.write("Exiting early because of signal %s.\n" % sig
)
88 for sig
in (signal
.SIGINT
, signal
.SIGQUIT
, signal
.SIGTERm
, signal
.SIGPIPE
):
89 signal
.signal(sig
, handle_signal
)
92 return testlist
.find_in_list(excludes
, name
)
95 if (not opts
.socket_wrapper_pcap
or
96 not os
.environ
.get("SOCKET_WRAPPER_PCAP_DIR")):
99 fname
= "".join([x
for x
in name
if x
.isalnum() or x
== '-'])
101 pcap_file
= os
.path
.join(
102 os
.environ
["SOCKET_WRAPPER_PCAP_DIR"], "%s.pcap" % fname
)
104 socket_wrapper
.setup_pcap(pcap_file
)
108 def cleanup_pcap(pcap_file
, exit_code
):
109 if not opts
.socket_wrapper_pcap
:
111 if opts
.socket_wrapper_keep_pcap
:
115 if pcap_file
is None:
121 # expand strings from %ENV
122 def expand_environment_strings(s
):
123 # we use a reverse sort so we do the longer ones first
124 for k
in sorted(os
.environ
.keys(), reverse
=True):
126 s
= s
.replace("$%s" % k
, v
)
130 def run_testsuite(envname
, name
, cmd
):
131 """Run a single testsuite.
133 :param envname: Name of the environment to ru nin
134 :param name: Name of the testsuite
135 :param cmd: Name of the (fully expanded) command to run
136 :return: exitcode of the command
138 pcap_file
= setup_pcap(name
)
140 subunit_ops
.start_testsuite(name
)
141 subunit_ops
.progress(None, subunit
.PROGRESS_PUSH
)
142 subunit_ops
.time(now())
144 exitcode
= subprocess
.call(cmd
, shell
=True)
146 subunit_ops
.time(now())
147 subunit_ops
.progress(None, subunit
.PROGRESS_POP
)
148 subunit_ops
.end_testsuite(name
, "error", "Unable to run %r: %s" % (cmd
, e
))
151 subunit_ops
.time(now())
152 subunit_ops
.progress(None, subunit
.PROGRESS_POP
)
154 envlog
= env_manager
.getlog_env(envname
)
156 sys
.stdout
.write("envlog: %s\n" % envlog
)
158 sys
.stdout
.write("command: %s\n" % cmd
)
159 sys
.stdout
.write("expanded command: %s\n" % expand_environment_strings(cmd
))
162 subunit_ops
.end_testsuite(name
, "success")
164 subunit_ops
.end_testsuite(name
, "failure", "Exit code was %d" % exitcode
)
166 cleanup_pcap(pcap_file
, exitcode
)
168 if not opts
.socket_wrapper_keep_pcap
and pcap_file
is not None:
169 sys
.stdout
.write("PCAP FILE: %s\n" % pcap_file
)
171 if exitcode
!= 0 and opts
.one
:
176 if opts
.list and opts
.testenv
:
177 sys
.stderr
.write("--list and --testenv are mutually exclusive\n")
182 # quick hack to disable rpc validation when using valgrind - it is way too slow
183 if not os
.environ
.get("VALGRIND"):
184 os
.environ
["VALIDATE"] = "validate"
185 os
.environ
["MALLOC_CHECK_"] = "2"
187 # make all our python scripts unbuffered
188 os
.environ
["PYTHONUNBUFFERED"] = "1"
190 bindir_abs
= os
.path
.abspath(opts
.bindir
)
192 # Backwards compatibility:
193 if os
.environ
.get("TEST_LDAP") == "yes":
194 if os
.environ
.get("FEDORA_DS_ROOT"):
199 torture_maxtime
= int(os
.getenv("TORTURE_MAXTIME", "1200"))
204 prefix
= os
.path
.normpath(opts
.prefix
)
207 raise Exception("using an empty prefix isn't allowed")
209 # Ensure we have the test prefix around.
211 # We need restrictive permissions on this as some subdirectories in this tree
212 # will have wider permissions (ie 0777) and this would allow other users on the
213 # host to subvert the test process.
214 if not os
.path
.isdir(prefix
):
215 os
.mkdir(prefix
, 0700)
217 os
.chmod(prefix
, 0700)
219 prefix_abs
= os
.path
.abspath(prefix
)
220 tmpdir_abs
= os
.path
.abspath(os
.path
.join(prefix_abs
, "tmp"))
221 if not os
.path
.isdir(tmpdir_abs
):
222 os
.mkdir(tmpdir_abs
, 0777)
224 srcdir_abs
= os
.path
.abspath(opts
.srcdir
)
227 raise Exception("using an empty absolute prefix isn't allowed")
228 if prefix_abs
== "/":
229 raise Exception("using '/' as absolute prefix isn't allowed")
231 os
.environ
["PREFIX"] = prefix
232 os
.environ
["KRB5CCNAME"] = os
.path
.join(prefix
, "krb5ticket")
233 os
.environ
["PREFIX_ABS"] = prefix_abs
234 os
.environ
["SRCDIR"] = opts
.srcdir
235 os
.environ
["SRCDIR_ABS"] = srcdir_abs
236 os
.environ
["BINDIR"] = bindir_abs
238 tls_enabled
= not opts
.quick
240 os
.environ
["TLS_ENABLED"] = "yes"
242 os
.environ
["TLS_ENABLED"] = "no"
244 def prefix_pathvar(name
, newpath
):
245 if name
in os
.environ
:
246 os
.environ
[name
] = "%s:%s" % (newpath
, os
.environ
[name
])
248 os
.environ
[name
] = newpath
249 prefix_pathvar("PKG_CONFIG_PATH", os
.path
.join(bindir_abs
, "pkgconfig"))
250 prefix_pathvar("PYTHONPATH", os
.path
.join(bindir_abs
, "python"))
252 if opts
.socket_wrapper_keep_pcap
:
253 # Socket wrapper keep pcap implies socket wrapper pcap
254 opts
.socket_wrapper_pcap
= True
256 if opts
.socket_wrapper_pcap
:
257 # Socket wrapper pcap implies socket wrapper
258 opts
.socket_wrapper
= True
260 if opts
.socket_wrapper
:
261 socket_wrapper_dir
= socket_wrapper
.setup_dir(os
.path
.join(prefix_abs
, "w"), opts
.socket_wrapper_pcap
)
262 sys
.stdout
.write("SOCKET_WRAPPER_DIR=%s\n" % socket_wrapper_dir
)
265 warnings
.warn("not using socket wrapper, but also not running as root. Will not be able to listen on proper ports")
267 testenv_default
= "none"
269 if opts
.binary_mapping
:
270 binary_mapping
= dict([l
.split(":") for l
in opts
.binary_mapping
.split(",")])
271 os
.environ
["BINARY_MAPPING"] = opts
.binary_mapping
274 os
.environ
["BINARY_MAPPING"] = ""
276 # After this many seconds, the server will self-terminate. All tests
277 # must terminate in this time, and testenv will only stay alive this
280 server_maxtime
= 7500
281 if os
.environ
.get("SMBD_MAXTIME", ""):
282 server_maxtime
= int(os
.environ
["SMBD_MAXTIME"])
285 def has_socket_wrapper(bindir
):
286 """Check if Samba has been built with socket wrapper support.
289 subprocess
.check_call([os
.path
.join(bindir
, "smbd"), "-b"], stdout
=f
)
290 for l
in f
.readlines():
291 if "SOCKET_WRAPPER" in l
:
297 if opts
.target
== "samba":
298 if opts
.socket_wrapper
and not has_socket_wrapper(opts
.bindir
):
299 sys
.stderr
.write("You must include --enable-socket-wrapper when compiling Samba in order to execute 'make test'. Exiting....\n")
301 testenv_default
= "dc"
302 from selftest
.target
.samba
import Samba
303 target
= Samba(opts
.bindir
, binary_mapping
, ldap
, opts
.srcdir
, server_maxtime
)
304 elif opts
.target
== "samba3":
305 if opts
.socket_wrapper
and not has_socket_wrapper(opts
.bindir
):
306 sys
.stderr
.write("You must include --enable-socket-wrapper when compiling Samba in order to execute 'make test'. Exiting....\n")
308 testenv_default
= "member"
309 from selftest
.target
.samba3
import Samba3
310 target
= Samba3(opts
.bindir
, binary_mapping
, srcdir_abs
, server_maxtime
)
311 elif opts
.target
== "none":
312 testenv_default
= "none"
313 target
= NoneTarget()
315 env_manager
= EnvironmentManager(target
)
316 atexit
.register(env_manager
.teardown_all
)
318 interfaces
= ",".join([
326 clientdir
= os
.path
.join(prefix_abs
, "client")
328 conffile
= os
.path
.join(clientdir
, "client.conf")
329 os
.environ
["SMB_CONF_PATH"] = conffile
331 def write_clientconf(conffile
, clientdir
, vars):
332 if not os
.path
.isdir(clientdir
):
333 os
.mkdir(clientdir
, 0777)
335 for n
in ["private", "lockdir", "statedir", "cachedir"]:
336 p
= os
.path
.join(clientdir
, n
)
341 # this is ugly, but the ncalrpcdir needs exactly 0755
342 # otherwise tests fail.
343 mask
= os
.umask(0022)
345 for n
in ["ncalrpcdir", "ncalrpcdir/np"]:
346 p
= os
.path
.join(clientdir
, n
)
353 "netbios name": "client",
354 "private dir": os
.path
.join(clientdir
, "private"),
355 "lock dir": os
.path
.join(clientdir
, "lockdir"),
356 "state directory": os
.path
.join(clientdir
, "statedir"),
357 "cache directory": os
.path
.join(clientdir
, "cachedir"),
358 "ncalrpc dir": os
.path
.join(clientdir
, "ncalrpcdir"),
359 "name resolve order": "file bcast",
360 "panic action": os
.path
.join(os
.path
.dirname(__file__
), "gdb_backtrace \%d"),
362 "notify:inotify": "false",
363 "ldb:nosync": "true",
364 "system:anonymous": "true",
365 "client lanman auth": "Yes",
367 "torture:basedir": clientdir
,
368 # We don't want to pass our self-tests if the PAC code is wrong
369 "gensec:require_pac": "true",
370 "resolv:host file": os
.path
.join(prefix_abs
, "dns_host_file"),
371 # We don't want to run 'speed' tests for very long
372 "torture:timelimit": "1",
376 settings
["workgroup"] = vars["DOMAIN"]
378 settings
["realm"] = vars["REALM"]
379 if opts
.socket_wrapper
:
380 settings
["interfaces"] = interfaces
382 f
= open(conffile
, 'w')
384 f
.write("[global]\n")
385 for item
in settings
.iteritems():
386 f
.write("\t%s = %s\n" % item
)
392 if not opts
.testlist
:
393 sys
.stderr
.write("No testlists specified\n")
396 os
.environ
["SELFTEST_PREFIX"] = prefix_abs
397 os
.environ
["SELFTEST_TMPDIR"] = tmpdir_abs
398 os
.environ
["TEST_DATA_PREFIX"] = tmpdir_abs
399 if opts
.socket_wrapper
:
400 os
.environ
["SELFTEST_INTERFACES"] = interfaces
402 os
.environ
["SELFTEST_INTERFACES"] = ""
404 os
.environ
["SELFTEST_QUICK"] = "1"
406 os
.environ
["SELFTEST_QUICK"] = ""
407 os
.environ
["SELFTEST_MAXTIME"] = str(torture_maxtime
)
410 def open_file_or_pipe(path
, mode
):
411 if path
.endswith("|"):
412 return os
.popen(path
[:-1], mode
)
413 return open(path
, mode
)
416 for fn
in opts
.testlist
:
417 inf
= open_file_or_pipe(fn
, 'r')
419 for testsuite
in testlist
.read_testlist(inf
, sys
.stdout
):
420 if not testlist
.should_run_test(tests
, testsuite
):
423 if includes
is not None and testlist
.find_in_list(includes
, name
) is not None:
425 available
.append(testsuite
)
430 restricted_mgr
= testlist
.RestrictedTestManager
.from_path(opts
.load_list
)
432 restricted_mgr
= None
435 for testsuite
in available
:
437 skipreason
= skip(name
)
438 if restricted_mgr
is not None:
439 match
= restricted_mgr
.should_run_testsuite(name
)
444 if skipreason
is not None:
446 subunit_ops
.skip_testsuite(name
, skipreason
)
448 todo
.append(testsuite
+ (match
,))
450 if restricted_mgr
is not None:
451 for name
in restricted_mgr
.iter_unused():
452 sys
.stdout
.write("No test or testsuite found matching %s\n" % name
)
454 sys
.stderr
.write("No tests to run\n")
457 suitestotal
= len(todo
)
460 subunit_ops
.progress(suitestotal
, subunit
.PROGRESS_SET
)
461 subunit_ops
.time(now())
468 # domain controller stuff
477 "MEMBER_NETBIOSNAME",
478 "MEMBER_NETBIOSALIAS",
480 # rpc proxy controller stuff
482 "RPC_PROXY_SERVER_IP",
483 "RPC_PROXY_NETBIOSNAME",
484 "RPC_PROXY_NETBIOSALIAS",
486 # domain controller stuff for Vampired DC
488 "VAMPIRE_DC_SERVER_IP",
489 "VAMPIRE_DC_NETBIOSNAME",
490 "VAMPIRE_DC_NETBIOSALIAS",
507 "WINBINDD_SOCKET_DIR",
508 "WINBINDD_PRIV_PIPE_DIR",
513 def exported_envvars_str(testenv_vars
):
516 for n
in exported_envvars
:
517 if not n
in testenv_vars
:
519 out
+= "%s=%s\n" % (n
, testenv_vars
[n
])
524 def switch_env(name
, prefix
):
526 (envname
, option
) = name
.split(":", 1)
531 env
= env_manager
.setup_env(envname
, prefix
)
533 testenv_vars
= env
.get_vars()
535 if option
== "local":
536 socket_wrapper
.set_default_iface(testenv_vars
["SOCKET_WRAPPER_DEFAULT_IFACE"])
537 os
.environ
["SMB_CONF_PATH"] = testenv_vars
["SERVERCONFFILE"]
538 elif option
== "client":
539 socket_wrapper
.set_default_iface(11)
540 write_clientconf(conffile
, clientdir
, testenv_vars
)
541 os
.environ
["SMB_CONF_PATH"] = conffile
543 raise Exception("Unknown option[%s] for envname[%s]" % (option
,
546 for name
in exported_envvars
:
547 if name
in testenv_vars
:
548 os
.environ
[name
] = testenv_vars
[name
]
549 elif name
in os
.environ
:
554 # This 'global' file needs to be empty when we start
555 dns_host_file_path
= os
.path
.join(prefix_abs
, "dns_host_file")
556 if os
.path
.exists(dns_host_file_path
):
557 os
.unlink(dns_host_file_path
)
560 testenv_name
= os
.environ
.get("SELFTEST_TESTENV", testenv_default
)
562 testenv_vars
= switch_env(testenv_name
, prefix
)
564 os
.environ
["PIDDIR"] = testenv_vars
["PIDDIR"]
565 os
.environ
["ENVNAME"] = testenv_name
567 envvarstr
= exported_envvars_str(testenv_vars
)
569 term
= os
.environ
.get("TERMINAL", "xterm -e")
571 Welcome to the Samba4 Test environment '%(testenv_name)'
573 This matches the client environment used in make test
574 server is pid `cat \$PIDDIR/samba.pid`
576 Some useful environment variables:
577 TORTURE_OPTIONS=\$TORTURE_OPTIONS
578 SMB_CONF_PATH=\$SMB_CONF_PATH
581 \" && LD_LIBRARY_PATH=%(LD_LIBRARY_PATH)s $(SHELL)'""" % {
582 "testenv_name": testenv_name
,
583 "LD_LIBRARY_PATH": os
.environ
["LD_LIBRARY_PATH"]}
584 subprocess
.call(term
+ ' ' + cmd
, shell
=True)
585 env_manager
.teardown_env(testenv_name
)
587 for (name
, envname
, cmd
, supports_loadfile
, supports_idlist
, subtests
) in todo
:
588 if not "$LISTOPT" in cmd
:
589 warnings
.warn("Unable to list tests in %s" % name
)
592 cmd
= cmd
.replace("$LISTOPT", "--list")
594 exitcode
= subprocess
.call(cmd
, shell
=True)
597 sys
.stderr
.write("%s exited with exit code %s\n" % (cmd
, exitcode
))
600 for (name
, envname
, cmd
, supports_loadfile
, supports_idlist
, subtests
) in todo
:
602 envvars
= switch_env(envname
, prefix
)
603 except UnsupportedEnvironment
:
604 subunit_ops
.start_testsuite(name
)
605 subunit_ops
.end_testsuite(name
, "skip",
606 "environment %s is unknown in this test backend - skipping" % envname
)
609 subunit_ops
.start_testsuite(name
)
610 traceback
.print_exc()
611 subunit_ops
.end_testsuite(name
, "error",
612 "unable to set up environment %s: %s" % (envname
, e
))
615 # Generate a file with the individual tests to run, if the
616 # test runner for this test suite supports it.
617 if subtests
is not None:
618 if supports_loadfile
:
619 (fd
, listid_file
) = tempfile
.mkstemp()
620 # FIXME: Remove tempfile afterwards
623 for test
in subtests
:
627 cmd
= cmd
.replace("$LOADLIST", "--load-list=%s" % listid_file
)
628 elif supports_idlist
:
629 cmd
+= " ".join(subtests
)
631 run_testsuite(envname
, name
, cmd
)
633 if opts
.resetup_environment
:
634 env_manager
.teardown_env(envname
)
636 sys
.stdout
.write("\n")
639 env_manager
.teardown_all()
641 # if there were any valgrind failures, show them
642 for fn
in os
.listdir(prefix
):
643 if fn
.startswith("valgrind.log"):
644 sys
.stdout
.write("VALGRIND FAILURE\n")
645 f
= open(os
.path
.join(prefix
, fn
), 'r')
647 sys
.stdout
.write(f
.read())