Bug 1038943: Turn on leak checking on B2G with an initial threshold of 400000 bytes. r=ahal,dbaron
authorKyle Huey <khuey@kylehuey.com>
Tue, 05 Aug 2014 14:11:53 -0700
changeset 219633 78613874d413a49a21c9a9f3adddfda5f03168a0
parent 219536 e66e1130da318dd06853572df55373a3196f9d10
child 219634 7a54b04fe52fa971d5852b9275a7876f1030f09d
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersahal, dbaron
bugs1038943, 400000
milestone34.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1038943: Turn on leak checking on B2G with an initial threshold of 400000 bytes. r=ahal,dbaron
build/automationutils.py
testing/mochitest/mochitest_options.py
testing/mochitest/runtests.py
testing/mochitest/runtestsb2g.py
testing/mozbase/mozrunner/mozrunner/base/device.py
--- a/build/automationutils.py
+++ b/build/automationutils.py
@@ -471,17 +471,20 @@ def environment(xrePath, env=None, crash
 
   assert os.path.isabs(xrePath)
 
   ldLibraryPath = xrePath
 
   envVar = None
   dmdLibrary = None
   preloadEnvVar = None
-  if mozinfo.isUnix:
+  if mozinfo.info['toolkit'] == "gonk":
+    # Skip all of this, it's only valid for the host.
+    pass
+  elif mozinfo.isUnix:
     envVar = "LD_LIBRARY_PATH"
     env['MOZILLA_FIVE_HOME'] = xrePath
     dmdLibrary = "libdmd.so"
     preloadEnvVar = "LD_PRELOAD"
   elif mozinfo.isMac:
     envVar = "DYLD_LIBRARY_PATH"
     dmdLibrary = "libdmd.dylib"
     preloadEnvVar = "DYLD_INSERT_LIBRARIES"
--- a/testing/mochitest/mochitest_options.py
+++ b/testing/mochitest/mochitest_options.py
@@ -750,16 +750,18 @@ class B2GOptions(MochitestOptions):
         defaults = {}
         defaults["httpPort"] = DEFAULT_PORTS['http']
         defaults["sslPort"] = DEFAULT_PORTS['https']
         defaults["logFile"] = "mochitest.log"
         defaults["autorun"] = True
         defaults["closeWhenDone"] = True
         defaults["testPath"] = ""
         defaults["extensionsToExclude"] = ["specialpowers"]
+        # See dependencies of bug 1038943.
+        defaults["leakThreshold"] = 5200
         self.set_defaults(**defaults)
 
     def verifyRemoteOptions(self, options):
         if options.remoteWebServer == None:
             if os.name != "nt":
                 options.remoteWebServer = moznetwork.get_ip()
             else:
                 self.error("You must specify a --remote-webserver=<ip address>")
--- a/testing/mochitest/runtests.py
+++ b/testing/mochitest/runtests.py
@@ -1156,25 +1156,26 @@ class Mochitest(MochitestUtilsMixin):
 
     # For packaged builds, gmp-fake will get copied under $profile/plugins.
     gmp_path = os.path.join(self.profile.profile, 'plugins', 'gmp-fake')
     if os.path.isdir(gmp_path):
       return gmp_path
     # This is fatal for desktop environments.
     raise EnvironmentError('Could not find gmp-fake')
 
-  def buildBrowserEnv(self, options, debugger=False):
+  def buildBrowserEnv(self, options, debugger=False, env=None):
     """build the environment variables for the specific test and operating system"""
     if mozinfo.info["asan"]:
       lsanPath = SCRIPT_DIR
     else:
       lsanPath = None
 
-    browserEnv = self.environment(xrePath=options.xrePath, debugger=debugger,
-                                  dmdPath=options.dmdPath, lsanPath=lsanPath)
+    browserEnv = self.environment(xrePath=options.xrePath, env=env,
+                                  debugger=debugger, dmdPath=options.dmdPath,
+                                  lsanPath=lsanPath)
 
     # These variables are necessary for correct application startup; change
     # via the commandline at your own risk.
     browserEnv["XPCOM_DEBUG_BREAK"] = "stack"
 
     # interpolate environment passed with options
     try:
       browserEnv.update(dict(parseKeyValue(options.environment, context='--setenv')))
--- a/testing/mochitest/runtestsb2g.py
+++ b/testing/mochitest/runtestsb2g.py
@@ -9,16 +9,17 @@ import shutil
 import sys
 import tempfile
 import threading
 import traceback
 
 here = os.path.abspath(os.path.dirname(__file__))
 sys.path.insert(0, here)
 
+from automationutils import processLeakLog
 from runtests import Mochitest
 from runtests import MochitestUtilsMixin
 from runtests import MessageLogger
 from runtests import MochitestFormatter
 from mochitest_options import B2GOptions, MochitestOptions
 from marionette import Marionette
 from mozprofile import Profile, Preferences
 import mozinfo
@@ -116,17 +117,16 @@ class B2GMochitest(MochitestUtilsMixin):
         manifest = self.addChromeToProfile(options)
         self.copyExtraFilesToProfile(options)
         return manifest
 
     def run_tests(self, options):
         """ Prepare, configure, run tests and cleanup """
 
         manifest = self.build_profile(options)
-        self.leak_report_file = os.path.join(options.profilePath, "runtests_leaks.log")
 
         # configuring the message logger's buffering
         self.message_logger.buffering = options.quiet
 
         if options.debugger or not options.autorun:
             timeout = None
         else:
             if not options.timeout:
@@ -155,16 +155,29 @@ class B2GMochitest(MochitestUtilsMixin):
             self.runner = self.marionette.runner
             self.app_ctx = self.runner.app_ctx
 
             self.remote_log = posixpath.join(self.app_ctx.remote_test_root,
                                              'log', 'mochitest.log')
             if not self.app_ctx.dm.dirExists(posixpath.dirname(self.remote_log)):
                 self.app_ctx.dm.mkDirs(self.remote_log)
 
+            self.leak_report_file = posixpath.join(self.app_ctx.remote_test_root,
+                                                   'log', 'runtests_leaks.log')
+
+            # We don't want to copy the host env onto the device, so pass in an
+            # empty env.
+            self.browserEnv = self.buildBrowserEnv(options, env={})
+
+            # XXXkhuey MOZ_DISABLE_NONLOCAL_CONNECTIONS is busted on b2g, so make
+            # sure we don't pass it through (bug 1039019).
+            if 'MOZ_DISABLE_NONLOCAL_CONNECTIONS' in self.browserEnv:
+                del self.browserEnv['MOZ_DISABLE_NONLOCAL_CONNECTIONS']
+            self.runner.env.update(self.browserEnv)
+
             self.startServers(options, None)
             self.buildURLOptions(options, {'MOZ_HIDE_RESULTS_TABLE': '1'})
             self.test_script_args.append(not options.emulator)
             self.test_script_args.append(options.wifi)
 
 
             self.runner.start(outputTimeout=timeout)
 
@@ -188,16 +201,22 @@ class B2GMochitest(MochitestUtilsMixin):
             else:
                 self.marionette.execute_script(self.test_script,
                                                script_args=self.test_script_args)
             status = self.runner.wait()
 
             if status is None:
                 # the runner has timed out
                 status = 124
+
+            local_leak_file = tempfile.NamedTemporaryFile()
+            self.app_ctx.dm.getFile(self.leak_report_file, local_leak_file.name)
+            self.app_ctx.dm.removeFile(self.leak_report_file)
+
+            processLeakLog(local_leak_file.name, options.leakThreshold)
         except KeyboardInterrupt:
             log.info("runtests.py | Received keyboard interrupt.\n");
             status = -1
         except:
             traceback.print_exc()
             log.error("Automation Error: Received unexpected exception while running application\n")
             if hasattr(self, 'runner'):
                 self.runner.check_for_crashes()
--- a/testing/mozbase/mozrunner/mozrunner/base/device.py
+++ b/testing/mozbase/mozrunner/mozrunner/base/device.py
@@ -14,47 +14,44 @@ import time
 from .runner import BaseRunner
 from ..devices import Emulator
 
 class DeviceRunner(BaseRunner):
     """
     The base runner class used for running gecko on
     remote devices (or emulators), such as B2G.
     """
+    env = { 'MOZ_CRASHREPORTER': '1',
+            'MOZ_CRASHREPORTER_NO_REPORT': '1',
+            'MOZ_CRASHREPORTER_SHUTDOWN': '1',
+            'MOZ_HIDE_RESULTS_TABLE': '1',
+            'NSPR_LOG_MODULES': 'signaling:5,mtransport:5,datachannel:5',
+            'R_LOG_LEVEL': '6',
+            'R_LOG_DESTINATION': 'stderr',
+            'R_LOG_VERBOSE': '1',
+            'NO_EM_RESTART': '1', }
+
     def __init__(self, device_class, device_args=None, **kwargs):
+        process_log = tempfile.NamedTemporaryFile(suffix='pidlog')
+        self._env = dict(self.env)
+        self._env['MOZ_PROCESS_LOG'] = process_log.name
+        self._env.update(kwargs.pop('env', {}) or {})
+
         process_args = {'stream': sys.stdout,
                         'processOutputLine': self.on_output,
                         'onTimeout': self.on_timeout }
         process_args.update(kwargs.get('process_args') or {})
 
         kwargs['process_args'] = process_args
+        kwargs['env'] = {}
         BaseRunner.__init__(self, **kwargs)
 
         device_args = device_args or {}
         self.device = device_class(**device_args)
 
-        process_log = tempfile.NamedTemporaryFile(suffix='pidlog')
-        self._env =  { 'MOZ_CRASHREPORTER': '1',
-                       'MOZ_CRASHREPORTER_NO_REPORT': '1',
-                       'MOZ_CRASHREPORTER_SHUTDOWN': '1',
-                       'MOZ_HIDE_RESULTS_TABLE': '1',
-                       'MOZ_PROCESS_LOG': process_log.name,
-                       'NSPR_LOG_MODULES': 'signaling:5,mtransport:5,datachannel:5',
-                       'R_LOG_LEVEL': '6',
-                       'R_LOG_DESTINATION': 'stderr',
-                       'R_LOG_VERBOSE': '1',
-                       'NO_EM_RESTART': '1', }
-        if kwargs.get('env'):
-            self._env.update(kwargs['env'])
-
-        # In this case we need to pass in env as part of the command.
-        # Make this empty so runner doesn't pass anything into the
-        # process class.
-        self.env = None
-
     @property
     def command(self):
         cmd = [self.app_ctx.adb]
         if self.app_ctx.dm._deviceSerial:
             cmd.extend(['-s', self.app_ctx.dm._deviceSerial])
         cmd.append('shell')
         for k, v in self._env.iteritems():
             cmd.append('%s=%s' % (k, v))
@@ -74,17 +71,23 @@ class DeviceRunner(BaseRunner):
 
         if not isinstance(self.device, Emulator):
             self.device.reboot()
 
         if not self.device.wait_for_net():
             raise Exception("Network did not come up when starting device")
         self.app_ctx.stop_application()
 
+        # In this case we need to pass in env as part of the command.
+        # Make this empty so BaseRunner doesn't pass anything into the
+        # process class.
+        self._env = self.env
+        self.env = None
         BaseRunner.start(self, *args, **kwargs)
+        self.env = self._env
 
         timeout = 10 # seconds
         starttime = datetime.datetime.now()
         while datetime.datetime.now() - starttime < datetime.timedelta(seconds=timeout):
             if self.app_ctx.dm.processExist(self.app_ctx.remote_process):
                 break
             time.sleep(1)
         else: