testing/mozbase/mozprofile/tests/test_addons.py

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/testing/mozbase/mozprofile/tests/test_addons.py	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,425 @@
     1.4 +#!/usr/bin/env python
     1.5 +
     1.6 +# This Source Code Form is subject to the terms of the Mozilla Public
     1.7 +# License, v. 2.0. If a copy of the MPL was not distributed with this file,
     1.8 +# You can obtain one at http://mozilla.org/MPL/2.0/.
     1.9 +
    1.10 +import os
    1.11 +import shutil
    1.12 +import tempfile
    1.13 +import unittest
    1.14 +import urllib2
    1.15 +
    1.16 +from manifestparser import ManifestParser
    1.17 +import mozfile
    1.18 +import mozhttpd
    1.19 +import mozlog
    1.20 +import mozprofile
    1.21 +
    1.22 +from addon_stubs import generate_addon, generate_manifest
    1.23 +
    1.24 +
    1.25 +here = os.path.dirname(os.path.abspath(__file__))
    1.26 +
    1.27 +
    1.28 +class TestAddonsManager(unittest.TestCase):
    1.29 +    """ Class to test mozprofile.addons.AddonManager """
    1.30 +
    1.31 +    def setUp(self):
    1.32 +        self.logger = mozlog.getLogger('mozprofile.addons')
    1.33 +        self.logger.setLevel(mozlog.ERROR)
    1.34 +
    1.35 +        self.profile = mozprofile.profile.Profile()
    1.36 +        self.am = self.profile.addon_manager
    1.37 +
    1.38 +        self.profile_path = self.profile.profile
    1.39 +        self.tmpdir = tempfile.mkdtemp()
    1.40 +
    1.41 +    def tearDown(self):
    1.42 +        mozfile.rmtree(self.tmpdir)
    1.43 +
    1.44 +        self.am = None
    1.45 +        self.profile = None
    1.46 +
    1.47 +        # Bug 934484
    1.48 +        # Sometimes the profile folder gets recreated at the end and will be left
    1.49 +        # behind. So we should ensure that we clean it up correctly.
    1.50 +        mozfile.rmtree(self.profile_path)
    1.51 +
    1.52 +    def test_install_addons_multiple_same_source(self):
    1.53 +        # Generate installer stubs for all possible types of addons
    1.54 +        addon_xpi = generate_addon('test-addon-1@mozilla.org',
    1.55 +                                   path=self.tmpdir)
    1.56 +        addon_folder = generate_addon('test-addon-1@mozilla.org',
    1.57 +                                      path=self.tmpdir,
    1.58 +                                      xpi=False)
    1.59 +
    1.60 +        # The same folder should not be installed twice
    1.61 +        self.am.install_addons([addon_folder, addon_folder])
    1.62 +        self.assertEqual(self.am.installed_addons, [addon_folder])
    1.63 +        self.am.clean()
    1.64 +
    1.65 +        # The same XPI file should not be installed twice
    1.66 +        self.am.install_addons([addon_xpi, addon_xpi])
    1.67 +        self.assertEqual(self.am.installed_addons, [addon_xpi])
    1.68 +        self.am.clean()
    1.69 +
    1.70 +        # Even if it is the same id the add-on should be installed twice, if
    1.71 +        # specified via XPI and folder
    1.72 +        self.am.install_addons([addon_folder, addon_xpi])
    1.73 +        self.assertEqual(len(self.am.installed_addons), 2)
    1.74 +        self.assertIn(addon_folder, self.am.installed_addons)
    1.75 +        self.assertIn(addon_xpi, self.am.installed_addons)
    1.76 +        self.am.clean()
    1.77 +
    1.78 +    def test_download(self):
    1.79 +        server = mozhttpd.MozHttpd(docroot=os.path.join(here, 'addons'))
    1.80 +        server.start()
    1.81 +
    1.82 +        # Download a valid add-on without a class instance to the general
    1.83 +        # tmp folder and clean-up
    1.84 +        try:
    1.85 +            addon = server.get_url() + 'empty.xpi'
    1.86 +            xpi_file = mozprofile.addons.AddonManager.download(addon)
    1.87 +            self.assertTrue(os.path.isfile(xpi_file))
    1.88 +            self.assertIn('test-empty@quality.mozilla.org.xpi',
    1.89 +                          os.path.basename(xpi_file))
    1.90 +            self.assertNotIn(self.tmpdir, os.path.dirname(xpi_file))
    1.91 +        finally:
    1.92 +            # Given that the file is stored outside of the created tmp dir
    1.93 +            # we have to ensure to explicitely remove it
    1.94 +            if os.path.isfile(xpi_file):
    1.95 +                os.remove(xpi_file)
    1.96 +
    1.97 +        # Download an valid add-on to a special folder
    1.98 +        addon = server.get_url() + 'empty.xpi'
    1.99 +        xpi_file = self.am.download(addon, self.tmpdir)
   1.100 +        self.assertTrue(os.path.isfile(xpi_file))
   1.101 +        self.assertIn('test-empty@quality.mozilla.org.xpi',
   1.102 +                      os.path.basename(xpi_file))
   1.103 +        self.assertIn(self.tmpdir, os.path.dirname(xpi_file))
   1.104 +        self.assertEqual(self.am.downloaded_addons, [])
   1.105 +        os.remove(xpi_file)
   1.106 +
   1.107 +        # Download an invalid add-on to a special folder
   1.108 +        addon = server.get_url() + 'invalid.xpi'
   1.109 +        self.assertRaises(mozprofile.addons.AddonFormatError,
   1.110 +                          self.am.download, addon, self.tmpdir)
   1.111 +        self.assertEqual(os.listdir(self.tmpdir), [])
   1.112 +
   1.113 +        # Download from an invalid URL
   1.114 +        addon = server.get_url() + 'not_existent.xpi'
   1.115 +        self.assertRaises(urllib2.HTTPError,
   1.116 +                          self.am.download, addon, self.tmpdir)
   1.117 +        self.assertEqual(os.listdir(self.tmpdir), [])
   1.118 +
   1.119 +        # Download from an invalid URL
   1.120 +        addon = 'not_existent.xpi'
   1.121 +        self.assertRaises(ValueError,
   1.122 +                          self.am.download, addon, self.tmpdir)
   1.123 +        self.assertEqual(os.listdir(self.tmpdir), [])
   1.124 +
   1.125 +        server.stop()
   1.126 +
   1.127 +    def test_install_from_path_xpi(self):
   1.128 +        addons_to_install = []
   1.129 +        addons_installed = []
   1.130 +
   1.131 +        # Generate installer stubs and install them
   1.132 +        for ext in ['test-addon-1@mozilla.org', 'test-addon-2@mozilla.org']:
   1.133 +            temp_addon = generate_addon(ext, path=self.tmpdir)
   1.134 +            addons_to_install.append(self.am.addon_details(temp_addon)['id'])
   1.135 +            self.am.install_from_path(temp_addon)
   1.136 +
   1.137 +        # Generate a list of addons installed in the profile
   1.138 +        addons_installed = [unicode(x[:-len('.xpi')]) for x in os.listdir(os.path.join(
   1.139 +                            self.profile.profile, 'extensions', 'staged'))]
   1.140 +        self.assertEqual(addons_to_install.sort(), addons_installed.sort())
   1.141 +
   1.142 +    def test_install_from_path_folder(self):
   1.143 +        # Generate installer stubs for all possible types of addons
   1.144 +        addons = []
   1.145 +        addons.append(generate_addon('test-addon-1@mozilla.org',
   1.146 +                                     path=self.tmpdir))
   1.147 +        addons.append(generate_addon('test-addon-2@mozilla.org',
   1.148 +                                     path=self.tmpdir,
   1.149 +                                     xpi=False))
   1.150 +        addons.append(generate_addon('test-addon-3@mozilla.org',
   1.151 +                                     path=self.tmpdir,
   1.152 +                                     name='addon-3'))
   1.153 +        addons.append(generate_addon('test-addon-4@mozilla.org',
   1.154 +                                     path=self.tmpdir,
   1.155 +                                     name='addon-4',
   1.156 +                                     xpi=False))
   1.157 +        addons.sort()
   1.158 +
   1.159 +        self.am.install_from_path(self.tmpdir)
   1.160 +
   1.161 +        self.assertEqual(self.am.installed_addons, addons)
   1.162 +
   1.163 +    def test_install_from_path_unpack(self):
   1.164 +        # Generate installer stubs for all possible types of addons
   1.165 +        addon_xpi = generate_addon('test-addon-unpack@mozilla.org',
   1.166 +                                   path=self.tmpdir)
   1.167 +        addon_folder = generate_addon('test-addon-unpack@mozilla.org',
   1.168 +                                      path=self.tmpdir,
   1.169 +                                      xpi=False)
   1.170 +        addon_no_unpack = generate_addon('test-addon-1@mozilla.org',
   1.171 +                                         path=self.tmpdir)
   1.172 +
   1.173 +        # Test unpack flag for add-on as XPI
   1.174 +        self.am.install_from_path(addon_xpi)
   1.175 +        self.assertEqual(self.am.installed_addons, [addon_xpi])
   1.176 +        self.am.clean()
   1.177 +
   1.178 +        # Test unpack flag for add-on as folder
   1.179 +        self.am.install_from_path(addon_folder)
   1.180 +        self.assertEqual(self.am.installed_addons, [addon_folder])
   1.181 +        self.am.clean()
   1.182 +
   1.183 +        # Test forcing unpack an add-on
   1.184 +        self.am.install_from_path(addon_no_unpack, unpack=True)
   1.185 +        self.assertEqual(self.am.installed_addons, [addon_no_unpack])
   1.186 +        self.am.clean()
   1.187 +
   1.188 +    def test_install_from_path_url(self):
   1.189 +        server = mozhttpd.MozHttpd(docroot=os.path.join(here, 'addons'))
   1.190 +        server.start()
   1.191 +
   1.192 +        addon = server.get_url() + 'empty.xpi'
   1.193 +        self.am.install_from_path(addon)
   1.194 +
   1.195 +        server.stop()
   1.196 +
   1.197 +        self.assertEqual(len(self.am.downloaded_addons), 1)
   1.198 +        self.assertTrue(os.path.isfile(self.am.downloaded_addons[0]))
   1.199 +        self.assertIn('test-empty@quality.mozilla.org.xpi',
   1.200 +                      os.path.basename(self.am.downloaded_addons[0]))
   1.201 +
   1.202 +    def test_install_from_path_after_reset(self):
   1.203 +        # Installing the same add-on after a reset should not cause a failure
   1.204 +        addon = generate_addon('test-addon-1@mozilla.org',
   1.205 +                               path=self.tmpdir, xpi=False)
   1.206 +
   1.207 +        # We cannot use self.am because profile.reset() creates a new instance
   1.208 +        self.profile.addon_manager.install_from_path(addon)
   1.209 +
   1.210 +        self.profile.reset()
   1.211 +
   1.212 +        self.profile.addon_manager.install_from_path(addon)
   1.213 +        self.assertEqual(self.profile.addon_manager.installed_addons, [addon])
   1.214 +
   1.215 +    def test_install_from_path_backup(self):
   1.216 +        staged_path = os.path.join(self.profile_path, 'extensions', 'staged')
   1.217 +
   1.218 +        # Generate installer stubs for all possible types of addons
   1.219 +        addon_xpi = generate_addon('test-addon-1@mozilla.org',
   1.220 +                                   path=self.tmpdir)
   1.221 +        addon_folder = generate_addon('test-addon-1@mozilla.org',
   1.222 +                                      path=self.tmpdir,
   1.223 +                                      xpi=False)
   1.224 +        addon_name = generate_addon('test-addon-1@mozilla.org',
   1.225 +                                    path=self.tmpdir,
   1.226 +                                    name='test-addon-1-dupe@mozilla.org')
   1.227 +
   1.228 +        # Test backup of xpi files
   1.229 +        self.am.install_from_path(addon_xpi)
   1.230 +        self.assertIsNone(self.am.backup_dir)
   1.231 +
   1.232 +        self.am.install_from_path(addon_xpi)
   1.233 +        self.assertIsNotNone(self.am.backup_dir)
   1.234 +        self.assertEqual(os.listdir(self.am.backup_dir),
   1.235 +                         ['test-addon-1@mozilla.org.xpi'])
   1.236 +
   1.237 +        self.am.clean()
   1.238 +        self.assertEqual(os.listdir(staged_path),
   1.239 +                         ['test-addon-1@mozilla.org.xpi'])
   1.240 +        self.am.clean()
   1.241 +
   1.242 +        # Test backup of folders
   1.243 +        self.am.install_from_path(addon_folder)
   1.244 +        self.assertIsNone(self.am.backup_dir)
   1.245 +
   1.246 +        self.am.install_from_path(addon_folder)
   1.247 +        self.assertIsNotNone(self.am.backup_dir)
   1.248 +        self.assertEqual(os.listdir(self.am.backup_dir),
   1.249 +                         ['test-addon-1@mozilla.org'])
   1.250 +
   1.251 +        self.am.clean()
   1.252 +        self.assertEqual(os.listdir(staged_path),
   1.253 +                         ['test-addon-1@mozilla.org'])
   1.254 +        self.am.clean()
   1.255 +
   1.256 +        # Test backup of xpi files with another file name
   1.257 +        self.am.install_from_path(addon_name)
   1.258 +        self.assertIsNone(self.am.backup_dir)
   1.259 +
   1.260 +        self.am.install_from_path(addon_xpi)
   1.261 +        self.assertIsNotNone(self.am.backup_dir)
   1.262 +        self.assertEqual(os.listdir(self.am.backup_dir),
   1.263 +                         ['test-addon-1@mozilla.org.xpi'])
   1.264 +
   1.265 +        self.am.clean()
   1.266 +        self.assertEqual(os.listdir(staged_path),
   1.267 +                         ['test-addon-1@mozilla.org.xpi'])
   1.268 +        self.am.clean()
   1.269 +
   1.270 +    def test_install_from_path_invalid_addons(self):
   1.271 +        # Generate installer stubs for all possible types of addons
   1.272 +        addons = []
   1.273 +        addons.append(generate_addon('test-addon-invalid-no-manifest@mozilla.org',
   1.274 +                      path=self.tmpdir,
   1.275 +                      xpi=False))
   1.276 +        addons.append(generate_addon('test-addon-invalid-no-id@mozilla.org',
   1.277 +                      path=self.tmpdir))
   1.278 +
   1.279 +        self.am.install_from_path(self.tmpdir)
   1.280 +
   1.281 +        self.assertEqual(self.am.installed_addons, [])
   1.282 +
   1.283 +    @unittest.skip("Feature not implemented as part of AddonManger")
   1.284 +    def test_install_from_path_error(self):
   1.285 +        """ Check install_from_path raises an error with an invalid addon"""
   1.286 +
   1.287 +        temp_addon = generate_addon('test-addon-invalid-version@mozilla.org')
   1.288 +        # This should raise an error here
   1.289 +        self.am.install_from_path(temp_addon)
   1.290 +
   1.291 +    def test_install_from_manifest(self):
   1.292 +        temp_manifest = generate_manifest(['test-addon-1@mozilla.org',
   1.293 +                                           'test-addon-2@mozilla.org'])
   1.294 +        m = ManifestParser()
   1.295 +        m.read(temp_manifest)
   1.296 +        addons = m.get()
   1.297 +
   1.298 +        # Obtain details of addons to install from the manifest
   1.299 +        addons_to_install = [self.am.addon_details(x['path']).get('id') for x in addons]
   1.300 +
   1.301 +        self.am.install_from_manifest(temp_manifest)
   1.302 +        # Generate a list of addons installed in the profile
   1.303 +        addons_installed = [unicode(x[:-len('.xpi')]) for x in os.listdir(os.path.join(
   1.304 +                            self.profile.profile, 'extensions', 'staged'))]
   1.305 +        self.assertEqual(addons_installed.sort(), addons_to_install.sort())
   1.306 +
   1.307 +        # Cleanup the temporary addon and manifest directories
   1.308 +        mozfile.rmtree(os.path.dirname(temp_manifest))
   1.309 +
   1.310 +    def test_addon_details(self):
   1.311 +        # Generate installer stubs for a valid and invalid add-on manifest
   1.312 +        valid_addon = generate_addon('test-addon-1@mozilla.org',
   1.313 +                                     path=self.tmpdir)
   1.314 +        invalid_addon = generate_addon('test-addon-invalid-not-wellformed@mozilla.org',
   1.315 +                                       path=self.tmpdir)
   1.316 +
   1.317 +        # Check valid add-on
   1.318 +        details = self.am.addon_details(valid_addon)
   1.319 +        self.assertEqual(details['id'], 'test-addon-1@mozilla.org')
   1.320 +        self.assertEqual(details['name'], 'Test Add-on 1')
   1.321 +        self.assertEqual(details['unpack'], False)
   1.322 +        self.assertEqual(details['version'], '0.1')
   1.323 +
   1.324 +        # Check invalid add-on
   1.325 +        self.assertRaises(mozprofile.addons.AddonFormatError,
   1.326 +                          self.am.addon_details, invalid_addon)
   1.327 +
   1.328 +        # Check invalid path
   1.329 +        self.assertRaises(IOError,
   1.330 +                          self.am.addon_details, '')
   1.331 +
   1.332 +        # Check invalid add-on format
   1.333 +        addon_path = os.path.join(os.path.join(here, 'files'), 'not_an_addon.txt')
   1.334 +        self.assertRaises(mozprofile.addons.AddonFormatError,
   1.335 +                          self.am.addon_details, addon_path)
   1.336 +
   1.337 +    @unittest.skip("Bug 900154")
   1.338 +    def test_clean_addons(self):
   1.339 +        addon_one = generate_addon('test-addon-1@mozilla.org')
   1.340 +        addon_two = generate_addon('test-addon-2@mozilla.org')
   1.341 +
   1.342 +        self.am.install_addons(addon_one)
   1.343 +        installed_addons = [unicode(x[:-len('.xpi')]) for x in os.listdir(os.path.join(
   1.344 +                            self.profile.profile, 'extensions', 'staged'))]
   1.345 +
   1.346 +        # Create a new profile based on an existing profile
   1.347 +        # Install an extra addon in the new profile
   1.348 +        # Cleanup addons
   1.349 +        duplicate_profile = mozprofile.profile.Profile(profile=self.profile.profile,
   1.350 +                                                       addons=addon_two)
   1.351 +        duplicate_profile.addon_manager.clean()
   1.352 +
   1.353 +        addons_after_cleanup = [unicode(x[:-len('.xpi')]) for x in os.listdir(os.path.join(
   1.354 +                                duplicate_profile.profile, 'extensions', 'staged'))]
   1.355 +        # New addons installed should be removed by clean_addons()
   1.356 +        self.assertEqual(installed_addons, addons_after_cleanup)
   1.357 +
   1.358 +    def test_noclean(self):
   1.359 +        """test `restore=True/False` functionality"""
   1.360 +
   1.361 +        server = mozhttpd.MozHttpd(docroot=os.path.join(here, 'addons'))
   1.362 +        server.start()
   1.363 +
   1.364 +        profile = tempfile.mkdtemp()
   1.365 +        tmpdir = tempfile.mkdtemp()
   1.366 +
   1.367 +        try:
   1.368 +            # empty initially
   1.369 +            self.assertFalse(bool(os.listdir(profile)))
   1.370 +
   1.371 +            # make an addon
   1.372 +            addons = []
   1.373 +            addons.append(generate_addon('test-addon-1@mozilla.org',
   1.374 +                                         path=tmpdir))
   1.375 +            addons.append(server.get_url() + 'empty.xpi')
   1.376 +
   1.377 +            # install it with a restore=True AddonManager
   1.378 +            am = mozprofile.addons.AddonManager(profile, restore=True)
   1.379 +
   1.380 +            for addon in addons:
   1.381 +                am.install_from_path(addon)
   1.382 +
   1.383 +            # now its there
   1.384 +            self.assertEqual(os.listdir(profile), ['extensions'])
   1.385 +            staging_folder = os.path.join(profile, 'extensions', 'staged')
   1.386 +            self.assertTrue(os.path.exists(staging_folder))
   1.387 +            self.assertEqual(len(os.listdir(staging_folder)), 2)
   1.388 +
   1.389 +            # del addons; now its gone though the directory tree exists
   1.390 +            downloaded_addons = am.downloaded_addons
   1.391 +            del am
   1.392 +
   1.393 +            self.assertEqual(os.listdir(profile), ['extensions'])
   1.394 +            self.assertTrue(os.path.exists(staging_folder))
   1.395 +            self.assertEqual(os.listdir(staging_folder), [])
   1.396 +
   1.397 +            for addon in downloaded_addons:
   1.398 +                self.assertFalse(os.path.isfile(addon))
   1.399 +
   1.400 +        finally:
   1.401 +            mozfile.rmtree(tmpdir)
   1.402 +            mozfile.rmtree(profile)
   1.403 +
   1.404 +    def test_remove_addon(self):
   1.405 +        addons = []
   1.406 +        addons.append(generate_addon('test-addon-1@mozilla.org',
   1.407 +                                     path=self.tmpdir))
   1.408 +        addons.append(generate_addon('test-addon-2@mozilla.org',
   1.409 +                                     path=self.tmpdir))
   1.410 +
   1.411 +        self.am.install_from_path(self.tmpdir)
   1.412 +
   1.413 +        extensions_path = os.path.join(self.profile_path, 'extensions')
   1.414 +        staging_path = os.path.join(extensions_path, 'staged')
   1.415 +
   1.416 +        # Fake a run by virtually installing one of the staged add-ons
   1.417 +        shutil.move(os.path.join(staging_path, 'test-addon-1@mozilla.org.xpi'),
   1.418 +                    extensions_path)
   1.419 +
   1.420 +        for addon in self.am._addons:
   1.421 +            self.am.remove_addon(addon)
   1.422 +
   1.423 +        self.assertEqual(os.listdir(staging_path), [])
   1.424 +        self.assertEqual(os.listdir(extensions_path), ['staged'])
   1.425 +
   1.426 +
   1.427 +if __name__ == '__main__':
   1.428 +    unittest.main()

mercurial