Bug 1251633 - Install all mochitest extensions as temporary addons draft
authorAndrew Halberstadt <ahalberstadt@mozilla.com>
Wed, 24 Feb 2016 14:08:27 -0500
changeset 334979 a50b94f69d17fa38e526e8246d44dd9ad174518e
parent 334552 c1e0d1890cfee9d86c8d566b0490053f21e0afc6
child 515040 24f6d948d273c4ab478b2b092acf636371bfd72c
push id11685
push userahalberstadt@mozilla.com
push dateFri, 26 Feb 2016 16:33:20 +0000
bugs1251633
milestone47.0a1
Bug 1251633 - Install all mochitest extensions as temporary addons MozReview-Commit-ID: HkX4Drn4tFT
testing/marionette/driver/marionette_driver/addons.py
testing/mochitest/mochitest_options.py
testing/mochitest/runtests.py
--- a/testing/marionette/driver/marionette_driver/addons.py
+++ b/testing/marionette/driver/marionette_driver/addons.py
@@ -1,12 +1,15 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # 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 os
+from zipfile import ZipFile
+
 from .errors import MarionetteException
 
 __all__ = ['Addons', 'AddonInstallException']
 
 
 # From https://developer.mozilla.org/en-US/Add-ons/Add-on_Manager/AddonManager#AddonInstall_errors
 ADDON_INSTALL_ERRORS = {
     -1: "ERROR_NETWORK_FAILURE: A network error occured.",
@@ -47,16 +50,17 @@ class Addons(object):
 
         :param path: A file path to the extension to be installed.
         :param temp: Install a temporary addon. Temporary addons will
                      automatically be uninstalled on shutdown and do not need
                      to be signed, though they must be restartless.
         :returns: The addon ID string of the newly installed addon.
         :raises: :exc:`AddonInstallException`
         """
+        print(temp)
         with self._mn.using_context('chrome'):
             addon_id, status = self._mn.execute_async_script("""
               let FileUtils = Components.utils.import("resource://gre/modules/FileUtils.jsm").FileUtils;
               Components.utils.import("resource://gre/modules/AddonManager.jsm");
               let listener = {
                 onInstallEnded: function(install, addon) {
                   marionetteScriptFinished([addon.id, 0]);
                 },
@@ -110,8 +114,24 @@ class Addons(object):
         with self._mn.using_context('chrome'):
             return self._mn.execute_async_script("""
               Components.utils.import("resource://gre/modules/AddonManager.jsm");
               AddonManager.getAddonByID(arguments[0], function(addon) {
                 addon.uninstall();
                 marionetteScriptFinished(0);
               });
             """, script_args=[addon_id])
+
+    @classmethod
+    def is_signed(cls, path):
+        """Determine whether an addon path is signed or not.
+
+        :param path: The path to the addon. Can be a directory or an xpi.
+        :return: True if the addon is signed, otherwise False.
+        """
+        if os.path.isdir(path):
+            return False
+
+        assert path.endswith('.xpi')
+        with ZipFile(path, 'r') as zfile:
+            print('foobar')
+            print(zfile.namelist())
+        
--- a/testing/mochitest/mochitest_options.py
+++ b/testing/mochitest/mochitest_options.py
@@ -573,17 +573,17 @@ class MochitestArguments(ArgumentContain
           "suppress": True,
           }],
     ]
 
     defaults = {
         # Bug 1065098 - The geckomediaplugin process fails to produce a leak
         # log for some reason.
         'ignoreMissingLeaks': ["geckomediaplugin"],
-        'extensionsToExclude': ['specialpowers'],
+        'extensionsToExclude': [],
         # Set server information on the args object
         'webServer': '127.0.0.1',
         'httpPort': DEFAULT_PORTS['http'],
         'sslPort': DEFAULT_PORTS['https'],
         'webSocketPort': '9988',
         # The default websocket port is incorrect in mozprofile; it is
         # set to the SSL proxy setting. See:
         # see https://bugzilla.mozilla.org/show_bug.cgi?id=916517
@@ -925,18 +925,16 @@ class B2GArguments(ArgumentContainer):
           }],
     ]
 
     defaults = {
         'logFile': 'mochitest.log',
         # Specialpowers is integrated with marionette for b2g,
         # see marionette's jar.mn.
         'extensionsToExclude': ['specialpowers'],
-        # mochijar doesn't get installed via marionette on android
-        'extensionsToInstall': [os.path.join(here, 'mochijar')],
         # See dependencies of bug 1038943.
         'defaultLeakThreshold': 5536,
     }
 
     def validate(self, parser, options, context):
         """Validate b2g options."""
 
         if options.remoteWebServer is None:
