Orange on Bd builds: Backed out changeset 745af1f3dbf5
authorClint Talbert <ctalbert@mozilla.com>
Wed, 13 Jan 2010 14:44:49 -0800
changeset 37161 b5d9fbeec04ed773b9f8c23973fe0e16e301343b
parent 37159 745af1f3dbf5bdb93a95e38d0a534ba489754cc8
child 37162 2c86dc6d6ec4412b534cafa2624f0bdc448ead9a
push idunknown
push userunknown
push dateunknown
milestone1.9.3a1pre
Orange on Bd builds: Backed out changeset 745af1f3dbf5
build/automation.py.in
build/leaktest.py.in
build/pgo/genpgocert.py.in
build/pgo/profileserver.py.in
layout/tools/reftest/runreftest.py
testing/mochitest/runtests.py.in
testing/xpcshell/runxpcshelltests.py
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -46,35 +46,107 @@ import re
 import select
 import shutil
 import signal
 import subprocess
 import sys
 import threading
 import tempfile
 
+"""
+Runs the browser from a script, and provides useful utilities
+for setting up the browser environment.
+"""
 
-#expand _DIST_BIN = __XPC_BIN_PATH__
-#expand _IS_WIN32 = len("__WIN32__") != 0
-#expand _IS_MAC = __IS_MAC__ != 0
-#expand _IS_LINUX = __IS_LINUX__ != 0
+SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
+sys.path.insert(0, SCRIPT_DIR);
+from automationutils import checkForCrashes
+
+__all__ = [
+           "UNIXISH",
+           "IS_WIN32",
+           "IS_MAC",
+           "log",
+           "runApp",
+           "Process",
+           "addExtraCommonOptions",
+           "initializeProfile",
+           "DIST_BIN",
+           "DEFAULT_APP",
+           "CERTS_SRC_DIR",
+           "environment",
+           "IS_TEST_BUILD",
+           "IS_DEBUG_BUILD",
+           "DEFAULT_TIMEOUT",
+          ]
+
+# timeout, in seconds
+DEFAULT_TIMEOUT = 60.0
+
+# These are generated in mozilla/build/Makefile.in
+#expand DIST_BIN = __XPC_BIN_PATH__
+#expand IS_WIN32 = len("__WIN32__") != 0
+#expand IS_MAC = __IS_MAC__ != 0
+#expand IS_LINUX = __IS_LINUX__ != 0
 #ifdef IS_CYGWIN
-#expand _IS_CYGWIN = __IS_CYGWIN__ == 1
+#expand IS_CYGWIN = __IS_CYGWIN__ == 1
 #else
-_IS_CYGWIN = False
+IS_CYGWIN = False
 #endif
-#expand _IS_CAMINO = __IS_CAMINO__ != 0
-#expand _BIN_SUFFIX = __BIN_SUFFIX__
-#expand _PERL = __PERL__
+#expand IS_CAMINO = __IS_CAMINO__ != 0
+#expand BIN_SUFFIX = __BIN_SUFFIX__
+#expand PERL = __PERL__
+
+UNIXISH = not IS_WIN32 and not IS_MAC
+
+#expand DEFAULT_APP = "./" + __BROWSER_PATH__
+#expand CERTS_SRC_DIR = __CERTS_SRC_DIR__
+#expand IS_TEST_BUILD = __IS_TEST_BUILD__
+#expand IS_DEBUG_BUILD = __IS_DEBUG_BUILD__
+#expand CRASHREPORTER = __CRASHREPORTER__ == 1
+
+###########
+# LOGGING #
+###########
+
+# We use the logging system here primarily because it'll handle multiple
+# threads, which is needed to process the output of the server and application
+# processes simultaneously.
+log = logging.getLogger()
+handler = logging.StreamHandler(sys.stdout)
+log.setLevel(logging.INFO)
+log.addHandler(handler)
+
 
-#expand _DEFAULT_APP = "./" + __BROWSER_PATH__
-#expand _CERTS_SRC_DIR = __CERTS_SRC_DIR__
-#expand _IS_TEST_BUILD = __IS_TEST_BUILD__
-#expand _IS_DEBUG_BUILD = __IS_DEBUG_BUILD__
-#expand _CRASHREPORTER = __CRASHREPORTER__ == 1
+#################
+# SUBPROCESSING #
+#################
+
+class Process(subprocess.Popen):
+  """
+  Represents our view of a subprocess.
+  It adds a kill() method which allows it to be stopped explicitly.
+  """
+
+  def kill(self):
+    if IS_WIN32:
+      import platform
+      pid = "%i" % self.pid
+      if platform.release() == "2000":
+        # Windows 2000 needs 'kill.exe' from the 'Windows 2000 Resource Kit tools'. (See bug 475455.)
+        try:
+          subprocess.Popen(["kill", "-f", pid]).wait()
+        except:
+          log.info("TEST-UNEXPECTED-FAIL | automation.py | Missing 'kill' utility to kill process with pid=%s. Kill it manually!", pid)
+      else:
+        # Windows XP and later.
+        subprocess.Popen(["taskkill", "/F", "/PID", pid]).wait()
+    else:
+      os.kill(self.pid, signal.SIGKILL)
+
 
 #################
 # PROFILE SETUP #
 #################
 
 class SyntaxError(Exception):
   "Signifies a syntax error on a particular line in server-locations.txt."
 
@@ -95,166 +167,83 @@ class Location:
   "Represents a location line in server-locations.txt."
 
   def __init__(self, scheme, host, port, options):
     self.scheme = scheme
     self.host = host
     self.port = port
     self.options = options
 
-class Automation(object):
+
+def readLocations(locationsPath = "server-locations.txt"):
   """
-  Runs the browser from a script, and provides useful utilities
-  for setting up the browser environment.
+  Reads the locations at which the Mochitest HTTP server is available from
+  server-locations.txt.
   """
 
-  DIST_BIN = _DIST_BIN
-  IS_WIN32 = _IS_WIN32
-  IS_MAC = _IS_MAC
-  IS_LINUX = _IS_LINUX
-  IS_CYGWIN = _IS_CYGWIN
-  IS_CAMINO = _IS_CAMINO
-  BIN_SUFFIX = _BIN_SUFFIX
-  PERL = _PERL
-
-  UNIXISH = not IS_WIN32 and not IS_MAC
-
-  DEFAULT_APP = _DEFAULT_APP
-  CERTS_SRC_DIR = _CERTS_SRC_DIR
-  IS_TEST_BUILD = _IS_TEST_BUILD
-  IS_DEBUG_BUILD = _IS_DEBUG_BUILD
-  CRASHREPORTER = _CRASHREPORTER
-
-  SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
-  sys.path.insert(0, SCRIPT_DIR)
-  automationutils = __import__('automationutils')
-
-  # timeout, in seconds
-  DEFAULT_TIMEOUT = 60.0
-
-  log = logging.getLogger()
-
-  def __init__(self):
-
-    # We use the logging system here primarily because it'll handle multiple
-    # threads, which is needed to process the output of the server and application
-    # processes simultaneously.
-    handler = logging.StreamHandler(sys.stdout)
-    self.log.setLevel(logging.INFO)
-    self.log.addHandler(handler)
+  locationFile = codecs.open(locationsPath, "r", "UTF-8")
 
