blob: fe564a9a57d0f90a8678961146794974691e30f3 [file] [log] [blame]
#!/usr/bin/env python
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""A "smart" test runner for gtest unit tests (that caches successes)."""
import argparse
import logging
import os
import subprocess
import sys
from mopy import gtest
from mopy.config import Config
from mopy.gn import ConfigForGNArgs, ParseGNConfig
from mopy.log import InitLogging
from mopy.paths import Paths
from mopy.transitive_hash import file_hash, transitive_hash
_logger = logging.getLogger()
_paths = Paths()
def main():
parser = argparse.ArgumentParser(
description="A 'smart' test runner for gtest unit tests (that caches "
"successes).")
parser.add_argument("--verbose", help="be verbose (multiple times for more)",
default=0, dest="verbose_count", action="count")
parser.add_argument("--successes-cache",
help="the file caching test results (empty to not cache)",
default="mojob_test_successes")
parser.add_argument("test_list_file",
help="the file containing the tests to run", type=file)
parser.add_argument("root_dir", help="the build directory")
args = parser.parse_args()
InitLogging(args.verbose_count)
config = ConfigForGNArgs(ParseGNConfig(args.root_dir))
_logger.debug("Test list file: %s", args.test_list_file)
execution_globals = {"config": config}
exec args.test_list_file in execution_globals
test_list = execution_globals["tests"]
_logger.debug("Test list: %s" % test_list)
print "Running tests in directory: %s" % args.root_dir
os.chdir(args.root_dir)
if args.successes_cache:
print "Successes cache file: %s" % args.successes_cache
else:
print "No successes cache file (will run all tests unconditionally)"
if args.successes_cache:
# This file simply contains a list of transitive hashes of tests that
# succeeded.
try:
_logger.debug("Trying to read successes cache file: %s",
args.successes_cache)
with open(args.successes_cache, 'rb') as f:
successes = set([x.strip() for x in f.readlines()])
_logger.debug("Successes: %s", successes)
except IOError:
# Just assume that it didn't exist, or whatever.
print ("Failed to read successes cache file %s (will create)" %
args.successes_cache)
successes = set()
gtest.set_color()
exit_code = 0
successes_cache_file = (open(args.successes_cache, "ab")
if args.successes_cache else None)
for test_dict in test_list:
test = test_dict["test"]
test_name = test_dict.get("name", test)
# TODO(vtl): Add type.
cacheable = test_dict.get("cacheable", True)
if not cacheable:
_logger.debug("%s is marked as non-cacheable" % test_name)
gtest_file = test
if config.target_os == Config.OS_ANDROID:
gtest_file = test + "_apk/" + test + "-debug.apk"
if successes_cache_file and cacheable:
_logger.debug("Getting transitive hash for %s ... " % test_name)
try:
if config.target_os == Config.OS_ANDROID:
gtest_hash = file_hash(gtest_file)
else:
gtest_hash = transitive_hash(gtest_file)
except subprocess.CalledProcessError:
print "Failed to get transitive hash for %s" % test_name
exit_code = 1
continue
_logger.debug(" Transitive hash: %s" % gtest_hash)
if gtest_hash in successes:
print "Skipping %s (previously succeeded)" % test_name
continue
_logger.info("Will start: %s" % test_name)
print "Running %s...." % test_name,
sys.stdout.flush()
try:
if config.target_os == Config.OS_ANDROID:
command = [
"python",
os.path.join(_paths.src_root, "build", "android", "test_runner.py"),
"gtest",
"--output-directory",
args.root_dir,
"-s",
test,
]
else:
command = ["./" + test]
_logger.debug("Command: %s" % command)
subprocess.check_output(command, stderr=subprocess.STDOUT)
print "Succeeded"
# Record success.
if args.successes_cache and cacheable:
successes.add(gtest_hash)
successes_cache_file.write(gtest_hash + "\n")
successes_cache_file.flush()
except subprocess.CalledProcessError as e:
print "Failed with exit code %d and output:" % e.returncode
print 72 * "-"
print e.output
print 72 * "-"
exit_code = 1
continue
except OSError as e:
print " Failed to start test"
exit_code = 1
continue
_logger.info("Completed: %s" % test_name)
if exit_code == 0:
print "All tests succeeded"
if successes_cache_file:
successes_cache_file.close()
return exit_code
if __name__ == "__main__":
sys.exit(main())