vfs:fruit: implement copyfile style copy_chunk
[Samba.git] / selftest / selftest.py
blobef2278d0de66080d54051157ae45c0333d51f37d
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 from samba 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("--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)
86 sys.exit(1)
88 for sig in (signal.SIGINT, signal.SIGQUIT, signal.SIGTERM, signal.SIGPIPE):
89 signal.signal(sig, handle_signal)
91 def skip(name):
92 return testlist.find_in_list(excludes, name)
94 def setup_pcap(name):
95 if (not opts.socket_wrapper_pcap or
96 not os.environ.get("SOCKET_WRAPPER_PCAP_DIR")):
97 return
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)
105 return pcap_file
108 def cleanup_pcap(pcap_file, exit_code):
109 if not opts.socket_wrapper_pcap:
110 return
111 if opts.socket_wrapper_keep_pcap:
112 return
113 if exitcode == 0:
114 return
115 if pcap_file is None:
116 return
118 os.unlink(pcap_file)
121 def run_testsuite(name, cmd, subunit_ops, env=None):
122 """Run a single testsuite.
124 :param env: Environment to run in
125 :param name: Name of the testsuite
126 :param cmd: Name of the (fully expanded) command to run
127 :return: exitcode of the command
129 pcap_file = setup_pcap(name)
131 exitcode = run_testsuite_command(name, cmd, subunit_ops, env)
132 if exitcode is None:
133 sys.exit(1)
135 cleanup_pcap(pcap_file, exitcode)
137 if not opts.socket_wrapper_keep_pcap and pcap_file is not None:
138 sys.stdout.write("PCAP FILE: %s\n" % pcap_file)
140 if exitcode != 0 and opts.one:
141 sys.exit(1)
143 return exitcode
146 if opts.list and opts.testenv:
147 sys.stderr.write("--list and --testenv are mutually exclusive\n")
148 sys.exit(1)
150 tests = args
152 # quick hack to disable rpc validation when using valgrind - it is way too slow
153 if not os.environ.get("VALGRIND"):
154 os.environ["VALIDATE"] = "validate"
155 os.environ["MALLOC_CHECK_"] = "3"
157 # make all our python scripts unbuffered
158 os.environ["PYTHONUNBUFFERED"] = "1"
160 bindir_abs = os.path.abspath(opts.bindir)
162 # Backwards compatibility:
163 if os.environ.get("TEST_LDAP") == "yes":
164 if os.environ.get("FEDORA_DS_ROOT"):
165 ldap = "fedora-ds"
166 else:
167 ldap = "openldap"
169 torture_maxtime = int(os.getenv("TORTURE_MAXTIME", "1200"))
170 if opts.ldap:
171 # LDAP is slow
172 torture_maxtime *= 2
174 prefix = os.path.normpath(opts.prefix)
176 # Ensure we have the test prefix around.
178 # We need restrictive permissions on this as some subdirectories in this tree
179 # will have wider permissions (ie 0777) and this would allow other users on the
180 # host to subvert the test process.
181 if not os.path.isdir(prefix):
182 os.mkdir(prefix, 0700)
183 else:
184 os.chmod(prefix, 0700)
186 prefix_abs = os.path.abspath(prefix)
187 tmpdir_abs = os.path.abspath(os.path.join(prefix_abs, "tmp"))
188 if not os.path.isdir(tmpdir_abs):
189 os.mkdir(tmpdir_abs, 0777)
191 srcdir_abs = os.path.abspath(opts.srcdir)
193 if prefix_abs == "/":
194 raise Exception("using '/' as absolute prefix is a bad idea")
196 os.environ["PREFIX"] = prefix
197 os.environ["KRB5CCNAME"] = os.path.join(prefix, "krb5ticket")
198 os.environ["PREFIX_ABS"] = prefix_abs
199 os.environ["SRCDIR"] = opts.srcdir
200 os.environ["SRCDIR_ABS"] = srcdir_abs
201 os.environ["BINDIR"] = bindir_abs
203 tls_enabled = not opts.quick
204 if tls_enabled:
205 os.environ["TLS_ENABLED"] = "yes"
206 else:
207 os.environ["TLS_ENABLED"] = "no"
209 def prefix_pathvar(name, newpath):
210 if name in os.environ:
211 os.environ[name] = "%s:%s" % (newpath, os.environ[name])
212 else:
213 os.environ[name] = newpath
214 prefix_pathvar("PKG_CONFIG_PATH", os.path.join(bindir_abs, "pkgconfig"))
215 prefix_pathvar("PYTHONPATH", os.path.join(bindir_abs, "python"))
217 if opts.socket_wrapper_keep_pcap:
218 # Socket wrapper keep pcap implies socket wrapper pcap
219 opts.socket_wrapper_pcap = True
221 if opts.socket_wrapper_pcap:
222 # Socket wrapper pcap implies socket wrapper
223 opts.socket_wrapper = True
225 if opts.socket_wrapper:
226 socket_wrapper_dir = socket_wrapper.setup_dir(os.path.join(prefix_abs, "w"), opts.socket_wrapper_pcap)
227 sys.stdout.write("SOCKET_WRAPPER_DIR=%s\n" % socket_wrapper_dir)
228 elif not opts.list:
229 if os.getuid() != 0:
230 warnings.warn("not using socket wrapper, but also not running as root. Will not be able to listen on proper ports")
232 testenv_default = "none"
234 # After this many seconds, the server will self-terminate. All tests
235 # must terminate in this time, and testenv will only stay alive this
236 # long
238 if os.environ.get("SMBD_MAXTIME", ""):
239 server_maxtime = int(os.environ["SMBD_MAXTIME"])
240 else:
241 server_maxtime = 7500
244 def has_socket_wrapper(bindir):
245 """Check if Samba has been built with socket wrapper support.
247 f = StringIO()
248 subprocess.check_call([os.path.join(bindir, "smbd"), "-b"], stdout=f)
249 for l in f.readlines():
250 if "SOCKET_WRAPPER" in l:
251 return True
252 return False
255 if not opts.list:
256 if opts.target == "samba":
257 if opts.socket_wrapper and not has_socket_wrapper(opts.bindir):
258 sys.stderr.write("You must include --enable-socket-wrapper when compiling Samba in order to execute 'make test'. Exiting....\n")
259 sys.exit(1)
260 testenv_default = "ad_dc_ntvfs"
261 from selftest.target.samba import Samba
262 target = Samba(opts.bindir, ldap, opts.srcdir, server_maxtime)
263 elif opts.target == "samba3":
264 if opts.socket_wrapper and not has_socket_wrapper(opts.bindir):
265 sys.stderr.write("You must include --enable-socket-wrapper when compiling Samba in order to execute 'make test'. Exiting....\n")
266 sys.exit(1)
267 testenv_default = "member"
268 from selftest.target.samba3 import Samba3
269 target = Samba3(opts.bindir, srcdir_abs, server_maxtime)
270 elif opts.target == "none":
271 testenv_default = "none"
272 target = NoneTarget()
274 env_manager = EnvironmentManager(target)
275 atexit.register(env_manager.teardown_all)
277 interfaces = ",".join([
278 "127.0.0.11/8",
279 "127.0.0.12/8",
280 "127.0.0.13/8",
281 "127.0.0.14/8",
282 "127.0.0.15/8",
283 "127.0.0.16/8"])
285 clientdir = os.path.join(prefix_abs, "client")
287 conffile = os.path.join(clientdir, "client.conf")
288 os.environ["SMB_CONF_PATH"] = conffile
290 todo = []
292 if not opts.testlist:
293 sys.stderr.write("No testlists specified\n")
294 sys.exit(1)
296 os.environ["SELFTEST_PREFIX"] = prefix_abs
297 os.environ["SELFTEST_TMPDIR"] = tmpdir_abs
298 os.environ["TEST_DATA_PREFIX"] = tmpdir_abs
299 if opts.socket_wrapper:
300 os.environ["SELFTEST_INTERFACES"] = interfaces
301 else:
302 os.environ["SELFTEST_INTERFACES"] = ""
303 if opts.quick:
304 os.environ["SELFTEST_QUICK"] = "1"
305 else:
306 os.environ["SELFTEST_QUICK"] = ""
307 os.environ["SELFTEST_MAXTIME"] = str(torture_maxtime)
310 available = []
311 for fn in opts.testlist:
312 for testsuite in testlist.read_testlist_file(fn):
313 if not testlist.should_run_test(tests, testsuite):
314 continue
315 name = testsuite[0]
316 if (includes is not None and
317 testlist.find_in_list(includes, name) is not None):
318 continue
319 available.append(testsuite)
321 if opts.load_list:
322 restricted_mgr = testlist.RestrictedTestManager.from_path(opts.load_list)
323 else:
324 restricted_mgr = None
326 for testsuite in available:
327 name = testsuite[0]
328 skipreason = skip(name)
329 if restricted_mgr is not None:
330 match = restricted_mgr.should_run_testsuite(name)
331 if match == []:
332 continue
333 else:
334 match = None
335 if skipreason is not None:
336 if not opts.list:
337 subunit_ops.skip_testsuite(name, skipreason)
338 else:
339 todo.append(testsuite + (match,))
341 if restricted_mgr is not None:
342 for name in restricted_mgr.iter_unused():
343 sys.stdout.write("No test or testsuite found matching %s\n" % name)
344 if todo == []:
345 sys.stderr.write("No tests to run\n")
346 sys.exit(1)
348 suitestotal = len(todo)
350 if not opts.list:
351 subunit_ops.progress(suitestotal, subunit.PROGRESS_SET)
352 subunit_ops.time(now())
354 exported_envvars = [
355 # domain stuff
356 "DOMAIN",
357 "REALM",
359 # domain controller stuff
360 "DC_SERVER",
361 "DC_SERVER_IP",
362 "DC_NETBIOSNAME",
363 "DC_NETBIOSALIAS",
365 # domain member
366 "MEMBER_SERVER",
367 "MEMBER_SERVER_IP",
368 "MEMBER_NETBIOSNAME",
369 "MEMBER_NETBIOSALIAS",
371 # rpc proxy controller stuff
372 "RPC_PROXY_SERVER",
373 "RPC_PROXY_SERVER_IP",
374 "RPC_PROXY_NETBIOSNAME",
375 "RPC_PROXY_NETBIOSALIAS",
377 # domain controller stuff for Vampired DC
378 "VAMPIRE_DC_SERVER",
379 "VAMPIRE_DC_SERVER_IP",
380 "VAMPIRE_DC_NETBIOSNAME",
381 "VAMPIRE_DC_NETBIOSALIAS",
383 # domain controller stuff for Vampired DC
384 "PROMOTED_DC_SERVER",
385 "PROMOTED_DC_SERVER_IP",
386 "PROMOTED_DC_NETBIOSNAME",
387 "PROMOTED_DC_NETBIOSALIAS",
389 # server stuff
390 "SERVER",
391 "SERVER_IP",
392 "NETBIOSNAME",
393 "NETBIOSALIAS",
395 # user stuff
396 "USERNAME",
397 "USERID",
398 "PASSWORD",
399 "DC_USERNAME",
400 "DC_PASSWORD",
402 # misc stuff
403 "KRB5_CONFIG",
404 "WINBINDD_SOCKET_DIR",
405 "WINBINDD_PRIV_PIPE_DIR",
406 "NMBD_SOCKET_DIR",
407 "LOCAL_PATH"
410 def switch_env(name, prefix):
411 if ":" in name:
412 (envname, option) = name.split(":", 1)
413 else:
414 envname = name
415 option = "client"
417 env = env_manager.setup_env(envname, prefix)
419 testenv_vars = env.get_vars()
421 if option == "local":
422 socket_wrapper.set_default_iface(testenv_vars["SOCKET_WRAPPER_DEFAULT_IFACE"])
423 os.environ["SMB_CONF_PATH"] = testenv_vars["SERVERCONFFILE"]
424 elif option == "client":
425 socket_wrapper.set_default_iface(11)
426 write_clientconf(conffile, clientdir, testenv_vars)
427 os.environ["SMB_CONF_PATH"] = conffile
428 else:
429 raise Exception("Unknown option[%s] for envname[%s]" % (option,
430 envname))
432 for name in exported_envvars:
433 if name in testenv_vars:
434 os.environ[name] = testenv_vars[name]
435 elif name in os.environ:
436 del os.environ[name]
438 return env
440 # This 'global' file needs to be empty when we start
441 dns_host_file_path = os.path.join(prefix_abs, "dns_host_file")
442 if os.path.exists(dns_host_file_path):
443 os.unlink(dns_host_file_path)
445 if opts.testenv:
446 testenv_name = os.environ.get("SELFTEST_TESTENV", testenv_default)
448 env = switch_env(testenv_name, prefix)
449 testenv_vars = env.get_vars()
451 os.environ["PIDDIR"] = testenv_vars["PIDDIR"]
452 os.environ["ENVNAME"] = testenv_name
454 envvarstr = exported_envvars_str(testenv_vars, exported_envvars)
456 term = os.environ.get("TERMINAL", "xterm -e")
457 cmd = """'echo -e "
458 Welcome to the Samba4 Test environment '%(testenv_name)'
460 This matches the client environment used in make test
461 server is pid `cat \$PIDDIR/samba.pid`
463 Some useful environment variables:
464 TORTURE_OPTIONS=\$TORTURE_OPTIONS
465 SMB_CONF_PATH=\$SMB_CONF_PATH
467 $envvarstr
468 \" && LD_LIBRARY_PATH=%(LD_LIBRARY_PATH)s $(SHELL)'""" % {
469 "testenv_name": testenv_name,
470 "LD_LIBRARY_PATH": os.environ["LD_LIBRARY_PATH"]}
471 subprocess.call(term + ' ' + cmd, shell=True)
472 env_manager.teardown_env(testenv_name)
473 elif opts.list:
474 for (name, envname, cmd, supports_loadfile, supports_idlist, subtests) in todo:
475 cmd = expand_command_list(cmd)
476 if cmd is None:
477 warnings.warn("Unable to list tests in %s" % name)
478 continue
480 exitcode = subprocess.call(cmd, shell=True)
482 if exitcode != 0:
483 sys.stderr.write("%s exited with exit code %s\n" % (cmd, exitcode))
484 sys.exit(1)
485 else:
486 for (name, envname, cmd, supports_loadfile, supports_idlist, subtests) in todo:
487 try:
488 env = switch_env(envname, prefix)
489 except UnsupportedEnvironment:
490 subunit_ops.start_testsuite(name)
491 subunit_ops.end_testsuite(name, "skip",
492 "environment %s is unknown in this test backend - skipping" % envname)
493 continue
494 except Exception, e:
495 subunit_ops.start_testsuite(name)
496 traceback.print_exc()
497 subunit_ops.end_testsuite(name, "error",
498 "unable to set up environment %s: %s" % (envname, e))
499 continue
501 cmd, tmpf = expand_command_run(cmd, supports_loadfile, supports_idlist,
502 subtests)
504 run_testsuite(name, cmd, subunit_ops, env=env)
506 if tmpf is not None:
507 os.remove(tmpf)
509 if opts.resetup_environment:
510 env_manager.teardown_env(envname)
511 env_manager.teardown_all()
513 sys.stdout.write("\n")
515 # if there were any valgrind failures, show them
516 for fn in os.listdir(prefix):
517 if fn.startswith("valgrind.log"):
518 sys.stdout.write("VALGRIND FAILURE\n")
519 f = open(os.path.join(prefix, fn), 'r')
520 try:
521 sys.stdout.write(f.read())
522 finally:
523 f.close()
525 sys.exit(0)