-  @property
-  def __all__(self):
-    return [
-           "UNIXISH",
-           "IS_WIN32",
-           "IS_MAC",
-           "log",
-           "runApp",
-           "Process",
-           "addCommonOptions",
-           "initializeProfile",
-           "DIST_BIN",
-           "DEFAULT_APP",
-           "CERTS_SRC_DIR",
-           "environment",
-           "IS_TEST_BUILD",
-           "IS_DEBUG_BUILD",
-           "DEFAULT_TIMEOUT",
-          ]
-
-  class Process(subprocess.Popen):
-    """
-    Represents our view of a subprocess.
-    It adds a kill() method which allows it to be stopped explicitly.
-    """
-
-    def kill(self):
-      if Automation().IS_WIN32:
-        import platform
-        pid = "%i" % self.pid
-        if platform.release() == "2000":
-          # Windows 2000 needs 'kill.exe' from the 
-          #'Windows 2000 Resource Kit tools'. (See bug 475455.)
-          try:
-            subprocess.Popen(["kill", "-f", pid]).wait()
-          except:
-            self.log.info("TEST-UNEXPECTED-FAIL | automation.py | Missing 'kill' utility to kill process with pid=%s. Kill it manually!", pid)
-        else:
-          # Windows XP and later.
-          subprocess.Popen(["taskkill", "/F", "/PID", pid]).wait()
-      else:
-        os.kill(self.pid, signal.SIGKILL)
-
-  def readLocations(self, locationsPath = "server-locations.txt"):
-    """
-    Reads the locations at which the Mochitest HTTP server is available from
-    server-locations.txt.
-    """
-
-    locationFile = codecs.open(locationsPath, "r", "UTF-8")
-
-    # Perhaps more detail than necessary, but it's the easiest way to make sure
-    # we get exactly the format we want.  See server-locations.txt for the exact
-    # format guaranteed here.
-    lineRe = re.compile(r"^(?P<scheme>[a-z][-a-z0-9+.]*)"
+  # Perhaps more detail than necessary, but it's the easiest way to make sure
+  # we get exactly the format we want.  See server-locations.txt for the exact
+  # format guaranteed here.
+  lineRe = re.compile(r"^(?P<scheme>[a-z][-a-z0-9+.]*)"
                       r"://"
                       r"(?P<host>"
                         r"\d+\.\d+\.\d+\.\d+"
                         r"|"
                         r"(?:[a-z0-9](?:[-a-z0-9]*[a-z0-9])?\.)*"
                         r"[a-z](?:[-a-z0-9]*[a-z0-9])?"
                       r")"
                       r":"
                       r"(?P<port>\d+)"
                       r"(?:"
                       r"\s+"
                       r"(?P<options>\S+(?:,\S+)*)"
                       r")?$")
-    locations = []
-    lineno = 0
-    seenPrimary = False
-    for line in locationFile:
-      lineno += 1
-      if line.startswith("#") or line == "\n":
-        continue
+  locations = []
+  lineno = 0
+  seenPrimary = False
+  for line in locationFile:
+    lineno += 1
+    if line.startswith("#") or line == "\n":
+      continue
       
-      match = lineRe.match(line)
-      if not match:
-        raise SyntaxError(lineno)
+    match = lineRe.match(line)
+    if not match:
+      raise SyntaxError(lineno)
 
-      options = match.group("options")
-      if options:
-        options = options.split(",")
-        if "primary" in options:
-          if seenPrimary:
-            raise SyntaxError(lineno, "multiple primary locations")
-          seenPrimary = True
-      else:
-        options = []
+    options = match.group("options")
+    if options:
+      options = options.split(",")
+      if "primary" in options:
+        if seenPrimary:
+          raise SyntaxError(lineno, "multiple primary locations")
+        seenPrimary = True
+    else:
+      options = []
 
-      locations.append(Location(match.group("scheme"), match.group("host"),
-                                match.group("port"), options))
+    locations.append(Location(match.group("scheme"), match.group("host"),
+                              match.group("port"), options))
 
-    if not seenPrimary:
-      raise SyntaxError(lineno + 1, "missing primary location")
+  if not seenPrimary:
+    raise SyntaxError(lineno + 1, "missing primary location")
 
-    return locations
+  return locations
 
 
-  def initializeProfile(self, profileDir, extraPrefs = []):
-    "Sets up the standard testing profile."
+def initializeProfile(profileDir, extraPrefs = []):
+  "Sets up the standard testing profile."
 
-    # Start with a clean slate.
-    shutil.rmtree(profileDir, True)
-    os.mkdir(profileDir)
+  # Start with a clean slate.
+  shutil.rmtree(profileDir, True)
+  os.mkdir(profileDir)
 
-    prefs = []
+  prefs = []
 
-    part = """\
+  part = """\
 user_pref("browser.dom.window.dump.enabled", true);
 user_pref("dom.allow_scripts_to_close_windows", true);
 user_pref("dom.disable_open_during_load", false);
 user_pref("dom.max_script_run_time", 0); // no slow script dialogs
 user_pref("dom.max_chrome_script_run_time", 0);
 user_pref("dom.popup_maximum", -1);
 user_pref("signed.applets.codebase_principal_support", true);
 user_pref("security.warn_submit_insecure", false);
@@ -283,40 +272,40 @@ user_pref("camino.warn_when_closing", fa
 user_pref("urlclassifier.updateinterval", 172800);
 // Point the url-classifier to the local testing server for fast failures
 user_pref("browser.safebrowsing.provider.0.gethashURL", "http://localhost:8888/safebrowsing-dummy/gethash");
 user_pref("browser.safebrowsing.provider.0.keyURL", "http://localhost:8888/safebrowsing-dummy/newkey");
 user_pref("browser.safebrowsing.provider.0.lookupURL", "http://localhost:8888/safebrowsing-dummy/lookup");
 user_pref("browser.safebrowsing.provider.0.updateURL", "http://localhost:8888/safebrowsing-dummy/update");
 """
   
-    prefs.append(part)
+  prefs.append(part)
 
-    locations = self.readLocations()
+  locations = readLocations()
 
-    # Grant God-power to all the privileged servers on which tests run.
-    privileged = filter(lambda loc: "privileged" in loc.options, locations)
-    for (i, l) in itertools.izip(itertools.count(1), privileged):
-      part = """
+  # Grant God-power to all the privileged servers on which tests run.
+  privileged = filter(lambda loc: "privileged" in loc.options, locations)
+  for (i, l) in itertools.izip(itertools.count(1), privileged):
+    part = """
 user_pref("capability.principal.codebase.p%(i)d.granted",
           "UniversalXPConnect UniversalBrowserRead UniversalBrowserWrite \
            UniversalPreferencesRead UniversalPreferencesWrite \
            UniversalFileRead");
 user_pref("capability.principal.codebase.p%(i)d.id", "%(origin)s");
 user_pref("capability.principal.codebase.p%(i)d.subjectName", "");
 """  % { "i": i,
          "origin": (l.scheme + "://" + l.host + ":" + l.port) }
-      prefs.append(part)
+    prefs.append(part)
 
-    # We need to proxy every server but the primary one.
-    origins = ["'%s://%s:%s'" % (l.scheme, l.host, l.port)
-              for l in filter(lambda l: "primary" not in l.options, locations)]
-    origins = ", ".join(origins)
+  # We need to proxy every server but the primary one.
+  origins = ["'%s://%s:%s'" % (l.scheme, l.host, l.port)
+             for l in filter(lambda l: "primary" not in l.options, locations)]
+  origins = ", ".join(origins)
 
-    pacURL = """data:text/plain,
+  pacURL = """data:text/plain,
 function FindProxyForURL(url, host)
 {
   var origins = [%(origins)s];
   var regex = new RegExp('^([a-z][-a-z0-9+.]*)' +
                          '://' +
                          '(?:[^/@]*@)?' +
                          '(.*?)' +
                          '(?::(\\\\\\\\d+))?/');
@@ -335,401 +324,387 @@ function FindProxyForURL(url, host)
   if (origins.indexOf(origin) < 0)
     return 'DIRECT';
   if (isHttp)
     return 'PROXY 127.0.0.1:8888';
   if (isHttps)
     return 'PROXY 127.0.0.1:4443';
   return 'DIRECT';
 }""" % { "origins": origins }
-    pacURL = "".join(pacURL.splitlines())
+  pacURL = "".join(pacURL.splitlines())
 
-    part = """
+  part = """
 user_pref("network.proxy.type", 2);
 user_pref("network.proxy.autoconfig_url", "%(pacURL)s");
 
 user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless to others
 """ % {"pacURL": pacURL}
+  prefs.append(part)
+
+  for v in extraPrefs:
+    thispref = v.split("=")
+    if len(thispref) < 2:
+      print "Error: syntax error in --setpref=" + v
+      sys.exit(1)
+    part = 'user_pref("%s", %s);\n' % (thispref[0], thispref[1])
     prefs.append(part)
 
-    for v in extraPrefs:
-      thispref = v.split("=")
-      if len(thispref) < 2:
-        print "Error: syntax error in --setpref=" + v
-        sys.exit(1)
-      part = 'user_pref("%s", %s);\n' % (thispref[0], thispref[1])
-      prefs.append(part)
+  # write the preferences
+  prefsFile = open(profileDir + "/" + "user.js", "a")
+  prefsFile.write("".join(prefs))
+  prefsFile.close()
 
-    # write the preferences
-    prefsFile = open(profileDir + "/" + "user.js", "a")
-    prefsFile.write("".join(prefs))
-    prefsFile.close()
-
-  def addCommonOptions(self, parser):
-    "Adds command-line options which are common to mochitest and reftest."
+def addExtraCommonOptions(parser):
+  "Adds command-line options which are common to mochitest and reftest."
 
-    parser.add_option("--setpref",
-                      action = "append", type = "string",
-                      default = [],
-                      dest = "extraPrefs", metavar = "PREF=VALUE",
-                      help = "defines an extra user preference")  
+  parser.add_option("--setpref",
+                    action = "append", type = "string",
+                    default = [],
+                    dest = "extraPrefs", metavar = "PREF=VALUE",
+                    help = "defines an extra user preference")  
 
-  def fillCertificateDB(self, profileDir, certPath, utilityPath, xrePath):
-    pwfilePath = os.path.join(profileDir, ".crtdbpw")
+def fillCertificateDB(profileDir, certPath, utilityPath, xrePath):
+  pwfilePath = os.path.join(profileDir, ".crtdbpw")
   
-    pwfile = open(pwfilePath, "w")
-    pwfile.write("\n")
-    pwfile.close()
+  pwfile = open(pwfilePath, "w")
+  pwfile.write("\n")
+  pwfile.close()
 
-    # Create head of the ssltunnel configuration file
-    sslTunnelConfigPath = os.path.join(profileDir, "ssltunnel.cfg")
-    sslTunnelConfig = open(sslTunnelConfigPath, "w")
+  # Create head of the ssltunnel configuration file
+  sslTunnelConfigPath = os.path.join(profileDir, "ssltunnel.cfg")
+  sslTunnelConfig = open(sslTunnelConfigPath, "w")
   
-    sslTunnelConfig.write("httpproxy:1\n")
-    sslTunnelConfig.write("certdbdir:%s\n" % certPath)
-    sslTunnelConfig.write("forward:127.0.0.1:8888\n")
-    sslTunnelConfig.write("listen:*:4443:pgo server certificate\n")
+  sslTunnelConfig.write("httpproxy:1\n")
+  sslTunnelConfig.write("certdbdir:%s\n" % certPath)
+  sslTunnelConfig.write("forward:127.0.0.1:8888\n")
+  sslTunnelConfig.write("listen:*:4443:pgo server certificate\n")
 
-    # Configure automatic certificate and bind custom certificates, client authentication
-    locations = self.readLocations()
-    locations.pop(0)
-    for loc in locations:
-      if loc.scheme == "https" and "nocert" not in loc.options:
-        customCertRE = re.compile("^cert=(?P<nickname>[0-9a-zA-Z_ ]+)")
-        clientAuthRE = re.compile("^clientauth=(?P<clientauth>[a-z]+)")
-        for option in loc.options:
-          match = customCertRE.match(option)
-          if match:
-            customcert = match.group("nickname");
-            sslTunnelConfig.write("listen:%s:%s:4443:%s\n" %
-                      (loc.host, loc.port, customcert))
+  # Configure automatic certificate and bind custom certificates, client authentication
+  locations = readLocations()
+  locations.pop(0)
+  for loc in locations:
+    if loc.scheme == "https" and "nocert" not in loc.options:
+      customCertRE = re.compile("^cert=(?P<nickname>[0-9a-zA-Z_ ]+)")
+      clientAuthRE = re.compile("^clientauth=(?P<clientauth>[a-z]+)")
+      for option in loc.options:
+        match = customCertRE.match(option)
+        if match:
+          customcert = match.group("nickname");
+          sslTunnelConfig.write("listen:%s:%s:4443:%s\n" %
+              (loc.host, loc.port, customcert))
 
-          match = clientAuthRE.match(option)
-          if match:
-            clientauth = match.group("clientauth");
-            sslTunnelConfig.write("clientauth:%s:%s:4443:%s\n" %
-                      (loc.host, loc.port, clientauth))
+        match = clientAuthRE.match(option)
+        if match:
+          clientauth = match.group("clientauth");
+          sslTunnelConfig.write("clientauth:%s:%s:4443:%s\n" %
+              (loc.host, loc.port, clientauth))
 
-    sslTunnelConfig.close()
+  sslTunnelConfig.close()
 
-    # Pre-create the certification database for the profile
-    env = self.environment(xrePath = xrePath)
-    certutil = os.path.join(utilityPath, "certutil" + self.BIN_SUFFIX)
-    pk12util = os.path.join(utilityPath, "pk12util" + self.BIN_SUFFIX)
+  # Pre-create the certification database for the profile
+  env = environment(xrePath = xrePath)
+  certutil = os.path.join(utilityPath, "certutil" + BIN_SUFFIX)
+  pk12util = os.path.join(utilityPath, "pk12util" + BIN_SUFFIX)
 
-    status = self.Process([certutil, "-N", "-d", profileDir, "-f", pwfilePath], env = env).wait()
-    if status != 0:
-      return status
+  status = Process([certutil, "-N", "-d", profileDir, "-f", pwfilePath], env = env).wait()
+  if status != 0:
+    return status
 
-    # Walk the cert directory and add custom CAs and client certs
-    files = os.listdir(certPath)
-    for item in files:
-      root, ext = os.path.splitext(item)
-      if ext == ".ca":
-        trustBits = "CT,,"
-        if root.endswith("-object"):
-          trustBits = "CT,,CT"
-        self.Process([certutil, "-A", "-i", os.path.join(certPath, item),
-                    "-d", profileDir, "-f", pwfilePath, "-n", root, "-t", trustBits],
-                    env = env).wait()
-      if ext == ".client":
-        self.Process([pk12util, "-i", os.path.join(certPath, item), "-w",
-                    pwfilePath, "-d", profileDir], 
-                    env = env).wait()
-
-    os.unlink(pwfilePath)
-    return 0
+  # Walk the cert directory and add custom CAs and client certs
+  files = os.listdir(certPath)
+  for item in files:
+    root, ext = os.path.splitext(item)
+    if ext == ".ca":
+      trustBits = "CT,,"
+      if root.endswith("-object"):
+        trustBits = "CT,,CT"
+      Process([certutil, "-A", "-i", os.path.join(certPath, item),
+        "-d", profileDir, "-f", pwfilePath, "-n", root, "-t", trustBits],
+        env = env).wait()
+    if ext == ".client":
+      Process([pk12util, "-i", os.path.join(certPath, item), "-w",
+        pwfilePath, "-d", profileDir], 
+        env = env).wait()
 
-  def environment(self, env = None, xrePath = None, crashreporter = True):
-    if xrePath == None:
-      xrePath = self.DIST_BIN
-    if env == None:
-      env = dict(os.environ)
+  os.unlink(pwfilePath)
+  return 0
+
+def environment(env = None, xrePath = DIST_BIN, crashreporter = True):
+  if env == None:
+    env = dict(os.environ)
 
-    ldLibraryPath = os.path.abspath(os.path.join(self.SCRIPT_DIR, xrePath))
-    if self.UNIXISH or self.IS_MAC:
-      envVar = "LD_LIBRARY_PATH"
-      if self.IS_MAC:
-        envVar = "DYLD_LIBRARY_PATH"
-      else: # unixish
-        env['MOZILLA_FIVE_HOME'] = xrePath
-      if envVar in env:
-        ldLibraryPath = ldLibraryPath + ":" + env[envVar]
-      env[envVar] = ldLibraryPath
-    elif self.IS_WIN32:
-      env["PATH"] = env["PATH"] + ";" + ldLibraryPath
+  ldLibraryPath = os.path.abspath(os.path.join(SCRIPT_DIR, xrePath))
+  if UNIXISH or IS_MAC:
+    envVar = "LD_LIBRARY_PATH"
+    if IS_MAC:
+      envVar = "DYLD_LIBRARY_PATH"
+    else: # unixish
+      env['MOZILLA_FIVE_HOME'] = xrePath
+    if envVar in env:
+      ldLibraryPath = ldLibraryPath + ":" + env[envVar]
+    env[envVar] = ldLibraryPath
+  elif IS_WIN32:
+    env["PATH"] = env["PATH"] + ";" + ldLibraryPath
 
-    if crashreporter:
-      env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
-      env['MOZ_CRASHREPORTER'] = '1'
-    else:
-      env['MOZ_CRASHREPORTER_DISABLE'] = '1'
+  if crashreporter:
+    env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
+    env['MOZ_CRASHREPORTER'] = '1'
+  else:
+    env['MOZ_CRASHREPORTER_DISABLE'] = '1'
 
-    env['GNOME_DISABLE_CRASH_DIALOG'] = '1'
-    env['XRE_NO_WINDOWS_CRASH_DIALOG'] = '1'
-    return env
+  env['GNOME_DISABLE_CRASH_DIALOG'] = "1"
+  env['XRE_NO_WINDOWS_CRASH_DIALOG'] = '1'
+  return env
 
-  if IS_WIN32:
-    ctypes = __import__('ctypes')
-    wintypes = __import__('ctypes.wintypes')
-    time = __import__('time')
-    msvcrt = __import__('msvcrt')
-    PeekNamedPipe = ctypes.windll.kernel32.PeekNamedPipe
-    GetLastError = ctypes.windll.kernel32.GetLastError
+if IS_WIN32:
+  import ctypes, ctypes.wintypes, time, msvcrt
+  PeekNamedPipe = ctypes.windll.kernel32.PeekNamedPipe
+  GetLastError = ctypes.windll.kernel32.GetLastError
 
-    def readWithTimeout(self, f, timeout):
-      """Try to read a line of output from the file object |f|.
-      |f| must be a  pipe, like the |stdout| member of a subprocess.Popen
-      object created with stdout=PIPE. If no output
-      is received within |timeout| seconds, return a blank line.
-      Returns a tuple (line, did_timeout), where |did_timeout| is True
-      if the read timed out, and False otherwise."""
-      if timeout is None:
-        # shortcut to allow callers to pass in "None" for no timeout.
+  def readWithTimeout(f, timeout):
+    """Try to read a line of output from the file object |f|.
+    |f| must be a  pipe, like the |stdout| member of a subprocess.Popen
+    object created with stdout=PIPE. If no output
+    is received within |timeout| seconds, return a blank line.
+    Returns a tuple (line, did_timeout), where |did_timeout| is True
+    if the read timed out, and False otherwise."""
+    if timeout is None:
+      # shortcut to allow callers to pass in "None" for no timeout.
+      return (f.readline(), False)
+    x = msvcrt.get_osfhandle(f.fileno())
+    l = ctypes.c_long()
+    done = time.time() + timeout
+    while time.time() < done:
+      if PeekNamedPipe(x, None, 0, None, ctypes.byref(l), None) == 0:
+        err = GetLastError()
+        if err == 38 or err == 109: # ERROR_HANDLE_EOF || ERROR_BROKEN_PIPE
+          return ('', False)
+        else:
+          log.error("readWithTimeout got error: %d", err)
+      if l > 0:
+        # we're assuming that the output is line-buffered,
+        # which is not unreasonable
         return (f.readline(), False)
-      x = self.msvcrt.get_osfhandle(f.fileno())
-      l = self.ctypes.c_long()
-      done = self.time.time() + timeout
-      while self.time.time() < done:
-        if self.PeekNamedPipe(x, None, 0, None, self.ctypes.byref(l), None) == 0:
-          err = self.GetLastError()
-          if err == 38 or err == 109: # ERROR_HANDLE_EOF || ERROR_BROKEN_PIPE
-            return ('', False)
-          else:
-            log.error("readWithTimeout got error: %d", err)
-        if l > 0:
-          # we're assuming that the output is line-buffered,
-          # which is not unreasonable
-          return (f.readline(), False)
-        self.time.sleep(0.01)
-      return ('', True)
+      time.sleep(0.01)
+    return ('', True)
 
-    def isPidAlive(self, pid):
-      STILL_ACTIVE = 259
-      PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
-      pHandle = self.ctypes.windll.kernel32.OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, 0, pid)
-      if not pHandle:
-        return False
-      pExitCode = self.wintypes.DWORD()
-      self.ctypes.windll.kernel32.GetExitCodeProcess(pHandle, self.ctypes.byref(pExitCode))
-      self.ctypes.windll.kernel32.CloseHandle(pHandle)
-      if (pExitCode.value == STILL_ACTIVE):
-        return True
-      else:
-        return False
+  def isPidAlive(pid):
+    STILL_ACTIVE = 259
+    PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
+    pHandle = ctypes.windll.kernel32.OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, 0, pid)
+    if not pHandle:
+      return False
+    pExitCode = ctypes.wintypes.DWORD()
+    ctypes.windll.kernel32.GetExitCodeProcess(pHandle, ctypes.byref(pExitCode))
+    ctypes.windll.kernel32.CloseHandle(pHandle)
+    if (pExitCode.value == STILL_ACTIVE):
+      return True
+    else:
+      return False
 
