416 lines
17 KiB
Python
416 lines
17 KiB
Python
#!/usr/bin/env python
|
|
|
|
# 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 shutil
|
|
import tempfile
|
|
import unittest
|
|
import urllib2
|
|
|
|
from manifestparser import ManifestParser
|
|
import mozfile
|
|
import mozhttpd
|
|
import mozlog.unstructured as mozlog
|
|
import mozprofile
|
|
|
|
from addon_stubs import generate_addon, generate_manifest
|
|
|
|
|
|
here = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
|
|
class TestAddonsManager(unittest.TestCase):
|
|
""" Class to test mozprofile.addons.AddonManager """
|
|
|
|
def setUp(self):
|
|
self.logger = mozlog.getLogger('mozprofile.addons')
|
|
self.logger.setLevel(mozlog.ERROR)
|
|
|
|
self.profile = mozprofile.profile.Profile()
|
|
self.am = self.profile.addon_manager
|
|
|
|
self.profile_path = self.profile.profile
|
|
self.tmpdir = tempfile.mkdtemp()
|
|
self.addCleanup(mozfile.remove, self.tmpdir)
|
|
|
|
def test_install_addons_multiple_same_source(self):
|
|
# Generate installer stubs for all possible types of addons
|
|
addon_xpi = generate_addon('test-addon-1@mozilla.org',
|
|
path=self.tmpdir)
|
|
addon_folder = generate_addon('test-addon-1@mozilla.org',
|
|
path=self.tmpdir,
|
|
xpi=False)
|
|
|
|
# The same folder should not be installed twice
|
|
self.am.install_addons([addon_folder, addon_folder])
|
|
self.assertEqual(self.am.installed_addons, [addon_folder])
|
|
self.am.clean()
|
|
|
|
# The same XPI file should not be installed twice
|
|
self.am.install_addons([addon_xpi, addon_xpi])
|
|
self.assertEqual(self.am.installed_addons, [addon_xpi])
|
|
self.am.clean()
|
|
|
|
# Even if it is the same id the add-on should be installed twice, if
|
|
# specified via XPI and folder
|
|
self.am.install_addons([addon_folder, addon_xpi])
|
|
self.assertEqual(len(self.am.installed_addons), 2)
|
|
self.assertIn(addon_folder, self.am.installed_addons)
|
|
self.assertIn(addon_xpi, self.am.installed_addons)
|
|
self.am.clean()
|
|
|
|
def test_download(self):
|
|
server = mozhttpd.MozHttpd(docroot=os.path.join(here, 'addons'))
|
|
server.start()
|
|
|
|
# Download a valid add-on without a class instance to the general
|
|
# tmp folder and clean-up
|
|
try:
|
|
addon = server.get_url() + 'empty.xpi'
|
|
xpi_file = mozprofile.addons.AddonManager.download(addon)
|
|
self.assertTrue(os.path.isfile(xpi_file))
|
|
self.assertIn('test-empty@quality.mozilla.org.xpi',
|
|
os.path.basename(xpi_file))
|
|
self.assertNotIn(self.tmpdir, os.path.dirname(xpi_file))
|
|
finally:
|
|
# Given that the file is stored outside of the created tmp dir
|
|
# we have to ensure to explicitely remove it
|
|
if os.path.isfile(xpi_file):
|
|
os.remove(xpi_file)
|
|
|
|
# Download an valid add-on to a special folder
|
|
addon = server.get_url() + 'empty.xpi'
|
|
xpi_file = self.am.download(addon, self.tmpdir)
|
|
self.assertTrue(os.path.isfile(xpi_file))
|
|
self.assertIn('test-empty@quality.mozilla.org.xpi',
|
|
os.path.basename(xpi_file))
|
|
self.assertIn(self.tmpdir, os.path.dirname(xpi_file))
|
|
self.assertEqual(self.am.downloaded_addons, [])
|
|
os.remove(xpi_file)
|
|
|
|
# Download an invalid add-on to a special folder
|
|
addon = server.get_url() + 'invalid.xpi'
|
|
self.assertRaises(mozprofile.addons.AddonFormatError,
|
|
self.am.download, addon, self.tmpdir)
|
|
self.assertEqual(os.listdir(self.tmpdir), [])
|
|
|
|
# Download from an invalid URL
|
|
addon = server.get_url() + 'not_existent.xpi'
|
|
self.assertRaises(urllib2.HTTPError,
|
|
self.am.download, addon, self.tmpdir)
|
|
self.assertEqual(os.listdir(self.tmpdir), [])
|
|
|
|
# Download from an invalid URL
|
|
addon = 'not_existent.xpi'
|
|
self.assertRaises(ValueError,
|
|
self.am.download, addon, self.tmpdir)
|
|
self.assertEqual(os.listdir(self.tmpdir), [])
|
|
|
|
server.stop()
|
|
|
|
def test_install_from_path_xpi(self):
|
|
addons_to_install = []
|
|
addons_installed = []
|
|
|
|
# Generate installer stubs and install them
|
|
for ext in ['test-addon-1@mozilla.org', 'test-addon-2@mozilla.org']:
|
|
temp_addon = generate_addon(ext, path=self.tmpdir)
|
|
addons_to_install.append(self.am.addon_details(temp_addon)['id'])
|
|
self.am.install_from_path(temp_addon)
|
|
|
|
# Generate a list of addons installed in the profile
|
|
addons_installed = [unicode(x[:-len('.xpi')]) for x in os.listdir(os.path.join(
|
|
self.profile.profile, 'extensions', 'staged'))]
|
|
self.assertEqual(addons_to_install.sort(), addons_installed.sort())
|
|
|
|
def test_install_from_path_folder(self):
|
|
# Generate installer stubs for all possible types of addons
|
|
addons = []
|
|
addons.append(generate_addon('test-addon-1@mozilla.org',
|
|
path=self.tmpdir))
|
|
addons.append(generate_addon('test-addon-2@mozilla.org',
|
|
path=self.tmpdir,
|
|
xpi=False))
|
|
addons.append(generate_addon('test-addon-3@mozilla.org',
|
|
path=self.tmpdir,
|
|
name='addon-3'))
|
|
addons.append(generate_addon('test-addon-4@mozilla.org',
|
|
path=self.tmpdir,
|
|
name='addon-4',
|
|
xpi=False))
|
|
addons.sort()
|
|
|
|
self.am.install_from_path(self.tmpdir)
|
|
|
|
self.assertEqual(self.am.installed_addons, addons)
|
|
|
|
def test_install_from_path_unpack(self):
|
|
# Generate installer stubs for all possible types of addons
|
|
addon_xpi = generate_addon('test-addon-unpack@mozilla.org',
|
|
path=self.tmpdir)
|
|
addon_folder = generate_addon('test-addon-unpack@mozilla.org',
|
|
path=self.tmpdir,
|
|
xpi=False)
|
|
addon_no_unpack = generate_addon('test-addon-1@mozilla.org',
|
|
path=self.tmpdir)
|
|
|
|
# Test unpack flag for add-on as XPI
|
|
self.am.install_from_path(addon_xpi)
|
|
self.assertEqual(self.am.installed_addons, [addon_xpi])
|
|
self.am.clean()
|
|
|
|
# Test unpack flag for add-on as folder
|
|
self.am.install_from_path(addon_folder)
|
|
self.assertEqual(self.am.installed_addons, [addon_folder])
|
|
self.am.clean()
|
|
|
|
# Test forcing unpack an add-on
|
|
self.am.install_from_path(addon_no_unpack, unpack=True)
|
|
self.assertEqual(self.am.installed_addons, [addon_no_unpack])
|
|
self.am.clean()
|
|
|
|
def test_install_from_path_url(self):
|
|
server = mozhttpd.MozHttpd(docroot=os.path.join(here, 'addons'))
|
|
server.start()
|
|
|
|
addon = server.get_url() + 'empty.xpi'
|
|
self.am.install_from_path(addon)
|
|
|
|
server.stop()
|
|
|
|
self.assertEqual(len(self.am.downloaded_addons), 1)
|
|
self.assertTrue(os.path.isfile(self.am.downloaded_addons[0]))
|
|
self.assertIn('test-empty@quality.mozilla.org.xpi',
|
|
os.path.basename(self.am.downloaded_addons[0]))
|
|
|
|
def test_install_from_path_after_reset(self):
|
|
# Installing the same add-on after a reset should not cause a failure
|
|
addon = generate_addon('test-addon-1@mozilla.org',
|
|
path=self.tmpdir, xpi=False)
|
|
|
|
# We cannot use self.am because profile.reset() creates a new instance
|
|
self.profile.addon_manager.install_from_path(addon)
|
|
|
|
self.profile.reset()
|
|
|
|
self.profile.addon_manager.install_from_path(addon)
|
|
self.assertEqual(self.profile.addon_manager.installed_addons, [addon])
|
|
|
|
def test_install_from_path_backup(self):
|
|
staged_path = os.path.join(self.profile_path, 'extensions', 'staged')
|
|
|
|
# Generate installer stubs for all possible types of addons
|
|
addon_xpi = generate_addon('test-addon-1@mozilla.org',
|
|
path=self.tmpdir)
|
|
addon_folder = generate_addon('test-addon-1@mozilla.org',
|
|
path=self.tmpdir,
|
|
xpi=False)
|
|
addon_name = generate_addon('test-addon-1@mozilla.org',
|
|
path=self.tmpdir,
|
|
name='test-addon-1-dupe@mozilla.org')
|
|
|
|
# Test backup of xpi files
|
|
self.am.install_from_path(addon_xpi)
|
|
self.assertIsNone(self.am.backup_dir)
|
|
|
|
self.am.install_from_path(addon_xpi)
|
|
self.assertIsNotNone(self.am.backup_dir)
|
|
self.assertEqual(os.listdir(self.am.backup_dir),
|
|
['test-addon-1@mozilla.org.xpi'])
|
|
|
|
self.am.clean()
|
|
self.assertEqual(os.listdir(staged_path),
|
|
['test-addon-1@mozilla.org.xpi'])
|
|
self.am.clean()
|
|
|
|
# Test backup of folders
|
|
self.am.install_from_path(addon_folder)
|
|
self.assertIsNone(self.am.backup_dir)
|
|
|
|
self.am.install_from_path(addon_folder)
|
|
self.assertIsNotNone(self.am.backup_dir)
|
|
self.assertEqual(os.listdir(self.am.backup_dir),
|
|
['test-addon-1@mozilla.org'])
|
|
|
|
self.am.clean()
|
|
self.assertEqual(os.listdir(staged_path),
|
|
['test-addon-1@mozilla.org'])
|
|
self.am.clean()
|
|
|
|
# Test backup of xpi files with another file name
|
|
self.am.install_from_path(addon_name)
|
|
self.assertIsNone(self.am.backup_dir)
|
|
|
|
self.am.install_from_path(addon_xpi)
|
|
self.assertIsNotNone(self.am.backup_dir)
|
|
self.assertEqual(os.listdir(self.am.backup_dir),
|
|
['test-addon-1@mozilla.org.xpi'])
|
|
|
|
self.am.clean()
|
|
self.assertEqual(os.listdir(staged_path),
|
|
['test-addon-1@mozilla.org.xpi'])
|
|
self.am.clean()
|
|
|
|
def test_install_from_path_invalid_addons(self):
|
|
# Generate installer stubs for all possible types of addons
|
|
addons = []
|
|
addons.append(generate_addon('test-addon-invalid-no-manifest@mozilla.org',
|
|
path=self.tmpdir,
|
|
xpi=False))
|
|
addons.append(generate_addon('test-addon-invalid-no-id@mozilla.org',
|
|
path=self.tmpdir))
|
|
|
|
self.am.install_from_path(self.tmpdir)
|
|
|
|
self.assertEqual(self.am.installed_addons, [])
|
|
|
|
@unittest.skip("Feature not implemented as part of AddonManger")
|
|
def test_install_from_path_error(self):
|
|
""" Check install_from_path raises an error with an invalid addon"""
|
|
|
|
temp_addon = generate_addon('test-addon-invalid-version@mozilla.org')
|
|
# This should raise an error here
|
|
self.am.install_from_path(temp_addon)
|
|
|
|
def test_install_from_manifest(self):
|
|
temp_manifest = generate_manifest(['test-addon-1@mozilla.org',
|
|
'test-addon-2@mozilla.org'])
|
|
m = ManifestParser()
|
|
m.read(temp_manifest)
|
|
addons = m.get()
|
|
|
|
# Obtain details of addons to install from the manifest
|
|
addons_to_install = [self.am.addon_details(x['path']).get('id') for x in addons]
|
|
|
|
self.am.install_from_manifest(temp_manifest)
|
|
# Generate a list of addons installed in the profile
|
|
addons_installed = [unicode(x[:-len('.xpi')]) for x in os.listdir(os.path.join(
|
|
self.profile.profile, 'extensions', 'staged'))]
|
|
self.assertEqual(addons_installed.sort(), addons_to_install.sort())
|
|
|
|
# Cleanup the temporary addon and manifest directories
|
|
mozfile.rmtree(os.path.dirname(temp_manifest))
|
|
|
|
def test_addon_details(self):
|
|
# Generate installer stubs for a valid and invalid add-on manifest
|
|
valid_addon = generate_addon('test-addon-1@mozilla.org',
|
|
path=self.tmpdir)
|
|
invalid_addon = generate_addon('test-addon-invalid-not-wellformed@mozilla.org',
|
|
path=self.tmpdir)
|
|
|
|
# Check valid add-on
|
|
details = self.am.addon_details(valid_addon)
|
|
self.assertEqual(details['id'], 'test-addon-1@mozilla.org')
|
|
self.assertEqual(details['name'], 'Test Add-on 1')
|
|
self.assertEqual(details['unpack'], False)
|
|
self.assertEqual(details['version'], '0.1')
|
|
|
|
# Check invalid add-on
|
|
self.assertRaises(mozprofile.addons.AddonFormatError,
|
|
self.am.addon_details, invalid_addon)
|
|
|
|
# Check invalid path
|
|
self.assertRaises(IOError,
|
|
self.am.addon_details, '')
|
|
|
|
# Check invalid add-on format
|
|
addon_path = os.path.join(os.path.join(here, 'files'), 'not_an_addon.txt')
|
|
self.assertRaises(mozprofile.addons.AddonFormatError,
|
|
self.am.addon_details, addon_path)
|
|
|
|
@unittest.skip("Bug 900154")
|
|
def test_clean_addons(self):
|
|
addon_one = generate_addon('test-addon-1@mozilla.org')
|
|
addon_two = generate_addon('test-addon-2@mozilla.org')
|
|
|
|
self.am.install_addons(addon_one)
|
|
installed_addons = [unicode(x[:-len('.xpi')]) for x in os.listdir(os.path.join(
|
|
self.profile.profile, 'extensions', 'staged'))]
|
|
|
|
# Create a new profile based on an existing profile
|
|
# Install an extra addon in the new profile
|
|
# Cleanup addons
|
|
duplicate_profile = mozprofile.profile.Profile(profile=self.profile.profile,
|
|
addons=addon_two)
|
|
duplicate_profile.addon_manager.clean()
|
|
|
|
addons_after_cleanup = [unicode(x[:-len('.xpi')]) for x in os.listdir(os.path.join(
|
|
duplicate_profile.profile, 'extensions', 'staged'))]
|
|
# New addons installed should be removed by clean_addons()
|
|
self.assertEqual(installed_addons, addons_after_cleanup)
|
|
|
|
def test_noclean(self):
|
|
"""test `restore=True/False` functionality"""
|
|
|
|
server = mozhttpd.MozHttpd(docroot=os.path.join(here, 'addons'))
|
|
server.start()
|
|
|
|
profile = tempfile.mkdtemp()
|
|
tmpdir = tempfile.mkdtemp()
|
|
|
|
try:
|
|
# empty initially
|
|
self.assertFalse(bool(os.listdir(profile)))
|
|
|
|
# make an addon
|
|
addons = []
|
|
addons.append(generate_addon('test-addon-1@mozilla.org',
|
|
path=tmpdir))
|
|
addons.append(server.get_url() + 'empty.xpi')
|
|
|
|
# install it with a restore=True AddonManager
|
|
am = mozprofile.addons.AddonManager(profile, restore=True)
|
|
|
|
for addon in addons:
|
|
am.install_from_path(addon)
|
|
|
|
# now its there
|
|
self.assertEqual(os.listdir(profile), ['extensions'])
|
|
staging_folder = os.path.join(profile, 'extensions', 'staged')
|
|
self.assertTrue(os.path.exists(staging_folder))
|
|
self.assertEqual(len(os.listdir(staging_folder)), 2)
|
|
|
|
# del addons; now its gone though the directory tree exists
|
|
downloaded_addons = am.downloaded_addons
|
|
del am
|
|
|
|
self.assertEqual(os.listdir(profile), ['extensions'])
|
|
self.assertTrue(os.path.exists(staging_folder))
|
|
self.assertEqual(os.listdir(staging_folder), [])
|
|
|
|
for addon in downloaded_addons:
|
|
self.assertFalse(os.path.isfile(addon))
|
|
|
|
finally:
|
|
mozfile.rmtree(tmpdir)
|
|
mozfile.rmtree(profile)
|
|
|
|
def test_remove_addon(self):
|
|
addons = []
|
|
addons.append(generate_addon('test-addon-1@mozilla.org',
|
|
path=self.tmpdir))
|
|
addons.append(generate_addon('test-addon-2@mozilla.org',
|
|
path=self.tmpdir))
|
|
|
|
self.am.install_from_path(self.tmpdir)
|
|
|
|
extensions_path = os.path.join(self.profile_path, 'extensions')
|
|
staging_path = os.path.join(extensions_path, 'staged')
|
|
|
|
# Fake a run by virtually installing one of the staged add-ons
|
|
shutil.move(os.path.join(staging_path, 'test-addon-1@mozilla.org.xpi'),
|
|
extensions_path)
|
|
|
|
for addon in self.am._addons:
|
|
self.am.remove_addon(addon)
|
|
|
|
self.assertEqual(os.listdir(staging_path), [])
|
|
self.assertEqual(os.listdir(extensions_path), ['staged'])
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|