selftest.py: Move some infrastructure for running commands to selftest.run, with...
[sharpe/samba-autobuild/.git] / selftest / run.py
1 #!/usr/bin/python -u
2 # Bootstrap Samba and run a number of tests against it.
3 # Copyright (C) 2012 Jelmer Vernooij <jelmer@samba.org>
4
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
9
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14
15 # You should have received a copy of the GNU General Public License
16 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18 """Test command running."""
19
20 import datetime
21 import iso8601
22 import os
23 import subprocess
24 import subunit
25 import sys
26 import tempfile
27 import warnings
28
29 # expand strings from %ENV
30 def expand_environment_strings(s, vars):
31     # we use a reverse sort so we do the longer ones first
32     for k in sorted(vars.keys(), reverse=True):
33         v = vars[k]
34         s = s.replace("$%s" % k, v)
35     return s
36
37
38 def expand_command_list(cmd):
39     if not "$LISTOPT" in cmd:
40         return None
41     return cmd.replace("$LISTOPT", "--list")
42
43
44 def expand_command_run(cmd, supports_loadfile, supports_idlist, subtests=None):
45     """Expand a test command.
46
47     :param cmd: Command to expand
48     :param supports_loadfile: Whether command supports loadfile
49     :param supports_idlist: Whether the command supports running specific
50         subtests
51     :param subtests: List of subtests to run - None for all subtests
52     :return: Tuple with command to run and temporary file to remove after
53         running (or None)
54     """
55     # Generate a file with the individual tests to run, if the
56     # test runner for this test suite supports it.
57     if subtests is None:
58         return (cmd.replace("$LOADLIST", ""), None)
59     if supports_loadfile:
60         (fd, listid_file) = tempfile.mkstemp()
61         f = os.fdopen(fd, 'w')
62         try:
63             for test in subtests:
64                 f.write(test+"\n")
65         finally:
66             f.close()
67         return (
68             cmd.replace("$LOADLIST", "--load-list=%s" % listid_file),
69             listid_file)
70     elif supports_idlist:
71         cmd += " " + " ".join(subtests)
72         return (cmd, None)
73     else:
74         warnings.warn(
75             "Running subtests requested, but command does not support "
76             "this.")
77         return (cmd, None)
78
79
80 def exported_envvars_str(vars, names):
81     out = ""
82     for n in names:
83         if not n in vars:
84             continue
85         out += "%s=%s\n" % (n, vars[n])
86     return out
87
88
89 def now():
90     """Return datetime instance for current time in UTC.
91     """
92     return datetime.datetime.utcnow().replace(tzinfo=iso8601.iso8601.Utc())
93
94
95 def run_testsuite_command(name, cmd, subunit_ops, env=None, outf=None):
96     """Run a testsuite command.
97
98     :param name: Name of the testsuite
99     :param cmd: Command to run
100     :param subunit_ops: Subunit ops to use for reporting results
101     :param env: Environment the test is run in
102     :param outf: File-like object to write standard out to (defaults to sys.stdout)
103     :return: Exit code or None if the test failed to run completely
104     """
105     if outf is None:
106         outf = sys.stdout
107     subunit_ops.start_testsuite(name)
108     subunit_ops.progress(None, subunit.PROGRESS_PUSH)
109     subunit_ops.time(now())
110     try:
111         exitcode = subprocess.call(cmd, shell=True, stdout=outf)
112     except Exception, e:
113         subunit_ops.time(now())
114         subunit_ops.progress(None, subunit.PROGRESS_POP)
115         subunit_ops.end_testsuite(name, "error", "Unable to run %r: %s" % (cmd, e))
116         return None
117
118     subunit_ops.time(now())
119     subunit_ops.progress(None, subunit.PROGRESS_POP)
120
121     if env is not None:
122         envlog = env.get_log()
123         if envlog != "":
124             outf.write("envlog: %s\n" % envlog)
125
126     outf.write("command: %s\n" % cmd)
127     outf.write("expanded command: %s\n" % expand_environment_strings(cmd, os.environ))
128
129     if exitcode == 0:
130         subunit_ops.end_testsuite(name, "success")
131     else:
132         subunit_ops.end_testsuite(name, "failure", "Exit code was %d" % exitcode)
133
134     return exitcode