-    def killPid(self, pid):
-      PROCESS_TERMINATE = 0x0001
-      pHandle = self.ctypes.windll.kernel32.OpenProcess(PROCESS_TERMINATE, 0, pid)
-      if not pHandle:
-        return
-      success = self.ctypes.windll.kernel32.TerminateProcess(pHandle, 1)
-      self.ctypes.windll.kernel32.CloseHandle(pHandle)
+  def killPid(pid):
+    PROCESS_TERMINATE = 0x0001
+    pHandle = ctypes.windll.kernel32.OpenProcess(PROCESS_TERMINATE, 0, pid)
+    if not pHandle:
+      return
+    success = ctypes.windll.kernel32.TerminateProcess(pHandle, 1)
+    ctypes.windll.kernel32.CloseHandle(pHandle)
 
-  else:
-    errno = __import__('errno')
-
-    def readWithTimeout(self, f, timeout):
-      """Try to read a line of output from the file object |f|. If no output
-      is received within |timeout| seconds, return a blank line.
-      Returns a tuple (line, did_timeout), where |did_timeout| is True
-      if the read timed out, and False otherwise."""
-      (r, w, e) = select.select([f], [], [], timeout)
-      if len(r) == 0:
-        return ('', True)
-      return (f.readline(), False)
+else:
+  import errno
 
-    def isPidAlive(self, pid):
-      try:
-        # kill(pid, 0) checks for a valid PID without actually sending a signal
-        # The method throws OSError if the PID is invalid, which we catch below.
-        os.kill(pid, 0)
+  def readWithTimeout(f, timeout):
+    """Try to read a line of output from the file object |f|. If no output
+    is received within |timeout| seconds, return a blank line.
+    Returns a tuple (line, did_timeout), where |did_timeout| is True
+    if the read timed out, and False otherwise."""
+    (r, w, e) = select.select([f], [], [], timeout)
+    if len(r) == 0:
+      return ('', True)
+    return (f.readline(), False)
 
-        # Wait on it to see if it's a zombie. This can throw OSError.ECHILD if
-        # the process terminates before we get to this point.
-        wpid, wstatus = os.waitpid(pid, os.WNOHANG)
-        if wpid == 0:
-          return True
-
-        return False
-      except OSError, err:
-        # Catch the errors we might expect from os.kill/os.waitpid, 
-        # and re-raise any others
-        if err.errno == self.errno.ESRCH or err.errno == self.errno.ECHILD:
-          return False
-        raise
+  def isPidAlive(pid):
+    try:
+      # kill(pid, 0) checks for a valid PID without actually sending a signal
+      # The method throws OSError if the PID is invalid, which we catch below.
+      os.kill(pid, 0)
 
-    def killPid(self, pid):
-      os.kill(pid, signal.SIGKILL)
+      # Wait on it to see if it's a zombie. This can throw OSError.ECHILD if
+      # the process terminates before we get to this point.
+      wpid, wstatus = os.waitpid(pid, os.WNOHANG)
+      if wpid == 0:
+        return True
 
-  def triggerBreakpad(self, proc, utilityPath):
-    """Attempt to kill this process in a way that triggers Breakpad crash
-    reporting, if we know how for this platform. Otherwise just .kill() it."""
-    if self.CRASHREPORTER:
-      if self.UNIXISH:
-        # SEGV will get picked up by Breakpad's signal handler
-        os.kill(proc.pid, signal.SIGSEGV)
-        return
-      elif self.IS_WIN32:
-        # We should have a "crashinject" program in our utility path
-        crashinject = os.path.normpath(os.path.join(utilityPath, "crashinject.exe"))
-        if os.path.exists(crashinject) and subprocess.Popen([crashinject, str(proc.pid)]).wait() == 0:
-          return
-    #TODO: kill the process such that it triggers Breakpad on OS X (bug 525296)
-    self.log.info("Can't trigger Breakpad, just killing process")
-    proc.kill()
+      return False
+    except OSError, err:
+      # Catch the errors we might expect from os.kill/os.waitpid, 
+      # and re-raise any others
+      if err.errno == errno.ESRCH or err.errno == errno.ECHILD:
+        return False
+      raise
+
+  def killPid(pid):
+    os.kill(pid, signal.SIGKILL)
 
-  def runApp(self, testURL, env, app, profileDir, extraArgs,
-             runSSLTunnel = False, utilityPath = None,
-             xrePath = None, certPath = None,
-             debuggerInfo = None, symbolsPath = None,
-             timeout = -1, maxTime = None):
-    """
-    Run the app, log the duration it took to execute, return the status code.
-    Kills the app if it runs for longer than |maxTime| seconds, or outputs nothing for |timeout| seconds.
-    """
+def triggerBreakpad(proc, utilityPath):
+  """Attempt to kill this process in a way that triggers Breakpad crash
+  reporting, if we know how for this platform. Otherwise just .kill() it."""
+  if CRASHREPORTER:
+    if UNIXISH:
+      # SEGV will get picked up by Breakpad's signal handler
+      os.kill(proc.pid, signal.SIGSEGV)
+      return
+    elif IS_WIN32:
+      # We should have a "crashinject" program in our utility path
+      crashinject = os.path.normpath(os.path.join(utilityPath, "crashinject.exe"))
+      if os.path.exists(crashinject) and subprocess.Popen([crashinject, str(proc.pid)]).wait() == 0:
+        return
+  #TODO: kill the process such that it triggers Breakpad on OS X (bug 525296)
+  log.info("Can't trigger Breakpad, just killing process")
+  proc.kill()
 
-    if utilityPath == None:
-      utilityPath = self.DIST_BIN
-    if xrePath == None:
-      xrePath = self.DIST_BIN
-    if certPath == None:
-      certPath = self.CERTS_SRC_DIR
-    if timeout == -1:
-      timeout = self.DEFAULT_TIMEOUT
+###############
+# RUN THE APP #
+###############
 
-    # copy env so we don't munge the caller's environment
-    env = dict(env);
-    env["NO_EM_RESTART"] = "1"
-    tmpfd, processLog = tempfile.mkstemp(suffix='pidlog')
-    os.close(tmpfd)
-    env["MOZ_PROCESS_LOG"] = processLog
+def runApp(testURL, env, app, profileDir, extraArgs,
+           runSSLTunnel = False, utilityPath = DIST_BIN,
+           xrePath = DIST_BIN, certPath = CERTS_SRC_DIR,
+           debuggerInfo = None, symbolsPath = None,
+           timeout = DEFAULT_TIMEOUT, maxTime = None):
+  """
+  Run the app, log the duration it took to execute, return the status code.
+  Kills the app if it runs for longer than |maxTime| seconds, or outputs nothing for |timeout| seconds.
+  """
 
-    if self.IS_TEST_BUILD and runSSLTunnel:
-      # create certificate database for the profile
-      certificateStatus = self.fillCertificateDB(profileDir, certPath, utilityPath, xrePath)
-      if certificateStatus != 0:
-        self.log.info("TEST-UNEXPECTED FAIL | automation.py | Certificate integration failed")
-        return certificateStatus
+  # copy env so we don't munge the caller's environment
+  env = dict(env);
+  env["NO_EM_RESTART"] = "1"
+  tmpfd, processLog = tempfile.mkstemp(suffix='pidlog')
+  os.close(tmpfd)
+  env["MOZ_PROCESS_LOG"] = processLog
 
-      # start ssltunnel to provide https:// URLs capability
-      ssltunnel = os.path.join(utilityPath, "ssltunnel" + self.BIN_SUFFIX)
-      ssltunnelProcess = self.Process([ssltunnel, 
-                               os.path.join(profileDir, "ssltunnel.cfg")], 
-                               env = self.environment(xrePath = xrePath))
-      self.log.info("INFO | automation.py | SSL tunnel pid: %d", ssltunnelProcess.pid)
+  if IS_TEST_BUILD and runSSLTunnel:
+    # create certificate database for the profile
+    certificateStatus = fillCertificateDB(profileDir, certPath, utilityPath, xrePath)
+    if certificateStatus != 0:
+      log.info("TEST-UNEXPECTED FAIL | automation.py | Certificate integration failed")
+      return certificateStatus
 
-    # now run with the profile we created
-    cmd = app
-    if self.IS_MAC and not self.IS_CAMINO and not cmd.endswith("-bin"):
-      cmd += "-bin"
-    cmd = os.path.abspath(cmd)
+    # start ssltunnel to provide https:// URLs capability
+    ssltunnel = os.path.join(utilityPath, "ssltunnel" + BIN_SUFFIX)
+    ssltunnelProcess = Process([ssltunnel, os.path.join(profileDir, "ssltunnel.cfg")], env = environment(xrePath = xrePath))
+    log.info("INFO | automation.py | SSL tunnel pid: %d", ssltunnelProcess.pid)
 
-    args = []
+  # now run with the profile we created
+  cmd = app
+  if IS_MAC and not IS_CAMINO and not cmd.endswith("-bin"):
+    cmd += "-bin"
+  cmd = os.path.abspath(cmd)
+
+  args = []
 
-    if debuggerInfo:
-      args.extend(debuggerInfo["args"])
-      args.append(cmd)
-      cmd = os.path.abspath(debuggerInfo["path"])
+  if debuggerInfo:
+    args.extend(debuggerInfo["args"])
+    args.append(cmd)
+    cmd = os.path.abspath(debuggerInfo["path"])
+
+  if IS_MAC:
+    args.append("-foreground")
 
-    if self.IS_MAC:
-      args.append("-foreground")
+  if IS_CYGWIN:
+    profileDirectory = commands.getoutput("cygpath -w \"" + profileDir + "/\"")
+  else:
+    profileDirectory = profileDir + "/"
 
-    if self.IS_CYGWIN:
-      profileDirectory = commands.getoutput("cygpath -w \"" + profileDir + "/\"")
+  args.extend(("-no-remote", "-profile", profileDirectory))
+  if testURL is not None:
+    if IS_CAMINO:
+      args.extend(("-url", testURL))
     else:
-      profileDirectory = profileDir + "/"
+      args.append((testURL))
+  args.extend(extraArgs)
 
-    args.extend(("-no-remote", "-profile", profileDirectory))
-    if testURL is not None:
-      if self.IS_CAMINO:
-        args.extend(("-url", testURL))
-      else:
-        args.append((testURL))
-    args.extend(extraArgs)
+  startTime = datetime.now()
 
-    startTime = datetime.now()
+  # Don't redirect stdout and stderr if an interactive debugger is attached
+  if debuggerInfo and debuggerInfo["interactive"]:
+    outputPipe = None
+  else:
+    outputPipe = subprocess.PIPE
 
