Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Unified Diff: tools/valgrind/chrome_tests.py

Issue 16583: Make a valgrind tool in the same vein as the purify one. (Closed)
Patch Set: STOP! Grammar time! Created 11 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | tools/valgrind/chrome_tests.sh » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/valgrind/chrome_tests.py
diff --git a/tools/valgrind/chrome_tests.py b/tools/valgrind/chrome_tests.py
new file mode 100755
index 0000000000000000000000000000000000000000..d8b1d82347a055410095f2330203008c5ad14c23
--- /dev/null
+++ b/tools/valgrind/chrome_tests.py
@@ -0,0 +1,342 @@
+#!/usr/bin/python
+# Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# chrome_tests.py
+
+''' Runs various chrome tests through valgrind_test.py.
+
+This file is a copy of ../purify/chrome_tests.py. Eventually, it would be nice
+to merge these two files. For now, I'm leaving it here with sections that
+aren't supported commented out as this is more of a work in progress.
+'''
+
+import glob
+import logging
+import optparse
+import os
+import stat
+import sys
+
+import google.logging_utils
+import google.path_utils
+# Import the platform_utils up in the layout tests which have been modified to
+# work under non-Windows platforms instead of the ones that are in the
+# tools/python/google directory. (See chrome_tests.sh which sets PYTHONPATH
+# correctly.)
+import platform_utils
+
+import common
+
+
+class TestNotFound(Exception): pass
+
+
+class ChromeTests:
+ '''This class is derived from the chrome_tests.py file in ../purify/.
+
+ TODO(erg): Finish implementing this. I've commented out all the parts that I
+ don't have working yet. We still need to deal with layout tests, and long
+ term, the UI tests.
+ '''
+
+ def __init__(self, options, args, test):
+ # the known list of tests
+ self._test_list = {
+# "test_shell": self.TestTestShell,
+ "unit": self.TestUnit,
+ "net": self.TestNet,
+ "ipc": self.TestIpc,
+ "base": self.TestBase,
+# "layout": self.TestLayout,
+# "layout_all": self.TestLayoutAll,
+# "ui": self.TestUI
+ }
+
+ if test not in self._test_list:
+ raise TestNotFound("Unknown test: %s" % test)
+
+ self._options = options
+ self._args = args
+ self._test = test
+
+ script_dir = google.path_utils.ScriptDir()
+ utility = platform_utils.PlatformUtility(script_dir)
+ # Compute the top of the tree (the "source dir") from the script dir (where
+ # this script lives). We assume that the script dir is in tools/valgrind/
+ # relative to the top of the tree.
+ self._source_dir = os.path.dirname(os.path.dirname(script_dir))
+ # since this path is used for string matching, make sure it's always
+ # an absolute Windows-style path
+ self._source_dir = utility.GetAbsolutePath(self._source_dir)
+ valgrind_test = os.path.join(script_dir, "valgrind_test.py")
+ self._command_preamble = ["python", valgrind_test, "--echo_to_stdout",
+ "--source_dir=%s" % (self._source_dir)]
+
+ def _DefaultCommand(self, module, exe=None):
+ '''Generates the default command array that most tests will use.'''
+ module_dir = os.path.join(self._source_dir, module)
+
+ # For now, the suppressions files are all the same across all modules. Copy
+ # the code in the purify version of chrome_tests.py if we ever need
+ # per-module suppressions again...
+ self._data_dir = google.path_utils.ScriptDir()
+
+ if not self._options.build_dir:
+ dir_chrome = os.path.join(self._source_dir, "chrome", "Hammer")
+ dir_module = os.path.join(module_dir, "Hammer")
+ if exe:
+ exe_chrome = os.path.join(dir_chrome, exe)
+ exe_module = os.path.join(dir_module, exe)
+ if os.path.isfile(exe_chrome) and not os.path.isfile(exe_module):
+ self._options.build_dir = dir_chrome
+ elif os.path.isfile(exe_module) and not os.path.isfile(exe_chrome):
+ self._options.build_dir = dir_module
+ elif (os.stat(exe_module)[stat.ST_MTIME] >
+ os.stat(exe_chrome)[stat.ST_MTIME]):
+ self._options.build_dir = dir_module
+ else:
+ self._options.build_dir = dir_chrome
+ else:
+ if os.path.isdir(dir_chrome) and not os.path.isdir(dir_module):
+ self._options.build_dir = dir_chrome
+ elif os.path.isdir(dir_module) and not os.path.isdir(dir_chrome):
+ self._options.build_dir = dir_module
+ elif (os.stat(dir_module)[stat.ST_MTIME] >
+ os.stat(dir_chrome)[stat.ST_MTIME]):
+ self._options.build_dir = dir_module
+ else:
+ self._options.build_dir = dir_chrome
+
+ cmd = list(self._command_preamble)
+ cmd.append("--data_dir=%s" % self._data_dir)
+ if self._options.baseline:
+ cmd.append("--baseline")
+ if self._options.verbose:
+ cmd.append("--verbose")
+ if self._options.generate_suppressions:
+ cmd.append("--generate_suppressions")
+ if exe:
+ cmd.append(os.path.join(self._options.build_dir, exe))
+ return cmd
+
+ def Run(self):
+ ''' Runs the test specified by command-line argument --test '''
+ logging.info("running test %s" % (self._test))
+ return self._test_list[self._test]()
+
+ def _ReadGtestFilterFile(self, name, cmd):
+ '''Read a file which is a list of tests to filter out with --gtest_filter
+ and append the command-line option to cmd.
+ '''
+ filters = []
+ filename = os.path.join(self._data_dir, name + ".gtest.txt")
+ if os.path.exists(filename):
+ f = open(filename, 'r')
+ for line in f.readlines():
+ if line.startswith("#") or line.startswith("//") or line.isspace():
+ continue
+ line = line.rstrip()
+ filters.append(line)
+ gtest_filter = self._options.gtest_filter
+ if len(filters):
+ if gtest_filter:
+ gtest_filter += ":"
+ if gtest_filter.find("-") < 0:
+ gtest_filter += "-"
+ else:
+ gtest_filter = "-"
+ gtest_filter += ":".join(filters)
+ if gtest_filter:
+ cmd.append("--gtest_filter=%s" % gtest_filter)
+
+ def SimpleTest(self, module, name):
+ cmd = self._DefaultCommand(module, name)
+ self._ReadGtestFilterFile(name, cmd)
+ return common.RunSubprocess(cmd, 0)
+
+ def ScriptedTest(self, module, exe, name, script, multi=False, cmd_args=None,
+ out_dir_extra=None):
+ '''Valgrind a target binary, which will be executed one or more times via a
+ script or driver program.
+ Args:
+ module - which top level component this test is from (webkit, base, etc.)
+ exe - the name of the exe (it's assumed to exist in build_dir)
+ name - the name of this test (used to name output files)
+ script - the driver program or script. If it's python.exe, we use
+ search-path behavior to execute, otherwise we assume that it is in
+ build_dir.
+ multi - a boolean hint that the exe will be run multiple times, generating
+ multiple output files (without this option, only the last run will be
+ recorded and analyzed)
+ cmd_args - extra arguments to pass to the valgrind_test.py script
+ '''
+ cmd = self._DefaultCommand(module)
+ exe = os.path.join(self._options.build_dir, exe)
+ cmd.append("--exe=%s" % exe)
+ cmd.append("--name=%s" % name)
+ if multi:
+ out = os.path.join(google.path_utils.ScriptDir(),
+ "latest")
+ if out_dir_extra:
+ out = os.path.join(out, out_dir_extra)
+ if os.path.exists(out):
+ old_files = glob.glob(os.path.join(out, "*.txt"))
+ for f in old_files:
+ os.remove(f)
+ else:
+ os.makedirs(out)
+ out = os.path.join(out, "%s%%5d.txt" % name)
+ cmd.append("--out_file=%s" % out)
+ if cmd_args:
+ cmd.extend(cmd_args)
+ if script[0] != "python.exe" and not os.path.exists(script[0]):
+ script[0] = os.path.join(self._options.build_dir, script[0])
+ cmd.extend(script)
+ self._ReadGtestFilterFile(name, cmd)
+ return common.RunSubprocess(cmd, 0)
+
+ def TestBase(self):
+ return self.SimpleTest("base", "base_unittests")
+
+ def TestIpc(self):
+ return self.SimpleTest("chrome", "ipc_tests")
+
+ def TestNet(self):
+ return self.SimpleTest("net", "net_unittests")
+
+ def TestTestShell(self):
+ return self.SimpleTest("webkit", "test_shell_tests")
+
+ def TestUnit(self):
+ return self.SimpleTest("chrome", "unit_tests")
+
+# def TestLayoutAll(self):
+# return self.TestLayout(run_all=True)
+
+# def TestLayout(self, run_all=False):
+# # A "chunk file" is maintained in the local directory so that each test
+# # runs a slice of the layout tests of size chunk_size that increments with
+# # each run. Since tests can be added and removed from the layout tests at
+# # any time, this is not going to give exact coverage, but it will allow us
+# # to continuously run small slices of the layout tests under purify rather
+# # than having to run all of them in one shot.
+# chunk_num = 0
+# # Tests currently seem to take about 20-30s each.
+# chunk_size = 120 # so about 40-60 minutes per run
+# chunk_file = os.path.join(os.environ["TEMP"], "purify_layout_chunk.txt")
+# if not run_all:
+# try:
+# f = open(chunk_file)
+# if f:
+# str = f.read()
+# if len(str):
+# chunk_num = int(str)
+# # This should be enough so that we have a couple of complete runs
+# # of test data stored in the archive (although note that when we loop
+# # that we almost guaranteed won't be at the end of the test list)
+# if chunk_num > 10000:
+# chunk_num = 0
+# f.close()
+# except IOError, (errno, strerror):
+# logging.error("error reading from file %s (%d, %s)" % (chunk_file,
+# errno, strerror))
+
+# script = os.path.join(self._source_dir, "webkit", "tools", "layout_tests",
+# "run_webkit_tests.py")
+# script_cmd = ["python.exe", script, "--run-singly", "-v",
+# "--noshow-results", "--time-out-ms=200000",
+# "--nocheck-sys-deps"]
+# if not run_all:
+# script_cmd.append("--run-chunk=%d:%d" % (chunk_num, chunk_size))
+
+# if len(self._args):
+# # if the arg is a txt file, then treat it as a list of tests
+# if os.path.isfile(self._args[0]) and self._args[0][-4:] == ".txt":
+# script_cmd.append("--test-list=%s" % self._args[0])
+# else:
+# script_cmd.extend(self._args)
+
+# if run_all:
+# ret = self.ScriptedTest("webkit", "test_shell.exe", "layout",
+# script_cmd, multi=True, cmd_args=["--timeout=0"])
+# return ret
+
+# # store each chunk in its own directory so that we can find the data later
+# chunk_dir = os.path.join("layout", "chunk_%05d" % chunk_num)
+# ret = self.ScriptedTest("webkit", "test_shell.exe", "layout",
+# script_cmd, multi=True, cmd_args=["--timeout=0"],
+# out_dir_extra=chunk_dir)
+
+# # Wait until after the test runs to completion to write out the new chunk
+# # number. This way, if the bot is killed, we'll start running again from
+# # the current chunk rather than skipping it.
+# try:
+# f = open(chunk_file, "w")
+# chunk_num += 1
+# f.write("%d" % chunk_num)
+# f.close()
+# except IOError, (errno, strerror):
+# logging.error("error writing to file %s (%d, %s)" % (chunk_file, errno,
+# strerror))
+# # Since we're running small chunks of the layout tests, it's important to
+# # mark the ones that have errors in them. These won't be visible in the
+# # summary list for long, but will be useful for someone reviewing this bot.
+# return ret
+
+# def TestUI(self):
+# if not self._options.no_reinstrument:
+# instrumentation_error = self.InstrumentDll()
+# if instrumentation_error:
+# return instrumentation_error
+# return self.ScriptedTest("chrome", "chrome.exe", "ui_tests",
+# ["ui_tests.exe",
+# "--single-process",
+# "--ui-test-timeout=120000",
+# "--ui-test-action-timeout=80000",
+# "--ui-test-action-max-timeout=180000"],
+# multi=True)
+
+
+def _main(argv):
+ parser = optparse.OptionParser("usage: %prog -b <dir> -t <test> "
+ "[-t <test> ...]")
+ parser.disable_interspersed_args()
+ parser.add_option("-b", "--build_dir",
+ help="the location of the output of the compiler output")
+ parser.add_option("-t", "--test", action="append",
+ help="which test to run")
+ parser.add_option("", "--baseline", action="store_true", default=False,
+ help="generate baseline data instead of validating")
+ parser.add_option("", "--gtest_filter",
+ help="additional arguments to --gtest_filter")
+ parser.add_option("-v", "--verbose", action="store_true", default=False,
+ help="verbose output - enable debug log messages")
+ parser.add_option("", "--no-reinstrument", action="store_true", default=False,
+ help="Don't force a re-instrumentation for ui_tests")
+ parser.add_option("", "--generate_suppressions", action="store_true",
+ default=False,
+ help="Skip analysis and generate suppressions")
+
+ options, args = parser.parse_args()
+
+ if options.verbose:
+ google.logging_utils.config_root(logging.DEBUG)
+ else:
+ google.logging_utils.config_root()
+
+ if not options.test or not len(options.test):
+ parser.error("--test not specified")
+
+ for t in options.test:
+ tests = ChromeTests(options, args, t)
+ ret = tests.Run()
+ if ret: return ret
+ return 0
+
+
+if __name__ == "__main__":
+ ret = _main(sys.argv)
+ sys.exit(ret)
+
« no previous file with comments | « no previous file | tools/valgrind/chrome_tests.sh » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698