Bug 1034272 - Convert cppunittests to structured logging.;r=ted

This commit is contained in:
Chris Manchester 2014-07-10 09:33:39 -04:00
parent 3c53568904
commit 644813fdf7
3 changed files with 80 additions and 39 deletions

View File

@ -253,8 +253,12 @@ class MachCommands(MachCommandBase):
'executed.')
def run_cppunit_test(self, **params):
from mozlog.structured import commandline
import runcppunittests as cppunittests
import logging
log = commandline.setup_logging("cppunittest",
{},
{"tbpl": sys.stdout})
if len(params['test_files']) == 0:
testdir = os.path.join(self.distdir, 'cppunittests')
@ -269,11 +273,9 @@ class MachCommands(MachCommandBase):
tester = cppunittests.CPPUnitTests()
try:
result = tester.run_tests(progs, self.bindir, symbols_path)
except Exception, e:
self.log(logging.ERROR, 'cppunittests',
{'exception': str(e)},
'Caught exception running cpp unit tests: {exception}')
result = tester.run_tests(progs, self.bindir, symbols_path, interactive=True)
except Exception as e:
log.error("Caught exception running cpp unit tests: %s" % str(e))
result = False
return 0 if result else 1

View File

@ -9,11 +9,12 @@ import subprocess
import tempfile
from zipfile import ZipFile
import runcppunittests as cppunittests
import mozcrash, mozlog
import mozcrash
import mozfile
import StringIO
import posixpath
from mozdevice import devicemanager, devicemanagerADB, devicemanagerSUT
from mozlog import structured
try:
from mozbuild.base import MozbuildObject
@ -21,8 +22,6 @@ try:
except ImportError:
build_obj = None
log = mozlog.getLogger('remotecppunittests')
class RemoteCPPUnitTests(cppunittests.CPPUnitTests):
def __init__(self, devmgr, options, progs):
cppunittests.CPPUnitTests.__init__(self)
@ -110,11 +109,11 @@ class RemoteCPPUnitTests(cppunittests.CPPUnitTests):
elif len(envdef_parts) == 1:
env[envdef_parts[0]] = ""
else:
print >> sys.stderr, "warning: invalid --addEnv option skipped: "+envdef
self.log.warning("invalid --addEnv option skipped: %s" % envdef)
return env
def run_one_test(self, prog, env, symbols_path=None):
def run_one_test(self, prog, env, symbols_path=None, interactive=False):
"""
Run a single C++ unit test program remotely.
@ -128,21 +127,25 @@ class RemoteCPPUnitTests(cppunittests.CPPUnitTests):
"""
basename = os.path.basename(prog)
remote_bin = posixpath.join(self.remote_bin_dir, basename)
log.info("Running test %s", basename)
self.log.test_start(basename)
buf = StringIO.StringIO()
returncode = self.device.shell([remote_bin], buf, env=env, cwd=self.remote_home_dir,
timeout=cppunittests.CPPUnitTests.TEST_PROC_TIMEOUT)
print >> sys.stdout, buf.getvalue()
self.log.process_output(basename, "\n%s" % buf.getvalue(),
command=[remote_bin])
with mozfile.TemporaryDirectory() as tempdir:
self.device.getDirectory(self.remote_home_dir, tempdir)
if mozcrash.check_for_crashes(tempdir, symbols_path,
test_name=basename):
log.testFail("%s | test crashed", basename)
self.log.test_end(basename, status='CRASH', expected='PASS')
return False
result = returncode == 0
if not result:
log.testFail("%s | test failed with return code %s",
basename, returncode)
self.log.test_end(basename, status='FAIL', expected='PASS',
message=("test failed with return code %d" %
returncode))
else:
self.log.test_end(basename, status='PASS', expected='PASS')
return result
class RemoteCPPUnittestOptions(cppunittests.CPPUnittestOptions):
@ -204,6 +207,7 @@ class RemoteCPPUnittestOptions(cppunittests.CPPUnittestOptions):
def main():
parser = RemoteCPPUnittestOptions()
structured.commandline.add_logging_group(parser)
options, args = parser.parse_args()
if not args:
print >>sys.stderr, """Usage: %s <test binary> [<test binary>...]""" % sys.argv[0]
@ -243,6 +247,12 @@ def main():
if not options.device_ip:
print "Error: you must provide a device IP to connect to via the --deviceIP option"
sys.exit(1)
log = structured.commandline.setup_logging("remotecppunittests",
options,
{"tbpl": sys.stdout})
options.xre_path = os.path.abspath(options.xre_path)
progs = cppunittests.extract_unittests_from_args(args, options.manifest_file)
tester = RemoteCPPUnitTests(dm, options, progs)

View File

