diff options
author | paulg@google.com <paulg@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-12-11 22:24:57 +0000 |
---|---|---|
committer | paulg@google.com <paulg@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-12-11 22:24:57 +0000 |
commit | 699614ff7a85fe28c2a088dc611dac3192bea807 (patch) | |
tree | 29294e39ac73d494739767620096b4ac421633e6 /tools | |
parent | 94558e636ae78dfaaa996fe5b02416aad67992ca (diff) | |
download | chromium_src-699614ff7a85fe28c2a088dc611dac3192bea807.zip chromium_src-699614ff7a85fe28c2a088dc611dac3192bea807.tar.gz chromium_src-699614ff7a85fe28c2a088dc611dac3192bea807.tar.bz2 |
Preliminary support for running the ui_tests under Purify.
This current change doesn't quite work: the blocking instrumentation
of chrome.dll succeeds, but when the ui_test runs, it re-instruments
chrome.dll even though it exists under the same name in the
instrumentation cache.
Review URL: http://codereview.chromium.org/14003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@6833 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'tools')
-rw-r--r-- | tools/purify/chrome_tests.py | 26 | ||||
-rw-r--r-- | tools/purify/common.py | 46 | ||||
-rw-r--r-- | tools/purify/purify_test.py | 11 |
3 files changed, 65 insertions, 18 deletions
diff --git a/tools/purify/chrome_tests.py b/tools/purify/chrome_tests.py index b8491ee..d4a1b88 100644 --- a/tools/purify/chrome_tests.py +++ b/tools/purify/chrome_tests.py @@ -20,8 +20,10 @@ import google.platform_utils import common + class TestNotFound(Exception): pass + class ChromeTests: def __init__(self, options, args, test): @@ -32,6 +34,7 @@ class ChromeTests: "ipc": self.TestIpc, "base": self.TestBase, "layout": self.TestLayout, + "dll": self.TestDll, "layout_all": self.TestLayoutAll, "ui": self.TestUI} @@ -88,7 +91,7 @@ class ChromeTests: else: self._options.build_dir = dir_chrome - cmd = self._command_preamble + cmd = list(self._command_preamble) cmd.append("--data_dir=%s" % self._data_dir) if self._options.baseline: cmd.append("--baseline") @@ -169,6 +172,20 @@ class ChromeTests: self._ReadGtestFilterFile(name, cmd) return common.RunSubprocess(cmd, 0) + def InstrumentDll(self): + '''Does a blocking Purify instrumentation of chrome.dll.''' + # TODO(paulg): Make this code support any DLL. + cmd = self._DefaultCommand("chrome") + cmd.append("--instrument_only") + cmd.append(os.path.join(self._options.build_dir, "chrome.dll")) + result = common.RunSubprocess(cmd, 0) + if result: + logging.error("Instrumentation error: %d" % result) + return result + + def TestDll(self): + return self.InstrumentDll() + def TestBase(self): return self.SimpleTest("base", "base_unittests.exe") @@ -259,9 +276,13 @@ class ChromeTests: return ret def TestUI(self): + instrumentation_error = self.InstrumentDll() + if instrumentation_error: + return instrumentation_error return self.ScriptedTest("chrome", "chrome.exe", "ui_tests", ["ui_tests.exe", "--single-process", "--test-timeout=100000000"], multi=True) + def _main(argv): parser = optparse.OptionParser("usage: %prog -b <dir> -t <test> " "[-t <test> ...]") @@ -276,7 +297,7 @@ def _main(argv): help="additional arguments to --gtest_filter") parser.add_option("-v", "--verbose", action="store_true", default=False, help="verbose output - enable debug log messages") - (options, args) = parser.parse_args() + options, args = parser.parse_args() if options.verbose: google.logging_utils.config_root(logging.DEBUG) @@ -292,6 +313,7 @@ def _main(argv): if ret: return ret return 0 + if __name__ == "__main__": ret = _main(sys.argv) sys.exit(ret) diff --git a/tools/purify/common.py b/tools/purify/common.py index 362badb..6fb96fc 100644 --- a/tools/purify/common.py +++ b/tools/purify/common.py @@ -48,6 +48,7 @@ QUANTIFYW_PATH = os.path.join(PPLUS_PATH, "quantifyw.exe") class TimeoutError(Exception): pass + def RunSubprocess(proc, timeout=0, detach=False): """ Runs a subprocess, polling every .2 seconds until it finishes or until timeout is reached. Then kills the process with taskkill. A timeout <= 0 @@ -77,16 +78,17 @@ def RunSubprocess(proc, timeout=0, detach=False): result = p.poll() if result is None: subprocess.call(["taskkill", "/T", "/F", "/PID", str(p.pid)]) - logging.error("KILLED %d" % (p.pid)) + logging.error("KILLED %d" % p.pid) # give the process a chance to actually die before continuing # so that cleanup can happen safely time.sleep(1.0) - logging.error("TIMEOUT waiting for %s" % (proc[0])) + logging.error("TIMEOUT waiting for %s" % proc[0]) raise TimeoutError(proc[0]) if result: logging.error("%s exited with non-zero result code %d" % (proc[0], result)) return result + def FixPath(path): """We pass computed paths to Rational as arguments, so these paths must be valid windows paths. When running in cygwin's python, computed paths @@ -98,6 +100,7 @@ def FixPath(path): p = subprocess.Popen(["cygpath", "-a", "-m", path], stdout=subprocess.PIPE) return p.communicate()[0].rstrip() + class Rational(object): ''' Common superclass for Purify and Quantify automation objects. Handles common argument parsing as well as the general program flow of Instrument, @@ -114,17 +117,7 @@ class Rational(object): start = datetime.datetime.now() retcode = -1 if self.Setup(): - if self.Instrument(): - if self.Execute(): - retcode = self.Analyze() - if not retcode: - logging.info("instrumentation and execution completed successfully.") - else: - logging.error("Analyze failed") - else: - logging.error("Execute failed") - else: - logging.error("Instrument failed") + retcode = self._Run() self.Cleanup() else: logging.error("Setup failed") @@ -137,6 +130,24 @@ class Rational(object): logging.info("elapsed time: %02d:%02d:%02d" % (hours, minutes, seconds)) return retcode + def _Run(self): + retcode = -1 + if not self.Instrument(): + logging.error("Instrumentation failed.") + return retcode + if self._instrument_only: + logging.info("Instrumentation completed successfully.") + return 0 + if not self.Execute(): + logging.error("Execute failed.") + return + retcode = self.Analyze() + if recode: + logging.error("Analyze failed.") + return retcode + logging.info("Instrumentation and execution completed successfully.") + return 0 + def CreateOptionParser(self): '''Creates OptionParser with shared arguments. Overridden by subclassers to add custom arguments.''' @@ -161,6 +172,9 @@ class Rational(object): help="timeout in seconds for the run (default 10000)") parser.add_option("-v", "--verbose", action="store_true", default=False, help="verbose output - enable debug log messages") + parser.add_option("", "--instrument_only", action="store_true", + default=False, + help="Only instrument the target without running") self._parser = parser def Setup(self): @@ -185,6 +199,9 @@ class Rational(object): if "/Replace=yes" in proc: if os.path.exists(self._exe + ".Original"): return True + elif self._instrument_only: + # TODO(paulg): Catch instrumentation errors and clean up properly. + return True elif os.path.isdir(self._cache_dir): for cfile in os.listdir(self._cache_dir): # TODO(erikkay): look for the actual munged purify filename @@ -216,7 +233,7 @@ class Rational(object): '''Parses arguments according to CreateOptionParser Subclassers must override if they have extra arguments.''' self.CreateOptionParser() - (self._options, self._args) = self._parser.parse_args() + self._options, self._args = self._parser.parse_args() if self._options.verbose: google.logging_utils.config_root(logging.DEBUG) self._save_cache = self._options.save_cache @@ -245,6 +262,7 @@ class Rational(object): return False self._exe = self._args[0] self._exe_dir = FixPath(os.path.abspath(os.path.dirname(self._exe))) + self._instrument_only = self._options.instrument_only return True def Cleanup(self): diff --git a/tools/purify/purify_test.py b/tools/purify/purify_test.py index a2733e7..2d8f48a 100644 --- a/tools/purify/purify_test.py +++ b/tools/purify/purify_test.py @@ -92,6 +92,8 @@ class Purify(common.Rational): script_dir = google.path_utils.ScriptDir() self._latest_dir = os.path.join(script_dir, "latest") if common.Rational.Setup(self): + if self._instrument_only: + return True pft_file = os.path.join(script_dir, "data", "filters.pft") shutil.copyfile(pft_file, self._exe.replace(".exe", "_exe.pft")) string_list = [ @@ -126,8 +128,11 @@ class Purify(common.Rational): logging.error("file doesn't exist " + self._exe) return False cmd = self._PurifyCommand() - # /Run=no means instrument only, /Replace=yes means replace the exe in place - cmd.extend(["/Run=no", "/Replace=yes"]) + # /Run=no means instrument + cmd.extend(["/Run=no"]) + if not self._instrument_only: + # /Replace=yes means replace the exe in place + cmd.extend(["/Replace=yes"]) cmd.append(os.path.abspath(self._exe)) return common.Rational.Instrument(self, cmd) @@ -198,6 +203,8 @@ class Purify(common.Rational): def Cleanup(self): common.Rational.Cleanup(self); + if self._instrument_only: + return cmd = self._PurifyCommand() # undo the /Replace=yes that was done in Instrument(), which means to # remove the instrumented exe, and then rename exe.Original back to exe. |