blob: 06e178bd226b44034eab09c3454112e023ecd8db [file] [log] [blame] [edit]
#!/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 ast
import logging
import os
import platform
import subprocess
import sys
import mopy.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("gtest_list_file",
help="The file containing the tests to run.",
type=file)
parser.add_argument("root_dir", help="The build directory.")
parser.add_argument("successes_cache_filename",
help="The file caching test results.", default=None,
nargs="?")
args = parser.parse_args()
InitLogging(args.verbose_count)
config = ConfigForGNArgs(ParseGNConfig(args.root_dir))
_logger.debug("Test list file: %s", args.gtest_list_file)
execution_globals = {
"config": config,
}
exec args.gtest_list_file in execution_globals
gtest_list = execution_globals["tests"]
_logger.debug("Test list: %s" % gtest_list)
print "Running tests in directory: %s" % args.root_dir
os.chdir(args.root_dir)
if args.successes_cache_filename:
print "Successes cache file: %s" % args.successes_cache_filename
else:
print "No successes cache file (will run all tests unconditionally)"
if args.successes_cache_filename:
# 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_filename)
with open(args.successes_cache_filename, '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_filename)
successes = set()
mopy.gtest.set_color()
# TODO(vtl): We may not close this file on failure.
successes_cache_file = open(args.successes_cache_filename, "ab") \
if args.successes_cache_filename else None
for gtest_dict in gtest_list:
gtest = gtest_dict["test"]
cacheable = gtest_dict.get("cacheable", True)
if not cacheable:
_logger.debug("%s is marked as non-cacheable" % gtest)
gtest_file = gtest
if platform.system() == "Windows":
gtest_file += ".exe"
if config.target_os == Config.OS_ANDROID:
gtest_file = gtest + "_apk/" + gtest + "-debug.apk"
if successes_cache_file and cacheable:
_logger.debug("Getting transitive hash for %s ... " % gtest)
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" % gtest
return 1
_logger.debug(" Transitive hash: %s" % gtest_hash)
if gtest_hash in successes:
print "Skipping %s (previously succeeded)" % gtest
continue
_logger.info("Will start: %s" % gtest)
print "Running %s...." % gtest,
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",
gtest,
]
else:
command = ["./" + gtest]
_logger.debug("Command: %s" % command)
subprocess.check_output(command, stderr=subprocess.STDOUT)
print "Succeeded"
# Record success.
if args.successes_cache_filename 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 * "-"
return 1
except OSError as e:
print " Failed to start test"
return 1
_logger.info("Completed: %s" % gtest)
print "All tests succeeded"
if successes_cache_file:
successes_cache_file.close()
return 0
if __name__ == "__main__":
sys.exit(main())