| #!/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() |