@ -7,10 +7,13 @@
from __future__ import with_statement
import sys, os, tempfile, shutil
from optparse import OptionParser
import mozprocess, mozinfo, mozlog, mozcrash, mozfile
import mozprocess
import mozinfo
import mozcrash
import mozfile
from contextlib import contextmanager
log = mozlog.getLogger('cppunittests')
from mozlog import structured
from subprocess import PIPE
class CPPUnitTests(object):
# Time (seconds) to wait for test process to complete
@ -18,7 +21,7 @@ class CPPUnitTests(object):
# Time (seconds) in which process will be killed if it produces no output.
TEST_PROC_NO_OUTPUT_TIMEOUT = 300
def run_one_test(self, prog, env, symbols_path=None):
def run_one_test(self, prog, env, symbols_path=None, interactive=False):
"""
Run a single C++ unit test program.
@ -31,28 +34,44 @@ class CPPUnitTests(object):
Return True if the program exits with a zero status, False otherwise.
"""
basename = os.path.basename(prog)
log.info("Running test %s", basename)
self.log.test_start(basename)
with mozfile.TemporaryDirectory() as tempdir:
proc = mozprocess.ProcessHandler([prog],
cwd=tempdir,
env=env)
if interactive:
# For tests run locally, via mach, print output directly
proc = mozprocess.ProcessHandler([prog],
cwd=tempdir,
env=env,
storeOutput=False)
else:
proc = mozprocess.ProcessHandler([prog],
cwd=tempdir,
env=env,
storeOutput=True,
processOutputLine=lambda _: None)
#TODO: After bug 811320 is fixed, don't let .run() kill the process,
# instead use a timeout in .wait() and then kill to get a stack.
proc.run(timeout=CPPUnitTests.TEST_PROC_TIMEOUT,
outputTimeout=CPPUnitTests.TEST_PROC_NO_OUTPUT_TIMEOUT)
proc.wait()
if proc.output:
output = "\n%s" % "\n".join(proc.output)
self.log.process_output(proc.pid, output, command=[prog])
if proc.timedOut:
log.testFail("%s | timed out after %d seconds",
basename, CPPUnitTests.TEST_PROC_TIMEOUT)
message = "timed out after %d seconds" % CPPUnitTests.TEST_PROC_TIMEOUT
self.log.test_end(basename, status='TIMEOUT', expected='PASS',
message=message)
return False
if mozcrash.check_for_crashes(tempdir, symbols_path,
test_name=basename):
log.testFail("%s | test crashed", basename)
self.log.test_end(basename, status='CRASH', expected='PASS')
return False
result = proc.proc.returncode == 0
if not result:
log.testFail("%s | test failed with return code %d",
basename, proc.proc.returncode)
self.log.test_end(basename, status='FAIL', expected='PASS',
message=("test failed with return code %d" %
proc.proc.returncode))
else:
self.log.test_end(basename, status='PASS', expected='PASS')
return result
def build_core_environment(self, env = {}):
@ -94,13 +113,13 @@ class CPPUnitTests(object):
llvmsym = os.path.join(self.xre_path, "llvm-symbolizer")
if os.path.isfile(llvmsym):
env["ASAN_SYMBOLIZER_PATH"] = llvmsym
log.info("ASan using symbolizer at %s", llvmsym)
self.log.info("ASan using symbolizer at %s" % llvmsym)
else:
log.info("Failed to find ASan symbolizer at %s", llvmsym)
self.log.info("Failed to find ASan symbolizer at %s" % llvmsym)
return env
def run_tests(self, programs, xre_path, symbols_path=None):
def run_tests(self, programs, xre_path, symbols_path=None, interactive=False):
"""
Run a set of C++ unit test programs.
@ -114,19 +133,23 @@ class CPPUnitTests(object):
otherwise.
"""
self.xre_path = xre_path
self.log = structured.structuredlog.get_default_logger()
self.log.suite_start(programs)
env = self.build_environment()
pass_count = 0
fail_count = 0
for prog in programs:
single_result = self.run_one_test(prog, env, symbols_path)
single_result = self.run_one_test(prog, env, symbols_path, interactive)
if single_result:
pass_count += 1
else:
fail_count += 1
self.log.suite_end()
log.info("Result summary:")
log.info("Passed: %d" % pass_count)
log.info("Failed: %d" % fail_count)
# Mozharness-parseable summary formatting.
self.log.info("Result summary:")
self.log.info("cppunittests INFO | Passed: %d" % pass_count)
self.log.info("cppunittests INFO | Failed: %d" % fail_count)
return fail_count == 0
class CPPUnittestOptions(OptionParser):
@ -171,6 +194,7 @@ def extract_unittests_from_args(args, manifest_file):
def main():
parser = CPPUnittestOptions()
structured.commandline.add_logging_group(parser)
options, args = parser.parse_args()
if not args:
print >>sys.stderr, """Usage: %s <test binary> [<test binary>...]""" % sys.argv[0]
@ -178,17 +202,22 @@ def main():
if not options.xre_path:
print >>sys.stderr, """Error: --xre-path is required"""
sys.exit(1)
log = structured.commandline.setup_logging("cppunittests",
options,
{"tbpl": sys.stdout})
progs = extract_unittests_from_args(args, options.manifest_file)
options.xre_path = os.path.abspath(options.xre_path)
tester = CPPUnitTests()
try:
result = tester.run_tests(progs, options.xre_path, options.symbols_path)
except Exception, e:
except Exception as e:
log.error(str(e))
result = False
sys.exit(0 if result else 1)
if __name__ == '__main__':
main()