[6a3a178] | 1 | #!/usr/bin/env python
|
---|
| 2 | # Copyright (c) 2012 Google Inc. 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 | """gyptest.py -- test runner for GYP tests."""
|
---|
| 7 |
|
---|
| 8 | from __future__ import print_function
|
---|
| 9 |
|
---|
| 10 | import argparse
|
---|
| 11 | import os
|
---|
| 12 | import platform
|
---|
| 13 | import subprocess
|
---|
| 14 | import sys
|
---|
| 15 | import time
|
---|
| 16 |
|
---|
| 17 |
|
---|
| 18 | def is_test_name(f):
|
---|
| 19 | return f.startswith("gyptest") and f.endswith(".py")
|
---|
| 20 |
|
---|
| 21 |
|
---|
| 22 | def find_all_gyptest_files(directory):
|
---|
| 23 | result = []
|
---|
| 24 | for root, dirs, files in os.walk(directory):
|
---|
| 25 | result.extend([os.path.join(root, f) for f in files if is_test_name(f)])
|
---|
| 26 | result.sort()
|
---|
| 27 | return result
|
---|
| 28 |
|
---|
| 29 |
|
---|
| 30 | def main(argv=None):
|
---|
| 31 | if argv is None:
|
---|
| 32 | argv = sys.argv
|
---|
| 33 |
|
---|
| 34 | parser = argparse.ArgumentParser()
|
---|
| 35 | parser.add_argument("-a", "--all", action="store_true", help="run all tests")
|
---|
| 36 | parser.add_argument("-C", "--chdir", action="store", help="change to directory")
|
---|
| 37 | parser.add_argument(
|
---|
| 38 | "-f",
|
---|
| 39 | "--format",
|
---|
| 40 | action="store",
|
---|
| 41 | default="",
|
---|
| 42 | help="run tests with the specified formats",
|
---|
| 43 | )
|
---|
| 44 | parser.add_argument(
|
---|
| 45 | "-G",
|
---|
| 46 | "--gyp_option",
|
---|
| 47 | action="append",
|
---|
| 48 | default=[],
|
---|
| 49 | help="Add -G options to the gyp command line",
|
---|
| 50 | )
|
---|
| 51 | parser.add_argument(
|
---|
| 52 | "-l", "--list", action="store_true", help="list available tests and exit"
|
---|
| 53 | )
|
---|
| 54 | parser.add_argument(
|
---|
| 55 | "-n",
|
---|
| 56 | "--no-exec",
|
---|
| 57 | action="store_true",
|
---|
| 58 | help="no execute, just print the command line",
|
---|
| 59 | )
|
---|
| 60 | parser.add_argument(
|
---|
| 61 | "--path", action="append", default=[], help="additional $PATH directory"
|
---|
| 62 | )
|
---|
| 63 | parser.add_argument(
|
---|
| 64 | "-q",
|
---|
| 65 | "--quiet",
|
---|
| 66 | action="store_true",
|
---|
| 67 | help="quiet, don't print anything unless there are failures",
|
---|
| 68 | )
|
---|
| 69 | parser.add_argument(
|
---|
| 70 | "-v",
|
---|
| 71 | "--verbose",
|
---|
| 72 | action="store_true",
|
---|
| 73 | help="print configuration info and test results.",
|
---|
| 74 | )
|
---|
| 75 | parser.add_argument("tests", nargs="*")
|
---|
| 76 | args = parser.parse_args(argv[1:])
|
---|
| 77 |
|
---|
| 78 | if args.chdir:
|
---|
| 79 | os.chdir(args.chdir)
|
---|
| 80 |
|
---|
| 81 | if args.path:
|
---|
| 82 | extra_path = [os.path.abspath(p) for p in args.path]
|
---|
| 83 | extra_path = os.pathsep.join(extra_path)
|
---|
| 84 | os.environ["PATH"] = extra_path + os.pathsep + os.environ["PATH"]
|
---|
| 85 |
|
---|
| 86 | if not args.tests:
|
---|
| 87 | if not args.all:
|
---|
| 88 | sys.stderr.write("Specify -a to get all tests.\n")
|
---|
| 89 | return 1
|
---|
| 90 | args.tests = ["test"]
|
---|
| 91 |
|
---|
| 92 | tests = []
|
---|
| 93 | for arg in args.tests:
|
---|
| 94 | if os.path.isdir(arg):
|
---|
| 95 | tests.extend(find_all_gyptest_files(os.path.normpath(arg)))
|
---|
| 96 | else:
|
---|
| 97 | if not is_test_name(os.path.basename(arg)):
|
---|
| 98 | print(arg, "is not a valid gyp test name.", file=sys.stderr)
|
---|
| 99 | sys.exit(1)
|
---|
| 100 | tests.append(arg)
|
---|
| 101 |
|
---|
| 102 | if args.list:
|
---|
| 103 | for test in tests:
|
---|
| 104 | print(test)
|
---|
| 105 | sys.exit(0)
|
---|
| 106 |
|
---|
| 107 | os.environ["PYTHONPATH"] = os.path.abspath("test/lib")
|
---|
| 108 |
|
---|
| 109 | if args.verbose:
|
---|
| 110 | print_configuration_info()
|
---|
| 111 |
|
---|
| 112 | if args.gyp_option and not args.quiet:
|
---|
| 113 | print("Extra Gyp options: %s\n" % args.gyp_option)
|
---|
| 114 |
|
---|
| 115 | if args.format:
|
---|
| 116 | format_list = args.format.split(",")
|
---|
| 117 | else:
|
---|
| 118 | format_list = {
|
---|
| 119 | "aix5": ["make"],
|
---|
| 120 | "freebsd7": ["make"],
|
---|
| 121 | "freebsd8": ["make"],
|
---|
| 122 | "openbsd5": ["make"],
|
---|
| 123 | "cygwin": ["msvs"],
|
---|
| 124 | "win32": ["msvs", "ninja"],
|
---|
| 125 | "linux": ["make", "ninja"],
|
---|
| 126 | "linux2": ["make", "ninja"],
|
---|
| 127 | "linux3": ["make", "ninja"],
|
---|
| 128 | # TODO: Re-enable xcode-ninja.
|
---|
| 129 | # https://bugs.chromium.org/p/gyp/issues/detail?id=530
|
---|
| 130 | # 'darwin': ['make', 'ninja', 'xcode', 'xcode-ninja'],
|
---|
| 131 | "darwin": ["make", "ninja", "xcode"],
|
---|
| 132 | }[sys.platform]
|
---|
| 133 |
|
---|
| 134 | gyp_options = []
|
---|
| 135 | for option in args.gyp_option:
|
---|
| 136 | gyp_options += ["-G", option]
|
---|
| 137 |
|
---|
| 138 | runner = Runner(format_list, tests, gyp_options, args.verbose)
|
---|
| 139 | runner.run()
|
---|
| 140 |
|
---|
| 141 | if not args.quiet:
|
---|
| 142 | runner.print_results()
|
---|
| 143 |
|
---|
| 144 | if runner.failures:
|
---|
| 145 | return 1
|
---|
| 146 | else:
|
---|
| 147 | return 0
|
---|
| 148 |
|
---|
| 149 |
|
---|
| 150 | def print_configuration_info():
|
---|
| 151 | print("Test configuration:")
|
---|
| 152 | if sys.platform == "darwin":
|
---|
| 153 | sys.path.append(os.path.abspath("test/lib"))
|
---|
| 154 | import TestMac
|
---|
| 155 |
|
---|
| 156 | print(" Mac %s %s" % (platform.mac_ver()[0], platform.mac_ver()[2]))
|
---|
| 157 | print(" Xcode %s" % TestMac.Xcode.Version())
|
---|
| 158 | elif sys.platform == "win32":
|
---|
| 159 | sys.path.append(os.path.abspath("pylib"))
|
---|
| 160 | import gyp.MSVSVersion
|
---|
| 161 |
|
---|
| 162 | print(" Win %s %s\n" % platform.win32_ver()[0:2])
|
---|
| 163 | print(" MSVS %s" % gyp.MSVSVersion.SelectVisualStudioVersion().Description())
|
---|
| 164 | elif sys.platform in ("linux", "linux2"):
|
---|
| 165 | print(" Linux %s" % " ".join(platform.linux_distribution()))
|
---|
| 166 | print(" Python %s" % platform.python_version())
|
---|
| 167 | print(" PYTHONPATH=%s" % os.environ["PYTHONPATH"])
|
---|
| 168 | print()
|
---|
| 169 |
|
---|
| 170 |
|
---|
| 171 | class Runner(object):
|
---|
| 172 | def __init__(self, formats, tests, gyp_options, verbose):
|
---|
| 173 | self.formats = formats
|
---|
| 174 | self.tests = tests
|
---|
| 175 | self.verbose = verbose
|
---|
| 176 | self.gyp_options = gyp_options
|
---|
| 177 | self.failures = []
|
---|
| 178 | self.num_tests = len(formats) * len(tests)
|
---|
| 179 | num_digits = len(str(self.num_tests))
|
---|
| 180 | self.fmt_str = "[%%%dd/%%%dd] (%%s) %%s" % (num_digits, num_digits)
|
---|
| 181 | self.isatty = sys.stdout.isatty() and not self.verbose
|
---|
| 182 | self.env = os.environ.copy()
|
---|
| 183 | self.hpos = 0
|
---|
| 184 |
|
---|
| 185 | def run(self):
|
---|
| 186 | run_start = time.time()
|
---|
| 187 |
|
---|
| 188 | i = 1
|
---|
| 189 | for fmt in self.formats:
|
---|
| 190 | for test in self.tests:
|
---|
| 191 | self.run_test(test, fmt, i)
|
---|
| 192 | i += 1
|
---|
| 193 |
|
---|
| 194 | if self.isatty:
|
---|
| 195 | self.erase_current_line()
|
---|
| 196 |
|
---|
| 197 | self.took = time.time() - run_start
|
---|
| 198 |
|
---|
| 199 | def run_test(self, test, fmt, i):
|
---|
| 200 | if self.isatty:
|
---|
| 201 | self.erase_current_line()
|
---|
| 202 |
|
---|
| 203 | msg = self.fmt_str % (i, self.num_tests, fmt, test)
|
---|
| 204 | self.print_(msg)
|
---|
| 205 |
|
---|
| 206 | start = time.time()
|
---|
| 207 | cmd = [sys.executable, test] + self.gyp_options
|
---|
| 208 | self.env["TESTGYP_FORMAT"] = fmt
|
---|
| 209 | proc = subprocess.Popen(
|
---|
| 210 | cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=self.env
|
---|
| 211 | )
|
---|
| 212 | proc.wait()
|
---|
| 213 | took = time.time() - start
|
---|
| 214 |
|
---|
| 215 | stdout = proc.stdout.read().decode("utf8")
|
---|
| 216 | if proc.returncode == 2:
|
---|
| 217 | res = "skipped"
|
---|
| 218 | elif proc.returncode:
|
---|
| 219 | res = "failed"
|
---|
| 220 | self.failures.append("(%s) %s" % (test, fmt))
|
---|
| 221 | else:
|
---|
| 222 | res = "passed"
|
---|
| 223 | res_msg = " %s %.3fs" % (res, took)
|
---|
| 224 | self.print_(res_msg)
|
---|
| 225 |
|
---|
| 226 | if (
|
---|
| 227 | stdout
|
---|
| 228 | and not stdout.endswith("PASSED\n")
|
---|
| 229 | and not (stdout.endswith("NO RESULT\n"))
|
---|
| 230 | ):
|
---|
| 231 | print()
|
---|
| 232 | print("\n".join(" %s" % line for line in stdout.splitlines()))
|
---|
| 233 | elif not self.isatty:
|
---|
| 234 | print()
|
---|
| 235 |
|
---|
| 236 | def print_(self, msg):
|
---|
| 237 | print(msg, end="")
|
---|
| 238 | index = msg.rfind("\n")
|
---|
| 239 | if index == -1:
|
---|
| 240 | self.hpos += len(msg)
|
---|
| 241 | else:
|
---|
| 242 | self.hpos = len(msg) - index
|
---|
| 243 | sys.stdout.flush()
|
---|
| 244 |
|
---|
| 245 | def erase_current_line(self):
|
---|
| 246 | print("\b" * self.hpos + " " * self.hpos + "\b" * self.hpos, end="")
|
---|
| 247 | sys.stdout.flush()
|
---|
| 248 | self.hpos = 0
|
---|
| 249 |
|
---|
| 250 | def print_results(self):
|
---|
| 251 | num_failures = len(self.failures)
|
---|
| 252 | if num_failures:
|
---|
| 253 | print()
|
---|
| 254 | if num_failures == 1:
|
---|
| 255 | print("Failed the following test:")
|
---|
| 256 | else:
|
---|
| 257 | print("Failed the following %d tests:" % num_failures)
|
---|
| 258 | print("\t" + "\n\t".join(sorted(self.failures)))
|
---|
| 259 | print()
|
---|
| 260 | print(
|
---|
| 261 | "Ran %d tests in %.3fs, %d failed."
|
---|
| 262 | % (self.num_tests, self.took, num_failures)
|
---|
| 263 | )
|
---|
| 264 | print()
|
---|
| 265 |
|
---|
| 266 |
|
---|
| 267 | if __name__ == "__main__":
|
---|
| 268 | sys.exit(main())
|
---|