-    # Don't redirect stdout and stderr if an interactive debugger is attached
-    if debuggerInfo and debuggerInfo["interactive"]:
-      outputPipe = None
-    else:
-      outputPipe = subprocess.PIPE
-
-    proc = self.Process([cmd] + args,
-                 env = self.environment(env, xrePath = xrePath,
+  proc = Process([cmd] + args,
+                 env = environment(env, xrePath = xrePath,
                                    crashreporter = not debuggerInfo),
                  stdout = outputPipe,
                  stderr = subprocess.STDOUT)
-    self.log.info("INFO | automation.py | Application pid: %d", proc.pid)
+  log.info("INFO | automation.py | Application pid: %d", proc.pid)
 
-    stackFixerProcess = None
-    didTimeout = False
-    if outputPipe is None:
-      self.log.info("TEST-INFO: Not logging stdout or stderr due to debugger connection")
-    else:
-      logsource = proc.stdout
-      if self.IS_DEBUG_BUILD:
-        stackFixerCommand = None
-        if self.IS_MAC:
-          stackFixerCommand = "fix-macosx-stack.pl"
-        elif self.IS_LINUX:
-          stackFixerCommand = "fix-linux-stack.pl"
-        if stackFixerCommand is not None:
-          stackFixerProcess = self.Process([self.PERL, os.path.join(utilityPath, stackFixerCommand)], 
-                                           stdin=logsource, 
-                                           stdout=subprocess.PIPE)
-          logsource = stackFixerProcess.stdout
+  stackFixerProcess = None
+  didTimeout = False
+  if outputPipe is None:
+    log.info("TEST-INFO: Not logging stdout or stderr due to debugger connection")
+  else:
+    logsource = proc.stdout
+    if IS_DEBUG_BUILD:
+      stackFixerCommand = None
+      if IS_MAC:
+        stackFixerCommand = "fix-macosx-stack.pl"
+      elif IS_LINUX:
+        stackFixerCommand = "fix-linux-stack.pl"
+      if stackFixerCommand is not None:
+        stackFixerProcess = Process([PERL, os.path.join(utilityPath, stackFixerCommand)], stdin=logsource, stdout=subprocess.PIPE)
+        logsource = stackFixerProcess.stdout
 
-      (line, didTimeout) = self.readWithTimeout(logsource, timeout)
-      hitMaxTime = False
-      while line != "" and not didTimeout:
-        self.log.info(line.rstrip())
-        (line, didTimeout) = self.readWithTimeout(logsource, timeout)
-        if not hitMaxTime and maxTime and datetime.now() - startTime > timedelta(seconds = maxTime):
-          # Kill the application, but continue reading from stack fixer so as not to deadlock on stackFixerProcess.wait().
-          hitMaxTime = True
-          self.log.info("TEST-UNEXPECTED-FAIL | automation.py | application ran for longer than allowed maximum time of %d seconds", int(maxTime))
-          self.triggerBreakpad(proc, utilityPath)
-      if didTimeout:
-        self.log.info("TEST-UNEXPECTED-FAIL | automation.py | application timed out after %d seconds with no output", int(timeout))
-        self.triggerBreakpad(proc, utilityPath)
+    (line, didTimeout) = readWithTimeout(logsource, timeout)
+    hitMaxTime = False
+    while line != "" and not didTimeout:
+      log.info(line.rstrip())
+      (line, didTimeout) = readWithTimeout(logsource, timeout)
+      if not hitMaxTime and maxTime and datetime.now() - startTime > timedelta(seconds = maxTime):
+        # Kill the application, but continue reading from stack fixer so as not to deadlock on stackFixerProcess.wait().
+        hitMaxTime = True
+        log.info("TEST-UNEXPECTED-FAIL | automation.py | application ran for longer than allowed maximum time of %d seconds", int(maxTime))
+        triggerBreakpad(proc, utilityPath)
+    if didTimeout:
+      log.info("TEST-UNEXPECTED-FAIL | automation.py | application timed out after %d seconds with no output", int(timeout))
+      triggerBreakpad(proc, utilityPath)
 
-    status = proc.wait()
-    if status != 0 and not didTimeout and not hitMaxTime:
-      self.log.info("TEST-UNEXPECTED-FAIL | automation.py | Exited with code %d during test run", status)
-    if stackFixerProcess is not None:
-      fixerStatus = stackFixerProcess.wait()
-      if fixerStatus != 0 and not didTimeout and not hitMaxTime:
-        self.log.info("TEST-UNEXPECTED-FAIL | automation.py | Stack fixer process exited with code %d during test run", fixerStatus)
-    self.log.info("INFO | automation.py | Application ran for: %s", str(datetime.now() - startTime))
+  status = proc.wait()
+  if status != 0 and not didTimeout and not hitMaxTime:
+    log.info("TEST-UNEXPECTED-FAIL | automation.py | Exited with code %d during test run", status)
+  if stackFixerProcess is not None:
+    fixerStatus = stackFixerProcess.wait()
+    if fixerStatus != 0 and not didTimeout and not hitMaxTime:
+      log.info("TEST-UNEXPECTED-FAIL | automation.py | Stack fixer process exited with code %d during test run", fixerStatus)
+  log.info("INFO | automation.py | Application ran for: %s", str(datetime.now() - startTime))
 
-    # Do a final check for zombie child processes.
-    if not os.path.exists(processLog):
-      self.log.info('INFO | automation.py | PID log not found: %s', processLog)
-    else:
-      self.log.info('INFO | automation.py | Reading PID log: %s', processLog)
-      processList = []
-      pidRE = re.compile(r'launched child process (\d+)$')
-      processLogFD = open(processLog)
-      for line in processLogFD:
-        self.log.info(line.rstrip())
-        m = pidRE.search(line)
-        if m:
-          processList.append(int(m.group(1)))
-      processLogFD.close()
+  # Do a final check for zombie child processes.
+  if not os.path.exists(processLog):
+    log.info('INFO | automation.py | PID log not found: %s', processLog)
+  else:
+    log.info('INFO | automation.py | Reading PID log: %s', processLog)
+    processList = []
+    pidRE = re.compile(r'launched child process (\d+)$')
+    processLogFD = open(processLog)
+    for line in processLogFD:
+      log.info(line.rstrip())
+      m = pidRE.search(line)
+      if m:
+        processList.append(int(m.group(1)))
+    processLogFD.close()
 
-      for processPID in processList:
-        self.log.info("INFO | automation.py | Checking for orphan process with PID: %d", processPID)
-        if self.isPidAlive(processPID):
-          self.log.info("TEST-UNEXPECTED-FAIL | automation.py | child process %d still alive after shutdown", processPID)
-          self.killPid(processPID)
+    for processPID in processList:
+      log.info("INFO | automation.py | Checking for orphan process with PID: %d", processPID)
+      if isPidAlive(processPID):
+        log.info("TEST-UNEXPECTED-FAIL | automation.py | child process %d still alive after shutdown", processPID)
+        killPid(processPID)
 
-    if self.automationutils.checkForCrashes(os.path.join(profileDir, "minidumps"), symbolsPath):
-      status = -1
+  if checkForCrashes(os.path.join(profileDir, "minidumps"), symbolsPath):
+    status = -1
 
-    if os.path.exists(processLog):
-      os.unlink(processLog)
+  if os.path.exists(processLog):
+    os.unlink(processLog)
 
-    if self.IS_TEST_BUILD and runSSLTunnel:
-      ssltunnelProcess.kill()
+  if IS_TEST_BUILD and runSSLTunnel:
+    ssltunnelProcess.kill()
 
-    return status
+  return status
--- a/build/leaktest.py.in
+++ b/build/leaktest.py.in
@@ -41,29 +41,28 @@
 
 import SimpleHTTPServer
 import SocketServer
 import threading
 import os
 import sys
 import logging
 from getopt import getopt
-from automation import Automation
+import automation
 
 PORT = 8888
 SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
 PROFILE_DIRECTORY = os.path.abspath(os.path.join(SCRIPT_DIR, "./leakprofile"))
+DIST_BIN = os.path.join(SCRIPT_DIR, automation.DIST_BIN)
 os.chdir(SCRIPT_DIR)
 
 class EasyServer(SocketServer.TCPServer):
     allow_reuse_address = True
 
 if __name__ == '__main__':
-    automation = Automation()
-    DIST_BIN = os.path.join(SCRIPT_DIR, automation.DIST_BIN)
     opts, extraArgs = getopt(sys.argv[1:], 'l:')
     if len(opts) > 0:
         try:
             automation.log.addHandler(logging.FileHandler(opts[0][1], "w"))
         except:
             automation.log.info("Unable to open logfile " + opts[0][1] + \
                                 "ONLY logging to stdout.")
 
--- a/build/pgo/genpgocert.py.in
+++ b/build/pgo/genpgocert.py.in
@@ -31,29 +31,27 @@
 # use your version of this file under the terms of the MPL, indicate your
 # decision by deleting the provisions above and replace them with the notice
 # and other provisions required by the GPL or the LGPL. If you do not delete
 # the provisions above, a recipient may use your version of this file under
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ***** END LICENSE BLOCK *****
 
-from automation import Automation
+import automation
 import os
 import re
 import shutil
 import sys
 
 #expand DIST_BIN = __XPC_BIN_PATH__
 #expand BIN_SUFFIX = __BIN_SUFFIX__
 #expand PROFILE_DIR = __PROFILE_DIR__
 #expand CERTS_SRC_DIR = __CERTS_SRC_DIR__
 
-automation = Automation()
-
 dbFiles = [
   re.compile("^cert[0-9]+\.db$"),
   re.compile("^key[0-9]+\.db$"),
   re.compile("^secmod\.db$")
 ]
 
 def unlinkDbFiles(path):
   for root, dirs, files in os.walk(path):
--- a/build/pgo/profileserver.py.in
+++ b/build/pgo/profileserver.py.in
@@ -41,28 +41,27 @@
 import SimpleHTTPServer
 import SocketServer
 import socket
 import threading
 import os
 import sys
 import shutil
 from datetime import datetime
-from automation import Automation
+import automation
 
 PORT = 8888
 SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
 PROFILE_DIRECTORY = os.path.abspath(os.path.join(SCRIPT_DIR, "./pgoprofile"))
 os.chdir(SCRIPT_DIR)
 
 class EasyServer(SocketServer.TCPServer):
   allow_reuse_address = True
 
 if __name__ == '__main__':
-  automation = Automation()
   httpd = EasyServer(("", PORT), SimpleHTTPServer.SimpleHTTPRequestHandler)
   t = threading.Thread(target=httpd.serve_forever)
   t.setDaemon(True) # don't hang on exit
   t.start()
 
   automation.initializeProfile(PROFILE_DIRECTORY)
   browserEnv = automation.environment()
   browserEnv["XPCOM_DEBUG_BREAK"] = "warn"
--- a/layout/tools/reftest/runreftest.py
+++ b/layout/tools/reftest/runreftest.py
@@ -39,138 +39,64 @@
 
 """
 Runs the reftest test harness.
 """
 
 import sys, shutil, os, os.path
 SCRIPT_DIRECTORY = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
 sys.path.append(SCRIPT_DIRECTORY)
-from automation import Automation
+import automation
 from automationutils import *
 from optparse import OptionParser
 from tempfile import mkdtemp
 
-class RefTest(object):
-
-  oldcwd = os.getcwd()
-
-  def __init__(self, automation):
-    self.automation = automation
-    os.chdir(SCRIPT_DIRECTORY)
+oldcwd = os.getcwd()
+os.chdir(SCRIPT_DIRECTORY)
 
-  def getFullPath(self, path):
-    "Get an absolute path relative to self.oldcwd."
-    return os.path.normpath(os.path.join(self.oldcwd, os.path.expanduser(path)))
-
-  def createReftestProfile(self, options, profileDir):
-    "Sets up a profile for reftest."
-
-    # Set preferences.
-    prefsFile = open(os.path.join(profileDir, "user.js"), "w")
-    prefsFile.write("""user_pref("browser.dom.window.dump.enabled", true);
-    """)
-    prefsFile.write('user_pref("reftest.timeout", %d);\n' % (options.timeout * 1000))
-    prefsFile.write('user_pref("ui.caretBlinkTime", -1);\n')
+def getFullPath(path):
+  "Get an absolute path relative to oldcwd."
+  return os.path.normpath(os.path.join(oldcwd, os.path.expanduser(path)))
 
-    for v in options.extraPrefs:
-      thispref = v.split("=")
-      if len(thispref) < 2:
-        print "Error: syntax error in --setpref=" + v
-        sys.exit(1)
-      part = 'user_pref("%s", %s);\n' % (thispref[0], thispref[1])
-      prefsFile.write(part)
-    # no slow script dialogs
-    prefsFile.write('user_pref("dom.max_script_run_time", 0);')
-    prefsFile.write('user_pref("dom.max_chrome_script_run_time", 0);')
-    prefsFile.close()
+def createReftestProfile(options, profileDir):
+  "Sets up a profile for reftest."
 
-    # install the reftest extension bits into the profile
-    profileExtensionsPath = os.path.join(profileDir, "extensions")
-    os.mkdir(profileExtensionsPath)
-    reftestExtensionPath = os.path.join(SCRIPT_DIRECTORY, "reftest")
-    extFile = open(os.path.join(profileExtensionsPath, "reftest@mozilla.org"), "w")
-    extFile.write(reftestExtensionPath)
-    extFile.close()
-
-  def runTests(self, manifest, options):
-    debuggerInfo = getDebuggerInfo(self.oldcwd, options.debugger, options.debuggerArgs,
-        options.debuggerInteractive);
-
-    profileDir = None
-    try:
-      profileDir = mkdtemp()
-      self.createReftestProfile(options, profileDir)
-      self.copyExtraFilesToProfile(options, profileDir)
+  # Set preferences.
+  prefsFile = open(os.path.join(profileDir, "user.js"), "w")
+  prefsFile.write("""user_pref("browser.dom.window.dump.enabled", true);
+""")
+  prefsFile.write('user_pref("reftest.timeout", %d);\n' % (options.timeout * 1000))
+  prefsFile.write('user_pref("ui.caretBlinkTime", -1);\n')
 
-      # browser environment
-      browserEnv = self.automation.environment(xrePath = options.xrePath)
-      browserEnv["XPCOM_DEBUG_BREAK"] = "stack"
-
-      # Enable leaks detection to its own log file.
-      leakLogFile = os.path.join(profileDir, "runreftest_leaks.log")
-      browserEnv["XPCOM_MEM_BLOAT_LOG"] = leakLogFile
-
-      # run once with -silent to let the extension manager do its thing
-      # and then exit the app
-      self.automation.log.info("REFTEST INFO | runreftest.py | Performing extension manager registration: start.\n")
-      # Don't care about this |status|: |runApp()| reporting it should be enough.
-      status = self.automation.runApp(None, browserEnv, options.app, profileDir,
-                                 ["-silent"],
-                                 utilityPath = options.utilityPath,
-                                 xrePath=options.xrePath,
-                                 symbolsPath=options.symbolsPath)
-      # We don't care to call |processLeakLog()| for this step.
-      self.automation.log.info("\nREFTEST INFO | runreftest.py | Performing extension manager registration: end.")
-
-      # Remove the leak detection file so it can't "leak" to the tests run.
-      # The file is not there if leak logging was not enabled in the application build.
-      if os.path.exists(leakLogFile):
-        os.remove(leakLogFile)
+  for v in options.extraPrefs:
+    thispref = v.split("=")
+    if len(thispref) < 2:
+      print "Error: syntax error in --setpref=" + v
+      sys.exit(1)
+    part = 'user_pref("%s", %s);\n' % (thispref[0], thispref[1])
+    prefsFile.write(part)
+  # no slow script dialogs
+  prefsFile.write('user_pref("dom.max_script_run_time", 0);')
+  prefsFile.write('user_pref("dom.max_chrome_script_run_time", 0);')
+  prefsFile.close()
 
-      # then again to actually run reftest
-      self.automation.log.info("REFTEST INFO | runreftest.py | Running tests: start.\n")
-      reftestlist = self.getFullPath(manifest)
-      status = self.automation.runApp(None, browserEnv, options.app, profileDir,
-                                 ["-reftest", reftestlist],
-                                 utilityPath = options.utilityPath,
-                                 xrePath=options.xrePath,
-                                 debuggerInfo=debuggerInfo,
-                                 symbolsPath=options.symbolsPath,
-                                 # give the JS harness 30 seconds to deal
-                                 # with its own timeouts
-                                 timeout=options.timeout + 30.0)
-      processLeakLog(leakLogFile, options.leakThreshold)
-      self.automation.log.info("\nREFTEST INFO | runreftest.py | Running tests: end.")
-    finally:
-      if profileDir:
-        shutil.rmtree(profileDir)
-    return status
-
-  def copyExtraFilesToProfile(self, options, profileDir):
-    "Copy extra files or dirs specified on the command line to the testing profile."
-    for f in options.extraProfileFiles:
-      abspath = self.getFullPath(f)
-      dest = os.path.join(profileDir, os.path.basename(abspath))
-      if os.path.isdir(abspath):
-        shutil.copytree(abspath, dest)
-      else:
-        shutil.copy(abspath, dest)
-
+  # install the reftest extension bits into the profile
+  profileExtensionsPath = os.path.join(profileDir, "extensions")
+  os.mkdir(profileExtensionsPath)
+  reftestExtensionPath = os.path.join(SCRIPT_DIRECTORY, "reftest")
+  extFile = open(os.path.join(profileExtensionsPath, "reftest@mozilla.org"), "w")
+  extFile.write(reftestExtensionPath)
+  extFile.close()
 
 def main():
-  automation = Automation()
   parser = OptionParser()
-  reftest = RefTest(automation)
 
   # we want to pass down everything from automation.__all__
-  addCommonOptions(parser, 
-                   defaults=dict(zip(automation.__all__, 
-                            [getattr(automation, x) for x in automation.__all__])))
-  automation.addCommonOptions(parser)
+  addCommonOptions(parser, defaults=dict(zip(automation.__all__, [getattr(automation, x) for x in automation.__all__])))
+  automation.addExtraCommonOptions(parser)
   parser.add_option("--appname",
                     action = "store", type = "string", dest = "app",
                     default = os.path.join(SCRIPT_DIRECTORY, automation.DEFAULT_APP),
                     help = "absolute path to application, overriding default")
   parser.add_option("--extra-profile-file",
                     action = "append", dest = "extraProfileFiles",
                     default = [],
                     help = "copy specified files/dirs to testing profile")
@@ -187,33 +113,95 @@ def main():
                            "than the given number")
   parser.add_option("--utility-path",
                     action = "store", type = "string", dest = "utilityPath",
                     default = automation.DIST_BIN,
                     help = "absolute path to directory containing utility "
                            "programs (xpcshell, ssltunnel, certutil)")
 
   options, args = parser.parse_args()
+
   if len(args) != 1:
     print >>sys.stderr, "No reftest.list specified."
     sys.exit(1)
 
-  options.app = reftest.getFullPath(options.app)
+  options.app = getFullPath(options.app)
   if not os.path.exists(options.app):
     print """Error: Path %(app)s doesn't exist.
 Are you executing $objdir/_tests/reftest/runreftest.py?""" \
-            % {"app": options.app}
+        % {"app": options.app}
     sys.exit(1)
 
   if options.xrePath is None:
     options.xrePath = os.path.dirname(options.app)
   else:
     # allow relative paths
-    options.xrePath = reftest.getFullPath(options.xrePath)
+    options.xrePath = getFullPath(options.xrePath)
 
   if options.symbolsPath:
-    options.symbolsPath = reftest.getFullPath(options.symbolsPath)
-  options.utilityPath = reftest.getFullPath(options.utilityPath)
+    options.symbolsPath = getFullPath(options.symbolsPath)
+  options.utilityPath = getFullPath(options.utilityPath)
+
+  debuggerInfo = getDebuggerInfo(oldcwd, options.debugger, options.debuggerArgs,
+     options.debuggerInteractive);
+
+  profileDir = None
+  try:
+    profileDir = mkdtemp()
+    createReftestProfile(options, profileDir)
+    copyExtraFilesToProfile(options, profileDir)
+
+    # browser environment
+    browserEnv = automation.environment(xrePath = options.xrePath)
+    browserEnv["XPCOM_DEBUG_BREAK"] = "stack"
+
+    # Enable leaks detection to its own log file.
+    leakLogFile = os.path.join(profileDir, "runreftest_leaks.log")
+    browserEnv["XPCOM_MEM_BLOAT_LOG"] = leakLogFile
+
+    # run once with -silent to let the extension manager do its thing
+    # and then exit the app
+    automation.log.info("REFTEST INFO | runreftest.py | Performing extension manager registration: start.\n")
+    # Don't care about this |status|: |runApp()| reporting it should be enough.
+    status = automation.runApp(None, browserEnv, options.app, profileDir,
+                               ["-silent"],
+                               utilityPath = options.utilityPath,
+                               xrePath=options.xrePath,
+                               symbolsPath=options.symbolsPath)
+    # We don't care to call |processLeakLog()| for this step.
+    automation.log.info("\nREFTEST INFO | runreftest.py | Performing extension manager registration: end.")
 
-  sys.exit(reftest.runTests(args[0], options))
-  
+    # Remove the leak detection file so it can't "leak" to the tests run.
+    # The file is not there if leak logging was not enabled in the application build.
+    if os.path.exists(leakLogFile):
+      os.remove(leakLogFile)
+
+    # then again to actually run reftest
+    automation.log.info("REFTEST INFO | runreftest.py | Running tests: start.\n")
+    reftestlist = getFullPath(args[0])
+    status = automation.runApp(None, browserEnv, options.app, profileDir,
+                               ["-reftest", reftestlist],
+                               utilityPath = options.utilityPath,
+                               xrePath=options.xrePath,
+                               debuggerInfo=debuggerInfo,
+                               symbolsPath=options.symbolsPath,
+                               # give the JS harness 30 seconds to deal
+                               # with its own timeouts
+                               timeout=options.timeout + 30.0)
+    processLeakLog(leakLogFile, options.leakThreshold)
+    automation.log.info("\nREFTEST INFO | runreftest.py | Running tests: end.")
+  finally:
+    if profileDir:
+      shutil.rmtree(profileDir)
+  sys.exit(status)
+
+def copyExtraFilesToProfile(options, profileDir):
+  "Copy extra files or dirs specified on the command line to the testing profile."
+  for f in options.extraProfileFiles:
+    abspath = getFullPath(f)
+    dest = os.path.join(profileDir, os.path.basename(abspath))
+    if os.path.isdir(abspath):
+      shutil.copytree(abspath, dest)
+    else:
+      shutil.copy(abspath, dest)
+
 if __name__ == "__main__":
   main()
--- a/testing/mochitest/runtests.py.in
+++ b/testing/mochitest/runtests.py.in
@@ -47,55 +47,84 @@ import optparse
 import os
 import os.path
 import sys
 import time
 import shutil
 from urllib import quote_plus as encodeURIComponent
 import urllib2
 import commands
-from automation import Automation
+import automation
 from automationutils import *
 
+# Path to the test script on the server
+TEST_SERVER_HOST = "localhost:8888"
+TEST_PATH = "/tests/"
+CHROME_PATH = "/redirect.html";
+A11Y_PATH = "/redirect-a11y.html"
+TESTS_URL = "http://" + TEST_SERVER_HOST + TEST_PATH
+CHROMETESTS_URL = "http://" + TEST_SERVER_HOST + CHROME_PATH
+A11YTESTS_URL = "http://" + TEST_SERVER_HOST + A11Y_PATH
+SERVER_SHUTDOWN_URL = "http://" + TEST_SERVER_HOST + "/server/shutdown"
+# main browser chrome URL, same as browser.chromeURL pref
+#ifdef MOZ_SUITE
+BROWSER_CHROME_URL = "chrome://navigator/content/navigator.xul"
+#else
+BROWSER_CHROME_URL = "chrome://browser/content/browser.xul"
+#endif
+
+# Max time in seconds to wait for server startup before tests will fail -- if
+# this seems big, it's mostly for debug machines where cold startup
+# (particularly after a build) takes forever.
+if automation.IS_DEBUG_BUILD:
+    SERVER_STARTUP_TIMEOUT = 180
+else:
+    SERVER_STARTUP_TIMEOUT = 90
+
+oldcwd = os.getcwd()
+SCRIPT_DIRECTORY = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
+os.chdir(SCRIPT_DIRECTORY)
+
+PROFILE_DIRECTORY = os.path.abspath("./mochitesttestingprofile")
+
+LEAK_REPORT_FILE = os.path.join(PROFILE_DIRECTORY, "runtests_leaks.log")
 
 #######################
 # COMMANDLINE OPTIONS #
 #######################
 
 class MochitestOptions(optparse.OptionParser):
   """Parses Mochitest commandline options."""
-  def __init__(self, automation, scriptdir, **kwargs):
-    self._automation = automation
+  def __init__(self, **kwargs):
     optparse.OptionParser.__init__(self, **kwargs)
     defaults = {}
 
-    # we want to pass down everything from self._automation.__all__
-    addCommonOptions(self, defaults=dict(zip(self._automation.__all__, 
-             [getattr(self._automation, x) for x in self._automation.__all__])))
-    self._automation.addCommonOptions(self)
+    # we want to pass down everything from automation.__all__
+    addCommonOptions(self, defaults=dict(zip(automation.__all__, [getattr(automation, x) for x in automation.__all__])))
+    automation.addExtraCommonOptions(self)
 
     self.add_option("--close-when-done",
                     action = "store_true", dest = "closeWhenDone",
                     help = "close the application when tests are done running")
     defaults["closeWhenDone"] = False
 
     self.add_option("--appname",
                     action = "store", type = "string", dest = "app",
                     help = "absolute path to application, overriding default")
-    defaults["app"] = os.path.join(scriptdir, self._automation.DEFAULT_APP)
+    defaults["app"] = os.path.join(SCRIPT_DIRECTORY, automation.DEFAULT_APP)
 
     self.add_option("--utility-path",
                     action = "store", type = "string", dest = "utilityPath",
                     help = "absolute path to directory containing utility programs (xpcshell, ssltunnel, certutil)")
-    defaults["utilityPath"] = self._automation.DIST_BIN
+    defaults["utilityPath"] = automation.DIST_BIN
 
     self.add_option("--certificate-path",
                     action = "store", type = "string", dest = "certPath",
                     help = "absolute path to directory containing certificate store to use testing profile")
-    defaults["certPath"] = self._automation.CERTS_SRC_DIR
+    defaults["certPath"] = automation.CERTS_SRC_DIR
 
     self.add_option("--log-file",
                     action = "store", type = "string",
                     dest = "logFile", metavar = "FILE",
                     help = "file to which logging occurs")
     defaults["logFile"] = ""
 
     self.add_option("--autorun",
@@ -215,49 +244,48 @@ See <http://mochikit.com/doc/html/MochiK
 
 #######################
 # HTTP SERVER SUPPORT #
 #######################
 
 class MochitestServer:
   "Web server used to serve Mochitests, for closer fidelity to the real web."
 
-  def __init__(self, automation, options, profileDir):
-    self._automation = automation
+  def __init__(self, options):
     self._closeWhenDone = options.closeWhenDone
     self._utilityPath = options.utilityPath
     self._xrePath = options.xrePath
-    self._profileDir = profileDir
 
   def start(self):
     "Run the Mochitest server, returning the process ID of the server."
     
-    env = self._automation.environment(xrePath = self._xrePath)
+    env = automation.environment(xrePath = self._xrePath)
     env["XPCOM_DEBUG_BREAK"] = "warn"
-    if self._automation.IS_WIN32:
+    if automation.IS_WIN32:
       env["PATH"] = env["PATH"] + ";" + self._xrePath
 
     args = ["-g", self._xrePath,
             "-v", "170",
             "-f", "./" + "httpd.js",
             "-f", "./" + "server.js"]
 
     xpcshell = os.path.join(self._utilityPath,
-                            "xpcshell" + self._automation.BIN_SUFFIX)
-    self._process = self._automation.Process([xpcshell] + args, env = env)
+                            "xpcshell" + automation.BIN_SUFFIX)
+    self._process = automation.Process([xpcshell] + args, env = env)
     pid = self._process.pid
     if pid < 0:
       print "Error starting server."
       sys.exit(2)
-    self._automation.log.info("INFO | runtests.py | Server pid: %d", pid)
+    automation.log.info("INFO | runtests.py | Server pid: %d", pid)
+    
 
   def ensureReady(self, timeout):
     assert timeout >= 0
 
-    aliveFile = os.path.join(self._profileDir, "server_alive.txt")
+    aliveFile = os.path.join(PROFILE_DIRECTORY, "server_alive.txt")
     i = 0
     while i < timeout:
       if os.path.exists(aliveFile):
         break
       time.sleep(1)
       i += 1
     else:
       print "Timed out while waiting for server startup."
@@ -268,301 +296,282 @@ class MochitestServer:
     try:
       c = urllib2.urlopen(SERVER_SHUTDOWN_URL)
       c.read()
       c.close()
       self._process.wait()
     except:
       self._process.kill()
 
-
-class Mochitest(object):
-  # Path to the test script on the server
-  TEST_SERVER_HOST = "localhost:8888"
-  TEST_PATH = "/tests/"
-  CHROME_PATH = "/redirect.html";
-  A11Y_PATH = "/redirect-a11y.html"
-  TESTS_URL = "http://" + TEST_SERVER_HOST + TEST_PATH
-  CHROMETESTS_URL = "http://" + TEST_SERVER_HOST + CHROME_PATH
-  A11YTESTS_URL = "http://" + TEST_SERVER_HOST + A11Y_PATH
-  SERVER_SHUTDOWN_URL = "http://" + TEST_SERVER_HOST + "/server/shutdown"
- 
-  oldcwd = os.getcwd()
-
-  def __init__(self, automation):
-    self.automation = automation
-
-    # Max time in seconds to wait for server startup before tests will fail -- if
-    # this seems big, it's mostly for debug machines where cold startup
-    # (particularly after a build) takes forever.
-    if self.automation.IS_DEBUG_BUILD:
-      self.SERVER_STARTUP_TIMEOUT = 180
-    else:
-      self.SERVER_STARTUP_TIMEOUT = 90
-
-    self.SCRIPT_DIRECTORY = os.path.abspath(os.path.realpath(os.path.dirname(__file__)))
-    os.chdir(self.SCRIPT_DIRECTORY)
-
-    self.PROFILE_DIRECTORY = os.path.abspath("./mochitesttestingprofile")
-
-    self.LEAK_REPORT_FILE = os.path.join(self.PROFILE_DIRECTORY, "runtests_leaks.log")
-
-  def getFullPath(self, path):
-    "Get an absolute path relative to self.oldcwd."
-    return os.path.normpath(os.path.join(self.oldcwd, os.path.expanduser(path)))
-
-  def runTests(self, options):
-    debuggerInfo = getDebuggerInfo(self.oldcwd, options.debugger, options.debuggerArgs,
-                      options.debuggerInteractive);
-
-    # browser environment
-    browserEnv = self.automation.environment(xrePath = options.xrePath)
-
-    # These variables are necessary for correct application startup; change
-    # via the commandline at your own risk.
-    browserEnv["XPCOM_DEBUG_BREAK"] = "stack"
-
-    for v in options.environment:
-      ix = v.find("=")
-      if ix <= 0:
-        print "Error: syntax error in --setenv=" + v
-        return 1
-      browserEnv[v[:ix]] = v[ix + 1:]
-
-    self.automation.initializeProfile(self.PROFILE_DIRECTORY, options.extraPrefs)
-    manifest = self.addChromeToProfile(options)
-    self.copyExtraFilesToProfile(options)
-    server = MochitestServer(self.automation, options, self.PROFILE_DIRECTORY)
-    server.start()
-
-    # If we're lucky, the server has fully started by now, and all paths are
-    # ready, etc.  However, xpcshell cold start times suck, at least for debug
-    # builds.  We'll try to connect to the server for awhile, and if we fail,
-    # we'll try to kill the server and exit with an error.
-    server.ensureReady(self.SERVER_STARTUP_TIMEOUT)
-
-    # URL parameters to test URL:
-    #
-    # autorun -- kick off tests automatically
-    # closeWhenDone -- runs quit.js after tests
-    # logFile -- logs test run to an absolute path
-    # totalChunks -- how many chunks to split tests into
-    # thisChunk -- which chunk to run
-    # timeout -- per-test timeout in seconds
-    #
-  
-    # consoleLevel, fileLevel: set the logging level of the console and
-    # file logs, if activated.
-    # <http://mochikit.com/doc/html/MochiKit/Logging.html>
-
-    testURL = self.TESTS_URL + options.testPath
-    urlOpts = []
-    if options.chrome:
-      testURL = self.CHROMETESTS_URL
-      if options.testPath:
-        urlOpts.append("testPath=" + encodeURIComponent(options.testPath))
-    elif options.a11y:
-      testURL = self.A11YTESTS_URL
-      if options.testPath:
-        urlOpts.append("testPath=" + encodeURIComponent(options.testPath))
-    elif options.browserChrome:
-      testURL = "about:blank"
-
-    # allow relative paths for logFile
-    if options.logFile:
-      options.logFile = self.getFullPath(options.logFile)
-    if options.browserChrome:
-      self.makeTestConfig(options)
-    else:
-      if options.autorun:
-        urlOpts.append("autorun=1")
-      if options.timeout:
-        urlOpts.append("timeout=%d" % options.timeout)
-      if options.closeWhenDone:
-        urlOpts.append("closeWhenDone=1")
-      if options.logFile:
-        urlOpts.append("logFile=" + encodeURIComponent(options.logFile))
-        urlOpts.append("fileLevel=" + encodeURIComponent(options.fileLevel))
-      if options.consoleLevel:
-        urlOpts.append("consoleLevel=" + encodeURIComponent(options.consoleLevel))
-      if options.totalChunks:
-        urlOpts.append("totalChunks=%d" % options.totalChunks)
-        urlOpts.append("thisChunk=%d" % options.thisChunk)
-      if options.chunkByDir:
-        urlOpts.append("chunkByDir=%d" % options.chunkByDir)
-      if options.shuffle:
-        urlOpts.append("shuffle=1")
-      if len(urlOpts) > 0:
-        testURL += "?" + "&".join(urlOpts)
-
-    browserEnv["XPCOM_MEM_BLOAT_LOG"] = self.LEAK_REPORT_FILE
-
-    if options.fatalAssertions:
-      browserEnv["XPCOM_DEBUG_BREAK"] = "stack-and-abort"
+def getFullPath(path):
+  "Get an absolute path relative to oldcwd."
+  return os.path.normpath(os.path.join(oldcwd, os.path.expanduser(path)))
 
-    # run once with -silent to let the extension manager do its thing
-    # and then exit the app
-    self.automation.log.info("INFO | runtests.py | Performing extension manager registration: start.\n")
-    # Don't care about this |status|: |runApp()| reporting it should be enough.
-    status = self.automation.runApp(None, browserEnv, options.app,
-                                self.PROFILE_DIRECTORY, ["-silent"],
-                                utilityPath = options.utilityPath,
-                                xrePath = options.xrePath,
-                                symbolsPath=options.symbolsPath)
-    # We don't care to call |processLeakLog()| for this step.
-    self.automation.log.info("\nINFO | runtests.py | Performing extension manager registration: end.")
-
-    # Remove the leak detection file so it can't "leak" to the tests run.
-    # The file is not there if leak logging was not enabled in the application build.
-    if os.path.exists(self.LEAK_REPORT_FILE):
-      os.remove(self.LEAK_REPORT_FILE)
-
-    # then again to actually run mochitest
-    if options.timeout:
-      timeout = options.timeout + 30
-    elif options.autorun:
-      timeout = None
-    else:
-      timeout = 330.0 # default JS harness timeout is 300 seconds
-    self.automation.log.info("INFO | runtests.py | Running tests: start.\n")
-    status = self.automation.runApp(testURL, browserEnv, options.app,
-                                self.PROFILE_DIRECTORY, options.browserArgs,
-                                runSSLTunnel = True,
-                                utilityPath = options.utilityPath,
-                                xrePath = options.xrePath,
-                                certPath=options.certPath,
-                                debuggerInfo=debuggerInfo,
-                                symbolsPath=options.symbolsPath,
-                                timeout = timeout)
-
-    # Server's no longer needed, and perhaps more importantly, anything it might
-    # spew to console shouldn't disrupt the leak information table we print next.
-    server.stop()
-
-    processLeakLog(self.LEAK_REPORT_FILE, options.leakThreshold)
-    self.automation.log.info("\nINFO | runtests.py | Running tests: end.")
-
-    # delete the profile and manifest
-    os.remove(manifest)
-
-    # hanging due to non-halting threads is no fun; assume we hit the errors we
-    # were going to hit already and exit.
-    return status
-
-  def makeTestConfig(self, options):
-    "Creates a test configuration file for customizing test execution."
-    def boolString(b):
-      if b:
-        return "true"
-      return "false"
-
-    logFile = options.logFile.replace("\\", "\\\\")
-    testPath = options.testPath.replace("\\", "\\\\")
-    content = """\
-({
-  autoRun: %(autorun)s,
-  closeWhenDone: %(closeWhenDone)s,
-  logPath: "%(logPath)s",
-  testPath: "%(testPath)s"
-})""" % {"autorun": boolString(options.autorun),
-         "closeWhenDone": boolString(options.closeWhenDone),
-         "logPath": logFile,
-         "testPath": testPath}
-
-    config = open(os.path.join(self.PROFILE_DIRECTORY, "testConfig.js"), "w")
-    config.write(content)
-    config.close() 
-
-
-  def addChromeToProfile(self, options):
-    "Adds MochiKit chrome tests to the profile."
-
-    chromedir = os.path.join(self.PROFILE_DIRECTORY, "chrome")
-    os.mkdir(chromedir)
-
-    chrome = """
-@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); /* set default namespace to XUL */
-toolbar,
-toolbarpalette {
-  background-color: rgb(235, 235, 235) !important;
-}
-toolbar#nav-bar {
-  background-image: none !important;
-}
-"""
-
-    # write userChrome.css
-    chromeFile = open(os.path.join(self.PROFILE_DIRECTORY, "userChrome.css"), "a")
-    chromeFile.write(chrome)
-    chromeFile.close()
-
-
-    # register our chrome dir
-    chrometestDir = os.path.abspath(".") + "/"
-    if self.automation.IS_WIN32:
-      chrometestDir = "file:///" + chrometestDir.replace("\\", "/")
-
-
-    (path, leaf) = os.path.split(options.app)
-    manifest = os.path.join(path, "chrome", "mochikit.manifest")
-    manifestFile = open(manifest, "w")
-    manifestFile.write("content mochikit " + chrometestDir + " contentaccessible=yes\n")
-
-    if options.browserChrome:
-      manifestFile.write("""overlay chrome://navigator/content/navigator.xul chrome://mochikit/content/browser-test-overlay.xul
-overlay chrome://browser/content/browser.xul chrome://mochikit/content/browser-test-overlay.xul
-""")
-    manifestFile.close()
-
-    return manifest
-
-  def copyExtraFilesToProfile(self, options):
-    "Copy extra files or dirs specified on the command line to the testing profile."
-    for f in options.extraProfileFiles:
-      abspath = self.getFullPath(f)
-      dest = os.path.join(self.PROFILE_DIRECTORY, os.path.basename(abspath))
-      if os.path.isdir(abspath):
-        shutil.copytree(abspath, dest)
-      else:
-        shutil.copy(abspath, dest)
+#################
+# MAIN FUNCTION #
+#################
 
 def main():
-  automation = Automation()
-  mochitest = Mochitest(automation)
-  parser = MochitestOptions(automation, mochitest.SCRIPT_DIRECTORY)
+  parser = MochitestOptions()
   options, args = parser.parse_args()
 
   if options.totalChunks is not None and options.thisChunk is None:
     parser.error("thisChunk must be specified when totalChunks is specified")
 
   if options.totalChunks:
     if not 1 <= options.thisChunk <= options.totalChunks:
-      parser.error("thisChunk must be between 1 and totalChunks")
+       parser.error("thisChunk must be between 1 and totalChunks")
 
   if options.xrePath is None:
     # default xrePath to the app path if not provided
     # but only if an app path was explicitly provided
     if options.app != parser.defaults['app']:
       options.xrePath = os.path.dirname(options.app)
     else:
       # otherwise default to dist/bin
       options.xrePath = automation.DIST_BIN
 
   # allow relative paths
-  options.xrePath = mochitest.getFullPath(options.xrePath)
+  options.xrePath = getFullPath(options.xrePath)
 
-  options.app = mochitest.getFullPath(options.app)
+  options.app = getFullPath(options.app)
   if not os.path.exists(options.app):
     msg = """\
-    Error: Path %(app)s doesn't exist.
-    Are you executing $objdir/_tests/testing/mochitest/runtests.py?"""
+Error: Path %(app)s doesn't exist.
+Are you executing $objdir/_tests/testing/mochitest/runtests.py?"""
     print msg % {"app": options.app}
     sys.exit(1)
 
-  options.utilityPath = mochitest.getFullPath(options.utilityPath)
-  options.certPath = mochitest.getFullPath(options.certPath)
+  options.utilityPath = getFullPath(options.utilityPath)
+  options.certPath = getFullPath(options.certPath)
   if options.symbolsPath:
-    options.symbolsPath = mochitest.getFullPath(options.symbolsPath)
+    options.symbolsPath = getFullPath(options.symbolsPath)
+
+  debuggerInfo = getDebuggerInfo(oldcwd, options.debugger, options.debuggerArgs,
+    options.debuggerInteractive);
+
+  # browser environment
+  browserEnv = automation.environment(xrePath = options.xrePath)
+
+  # These variables are necessary for correct application startup; change
+  # via the commandline at your own risk.
+  browserEnv["XPCOM_DEBUG_BREAK"] = "stack"
+
+  for v in options.environment:
+    ix = v.find("=")
+    if ix <= 0:
+      print "Error: syntax error in --setenv=" + v
+      sys.exit(1)
+    browserEnv[v[:ix]] = v[ix + 1:]
+
+  automation.initializeProfile(PROFILE_DIRECTORY, options.extraPrefs)
+  manifest = addChromeToProfile(options)
+  copyExtraFilesToProfile(options)
+  server = MochitestServer(options)
+  server.start()
+
+  # If we're lucky, the server has fully started by now, and all paths are
+  # ready, etc.  However, xpcshell cold start times suck, at least for debug
+  # builds.  We'll try to connect to the server for awhile, and if we fail,
+  # we'll try to kill the server and exit with an error.
+  server.ensureReady(SERVER_STARTUP_TIMEOUT)
+
+  # URL parameters to test URL:
+  #
+  # autorun -- kick off tests automatically
+  # closeWhenDone -- runs quit.js after tests
+  # logFile -- logs test run to an absolute path
+  # totalChunks -- how many chunks to split tests into
+  # thisChunk -- which chunk to run
+  # timeout -- per-test timeout in seconds
+  #
+  
+  # consoleLevel, fileLevel: set the logging level of the console and
+  # file logs, if activated.
+  # <http://mochikit.com/doc/html/MochiKit/Logging.html>
+
+  testURL = TESTS_URL + options.testPath
+  urlOpts = []
+  if options.chrome:
+    testURL = CHROMETESTS_URL
+    if options.testPath:
+      urlOpts.append("testPath=" + encodeURIComponent(options.testPath))
+  elif options.a11y:
+    testURL = A11YTESTS_URL
+    if options.testPath:
+      urlOpts.append("testPath=" + encodeURIComponent(options.testPath))
+  elif options.browserChrome:
+    testURL = "about:blank"
+
+  # allow relative paths for logFile
+  if options.logFile:
+    options.logFile = getFullPath(options.logFile)
+  if options.browserChrome:
+    makeTestConfig(options)
+  else:
+    if options.autorun:
+      urlOpts.append("autorun=1")
+    if options.timeout:
+      urlOpts.append("timeout=%d" % options.timeout)
+    if options.closeWhenDone:
+      urlOpts.append("closeWhenDone=1")
+    if options.logFile:
+      urlOpts.append("logFile=" + encodeURIComponent(options.logFile))
+      urlOpts.append("fileLevel=" + encodeURIComponent(options.fileLevel))
+    if options.consoleLevel:
+      urlOpts.append("consoleLevel=" + encodeURIComponent(options.consoleLevel))
+    if options.totalChunks:
+        urlOpts.append("totalChunks=%d" % options.totalChunks)
+        urlOpts.append("thisChunk=%d" % options.thisChunk)
+        if options.chunkByDir:
+            urlOpts.append("chunkByDir=%d" % options.chunkByDir)
+    if options.shuffle:
+        urlOpts.append("shuffle=1")
+    if len(urlOpts) > 0:
+      testURL += "?" + "&".join(urlOpts)
+
+  browserEnv["XPCOM_MEM_BLOAT_LOG"] = LEAK_REPORT_FILE
+
+  if options.fatalAssertions:
+    browserEnv["XPCOM_DEBUG_BREAK"] = "stack-and-abort"
+
+  # run once with -silent to let the extension manager do its thing
+  # and then exit the app
+  automation.log.info("INFO | runtests.py | Performing extension manager registration: start.\n")
+  # Don't care about this |status|: |runApp()| reporting it should be enough.
+  status = automation.runApp(None, browserEnv, options.app,
+                             PROFILE_DIRECTORY, ["-silent"],
+                             utilityPath = options.utilityPath,
+                             xrePath = options.xrePath,
+                             symbolsPath=options.symbolsPath)
+  # We don't care to call |processLeakLog()| for this step.
+  automation.log.info("\nINFO | runtests.py | Performing extension manager registration: end.")
+
+  # Remove the leak detection file so it can't "leak" to the tests run.
+  # The file is not there if leak logging was not enabled in the application build.
+  if os.path.exists(LEAK_REPORT_FILE):
+    os.remove(LEAK_REPORT_FILE)
 
-  sys.exit(mochitest.runTests(options))
+  # then again to actually run mochitest
+  if options.timeout:
+      timeout = options.timeout + 30
+  elif options.autorun:
+      timeout = None
+  else:
+      timeout = 330.0 # default JS harness timeout is 300 seconds
+  automation.log.info("INFO | runtests.py | Running tests: start.\n")
+  status = automation.runApp(testURL, browserEnv, options.app,
+                             PROFILE_DIRECTORY, options.browserArgs,
+                             runSSLTunnel = True,
+                             utilityPath = options.utilityPath,
+                             xrePath = options.xrePath,
+                             certPath=options.certPath,
+                             debuggerInfo=debuggerInfo,
+                             symbolsPath=options.symbolsPath,
+                             timeout = timeout)
+
+  # Server's no longer needed, and perhaps more importantly, anything it might
+  # spew to console shouldn't disrupt the leak information table we print next.
+  server.stop()
+
+  processLeakLog(LEAK_REPORT_FILE, options.leakThreshold)
+  automation.log.info("\nINFO | runtests.py | Running tests: end.")
+
+  # delete the profile and manifest
+  os.remove(manifest)
+
+  # hanging due to non-halting threads is no fun; assume we hit the errors we
+  # were going to hit already and exit.
+  sys.exit(status)
+
+
+
+#######################
+# CONFIGURATION SETUP #
+#######################
+
+def makeTestConfig(options):
+  "Creates a test configuration file for customizing test execution."
+  def boolString(b):
+    if b:
+      return "true"
+    return "false"
+
+  logFile = options.logFile.replace("\\", "\\\\")
+  testPath = options.testPath.replace("\\", "\\\\")
+  content = """\
+({
+  autoRun: %(autorun)s,
+  closeWhenDone: %(closeWhenDone)s,
+  logPath: "%(logPath)s",
+  testPath: "%(testPath)s"
+})""" % {"autorun": boolString(options.autorun),
+         "closeWhenDone": boolString(options.closeWhenDone),
+         "logPath": logFile,
+         "testPath": testPath}
+
+  config = open(os.path.join(PROFILE_DIRECTORY, "testConfig.js"), "w")
+  config.write(content)
+  config.close() 
+
+
+def addChromeToProfile(options):
+  "Adds MochiKit chrome tests to the profile."
+
+  chromedir = os.path.join(PROFILE_DIRECTORY, "chrome")
+  os.mkdir(chromedir)
+
+  chrome = []
+
+  part = """
+@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); /* set default namespace to XUL */
+toolbar,
+toolbarpalette {
+  background-color: rgb(235, 235, 235) !important;
+}
+toolbar#nav-bar {
+  background-image: none !important;
+}
+"""
+  chrome.append(part)
+
+
+
+  # write userChrome.css
+  chromeFile = open(os.path.join(PROFILE_DIRECTORY, "userChrome.css"), "a")
+  chromeFile.write("".join(chrome))
+  chromeFile.close()
+
+
+  # register our chrome dir
+  chrometestDir = os.path.abspath(".") + "/"
+  if automation.IS_WIN32:
+    chrometestDir = "file:///" + chrometestDir.replace("\\", "/")
+
+
+  (path, leaf) = os.path.split(options.app)
+  manifest = os.path.join(path, "chrome", "mochikit.manifest")
+  manifestFile = open(manifest, "w")
+  manifestFile.write("content mochikit " + chrometestDir + " contentaccessible=yes\n")
+  if options.browserChrome:
+    overlayLine = "overlay " + BROWSER_CHROME_URL + " " \
+                  "chrome://mochikit/content/browser-test-overlay.xul\n"
+    manifestFile.write(overlayLine)
+  manifestFile.close()
+
+  return manifest
+
+def copyExtraFilesToProfile(options):
+  "Copy extra files or dirs specified on the command line to the testing profile."
+  for f in options.extraProfileFiles:
+    abspath = getFullPath(f)
+    dest = os.path.join(PROFILE_DIRECTORY, os.path.basename(abspath))
+    if os.path.isdir(abspath):
+      shutil.copytree(abspath, dest)
+    else:
+      shutil.copy(abspath, dest)
+
+#########
+# DO IT #
+#########
 
 if __name__ == "__main__":
   main()
--- a/testing/xpcshell/runxpcshelltests.py
+++ b/testing/xpcshell/runxpcshelltests.py
@@ -17,17 +17,16 @@
 #
 # The Initial Developer of the Original Code is The Mozilla Foundation
 # Portions created by the Initial Developer are Copyright (C) 2009
 # the Initial Developer. All Rights Reserved.
 #
 # Contributor(s):
 #  Serge Gautherie <sgautherie.bz@free.fr>
 #  Ted Mielczarek <ted.mielczarek@gmail.com>
-#  Joel Maher <joel.maher@gmail.com>
 #
 # Alternatively, the contents of this file may be used under the terms of
 # either the GNU General Public License Version 2 or later (the "GPL"), or
 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 # in which case the provisions of the GPL or the LGPL are applicable instead
 # of those above. If you wish to allow use of your version of this file only
 # under the terms of either the GPL or the LGPL, and not to allow others to
 # use your version of this file under the terms of the MPL, indicate your
@@ -41,256 +40,253 @@
 import re, sys, os, os.path, logging, shutil, signal
 from glob import glob
 from optparse import OptionParser
 from subprocess import Popen, PIPE, STDOUT
 from tempfile import mkdtemp
 
 from automationutils import *
 
-class XPCShellTests(object):
-
-  log = logging.getLogger()
-  oldcwd = os.getcwd()
+# Init logging
+log = logging.getLogger()
+handler = logging.StreamHandler(sys.stdout)
+log.setLevel(logging.INFO)
+log.addHandler(handler)
 
-  def __init__(self):
-    # Init logging
-    handler = logging.StreamHandler(sys.stdout)
-    self.log.setLevel(logging.INFO)
-    self.log.addHandler(handler)
+oldcwd = os.getcwd()
 
-  def readManifest(self, manifest):
-    """Given a manifest file containing a list of test directories,
-    return a list of absolute paths to the directories contained within."""
-    manifestdir = os.path.dirname(manifest)
-    testdirs = []
-    try:
-      f = open(manifest, "r")
-      for line in f:
-        dir = line.rstrip()
-        path = os.path.join(manifestdir, dir)
-        if os.path.isdir(path):
-          testdirs.append(path)
-      f.close()
-    except:
-      pass # just eat exceptions
-    return testdirs
+def readManifest(manifest):
+  """Given a manifest file containing a list of test directories,
+  return a list of absolute paths to the directories contained within."""
+  manifestdir = os.path.dirname(manifest)
+  testdirs = []
+  try:
+    f = open(manifest, "r")
+    for line in f:
+      dir = line.rstrip()
+      path = os.path.join(manifestdir, dir)
+      if os.path.isdir(path):
+        testdirs.append(path)
+    f.close()
+  except:
+    pass # just eat exceptions
+  return testdirs
 
-  def runTests(self, xpcshell, xrePath=None, symbolsPath=None,
-               manifest=None, testdirs=[], testPath=None,
-               interactive=False, logfiles=True,
-               debuggerInfo=None):
-    """Run xpcshell tests.
+def runTests(xpcshell, xrePath=None, symbolsPath=None,
+             manifest=None, testdirs=[], testPath=None,
+             interactive=False, logfiles=True,
+             debuggerInfo=None):
+  """Run xpcshell tests.
 
-    |xpcshell|, is the xpcshell executable to use to run the tests.
-    |xrePath|, if provided, is the path to the XRE to use.
-    |symbolsPath|, if provided is the path to a directory containing
-      breakpad symbols for processing crashes in tests.
-    |manifest|, if provided, is a file containing a list of
-      test directories to run.
-    |testdirs|, if provided, is a list of absolute paths of test directories.
-      No-manifest only option.
-    |testPath|, if provided, indicates a single path and/or test to run.
-    |interactive|, if set to True, indicates to provide an xpcshell prompt
-      instead of automatically executing the test.
-    |logfiles|, if set to False, indicates not to save output to log files.
-      Non-interactive only option.
-    |debuggerInfo|, if set, specifies the debugger and debugger arguments
-      that will be used to launch xpcshell.
-    """
+  |xpcshell|, is the xpcshell executable to use to run the tests.
+  |xrePath|, if provided, is the path to the XRE to use.
+  |symbolsPath|, if provided is the path to a directory containing
+    breakpad symbols for processing crashes in tests.
+  |manifest|, if provided, is a file containing a list of
+    test directories to run.
+  |testdirs|, if provided, is a list of absolute paths of test directories.
+    No-manifest only option.
+  |testPath|, if provided, indicates a single path and/or test to run.
+  |interactive|, if set to True, indicates to provide an xpcshell prompt
+    instead of automatically executing the test.
+  |logfiles|, if set to False, indicates not to save output to log files.
+    Non-interactive only option.
+  |debuggerInfo|, if set, specifies the debugger and debugger arguments
+    that will be used to launch xpcshell.
+  """
 
-    if not testdirs and not manifest:
-      # nothing to test!
-      print >>sys.stderr, "Error: No test dirs or test manifest specified!"
-      return False
+  if not testdirs and not manifest:
+    # nothing to test!
+    print >>sys.stderr, "Error: No test dirs or test manifest specified!"
+    return False
 
-    passCount = 0
-    failCount = 0
+  passCount = 0
+  failCount = 0
 
-    testharnessdir = os.path.dirname(os.path.abspath(__file__))
-    xpcshell = os.path.abspath(xpcshell)
-    # we assume that httpd.js lives in components/ relative to xpcshell
-    httpdJSPath = os.path.join(os.path.dirname(xpcshell), "components", "httpd.js").replace("\\", "/");
+  testharnessdir = os.path.dirname(os.path.abspath(__file__))
+  xpcshell = os.path.abspath(xpcshell)
+  # we assume that httpd.js lives in components/ relative to xpcshell
+  httpdJSPath = os.path.join(os.path.dirname(xpcshell), "components", "httpd.js").replace("\\", "/");
 
-    env = dict(os.environ)
-    # Make assertions fatal
-    env["XPCOM_DEBUG_BREAK"] = "stack-and-abort"
-    # Don't launch the crash reporter client
-    env["MOZ_CRASHREPORTER_NO_REPORT"] = "1"
+  env = dict(os.environ)
+  # Make assertions fatal
+  env["XPCOM_DEBUG_BREAK"] = "stack-and-abort"
+  # Don't launch the crash reporter client
+  env["MOZ_CRASHREPORTER_NO_REPORT"] = "1"
 
-    if xrePath is None:
-      xrePath = os.path.dirname(xpcshell)
-    else:
-      xrePath = os.path.abspath(xrePath)
-    if sys.platform == 'win32':
-      env["PATH"] = env["PATH"] + ";" + xrePath
-    elif sys.platform in ('os2emx', 'os2knix'):
-      os.environ["BEGINLIBPATH"] = xrePath + ";" + env["BEGINLIBPATH"]
-      os.environ["LIBPATHSTRICT"] = "T"
-    elif sys.platform == 'osx':
-      env["DYLD_LIBRARY_PATH"] = xrePath
-    else: # unix or linux?
-      env["LD_LIBRARY_PATH"] = xrePath
+  if xrePath is None:
+    xrePath = os.path.dirname(xpcshell)
+  else:
+    xrePath = os.path.abspath(xrePath)
+  if sys.platform == 'win32':
+    env["PATH"] = env["PATH"] + ";" + xrePath
+  elif sys.platform in ('os2emx', 'os2knix'):
+    os.environ["BEGINLIBPATH"] = xrePath + ";" + env["BEGINLIBPATH"]
+    os.environ["LIBPATHSTRICT"] = "T"
+  elif sys.platform == 'osx':
+    env["DYLD_LIBRARY_PATH"] = xrePath
+  else: # unix or linux?
+    env["LD_LIBRARY_PATH"] = xrePath
 
-    # xpcsRunArgs: <head.js> function to call to run the test.
-    # pStdout, pStderr: Parameter values for later |Popen()| call.
-    if interactive:
-      xpcsRunArgs = [
+  # xpcsRunArgs: <head.js> function to call to run the test.
+  # pStdout, pStderr: Parameter values for later |Popen()| call.
+  if interactive:
+    xpcsRunArgs = [
       '-e', 'print("To start the test, type |_execute_test();|.");',
       '-i']
+    pStdout = None
+    pStderr = None
+  else:
+    xpcsRunArgs = ['-e', '_execute_test();']
+    if (debuggerInfo and debuggerInfo["interactive"]):
       pStdout = None
       pStderr = None
     else:
-      xpcsRunArgs = ['-e', '_execute_test();']
-      if (debuggerInfo and debuggerInfo["interactive"]):
+      if sys.platform == 'os2emx':
         pStdout = None
-        pStderr = None
       else:
-        if sys.platform == 'os2emx':
-          pStdout = None
-        else:
-          pStdout = PIPE
-        pStderr = STDOUT
+        pStdout = PIPE
+      pStderr = STDOUT
 
-    # <head.js> has to be loaded by xpchell: it can't load itself.
-    xpcsCmd = [xpcshell, '-g', xrePath, '-j', '-s'] + \
-              ['-e', 'const _HTTPD_JS_PATH = "%s";' % httpdJSPath,
-              '-f', os.path.join(testharnessdir, 'head.js')]
+  # <head.js> has to be loaded by xpchell: it can't load itself.
+  xpcsCmd = [xpcshell, '-g', xrePath, '-j', '-s'] + \
+            ['-e', 'const _HTTPD_JS_PATH = "%s";' % httpdJSPath,
+             '-f', os.path.join(testharnessdir, 'head.js')]
 
-    if debuggerInfo:
-      xpcsCmd = [debuggerInfo["path"]] + debuggerInfo["args"] + xpcsCmd
+  if debuggerInfo:
+    xpcsCmd = [debuggerInfo["path"]] + debuggerInfo["args"] + xpcsCmd
 
-    # |testPath| will be the optional path only, or |None|.
-    # |singleFile| will be the optional test only, or |None|.
-    singleFile = None
-    if testPath:
-      if testPath.endswith('.js'):
-        # Split into path and file.
-        if testPath.find('/') == -1:
-          # Test only.
-          singleFile = testPath
-          testPath = None
-        else:
-          # Both path and test.
-          # Reuse |testPath| temporarily.
-          testPath = testPath.rsplit('/', 1)
-          singleFile = testPath[1]
-          testPath = testPath[0]
+  # |testPath| will be the optional path only, or |None|.
+  # |singleFile| will be the optional test only, or |None|.
+  singleFile = None
+  if testPath:
+    if testPath.endswith('.js'):
+      # Split into path and file.
+      if testPath.find('/') == -1:
+        # Test only.
+        singleFile = testPath
+        testPath = None
       else:
-        # Path only.
-        # Simply remove optional ending separator.
-        testPath = testPath.rstrip("/")
+        # Both path and test.
+        # Reuse |testPath| temporarily.
+        testPath = testPath.rsplit('/', 1)
+        singleFile = testPath[1]
+        testPath = testPath[0]
+    else:
+      # Path only.
+      # Simply remove optional ending separator.
+      testPath = testPath.rstrip("/")
+
+  # Override testdirs.
+  if manifest is not None:
+    testdirs = readManifest(os.path.abspath(manifest))
+
+  # Process each test directory individually.
+  for testdir in testdirs:
+    if testPath and not testdir.endswith(testPath):
+      continue
 
-    # Override testdirs.
-    if manifest is not None:
-      testdirs = self.readManifest(os.path.abspath(manifest))
+    testdir = os.path.abspath(testdir)
 
-    # Process each test directory individually.
-    for testdir in testdirs:
-      if testPath and not testdir.endswith(testPath):
+    # get the list of head and tail files from the directory
+    testHeadFiles = []
+    for f in sorted(glob(os.path.join(testdir, "head_*.js"))):
+      if os.path.isfile(f):
+        testHeadFiles += [f]
+    testTailFiles = []
+    # Tails are executed in the reverse order, to "match" heads order,
+    # as in "h1-h2-h3 then t3-t2-t1".
+    for f in reversed(sorted(glob(os.path.join(testdir, "tail_*.js")))):
+      if os.path.isfile(f):
+        testTailFiles += [f]
+
+    # if a single test file was specified, we only want to execute that test
+    testfiles = sorted(glob(os.path.join(testdir, "test_*.js")))
+    if singleFile:
+      if singleFile in [os.path.basename(x) for x in testfiles]:
+        testfiles = [os.path.join(testdir, singleFile)]
+      else: # not in this dir? skip it
         continue
 
-      testdir = os.path.abspath(testdir)
-
-      # get the list of head and tail files from the directory
-      testHeadFiles = []
-      for f in sorted(glob(os.path.join(testdir, "head_*.js"))):
-        if os.path.isfile(f):
-          testHeadFiles += [f]
-      testTailFiles = []
-      # Tails are executed in the reverse order, to "match" heads order,
-      # as in "h1-h2-h3 then t3-t2-t1".
-      for f in reversed(sorted(glob(os.path.join(testdir, "tail_*.js")))):
-        if os.path.isfile(f):
-          testTailFiles += [f]
+    cmdH = ", ".join(['"' + f.replace('\\', '/') + '"'
+                       for f in testHeadFiles])
+    cmdT = ", ".join(['"' + f.replace('\\', '/') + '"'
+                       for f in testTailFiles])
+    cmdH = xpcsCmd + \
+           ['-e', 'const _HEAD_FILES = [%s];' % cmdH] + \
+           ['-e', 'const _TAIL_FILES = [%s];' % cmdT]
 
-      # if a single test file was specified, we only want to execute that test
-      testfiles = sorted(glob(os.path.join(testdir, "test_*.js")))
-      if singleFile:
-        if singleFile in [os.path.basename(x) for x in testfiles]:
-          testfiles = [os.path.join(testdir, singleFile)]
-        else: # not in this dir? skip it
-          continue
+    # Now execute each test individually.
+    for test in testfiles:
+      # The test file will have to be loaded after the head files.
+      cmdT = ['-e', 'const _TEST_FILE = ["%s"];' %
+                      os.path.join(testdir, test).replace('\\', '/')]
 
-      cmdH = ", ".join(['"' + f.replace('\\', '/') + '"'
-                 for f in testHeadFiles])
-      cmdT = ", ".join(['"' + f.replace('\\', '/') + '"'
-                 for f in testTailFiles])
-      cmdH = xpcsCmd + \
-                ['-e', 'const _HEAD_FILES = [%s];' % cmdH] + \
-                ['-e', 'const _TAIL_FILES = [%s];' % cmdT]
+      # create a temp dir that the JS harness can stick a profile in
+      profileDir = None
+      try:
+        profileDir = mkdtemp()
+        env["XPCSHELL_TEST_PROFILE_DIR"] = profileDir
 
-      # Now execute each test individually.
-      for test in testfiles:
-        # The test file will have to be loaded after the head files.
-        cmdT = ['-e', 'const _TEST_FILE = ["%s"];' %
-                os.path.join(testdir, test).replace('\\', '/')]
+        # Enable leaks (only) detection to its own log file.
+        leakLogFile = os.path.join(profileDir, "runxpcshelltests_leaks.log")
+        env["XPCOM_MEM_LEAK_LOG"] = leakLogFile
 
-        # create a temp dir that the JS harness can stick a profile in
-        profileDir = None
-        try:
-          profileDir = mkdtemp()
-          env["XPCSHELL_TEST_PROFILE_DIR"] = profileDir
-
-          # Enable leaks (only) detection to its own log file.
-          leakLogFile = os.path.join(profileDir, "runxpcshelltests_leaks.log")
-          env["XPCOM_MEM_LEAK_LOG"] = leakLogFile
+        proc = Popen(cmdH + cmdT + xpcsRunArgs,
+                     stdout=pStdout, stderr=pStderr, env=env, cwd=testdir)
 
-          proc = Popen(cmdH + cmdT + xpcsRunArgs,
-                      stdout=pStdout, stderr=pStderr, env=env, cwd=testdir)
+        # allow user to kill hung subprocess with SIGINT w/o killing this script
+        # - don't move this line above Popen, or child will inherit the SIG_IGN
+        signal.signal(signal.SIGINT, signal.SIG_IGN)
+        # |stderr == None| as |pStderr| was either |None| or redirected to |stdout|.
+        stdout, stderr = proc.communicate()
+        signal.signal(signal.SIGINT, signal.SIG_DFL)
 
-          # allow user to kill hung subprocess with SIGINT w/o killing this script
-          # - don't move this line above Popen, or child will inherit the SIG_IGN
-          signal.signal(signal.SIGINT, signal.SIG_IGN)
-          # |stderr == None| as |pStderr| was either |None| or redirected to |stdout|.
-          stdout, stderr = proc.communicate()
-          signal.signal(signal.SIGINT, signal.SIG_DFL)
+        if interactive:
+          # Not sure what else to do here...
+          return True
 
-          if interactive:
-            # Not sure what else to do here...
-            return True
-
-          if proc.returncode != 0 or (stdout and re.search("^TEST-UNEXPECTED-FAIL", stdout, re.MULTILINE)):
-            print """TEST-UNEXPECTED-FAIL | %s | test failed (with xpcshell return code: %d), see following log:
+        if proc.returncode != 0 or (stdout and re.search("^TEST-UNEXPECTED-FAIL", stdout, re.MULTILINE)):
+          print """TEST-UNEXPECTED-FAIL | %s | test failed (with xpcshell return code: %d), see following log:
   >>>>>>>
   %s
   <<<<<<<""" % (test, proc.returncode, stdout)
