summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2013-11-12 11:21:08 +0100
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-11-13 12:23:41 +0100
commit1ddd80fd1d7e06f26f7d6a34123ace7f63e6ead8 (patch)
treea289df97387e02f078f369830b736b487511b80f
parenta7f7b4d7257ab8dd778afc853657877eecd8b9f2 (diff)
framework: Add support for a test timeout
i-g-t tests can take a long time, and for a bunch of reasons (bad tuning on disparate set of platforms, stuck in the kernel which often can be recovered by interrupting with a signal, ...) that sometimes extends to a good approximation of forever. Hence this adds a per-test timeout value and a bit of infrastructure to adjust the results. Test results adjusting is done after calling interpretResult so that we don't have to replicate this all over the place. This might need to be adjusted for the piglit-native subtest stuff, but otoh igt is a bit special with it's crazy long-running tests. So I think we can fix this once it's actually needed. The default timeout is None, so this is purely opt-in. Note on the implementation: SIG_ALARM doesn't exists on Windows and stackoverflow overwhelmingly recommended to go with this thread-based approach here. But only tested on my Linux box here.
-rw-r--r--framework/exectest.py28
1 files changed, 25 insertions, 3 deletions
diff --git a/framework/exectest.py b/framework/exectest.py
index 986d8032..32b00622 100644
--- a/framework/exectest.py
+++ b/framework/exectest.py
@@ -23,6 +23,7 @@
import errno
import os
import subprocess
+import threading
import shlex
import types
import re
@@ -72,6 +73,7 @@ class ExecTest(Test):
self.command = command
self.split_command = os.path.split(self.command[0])[1]
self.env = {}
+ self.timeout = None
if isinstance(self.command, basestring):
self.command = shlex.split(str(self.command))
@@ -113,7 +115,7 @@ class ExecTest(Test):
else:
if env.dmesg:
old_dmesg = read_dmesg()
- (out, err, returncode) = \
+ (out, err, returncode, timeout) = \
self.get_command_result(command, fullenv)
if env.dmesg:
dmesg_diff = get_dmesg_diff(old_dmesg, read_dmesg())
@@ -172,6 +174,9 @@ class ExecTest(Test):
elif returncode != 0:
results['note'] = 'Returncode was {0}'.format(returncode)
+ if timeout:
+ results['result'] = 'timeout'
+
if env.valgrind:
# If the underlying test failed, simply report
# 'skip' for this valgrind test.
@@ -196,6 +201,7 @@ class ExecTest(Test):
results['returncode'] = returncode
results['command'] = ' '.join(self.command)
results['dmesg'] = dmesg_diff
+ results['timeout'] = timeout
self.handleErr(results, err)
@@ -222,7 +228,23 @@ class ExecTest(Test):
stderr=subprocess.PIPE,
env=fullenv,
universal_newlines=True)
- out, err = proc.communicate()
+ out = ''
+ err = ''
+
+ def thread_fn():
+ out, err = proc.communicate()
+
+ thread = threading.Thread(target=thread_fn)
+ thread.start()
+
+ thread.join(self.timeout)
+
+ if thread.is_alive():
+ proc.terminate()
+ thread.join()
+ timeout = True
+ else:
+ timeout = False
returncode = proc.returncode
except OSError as e:
# Different sets of tests get built under
@@ -237,7 +259,7 @@ class ExecTest(Test):
returncode = None
else:
raise e
- return out, err, returncode
+ return out, err, returncode, timeout
class PlainExecTest(ExecTest):