summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorpaulg@google.com <paulg@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-12-11 22:24:57 +0000
committerpaulg@google.com <paulg@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-12-11 22:24:57 +0000
commit699614ff7a85fe28c2a088dc611dac3192bea807 (patch)
tree29294e39ac73d494739767620096b4ac421633e6 /tools
parent94558e636ae78dfaaa996fe5b02416aad67992ca (diff)
downloadchromium_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.py26
-rw-r--r--tools/purify/common.py46
-rw-r--r--tools/purify/purify_test.py11
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.