diff options
Diffstat (limited to 'testing/mozbase/mozprofile/tests/test_addons.py')
-rw-r--r-- | testing/mozbase/mozprofile/tests/test_addons.py | 415 |
1 files changed, 415 insertions, 0 deletions
diff --git a/testing/mozbase/mozprofile/tests/test_addons.py b/testing/mozbase/mozprofile/tests/test_addons.py new file mode 100644 index 000000000..93b930fea --- /dev/null +++ b/testing/mozbase/mozprofile/tests/test_addons.py @@ -0,0 +1,415 @@ +#!/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() |