aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHemmo Nieminen <hemmo.nieminen@iki.fi>2016-02-26 21:18:21 +0200
committerHemmo Nieminen <hemmo.nieminen@iki.fi>2016-04-01 00:51:12 +0300
commit297749581dd4dcb4e68da4b1d0622d2916fb8db3 (patch)
tree2f69bc1c3c61fbf1065d1cec51f513a92f23919b
parentf2868420ca13c49ba25d00cd75b490d1629246a2 (diff)
downloadmeson-297749581dd4dcb4e68da4b1d0622d2916fb8db3.zip
meson-297749581dd4dcb4e68da4b1d0622d2916fb8db3.tar.gz
meson-297749581dd4dcb4e68da4b1d0622d2916fb8db3.tar.bz2
meson_test: Add support for --print-errorlogs option.
This option can be used to control whether the logs from failing tests should be shown to the user after the tests have been executed.
-rw-r--r--mesonbuild/scripts/meson_test.py83
1 files changed, 49 insertions, 34 deletions
diff --git a/mesonbuild/scripts/meson_test.py b/mesonbuild/scripts/meson_test.py
index 05c909d..01da9b4 100644
--- a/mesonbuild/scripts/meson_test.py
+++ b/mesonbuild/scripts/meson_test.py
@@ -25,7 +25,8 @@ def is_windows():
platname = platform.system().lower()
return platname == 'windows' or 'mingw' in platname
-tests_failed = []
+collected_logs = []
+error_count = 0
options = None
parser = argparse.ArgumentParser()
@@ -37,6 +38,8 @@ parser.add_argument('--suite', default=None, dest='suite',
help='Only run tests belonging to this suite.')
parser.add_argument('--no-stdsplit', default=True, dest='split', action='store_false',
help='Do not split stderr and stdout in test logs.')
+parser.add_argument('--print-errorlogs', default=False, action='store_true',
+ help="Whether to print faling tests' logs.")
parser.add_argument('args', nargs='+')
@@ -49,26 +52,31 @@ class TestRun():
self.stde = stde
self.cmd = cmd
+ def get_log(self):
+ res = '--- command ---\n'
+ if self.cmd is None:
+ res += 'NONE\n'
+ else:
+ res += ' '.join(self.cmd) + '\n'
+ if self.stdo:
+ res += '--- stdout ---\n'
+ res += self.stdo
+ if self.stde:
+ if res[-1:] != '\n':
+ res += '\n'
+ res += '--- stderr ---\n'
+ res += self.stde
+ if res[-1:] != '\n':
+ res += '\n'
+ res += '-------\n\n'
+ return res
+
def decode(stream):
try:
return stream.decode('utf-8')
except UnicodeDecodeError:
return stream.decode('iso-8859-1', errors='ignore')
-def write_log(logfile, test_name, result_str, result):
- logfile.write(result_str + '\n\n')
- logfile.write('--- command ---\n')
- if result.cmd is None:
- logfile.write('NONE')
- else:
- logfile.write(' '.join(result.cmd))
- logfile.write('\n--- "%s" stdout ---\n' % test_name)
- logfile.write(result.stdo)
- if result.stde:
- logfile.write('\n--- "%s" stderr ---\n' % test_name)
- logfile.write(result.stde)
- logfile.write('\n-------\n\n')
-
def write_json_log(jsonlogfile, test_name, result):
jresult = {'name' : test_name,
'stdout' : result.stdo,
@@ -86,7 +94,7 @@ def run_with_mono(fname):
return False
def run_single_test(wrap, test):
- global tests_failed, options
+ global options
if test.fname[0].endswith('.jar'):
cmd = ['java', '-jar'] + test.fname
elif not test.is_cross and run_with_mono(test.fname[0]):
@@ -146,17 +154,16 @@ def run_single_test(wrap, test):
stde = decode(stde)
if timed_out:
res = 'TIMEOUT'
- tests_failed.append((test.name, stdo, stde))
elif (not test.should_fail and p.returncode == 0) or \
(test.should_fail and p.returncode != 0):
res = 'OK'
else:
res = 'FAIL'
- tests_failed.append((test.name, stdo, stde))
returncode = p.returncode
return TestRun(res, returncode, duration, stdo, stde, cmd)
def print_stats(numlen, tests, name, result, i, logfile, jsonlogfile):
+ global collected_logs, error_count, options
startpad = ' '*(numlen - len('%d' % (i+1)))
num = '%s%d/%d' % (startpad, i+1, len(tests))
padding1 = ' '*(38-len(name))
@@ -164,7 +171,12 @@ def print_stats(numlen, tests, name, result, i, logfile, jsonlogfile):
result_str = '%s %s %s%s%s%5.2f s' % \
(num, name, padding1, result.res, padding2, result.duration)
print(result_str)
- write_log(logfile, name, result_str, result)
+ result_str += "\n\n" + result.get_log()
+ if result.returncode != 0:
+ error_count += 1
+ if options.print_errorlogs:
+ collected_logs.append(result_str)
+ logfile.write(result_str)
write_json_log(jsonlogfile, name, result)
def drain_futures(futures):
@@ -229,8 +241,9 @@ def run_tests(datafilename):
return logfilename
def run(args):
- global tests_failed, options
- tests_failed = [] # To avoid state leaks when invoked multiple times (running tests in-process)
+ global collected_logs, error_count, options
+ collected_logs = [] # To avoid state leaks when invoked multiple times (running tests in-process)
+ error_count = 0
options = parser.parse_args(args)
if len(options.args) != 1:
print('Test runner for Meson. Do not run on your own, mmm\'kay?')
@@ -239,19 +252,21 @@ def run(args):
os.chdir(options.wd)
datafile = options.args[0]
logfilename = run_tests(datafile)
- returncode = 0
- if len(tests_failed) > 0:
- print('\nOutput of failed tests (max 10):')
- for (name, stdo, stde) in tests_failed[:10]:
- print("{} stdout:\n".format(name))
- print(stdo)
- if stde:
- print('\n{} stderr:\n'.format(name))
- print(stde)
- print('\n')
- returncode = 1
- print('\nFull log written to %s.' % logfilename)
- return returncode
+ if len(collected_logs) > 0:
+ if len(collected_logs) > 10:
+ print('\nThe output from 10 first failed tests:\n')
+ else:
+ print('\nThe output from the failed tests:\n')
+ for log in collected_logs[:10]:
+ lines = log.splitlines()
+ if len(lines) > 100:
+ print(line[0])
+ print('--- Listing only the last 100 lines from a long log. ---')
+ lines = lines[-99:]
+ for line in lines:
+ print(line)
+ print('Full log written to %s.' % logfilename)
+ return error_count
if __name__ == '__main__':
sys.exit(run(sys.argv[1:]))