blob: fe564a9a57d0f90a8678961146794974691e30f3 [file] [log] [blame]
James Robinson646469d2014-10-03 15:33:28 -07001#!/usr/bin/env python
2# Copyright 2014 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""A "smart" test runner for gtest unit tests (that caches successes)."""
7
Benjamin Lermanf4583a82014-11-26 10:54:39 +01008import argparse
James Robinson646469d2014-10-03 15:33:28 -07009import logging
10import os
11import subprocess
12import sys
13
Viet-Trung Luubd9af432015-04-16 10:47:55 -070014from mopy import gtest
Benjamin Lermanb96671e2015-01-29 11:05:54 +010015from mopy.config import Config
16from mopy.gn import ConfigForGNArgs, ParseGNConfig
Viet-Trung Luudaab6d72015-04-08 13:51:28 -070017from mopy.log import InitLogging
Benjamin Lermanf4583a82014-11-26 10:54:39 +010018from mopy.paths import Paths
19from mopy.transitive_hash import file_hash, transitive_hash
James Robinson646469d2014-10-03 15:33:28 -070020
Viet-Trung Luudaab6d72015-04-08 13:51:28 -070021
22_logger = logging.getLogger()
23_paths = Paths()
24
Benjamin Lermanf4583a82014-11-26 10:54:39 +010025
26def main():
Benjamin Lermanf4583a82014-11-26 10:54:39 +010027 parser = argparse.ArgumentParser(
28 description="A 'smart' test runner for gtest unit tests (that caches "
29 "successes).")
James Robinson646469d2014-10-03 15:33:28 -070030
Viet-Trung Luubd9af432015-04-16 10:47:55 -070031 parser.add_argument("--verbose", help="be verbose (multiple times for more)",
Viet-Trung Luudaab6d72015-04-08 13:51:28 -070032 default=0, dest="verbose_count", action="count")
Viet-Trung Luubd9af432015-04-16 10:47:55 -070033 parser.add_argument("--successes-cache",
34 help="the file caching test results (empty to not cache)",
35 default="mojob_test_successes")
36 parser.add_argument("test_list_file",
37 help="the file containing the tests to run", type=file)
38 parser.add_argument("root_dir", help="the build directory")
Benjamin Lermanf4583a82014-11-26 10:54:39 +010039 args = parser.parse_args()
40
Viet-Trung Luudaab6d72015-04-08 13:51:28 -070041 InitLogging(args.verbose_count)
Benjamin Lermanb96671e2015-01-29 11:05:54 +010042 config = ConfigForGNArgs(ParseGNConfig(args.root_dir))
43
Viet-Trung Luubd9af432015-04-16 10:47:55 -070044 _logger.debug("Test list file: %s", args.test_list_file)
45 execution_globals = {"config": config}
46 exec args.test_list_file in execution_globals
47 test_list = execution_globals["tests"]
48 _logger.debug("Test list: %s" % test_list)
Benjamin Lerman75b30342015-02-04 16:54:56 +010049
Benjamin Lermanf4583a82014-11-26 10:54:39 +010050 print "Running tests in directory: %s" % args.root_dir
51 os.chdir(args.root_dir)
James Robinson646469d2014-10-03 15:33:28 -070052
Viet-Trung Luubd9af432015-04-16 10:47:55 -070053 if args.successes_cache:
54 print "Successes cache file: %s" % args.successes_cache
James Robinson646469d2014-10-03 15:33:28 -070055 else:
James Robinson646469d2014-10-03 15:33:28 -070056 print "No successes cache file (will run all tests unconditionally)"
57
Viet-Trung Luubd9af432015-04-16 10:47:55 -070058 if args.successes_cache:
James Robinson646469d2014-10-03 15:33:28 -070059 # This file simply contains a list of transitive hashes of tests that
60 # succeeded.
61 try:
Viet-Trung Luudaab6d72015-04-08 13:51:28 -070062 _logger.debug("Trying to read successes cache file: %s",
Viet-Trung Luubd9af432015-04-16 10:47:55 -070063 args.successes_cache)
64 with open(args.successes_cache, 'rb') as f:
James Robinson646469d2014-10-03 15:33:28 -070065 successes = set([x.strip() for x in f.readlines()])
Viet-Trung Luudaab6d72015-04-08 13:51:28 -070066 _logger.debug("Successes: %s", successes)
Viet-Trung Luuec5ef2f2014-10-22 15:53:25 -070067 except IOError:
James Robinson646469d2014-10-03 15:33:28 -070068 # Just assume that it didn't exist, or whatever.
Benjamin Lermanf4583a82014-11-26 10:54:39 +010069 print ("Failed to read successes cache file %s (will create)" %
Viet-Trung Luubd9af432015-04-16 10:47:55 -070070 args.successes_cache)
James Robinson646469d2014-10-03 15:33:28 -070071 successes = set()
72
Viet-Trung Luubd9af432015-04-16 10:47:55 -070073 gtest.set_color()
James Robinson646469d2014-10-03 15:33:28 -070074
Viet-Trung Luubd9af432015-04-16 10:47:55 -070075 exit_code = 0
76 successes_cache_file = (open(args.successes_cache, "ab")
77 if args.successes_cache else None)
78 for test_dict in test_list:
79 test = test_dict["test"]
80 test_name = test_dict.get("name", test)
81 # TODO(vtl): Add type.
82 cacheable = test_dict.get("cacheable", True)
Benjamin Lerman52915982014-12-04 09:33:02 +010083 if not cacheable:
Viet-Trung Luubd9af432015-04-16 10:47:55 -070084 _logger.debug("%s is marked as non-cacheable" % test_name)
James Robinson646469d2014-10-03 15:33:28 -070085
Viet-Trung Luubd9af432015-04-16 10:47:55 -070086 gtest_file = test
Benjamin Lermanb96671e2015-01-29 11:05:54 +010087 if config.target_os == Config.OS_ANDROID:
Viet-Trung Luubd9af432015-04-16 10:47:55 -070088 gtest_file = test + "_apk/" + test + "-debug.apk"
John Abd-El-Malek0f0b4f02014-11-11 12:42:38 -080089
James Robinson646469d2014-10-03 15:33:28 -070090 if successes_cache_file and cacheable:
Viet-Trung Luubd9af432015-04-16 10:47:55 -070091 _logger.debug("Getting transitive hash for %s ... " % test_name)
James Robinson646469d2014-10-03 15:33:28 -070092 try:
Benjamin Lermanb96671e2015-01-29 11:05:54 +010093 if config.target_os == Config.OS_ANDROID:
Benjamin Lermanf4583a82014-11-26 10:54:39 +010094 gtest_hash = file_hash(gtest_file)
95 else:
96 gtest_hash = transitive_hash(gtest_file)
Viet-Trung Luuec5ef2f2014-10-22 15:53:25 -070097 except subprocess.CalledProcessError:
Viet-Trung Luubd9af432015-04-16 10:47:55 -070098 print "Failed to get transitive hash for %s" % test_name
99 exit_code = 1
100 continue
Viet-Trung Luudaab6d72015-04-08 13:51:28 -0700101 _logger.debug(" Transitive hash: %s" % gtest_hash)
James Robinson646469d2014-10-03 15:33:28 -0700102
103 if gtest_hash in successes:
Viet-Trung Luubd9af432015-04-16 10:47:55 -0700104 print "Skipping %s (previously succeeded)" % test_name
James Robinson646469d2014-10-03 15:33:28 -0700105 continue
106
Viet-Trung Luubd9af432015-04-16 10:47:55 -0700107 _logger.info("Will start: %s" % test_name)
108 print "Running %s...." % test_name,
James Robinson646469d2014-10-03 15:33:28 -0700109 sys.stdout.flush()
110 try:
Benjamin Lermanb96671e2015-01-29 11:05:54 +0100111 if config.target_os == Config.OS_ANDROID:
Benjamin Lermanf4583a82014-11-26 10:54:39 +0100112 command = [
113 "python",
Viet-Trung Luudaab6d72015-04-08 13:51:28 -0700114 os.path.join(_paths.src_root, "build", "android", "test_runner.py"),
Benjamin Lermanf4583a82014-11-26 10:54:39 +0100115 "gtest",
116 "--output-directory",
117 args.root_dir,
118 "-s",
Viet-Trung Luubd9af432015-04-16 10:47:55 -0700119 test,
Benjamin Lermanf4583a82014-11-26 10:54:39 +0100120 ]
121 else:
Viet-Trung Luubd9af432015-04-16 10:47:55 -0700122 command = ["./" + test]
Viet-Trung Luudaab6d72015-04-08 13:51:28 -0700123 _logger.debug("Command: %s" % command)
Benjamin Lermanf4583a82014-11-26 10:54:39 +0100124 subprocess.check_output(command, stderr=subprocess.STDOUT)
James Robinson646469d2014-10-03 15:33:28 -0700125 print "Succeeded"
126 # Record success.
Viet-Trung Luubd9af432015-04-16 10:47:55 -0700127 if args.successes_cache and cacheable:
James Robinson646469d2014-10-03 15:33:28 -0700128 successes.add(gtest_hash)
Viet-Trung Luudaab6d72015-04-08 13:51:28 -0700129 successes_cache_file.write(gtest_hash + "\n")
James Robinson646469d2014-10-03 15:33:28 -0700130 successes_cache_file.flush()
131 except subprocess.CalledProcessError as e:
132 print "Failed with exit code %d and output:" % e.returncode
Viet-Trung Luudaab6d72015-04-08 13:51:28 -0700133 print 72 * "-"
James Robinson646469d2014-10-03 15:33:28 -0700134 print e.output
Viet-Trung Luudaab6d72015-04-08 13:51:28 -0700135 print 72 * "-"
Viet-Trung Luubd9af432015-04-16 10:47:55 -0700136 exit_code = 1
137 continue
James Robinson646469d2014-10-03 15:33:28 -0700138 except OSError as e:
139 print " Failed to start test"
Viet-Trung Luubd9af432015-04-16 10:47:55 -0700140 exit_code = 1
141 continue
142 _logger.info("Completed: %s" % test_name)
143 if exit_code == 0:
144 print "All tests succeeded"
James Robinson646469d2014-10-03 15:33:28 -0700145 if successes_cache_file:
146 successes_cache_file.close()
147
Viet-Trung Luubd9af432015-04-16 10:47:55 -0700148 return exit_code
James Robinson646469d2014-10-03 15:33:28 -0700149
Viet-Trung Luudaab6d72015-04-08 13:51:28 -0700150
151if __name__ == "__main__":
Benjamin Lermanf4583a82014-11-26 10:54:39 +0100152 sys.exit(main())