-            checkForCrashes(testdir, symbolsPath, testName=test)
-            failCount += 1
-          else:
-            print "TEST-PASS | %s | test passed" % test
-            passCount += 1
+          checkForCrashes(testdir, symbolsPath, testName=test)
+          failCount += 1
+        else:
+          print "TEST-PASS | %s | test passed" % test
+          passCount += 1
 
-          dumpLeakLog(leakLogFile, True)
+        dumpLeakLog(leakLogFile, True)
 
-          if logfiles and stdout:
-            try:
-              f = open(test + ".log", "w")
-              f.write(stdout)
+        if logfiles and stdout:
+          try:
+            f = open(test + ".log", "w")
+            f.write(stdout)
 
-              if os.path.exists(leakLogFile):
-                leaks = open(leakLogFile, "r")
-                f.write(leaks.read())
-                leaks.close()
-            finally:
-              if f:
-                f.close()
-        finally:
-          if profileDir:
-            shutil.rmtree(profileDir)
+            if os.path.exists(leakLogFile):
+              leaks = open(leakLogFile, "r")
+              f.write(leaks.read())
+              leaks.close()
+          finally:
+            if f:
+              f.close()
+      finally:
+        if profileDir:
+          shutil.rmtree(profileDir)
 
-    if passCount == 0 and failCount == 0:
-      print "TEST-UNEXPECTED-FAIL | runxpcshelltests.py | No tests run. Did you pass an invalid --test-path?"
-      failCount = 1
+  if passCount == 0 and failCount == 0:
+    print "TEST-UNEXPECTED-FAIL | runxpcshelltests.py | No tests run. Did you pass an invalid --test-path?"
+    failCount = 1
 
