Commit 9d7e6847 authored by Denis Bilenko's avatar Denis Bilenko

simplify testrunner: remove 'name' from util

always calculate it from environ and file name
parent 02169226
...@@ -29,8 +29,8 @@ def TESTRUNNER(tests=None): ...@@ -29,8 +29,8 @@ def TESTRUNNER(tests=None):
atexit.register(os.system, 'rm -f */@test*_tmp') atexit.register(os.system, 'rm -f */@test*_tmp')
for filename in tests: for filename in tests:
yield directory + '/' + filename, [sys.executable, '-u', '-m', 'monkey_test', filename], options.copy() yield [sys.executable, '-u', '-m', 'monkey_test', filename], options.copy()
yield directory + '/' + filename + '/Event', [sys.executable, '-u', '-m', 'monkey_test', '--Event', filename], options.copy() yield [sys.executable, '-u', '-m', 'monkey_test', '--Event', filename], options.copy()
def main(): def main():
......
...@@ -5,6 +5,7 @@ from gevent import monkey; monkey.patch_all() ...@@ -5,6 +5,7 @@ from gevent import monkey; monkey.patch_all()
import sys import sys
import os import os
import glob import glob
import traceback
from time import time from time import time
from gevent.pool import Pool from gevent.pool import Pool
...@@ -18,57 +19,35 @@ pool = None ...@@ -18,57 +19,35 @@ pool = None
def spawn(*args, **kwargs): def spawn(*args, **kwargs):
g = pool.spawn(*args, **kwargs) g = pool.spawn(*args, **kwargs)
g.link_exception(lambda *args: sys.exit('Internal error')) g.link_exception(lambda *args: sys.exit('Internal error in testrunner.py'))
return g return g
def process_test(name, cmd, options):
options = options or {}
setenv = options.get('setenv', {}).copy()
setenv.pop('PYTHONPATH', '')
environ = options.get('env')
if environ is None:
environ = os.environ.copy()
for key, value in environ.items():
if key.startswith('GEVENT_') or key.startswith('GEVENTARES_'):
if key not in setenv:
setenv[key] = value
env_str = ' '.join('%s=%s' % x for x in setenv.items())
if env_str and env_str not in name:
name = env_str + ' ' + name
return name, cmd, options
def process_tests(tests):
return [process_test(name, cmd, options) for (name, cmd, options) in tests]
def run_many(tests, expected=None, failfast=False): def run_many(tests, expected=None, failfast=False):
global NWORKERS, pool global NWORKERS, pool
start = time() start = time()
total = 0 total = 0
failed = {} failed = {}
tests = process_tests(tests)
NWORKERS = min(len(tests), NWORKERS) NWORKERS = min(len(tests), NWORKERS)
pool = Pool(NWORKERS) pool = Pool(NWORKERS)
util.BUFFER_OUTPUT = NWORKERS > 1 util.BUFFER_OUTPUT = NWORKERS > 1
def run_one(name, cmd, **kwargs): def run_one(cmd, **kwargs):
result = util.run(cmd, name=name, **kwargs) result = util.run(cmd, **kwargs)
if result: if result:
if failfast: if failfast:
sys.exit(1) sys.exit(1)
# the tests containing AssertionError might have failed because # the tests containing AssertionError might have failed because
# we spawned more workers than CPUs # we spawned more workers than CPUs
# we therefore will retry them sequentially # we therefore will retry them sequentially
failed[name] = [cmd, kwargs, 'AssertionError' in (result.output or '')] failed[result.name] = [cmd, kwargs, 'AssertionError' in (result.output or '')]
try: try:
try: try:
for name, cmd, options in tests: for cmd, options in tests:
total += 1 total += 1
spawn(run_one, name, cmd, **options) spawn(run_one, cmd, **(options or {}))
gevent.wait() gevent.wait()
except KeyboardInterrupt: except KeyboardInterrupt:
try: try:
...@@ -80,6 +59,7 @@ def run_many(tests, expected=None, failfast=False): ...@@ -80,6 +59,7 @@ def run_many(tests, expected=None, failfast=False):
util.log('(partial results)\n') util.log('(partial results)\n')
raise raise
except: except:
traceback.print_exc()
pool.kill() # this needed to kill the processes pool.kill() # this needed to kill the processes
raise raise
...@@ -89,7 +69,7 @@ def run_many(tests, expected=None, failfast=False): ...@@ -89,7 +69,7 @@ def run_many(tests, expected=None, failfast=False):
if NWORKERS > 1 and toretry: if NWORKERS > 1 and toretry:
util.log('\nWill retry %s failed tests without concurrency:\n- %s\n', len(toretry), '\n- '.join(toretry)) util.log('\nWill retry %s failed tests without concurrency:\n- %s\n', len(toretry), '\n- '.join(toretry))
for name, (cmd, kwargs, _ignore) in failed.items(): for name, (cmd, kwargs, _ignore) in failed.items():
if not util.run(cmd, name=name, buffer_output=False, **kwargs): if not util.run(cmd, buffer_output=False, **kwargs):
failed.pop(name) failed.pop(name)
failed_then_succeeded.append(name) failed_then_succeeded.append(name)
...@@ -120,12 +100,12 @@ def discover(tests=None, ignore=None): ...@@ -120,12 +100,12 @@ def discover(tests=None, ignore=None):
for filename in tests: for filename in tests:
if 'TESTRUNNER' in open(filename).read(): if 'TESTRUNNER' in open(filename).read():
module = __import__(filename.rsplit('.', 1)[0]) module = __import__(filename.rsplit('.', 1)[0])
for name, cmd, options in module.TESTRUNNER(): for cmd, options in module.TESTRUNNER():
if remove_options(cmd)[-1] in ignore: if remove_options(cmd)[-1] in ignore:
continue continue
to_process.append((filename + ' ' + name, cmd, options)) to_process.append((cmd, options))
else: else:
to_process.append((filename, [sys.executable, '-u', filename], default_options.copy())) to_process.append(([sys.executable, '-u', filename], default_options.copy()))
return to_process return to_process
...@@ -150,14 +130,14 @@ def full(args=None): ...@@ -150,14 +130,14 @@ def full(args=None):
for setenv, ignore in [('GEVENT_RESOLVER=thread', None), for setenv, ignore in [('GEVENT_RESOLVER=thread', None),
('GEVENT_RESOLVER=ares GEVENTARES_SERVERS=8.8.8.8', 'tests_that_dont_use_resolver.txt')]: ('GEVENT_RESOLVER=ares GEVENTARES_SERVERS=8.8.8.8', 'tests_that_dont_use_resolver.txt')]:
setenv = dict(x.split('=') for x in setenv.split()) setenv = dict(x.split('=') for x in setenv.split())
for name, cmd, options in discover(args, ignore=ignore): for cmd, options in discover(args, ignore=ignore):
my_setenv = options.get('setenv', {}) my_setenv = options.get('setenv', {})
my_setenv.update(setenv) my_setenv.update(setenv)
options['setenv'] = my_setenv options['setenv'] = my_setenv
tests.append((name, cmd, options)) tests.append((cmd, options))
if sys.version_info[:2] == (2, 7): if sys.version_info[:2] == (2, 7):
tests.append(('xtest_pep8.py', [sys.executable, '-u', 'xtest_pep8.py'], None)) tests.append(([sys.executable, '-u', 'xtest_pep8.py'], None))
return tests return tests
...@@ -178,8 +158,8 @@ def main(): ...@@ -178,8 +158,8 @@ def main():
else: else:
tests = discover(args, options.ignore) tests = discover(args, options.ignore)
if options.discover: if options.discover:
for name, cmd, options in process_tests(tests): for cmd, options in tests:
print '%s: %s' % (name, ' '.join(cmd)) print util.getname(cmd, env=options.get('env'), setenv=options.get('setenv'))
print '%s tests found.' % len(tests) print '%s tests found.' % len(tests)
else: else:
run_many(tests, expected=options.expected, failfast=options.failfast) run_many(tests, expected=options.expected, failfast=options.failfast)
......
...@@ -97,20 +97,33 @@ def kill(popen): ...@@ -97,20 +97,33 @@ def kill(popen):
traceback.print_exc() traceback.print_exc()
def getname(command): def getname(command, env=None, setenv=None):
return ' '.join(command) result = []
for key, value in sorted((env or {}).items()):
if key.startswith('GEVENT_') or key.startswith('GEVENTARES_'):
result.append('%s=%s' % (key, value))
for key, value in sorted((setenv or {}).items()):
if key.startswith('GEVENT_') or key.startswith('GEVENTARES_'):
result.append('%s=%s' % (key, value))
if isinstance(command, basestring):
result.append(command)
else:
result.extend(command)
return ' '.join(result)
def start(command, **kwargs): def start(command, **kwargs):
# XXX should not really need 'name' there: can still figure it out
# from command + environment vars starting with GEVENT_ and GEVENTARES_
name = kwargs.pop('name', None) or getname(command)
timeout = kwargs.pop('timeout', None) timeout = kwargs.pop('timeout', None)
preexec_fn = None preexec_fn = None
if not os.environ.get('DO_NOT_SETPGRP'): if not os.environ.get('DO_NOT_SETPGRP'):
preexec_fn = getattr(os, 'setpgrp', None) preexec_fn = getattr(os, 'setpgrp', None)
env = kwargs.pop('env', None) env = kwargs.pop('env', None)
setenv = kwargs.pop('setenv', None) or {} setenv = kwargs.pop('setenv', None) or {}
name = getname(command, env=env, setenv=setenv)
if preexec_fn is not None: if preexec_fn is not None:
setenv['DO_NOT_SETPGRP'] = '1' setenv['DO_NOT_SETPGRP'] = '1'
if setenv: if setenv:
...@@ -119,8 +132,10 @@ def start(command, **kwargs): ...@@ -119,8 +132,10 @@ def start(command, **kwargs):
else: else:
env = os.environ.copy() env = os.environ.copy()
env.update(setenv) env.update(setenv)
log('+ %s', name) log('+ %s', name)
popen = Popen(command, preexec_fn=preexec_fn, env=env, **kwargs) popen = Popen(command, preexec_fn=preexec_fn, env=env, **kwargs)
popen.name = name
popen.setpgrp_enabled = preexec_fn is not None popen.setpgrp_enabled = preexec_fn is not None
if timeout is not None: if timeout is not None:
popen._killer = spawn_later(timeout, kill, popen) popen._killer = spawn_later(timeout, kill, popen)
...@@ -132,9 +147,10 @@ def start(command, **kwargs): ...@@ -132,9 +147,10 @@ def start(command, **kwargs):
class RunResult(object): class RunResult(object):
def __init__(self, code, output=None): def __init__(self, code, output=None, name=None):
self.code = code self.code = code
self.output = output self.output = output
self.name = name
def __nonzero__(self): def __nonzero__(self):
return bool(self.code) return bool(self.code)
...@@ -144,13 +160,13 @@ class RunResult(object): ...@@ -144,13 +160,13 @@ class RunResult(object):
def run(command, **kwargs): def run(command, **kwargs):
name = kwargs.get('name') or getname(command)
buffer_output = kwargs.pop('buffer_output', BUFFER_OUTPUT) buffer_output = kwargs.pop('buffer_output', BUFFER_OUTPUT)
if buffer_output: if buffer_output:
assert 'stdout' not in kwargs and 'stderr' not in kwargs, kwargs assert 'stdout' not in kwargs and 'stderr' not in kwargs, kwargs
kwargs['stderr'] = subprocess.STDOUT kwargs['stderr'] = subprocess.STDOUT
kwargs['stdout'] = subprocess.PIPE kwargs['stdout'] = subprocess.PIPE
popen = start(command, **kwargs) popen = start(command, **kwargs)
name = popen.name
try: try:
time_start = time() time_start = time()
out, err = popen.communicate() out, err = popen.communicate()
...@@ -177,7 +193,7 @@ def run(command, **kwargs): ...@@ -177,7 +193,7 @@ def run(command, **kwargs):
log('- %s [took %.1fs]', name, took) log('- %s [took %.1fs]', name, took)
if took >= MIN_RUNTIME: if took >= MIN_RUNTIME:
runtimelog.append((-took, name)) runtimelog.append((-took, name))
return RunResult(result, out) return RunResult(result, out, name)
def expected_match(name, expected): def expected_match(name, expected):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment