s4/scripting: in MIT build do not install samba-tool, it is not usable yet
[Samba/vl.git] / selftest / selftest.py
blobaf2e5528b40dd2a7af5cbfaff9d84d91401d052f
1 #!/usr/bin/python -u
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 import atexit
20 from cStringIO import StringIO
21 import os
22 import sys
23 import signal
24 import subprocess
25 import subunit
26 import traceback
27 import warnings
29 import optparse
31 sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
33 from selftest import (
34 socket_wrapper,
35 subunithelper,
36 testlist,
38 from selftest.client import write_clientconf
39 from selftest.run import (
40 expand_command_list,
41 expand_command_run,
42 exported_envvars_str,
43 now,
44 run_testsuite_command,
46 from selftest.target import (
47 EnvironmentManager,
48 NoneTarget,
49 UnsupportedEnvironment,
52 includes = ()
53 excludes = ()
55 def read_excludes(fn):
56 excludes.extend(testlist.read_test_regexes(fn))
58 def read_includes(fn):
59 includes.extend(testlist.read_test_regexes(fn))
61 parser = optparse.OptionParser("TEST-REGEXES")
62 parser.add_option("--target", type="choice", choices=["samba", "samba3", "none"], default="samba", help="Samba version to target")
63 parser.add_option("--quick", help="run quick overall test", action="store_true", default=False)
64 parser.add_option("--list", help="list available tests", action="store_true", default=False)
65 parser.add_option("--socket-wrapper", help="enable socket wrapper", action="store_true", default=False)
66 parser.add_option("--socket-wrapper-pcap", help="save traffic to pcap directories", type="str")
67 parser.add_option("--socket-wrapper-keep-pcap", help="keep all pcap files, not just those for tests that failed", action="store_true", default=False)
68 parser.add_option("--one", help="abort when the first test fails", action="store_true", default=False)
69 parser.add_option("--exclude", action="callback", help="Add file to exclude files", callback=read_excludes)
70 parser.add_option("--include", action="callback", help="Add file to include files", callback=read_includes)
71 parser.add_option("--testenv", help="run a shell in the requested test environment", action="store_true", default=False)
72 parser.add_option("--resetup-environment", help="Re-setup environment", action="store_true", default=False)
73 parser.add_option("--binary-mapping", help="Map binaries to use", type=str)
74 parser.add_option("--load-list", help="Load list of tests to load from a file", type=str)
75 parser.add_option("--prefix", help="prefix to run tests in", type=str, default="./st")
76 parser.add_option("--srcdir", type=str, default=".", help="source directory")
77 parser.add_option("--bindir", type=str, default="./bin", help="binaries directory")
78 parser.add_option("--testlist", type=str, action="append", help="file to read available tests from")
79 parser.add_option("--ldap", help="back samba onto specified ldap server", choices=["openldap", "fedora-ds"], type="choice")
81 opts, args = parser.parse_args()
83 subunit_ops = subunithelper.SubunitOps(sys.stdout)
85 def handle_signal(sig, frame):
86 sys.stderr.write("Exiting early because of signal %s.\n" % sig)
87 sys.exit(1)
89 for sig in (signal.SIGINT, signal.SIGQUIT, signal.SIGTERm, signal.SIGPIPE):
90 signal.signal(sig, handle_signal)
92 def skip(name):
93 return testlist.find_in_list(excludes, name)
95 def setup_pcap(name):
96 if (not opts.socket_wrapper_pcap or
97 not os.environ.get("SOCKET_WRAPPER_PCAP_DIR")):
98 return
100 fname = "".join([x for x in name if x.isalnum() or x == '-'])
102 pcap_file = os.path.join(
103 os.environ["SOCKET_WRAPPER_PCAP_DIR"], "%s.pcap" % fname)
105 socket_wrapper.setup_pcap(pcap_file)
106 return pcap_file
109 def cleanup_pcap(pcap_file, exit_code):
110 if not opts.socket_wrapper_pcap:
111 return
112 if opts.socket_wrapper_keep_pcap:
113 return
114 if exitcode == 0:
115 return
116 if pcap_file is None:
117 return
119 os.unlink(pcap_file)
122 def run_testsuite(name, cmd, subunit_ops, env=None):
123 """Run a single testsuite.
125 :param env: Environment to run in
126 :param name: Name of the testsuite
127 :param cmd: Name of the (fully expanded) command to run
128 :return: exitcode of the command
130 pcap_file = setup_pcap(name)
132 exitcode = run_testsuite_command(name, cmd, subunit_ops, env)
133 if exitcode is None:
134 sys.exit(1)
136 cleanup_pcap(pcap_file, exitcode)
138 if not opts.socket_wrapper_keep_pcap and pcap_file is not None:
139 sys.stdout.write("PCAP FILE: %s\n" % pcap_file)
141 if exitcode != 0 and opts.one:
142 sys.exit(1)
144 return exitcode
147 if opts.list and opts.testenv:
148 sys.stderr.write("--list and --testenv are mutually exclusive\n")
149 sys.exit(1)
151 tests = args
153 # quick hack to disable rpc validation when using valgrind - it is way too slow
154 if not os.environ.get("VALGRIND"):
155 os.environ["VALIDATE"] = "validate"
156 os.environ["MALLOC_CHECK_"] = "2"
158 # make all our python scripts unbuffered
159 os.environ["PYTHONUNBUFFERED"] = "1"
161 bindir_abs = os.path.abspath(opts.bindir)
163 # Backwards compatibility:
164 if os.environ.get("TEST_LDAP") == "yes":
165 if os.environ.get("FEDORA_DS_ROOT"):
166 ldap = "fedora-ds"
167 else:
168 ldap = "openldap"
170 torture_maxtime = int(os.getenv("TORTURE_MAXTIME", "1200"))
171 if opts.ldap:
172 # LDAP is slow
173 torture_maxtime *= 2
175 prefix = os.path.normpath(opts.prefix)
177 # Ensure we have the test prefix around.
179 # We need restrictive permissions on this as some subdirectories in this tree
180 # will have wider permissions (ie 0777) and this would allow other users on the
181 # host to subvert the test process.
182 if not os.path.isdir(prefix):
183 os.mkdir(prefix, 0700)
184 else:
185 os.chmod(prefix, 0700)
187 prefix_abs = os.path.abspath(prefix)
188 tmpdir_abs = os.path.abspath(os.path.join(prefix_abs, "tmp"))
189 if not os.path.isdir(tmpdir_abs):
190 os.mkdir(tmpdir_abs, 0777)
192 srcdir_abs = os.path.abspath(opts.srcdir)
194 if prefix_abs == "/":
195 raise Exception("using '/' as absolute prefix is a bad idea")
197 os.environ["PREFIX"] = prefix
198 os.environ["KRB5CCNAME"] = os.path.join(prefix, "krb5ticket")
199 os.environ["PREFIX_ABS"] = prefix_abs
200 os.environ["SRCDIR"] = opts.srcdir
201 os.environ["SRCDIR_ABS"] = srcdir_abs
202 os.environ["BINDIR"] = bindir_abs
204 tls_enabled = not opts.quick
205 if tls_enabled:
206 os.environ["TLS_ENABLED"] = "yes"
207 else:
208 os.environ["TLS_ENABLED"] = "no"
210 def prefix_pathvar(name, newpath):
211 if name in os.environ:
212 os.environ[name] = "%s:%s" % (newpath, os.environ[name])
213 else:
214 os.environ[name] = newpath
215 prefix_pathvar("PKG_CONFIG_PATH", os.path.join(bindir_abs, "pkgconfig"))
216 prefix_pathvar("PYTHONPATH", os.path.join(bindir_abs, "python"))
218 if opts.socket_wrapper_keep_pcap:
219 # Socket wrapper keep pcap implies socket wrapper pcap
220 opts.socket_wrapper_pcap = True
222 if opts.socket_wrapper_pcap:
223 # Socket wrapper pcap implies socket wrapper
224 opts.socket_wrapper = True
226 if opts.socket_wrapper:
227 socket_wrapper_dir = socket_wrapper.setup_dir(os.path.join(prefix_abs, "w"), opts.socket_wrapper_pcap)
228 sys.stdout.write("SOCKET_WRAPPER_DIR=%s\n" % socket_wrapper_dir)
229 elif not opts.list:
230 if os.getuid() != 0:
231 warnings.warn("not using socket wrapper, but also not running as root. Will not be able to listen on proper ports")
233 testenv_default = "none"
235 if opts.binary_mapping:
236 binary_mapping = dict([l.split(":") for l in opts.binary_mapping.split(",")])
237 os.environ["BINARY_MAPPING"] = opts.binary_mapping
238 else:
239 binary_mapping = {}
240 os.environ["BINARY_MAPPING"] = ""
242 # After this many seconds, the server will self-terminate. All tests
243 # must terminate in this time, and testenv will only stay alive this
244 # long
246 if os.environ.get("SMBD_MAXTIME", ""):
247 server_maxtime = int(os.environ["SMBD_MAXTIME"])
248 else:
249 server_maxtime = 7500
252 def has_socket_wrapper(bindir):
253 """Check if Samba has been built with socket wrapper support.
255 f = StringIO()
256 subprocess.check_call([os.path.join(bindir, "smbd"), "-b"], stdout=f)
257 for l in f.readlines():
258 if "SOCKET_WRAPPER" in l:
259 return True
260 return False
263 if not opts.list:
264 if opts.target == "samba":
265 if opts.socket_wrapper and not has_socket_wrapper(opts.bindir):
266 sys.stderr.write("You must include --enable-socket-wrapper when compiling Samba in order to execute 'make test'. Exiting....\n")
267 sys.exit(1)
268 testenv_default = "dc"
269 from selftest.target.samba import Samba
270 target = Samba(opts.bindir, binary_mapping, ldap, opts.srcdir, server_maxtime)
271 elif opts.target == "samba3":
272 if opts.socket_wrapper and not has_socket_wrapper(opts.bindir):
273 sys.stderr.write("You must include --enable-socket-wrapper when compiling Samba in order to execute 'make test'. Exiting....\n")
274 sys.exit(1)
275 testenv_default = "member"
276 from selftest.target.samba3 import Samba3
277 target = Samba3(opts.bindir, binary_mapping, srcdir_abs, server_maxtime)
278 elif opts.target == "none":
279 testenv_default = "none"
280 target = NoneTarget()
282 env_manager = EnvironmentManager(target)
283 atexit.register(env_manager.teardown_all)
285 interfaces = ",".join([
286 "127.0.0.11/8",
287 "127.0.0.12/8",
288 "127.0.0.13/8",
289 "127.0.0.14/8",
290 "127.0.0.15/8",
291 "127.0.0.16/8"])
293 clientdir = os.path.join(prefix_abs, "client")
295 conffile = os.path.join(clientdir, "client.conf")
296 os.environ["SMB_CONF_PATH"] = conffile
298 todo = []
300 if not opts.testlist:
301 sys.stderr.write("No testlists specified\n")
302 sys.exit(1)
304 os.environ["SELFTEST_PREFIX"] = prefix_abs
305 os.environ["SELFTEST_TMPDIR"] = tmpdir_abs
306 os.environ["TEST_DATA_PREFIX"] = tmpdir_abs
307 if opts.socket_wrapper:
308 os.environ["SELFTEST_INTERFACES"] = interfaces
309 else:
310 os.environ["SELFTEST_INTERFACES"] = ""
311 if opts.quick:
312 os.environ["SELFTEST_QUICK"] = "1"
313 else:
314 os.environ["SELFTEST_QUICK"] = ""
315 os.environ["SELFTEST_MAXTIME"] = str(torture_maxtime)
318 available = []
319 for fn in opts.testlist:
320 for testsuite in testlist.read_testlist_file(fn):
321 if not testlist.should_run_test(tests, testsuite):
322 continue
323 name = testsuite[0]
324 if (includes is not None and
325 testlist.find_in_list(includes, name) is not None):
326 continue
327 available.append(testsuite)
329 if opts.load_list:
330 restricted_mgr = testlist.RestrictedTestManager.from_path(opts.load_list)
331 else:
332 restricted_mgr = None
334 for testsuite in available:
335 name = testsuite[0]
336 skipreason = skip(name)
337 if restricted_mgr is not None:
338 match = restricted_mgr.should_run_testsuite(name)
339 if match == []:
340 continue
341 else:
342 match = None
343 if skipreason is not None:
344 if not opts.list:
345 subunit_ops.skip_testsuite(name, skipreason)
346 else:
347 todo.append(testsuite + (match,))
349 if restricted_mgr is not None:
350 for name in restricted_mgr.iter_unused():
351 sys.stdout.write("No test or testsuite found matching %s\n" % name)
352 if todo == []:
353 sys.stderr.write("No tests to run\n")
354 sys.exit(1)
356 suitestotal = len(todo)
358 if not opts.list:
359 subunit_ops.progress(suitestotal, subunit.PROGRESS_SET)
360 subunit_ops.time(now())
362 exported_envvars = [
363 # domain stuff
364 "DOMAIN",
365 "REALM",
367 # domain controller stuff
368 "DC_SERVER",
369 "DC_SERVER_IP",
370 "DC_NETBIOSNAME",
371 "DC_NETBIOSALIAS",
373 # domain member
374 "MEMBER_SERVER",
375 "MEMBER_SERVER_IP",
376 "MEMBER_NETBIOSNAME",
377 "MEMBER_NETBIOSALIAS",
379 # rpc proxy controller stuff
380 "RPC_PROXY_SERVER",
381 "RPC_PROXY_SERVER_IP",
382 "RPC_PROXY_NETBIOSNAME",
383 "RPC_PROXY_NETBIOSALIAS",
385 # domain controller stuff for Vampired DC
386 "VAMPIRE_DC_SERVER",
387 "VAMPIRE_DC_SERVER_IP",
388 "VAMPIRE_DC_NETBIOSNAME",
389 "VAMPIRE_DC_NETBIOSALIAS",
391 # server stuff
392 "SERVER",
393 "SERVER_IP",
394 "NETBIOSNAME",
395 "NETBIOSALIAS",
397 # user stuff
398 "USERNAME",
399 "USERID",
400 "PASSWORD",
401 "DC_USERNAME",
402 "DC_PASSWORD",
404 # misc stuff
405 "KRB5_CONFIG",
406 "WINBINDD_SOCKET_DIR",
407 "WINBINDD_PRIV_PIPE_DIR",
408 "NMBD_SOCKET_DIR",
409 "LOCAL_PATH"
412 def switch_env(name, prefix):
413 if ":" in name:
414 (envname, option) = name.split(":", 1)
415 else:
416 envname = name
417 option = "client"
419 env = env_manager.setup_env(envname, prefix)
421 testenv_vars = env.get_vars()
423 if option == "local":
424 socket_wrapper.set_default_iface(testenv_vars["SOCKET_WRAPPER_DEFAULT_IFACE"])
425 os.environ["SMB_CONF_PATH"] = testenv_vars["SERVERCONFFILE"]
426 elif option == "client":
427 socket_wrapper.set_default_iface(11)
428 write_clientconf(conffile, clientdir, testenv_vars)
429 os.environ["SMB_CONF_PATH"] = conffile
430 else:
431 raise Exception("Unknown option[%s] for envname[%s]" % (option,
432 envname))
434 for name in exported_envvars:
435 if name in testenv_vars:
436 os.environ[name] = testenv_vars[name]
437 elif name in os.environ:
438 del os.environ[name]
440 return env
442 # This 'global' file needs to be empty when we start
443 dns_host_file_path = os.path.join(prefix_abs, "dns_host_file")
444 if os.path.exists(dns_host_file_path):
445 os.unlink(dns_host_file_path)
447 if opts.testenv:
448 testenv_name = os.environ.get("SELFTEST_TESTENV", testenv_default)
450 env = switch_env(testenv_name, prefix)
451 testenv_vars = env.get_vars()
453 os.environ["PIDDIR"] = testenv_vars["PIDDIR"]
454 os.environ["ENVNAME"] = testenv_name
456 envvarstr = exported_envvars_str(testenv_vars, exported_envvars)
458 term = os.environ.get("TERMINAL", "xterm -e")
459 cmd = """'echo -e "
460 Welcome to the Samba4 Test environment '%(testenv_name)'
462 This matches the client environment used in make test
463 server is pid `cat \$PIDDIR/samba.pid`
465 Some useful environment variables:
466 TORTURE_OPTIONS=\$TORTURE_OPTIONS
467 SMB_CONF_PATH=\$SMB_CONF_PATH
469 $envvarstr
470 \" && LD_LIBRARY_PATH=%(LD_LIBRARY_PATH)s $(SHELL)'""" % {
471 "testenv_name": testenv_name,
472 "LD_LIBRARY_PATH": os.environ["LD_LIBRARY_PATH"]}
473 subprocess.call(term + ' ' + cmd, shell=True)
474 env_manager.teardown_env(testenv_name)
475 elif opts.list:
476 for (name, envname, cmd, supports_loadfile, supports_idlist, subtests) in todo:
477 cmd = expand_command_list(cmd)
478 if cmd is None:
479 warnings.warn("Unable to list tests in %s" % name)
480 continue
482 exitcode = subprocess.call(cmd, shell=True)
484 if exitcode != 0:
485 sys.stderr.write("%s exited with exit code %s\n" % (cmd, exitcode))
486 sys.exit(1)
487 else:
488 for (name, envname, cmd, supports_loadfile, supports_idlist, subtests) in todo:
489 try:
490 env = switch_env(envname, prefix)
491 except UnsupportedEnvironment:
492 subunit_ops.start_testsuite(name)
493 subunit_ops.end_testsuite(name, "skip",
494 "environment %s is unknown in this test backend - skipping" % envname)
495 continue
496 except Exception, e:
497 subunit_ops.start_testsuite(name)
498 traceback.print_exc()
499 subunit_ops.end_testsuite(name, "error",
500 "unable to set up environment %s: %s" % (envname, e))
501 continue
503 cmd, tmpf = expand_command_run(cmd, supports_loadfile, supports_idlist,
504 subtests)
506 run_testsuite(name, cmd, subunit_ops, env=env)
508 if tmpf is not None:
509 os.remove(tmpf)
511 if opts.resetup_environment:
512 env_manager.teardown_env(envname)
513 env_manager.teardown_all()
515 sys.stdout.write("\n")
517 # if there were any valgrind failures, show them
518 for fn in os.listdir(prefix):
519 if fn.startswith("valgrind.log"):
520 sys.stdout.write("VALGRIND FAILURE\n")
521 f = open(os.path.join(prefix, fn), 'r')
522 try:
523 sys.stdout.write(f.read())
524 finally:
525 f.close()
527 sys.exit(0)