test_gyp.py 7.6 KB

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