@@ -1079,20 +1077,16 @@ class AndroidArguments(ArgumentContainer
           "help": "remote directory to use as test root \
                    (eg. /mnt/sdcard/tests or /data/local/tests)",
           "suppress": True,
           }],
     ]
 
     defaults = {
         'dm': None,
-        # we don't want to exclude specialpowers on android just yet
-        'extensionsToExclude': [],
-        # mochijar doesn't get installed via marionette on android
-        'extensionsToInstall': [os.path.join(here, 'mochijar')],
         'logFile': 'mochitest.log',
         'utilityPath': None,
     }
 
     def validate(self, parser, options, context):
         """Validate android options."""
 
         if build_obj:
--- a/testing/mochitest/runtests.py
+++ b/testing/mochitest/runtests.py
@@ -974,16 +974,17 @@ toolbar#nav-bar {
             if os.path.isdir(extensionDir):
                 for dirEntry in os.listdir(extensionDir):
                     if dirEntry not in options.extensionsToExclude:
                         path = os.path.join(extensionDir, dirEntry)
                         if os.path.isdir(path) or (
                                 os.path.isfile(path) and path.endswith(".xpi")):
                             extensions.append(path)
         extensions.extend(options.extensionsToInstall)
+        extensions.append(self.mochijar)
         return extensions
 
     def logPreamble(self, tests):
         """Logs a suite_start message and test_start/test_end at the beginning of a run.
         """
         self.log.suite_start([t['path'] for t in tests])
         for test in tests:
             if 'disabled' in test:
@@ -1611,18 +1612,20 @@ class MochitestDesktop(MochitestBase):
             "browser.tabs.remote.autostart=%s" %
             ('true' if options.e10s else 'false'))
         if options.strictContentSandbox:
             options.extraPrefs.append("security.sandbox.content.level=1")
         options.extraPrefs.append(
             "dom.ipc.tabs.nested.enabled=%s" %
             ('true' if options.nested_oop else 'false'))
 
-        # get extensions to install
-        extensions = self.getExtensionsToInstall(options)
+        extensions = None
+        if mozinfo.info.get('os').lower() == 'android':
+            # Android can't install addons via marionette yet
+            extensions = self.getExtensionsToInstall(options)
 
         # web apps
         appsPath = os.path.join(
             SCRIPT_DIR,
             'profile_data',
             'webapps_mochitest.json')
         if os.path.exists(appsPath):
             with open(appsPath) as apps_file:
@@ -1854,17 +1857,18 @@ class MochitestDesktop(MochitestBase):
                valgrindArgs=None,
                valgrindSuppFiles=None,
                symbolsPath=None,
                timeout=-1,
                detectShutdownLeaks=False,
                screenshotOnFail=False,
                bisectChunk=None,
                quiet=False,
-               marionette_args=None):
+               marionette_args=None,
+               extensions=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.
         """
 
         # configure the message logger buffering
         self.message_logger.buffering = quiet
 
@@ -1999,18 +2003,21 @@ class MochitestDesktop(MochitestBase):
             port_timeout = marionette_args.pop('port_timeout')
             self.marionette = Marionette(**marionette_args)
             self.marionette.start_session(timeout=port_timeout)
 
             # install specialpowers and mochikit as temporary addons
             addons = Addons(self.marionette)
 
             if mozinfo.info.get('toolkit') != 'gonk':
-                addons.install(os.path.join(here, 'extensions', 'specialpowers'), temp=True)
-                addons.install(self.mochijar, temp=True)
+                for ext in extensions:
+                    print(ext)
+                    # if an extension is signed, it doesn't need to be installed temporarily
+                    signed = addons.is_signed(ext)
+                    addons.install(ext, temp=not signed)
 
             self.execute_start_script()
 
             # an open marionette session interacts badly with mochitest,
             # delete it until we figure out why.
             self.marionette.delete_session()
             del self.marionette
 
@@ -2375,16 +2382,17 @@ class MochitestDesktop(MochitestBase):
                                      valgrindSuppFiles=valgrindSuppFiles,
                                      symbolsPath=options.symbolsPath,
                                      timeout=timeout,
                                      detectShutdownLeaks=detectShutdownLeaks,
                                      screenshotOnFail=options.screenshotOnFail,
                                      bisectChunk=options.bisectChunk,
                                      quiet=options.quiet,
                                      marionette_args=marionette_args,
+                                     extensions=self.getExtensionsToInstall(options),
                                      )
             except KeyboardInterrupt:
                 self.log.info("runtests.py | Received keyboard interrupt.\n")
                 status = -1
             except:
                 traceback.print_exc()
                 self.log.error(
                     "Automation Error: Received unexpected exception while running application\n")