From 45febf0fde5e83cc135b7eca7fe53cc71a599fc4 Mon Sep 17 00:00:00 2001 From: Andrew Halberstadt Date: Wed, 23 Oct 2013 14:45:48 -0400 Subject: [PATCH] Bug 930025 - b2g unittests need to check for crashes in more places, r=jgriffin --- .../client/marionette/b2ginstance.py | 7 +++-- .../marionette/client/marionette/emulator.py | 19 +++++++------ .../client/marionette/marionette.py | 4 +-- testing/mochitest/runtestsb2g.py | 2 ++ testing/mozbase/mozrunner/mozrunner/remote.py | 28 ++++++++++--------- testing/mozbase/mozrunner/mozrunner/runner.py | 16 ++++++++++- 6 files changed, 49 insertions(+), 27 deletions(-) diff --git a/testing/marionette/client/marionette/b2ginstance.py b/testing/marionette/client/marionette/b2ginstance.py index 88abf4c06773..4e9e8323e639 100644 --- a/testing/marionette/client/marionette/b2ginstance.py +++ b/testing/marionette/client/marionette/b2ginstance.py @@ -15,11 +15,12 @@ import mozcrash class B2GInstance(B2GBuild): - def __init__(self, devicemanager=None, **kwargs): + def __init__(self, devicemanager=None, symbols_path=None, **kwargs): B2GBuild.__init__(self, **kwargs) self._dm = devicemanager self._remote_profiles = None + self.symbols_path = symbols_path @property def dm(self): @@ -52,14 +53,14 @@ class B2GInstance(B2GBuild): self._remote_profiles = remote_profiles return remote_profiles - def check_for_crashes(self, symbols_path): + def check_for_crashes(self): remote_dump_dirs = [posixpath.join(p, 'minidumps') for p in self.remote_profiles] crashed = False for remote_dump_dir in remote_dump_dirs: local_dump_dir = tempfile.mkdtemp() self.dm.getDirectory(remote_dump_dir, local_dump_dir) try: - if mozcrash.check_for_crashes(local_dump_dir, symbols_path): + if mozcrash.check_for_crashes(local_dump_dir, self.symbols_path): crashed = True except: traceback.print_exc() diff --git a/testing/marionette/client/marionette/emulator.py b/testing/marionette/client/marionette/emulator.py index b579e12536cc..fac31fe5bdda 100644 --- a/testing/marionette/client/marionette/emulator.py +++ b/testing/marionette/client/marionette/emulator.py @@ -48,7 +48,7 @@ class Emulator(object): def __init__(self, homedir=None, noWindow=False, logcat_dir=None, arch="x86", emulatorBinary=None, res=None, sdcard=None, - userdata=None): + symbols_path=None, userdata=None): self.port = None self.dm = None self._emulator_launched = False @@ -69,6 +69,7 @@ class Emulator(object): self.screen = EmulatorScreen(self) self.homedir = homedir self.sdcard = sdcard + self.symbols_path = symbols_path self.noWindow = noWindow if self.homedir is not None: self.homedir = os.path.expanduser(homedir) @@ -76,7 +77,8 @@ class Emulator(object): self.copy_userdata = self.dataImg is None def _check_for_b2g(self): - self.b2g = B2GInstance(homedir=self.homedir, emulator=True) + self.b2g = B2GInstance(homedir=self.homedir, emulator=True, + symbols_path=self.symbols_path) self.adb = self.b2g.adb_path self.homedir = self.b2g.homedir @@ -159,13 +161,11 @@ class Emulator(object): closed), and self.proc.poll() is also not None (meaning the emulator process has terminated). """ - if (self._emulator_launched and self.proc is not None - and self.proc.poll() is not None): - return True - return False + return self._emulator_launched and self.proc is not None \ + and self.proc.poll() is not None - def check_for_minidumps(self, symbols_path): - return self.b2g.check_for_crashes(symbols_path) + def check_for_minidumps(self): + return self.b2g.check_for_crashes() def create_sdcard(self, sdcard): self._tmp_sdcard = tempfile.mktemp(prefix='sdcard') @@ -274,6 +274,9 @@ waitFor( # older emulators. 45s *should* be enough of a delay # to allow telephony API's to work. pass + except InvalidResponseException: + self.check_for_minidumps() + raise print 'done' marionette.set_context(marionette.CONTEXT_CONTENT) marionette.delete_session() diff --git a/testing/marionette/client/marionette/marionette.py b/testing/marionette/client/marionette/marionette.py index 3e2e516e92c6..28faf47aa475 100644 --- a/testing/marionette/client/marionette/marionette.py +++ b/testing/marionette/client/marionette/marionette.py @@ -442,7 +442,6 @@ class Marionette(object): self.noWindow = noWindow self.logcat_dir = logcat_dir self._test_name = None - self.symbols_path = symbols_path self.timeout = timeout self.device_serial = device_serial @@ -471,6 +470,7 @@ class Marionette(object): logcat_dir=self.logcat_dir, arch=emulator, sdcard=sdcard, + symbols_path=symbols_path, emulatorBinary=emulatorBinary, userdata=emulatorImg, res=emulator_res) @@ -648,7 +648,7 @@ class Marionette(object): name = 'emulator' crashed = True - if self.symbols_path and self.emulator.check_for_minidumps(self.symbols_path): + if self.emulator.check_for_minidumps(): crashed = True elif self.instance: # In the future, a check for crashed Firefox processes diff --git a/testing/mochitest/runtestsb2g.py b/testing/mochitest/runtestsb2g.py index 75ea1f241677..e5260e088d16 100644 --- a/testing/mochitest/runtestsb2g.py +++ b/testing/mochitest/runtestsb2g.py @@ -130,6 +130,7 @@ class B2GMochitest(MochitestUtilsMixin): 'devicemanager': self._dm, 'marionette': self.marionette, 'remote_test_root': self.remote_test_root, + 'symbols_path': options.symbolsPath, 'test_script': self.test_script, 'test_script_args': self.test_script_args } self.runner = B2GRunner(**runner_args) @@ -144,6 +145,7 @@ class B2GMochitest(MochitestUtilsMixin): except: traceback.print_exc() log.error("Automation Error: Received unexpected exception while running application\n") + self.runner.check_for_crashes() status = 1 self.stopWebServer(options) diff --git a/testing/mozbase/mozrunner/mozrunner/remote.py b/testing/mozbase/mozrunner/mozrunner/remote.py index 0f4e92364522..5d8ea2cdb63e 100644 --- a/testing/mozbase/mozrunner/mozrunner/remote.py +++ b/testing/mozbase/mozrunner/mozrunner/remote.py @@ -6,11 +6,9 @@ import shutil import subprocess import tempfile import time -import traceback from runner import Runner from mozdevice import DMError -import mozcrash import mozlog __all__ = ['RemoteRunner', 'B2GRunner', 'remote_runners'] @@ -23,13 +21,15 @@ class RemoteRunner(Runner): process_class=None, env=None, remote_test_root=None, - restore=True): + restore=True, + **kwargs): super(RemoteRunner, self).__init__(profile, clean_profile=clean_profile, - process_class=process_class, env=env) + process_class=process_class, env=env, **kwargs) self.log = mozlog.getLogger('RemoteRunner') self.dm = devicemanager + self.last_test = None self.remote_test_root = remote_test_root or self.dm.getDeviceRoot() self.remote_profile = posixpath.join(self.remote_test_root, 'profile') self.restore = restore @@ -44,20 +44,21 @@ class RemoteRunner(Runner): self.backup_files.add(remote_path) - def check_for_crashes(self, symbols_path, last_test=None): - crashed = False + def check_for_crashes(self, last_test=None): + last_test = last_test or self.last_test remote_dump_dir = posixpath.join(self.remote_profile, 'minidumps') + crashed = False + self.log.info("checking for crashes in '%s'" % remote_dump_dir) if self.dm.dirExists(remote_dump_dir): local_dump_dir = tempfile.mkdtemp() self.dm.getDirectory(remote_dump_dir, local_dump_dir) - try: - crashed = mozcrash.check_for_crashes(local_dump_dir, symbols_path, test_name=last_test) - except: - traceback.print_exc() - finally: - shutil.rmtree(local_dump_dir) - self.dm.removeDir(remote_dump_dir) + + crashed = super(RemoteRunner, self).check_for_crashes(local_dump_dir, \ + test_name=last_test) + shutil.rmtree(local_dump_dir) + self.dm.removeDir(remote_dump_dir) + return crashed def cleanup(self): @@ -197,6 +198,7 @@ class B2GRunner(RemoteRunner): msg = "%s with no output" % msg self.log.testFail(msg % (self.last_test, timeout)) + self.check_for_crashes() def _reboot_device(self): serial, status = self._get_device_status() diff --git a/testing/mozbase/mozrunner/mozrunner/runner.py b/testing/mozbase/mozrunner/mozrunner/runner.py index c1027cb0a9b9..c83e528ba44d 100755 --- a/testing/mozbase/mozrunner/mozrunner/runner.py +++ b/testing/mozbase/mozrunner/mozrunner/runner.py @@ -4,8 +4,10 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this file, # You can obtain one at http://mozilla.org/MPL/2.0/. import subprocess +import traceback from mozprocess.processhandler import ProcessHandler +import mozcrash import mozlog # we can replace this method with 'abc' @@ -21,7 +23,8 @@ def abstractmethod(method): class Runner(object): - def __init__(self, profile, clean_profile=True, process_class=None, kp_kwargs=None, env=None): + def __init__(self, profile, clean_profile=True, process_class=None, + kp_kwargs=None, env=None, symbols_path=None): self.clean_profile = clean_profile self.env = env or {} self.kp_kwargs = kp_kwargs or {} @@ -29,6 +32,7 @@ class Runner(object): self.process_handler = None self.profile = profile self.log = mozlog.getLogger('MozRunner') + self.symbols_path = symbols_path @abstractmethod def start(self, *args, **kwargs): @@ -103,6 +107,16 @@ class Runner(object): if getattr(self, 'profile', False): self.profile.reset() + def check_for_crashes(self, dump_directory, test_name=None): + crashed = False + try: + crashed = mozcrash.check_for_crashes(dump_directory, + self.symbols_path, + test_name=test_name) + except: + traceback.print_exc() + return crashed + def cleanup(self): """ Cleanup all runner state