-    print """INFO | Result summary:
+  print """INFO | Result summary:
 INFO | Passed: %d
 INFO | Failed: %d""" % (passCount, failCount)
 
-    return failCount == 0
+  return failCount == 0
 
 def main():
   """Process command line arguments and call runTests() to do the real work."""
   parser = OptionParser()
 
   addCommonOptions(parser)
   parser.add_option("--interactive",
                     action="store_true", dest="interactive", default=False,
@@ -306,35 +302,33 @@ def main():
                     help="don't create log files")
   parser.add_option("--test-path",
                     type="string", dest="testPath", default=None,
                     help="single path and/or test filename to test")
   options, args = parser.parse_args()
 
   if len(args) < 2 and options.manifest is None or \
      (len(args) < 1 and options.manifest is not None):
-     print >>sys.stderr, """Usage: %s <path to xpcshell> <test dirs>
-           or: %s --manifest=test.manifest <path to xpcshell>""" % (sys.argv[0],
+    print >>sys.stderr, """Usage: %s <path to xpcshell> <test dirs>
+  or: %s --manifest=test.manifest <path to xpcshell>""" % (sys.argv[0],
                                                            sys.argv[0])
-     sys.exit(1)
+    sys.exit(1)
 
-  xpcsh = XPCShellTests()
-  debuggerInfo = getDebuggerInfo(xpcsh.oldcwd, options.debugger, options.debuggerArgs,
+  debuggerInfo = getDebuggerInfo(oldcwd, options.debugger, options.debuggerArgs,
     options.debuggerInteractive);
 
   if options.interactive and not options.testPath:
     print >>sys.stderr, "Error: You must specify a test filename in interactive mode!"
     sys.exit(1)
 
-    
-  if not xpcsh.runTests(args[0],
-                        xrePath=options.xrePath,
-                        symbolsPath=options.symbolsPath,
-                        manifest=options.manifest,
-                        testdirs=args[1:],
-                        testPath=options.testPath,
-                        interactive=options.interactive,
-                        logfiles=options.logfiles,
-                        debuggerInfo=debuggerInfo):
+  if not runTests(args[0],
+                  xrePath=options.xrePath,
+                  symbolsPath=options.symbolsPath,
+                  manifest=options.manifest,
+                  testdirs=args[1:],
+                  testPath=options.testPath,
+                  interactive=options.interactive,
+                  logfiles=options.logfiles,
+                  debuggerInfo=debuggerInfo):
     sys.exit(1)
 
 if __name__ == '__main__':
   main()