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/>.
19 from cStringIO import StringIO
34 sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
36 from selftest import (
41 from selftest.target import (
44 UnsupportedEnvironment,
51 return datetime.datetime.utcnow().replace(tzinfo=iso8601.iso8601.Utc())
53 def read_excludes(fn):
54 excludes.extend(testlist.read_test_regexes(fn))
56 def read_includes(fn):
57 includes.extend(testlist.read_test_regexes(fn))
59 parser = optparse.OptionParser("TEST-REGEXES")
60 parser.add_option("--target", type="choice", choices=["samba", "samba3", "none"], default="samba", help="Samba version to target")
61 parser.add_option("--quick", help="run quick overall test")
62 parser.add_option("--verbose", help="be verbose")
63 parser.add_option("--list", help="list available tests")
64 parser.add_option("--socket-wrapper", help="enable socket wrapper")
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")
67 parser.add_option("--one", help="abort when the first test fails")
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")
71 parser.add_option("--resetup-environment", help="Re-setup environment")
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 pipe_handler(sig):
85 sys.stderr.write("Exiting early because of SIGPIPE.\n")
88 signal.signal(signal.SIGPIPE, pipe_handler)
91 return testlist.find_in_list(excludes, name)
94 if (not opts.socket_wrapper_pcap or
95 not os.environ.get("SOCKET_WRAPPER_PCAP_DIR")):
98 fname = "".join([x for x in name if x.isalnum() or x == '-'])
100 pcap_file = os.path.join(
101 os.environ["SOCKET_WRAPPER_PCAP_DIR"], "%s.pcap" % fname)
103 socket_wrapper.setup_pcap(pcap_file)
107 def cleanup_pcap(pcap_file, exit_code):
108 if not opts.socket_wrapper_pcap:
110 if opts.socket_wrapper_keep_pcap:
114 if pcap_file is None:
120 # expand strings from %ENV
121 def expand_environment_strings(s):
122 # we use a reverse sort so we do the longer ones first
123 for k in sorted(os.environ.keys(), reverse=True):
125 s = s.replace("$%s" % k, v)
129 def run_testsuite(envname, name, cmd, i, totalsuites):
130 pcap_file = setup_pcap(name)
132 subunit_ops.start_testsuite(name)
133 subunit_ops.progress(None, subunit.PROGRESS_PUSH)
134 subunit_ops.time(now())
136 exitcode = subprocess.call(cmd, shell=True)
138 subunit_ops.time(now())
139 subunit_ops.progress(None, subunit.PROGRESS_POP)
140 subunit_ops.end_testsuite(name, "error", "Unable to run %r: %s" % (cmd, e))
143 subunit_ops.time(now())
144 subunit_ops.progress(None, subunit.PROGRESS_POP)
146 envlog = env_manager.getlog_env(envname)
148 sys.stdout.write("envlog: %s\n" % envlog)
150 sys.stdout.write("command: %s\n" % cmd)
151 sys.stdout.write("expanded command: %s\n" % expand_environment_strings(cmd))
154 subunit_ops.end_testsuite(name, "success")
156 subunit_ops.end_testsuite(name, "failure", "Exit code was %d" % exitcode)
158 cleanup_pcap(pcap_file, exitcode)
160 if not opts.socket_wrapper_keep_pcap and pcap_file is not None:
161 sys.stdout.write("PCAP FILE: %s\n" % pcap_file)
163 if exitcode != 0 and opts.one:
168 if opts.list and opts.testenv:
169 sys.stderr.write("--list and --testenv are mutually exclusive\n")
174 # quick hack to disable rpc validation when using valgrind - its way too slow
175 if not os.environ.get("VALGRIND"):
176 os.environ["VALIDATE"] = "validate"
177 os.environ["MALLOC_CHECK_"] = "2"
179 # make all our python scripts unbuffered
180 os.environ["PYTHONUNBUFFERED"] = "1"
182 bindir_abs = os.path.abspath(opts.bindir)
184 # Backwards compatibility:
185 if os.environ.get("TEST_LDAP") == "yes":
186 if os.environ.get("FEDORA_DS_ROOT"):
191 torture_maxtime = int(os.getenv("TORTURE_MAXTIME", "1200"))
196 prefix = os.path.normpath(opts.prefix)
199 raise Exception("using an empty prefix isn't allowed")
201 # Ensure we have the test prefix around.
203 # We need restrictive
204 # permissions on this as some subdirectories in this tree will have
205 # wider permissions (ie 0777) and this would allow other users on the
206 # host to subvert the test process.
207 if not os.path.isdir(prefix):
208 os.mkdir(prefix, 0700)
210 os.chmod(prefix, 0700)
212 prefix_abs = os.path.abspath(prefix)
213 tmpdir_abs = os.path.abspath(os.path.join(prefix_abs, "tmp"))
214 if not os.path.isdir(tmpdir_abs):
215 os.mkdir(tmpdir_abs, 0777)
217 srcdir_abs = os.path.abspath(opts.srcdir)
220 raise Exception("using an empty absolute prefix isn't allowed")
221 if prefix_abs == "/":
222 raise Exception("using '/' as absolute prefix isn't allowed")
224 os.environ["PREFIX"] = prefix
225 os.environ["KRB5CCNAME"] = os.path.join(prefix, "krb5ticket")
226 os.environ["PREFIX_ABS"] = prefix_abs
227 os.environ["SRCDIR"] = opts.srcdir
228 os.environ["SRCDIR_ABS"] = srcdir_abs
229 os.environ["BINDIR"] = bindir_abs
231 tls_enabled = not opts.quick
233 os.environ["TLS_ENABLED"] = "yes"
235 os.environ["TLS_ENABLED"] = "no"
237 def prefix_pathvar(name, newpath):
238 if name in os.environ:
239 os.environ[name] = "%s:%s" % (newpath, os.environ[name])
241 os.environ[name] = newpath
242 prefix_pathvar("PKG_CONFIG_PATH", os.path.join(bindir_abs, "pkgconfig"))
243 prefix_pathvar("PYTHONPATH", os.path.join(bindir_abs, "python"))
245 if opts.socket_wrapper_keep_pcap:
246 # Socket wrapper keep pcap implies socket wrapper pcap
247 opts.socket_wrapper_pcap = True
249 if opts.socket_wrapper_pcap:
250 # Socket wrapper pcap implies socket wrapper
251 opts.socket_wrapper = True
253 if opts.socket_wrapper:
254 socket_wrapper_dir = socket_wrapper.setup_dir(os.path.join(prefix_abs, "w"), opts.socket_wrapper_pcap)
255 sys.stdout.write("SOCKET_WRAPPER_DIR=%s\n" % socket_wrapper_dir)
258 warnings.warn("not using socket wrapper, but also not running as root. Will not be able to listen on proper ports")
260 testenv_default = "none"
262 if opts.binary_mapping:
263 binary_mapping = dict([l.split(":") for l in opts.binary_mapping.split(",")])
264 os.environ["BINARY_MAPPING"] = opts.binary_mapping
267 os.environ["BINARY_MAPPING"] = ""
269 # After this many seconds, the server will self-terminate. All tests
270 # must terminate in this time, and testenv will only stay alive this
273 server_maxtime = 7500
274 if os.environ.get("SMBD_MAXTIME", ""):
275 server_maxtime = int(os.environ["SMBD_MAXTIME"])
278 def has_socket_wrapper(bindir):
280 subprocess.check_call([os.path.join(bindir, "smbd"), "-b"], stdout=f)
281 for l in f.readlines():
282 if "SOCKET_WRAPPER" in l:
288 if opts.target == "samba":
289 if opts.socket_wrapper and not has_socket_wrapper(opts.bindir):
290 sys.stderr.write("You must include --enable-socket-wrapper when compiling Samba in order to execute 'make test'. Exiting....\n")
292 testenv_default = "dc"
293 from selftest.target.samba import Samba
294 target = Samba(opts.bindir, binary_mapping, ldap, opts.srcdir, server_maxtime)
295 elif opts.target == "samba3":
296 if opts.socket_wrapper and not has_socket_wrapper(opts.bindir):
297 sys.stderr.write("You must include --enable-socket-wrapper when compiling Samba in order to execute 'make test'. Exiting....\n")
299 testenv_default = "member"
300 from selftest.target.samba3 import Samba3
301 target = Samba3(opts.bindir, binary_mapping, srcdir_abs, server_maxtime)
302 elif opts.target == "none":
303 testenv_default = "none"
304 target = NoneTarget()
306 env_manager = EnvironmentManager(target)
308 interfaces = ",".join([
316 clientdir = os.path.join(prefix_abs, "client")
318 conffile = os.path.join(clientdir, "client.conf")
319 os.environ["SMB_CONF_PATH"] = conffile
321 def write_clientconf(conffile, clientdir, vars):
322 if not os.path.isdir(clientdir):
323 os.mkdir(clientdir, 0777)
325 for n in ["private", "lockdir", "statedir", "cachedir"]:
326 p = os.path.join(clientdir, n)
331 # this is ugly, but the ncalrpcdir needs exactly 0755
332 # otherwise tests fail.
333 mask = os.umask(0022)
335 for n in ["ncalrpcdir", "ncalrpcdir/np"]:
336 p = os.path.join(clientdir, n)
343 "netbios name": "client",
344 "private dir": os.path.join(clientdir, "private"),
345 "lock dir": os.path.join(clientdir, "lockdir"),
346 "state directory": os.path.join(clientdir, "statedir"),
347 "cache directory": os.path.join(clientdir, "cachedir"),
348 "ncalrpc dir": os.path.join(clientdir, "ncalrpcdir"),
349 "name resolve order": "file bcast",
350 "panic action": os.path.join(os.path.dirname(__file__), "gdb_backtrace \%d"),
352 "notify:inotify": "false",
353 "ldb:nosync": "true",
354 "system:anonymous": "true",
355 "client lanman auth": "Yes",
357 "torture:basedir": clientdir,
358 # We don't want to pass our self-tests if the PAC code is wrong
359 "gensec:require_pac": "true",
360 "resolv:host file": os.path.join(prefix_abs, "dns_host_file"),
361 # We don't want to run 'speed' tests for very long
362 "torture:timelimit": "1",
366 settings["workgroup"] = vars["DOMAIN"]
368 settings["realm"] = vars["REALM"]
369 if opts.socket_wrapper:
370 settings["interfaces"] = interfaces
372 f = open(conffile, 'w')
374 f.write("[global]\n")
375 for item in settings.iteritems():
376 f.write("\t%s = %s\n" % item)
382 if not opts.testlist:
383 sys.stderr.write("No testlists specified\n")
386 os.environ["SELFTEST_PREFIX"] = prefix_abs
387 os.environ["SELFTEST_TMPDIR"] = tmpdir_abs
388 os.environ["TEST_DATA_PREFIX"] = tmpdir_abs
389 if opts.socket_wrapper:
390 os.environ["SELFTEST_INTERFACES"] = interfaces
392 os.environ["SELFTEST_INTERFACES"] = ""
394 os.environ["SELFTEST_VERBOSE"] = "1"
396 os.environ["SELFTEST_VERBOSE"] = ""
398 os.environ["SELFTEST_QUICK"] = "1"
400 os.environ["SELFTEST_QUICK"] = ""
401 os.environ["SELFTEST_MAXTIME"] = str(torture_maxtime)
404 def open_file_or_pipe(path, mode):
405 if path.endswith("|"):
406 return os.popen(path[:-1], mode)
407 return open(path, mode)
410 for fn in opts.testlist:
411 inf = open_file_or_pipe(fn, 'r')
413 for testsuite in testlist.read_testlist(inf, sys.stdout):
414 if not testlist.should_run_test(tests, testsuite):
417 if includes is not None and testlist.find_in_list(includes, name) is not None:
419 available.append(testsuite)
424 restricted_mgr = testlist.RestrictedTestManager.from_path(opts.load_list)
426 restricted_mgr = None
429 for testsuite in available:
431 skipreason = skip(name)
432 if restricted_mgr is not None:
433 match = restricted_mgr.should_run_testsuite(name)
438 if skipreason is not None:
440 subunit_ops.skip_testsuite(name, skipreason)
442 todo.append(testsuite + (match,))
444 if restricted_mgr is not None:
445 for name in restricted_mgr.iter_unused():
446 sys.stdout.write("No test or testsuite found matching %s\n" % name)
448 sys.stderr.write("No tests to run\n")
451 suitestotal = len(todo)
454 subunit_ops.progress(suitestotal, subunit.PROGRESS_SET)
455 subunit_ops.time(now())
464 # domain controller stuff
473 "MEMBER_NETBIOSNAME",
474 "MEMBER_NETBIOSALIAS",
476 # rpc proxy controller stuff
478 "RPC_PROXY_SERVER_IP",
479 "RPC_PROXY_NETBIOSNAME",
480 "RPC_PROXY_NETBIOSALIAS",
482 # domain controller stuff for Vampired DC
484 "VAMPIRE_DC_SERVER_IP",
485 "VAMPIRE_DC_NETBIOSNAME",
486 "VAMPIRE_DC_NETBIOSALIAS",
503 "WINBINDD_SOCKET_DIR",
504 "WINBINDD_PRIV_PIPE_DIR",
509 def handle_sigdie(signame):
510 env_manager.teardown_all()
511 sys.stderr.write("Received signal %s" % signame)
514 signal.signal(signal.SIGINT, handle_sigdie)
515 signal.signal(signal.SIGQUIT, handle_sigdie)
516 signal.signal(signal.SIGTERM, handle_sigdie)
518 def exported_envvars_str(testenv_vars):
521 for n in exported_envvars:
522 if not n in testenv_vars:
524 out += "%s=%s\n" % (n, testenv_vars[n])
529 def switch_env(name, prefix):
531 (envname, option) = name.split(":", 1)
536 env = env_manager.setup_env(envname, prefix)
538 testenv_vars = env.get_vars()
540 if option == "local":
541 socket_wrapper.set_default_iface(testenv_vars["SOCKET_WRAPPER_DEFAULT_IFACE"])
542 os.environ["SMB_CONF_PATH"] = testenv_vars["SERVERCONFFILE"]
543 elif option == "client":
544 socket_wrapper.set_default_iface(11)
545 write_clientconf(conffile, clientdir, testenv_vars)
546 os.environ["SMB_CONF_PATH"] = conffile
548 raise Exception("Unknown option[%s] for envname[%s]" % (option,
551 for name in exported_envvars:
552 if name in testenv_vars:
553 os.environ[name] = testenv_vars[name]
554 elif name in os.environ:
559 # This 'global' file needs to be empty when we start
560 dns_host_file_path = os.path.join(prefix_abs, "dns_host_file")
561 if os.path.exists(dns_host_file_path):
562 os.unlink(dns_host_file_path)
565 testenv_name = os.environ.get("SELFTEST_TESTENV", testenv_default)
567 testenv_vars = switch_env(testenv_name, prefix)
569 os.environ["PIDDIR"] = testenv_vars["PIDDIR"]
570 os.environ["ENVNAME"] = testenv_name
572 envvarstr = exported_envvars_str(testenv_vars)
574 term = os.environ.get("TERMINAL", "xterm -e")
576 Welcome to the Samba4 Test environment '%(testenv_name)'
578 This matches the client environment used in make test
579 server is pid `cat \$PIDDIR/samba.pid`
581 Some useful environment variables:
582 TORTURE_OPTIONS=\$TORTURE_OPTIONS
583 SMB_CONF_PATH=\$SMB_CONF_PATH
586 \" && LD_LIBRARY_PATH=%(LD_LIBRARY_PATH)s $(SHELL)'""" % {
587 "testenv_name": testenv_name,
588 "LD_LIBRARY_PATH": os.environ["LD_LIBRARY_PATH"]}
589 subprocess.call(term + ' ' + cmd, shell=True)
590 env_manager.teardown_env(testenv_name)
592 for (name, envname, cmd, supports_loadfile, supports_idlist, subtests) in todo:
593 if not "$LISTOPT" in cmd:
594 warnings.warn("Unable to list tests in %s" % name)
597 cmd = cmd.replace("$LISTOPT", "--list")
599 exitcode = subprocess.call(cmd, shell=True)
602 sys.stderr.write("%s exited with exit code %s\n" % (cmd, exitcode))
605 for (name, envname, cmd, supports_loadfile, supports_idlist, subtests) in todo:
607 envvars = switch_env(envname, prefix)
608 except UnsupportedEnvironment:
609 subunit_ops.start_testsuite(name)
610 subunit_ops.end_testsuite(name, "skip",
611 "environment %s is unknown in this test backend - skipping" % envname)
614 subunit_ops.start_testsuite(name)
615 traceback.print_exc()
616 subunit_ops.end_testsuite(name, "error",
617 "unable to set up environment %s: %s" % (envname, e))
620 # Generate a file with the individual tests to run, if the
621 # test runner for this test suite supports it.
622 if subtests is not None:
623 if supports_loadfile:
624 (fd, listid_file) = tempfile.mkstemp()
625 # FIXME: Remove tempfile afterwards
628 for test in subtests:
632 cmd = cmd.replace("$LOADLIST", "--load-list=%s" % listid_file)
633 elif supports_idlist:
634 cmd += " ".join(subtests)
636 run_testsuite(envname, name, cmd, i, suitestotal)
638 if opts.resetup_environment:
639 env_manager.teardown_env(envname)
641 sys.stdout.write("\n")
643 env_manager.teardown_all()
645 # if there were any valgrind failures, show them
646 for fn in os.listdir(prefix):
647 if fn.startswith("valgrind.log"):
648 sys.stdout.write("VALGRIND FAILURE\n")
649 f = open(os.path.join(prefix, fn), 'r')
651 sys.stdout.write(f.read())