# # run_tests.py - run the tests in the regression test suite. # '''usage: python run_tests.py [--url=] [--fs-type=] [--verbose] [--cleanup] The optional base-url, fs-type, verbose, and cleanup options, and the first four parameters are passed unchanged to the TestHarness constuctor. All other parameters are names of test programs. ''' import os, sys import getopt try: my_getopt = getopt.gnu_getopt except AttributeError: my_getopt = getopt.getopt class TestHarness: '''Test harness for Subversion tests. ''' def __init__(self, abs_srcdir, abs_builddir, logfile, base_url=None, fs_type=None, verbose=None, cleanup=None): '''Construct a TestHarness instance. ABS_SRCDIR and ABS_BUILDDIR are the source and build directories. LOGFILE is the name of the log file. BASE_URL is the base url for DAV tests. FS_TYPE is the FS type for repository creation. ''' self.srcdir = abs_srcdir self.builddir = abs_builddir self.logfile = logfile self.base_url = base_url self.fs_type = fs_type self.verbose = verbose self.cleanup = cleanup self.log = None def run(self, list): 'Run all test programs given in LIST.' self._open_log('w') failed = 0 for prog in list: failed = self._run_test(prog) or failed self._open_log('r') log_lines = self.log.readlines() skipped = filter(lambda x: x[:6] == 'SKIP: ', log_lines) if failed: print 'At least one test FAILED, checking ' + self.logfile map(sys.stdout.write, filter(lambda x: x[:6] in ('FAIL: ', 'XPASS:'), log_lines)) if skipped: print 'At least one test was SKIPPED, checking ' + self.logfile map(sys.stdout.write, skipped) self._close_log() return failed def _open_log(self, mode): 'Open the log file with the required MODE.' self._close_log() self.log = open(self.logfile, mode) def _close_log(self): 'Close the log file.' if not self.log is None: self.log.close() self.log = None def _run_test(self, prog): 'Run a single test.' def quote(arg): if sys.platform == 'win32': return '"' + arg + '"' else: return arg progdir, progbase = os.path.split(prog) # Using write here because we don't want even a trailing space sys.stdout.write('Running all tests in ' + progbase + '...') print >> self.log, 'START: ' + progbase if progbase[-3:] == '.py': progname = sys.executable cmdline = [quote(progname), quote(os.path.join(self.srcdir, prog))] if self.verbose is not None: cmdline.append('--verbose') if self.cleanup is not None: cmdline.append('--cleanup') if self.base_url is not None: cmdline.append(quote('--url=' + self.base_url)) if self.fs_type is not None: cmdline.append(quote('--fs-type=' + self.fs_type)) elif os.access(prog, os.X_OK): progname = './' + progbase cmdline = [quote(progname), quote('--srcdir=' + os.path.join(self.srcdir, progdir))] if self.verbose is not None: cmdline.append('--verbose') if self.cleanup is not None: cmdline.append('--cleanup') if self.fs_type is not None: cmdline.append(quote('--fs-type=' + self.fs_type)) else: print 'Don\'t know what to do about ' + progbase sys.exit(1) old_cwd = os.getcwd() try: os.chdir(progdir) failed = self._run_prog(progname, cmdline) except: os.chdir(old_cwd) raise else: os.chdir(old_cwd) if failed: print 'FAILURE' else: print 'success' print >> self.log, 'END: ' + progbase + '\n' return failed def _run_prog(self, progname, cmdline): 'Execute COMMAND, redirecting standard output and error to the log file.' def restore_streams(stdout, stderr): os.dup2(stdout, 1) os.dup2(stderr, 2) os.close(stdout) os.close(stderr) sys.stdout.flush() sys.stderr.flush() self.log.flush() old_stdout = os.dup(1) old_stderr = os.dup(2) try: os.dup2(self.log.fileno(), 1) os.dup2(self.log.fileno(), 2) rv = os.spawnv(os.P_WAIT, progname, cmdline) except: restore_streams(old_stdout, old_stderr) raise else: restore_streams(old_stdout, old_stderr) return rv def main(): try: opts, args = my_getopt(sys.argv[1:], 'u:f:vc', ['url=', 'fs-type=', 'verbose', 'cleanup']) except getopt.GetoptError: args = [] if len(args) < 3: print __doc__ sys.exit(2) base_url, fs_type, verbose, cleanup = None, None, None, None for opt, val in opts: if opt in ('-u', '--url'): base_url = val elif opt in ('-f', '--fs-type'): fs_type = val elif opt in ('-v', '--verbose'): verbose = 1 elif opt in ('-c', '--cleanup'): cleanup = 1 else: raise getopt.GetoptError th = TestHarness(args[0], args[1], os.path.abspath('tests.log'), base_url, fs_type, verbose, cleanup) failed = th.run(args[2:]) if failed: sys.exit(1) # Run main if not imported as a module if __name__ == '__main__': main()