| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 # chrome_tests.py | 6 # chrome_tests.py |
| 7 | 7 |
| 8 ''' Runs various chrome tests through valgrind_test.py.''' | 8 ''' Runs various chrome tests through valgrind_test.py.''' |
| 9 | 9 |
| 10 import glob | 10 import glob |
| 11 import logging | 11 import logging |
| 12 import optparse | 12 import optparse |
| 13 import os | 13 import os |
| 14 import stat | 14 import stat |
| 15 import sys | 15 import sys |
| 16 | 16 |
| 17 import logging_utils | 17 import logging_utils |
| 18 import path_utils | 18 import path_utils |
| 19 | 19 |
| 20 import common | 20 import common |
| 21 import valgrind_test | 21 import valgrind_test |
| 22 | 22 |
| 23 class TestNotFound(Exception): pass | 23 class TestNotFound(Exception): pass |
| 24 | 24 |
| 25 class MultipleGTestFiltersSpecified(Exception): pass |
| 26 |
| 25 def Dir2IsNewer(dir1, dir2): | 27 def Dir2IsNewer(dir1, dir2): |
| 26 if dir2 == None or not os.path.isdir(dir2): | 28 if dir2 == None or not os.path.isdir(dir2): |
| 27 return False | 29 return False |
| 28 if dir1 == None or not os.path.isdir(dir1): | 30 if dir1 == None or not os.path.isdir(dir1): |
| 29 return True | 31 return True |
| 30 return (os.stat(dir2)[stat.ST_MTIME] - os.stat(dir1)[stat.ST_MTIME]) > 0 | 32 return (os.stat(dir2)[stat.ST_MTIME] - os.stat(dir1)[stat.ST_MTIME]) > 0 |
| 31 | 33 |
| 32 def FindNewestDir(dirs): | 34 def FindNewestDir(dirs): |
| 33 newest_dir = None | 35 newest_dir = None |
| 34 for dir in dirs: | 36 for dir in dirs: |
| (...skipping 16 matching lines...) Expand all Loading... |
| 51 if File2IsNewer(newest_file, the_file): | 53 if File2IsNewer(newest_file, the_file): |
| 52 newest_dir = dir | 54 newest_dir = dir |
| 53 newest_file = the_file | 55 newest_file = the_file |
| 54 if newest_dir == None: | 56 if newest_dir == None: |
| 55 logging.error("cannot find file %s anywhere, have you built it?" % file) | 57 logging.error("cannot find file %s anywhere, have you built it?" % file) |
| 56 sys.exit(-1) | 58 sys.exit(-1) |
| 57 return newest_dir | 59 return newest_dir |
| 58 | 60 |
| 59 class ChromeTests: | 61 class ChromeTests: |
| 60 def __init__(self, options, args, test): | 62 def __init__(self, options, args, test): |
| 61 # The known list of tests. | 63 if ':' in test: |
| 62 # Recognise the original abbreviations as well as full executable names. | 64 (self._test, self._gtest_filter) = test.split(':', 1) |
| 63 self._test_list = { | 65 else: |
| 64 "base": self.TestBase, "base_unittests": self.TestBase, | 66 self._test = test |
| 65 "browser": self.TestBrowser, "browser_tests": self.TestBrowser, | 67 self._gtest_filter = options.gtest_filter |
| 66 "googleurl": self.TestGURL, "googleurl_unittests": self.TestGURL, | |
| 67 "ipc": self.TestIpc, "ipc_tests": self.TestIpc, | |
| 68 "layout": self.TestLayout, "layout_tests": self.TestLayout, | |
| 69 "media": self.TestMedia, "media_unittests": self.TestMedia, | |
| 70 "net": self.TestNet, "net_unittests": self.TestNet, | |
| 71 "printing": self.TestPrinting, "printing_unittests": self.TestPrinting, | |
| 72 "startup": self.TestStartup, "startup_tests": self.TestStartup, | |
| 73 "sync": self.TestSync, "sync_unit_tests": self.TestSync, | |
| 74 "test_shell": self.TestTestShell, "test_shell_tests": self.TestTestShell, | |
| 75 "ui": self.TestUI, "ui_tests": self.TestUI, | |
| 76 "unit": self.TestUnit, "unit_tests": self.TestUnit, | |
| 77 "app": self.TestApp, "app_unittests": self.TestApp, | |
| 78 } | |
| 79 | 68 |
| 80 if test not in self._test_list: | 69 if self._test not in self._test_list: |
| 81 raise TestNotFound("Unknown test: %s" % test) | 70 raise TestNotFound("Unknown test: %s" % test) |
| 82 | 71 |
| 72 if options.gtest_filter and options.gtest_filter != self._gtest_filter: |
| 73 raise MultipleGTestFiltersSpecified("Can not specify both --gtest_filter " |
| 74 "and --test %s" % test) |
| 75 |
| 83 self._options = options | 76 self._options = options |
| 84 self._args = args | 77 self._args = args |
| 85 self._test = test | |
| 86 | 78 |
| 87 script_dir = path_utils.ScriptDir() | 79 script_dir = path_utils.ScriptDir() |
| 88 # Compute the top of the tree (the "source dir") from the script dir (where | 80 # Compute the top of the tree (the "source dir") from the script dir (where |
| 89 # this script lives). We assume that the script dir is in tools/valgrind/ | 81 # this script lives). We assume that the script dir is in tools/valgrind/ |
| 90 # relative to the top of the tree. | 82 # relative to the top of the tree. |
| 91 self._source_dir = os.path.dirname(os.path.dirname(script_dir)) | 83 self._source_dir = os.path.dirname(os.path.dirname(script_dir)) |
| 92 # since this path is used for string matching, make sure it's always | 84 # since this path is used for string matching, make sure it's always |
| 93 # an absolute Unix-style path | 85 # an absolute Unix-style path |
| 94 self._source_dir = os.path.abspath(self._source_dir).replace('\\', '/') | 86 self._source_dir = os.path.abspath(self._source_dir).replace('\\', '/') |
| 95 valgrind_test_script = os.path.join(script_dir, "valgrind_test.py") | 87 valgrind_test_script = os.path.join(script_dir, "valgrind_test.py") |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 156 # Valgrind runs tests slowly, so slow tests hurt more; show elapased time | 148 # Valgrind runs tests slowly, so slow tests hurt more; show elapased time |
| 157 # so we can find the slowpokes. | 149 # so we can find the slowpokes. |
| 158 cmd.append("--gtest_print_time") | 150 cmd.append("--gtest_print_time") |
| 159 if self._options.gtest_repeat: | 151 if self._options.gtest_repeat: |
| 160 cmd.append("--gtest_repeat=%s" % self._options.gtest_repeat) | 152 cmd.append("--gtest_repeat=%s" % self._options.gtest_repeat) |
| 161 return cmd | 153 return cmd |
| 162 | 154 |
| 163 def Run(self): | 155 def Run(self): |
| 164 ''' Runs the test specified by command-line argument --test ''' | 156 ''' Runs the test specified by command-line argument --test ''' |
| 165 logging.info("running test %s" % (self._test)) | 157 logging.info("running test %s" % (self._test)) |
| 166 return self._test_list[self._test]() | 158 return self._test_list[self._test](self) |
| 167 | 159 |
| 168 def _ReadGtestFilterFile(self, name, cmd): | 160 def _ReadGtestFilterFile(self, name, cmd): |
| 169 '''Read a file which is a list of tests to filter out with --gtest_filter | 161 '''Read a file which is a list of tests to filter out with --gtest_filter |
| 170 and append the command-line option to cmd. | 162 and append the command-line option to cmd. |
| 171 ''' | 163 ''' |
| 172 filters = [] | 164 filters = [] |
| 173 for directory in self._data_dirs: | 165 for directory in self._data_dirs: |
| 174 gtest_filter_files = [ | 166 gtest_filter_files = [ |
| 175 os.path.join(directory, name + ".gtest.txt"), | 167 os.path.join(directory, name + ".gtest.txt"), |
| 176 os.path.join(directory, name + ".gtest-%s.txt" % \ | 168 os.path.join(directory, name + ".gtest-%s.txt" % \ |
| 177 self._options.valgrind_tool)] | 169 self._options.valgrind_tool)] |
| 178 for platform_suffix in common.PlatformNames(): | 170 for platform_suffix in common.PlatformNames(): |
| 179 gtest_filter_files += [ | 171 gtest_filter_files += [ |
| 180 os.path.join(directory, name + ".gtest_%s.txt" % platform_suffix), | 172 os.path.join(directory, name + ".gtest_%s.txt" % platform_suffix), |
| 181 os.path.join(directory, name + ".gtest-%s_%s.txt" % \ | 173 os.path.join(directory, name + ".gtest-%s_%s.txt" % \ |
| 182 (self._options.valgrind_tool, platform_suffix))] | 174 (self._options.valgrind_tool, platform_suffix))] |
| 183 for filename in gtest_filter_files: | 175 for filename in gtest_filter_files: |
| 184 if os.path.exists(filename): | 176 if os.path.exists(filename): |
| 185 logging.info("reading gtest filters from %s" % filename) | 177 logging.info("reading gtest filters from %s" % filename) |
| 186 f = open(filename, 'r') | 178 f = open(filename, 'r') |
| 187 for line in f.readlines(): | 179 for line in f.readlines(): |
| 188 if line.startswith("#") or line.startswith("//") or line.isspace(): | 180 if line.startswith("#") or line.startswith("//") or line.isspace(): |
| 189 continue | 181 continue |
| 190 line = line.rstrip() | 182 line = line.rstrip() |
| 191 filters.append(line) | 183 filters.append(line) |
| 192 gtest_filter = self._options.gtest_filter | 184 gtest_filter = self._gtest_filter |
| 193 if len(filters): | 185 if len(filters): |
| 194 if gtest_filter: | 186 if gtest_filter: |
| 195 gtest_filter += ":" | 187 gtest_filter += ":" |
| 196 if gtest_filter.find("-") < 0: | 188 if gtest_filter.find("-") < 0: |
| 197 gtest_filter += "-" | 189 gtest_filter += "-" |
| 198 else: | 190 else: |
| 199 gtest_filter = "-" | 191 gtest_filter = "-" |
| 200 gtest_filter += ":".join(filters) | 192 gtest_filter += ":".join(filters) |
| 201 if gtest_filter: | 193 if gtest_filter: |
| 202 cmd.append("--gtest_filter=%s" % gtest_filter) | 194 cmd.append("--gtest_filter=%s" % gtest_filter) |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 367 f.write("%d" % chunk_num) | 359 f.write("%d" % chunk_num) |
| 368 f.close() | 360 f.close() |
| 369 except IOError, (errno, strerror): | 361 except IOError, (errno, strerror): |
| 370 logging.error("error writing to file %s (%d, %s)" % (chunk_file, errno, | 362 logging.error("error writing to file %s (%d, %s)" % (chunk_file, errno, |
| 371 strerror)) | 363 strerror)) |
| 372 # Since we're running small chunks of the layout tests, it's important to | 364 # Since we're running small chunks of the layout tests, it's important to |
| 373 # mark the ones that have errors in them. These won't be visible in the | 365 # mark the ones that have errors in them. These won't be visible in the |
| 374 # summary list for long, but will be useful for someone reviewing this bot. | 366 # summary list for long, but will be useful for someone reviewing this bot. |
| 375 return ret | 367 return ret |
| 376 | 368 |
| 369 # The known list of tests. |
| 370 # Recognise the original abbreviations as well as full executable names. |
| 371 _test_list = { |
| 372 "base": TestBase, "base_unittests": TestBase, |
| 373 "browser": TestBrowser, "browser_tests": TestBrowser, |
| 374 "googleurl": TestGURL, "googleurl_unittests": TestGURL, |
| 375 "ipc": TestIpc, "ipc_tests": TestIpc, |
| 376 "layout": TestLayout, "layout_tests": TestLayout, |
| 377 "media": TestMedia, "media_unittests": TestMedia, |
| 378 "net": TestNet, "net_unittests": TestNet, |
| 379 "printing": TestPrinting, "printing_unittests": TestPrinting, |
| 380 "startup": TestStartup, "startup_tests": TestStartup, |
| 381 "sync": TestSync, "sync_unit_tests": TestSync, |
| 382 "test_shell": TestTestShell, "test_shell_tests": TestTestShell, |
| 383 "ui": TestUI, "ui_tests": TestUI, |
| 384 "unit": TestUnit, "unit_tests": TestUnit, |
| 385 "app": TestApp, "app_unittests": TestApp, |
| 386 } |
| 387 |
| 377 def _main(_): | 388 def _main(_): |
| 378 parser = optparse.OptionParser("usage: %prog -b <dir> -t <test> " | 389 parser = optparse.OptionParser("usage: %prog -b <dir> -t <test> " |
| 379 "[-t <test> ...]") | 390 "[-t <test> ...]") |
| 380 parser.disable_interspersed_args() | 391 parser.disable_interspersed_args() |
| 381 parser.add_option("-b", "--build_dir", | 392 parser.add_option("-b", "--build_dir", |
| 382 help="the location of the output of the compiler output") | 393 help="the location of the output of the compiler output") |
| 383 parser.add_option("-t", "--test", action="append", | 394 parser.add_option("-t", "--test", action="append", default=[], |
| 384 help="which test to run") | 395 help="which test to run, supports test:gtest_filter format " |
| 396 "as well.") |
| 385 parser.add_option("", "--baseline", action="store_true", default=False, | 397 parser.add_option("", "--baseline", action="store_true", default=False, |
| 386 help="generate baseline data instead of validating") | 398 help="generate baseline data instead of validating") |
| 387 parser.add_option("", "--gtest_filter", | 399 parser.add_option("", "--gtest_filter", |
| 388 help="additional arguments to --gtest_filter") | 400 help="additional arguments to --gtest_filter") |
| 389 parser.add_option("", "--gtest_repeat", | 401 parser.add_option("", "--gtest_repeat", |
| 390 help="argument for --gtest_repeat") | 402 help="argument for --gtest_repeat") |
| 391 parser.add_option("-v", "--verbose", action="store_true", default=False, | 403 parser.add_option("-v", "--verbose", action="store_true", default=False, |
| 392 help="verbose output - enable debug log messages") | 404 help="verbose output - enable debug log messages") |
| 393 parser.add_option("", "--tool", dest="valgrind_tool", default="memcheck", | 405 parser.add_option("", "--tool", dest="valgrind_tool", default="memcheck", |
| 394 help="specify a valgrind tool to run the tests under") | 406 help="specify a valgrind tool to run the tests under") |
| 395 parser.add_option("", "--tool_flags", dest="valgrind_tool_flags", default="", | 407 parser.add_option("", "--tool_flags", dest="valgrind_tool_flags", default="", |
| 396 help="specify custom flags for the selected valgrind tool") | 408 help="specify custom flags for the selected valgrind tool") |
| 397 # My machine can do about 120 layout tests/hour in release mode. | 409 # My machine can do about 120 layout tests/hour in release mode. |
| 398 # Let's do 30 minutes worth per run. | 410 # Let's do 30 minutes worth per run. |
| 399 # The CPU is mostly idle, so perhaps we can raise this when | 411 # The CPU is mostly idle, so perhaps we can raise this when |
| 400 # we figure out how to run them more efficiently. | 412 # we figure out how to run them more efficiently. |
| 401 parser.add_option("-n", "--num_tests", default=60, type="int", | 413 parser.add_option("-n", "--num_tests", default=60, type="int", |
| 402 help="for layout tests: # of subtests per run. 0 for all.") | 414 help="for layout tests: # of subtests per run. 0 for all.") |
| 403 | 415 |
| 404 options, args = parser.parse_args() | 416 options, args = parser.parse_args() |
| 405 | 417 |
| 406 if options.verbose: | 418 if options.verbose: |
| 407 logging_utils.config_root(logging.DEBUG) | 419 logging_utils.config_root(logging.DEBUG) |
| 408 else: | 420 else: |
| 409 logging_utils.config_root() | 421 logging_utils.config_root() |
| 410 | 422 |
| 411 if not options.test or not len(options.test): | 423 if not options.test: |
| 412 parser.error("--test not specified") | 424 parser.error("--test not specified") |
| 413 | 425 |
| 426 if len(options.test) != 1 and options.gtest_filter: |
| 427 parser.error("--gtest_filter and multiple tests don't make sense together") |
| 428 |
| 414 for t in options.test: | 429 for t in options.test: |
| 415 tests = ChromeTests(options, args, t) | 430 tests = ChromeTests(options, args, t) |
| 416 ret = tests.Run() | 431 ret = tests.Run() |
| 417 if ret: return ret | 432 if ret: return ret |
| 418 return 0 | 433 return 0 |
| 419 | 434 |
| 420 | 435 |
| 421 if __name__ == "__main__": | 436 if __name__ == "__main__": |
| 422 ret = _main(sys.argv) | 437 ret = _main(sys.argv) |
| 423 sys.exit(ret) | 438 sys.exit(ret) |
| OLD | NEW |