Chromium Code Reviews| Index: tools/testing/test_runner.py |
| diff --git a/tools/testing/test_runner.py b/tools/testing/test_runner.py |
| index 8bbf7df4660d9e00ccef9d949be24692884f06ed..057de15ecb23adb76741c68c1abcc0ec008522c9 100755 |
| --- a/tools/testing/test_runner.py |
| +++ b/tools/testing/test_runner.py |
| @@ -14,7 +14,6 @@ import threading |
| import traceback |
| import Queue |
| -import test |
| import testing |
| import utils |
| @@ -22,6 +21,164 @@ import utils |
| class Error(Exception): |
| pass |
|
ahe
2011/10/11 07:55:34
Add newline.
zundel
2011/10/11 22:45:44
Done.
|
| +def _CheckedUnlink(name): |
|
zundel
2011/10/11 22:45:44
I changed this method to start with _ as an indica
|
| + try: |
| + os.unlink(name) |
| + except OSError, e: |
| + PrintError("os.unlink() " + str(e)) |
| + |
|
ahe
2011/10/11 07:55:34
Extra line.
zundel
2011/10/11 22:45:44
Done.
|
| + |
| + |
| + |
| +class CommandOutput(object): |
| + |
| + def __init__(self, pid, exit_code, timed_out, stdout, stderr): |
| + self.pid = pid |
| + self.exit_code = exit_code |
| + self.timed_out = timed_out |
| + self.stdout = stdout |
| + self.stderr = stderr |
| + self.failed = None |
| + |
| + |
| +class TestOutput(object): |
| + |
| + def __init__(self, test, command, output): |
| + self.test = test |
| + self.command = command |
| + self.output = output |
| + |
| + def UnexpectedOutput(self): |
| + if self.HasCrashed(): |
| + outcome = testing.CRASH |
| + elif self.HasTimedOut(): |
| + outcome = testing.TIMEOUT |
| + elif self.HasFailed(): |
| + outcome = testing.FAIL |
| + else: |
| + outcome = testing.PASS |
| + return not outcome in self.test.outcomes |
| + |
| + def HasCrashed(self): |
| + if utils.IsWindows(): |
| + if self.output.exit_code == 3: |
| + # The VM uses std::abort to terminate on asserts. |
| + # std::abort terminates with exit code 3 on Windows. |
| + return True |
| + return 0x80000000 & self.output.exit_code and not (0x3FFFFF00 & self.output.exit_code) |
| + else: |
| + # Timed out tests will have exit_code -signal.SIGTERM. |
| + if self.output.timed_out: |
| + return False |
| + if self.output.exit_code == 253: |
| + # The Java dartc runners exit 253 in case of unhandled exceptions. |
| + return True |
| + return self.output.exit_code < 0 |
| + |
| + def HasTimedOut(self): |
| + return self.output.timed_out; |
| + |
| + def HasFailed(self): |
| + execution_failed = self.test.DidFail(self.output) |
| + if self.test.IsNegative(): |
| + return not execution_failed |
| + else: |
| + return execution_failed |
| + |
| + |
| +def Execute(args, context, timeout=None, cwd=None): |
| + (fd_out, outname) = tempfile.mkstemp() |
| + (fd_err, errname) = tempfile.mkstemp() |
| + (process, exit_code, timed_out) = RunProcess( |
| + context, |
| + timeout, |
| + args = args, |
| + stdout = fd_out, |
| + stderr = fd_err, |
| + cwd = cwd |
| + ) |
| + os.close(fd_out) |
| + os.close(fd_err) |
| + output = file(outname).read() |
| + errors = file(errname).read() |
| + _CheckedUnlink(outname) |
| + _CheckedUnlink(errname) |
| + result = CommandOutput(process.pid, exit_code, timed_out, |
| + output, errors) |
| + return result |
| + |
| + |
| +def KillProcessWithID(pid): |
| + if utils.IsWindows(): |
| + os.popen('taskkill /T /F /PID %d' % pid) |
| + else: |
| + os.kill(pid, signal.SIGTERM) |
| + |
| + |
| +MAX_SLEEP_TIME = 0.1 |
| +INITIAL_SLEEP_TIME = 0.0001 |
| +SLEEP_TIME_FACTOR = 1.25 |
| + |
| +SEM_INVALID_VALUE = -1 |
| +SEM_NOGPFAULTERRORBOX = 0x0002 # Microsoft Platform SDK WinBase.h |
| + |
| + |
| +def Win32SetErrorMode(mode): |
| + prev_error_mode = SEM_INVALID_VALUE |
| + try: |
| + import ctypes |
| + prev_error_mode = ctypes.windll.kernel32.SetErrorMode(mode); |
| + except ImportError: |
| + pass |
| + return prev_error_mode |
| + |
| +def RunProcess(context, timeout, args, **rest): |
| + if context.verbose: print "#", " ".join(args) |
| + popen_args = args |
| + prev_error_mode = SEM_INVALID_VALUE; |
| + if utils.IsWindows(): |
| + popen_args = '"' + subprocess.list2cmdline(args) + '"' |
| + if context.suppress_dialogs: |
| + # Try to change the error mode to avoid dialogs on fatal errors. Don't |
| + # touch any existing error mode flags by merging the existing error mode. |
| + # See http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx. |
| + error_mode = SEM_NOGPFAULTERRORBOX; |
| + prev_error_mode = Win32SetErrorMode(error_mode); |
| + Win32SetErrorMode(error_mode | prev_error_mode); |
| + process = subprocess.Popen( |
| + shell = utils.IsWindows(), |
| + args = popen_args, |
| + **rest |
| + ) |
| + if utils.IsWindows() and context.suppress_dialogs and prev_error_mode != SEM_INVALID_VALUE: |
| + Win32SetErrorMode(prev_error_mode) |
| + # Compute the end time - if the process crosses this limit we |
| + # consider it timed out. |
| + if timeout is None: end_time = None |
| + else: end_time = time.time() + timeout |
| + timed_out = False |
| + # Repeatedly check the exit code from the process in a |
| + # loop and keep track of whether or not it times out. |
| + exit_code = None |
| + sleep_time = INITIAL_SLEEP_TIME |
| + while exit_code is None: |
| + if (not end_time is None) and (time.time() >= end_time): |
| + # Kill the process and wait for it to exit. |
| + KillProcessWithID(process.pid) |
| + # Drain the output pipe from the process to avoid deadlock |
| + process.communicate() |
| + exit_code = process.wait() |
| + timed_out = True |
| + else: |
| + exit_code = process.poll() |
| + time.sleep(sleep_time) |
| + sleep_time = sleep_time * SLEEP_TIME_FACTOR |
| + if sleep_time > MAX_SLEEP_TIME: |
| + sleep_time = MAX_SLEEP_TIME |
| + return (process, exit_code, timed_out) |
| + |
| + |
| + |
| class TestRunner(object): |
| """Base class for runners """ |
| def __init__(self, work_queue, tasks, progress): |
| @@ -215,9 +372,9 @@ class BatchRunner(TestRunner): |
| else: |
| assert false, "Unexpected outcome: %s" % outcome |
| - cmd_output = test.CommandOutput(0, exit_code, |
| + cmd_output = CommandOutput(0, exit_code, |
| outcome == testing.TIMEOUT, stdout_buf, "") |
| - test_output = test.TestOutput(case.case, |
| + test_output = TestOutput(case.case, |
| case.case.GetCommand(), |
| cmd_output) |
| with self.progress.lock: |