Unittest - Allow specifying custom timeout for slow commands.

* Useful when testing with big tasks (1000+ annotations) or sync
operations that take longer than 1 second (default)
This commit is contained in:
Renato Alves
2014-10-16 20:52:17 +01:00
parent b236e78f2e
commit bb060d5ff8
2 changed files with 25 additions and 9 deletions

View File

@@ -177,7 +177,8 @@ class Task(object):
with open(self.taskrc, 'w') as rc: with open(self.taskrc, 'w') as rc:
rc.write("data.location={0}\n" rc.write("data.location={0}\n"
"confirmation=no\n" "confirmation=no\n"
"hooks=off\n".format(self.datadir)) "hooks=off\n"
"".format(self.datadir))
# Setup configuration to talk to taskd automatically # Setup configuration to talk to taskd automatically
if self.taskd is not None: if self.taskd is not None:
@@ -255,7 +256,8 @@ class Task(object):
cmd = (self.taskw, "config", "--", var, value) cmd = (self.taskw, "config", "--", var, value)
return run_cmd_wait(cmd, env=self.env) return run_cmd_wait(cmd, env=self.env)
def runSuccess(self, args=(), input=None, merge_streams=True): def runSuccess(self, args=(), input=None, merge_streams=True,
timeout=1):
"""Invoke task with given arguments and fail if exit code != 0 """Invoke task with given arguments and fail if exit code != 0
Use runError if you want exit_code to be tested automatically and Use runError if you want exit_code to be tested automatically and
@@ -267,6 +269,9 @@ class Task(object):
If merge_streams=True stdout and stderr will be merged into stdout. If merge_streams=True stdout and stderr will be merged into stdout.
timeout = number of seconds the test will wait for every task call.
Defaults to 1 second if not specified. Unit is seconds.
Returns (exit_code, stdout, stderr) Returns (exit_code, stdout, stderr)
""" """
# Create a copy of the command # Create a copy of the command
@@ -274,14 +279,16 @@ class Task(object):
command.extend(args) command.extend(args)
output = run_cmd_wait_nofail(command, input, output = run_cmd_wait_nofail(command, input,
merge_streams=merge_streams, env=self.env) merge_streams=merge_streams,
env=self.env,
timeout=timeout)
if output[0] != 0: if output[0] != 0:
raise CommandError(command, *output) raise CommandError(command, *output)
return output return output
def runError(self, args=(), input=None, merge_streams=True): def runError(self, args=(), input=None, merge_streams=True, timeout=1):
"""Invoke task with given arguments and fail if exit code == 0 """Invoke task with given arguments and fail if exit code == 0
Use runSuccess if you want exit_code to be tested automatically and Use runSuccess if you want exit_code to be tested automatically and
@@ -293,6 +300,9 @@ class Task(object):
If merge_streams=True stdout and stderr will be merged into stdout. If merge_streams=True stdout and stderr will be merged into stdout.
timeout = number of seconds the test will wait for every task call.
Defaults to 1 second if not specified. Unit is seconds.
Returns (exit_code, stdout, stderr) Returns (exit_code, stdout, stderr)
""" """
# Create a copy of the command # Create a copy of the command
@@ -300,7 +310,9 @@ class Task(object):
command.extend(args) command.extend(args)
output = run_cmd_wait_nofail(command, input, output = run_cmd_wait_nofail(command, input,
merge_streams=merge_streams, env=self.env) merge_streams=merge_streams,
env=self.env,
timeout=timeout)
# output[0] is the exit code # output[0] is the exit code
if output[0] == 0 or output[0] is None: if output[0] == 0 or output[0] is None:

View File

@@ -46,6 +46,9 @@ def binary_location(cmd):
def wait_process(proc, timeout=1): def wait_process(proc, timeout=1):
"""Wait for process to finish """Wait for process to finish
""" """
if timeout is None:
timeout = 1
sleeptime = .1 sleeptime = .1
# Max number of attempts until giving up # Max number of attempts until giving up
tries = int(timeout / sleeptime) tries = int(timeout / sleeptime)
@@ -62,7 +65,7 @@ def wait_process(proc, timeout=1):
return exit return exit
def _get_output(proc, input): def _get_output(proc, input, timeout=None):
"""Collect output from the subprocess without blocking the main process if """Collect output from the subprocess without blocking the main process if
subprocess hangs. subprocess hangs.
""" """
@@ -84,7 +87,7 @@ def _get_output(proc, input):
t.start() t.start()
# A task process shouldn't take longer than 1 second to finish # A task process shouldn't take longer than 1 second to finish
exit = wait_process(proc) exit = wait_process(proc, timeout)
# If it does take longer than 1 second, abort it # If it does take longer than 1 second, abort it
if exit is None: if exit is None:
@@ -113,7 +116,7 @@ def _get_output(proc, input):
def run_cmd_wait(cmd, input=None, stdout=PIPE, stderr=PIPE, def run_cmd_wait(cmd, input=None, stdout=PIPE, stderr=PIPE,
merge_streams=False, env=os.environ): merge_streams=False, env=os.environ, timeout=None):
"Run a subprocess and wait for it to finish" "Run a subprocess and wait for it to finish"
if input is None: if input is None:
@@ -128,7 +131,7 @@ def run_cmd_wait(cmd, input=None, stdout=PIPE, stderr=PIPE,
p = Popen(cmd, stdin=stdin, stdout=stdout, stderr=stderr, bufsize=1, p = Popen(cmd, stdin=stdin, stdout=stdout, stderr=stderr, bufsize=1,
close_fds=ON_POSIX, env=env) close_fds=ON_POSIX, env=env)
out, err, exit = _get_output(p, input) out, err, exit = _get_output(p, input, timeout)
if exit != 0: if exit != 0:
raise CommandError(cmd, exit, out, err) raise CommandError(cmd, exit, out, err)
@@ -276,6 +279,7 @@ except ImportError:
return name return name
return None return None
def parse_datafile(file): def parse_datafile(file):
"""Parse .data files on the client and server treating files as JSON """Parse .data files on the client and server treating files as JSON
""" """