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())
|
---|