diff options
Diffstat (limited to 'testing/mozbase/mozprofile/tests')
30 files changed, 2233 insertions, 0 deletions
diff --git a/testing/mozbase/mozprofile/tests/addon_stubs.py b/testing/mozbase/mozprofile/tests/addon_stubs.py new file mode 100644 index 0000000000..f9602de462 --- /dev/null +++ b/testing/mozbase/mozprofile/tests/addon_stubs.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python + +import os +import tempfile +import zipfile + +import mozfile + + +here = os.path.dirname(os.path.abspath(__file__)) + +# stubs is a dict of the form {'addon id': 'install manifest content'} +stubs = { + 'test-addon-1@mozilla.org': 'test_addon_1.rdf', + 'test-addon-2@mozilla.org': 'test_addon_2.rdf', + 'test-addon-3@mozilla.org': 'test_addon_3.rdf', + 'test-addon-4@mozilla.org': 'test_addon_4.rdf', + 'test-addon-invalid-no-id@mozilla.org': 'test_addon_invalid_no_id.rdf', + 'test-addon-invalid-version@mozilla.org': 'test_addon_invalid_version.rdf', + 'test-addon-invalid-no-manifest@mozilla.org': None, + 'test-addon-invalid-not-wellformed@mozilla.org': 'test_addon_invalid_not_wellformed.rdf', + 'test-addon-unpack@mozilla.org': 'test_addon_unpack.rdf'} + + +def generate_addon(addon_id, path=None, name=None, xpi=True): + """ + Method to generate a single addon. + + :param addon_id: id of an addon to generate from the stubs dictionary + :param path: path where addon and .xpi should be generated + :param name: name for the addon folder or .xpi file + :param xpi: Flag if an XPI or folder should be generated + + Returns the file-path of the addon's .xpi file + """ + + if addon_id not in stubs.keys(): + raise IOError('Requested addon stub "%s" does not exist' % addon_id) + + # Generate directory structure for addon + try: + tmpdir = path or tempfile.mkdtemp() + addon_dir = os.path.join(tmpdir, name or addon_id) + os.mkdir(addon_dir) + except IOError: + raise IOError('Could not generate directory structure for addon stub.') + + # Write install.rdf for addon + if stubs[addon_id]: + install_rdf = os.path.join(addon_dir, 'install.rdf') + with open(install_rdf, 'w') as f: + manifest = os.path.join(here, 'install_manifests', stubs[addon_id]) + f.write(open(manifest, 'r').read()) + + if not xpi: + return addon_dir + + # Generate the .xpi for the addon + xpi_file = os.path.join(tmpdir, (name or addon_id) + '.xpi') + with zipfile.ZipFile(xpi_file, 'w') as x: + x.write(install_rdf, install_rdf[len(addon_dir):]) + + # Ensure we remove the temporary folder to not install the addon twice + mozfile.rmtree(addon_dir) + + return xpi_file + + +def generate_manifest(addon_list, path=None): + tmpdir = path or tempfile.mkdtemp() + addons = [generate_addon(addon, path=tmpdir) for addon in addon_list] + + manifest = os.path.join(tmpdir, 'manifest.ini') + with open(manifest, 'w') as f: + for addon in addons: + f.write('[' + addon + ']\n') + + return manifest diff --git a/testing/mozbase/mozprofile/tests/addonid.py b/testing/mozbase/mozprofile/tests/addonid.py new file mode 100755 index 0000000000..f76c5a913c --- /dev/null +++ b/testing/mozbase/mozprofile/tests/addonid.py @@ -0,0 +1,184 @@ +#!/usr/bin/env python + +import os +import tempfile +import unittest +import shutil +from mozprofile import addons + + +here = os.path.dirname(os.path.abspath(__file__)) + + +class AddonIDTest(unittest.TestCase): + """ Test finding the addon id in a variety of install.rdf styles """ + + def make_install_rdf(self, filecontents): + path = tempfile.mkdtemp() + f = open(os.path.join(path, "install.rdf"), "w") + f.write(filecontents) + f.close() + return path + + def test_addonID(self): + testlist = self.get_test_list() + for t in testlist: + try: + p = self.make_install_rdf(t) + a = addons.AddonManager(os.path.join(p, "profile")) + addon_id = a.addon_details(p)['id'] + self.assertEqual(addon_id, "winning", "We got the addon id") + finally: + shutil.rmtree(p) + + def test_addonID_xpi(self): + a = addons.AddonManager("profile") + addon = a.addon_details(os.path.join(here, "addons", "empty.xpi")) + self.assertEqual(addon['id'], "test-empty@quality.mozilla.org", "We got the addon id") + + def get_test_list(self): + """ This just returns a hardcoded list of install.rdf snippets for testing. + When adding snippets for testing, remember that the id we're looking for + is "winning" (no quotes). So, make sure you have that id in your snippet + if you want it to pass. + """ + tests = [ + """<?xml version="1.0"?> +<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:em="http://www.mozilla.org/2004/em-rdf#"> + <Description about="urn:mozilla:install-manifest"> + <em:id>winning</em:id> + <em:name>MozMill</em:name> + <em:version>2.0a</em:version> + <em:creator>Adam Christian</em:creator> + <em:description>A testing extension based on the + Windmill Testing Framework client source</em:description> + <em:unpack>true</em:unpack> + <em:targetApplication> + <!-- Firefox --> + <Description> + <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> + <em:minVersion>3.5</em:minVersion> + <em:maxVersion>8.*</em:maxVersion> + </Description> + </em:targetApplication> + <em:targetApplication> + <!-- Thunderbird --> + <Description> + <em:id>{3550f703-e582-4d05-9a08-453d09bdfdc6}</em:id> + <em:minVersion>3.0a1pre</em:minVersion> + <em:maxVersion>3.2*</em:maxVersion> + </Description> + </em:targetApplication> + <em:targetApplication> + <!-- Sunbird --> + <Description> + <em:id>{718e30fb-e89b-41dd-9da7-e25a45638b28}</em:id> + <em:minVersion>0.6a1</em:minVersion> + <em:maxVersion>1.0pre</em:maxVersion> + </Description> + </em:targetApplication> + <em:targetApplication> + <!-- SeaMonkey --> + <Description> + <em:id>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</em:id> + <em:minVersion>2.0a1</em:minVersion> + <em:maxVersion>2.1*</em:maxVersion> + </Description> + </em:targetApplication> + <em:targetApplication> + <!-- Songbird --> + <Description> + <em:id>songbird@songbirdnest.com</em:id> + <em:minVersion>0.3pre</em:minVersion> + <em:maxVersion>1.3.0a</em:maxVersion> + </Description> + </em:targetApplication> + <em:targetApplication> + <Description> + <em:id>toolkit@mozilla.org</em:id> + <em:minVersion>1.9.1</em:minVersion> + <em:maxVersion>2.0*</em:maxVersion> + </Description> + </em:targetApplication> + </Description> +</RDF>""", + """<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:em="http://www.mozilla.org/2004/em-rdf#"> + <Description about="urn:mozilla:install-manifest"> + <em:targetApplication> + <!-- Firefox --> + <Description> + <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> + <em:minVersion>3.5</em:minVersion> + <em:maxVersion>8.*</em:maxVersion> + </Description> + </em:targetApplication> + <em:id>winning</em:id> + <em:name>MozMill</em:name> + <em:version>2.0a</em:version> + <em:creator>Adam Christian</em:creator> + <em:description>A testing extension based on the + Windmill Testing Framework client source</em:description> + <em:unpack>true</em:unpack> + </Description> + </RDF>""", + """<RDF xmlns="http://www.mozilla.org/2004/em-rdf#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> + <rdf:Description about="urn:mozilla:install-manifest"> + <id>winning</id> + <name>foo</name> + <version>42</version> + <description>A testing extension based on the + Windmill Testing Framework client source</description> + </rdf:Description> +</RDF>""", + """<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:foobar="http://www.mozilla.org/2004/em-rdf#"> + <Description about="urn:mozilla:install-manifest"> + <foobar:targetApplication> + <!-- Firefox --> + <Description> + <foobar:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</foobar:id> + <foobar:minVersion>3.5</foobar:minVersion> + <foobar:maxVersion>8.*</foobar:maxVersion> + </Description> + </foobar:targetApplication> + <foobar:id>winning</foobar:id> + <foobar:name>MozMill</foobar:name> + <foobar:version>2.0a</foobar:version> + <foobar:creator>Adam Christian</foobar:creator> + <foobar:description>A testing extension based on the + Windmill Testing Framework client source</foobar:description> + <foobar:unpack>true</foobar:unpack> + </Description> + </RDF>""", + """<?xml version="1.0"?> +<!-- + +--> + +<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:em="http://www.mozilla.org/2004/em-rdf#"> + <Description about="urn:mozilla:install-manifest" + em:id="winning" + em:name="Language Pack" + em:version="42.0a2" + em:type="8" + em:creator="Some Contributor"> + <em:contributor></em:contributor> + + <em:targetApplication> + <Description> + <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> + <em:minVersion>42.0a2</em:minVersion> + <em:maxVersion>42.0a2</em:maxVersion> + </Description> + </em:targetApplication> + </Description> +</RDF> +"""] + return tests + +if __name__ == '__main__': + unittest.main() diff --git a/testing/mozbase/mozprofile/tests/addons/empty.xpi b/testing/mozbase/mozprofile/tests/addons/empty.xpi Binary files differnew file mode 100644 index 0000000000..26f28f099d --- /dev/null +++ b/testing/mozbase/mozprofile/tests/addons/empty.xpi diff --git a/testing/mozbase/mozprofile/tests/addons/empty/install.rdf b/testing/mozbase/mozprofile/tests/addons/empty/install.rdf new file mode 100644 index 0000000000..70b9e13e44 --- /dev/null +++ b/testing/mozbase/mozprofile/tests/addons/empty/install.rdf @@ -0,0 +1,20 @@ +<?xml version="1.0"?> +<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#"> + <Description about="urn:mozilla:install-manifest"> + <em:id>test-empty@quality.mozilla.org</em:id> + <em:version>0.1</em:version> + <em:name>Test Extension (empty)</em:name> + <em:creator>Mozilla QA</em:creator> + <em:homepageURL>http://quality.mozilla.org</em:homepageURL> + <em:type>2</em:type> + + <!-- Firefox --> + <em:targetApplication> + <Description> + <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> + <em:minVersion>3.5.*</em:minVersion> + <em:maxVersion>*</em:maxVersion> + </Description> + </em:targetApplication> + </Description> +</RDF> diff --git a/testing/mozbase/mozprofile/tests/addons/invalid.xpi b/testing/mozbase/mozprofile/tests/addons/invalid.xpi Binary files differnew file mode 100644 index 0000000000..2f222c7637 --- /dev/null +++ b/testing/mozbase/mozprofile/tests/addons/invalid.xpi diff --git a/testing/mozbase/mozprofile/tests/bug758250.py b/testing/mozbase/mozprofile/tests/bug758250.py new file mode 100755 index 0000000000..f25901a199 --- /dev/null +++ b/testing/mozbase/mozprofile/tests/bug758250.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +import mozprofile +import os +import shutil +import tempfile +import unittest + + +here = os.path.dirname(os.path.abspath(__file__)) + + +class Bug758250(unittest.TestCase): + """ + use of --profile in mozrunner just blows away addon sources: + https://bugzilla.mozilla.org/show_bug.cgi?id=758250 + """ + + def setUp(self): + self.tmpdir = tempfile.mkdtemp() + self.addon = os.path.join(here, 'addons', 'empty') + + def tearDown(self): + # remove vestiges + shutil.rmtree(self.tmpdir) + + def test_profile_addon_cleanup(self): + + # sanity check: the empty addon should be here + self.assertTrue(os.path.exists(self.addon)) + self.assertTrue(os.path.isdir(self.addon)) + self.assertTrue(os.path.exists(os.path.join(self.addon, 'install.rdf'))) + + # because we are testing data loss, let's make sure we make a copy + shutil.rmtree(self.tmpdir) + shutil.copytree(self.addon, self.tmpdir) + self.assertTrue(os.path.exists(os.path.join(self.tmpdir, 'install.rdf'))) + + # make a starter profile + profile = mozprofile.FirefoxProfile() + path = profile.profile + + # make a new profile based on the old + newprofile = mozprofile.FirefoxProfile(profile=path, addons=[self.tmpdir]) + newprofile.cleanup() + + # the source addon *should* still exist + self.assertTrue(os.path.exists(self.tmpdir)) + self.assertTrue(os.path.exists(os.path.join(self.tmpdir, 'install.rdf'))) + + +if __name__ == '__main__': + unittest.main() diff --git a/testing/mozbase/mozprofile/tests/bug785146.py b/testing/mozbase/mozprofile/tests/bug785146.py new file mode 100755 index 0000000000..2bbf4fb050 --- /dev/null +++ b/testing/mozbase/mozprofile/tests/bug785146.py @@ -0,0 +1,51 @@ +#!/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 mozfile +import os +import shutil +import sqlite3 +import tempfile +import unittest +from mozprofile.permissions import Permissions + + +class PermissionsTest(unittest.TestCase): + + locations = """http://mochi.test:8888 primary,privileged +http://127.0.0.1:80 noxul +http://127.0.0.1:8888 privileged +""" + + def setUp(self): + self.profile_dir = tempfile.mkdtemp() + self.locations_file = mozfile.NamedTemporaryFile() + self.locations_file.write(self.locations) + self.locations_file.flush() + + def tearDown(self): + if self.profile_dir: + shutil.rmtree(self.profile_dir) + if self.locations_file: + self.locations_file.close() + + def test_schema_version(self): + perms = Permissions(self.profile_dir, self.locations_file.name) + perms_db_filename = os.path.join(self.profile_dir, 'permissions.sqlite') + perms.write_db(self.locations_file) + + stmt = 'PRAGMA user_version;' + + con = sqlite3.connect(perms_db_filename) + cur = con.cursor() + cur.execute(stmt) + entries = cur.fetchall() + + schema_version = entries[0][0] + self.assertEqual(schema_version, 5) + +if __name__ == '__main__': + unittest.main() diff --git a/testing/mozbase/mozprofile/tests/files/not_an_addon.txt b/testing/mozbase/mozprofile/tests/files/not_an_addon.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/testing/mozbase/mozprofile/tests/files/not_an_addon.txt diff --git a/testing/mozbase/mozprofile/tests/files/prefs_with_comments.js b/testing/mozbase/mozprofile/tests/files/prefs_with_comments.js new file mode 100644 index 0000000000..06a56f2138 --- /dev/null +++ b/testing/mozbase/mozprofile/tests/files/prefs_with_comments.js @@ -0,0 +1,6 @@ +# A leading comment +user_pref("browser.startup.homepage", "http://planet.mozilla.org"); # A trailing comment +user_pref("zoom.minPercent", 30); +// Another leading comment +user_pref("zoom.maxPercent", 300); // Another trailing comment +user_pref("webgl.verbose", "false"); diff --git a/testing/mozbase/mozprofile/tests/files/prefs_with_interpolation.js b/testing/mozbase/mozprofile/tests/files/prefs_with_interpolation.js new file mode 100644 index 0000000000..d0b30bf7bb --- /dev/null +++ b/testing/mozbase/mozprofile/tests/files/prefs_with_interpolation.js @@ -0,0 +1,4 @@ +user_pref("browser.foo", "http://{server}"); +user_pref("zoom.minPercent", 30); +user_pref("webgl.verbose", "false"); +user_pref("browser.bar", "{abc}xyz"); diff --git a/testing/mozbase/mozprofile/tests/files/webapps1.json b/testing/mozbase/mozprofile/tests/files/webapps1.json new file mode 100644 index 0000000000..00220a3d13 --- /dev/null +++ b/testing/mozbase/mozprofile/tests/files/webapps1.json @@ -0,0 +1,50 @@ +[{ "name": "http_example_org", + "csp": "", + "origin": "http://example.org", + "manifestURL": "http://example.org/manifest.webapp", + "description": "http://example.org App", + "appStatus": 1 + }, + { "name": "https_example_com", + "csp": "", + "origin": "https://example.com", + "manifestURL": "https://example.com/manifest.webapp", + "description": "https://example.com App", + "appStatus": 1 + }, + { "name": "http_test1_example_org", + "csp": "", + "origin": "http://test1.example.org", + "manifestURL": "http://test1.example.org/manifest.webapp", + "description": "http://test1.example.org App", + "appStatus": 1 + }, + { "name": "http_test1_example_org_8000", + "csp": "", + "origin": "http://test1.example.org:8000", + "manifestURL": "http://test1.example.org:8000/manifest.webapp", + "description": "http://test1.example.org:8000 App", + "appStatus": 1 + }, + { "name": "http_sub1_test1_example_org", + "csp": "", + "origin": "http://sub1.test1.example.org", + "manifestURL": "http://sub1.test1.example.org/manifest.webapp", + "description": "http://sub1.test1.example.org App", + "appStatus": 1 + }, + { "name": "https_example_com_privileged", + "csp": "", + "origin": "https://example.com", + "manifestURL": "https://example.com/manifest_priv.webapp", + "description": "https://example.com Privileged App", + "appStatus": 2 + }, + { "name": "https_example_com_certified", + "csp": "", + "origin": "https://example.com", + "manifestURL": "https://example.com/manifest_cert.webapp", + "description": "https://example.com Certified App", + "appStatus": 3 + } +] diff --git a/testing/mozbase/mozprofile/tests/files/webapps2.json b/testing/mozbase/mozprofile/tests/files/webapps2.json new file mode 100644 index 0000000000..03e84a0419 --- /dev/null +++ b/testing/mozbase/mozprofile/tests/files/webapps2.json @@ -0,0 +1,37 @@ +{ + "https_example_csp_certified": { + "csp": "default-src *; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'", + "origin": "https://example.com", + "manifestURL": "https://example.com/manifest_csp_cert.webapp", + "description": "https://example.com certified app with manifest policy", + "appStatus": 3 + }, + "https_example_csp_installed": { + "csp": "default-src *; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'", + "origin": "https://example.com", + "manifestURL": "https://example.com/manifest_csp_inst.webapp", + "description": "https://example.com installed app with manifest policy", + "appStatus": 1 + }, + "https_example_csp_privileged": { + "csp": "default-src *; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'", + "origin": "https://example.com", + "manifestURL": "https://example.com/manifest_csp_priv.webapp", + "description": "https://example.com privileged app with manifest policy", + "appStatus": 2 + }, + "https_a_domain_certified": { + "csp": "", + "origin": "https://acertified.com", + "manifestURL": "https://acertified.com/manifest.webapp", + "description": "https://acertified.com certified app", + "appStatus": 3 + }, + "https_a_domain_privileged": { + "csp": "", + "origin": "https://aprivileged.com", + "manifestURL": "https://aprivileged.com/manifest.webapp", + "description": "https://aprivileged.com privileged app ", + "appStatus": 2 + } +} diff --git a/testing/mozbase/mozprofile/tests/install_manifests/test_addon_1.rdf b/testing/mozbase/mozprofile/tests/install_manifests/test_addon_1.rdf new file mode 100644 index 0000000000..839ea9fbd5 --- /dev/null +++ b/testing/mozbase/mozprofile/tests/install_manifests/test_addon_1.rdf @@ -0,0 +1,21 @@ +<?xml version="1.0"?> +<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:em="http://www.mozilla.org/2004/em-rdf#"> + <Description about="urn:mozilla:install-manifest"> + <em:id>test-addon-1@mozilla.org</em:id> + <em:version>0.1</em:version> + <em:name>Test Add-on 1</em:name> + <em:creator>Mozilla</em:creator> + <em:homepageURL>http://mozilla.org</em:homepageURL> + <em:type>2</em:type> + + <!-- Firefox --> + <em:targetApplication> + <Description> + <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> + <em:minVersion>3.5.*</em:minVersion> + <em:maxVersion>*</em:maxVersion> + </Description> + </em:targetApplication> + </Description> +</RDF> diff --git a/testing/mozbase/mozprofile/tests/install_manifests/test_addon_2.rdf b/testing/mozbase/mozprofile/tests/install_manifests/test_addon_2.rdf new file mode 100644 index 0000000000..8303e862fc --- /dev/null +++ b/testing/mozbase/mozprofile/tests/install_manifests/test_addon_2.rdf @@ -0,0 +1,21 @@ +<?xml version="1.0"?> +<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:em="http://www.mozilla.org/2004/em-rdf#"> + <Description about="urn:mozilla:install-manifest"> + <em:id>test-addon-2@mozilla.org</em:id> + <em:version>0.2</em:version> + <em:name>Test Add-on 2</em:name> + <em:creator>Mozilla</em:creator> + <em:homepageURL>http://mozilla.org</em:homepageURL> + <em:type>2</em:type> + + <!-- Firefox --> + <em:targetApplication> + <Description> + <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> + <em:minVersion>3.5.*</em:minVersion> + <em:maxVersion>*</em:maxVersion> + </Description> + </em:targetApplication> + </Description> +</RDF> diff --git a/testing/mozbase/mozprofile/tests/install_manifests/test_addon_3.rdf b/testing/mozbase/mozprofile/tests/install_manifests/test_addon_3.rdf new file mode 100644 index 0000000000..5bd6d38043 --- /dev/null +++ b/testing/mozbase/mozprofile/tests/install_manifests/test_addon_3.rdf @@ -0,0 +1,22 @@ +<?xml version="1.0"?> +<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:em="http://www.mozilla.org/2004/em-rdf#"> + <Description about="urn:mozilla:install-manifest"> + <em:id>test-addon-3@mozilla.org</em:id> + <em:version>0.1</em:version> + <em:name>Test Add-on 3</em:name> + <em:creator>Mozilla</em:creator> + <em:homepageURL>http://mozilla.org</em:homepageURL> + <em:type>2</em:type> + + <!-- Firefox --> + <em:targetApplication> + <Description> + <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> + <em:minVersion>3.5.*</em:minVersion> + <em:maxVersion>*</em:maxVersion> + </Description> + </em:targetApplication> + </Description> +</RDF> + diff --git a/testing/mozbase/mozprofile/tests/install_manifests/test_addon_4.rdf b/testing/mozbase/mozprofile/tests/install_manifests/test_addon_4.rdf new file mode 100644 index 0000000000..e0f99d3133 --- /dev/null +++ b/testing/mozbase/mozprofile/tests/install_manifests/test_addon_4.rdf @@ -0,0 +1,22 @@ +<?xml version="1.0"?> +<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:em="http://www.mozilla.org/2004/em-rdf#"> + <Description about="urn:mozilla:install-manifest"> + <em:id>test-addon-4@mozilla.org</em:id> + <em:version>0.1</em:version> + <em:name>Test Add-on 4</em:name> + <em:creator>Mozilla</em:creator> + <em:homepageURL>http://mozilla.org</em:homepageURL> + <em:type>2</em:type> + + <!-- Firefox --> + <em:targetApplication> + <Description> + <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> + <em:minVersion>3.5.*</em:minVersion> + <em:maxVersion>*</em:maxVersion> + </Description> + </em:targetApplication> + </Description> +</RDF> + diff --git a/testing/mozbase/mozprofile/tests/install_manifests/test_addon_invalid_no_id.rdf b/testing/mozbase/mozprofile/tests/install_manifests/test_addon_invalid_no_id.rdf new file mode 100644 index 0000000000..23f60fece1 --- /dev/null +++ b/testing/mozbase/mozprofile/tests/install_manifests/test_addon_invalid_no_id.rdf @@ -0,0 +1,22 @@ +<?xml version="1.0"?> +<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:em="http://www.mozilla.org/2004/em-rdf#"> + <Description about="urn:mozilla:install-manifest"> + <!-- Invalid because of a missing add-on id --> + <em:version>0.1</em:version> + <em:name>Test Invalid Extension (no id)</em:name> + <em:creator>Mozilla</em:creator> + <em:homepageURL>http://mozilla.org</em:homepageURL> + <em:type>2</em:type> + + <!-- Firefox --> + <em:targetApplication> + <Description> + <!-- Invalid target application string --> + <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> + <em:minVersion>3.5.*</em:minVersion> + <em:maxVersion>*</em:maxVersion> + </Description> + </em:targetApplication> + </Description> +</RDF> diff --git a/testing/mozbase/mozprofile/tests/install_manifests/test_addon_invalid_not_wellformed.rdf b/testing/mozbase/mozprofile/tests/install_manifests/test_addon_invalid_not_wellformed.rdf new file mode 100644 index 0000000000..690ec406cc --- /dev/null +++ b/testing/mozbase/mozprofile/tests/install_manifests/test_addon_invalid_not_wellformed.rdf @@ -0,0 +1,23 @@ +<?xml version="1.0"?> +<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:em="http://www.mozilla.org/2004/em-rdf#"> + <Description about="urn:mozilla:install-manifest"> + <!-- Invalid because it's not well-formed --> + <em:id>test-addon-invalid-not-wellformed@mozilla.org</em:id + <em:version>0.1</em:version> + <em:name>Test Invalid Extension (no id)</em:name> + <em:creator>Mozilla</em:creator> + <em:homepageURL>http://mozilla.org</em:homepageURL> + <em:type>2</em:type> + + <!-- Firefox --> + <em:targetApplication> + <Description> + <!-- Invalid target application string --> + <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> + <em:minVersion>3.5.*</em:minVersion> + <em:maxVersion>*</em:maxVersion> + </Description> + </em:targetApplication> + </Description> +</RDF> diff --git a/testing/mozbase/mozprofile/tests/install_manifests/test_addon_invalid_version.rdf b/testing/mozbase/mozprofile/tests/install_manifests/test_addon_invalid_version.rdf new file mode 100644 index 0000000000..c854bfcdb5 --- /dev/null +++ b/testing/mozbase/mozprofile/tests/install_manifests/test_addon_invalid_version.rdf @@ -0,0 +1,23 @@ +<?xml version="1.0"?> +<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:em="http://www.mozilla.org/2004/em-rdf#"> + <Description about="urn:mozilla:install-manifest"> + <em:id>test-addon-invalid-version@mozilla.org</em:id> + <!-- Invalid addon version --> + <em:version>0.NOPE</em:version> + <em:name>Test Invalid Extension (invalid version)</em:name> + <em:creator>Mozilla</em:creator> + <em:homepageURL>http://mozilla.org</em:homepageURL> + <em:type>2</em:type> + + <!-- Firefox --> + <em:targetApplication> + <Description> + <!-- Invalid target application string --> + <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> + <em:minVersion>3.5.*</em:minVersion> + <em:maxVersion>*</em:maxVersion> + </Description> + </em:targetApplication> + </Description> +</RDF> diff --git a/testing/mozbase/mozprofile/tests/install_manifests/test_addon_unpack.rdf b/testing/mozbase/mozprofile/tests/install_manifests/test_addon_unpack.rdf new file mode 100644 index 0000000000..cc85ea560f --- /dev/null +++ b/testing/mozbase/mozprofile/tests/install_manifests/test_addon_unpack.rdf @@ -0,0 +1,22 @@ +<?xml version="1.0"?> +<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:em="http://www.mozilla.org/2004/em-rdf#"> + <Description about="urn:mozilla:install-manifest"> + <em:id>test-addon-unpack@mozilla.org</em:id> + <em:version>0.1</em:version> + <em:name>Test Add-on (unpack)</em:name> + <em:creator>Mozilla</em:creator> + <em:homepageURL>http://mozilla.org</em:homepageURL> + <em:type>2</em:type> + <em:unpack>true</em:unpack> + + <!-- Firefox --> + <em:targetApplication> + <Description> + <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> + <em:minVersion>3.5.*</em:minVersion> + <em:maxVersion>*</em:maxVersion> + </Description> + </em:targetApplication> + </Description> +</RDF> diff --git a/testing/mozbase/mozprofile/tests/manifest.ini b/testing/mozbase/mozprofile/tests/manifest.ini new file mode 100644 index 0000000000..3e5ea50d67 --- /dev/null +++ b/testing/mozbase/mozprofile/tests/manifest.ini @@ -0,0 +1,12 @@ +[addonid.py] +[server_locations.py] +[test_preferences.py] +[permissions.py] +[bug758250.py] +[test_nonce.py] +[bug785146.py] +[test_clone_cleanup.py] +[test_webapps.py] +[test_profile.py] +[test_profile_view.py] +[test_addons.py] diff --git a/testing/mozbase/mozprofile/tests/permissions.py b/testing/mozbase/mozprofile/tests/permissions.py new file mode 100755 index 0000000000..8889277afb --- /dev/null +++ b/testing/mozbase/mozprofile/tests/permissions.py @@ -0,0 +1,199 @@ +#!/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 mozfile +import os +import shutil +import sqlite3 +import tempfile +import unittest +from mozprofile.permissions import Permissions + + +class PermissionsTest(unittest.TestCase): + + locations = """http://mochi.test:8888 primary,privileged +http://127.0.0.1:80 noxul +http://127.0.0.1:8888 privileged +""" + + profile_dir = None + locations_file = None + + def setUp(self): + self.profile_dir = tempfile.mkdtemp() + self.locations_file = mozfile.NamedTemporaryFile() + self.locations_file.write(self.locations) + self.locations_file.flush() + + def tearDown(self): + if self.profile_dir: + shutil.rmtree(self.profile_dir) + if self.locations_file: + self.locations_file.close() + + def write_perm_db(self, version=3): + permDB = sqlite3.connect(os.path.join(self.profile_dir, "permissions.sqlite")) + cursor = permDB.cursor() + + cursor.execute("PRAGMA user_version=%d;" % version) + + if version == 5: + cursor.execute("""CREATE TABLE IF NOT EXISTS moz_hosts ( + id INTEGER PRIMARY KEY, + origin TEXT, + type TEXT, + permission INTEGER, + expireType INTEGER, + expireTime INTEGER, + modificationTime INTEGER)""") + elif version == 4: + cursor.execute("""CREATE TABLE IF NOT EXISTS moz_hosts ( + id INTEGER PRIMARY KEY, + host TEXT, + type TEXT, + permission INTEGER, + expireType INTEGER, + expireTime INTEGER, + modificationTime INTEGER, + appId INTEGER, + isInBrowserElement INTEGER)""") + elif version == 3: + cursor.execute("""CREATE TABLE IF NOT EXISTS moz_hosts ( + id INTEGER PRIMARY KEY, + host TEXT, + type TEXT, + permission INTEGER, + expireType INTEGER, + expireTime INTEGER, + appId INTEGER, + isInBrowserElement INTEGER)""") + elif version == 2: + cursor.execute("""CREATE TABLE IF NOT EXISTS moz_hosts ( + id INTEGER PRIMARY KEY, + host TEXT, + type TEXT, + permission INTEGER, + expireType INTEGER, + expireTime INTEGER)""") + else: + raise Exception("version must be 2, 3, 4 or 5") + + permDB.commit() + cursor.close() + + def test_create_permissions_db(self): + perms = Permissions(self.profile_dir, self.locations_file.name) + perms_db_filename = os.path.join(self.profile_dir, 'permissions.sqlite') + + select_stmt = 'select origin, type, permission from moz_hosts' + + con = sqlite3.connect(perms_db_filename) + cur = con.cursor() + cur.execute(select_stmt) + entries = cur.fetchall() + + self.assertEqual(len(entries), 3) + + self.assertEqual(entries[0][0], 'http://mochi.test:8888') + self.assertEqual(entries[0][1], 'allowXULXBL') + self.assertEqual(entries[0][2], 1) + + self.assertEqual(entries[1][0], 'http://127.0.0.1') + self.assertEqual(entries[1][1], 'allowXULXBL') + self.assertEqual(entries[1][2], 2) + + self.assertEqual(entries[2][0], 'http://127.0.0.1:8888') + self.assertEqual(entries[2][1], 'allowXULXBL') + self.assertEqual(entries[2][2], 1) + + perms._locations.add_host('a.b.c', port='8081', scheme='https', options='noxul') + + cur.execute(select_stmt) + entries = cur.fetchall() + + self.assertEqual(len(entries), 4) + self.assertEqual(entries[3][0], 'https://a.b.c:8081') + self.assertEqual(entries[3][1], 'allowXULXBL') + self.assertEqual(entries[3][2], 2) + + # when creating a DB we should default to user_version==5 + cur.execute('PRAGMA user_version') + entries = cur.fetchall() + self.assertEqual(entries[0][0], 5) + + perms.clean_db() + # table should be removed + cur.execute("select * from sqlite_master where type='table'") + entries = cur.fetchall() + self.assertEqual(len(entries), 0) + + def test_nw_prefs(self): + perms = Permissions(self.profile_dir, self.locations_file.name) + + prefs, user_prefs = perms.network_prefs(False) + + self.assertEqual(len(user_prefs), 0) + self.assertEqual(len(prefs), 0) + + prefs, user_prefs = perms.network_prefs(True) + self.assertEqual(len(user_prefs), 2) + self.assertEqual(user_prefs[0], ('network.proxy.type', 2)) + self.assertEqual(user_prefs[1][0], 'network.proxy.autoconfig_url') + + origins_decl = "var knownOrigins = (function () { return ['http://mochi.test:8888', " \ + "'http://127.0.0.1:80', 'http://127.0.0.1:8888'].reduce" + self.assertTrue(origins_decl in user_prefs[1][1]) + + proxy_check = ("'http': 'PROXY mochi.test:8888'", + "'https': 'PROXY mochi.test:4443'", + "'ws': 'PROXY mochi.test:4443'", + "'wss': 'PROXY mochi.test:4443'") + self.assertTrue(all(c in user_prefs[1][1] for c in proxy_check)) + + def verify_user_version(self, version): + """Verifies that we call INSERT statements using the correct number + of columns for existing databases. + """ + self.write_perm_db(version=version) + Permissions(self.profile_dir, self.locations_file.name) + perms_db_filename = os.path.join(self.profile_dir, 'permissions.sqlite') + + select_stmt = 'select * from moz_hosts' + + con = sqlite3.connect(perms_db_filename) + cur = con.cursor() + cur.execute(select_stmt) + entries = cur.fetchall() + + self.assertEqual(len(entries), 3) + + columns = { + 1: 6, + 2: 6, + 3: 8, + 4: 9, + 5: 7, + }[version] + + self.assertEqual(len(entries[0]), columns) + for x in range(4, columns): + self.assertEqual(entries[0][x], 0) + + def test_existing_permissions_db_v2(self): + self.verify_user_version(2) + + def test_existing_permissions_db_v3(self): + self.verify_user_version(3) + + def test_existing_permissions_db_v4(self): + self.verify_user_version(4) + + def test_existing_permissions_db_v5(self): + self.verify_user_version(5) + +if __name__ == '__main__': + unittest.main() diff --git a/testing/mozbase/mozprofile/tests/server_locations.py b/testing/mozbase/mozprofile/tests/server_locations.py new file mode 100644 index 0000000000..5aa5c0f5eb --- /dev/null +++ b/testing/mozbase/mozprofile/tests/server_locations.py @@ -0,0 +1,151 @@ +#!/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 mozfile +import unittest +from mozprofile.permissions import ServerLocations, \ + MissingPrimaryLocationError, MultiplePrimaryLocationsError, \ + DuplicateLocationError, BadPortLocationError, LocationsSyntaxError + + +class ServerLocationsTest(unittest.TestCase): + """test server locations""" + + locations = """# This is the primary location from which tests run. +# +http://mochi.test:8888 primary,privileged + +# a few test locations +http://127.0.0.1:80 privileged +http://127.0.0.1:8888 privileged +https://test:80 privileged +http://example.org:80 privileged +http://test1.example.org privileged + + """ + + locations_no_primary = """http://secondary.test:80 privileged +http://tertiary.test:8888 privileged +""" + + locations_bad_port = """http://mochi.test:8888 primary,privileged +http://127.0.0.1:80 privileged +http://127.0.0.1:8888 privileged +http://test:badport privileged +http://example.org:80 privileged +""" + + def compare_location(self, location, scheme, host, port, options): + self.assertEqual(location.scheme, scheme) + self.assertEqual(location.host, host) + self.assertEqual(location.port, port) + self.assertEqual(location.options, options) + + def create_temp_file(self, contents): + f = mozfile.NamedTemporaryFile() + f.write(contents) + f.flush() + return f + + def test_server_locations(self): + # write a permissions file + f = self.create_temp_file(self.locations) + + # read the locations + locations = ServerLocations(f.name) + + # ensure that they're what we expect + self.assertEqual(len(locations), 6) + i = iter(locations) + self.compare_location(i.next(), 'http', 'mochi.test', '8888', + ['primary', 'privileged']) + self.compare_location(i.next(), 'http', '127.0.0.1', '80', + ['privileged']) + self.compare_location(i.next(), 'http', '127.0.0.1', '8888', + ['privileged']) + self.compare_location(i.next(), 'https', 'test', '80', ['privileged']) + self.compare_location(i.next(), 'http', 'example.org', '80', + ['privileged']) + self.compare_location(i.next(), 'http', 'test1.example.org', '8888', + ['privileged']) + + locations.add_host('mozilla.org') + self.assertEqual(len(locations), 7) + self.compare_location(i.next(), 'http', 'mozilla.org', '80', + ['privileged']) + + # test some errors + self.assertRaises(MultiplePrimaryLocationsError, locations.add_host, + 'primary.test', options='primary') + + # We no longer throw these DuplicateLocation Error + try: + locations.add_host('127.0.0.1') + except DuplicateLocationError: + self.assertTrue(False, "Should no longer throw DuplicateLocationError") + + self.assertRaises(BadPortLocationError, locations.add_host, '127.0.0.1', + port='abc') + + # test some errors in locations file + f = self.create_temp_file(self.locations_no_primary) + + exc = None + try: + ServerLocations(f.name) + except LocationsSyntaxError as e: + exc = e + self.assertNotEqual(exc, None) + self.assertEqual(exc.err.__class__, MissingPrimaryLocationError) + self.assertEqual(exc.lineno, 3) + + # test bad port in a locations file to ensure lineno calculated + # properly. + f = self.create_temp_file(self.locations_bad_port) + + exc = None + try: + ServerLocations(f.name) + except LocationsSyntaxError as e: + exc = e + self.assertNotEqual(exc, None) + self.assertEqual(exc.err.__class__, BadPortLocationError) + self.assertEqual(exc.lineno, 4) + + def test_server_locations_callback(self): + class CallbackTest(object): + last_locations = None + + def callback(self, locations): + self.last_locations = locations + + c = CallbackTest() + f = self.create_temp_file(self.locations) + locations = ServerLocations(f.name, c.callback) + + # callback should be for all locations in file + self.assertEqual(len(c.last_locations), 6) + + # validate arbitrary one + self.compare_location(c.last_locations[2], 'http', '127.0.0.1', '8888', + ['privileged']) + + locations.add_host('a.b.c') + + # callback should be just for one location + self.assertEqual(len(c.last_locations), 1) + self.compare_location(c.last_locations[0], 'http', 'a.b.c', '80', + ['privileged']) + + # read a second file, which should generate a callback with both + # locations. + f = self.create_temp_file(self.locations_no_primary) + locations.read(f.name) + self.assertEqual(len(c.last_locations), 2) + + +if __name__ == '__main__': + unittest.main() diff --git a/testing/mozbase/mozprofile/tests/test_addons.py b/testing/mozbase/mozprofile/tests/test_addons.py new file mode 100644 index 0000000000..93b930feac --- /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() diff --git a/testing/mozbase/mozprofile/tests/test_clone_cleanup.py b/testing/mozbase/mozprofile/tests/test_clone_cleanup.py new file mode 100644 index 0000000000..51c7ba03e8 --- /dev/null +++ b/testing/mozbase/mozprofile/tests/test_clone_cleanup.py @@ -0,0 +1,63 @@ +#!/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 tempfile +import unittest +import mozfile + +from mozprofile.profile import Profile + + +class CloneCleanupTest(unittest.TestCase): + """ + test cleanup logic for the clone functionality + see https://bugzilla.mozilla.org/show_bug.cgi?id=642843 + """ + + def setUp(self): + # make a profile with one preference + path = tempfile.mktemp() + self.addCleanup(mozfile.remove, path) + self.profile = Profile(path, + preferences={'foo': 'bar'}, + restore=False) + user_js = os.path.join(self.profile.profile, 'user.js') + self.assertTrue(os.path.exists(user_js)) + + def test_restore_true(self): + # make a clone of this profile with restore=True + clone = Profile.clone(self.profile.profile, restore=True) + self.addCleanup(mozfile.remove, clone.profile) + + clone.cleanup() + + # clone should be deleted + self.assertFalse(os.path.exists(clone.profile)) + + def test_restore_false(self): + # make a clone of this profile with restore=False + clone = Profile.clone(self.profile.profile, restore=False) + self.addCleanup(mozfile.remove, clone.profile) + + clone.cleanup() + + # clone should still be around on the filesystem + self.assertTrue(os.path.exists(clone.profile)) + + def test_cleanup_on_garbage_collected(self): + clone = Profile.clone(self.profile.profile) + self.addCleanup(mozfile.remove, clone.profile) + profile_dir = clone.profile + self.assertTrue(os.path.exists(profile_dir)) + del clone + # clone should be deleted + self.assertFalse(os.path.exists(profile_dir)) + + +if __name__ == '__main__': + unittest.main() diff --git a/testing/mozbase/mozprofile/tests/test_nonce.py b/testing/mozbase/mozprofile/tests/test_nonce.py new file mode 100755 index 0000000000..fef2622725 --- /dev/null +++ b/testing/mozbase/mozprofile/tests/test_nonce.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +test nonce in prefs delimeters +see https://bugzilla.mozilla.org/show_bug.cgi?id=722804 +""" + +import os +import tempfile +import unittest +import mozfile +from mozprofile.prefs import Preferences +from mozprofile.profile import Profile + + +class PreferencesNonceTest(unittest.TestCase): + + def test_nonce(self): + + # make a profile with one preference + path = tempfile.mktemp() + self.addCleanup(mozfile.remove, path) + profile = Profile(path, + preferences={'foo': 'bar'}, + restore=False) + user_js = os.path.join(profile.profile, 'user.js') + self.assertTrue(os.path.exists(user_js)) + + # ensure the preference is correct + prefs = Preferences.read_prefs(user_js) + self.assertEqual(dict(prefs), {'foo': 'bar'}) + + del profile + + # augment the profile with a second preference + profile = Profile(path, + preferences={'fleem': 'baz'}, + restore=True) + prefs = Preferences.read_prefs(user_js) + self.assertEqual(dict(prefs), {'foo': 'bar', 'fleem': 'baz'}) + + # cleanup the profile; + # this should remove the new preferences but not the old + profile.cleanup() + prefs = Preferences.read_prefs(user_js) + self.assertEqual(dict(prefs), {'foo': 'bar'}) + +if __name__ == '__main__': + unittest.main() diff --git a/testing/mozbase/mozprofile/tests/test_preferences.py b/testing/mozbase/mozprofile/tests/test_preferences.py new file mode 100755 index 0000000000..45d99c2e27 --- /dev/null +++ b/testing/mozbase/mozprofile/tests/test_preferences.py @@ -0,0 +1,378 @@ +#!/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 mozfile +import mozhttpd +import os +import shutil +import tempfile +import unittest +from mozprofile.cli import MozProfileCLI +from mozprofile.prefs import Preferences +from mozprofile.profile import Profile + +here = os.path.dirname(os.path.abspath(__file__)) + + +class PreferencesTest(unittest.TestCase): + """test mozprofile preference handling""" + + # preferences from files/prefs_with_comments.js + _prefs_with_comments = {'browser.startup.homepage': 'http://planet.mozilla.org', + 'zoom.minPercent': 30, + 'zoom.maxPercent': 300, + 'webgl.verbose': 'false'} + + def run_command(self, *args): + """ + invokes mozprofile command line via the CLI factory + - args : command line arguments (equivalent of sys.argv[1:]) + """ + + # instantiate the factory + cli = MozProfileCLI(list(args)) + + # create the profile + profile = cli.profile() + + # return path to profile + return profile.profile + + def compare_generated(self, _prefs, commandline): + """ + writes out to a new profile with mozprofile command line + reads the generated preferences with prefs.py + compares the results + cleans up + """ + profile = self.run_command(*commandline) + prefs_file = os.path.join(profile, 'user.js') + self.assertTrue(os.path.exists(prefs_file)) + read = Preferences.read_prefs(prefs_file) + if isinstance(_prefs, dict): + read = dict(read) + self.assertEqual(_prefs, read) + shutil.rmtree(profile) + + def test_basic_prefs(self): + """test setting a pref from the command line entry point""" + + _prefs = {"browser.startup.homepage": "http://planet.mozilla.org/"} + commandline = [] + _prefs = _prefs.items() + for pref, value in _prefs: + commandline += ["--pref", "%s:%s" % (pref, value)] + self.compare_generated(_prefs, commandline) + + def test_ordered_prefs(self): + """ensure the prefs stay in the right order""" + _prefs = [("browser.startup.homepage", "http://planet.mozilla.org/"), + ("zoom.minPercent", 30), + ("zoom.maxPercent", 300), + ("webgl.verbose", 'false')] + commandline = [] + for pref, value in _prefs: + commandline += ["--pref", "%s:%s" % (pref, value)] + _prefs = [(i, Preferences.cast(j)) for i, j in _prefs] + self.compare_generated(_prefs, commandline) + + def test_ini(self): + + # write the .ini file + _ini = """[DEFAULT] +browser.startup.homepage = http://planet.mozilla.org/ + +[foo] +browser.startup.homepage = http://github.com/ +""" + try: + fd, name = tempfile.mkstemp(suffix='.ini') + os.write(fd, _ini) + os.close(fd) + commandline = ["--preferences", name] + + # test the [DEFAULT] section + _prefs = {'browser.startup.homepage': 'http://planet.mozilla.org/'} + self.compare_generated(_prefs, commandline) + + # test a specific section + _prefs = {'browser.startup.homepage': 'http://github.com/'} + commandline[-1] = commandline[-1] + ':foo' + self.compare_generated(_prefs, commandline) + + finally: + # cleanup + os.remove(name) + + def test_ini_keep_case(self): + """ + Read a preferences config file with a preference in camel-case style. + Check that the read preference name has not been lower-cased + """ + # write the .ini file + _ini = """[DEFAULT] +general.warnOnAboutConfig = False +""" + try: + fd, name = tempfile.mkstemp(suffix='.ini') + os.write(fd, _ini) + os.close(fd) + commandline = ["--preferences", name] + + # test the [DEFAULT] section + _prefs = {'general.warnOnAboutConfig': 'False'} + self.compare_generated(_prefs, commandline) + + finally: + # cleanup + os.remove(name) + + def test_reset_should_remove_added_prefs(self): + """Check that when we call reset the items we expect are updated""" + profile = Profile() + prefs_file = os.path.join(profile.profile, 'user.js') + + # we shouldn't have any initial preferences + initial_prefs = Preferences.read_prefs(prefs_file) + self.assertFalse(initial_prefs) + initial_prefs = file(prefs_file).read().strip() + self.assertFalse(initial_prefs) + + # add some preferences + prefs1 = [("mr.t.quotes", "i aint getting on no plane!")] + profile.set_preferences(prefs1) + self.assertEqual(prefs1, Preferences.read_prefs(prefs_file)) + lines = file(prefs_file).read().strip().splitlines() + self.assertTrue(any(line.startswith('#MozRunner Prefs Start') for line in lines)) + self.assertTrue(any(line.startswith('#MozRunner Prefs End') for line in lines)) + + profile.reset() + self.assertNotEqual(prefs1, + Preferences.read_prefs(os.path.join(profile.profile, 'user.js')), + "I pity the fool who left my pref") + + def test_reset_should_keep_user_added_prefs(self): + """Check that when we call reset the items we expect are updated""" + profile = Profile() + prefs_file = os.path.join(profile.profile, 'user.js') + + # we shouldn't have any initial preferences + initial_prefs = Preferences.read_prefs(prefs_file) + self.assertFalse(initial_prefs) + initial_prefs = file(prefs_file).read().strip() + self.assertFalse(initial_prefs) + + # add some preferences + prefs1 = [("mr.t.quotes", "i aint getting on no plane!")] + profile.set_persistent_preferences(prefs1) + self.assertEqual(prefs1, Preferences.read_prefs(prefs_file)) + lines = file(prefs_file).read().strip().splitlines() + self.assertTrue(any(line.startswith('#MozRunner Prefs Start') for line in lines)) + self.assertTrue(any(line.startswith('#MozRunner Prefs End') for line in lines)) + + profile.reset() + self.assertEqual(prefs1, + Preferences.read_prefs(os.path.join(profile.profile, 'user.js')), + "I pity the fool who left my pref") + + def test_magic_markers(self): + """ensure our magic markers are working""" + + profile = Profile() + prefs_file = os.path.join(profile.profile, 'user.js') + + # we shouldn't have any initial preferences + initial_prefs = Preferences.read_prefs(prefs_file) + self.assertFalse(initial_prefs) + initial_prefs = file(prefs_file).read().strip() + self.assertFalse(initial_prefs) + + # add some preferences + prefs1 = [("browser.startup.homepage", "http://planet.mozilla.org/"), + ("zoom.minPercent", 30)] + profile.set_preferences(prefs1) + self.assertEqual(prefs1, Preferences.read_prefs(prefs_file)) + lines = file(prefs_file).read().strip().splitlines() + self.assertTrue(bool([line for line in lines + if line.startswith('#MozRunner Prefs Start')])) + self.assertTrue(bool([line for line in lines + if line.startswith('#MozRunner Prefs End')])) + + # add some more preferences + prefs2 = [("zoom.maxPercent", 300), + ("webgl.verbose", 'false')] + profile.set_preferences(prefs2) + self.assertEqual(prefs1 + prefs2, Preferences.read_prefs(prefs_file)) + lines = file(prefs_file).read().strip().splitlines() + self.assertTrue(len([line for line in lines + if line.startswith('#MozRunner Prefs Start')]) == 2) + self.assertTrue(len([line for line in lines + if line.startswith('#MozRunner Prefs End')]) == 2) + + # now clean it up + profile.clean_preferences() + final_prefs = Preferences.read_prefs(prefs_file) + self.assertFalse(final_prefs) + lines = file(prefs_file).read().strip().splitlines() + self.assertTrue('#MozRunner Prefs Start' not in lines) + self.assertTrue('#MozRunner Prefs End' not in lines) + + def test_preexisting_preferences(self): + """ensure you don't clobber preexisting preferences""" + + # make a pretend profile + tempdir = tempfile.mkdtemp() + + try: + # make a user.js + contents = """ +user_pref("webgl.enabled_for_all_sites", true); +user_pref("webgl.force-enabled", true); +""" + user_js = os.path.join(tempdir, 'user.js') + f = file(user_js, 'w') + f.write(contents) + f.close() + + # make sure you can read it + prefs = Preferences.read_prefs(user_js) + original_prefs = [('webgl.enabled_for_all_sites', True), ('webgl.force-enabled', True)] + self.assertTrue(prefs == original_prefs) + + # now read this as a profile + profile = Profile(tempdir, preferences={"browser.download.dir": "/home/jhammel"}) + + # make sure the new pref is now there + new_prefs = original_prefs[:] + [("browser.download.dir", "/home/jhammel")] + prefs = Preferences.read_prefs(user_js) + self.assertTrue(prefs == new_prefs) + + # clean up the added preferences + profile.cleanup() + del profile + + # make sure you have the original preferences + prefs = Preferences.read_prefs(user_js) + self.assertTrue(prefs == original_prefs) + finally: + shutil.rmtree(tempdir) + + def test_can_read_prefs_with_multiline_comments(self): + """ + Ensure that multiple comments in the file header do not break reading + the prefs (https://bugzilla.mozilla.org/show_bug.cgi?id=1233534). + """ + user_js = tempfile.NamedTemporaryFile(suffix='.js', delete=False) + self.addCleanup(mozfile.remove, user_js.name) + with user_js: + user_js.write(""" +# Mozilla User Preferences + +/* Do not edit this file. + * + * If you make changes to this file while the application is running, + * the changes will be overwritten when the application exits. + * + * To make a manual change to preferences, you can visit the URL about:config + */ + +user_pref("webgl.enabled_for_all_sites", true); +user_pref("webgl.force-enabled", true); +""") + self.assertEqual( + Preferences.read_prefs(user_js.name), + [('webgl.enabled_for_all_sites', True), + ('webgl.force-enabled', True)] + ) + + def test_json(self): + _prefs = {"browser.startup.homepage": "http://planet.mozilla.org/"} + json = '{"browser.startup.homepage": "http://planet.mozilla.org/"}' + + # just repr it...could use the json module but we don't need it here + with mozfile.NamedTemporaryFile(suffix='.json') as f: + f.write(json) + f.flush() + + commandline = ["--preferences", f.name] + self.compare_generated(_prefs, commandline) + + def test_prefs_write(self): + """test that the Preferences.write() method correctly serializes preferences""" + + _prefs = {'browser.startup.homepage': "http://planet.mozilla.org", + 'zoom.minPercent': 30, + 'zoom.maxPercent': 300} + + # make a Preferences manager with the testing preferences + preferences = Preferences(_prefs) + + # write them to a temporary location + path = None + read_prefs = None + try: + with mozfile.NamedTemporaryFile(suffix='.js', delete=False) as f: + path = f.name + preferences.write(f, _prefs) + + # read them back and ensure we get what we put in + read_prefs = dict(Preferences.read_prefs(path)) + + finally: + # cleanup + if path and os.path.exists(path): + os.remove(path) + + self.assertEqual(read_prefs, _prefs) + + def test_read_prefs_with_comments(self): + """test reading preferences from a prefs.js file that contains comments""" + + path = os.path.join(here, 'files', 'prefs_with_comments.js') + self.assertEqual(dict(Preferences.read_prefs(path)), self._prefs_with_comments) + + def test_read_prefs_with_interpolation(self): + """test reading preferences from a prefs.js file whose values + require interpolation""" + + expected_prefs = { + "browser.foo": "http://server-name", + "zoom.minPercent": 30, + "webgl.verbose": "false", + "browser.bar": "somethingxyz" + } + values = { + "server": "server-name", + "abc": "something" + } + path = os.path.join(here, 'files', 'prefs_with_interpolation.js') + read_prefs = Preferences.read_prefs(path, interpolation=values) + self.assertEqual(dict(read_prefs), expected_prefs) + + def test_read_prefs_ttw(self): + """test reading preferences through the web via mozhttpd""" + + # create a MozHttpd instance + docroot = os.path.join(here, 'files') + host = '127.0.0.1' + port = 8888 + httpd = mozhttpd.MozHttpd(host=host, port=port, docroot=docroot) + + # create a preferences instance + prefs = Preferences() + + try: + # start server + httpd.start(block=False) + + # read preferences through the web + read = prefs.read_prefs('http://%s:%d/prefs_with_comments.js' % (host, port)) + self.assertEqual(dict(read), self._prefs_with_comments) + finally: + httpd.stop() + +if __name__ == '__main__': + unittest.main() diff --git a/testing/mozbase/mozprofile/tests/test_profile.py b/testing/mozbase/mozprofile/tests/test_profile.py new file mode 100644 index 0000000000..e24de1904c --- /dev/null +++ b/testing/mozbase/mozprofile/tests/test_profile.py @@ -0,0 +1,30 @@ +#!/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 unittest +import os +from mozprofile import Profile + + +class TestProfile(unittest.TestCase): + + def test_with_profile_should_cleanup(self): + with Profile() as profile: + self.assertTrue(os.path.exists(profile.profile)) + # profile is cleaned + self.assertFalse(os.path.exists(profile.profile)) + + def test_with_profile_should_cleanup_even_on_exception(self): + with self.assertRaises(ZeroDivisionError): + with Profile() as profile: + self.assertTrue(os.path.exists(profile.profile)) + 1 / 0 # will raise ZeroDivisionError + # profile is cleaned + self.assertFalse(os.path.exists(profile.profile)) + + +if __name__ == '__main__': + unittest.main() diff --git a/testing/mozbase/mozprofile/tests/test_profile_view.py b/testing/mozbase/mozprofile/tests/test_profile_view.py new file mode 100644 index 0000000000..2e10a913bd --- /dev/null +++ b/testing/mozbase/mozprofile/tests/test_profile_view.py @@ -0,0 +1,75 @@ +#!/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 mozfile +import mozprofile +import os +import tempfile +import unittest + +here = os.path.dirname(os.path.abspath(__file__)) + + +class TestProfilePrint(unittest.TestCase): + + def test_profileprint(self): + """ + test the summary function + """ + + keys = set(['Files', 'Path', 'user.js']) + ff_prefs = mozprofile.FirefoxProfile.preferences # shorthand + pref_string = '\n'.join(['%s: %s' % (key, ff_prefs[key]) + for key in sorted(ff_prefs.keys())]) + + tempdir = tempfile.mkdtemp() + try: + profile = mozprofile.FirefoxProfile(tempdir) + parts = profile.summary(return_parts=True) + parts = dict(parts) + + self.assertEqual(parts['Path'], tempdir) + self.assertEqual(set(parts.keys()), keys) + self.assertEqual(pref_string, parts['user.js'].strip()) + + except: + raise + finally: + mozfile.rmtree(tempdir) + + def test_strcast(self): + """ + test casting to a string + """ + + profile = mozprofile.Profile() + self.assertEqual(str(profile), profile.summary()) + + def test_profile_diff(self): + profile1 = mozprofile.Profile() + profile2 = mozprofile.Profile(preferences=dict(foo='bar')) + + # diff a profile against itself; no difference + self.assertEqual([], mozprofile.diff(profile1, profile1)) + + # diff two profiles + diff = dict(mozprofile.diff(profile1, profile2)) + self.assertEqual(diff.keys(), ['user.js']) + lines = [line.strip() for line in diff['user.js'].splitlines()] + self.assertTrue('+foo: bar' in lines) + + # diff a blank vs FirefoxProfile + ff_profile = mozprofile.FirefoxProfile() + diff = dict(mozprofile.diff(profile2, ff_profile)) + self.assertEqual(diff.keys(), ['user.js']) + lines = [line.strip() for line in diff['user.js'].splitlines()] + self.assertTrue('-foo: bar' in lines) + ff_pref_lines = ['+%s: %s' % (key, value) + for key, value in mozprofile.FirefoxProfile.preferences.items()] + self.assertTrue(set(ff_pref_lines).issubset(lines)) + +if __name__ == '__main__': + unittest.main() diff --git a/testing/mozbase/mozprofile/tests/test_webapps.py b/testing/mozbase/mozprofile/tests/test_webapps.py new file mode 100755 index 0000000000..4db992d696 --- /dev/null +++ b/testing/mozbase/mozprofile/tests/test_webapps.py @@ -0,0 +1,202 @@ +#!/usr/bin/env python + +""" +test installing and managing webapps in a profile +""" + +import os +import shutil +import unittest +from tempfile import mkdtemp + +from mozprofile.webapps import WebappCollection, Webapp, WebappFormatException + +here = os.path.dirname(os.path.abspath(__file__)) + + +class WebappTest(unittest.TestCase): + """Tests reading, installing and cleaning webapps + from a profile. + """ + manifest_path_1 = os.path.join(here, 'files', 'webapps1.json') + manifest_path_2 = os.path.join(here, 'files', 'webapps2.json') + + def setUp(self): + self.profile = mkdtemp(prefix='test_webapp') + self.webapps_dir = os.path.join(self.profile, 'webapps') + self.webapps_json_path = os.path.join(self.webapps_dir, 'webapps.json') + + def tearDown(self): + shutil.rmtree(self.profile) + + def test_read_json_manifest(self): + """Tests WebappCollection.read_json""" + # Parse a list of webapp objects and verify it worked + manifest_json_1 = WebappCollection.read_json(self.manifest_path_1) + self.assertEqual(len(manifest_json_1), 7) + for app in manifest_json_1: + self.assertIsInstance(app, Webapp) + for key in Webapp.required_keys: + self.assertIn(key, app) + + # Parse a dictionary of webapp objects and verify it worked + manifest_json_2 = WebappCollection.read_json(self.manifest_path_2) + self.assertEqual(len(manifest_json_2), 5) + for app in manifest_json_2: + self.assertIsInstance(app, Webapp) + for key in Webapp.required_keys: + self.assertIn(key, app) + + def test_invalid_webapp(self): + """Tests a webapp with a missing required key""" + webapps = WebappCollection(self.profile) + # Missing the required key "description", exception should be raised + self.assertRaises(WebappFormatException, webapps.append, {'name': 'foo'}) + + def test_webapp_collection(self): + """Tests the methods of the WebappCollection object""" + webapp_1 = {'name': 'test_app_1', + 'description': 'a description', + 'manifestURL': 'http://example.com/1/manifest.webapp', + 'appStatus': 1} + + webapp_2 = {'name': 'test_app_2', + 'description': 'another description', + 'manifestURL': 'http://example.com/2/manifest.webapp', + 'appStatus': 2} + + webapp_3 = {'name': 'test_app_2', + 'description': 'a third description', + 'manifestURL': 'http://example.com/3/manifest.webapp', + 'appStatus': 3} + + webapps = WebappCollection(self.profile) + self.assertEqual(len(webapps), 0) + + # WebappCollection should behave like a list + def invalid_index(): + webapps[0] + self.assertRaises(IndexError, invalid_index) + + # Append a webapp object + webapps.append(webapp_1) + self.assertTrue(len(webapps), 1) + self.assertIsInstance(webapps[0], Webapp) + self.assertEqual(len(webapps[0]), len(webapp_1)) + self.assertEqual(len(set(webapps[0].items()) & set(webapp_1.items())), len(webapp_1)) + + # Remove a webapp object + webapps.remove(webapp_1) + self.assertEqual(len(webapps), 0) + + # Extend a list of webapp objects + webapps.extend([webapp_1, webapp_2]) + self.assertEqual(len(webapps), 2) + self.assertTrue(webapp_1 in webapps) + self.assertTrue(webapp_2 in webapps) + self.assertNotEquals(webapps[0], webapps[1]) + + # Insert a webapp object + webapps.insert(1, webapp_3) + self.assertEqual(len(webapps), 3) + self.assertEqual(webapps[1], webapps[2]) + for app in webapps: + self.assertIsInstance(app, Webapp) + + # Assigning an invalid type (must be accepted by the dict() constructor) should throw + def invalid_type(): + webapps[2] = 1 + self.assertRaises(WebappFormatException, invalid_type) + + def test_install_webapps(self): + """Test installing webapps into a profile that has no prior webapps""" + webapps = WebappCollection(self.profile, apps=self.manifest_path_1) + self.assertFalse(os.path.exists(self.webapps_dir)) + + # update the webapp manifests for the first time + webapps.update_manifests() + self.assertFalse(os.path.isdir(os.path.join(self.profile, webapps.backup_dir))) + self.assertTrue(os.path.isfile(self.webapps_json_path)) + + webapps_json = webapps.read_json(self.webapps_json_path, description="fake description") + self.assertEqual(len(webapps_json), 7) + for app in webapps_json: + self.assertIsInstance(app, Webapp) + + manifest_json_1 = webapps.read_json(self.manifest_path_1) + manifest_json_2 = webapps.read_json(self.manifest_path_2) + self.assertEqual(len(webapps_json), len(manifest_json_1)) + for app in webapps_json: + self.assertTrue(app in manifest_json_1) + + # Remove one of the webapps from WebappCollection after it got installed + removed_app = manifest_json_1[2] + webapps.remove(removed_app) + # Add new webapps to the collection + webapps.extend(manifest_json_2) + + # update the webapp manifests a second time + webapps.update_manifests() + self.assertFalse(os.path.isdir(os.path.join(self.profile, webapps.backup_dir))) + self.assertTrue(os.path.isfile(self.webapps_json_path)) + + webapps_json = webapps.read_json(self.webapps_json_path, description="a description") + self.assertEqual(len(webapps_json), 11) + + # The new apps should be added + for app in webapps_json: + self.assertIsInstance(app, Webapp) + self.assertTrue(os.path.isfile(os.path.join(self.webapps_dir, app['name'], + 'manifest.webapp'))) + # The removed app should not exist in the manifest + self.assertNotIn(removed_app, webapps_json) + self.assertFalse(os.path.exists(os.path.join(self.webapps_dir, removed_app['name']))) + + # Cleaning should delete the webapps directory entirely + # since there was nothing there before + webapps.clean() + self.assertFalse(os.path.isdir(self.webapps_dir)) + + def test_install_webapps_preexisting(self): + """Tests installing webapps when the webapps directory already exists""" + manifest_json_2 = WebappCollection.read_json(self.manifest_path_2) + + # Synthesize a pre-existing webapps directory + os.mkdir(self.webapps_dir) + shutil.copyfile(self.manifest_path_2, self.webapps_json_path) + for app in manifest_json_2: + app_path = os.path.join(self.webapps_dir, app['name']) + os.mkdir(app_path) + f = open(os.path.join(app_path, 'manifest.webapp'), 'w') + f.close() + + webapps = WebappCollection(self.profile, apps=self.manifest_path_1) + self.assertTrue(os.path.exists(self.webapps_dir)) + + # update webapp manifests for the first time + webapps.update_manifests() + # A backup should be created + self.assertTrue(os.path.isdir(os.path.join(self.profile, webapps.backup_dir))) + + # Both manifests should remain installed + webapps_json = webapps.read_json(self.webapps_json_path, description='a fake description') + self.assertEqual(len(webapps_json), 12) + for app in webapps_json: + self.assertIsInstance(app, Webapp) + self.assertTrue(os.path.isfile(os.path.join(self.webapps_dir, app['name'], + 'manifest.webapp'))) + + # Upon cleaning the backup should be restored + webapps.clean() + self.assertFalse(os.path.isdir(os.path.join(self.profile, webapps.backup_dir))) + + # The original webapps should still be installed + webapps_json = webapps.read_json(self.webapps_json_path) + for app in webapps_json: + self.assertIsInstance(app, Webapp) + self.assertTrue(os.path.isfile(os.path.join(self.webapps_dir, app['name'], + 'manifest.webapp'))) + self.assertEqual(webapps_json, manifest_json_2) + +if __name__ == '__main__': + unittest.main() |