Bug 1239330 - Support AddonManager.installTemporaryAddon() in marionette_driver.addons, r?ato
rename from testing/marionette/client/marionette/tests/unit/mn-restartless.xpi
rename to testing/marionette/client/marionette/tests/unit/mn-restartless-unsigned.xpi
--- a/testing/marionette/client/marionette/tests/unit/test_addons.py
+++ b/testing/marionette/client/marionette/tests/unit/test_addons.py
@@ -1,25 +1,25 @@
# 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
+import unittest
from marionette import MarionetteTestCase
from marionette_driver.addons import Addons, AddonInstallException
here = os.path.abspath(os.path.dirname(__file__))
class TestAddons(MarionetteTestCase):
def setUp(self):
MarionetteTestCase.setUp(self)
self.addons = Addons(self.marionette)
- self.addon_path = os.path.join(here, 'mn-restartless.xpi')
@property
def all_addon_ids(self):
with self.marionette.using_context('chrome'):
addons = self.marionette.execute_async_script("""
Components.utils.import("resource://gre/modules/AddonManager.jsm");
AddonManager.getAllAddons(function(addons){
@@ -27,24 +27,32 @@ class TestAddons(MarionetteTestCase):
return x.id;
});
marionetteScriptFinished(ids);
});
""")
return addons
- def test_install_and_remove_unsigned_addon(self):
- self.addons.signature_required = False
+ def test_install_and_remove_temporary_unsigned_addon(self):
+ addon_path = os.path.join(here, 'mn-restartless-unsigned.xpi')
- addon_id = self.addons.install(self.addon_path)
+ addon_id = self.addons.install(addon_path, temp=True)
self.assertIn(addon_id, self.all_addon_ids)
self.addons.uninstall(addon_id)
self.assertNotIn(addon_id, self.all_addon_ids)
- self.addons.signature_required = True
-
- def test_install_unsigned_addon_with_signature_required(self):
- self.signature_required = True
+ def test_install_unsigned_addon(self):
+ addon_path = os.path.join(here, 'mn-restartless-unsigned.xpi')
with self.assertRaises(AddonInstallException):
- self.addons.install(self.addon_path)
+ self.addons.install(addon_path)
+
+ @unittest.skip("need to get the test extension signed")
+ def test_install_and_remove_signed_addon(self):
+ addon_path = os.path.join(here, 'mn-restartless-signed.xpi')
+
+ addon_id = self.addons.install(addon_path)
+ self.assertIn(addon_id, self.all_addon_ids)
+
+ self.addons.uninstall(addon_id)
+ self.assertNotIn(addon_id, self.all_addon_ids)
--- a/testing/marionette/driver/marionette_driver/addons.py
+++ b/testing/marionette/driver/marionette_driver/addons.py
@@ -32,68 +32,65 @@ class Addons(object):
addons = Addons(marionette)
addons.install('path/to/extension.xpi')
.. _AddonManager API: https://developer.mozilla.org/en-US/Add-ons/Add-on_Manager
"""
def __init__(self, marionette):
self._mn = marionette
- self._signature_required = True
- def on_restart():
- self.signature_required = self._signature_required
- self._mn.restart_handlers.append(on_restart)
-
- @property
- def signature_required(self):
- """
- Whether or not addons must be signed.
- """
- return self._signature_required
-
- @signature_required.setter
- def signature_required(self, val):
- self._mn.set_pref('xpinstall.signatures.required', val)
- self._signature_required = val
-
- def install(self, path):
+ def install(self, path, temp=False):
"""Install an addon.
If the addon is restartless, it can be used right away. Otherwise
a restart using :func:`~marionette_driver.marionette.Marionette.restart`
will be needed.
: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`
"""
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]);
},
onInstallFailed: function(install) {
marionetteScriptFinished([null, install.error]);
+ },
+
+ onInstalled: function(addon) {
+ marionetteScriptFinished([addon.id, 0]);
}
}
let file = new FileUtils.File(arguments[0]);
- AddonManager.getInstallForFile(file, function(aInstall) {
- if (aInstall.error != 0) {
- marionetteScriptFinished([null, aInstall.error]);
- }
- aInstall.addListener(listener);
- aInstall.install();
- });
- """, script_args=[path], debug_script=True)
+ let temp = arguments[1];
+
+ if (!temp) {
+ AddonManager.getInstallForFile(file, function(aInstall) {
+ if (aInstall.error != 0) {
+ marionetteScriptFinished([null, aInstall.error]);
+ }
+ aInstall.addListener(listener);
+ aInstall.install();
+ });
+ } else {
+ AddonManager.addAddonListener(listener);
+ AddonManager.installTemporaryAddon(file);
+ }
+ """, script_args=[path, temp], debug_script=True)
if status:
if status in ADDON_INSTALL_ERRORS:
raise AddonInstallException(ADDON_INSTALL_ERRORS[status])
raise AddonInstallException("Addon failed to install with return code: %d" % status)
return addon_id
def uninstall(self, addon_id):
--- a/testing/marionette/driver/marionette_driver/marionette.py
+++ b/testing/marionette/driver/marionette_driver/marionette.py
@@ -559,17 +559,16 @@ class Marionette(object):
self.baseurl = baseurl
self.no_window = no_window
self._test_name = None
self.timeout = timeout
self.socket_timeout = socket_timeout
self.device_serial = device_serial
self.adb_host = adb_host
self.adb_port = adb_port
- self.restart_handlers = []
startup_timeout = startup_timeout or self.DEFAULT_STARTUP_TIMEOUT
if bin:
port = int(self.port)
if not Marionette.is_port_available(port, host=self.host):
ex_msg = "%s:%d is unavailable." % (self.host, port)
raise errors.MarionetteException(message=ex_msg)
@@ -1140,21 +1139,16 @@ class Marionette(object):
self.instance.detached = True
else:
self.delete_session()
self.instance.restart(clean=clean)
self.raise_for_port(self.wait_for_port())
self.start_session(session_id=self.session_id)
self._reset_timeouts()
- # Give consumers who depended on the old session a
- # chance to re-initialize and/or restore state.
- for handler in self.restart_handlers:
- handler()
-
def absolute_url(self, relative_url):
'''
Returns an absolute url for files served from Marionette's www directory.
:param relative_url: The url of a static file, relative to Marionette's www directory.
'''
return "%s%s" % (self.baseurl, relative_url)