| Index: tests/test_packagerWebExt.py |
| diff --git a/tests/test_packagerWebExt.py b/tests/test_packagerWebExt.py |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..985f09e7f4775b7c2d951b8d19e4ecead63baa96 |
| --- /dev/null |
| +++ b/tests/test_packagerWebExt.py |
| @@ -0,0 +1,294 @@ |
| +# 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 json |
| +import re |
| + |
| +import pytest |
| + |
| +from buildtools import packager |
| +from buildtools.tests.tools import DirContent |
|
Vasily Kuznetsov
2017/09/11 12:50:07
These imports also can be combined.
tlucas
2017/09/12 11:32:10
Acknowledged.
tlucas
2017/09/13 13:43:24
Done.
|
| +from buildtools.tests.tools import ZipContent |
| +from buildtools.tests.tools import copy_metadata |
| +from buildtools.tests.tools import run_webext_build |
| +from buildtools.tests.tools import assert_all_locales_present |
| +from buildtools.tests.tools import assert_manifest_content |
| +from buildtools.tests.tools import locale_files |
| +from buildtools.tests.conftest import ALL_LANGUAGES |
| + |
| + |
| +LOCALES_MODULE = { |
| + 'test.Foobar': { |
| + 'message': 'Ensuring dict-copy from modules for $domain$', |
| + 'description': 'test description', |
| + 'placeholders': {'content': '$1', 'example': 'www.adblockplus.org'} |
| + } |
| +} |
| + |
| +DTD_TEST = ('<!ENTITY access.key "access key(&a)">' |
| + '<!ENTITY ampersand "foo &-bar">') |
| + |
| +PROPERTIES_TEST = 'description=very descriptive!' |
| + |
| + |
| +@pytest.fixture |
| +def gecko_import(tmpdir): |
| + tmpdir.mkdir('_imp').mkdir('en-US').join('gecko.dtd').write(DTD_TEST) |
| + |
| + |
| +@pytest.fixture |
| +def locale_modules(tmpdir): |
| + mod_dir = tmpdir.mkdir('_modules') |
| + lang_dir = mod_dir.mkdir('en-US') |
| + lang_dir.join('module.json').write(json.dumps(LOCALES_MODULE)) |
| + lang_dir.join('unit.properties').write(json.dumps(PROPERTIES_TEST)) |
| + |
| + |
| +@pytest.fixture |
| +def icons(srcdir): |
| + icons_dir = srcdir.mkdir('icons') |
| + for filename in ['abp-16.png', 'abp-19.png', 'abp-53.png']: |
| + shutil.copy( |
| + os.path.join(os.path.dirname(__file__), filename), |
| + os.path.join(str(icons_dir), filename), |
| + ) |
| + |
| + |
| +@pytest.fixture |
| +def all_lang_locales(tmpdir): |
| + return locale_files(ALL_LANGUAGES, '_locales', tmpdir) |
| + |
| + |
| +@pytest.fixture |
| +def chrome_metadata(tmpdir): |
| + filename = 'metadata.chrome' |
| + copy_metadata(filename, tmpdir) |
| + |
| + |
| +@pytest.fixture |
| +def gecko_webext_metadata(tmpdir, chrome_metadata): |
| + filename = 'metadata.gecko-webext' |
| + copy_metadata(filename, tmpdir) |
| + |
| + |
| +@pytest.fixture |
| +def keyfile(tmpdir): |
| + """Test-privatekey for signing chrome release-package""" |
| + return os.path.join(os.path.dirname(__file__), 'chrome_rsa.pem') |
| + |
| + |
| +@pytest.fixture |
| +def lib_files(tmpdir): |
| + files = packager.Files(['lib'], set()) |
| + files['ext/a.js'] = 'var bar;' |
| + files['lib/b.js'] = 'var foo;' |
| + |
| + tmpdir.mkdir('lib').join('b.js').write(files['lib/b.js']) |
| + tmpdir.mkdir('ext').join('a.js').write(files['ext/a.js']) |
| + |
| + return files |
| + |
| + |
| +def assert_gecko_locale_conversion(package): |
| + locale = json.loads(package.read('_locales/en_US/messages.json')) |
| + |
| + assert locale.get('test_Foobar', {}) == LOCALES_MODULE['test.Foobar'] |
| + assert locale.get('access_key', {}) == {'message': 'access key'} |
| + assert locale.get('ampersand', {}) == {'message': 'foo -bar'} |
| + assert locale.get('_description', {}) == {'message': 'very descriptive!"'} |
| + |
| + |
| +def assert_convert_js(package, excluded=False): |
| + libfoo = package.read('lib/foo.js') |
| + |
| + assert 'var bar;' in libfoo |
| + assert 'require.modules["ext_a"]' in libfoo |
| + |
| + assert ('var foo;' in libfoo) != excluded |
| + assert ('require.modules["b"]' in libfoo) != excluded |
| + |
| + |
| +def assert_devenv_scripts(package, devenv): |
| + manifest = json.loads(package.read('manifest.json')) |
| + filenames = package.namelist() |
| + scripts = [ |
| + 'ext/common.js', |
| + 'ext/background.js', |
| + ] |
| + |
| + if devenv: |
| + assert 'qunit/index.html' in filenames |
| + assert 'devenvPoller__.js' in filenames |
| + assert 'devenvVersion__' in filenames |
| + |
| + assert '../ext/common.js' in package.read('qunit/index.html') |
| + assert '../ext/background.js' in package.read('qunit/index.html') |
| + |
| + assert set(manifest['background']['scripts']) == set( |
| + scripts + ['devenvPoller__.js'] |
| + ) |
| + else: |
| + assert 'qunit/index.html' not in filenames |
| + |
| + assert set(manifest['background']['scripts']) == set(scripts) |
| + |
| + |
| +def assert_base_files(package): |
| + filenames = set(package.namelist()) |
| + |
| + assert 'bar.json' in filenames |
| + assert 'manifest.json' in filenames |
| + assert 'lib/foo.js' in filenames |
| + assert 'foo/logo_50.png' in filenames |
| + assert 'icons/logo_150.png' in filenames |
| + |
| + |
| +def assert_chrome_signature(filename, keyfile): |
| + from struct import unpack |
|
Vasily Kuznetsov
2017/09/11 12:50:07
Is there any specific reason to have these imports
tlucas
2017/09/12 11:32:11
Not at all - merely a result of a speedy adjustmen
tlucas
2017/09/13 13:43:25
Done.
|
| + from Crypto.Hash import SHA |
| + from Crypto.PublicKey import RSA |
| + from Crypto.Signature import PKCS1_v1_5 |
| + |
| + with open(filename, 'r') as fp: |
| + content = fp.read() |
| + |
| + _, _, l_pubkey, l_signature = unpack('<4sIII', content[:16]) |
| + signature = content[16 + l_pubkey: 16 + l_pubkey + l_signature] |
| + |
| + digest = SHA.new() |
| + with open(keyfile, 'r') as fp: |
| + rsa_key = RSA.importKey(fp.read()) |
| + |
| + signer = PKCS1_v1_5.new(rsa_key) |
| + |
| + digest.update(content[16 + l_pubkey + l_signature:]) |
| + assert signer.verify(digest, signature) |
| + |
| + |
| +def assert_locale_upfix(package): |
| + translations = [ |
| + json.loads(package.read('_locales/{}/messages.json'.format(lang))) |
| + for lang in ALL_LANGUAGES |
| + ] |
| + |
| + manifest = package.read('manifest.json') |
| + |
| + # Chrome Web Store requires descriptive translations to be present in |
| + # every language. |
| + for match in re.finditer(r'__MSG_(\S+)__', manifest): |
| + name = match.group(1) |
| + |
| + for other in translations[1:]: |
| + assert translations[0][name]['message'] == other[name]['message'] |
| + |
| + |
| +@pytest.mark.usefixtures( |
| + 'all_lang_locales', |
| + 'gecko_import', |
| + 'locale_modules', |
| + 'icons', |
| + 'lib_files', |
| + 'chrome_metadata', |
| +) |
| +@pytest.mark.parametrize('dev_build_release', ['build', 'devenv', 'release']) |
| +def test_build_chrome(dev_build_release, keyfile, tmpdir, srcdir, capsys): |
| + from buildtools import packagerChrome |
| + release = dev_build_release == 'release' |
| + devenv = dev_build_release == 'devenv' |
| + |
| + run_webext_build('chrome', dev_build_release, srcdir, packagerChrome, |
| + keyfile if release else None) |
| + |
| + # The makeIcons() in packagerChrome.py should warn about non-square |
| + # icons via stderr. |
| + out, err = capsys.readouterr() |
| + assert 'icon should be square' in err |
| + |
| + if devenv: |
| + content_class = DirContent |
| + out_file_path = os.path.join(str(srcdir), 'devenv.chrome') |
| + else: |
| + content_class = ZipContent |
| + out_file = 'adblockpluschrome-1.2.3' |
| + if not release: |
| + out_file += '.0' |
| + |
| + if release: |
| + out_file += '.crx' |
| + else: |
| + out_file += '.zip' |
| + |
| + out_file_path = os.path.abspath(os.path.join( |
| + os.path.dirname(__file__), os.pardir, out_file)) |
| + |
| + assert os.path.exists(out_file_path) |
| + |
| + if release: |
| + assert_chrome_signature(out_file_path, keyfile) |
| + |
| + with content_class(out_file_path) as package: |
| + assert_base_files(package) |
| + assert_devenv_scripts(package, devenv) |
| + assert_all_locales_present(package, '_locales') |
| + assert_locale_upfix(package) |
| + assert_gecko_locale_conversion(package) |
| + assert_convert_js(package) |
| + expected = os.path.join( |
| + os.path.dirname(__file__), |
| + 'expecteddata', |
| + 'manifest_chrome_{}.json'.format(dev_build_release), |
| + ) |
| + assert_manifest_content(package.read('manifest.json'), expected) |
| + |
| + |
| +@pytest.mark.usefixtures( |
| + 'all_lang_locales', |
| + 'locale_modules', |
| + 'gecko_import', |
| + 'icons', |
| + 'lib_files', |
| + 'gecko_webext_metadata', |
| +) |
| +@pytest.mark.parametrize('dev_build_release', ['build', 'devenv', 'release']) |
| +def test_build_gecko_webext(dev_build_release, tmpdir, srcdir, capsys): |
|
Vasily Kuznetsov
2017/09/11 12:50:07
This test seems very similar to the previous one a
tlucas
2017/09/12 11:32:11
I agree - will do (also i fear the complexity of t
tlucas
2017/09/13 13:43:25
Done.
|
| + from buildtools import packagerChrome |
| + release = dev_build_release == 'release' |
| + devenv = dev_build_release == 'devenv' |
| + |
| + run_webext_build('gecko-webext', dev_build_release, srcdir, packagerChrome) |
| + |
| + # The makeIcons() in packagerChrome.py should warn about non-square |
| + # icons via stderr. |
| + out, err = capsys.readouterr() |
| + assert 'icon should be square' in err |
| + |
| + if devenv: |
| + content_class = DirContent |
| + out_file_path = os.path.join(str(srcdir), 'devenv.gecko-webext') |
| + else: |
| + content_class = ZipContent |
| + out_file = 'adblockplusfirefox-1.2.3{}.xpi'.format( |
| + '.0' if not release else '' |
| + ) |
| + |
| + out_file_path = os.path.abspath(os.path.join( |
| + os.path.dirname(__file__), os.pardir, out_file)) |
| + |
| + assert os.path.exists(out_file_path) |
| + |
| + with content_class(out_file_path) as package: |
| + assert_base_files(package) |
| + assert_devenv_scripts(package, devenv) |
| + assert_all_locales_present(package, '_locales') |
| + assert_gecko_locale_conversion(package) |
| + assert_convert_js(package, True) |
| + |
| + expected = os.path.join( |
| + os.path.dirname(__file__), |
| + 'expecteddata', |
| + 'manifest_gecko-webext_{}.json'.format(dev_build_release), |
| + ) |
| + assert_manifest_content(package.read('manifest.json'), expected) |